Skip to content

Commit

Permalink
Add lang module
Browse files Browse the repository at this point in the history
  • Loading branch information
schaable committed May 4, 2024
1 parent c2b2dc6 commit f0a6918
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 62 deletions.
2 changes: 2 additions & 0 deletions packages/hardhat-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"./eth": "./dist/src/eth.js",
"./fs": "./dist/src/fs.js",
"./hex": "./dist/src/hex.js",
"./lang": "./dist/src/lang.js",
"./number": "./dist/src/number.js",
"./package": "./dist/src/package.js",
"./request": "./dist/src/request.js"
Expand Down Expand Up @@ -65,6 +66,7 @@
},
"dependencies": {
"keccak": "^3.0.4",
"rfdc": "^1.3.1",
"undici": "^5.14.0"
}
}
12 changes: 12 additions & 0 deletions packages/hardhat-utils/src/internal/lang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type rfdcT from "rfdc";

let clone: ReturnType<typeof rfdcT> | null = null;
export async function getDeepCloneFunction() {
const { default: rfdc } = await import("rfdc");

if (clone === null) {
clone = rfdc();
}

return clone;
}
15 changes: 15 additions & 0 deletions packages/hardhat-utils/src/lang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { getDeepCloneFunction } from "./internal/lang.js";

/**
* Creates a deep clone of the provided value.
*
* @param value The value to clone.
* @returns The deep clone of the provided value.
*/
export async function deepClone<T>(value: T): Promise<T> {
const _deepClone = await getDeepCloneFunction();

return _deepClone<T>(value);
}

// export function deepEqual<T>(a: T, b: T): boolean {}
18 changes: 9 additions & 9 deletions packages/hardhat-utils/test/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,35 @@ import { toSeconds, secondsToDate, now } from "../src/date.js";

describe("date", () => {
describe("toSeconds", () => {
it("should convert a string to a Unix timestamp", () => {
it("Should convert a string to a Unix timestamp", () => {
const timestamp = toSeconds("2022-01-01T00:00:00Z");
expectTypeOf(timestamp).toEqualTypeOf<number>();
assert.strictEqual(timestamp, 1640995200);
assert.equal(timestamp, 1640995200);
});

it("should convert a number to a Unix timestamp", () => {
it("Should convert a number to a Unix timestamp", () => {
const timestamp = toSeconds(1640995200);
expectTypeOf(timestamp).toEqualTypeOf<number>();
assert.strictEqual(timestamp, Math.floor(1640995200 / 1000));
assert.equal(timestamp, Math.floor(1640995200 / 1000));
});

it("should convert a Date object to a Unix timestamp", () => {
it("Should convert a Date object to a Unix timestamp", () => {
const timestamp = toSeconds(new Date("2022-01-01T00:00:00Z"));
expectTypeOf(timestamp).toEqualTypeOf<number>();
assert.strictEqual(timestamp, 1640995200);
assert.equal(timestamp, 1640995200);
});
});

describe("secondsToDate", () => {
it("should convert a Unix timestamp to a Date object", () => {
it("Should convert a Unix timestamp to a Date object", () => {
const date = secondsToDate(1640995200);
expectTypeOf(date).toEqualTypeOf<Date>();
assert.strictEqual(date.toISOString(), "2022-01-01T00:00:00.000Z");
assert.equal(date.toISOString(), "2022-01-01T00:00:00.000Z");
});
});

describe("now", () => {
it("should return the current Unix timestamp", () => {
it("Should return the current Unix timestamp", () => {
const timestamp = now();
expectTypeOf(timestamp).toEqualTypeOf<number>();
const currentTimestamp = Math.floor(Date.now() / 1000);
Expand Down
134 changes: 134 additions & 0 deletions packages/hardhat-utils/test/lang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { expectTypeOf } from "expect-type";

import { deepClone } from "../src/lang.js";

describe("lang", () => {
describe("deepClone", () => {
it("Should clone an object", async () => {
const obj = { a: 1, b: 2, c: { d: 3 } };
const clonedObj = await deepClone(obj);

assert.deepEqual(clonedObj, obj);
assert.notEqual(clonedObj, obj);
assert.notEqual(clonedObj.c, obj.c);
expectTypeOf(clonedObj).toEqualTypeOf<typeof obj>();
});

it("Should clone an array", async () => {
const arr = [1, 2, [3]];
const clonedArr = await deepClone(arr);

assert.deepEqual(clonedArr, arr);
assert.notEqual(clonedArr, arr);
assert.notEqual(clonedArr[2], arr[2]);
expectTypeOf(clonedArr).toEqualTypeOf<typeof arr>();
});

it("Should clone a string", async () => {
const str = "hello";
const clonedStr = await deepClone(str);

assert.equal(clonedStr, str);
expectTypeOf(clonedStr).toBeString();
});

it("Should clone a number", async () => {
const num = 42;
const clonedNum = await deepClone(num);

assert.equal(clonedNum, num);
expectTypeOf(clonedNum).toBeNumber();
});

it("Should clone null", async () => {
const n = null;
const clonedN = await deepClone(n);

assert.equal(clonedN, n);
expectTypeOf(clonedN).toBeNull();
});

it("Should clone undefined", async () => {
const u = undefined;
const clonedU = await deepClone(u);

assert.equal(clonedU, u);
expectTypeOf(clonedU).toBeUndefined();
});

it("Should reference a function", async () => {
const fn = () => {};
const clonedFn = await deepClone(fn);

assert.equal(clonedFn, fn);
expectTypeOf(clonedFn).toEqualTypeOf<typeof fn>();
});

it("Should clone a Date", async () => {
const date = new Date();
const clonedDate = await deepClone(date);

assert.deepEqual(clonedDate, date);
assert.notEqual(clonedDate, date);
expectTypeOf(clonedDate).toEqualTypeOf<typeof date>();
});

it("Should clone a Map", async () => {
const map = new Map([
["a", 1],
["b", 2],
]);
const clonedMap = await deepClone(map);

assert.deepEqual(clonedMap, map);
assert.notEqual(clonedMap, map);
expectTypeOf(clonedMap).toEqualTypeOf<typeof map>();
});

it("Should clone a Set", async () => {
const set = new Set([1, 2]);
const clonedSet = await deepClone(set);

assert.deepEqual(clonedSet, set);
assert.notEqual(clonedSet, set);
expectTypeOf(clonedSet).toEqualTypeOf<typeof set>();
});

it("Should clone a Buffer", async () => {
const buffer = Buffer.from("test");
const clonedBuffer = await deepClone(buffer);

const expected: { [key: number]: number } = {};
for (let i = 0; i < buffer.length; i++) {
expected[i] = buffer[i] as number;
}

assert.deepEqual(clonedBuffer, expected);
assert.notEqual(clonedBuffer, expected);
expectTypeOf(clonedBuffer).toEqualTypeOf<Buffer>();
});

it("Should clone arguments to a normal object", async () => {
function testFunc(_a: number, _b: string, _c: boolean) {
return arguments;
}
const args = testFunc(1, "2", false);
const clonedArgs = await deepClone(args);

assert.deepEqual(clonedArgs, { "0": 1, "1": "2", "2": false });
expectTypeOf(clonedArgs).toHaveProperty("0").toBeNumber();
expectTypeOf(clonedArgs).toHaveProperty("1").toBeString();
expectTypeOf(clonedArgs).toHaveProperty("2").toBeBoolean();
});

it("Should match JSON.parse(JSON.stringify(o)) for other types", async () => {
const error = new Error("test");
const clonedError = await deepClone(error);

assert.deepEqual(clonedError, JSON.parse(JSON.stringify(error)));
expectTypeOf(clonedError).toEqualTypeOf<typeof error>();
});
});
});
28 changes: 14 additions & 14 deletions packages/hardhat-utils/test/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,46 +562,46 @@ describe("Requests util", () => {
delete process.env.NO_PROXY;
});

it("should return false for localhost", () => {
it("Should return false for localhost", () => {
assert.equal(shouldUseProxy("http://localhost"), false);
});

it("should return false for 127.0.0.1", () => {
it("Should return false for 127.0.0.1", () => {
assert.equal(shouldUseProxy("http://127.0.0.1"), false);
});

it("should return false if NO_PROXY is '*'", () => {
it("Should return false if NO_PROXY is '*'", () => {
process.env.NO_PROXY = "*";
assert.equal(shouldUseProxy("http://example.com"), false);
});

it("should return false if hostname is in NO_PROXY list", () => {
it("Should return false if hostname is in NO_PROXY list", () => {
process.env.NO_PROXY = "example.com,other.com";
assert.equal(shouldUseProxy("http://example.com"), false);
assert.equal(shouldUseProxy("http://other.com"), false);
});

it("should return true if hostname is not in NO_PROXY list", () => {
it("Should return true if hostname is not in NO_PROXY list", () => {
process.env.NO_PROXY = "other.com,different.com";
assert.equal(shouldUseProxy("http://example.com"), true);
});

it("should handle a mix of proxied and non-proxied URLs in NO_PROXY", () => {
it("Should handle a mix of proxied and non-proxied URLs in NO_PROXY", () => {
process.env.NO_PROXY = "example.com,other.com";
assert.strictEqual(shouldUseProxy("http://example.com"), false);
assert.strictEqual(shouldUseProxy("http://other.com"), false);
assert.strictEqual(shouldUseProxy("http://different.com"), true);
assert.equal(shouldUseProxy("http://example.com"), false);
assert.equal(shouldUseProxy("http://other.com"), false);
assert.equal(shouldUseProxy("http://different.com"), true);
});

it("should return true if NO_PROXY is not defined", () => {
it("Should return true if NO_PROXY is not defined", () => {
assert.equal(shouldUseProxy("http://example.com"), true);
});

it("should ignore the protocol part of the URL", () => {
it("Should ignore the protocol part of the URL", () => {
process.env.NO_PROXY = "example.com";
assert.strictEqual(shouldUseProxy("http://example.com"), false);
assert.strictEqual(shouldUseProxy("https://example.com"), false);
assert.strictEqual(shouldUseProxy("ftp://example.com"), false);
assert.equal(shouldUseProxy("http://example.com"), false);
assert.equal(shouldUseProxy("https://example.com"), false);
assert.equal(shouldUseProxy("ftp://example.com"), false);
});
});
});
28 changes: 14 additions & 14 deletions packages/hardhat-utils/test/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,32 @@ import { pluralize, capitalize } from "../src/string.js";

describe("string", () => {
describe("pluralize", () => {
it("should return the singular form when count is 1", () => {
assert.strictEqual(pluralize("word", 1), "word");
it("Should return the singular form when count is 1", () => {
assert.equal(pluralize("word", 1), "word");
});

it("should return the plural form when count is not 1", () => {
assert.strictEqual(pluralize("word", 0), "words");
assert.strictEqual(pluralize("word", 2), "words");
it("Should return the plural form when count is not 1", () => {
assert.equal(pluralize("word", 0), "words");
assert.equal(pluralize("word", 2), "words");
});

it("should return the provided plural form when count is not 1", () => {
assert.strictEqual(pluralize("word", 0, "wordz"), "wordz");
assert.strictEqual(pluralize("word", 2, "wordz"), "wordz");
it("Should return the provided plural form when count is not 1", () => {
assert.equal(pluralize("word", 0, "wordz"), "wordz");
assert.equal(pluralize("word", 2, "wordz"), "wordz");
});
});

describe("capitalize", () => {
it("should capitalize the first letter of a string", () => {
assert.strictEqual(capitalize("word"), "Word");
it("Should capitalize the first letter of a string", () => {
assert.equal(capitalize("word"), "Word");
});

it("should not change the string when it is already capitalized", () => {
assert.strictEqual(capitalize("Word"), "Word");
it("Should not change the string when it is already capitalized", () => {
assert.equal(capitalize("Word"), "Word");
});

it("should capitalize the first letter of a string and leave the rest as is", () => {
assert.strictEqual(capitalize("word word"), "Word word");
it("Should capitalize the first letter of a string and leave the rest as is", () => {
assert.equal(capitalize("word word"), "Word word");
});
});
});

0 comments on commit f0a6918

Please sign in to comment.