From 35f25f8126e3f3da234161c959c3fd66c6831263 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Sun, 10 Jul 2022 22:50:51 -0400 Subject: [PATCH 01/33] add set operation tests --- test/Set.test.ts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/Set.test.ts b/test/Set.test.ts index 3678adc..6ce92d3 100644 --- a/test/Set.test.ts +++ b/test/Set.test.ts @@ -82,4 +82,40 @@ describe('xjs.Set', () => { }); }); }); + + + context('Operation Methods', () => { + type Item = {id: number}; + const comparator = (a: Item, b: Item) => a.id === b.id; + const a: ReadonlySet = new Set([{id: 1}, {id: 2}, {id: 3}]); + const b: ReadonlySet = new Set([{id: 2}, {id: 3}, {id: 4}]); + specify('.intersection', () => { + assert.deepStrictEqual( + xjs_Set.intersection(a, b, comparator), + new Set([{id: 2}, {id: 3}]), + ); + }); + specify('.union', () => { + assert.deepStrictEqual( + xjs_Set.union(a, b, comparator), + new Set([{id: 1}, {id: 2}, {id: 3}, {id: 4}]), + ); + }); + specify('.difference', () => { + assert.deepStrictEqual( + xjs_Set.difference(a, b, comparator), + new Set([{id: 1}]), + ); + assert.deepStrictEqual( + xjs_Set.difference(b, a, comparator), + new Set([{id: 4}]), + ); + }); + specify('.symmetricDifference', () => { + assert.deepStrictEqual( + xjs_Set.symmetricDifference(a, b, comparator), + new Set([{id: 1}, {id: 4}]), + ); + }); + }); }) From d4fb418376a8f2d6ab35277ea117604d6eb747aa Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 25 Jan 2023 23:16:33 -0500 Subject: [PATCH 02/33] add xjs_Map.forEachAggregated --- src/class/Array.class.ts | 4 +- src/class/Map.class.ts | 52 +++++++++++++++++ test/Array.test.ts | 3 +- test/Map.test.ts | 120 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 4 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index 0b1d358..c52a6dd 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -220,7 +220,7 @@ export class xjs_Array { * @throws {AggregateError} if two or more iterations throws an error * @throws {Error} if one iteration throws an error */ - static forEachAggregated(array: readonly T[], callback: (item: T, i: number, src: readonly T[]) => void): void { + static forEachAggregated(array: readonly T[], callback: (item: T, i: number, src: typeof array) => void): void { const errors: readonly Error[] = array.map((it, i, src) => { try { callback.call(null, it, i, src); @@ -278,7 +278,7 @@ export class xjs_Array { * @throws {AggregateError} if two or more iterations throws an error * @throws {Error} if one iteration throws an error */ - static mapAggregated(array: readonly T[], callback: (item: T, i: number, src: readonly T[]) => U): U[] { + static mapAggregated(array: readonly T[], callback: (item: T, i: number, src: typeof array) => U): U[] { const results: ([U, true] | [Error, false])[] = array.map((it, i, src) => { try { return [callback(it, i, src), true]; diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index 296735e..b054f52 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -169,6 +169,58 @@ export class xjs_Map { return map.delete((foundkey === undefined) ? key : foundkey); } + /** + * Perform a callback function on a map, aggregating any errors caught. + * + * Instead of throwing on the first error and stopping iteration, as {@link Map#forEach} would do, + * this method continues performing the callback on the rest of the map until all items are done. + * If only one error was caught, then that error is simply rethrown. + * However, if more errors were caught, they are collected into a single AggregateError, which is then thrown. + * If no errors are caught, this method returns void. + * + * @example + * xjs.Map.forEachAggregated(new Map([ + * ['one', 1], + * ['two', 2], + * ['three', 3], + * ['four', 4], + * ]), (num, name) => { + * if (num % 2 === 0) { + * throw new Error(`${ name } is even.`); + * }; + * }); + * // Expected thrown error: + * AggregateError { + * errors: [ + * Error { message: "two is even." }, + * Error { message: "four is even." }, + * ] + * } + * @typeparam K the type of keys in the map + * @typeparam V the type of values in the map + * @param map the map of keys and values + * @param callback the function to call on each key–value pair + * @throws {AggregateError} if two or more iterations throws an error + * @throws {Error} if one iteration throws an error + */ + static forEachAggregated(map: ReadonlyMap, callback: (value: V, key: K, src: typeof map) => void): void { + const accumulator: Array = []; + map.forEach((value, key, src) => { + try { + callback.call(null, value, key, src); + accumulator.push(null); + } catch (err) { + accumulator.push((err instanceof Error) ? err : new Error(`${ err }`)); + } + }); + const errors: readonly Error[] = accumulator.filter((e): e is Error => e instanceof Error); + if (errors.length) { + throw (errors.length === 1) + ? errors[0] + : new AggregateError(errors, errors.map((err) => err.message).join('\n')); + } + } + private constructor() {} } diff --git a/test/Array.test.ts b/test/Array.test.ts index 09522c9..c5d30dd 100644 --- a/test/Array.test.ts +++ b/test/Array.test.ts @@ -168,8 +168,7 @@ describe('xjs.Array', () => { new RangeError(`${ n } is even.`), new RangeError(`${ n } is a multiple of 4.`), ]) - : new RangeError(`${ n } is even.`) - ; + : new RangeError(`${ n } is even.`); }; }), (err) => { assert.ok(err instanceof AggregateError); diff --git a/test/Map.test.ts b/test/Map.test.ts index 239caed..9b69d69 100644 --- a/test/Map.test.ts +++ b/test/Map.test.ts @@ -68,4 +68,124 @@ describe('xjs.Map', () => { }); }); }); + + describe('.forEachAggregated', () => { + it('acts like Map#forEach if no errors.', () => { + let times: number = 0; + xjs_Map.forEachAggregated(new Map([ + ['one', 1], + ['two', 2], + ['three', 3], + ['four', 4], + ]), (_n) => { + times++; + }); + assert.strictEqual(times, 4); + }); + it('callback params.', () => { + const results: Record> = { + v: new Set(), + k: new Set(), + s: new Set(), + }; + xjs_Map.forEachAggregated(new Map([ + ['ten', 10], + ['twenty', 20], + ['thirty', 30], + ['forty', 40], + ]), (value, key, src) => { + results.v.add(value.toString()); + results.k.add(key.toString()); + results.s.add([...src].toString()); + }); + assert.deepStrictEqual(results, { + v: new Set(['10', '20', '30', '40']), + k: new Set(['ten', 'twenty', 'thirty', 'forty']), + s: new Set([ + 'ten,10,twenty,20,thirty,30,forty,40', + 'ten,10,twenty,20,thirty,30,forty,40', + 'ten,10,twenty,20,thirty,30,forty,40', + 'ten,10,twenty,20,thirty,30,forty,40', + ]), + }); + }); + it('rethrows first error if only 1 error.', () => { + let times: number = 0; + assert.throws(() => xjs_Map.forEachAggregated(new Map([ + ['one', 1], + ['two', 2], + ['three', 3], + ['four', 4], + ]), (num, name) => { + times++; + if (num === 2) { + throw new RangeError(`${ name } is even.`); + }; + }), (err) => { + assert.ok(err instanceof RangeError); + assert.strictEqual(err.message, 'two is even.'); + assert.strictEqual(times, 4); + return true; + }); + }); + it('aggregates all caught errors if more than 1.', () => { + assert.throws(() => xjs_Map.forEachAggregated(new Map([ + ['one', 1], + ['two', 2], + ['three', 3], + ['four', 4], + ]), (num, name) => { + if (num % 2 === 0) { + throw new RangeError(`${ name } is even.`); + }; + }), (err) => { + assert.ok(err instanceof AggregateError); + assert.strictEqual(err.errors.length, 2); + assert.deepStrictEqual(err.errors.map((er) => { + assert.ok(er instanceof RangeError); + return er.message; + }), ['two is even.', 'four is even.']); + return true; + }); + }); + it('preserves any nested AggregateError errors.', () => { + assert.throws(() => xjs_Map.forEachAggregated(new Map([ + ['one', 1], + ['two', 2], + ['three', 3], + ['four', 4], + ['five', 5], + ['six', 6], + ['seven', 7], + ['eight', 8], + ]), (num, name) => { + if (num % 2 === 0) { + throw (num % 4 === 0) + ? new AggregateError([ + new RangeError(`${ name } is even.`), + new RangeError(`${ name } is a multiple of 4.`), + ]) + : new RangeError(`${ name } is even.`); + }; + }), (err) => { + assert.ok(err instanceof AggregateError); + assert.strictEqual(err.errors.length, 4); + assert.deepStrictEqual(err.errors.map((er, i) => { + if ([0, 2].includes(i)) { + assert.ok(er instanceof RangeError); + return er.message; + } else { + assert.ok(er instanceof AggregateError); + return er.errors.map((e) => e.message); + } + }), [ + 'two is even.', + ['four is even.', 'four is a multiple of 4.'], + 'six is even.', + ['eight is even.', 'eight is a multiple of 4.'], + ]); + return true; + }); + }); + }); }); From db30141c0334ced8e7208d51379983ea08d1c777 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Sun, 12 Mar 2023 21:24:09 -0400 Subject: [PATCH 03/33] fix xjs.Map.is fixes an issue where `xjs.Map.is` was returning false when keys/values failed the sameValueZero test and a predicate was given --- src/class/Map.class.ts | 17 ++++++++--------- test/Map.test.ts | 31 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index 296735e..7e6d660 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -24,17 +24,16 @@ export class xjs_Map { /** check the “sameness” of corresponding values of `a` and `b` */ values = xjs_Object.sameValueZero, }: { - keys ?: (x: K, y: K) => boolean, - values ?: (x: V, y: V) => boolean, + keys?: (x: K, y: K) => boolean, + values?: (x: V, y: V) => boolean, } = { - keys : xjs_Object.sameValueZero, - values : xjs_Object.sameValueZero, + keys: xjs_Object.sameValueZero, + values: xjs_Object.sameValueZero, }): boolean { - if (a === b) return true - return a.size === b.size && [...a].every(([a_key, a_value]) => - [...b].some(([b_key, b_value]) => - xjs_Object.sameValueZero(a_key , b_key ) && keys (a_key , b_key ) && - xjs_Object.sameValueZero(a_value, b_value) && values(a_value, b_value) + return a === b || a.size === b.size && [...a].every(([a_key, a_val]) => + [...b].some(([b_key, b_val]) => + (xjs_Object.sameValueZero(a_key, b_key) || keys (a_key, b_key)) + && (xjs_Object.sameValueZero(a_val, b_val) || values(a_val, b_val)) ) ) } diff --git a/test/Map.test.ts b/test/Map.test.ts index 239caed..e1a8c92 100644 --- a/test/Map.test.ts +++ b/test/Map.test.ts @@ -2,6 +2,37 @@ import * as assert from 'assert'; import {xjs_Map} from '../src/class/Map.class.js'; describe('xjs.Map', () => { + describe('.is', () => { + it('tests keys and values by equality predicate.', () => { + type Key = {id: number}; + type Val = {name: string}; + const comparator_keys = (a: Key, b: Key) => a.id === b.id; + const comparator_vals = (a: Val, b: Val) => a.name === b.name; + const key: Key = {id: 42}; + const val: Val = {name: 'alice'}; + const map1 = new Map([[key, val]]); + const map2 = new Map([[key, val]]); + const map3 = new Map([[{id: 42}, {name: 'alice'}]]); + const map4 = new Map([[{id: 43}, {name: 'bob'}]]); + assert.notStrictEqual(map1, map2, 'different maps with identical pairs are not identical.'); + assert.ok(xjs_Map.is(map1, map2), 'maps with identical pairs pass with the default predicate.'); + assert.ok(!xjs_Map.is(map2, map3), 'maps with equal (but non-identical) pairs fail with the default predicate.'); + assert.ok(xjs_Map.is(map1, map2, { + keys: comparator_keys, + values: comparator_vals, + }), 'maps with identical pairs pass with both the provided predicates.'); + assert.ok(xjs_Map.is(map2, map3, { + keys: comparator_keys, + values: comparator_vals, + }), 'maps with equal (but non-identical) pairs pass with both the provided predicates.'); + assert.ok(!xjs_Map.is(map3, map4, { + keys: comparator_keys, + values: comparator_vals, + }), 'maps with non-equal and non-identical pairs fail.'); + }); + }); + + context('Equality Methods', () => { type Key = {id: number}; const comparator = (a: Key, b: Key) => a.id === b.id; From 82b2e8e2726615975a0166dc2cb611b491f822d3 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Sun, 25 Jun 2023 20:12:14 -0400 Subject: [PATCH 04/33] fresh install && bump version number --- package-lock.json | 1009 ++++----------------------------------------- package.json | 12 +- 2 files changed, 84 insertions(+), 937 deletions(-) diff --git a/package-lock.json b/package-lock.json index c2aae7f..b4af92c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,23 @@ { "name": "extrajs", - "version": "0.25.0", - "lockfileVersion": 2, + "version": "0.26.0", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "extrajs", - "version": "0.25.0", + "version": "0.26.0", "license": "MIT", "devDependencies": { - "@types/mocha": "^9.0.0", - "@types/node": "^18.0.0", + "@types/mocha": "^10.0.0", + "@types/node": "^20.0.0", "mocha": "^10.0.0", "ts-node": "^10.0.0", - "typedoc": "^0.23.0", - "typescript": "~4.7.0" + "typedoc": "^0.24.0", + "typescript": "~5.1.3" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@cspotcode/source-map-support": { @@ -33,18 +33,18 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { @@ -76,33 +76,27 @@ "dev": true }, "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, "node_modules/@types/mocha": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", - "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", "dev": true }, "node_modules/@types/node": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz", - "integrity": "sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==", - "dev": true - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "version": "20.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", + "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", "dev": true }, "node_modules/acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", + "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -138,6 +132,12 @@ "node": ">=8" } }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", + "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", + "dev": true + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -154,9 +154,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -638,9 +638,9 @@ } }, "node_modules/jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, "node_modules/locate-path": { @@ -687,9 +687,9 @@ "dev": true }, "node_modules/marked": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz", - "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true, "bin": { "marked": "bin/marked.js" @@ -711,12 +711,11 @@ } }, "node_modules/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "dependencies": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", @@ -907,14 +906,15 @@ } }, "node_modules/shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", + "integrity": "sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==", "dev": true, "dependencies": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" } }, "node_modules/string-width": { @@ -983,9 +983,9 @@ } }, "node_modules/ts-node": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.2.tgz", - "integrity": "sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==", + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -1035,15 +1035,15 @@ } }, "node_modules/typedoc": { - "version": "0.23.7", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.7.tgz", - "integrity": "sha512-Vl/Yh4KYBaxQQOYImBgLQDX61hfaA7XaP/DZVd/w7rQvaqLEsdQH6gEMK8CMjyHo0bSzVnNYwxtD1KPSENoWug==", + "version": "0.24.8", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", + "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", "dev": true, "dependencies": { "lunr": "^2.3.9", - "marked": "^4.0.16", - "minimatch": "^5.1.0", - "shiki": "^0.10.1" + "marked": "^4.3.0", + "minimatch": "^9.0.0", + "shiki": "^0.14.1" }, "bin": { "typedoc": "bin/typedoc" @@ -1052,32 +1052,35 @@ "node": ">= 14.14" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.2.tgz", + "integrity": "sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/v8-compile-cache-lib": { @@ -1087,15 +1090,15 @@ "dev": true }, "node_modules/vscode-oniguruma": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", "dev": true }, "node_modules/vscode-textmate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, "node_modules/workerpool": { @@ -1199,861 +1202,5 @@ "url": "https://github.com/sponsors/sindresorhus" } } - }, - "dependencies": { - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "@types/mocha": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", - "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", - "dev": true - }, - "@types/node": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz", - "integrity": "sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==", - "dev": true - }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", - "dev": true - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "marked": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz", - "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==", - "dev": true - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", - "dev": true, - "requires": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "ts-node": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.2.tgz", - "integrity": "sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "typedoc": { - "version": "0.23.7", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.7.tgz", - "integrity": "sha512-Vl/Yh4KYBaxQQOYImBgLQDX61hfaA7XaP/DZVd/w7rQvaqLEsdQH6gEMK8CMjyHo0bSzVnNYwxtD1KPSENoWug==", - "dev": true, - "requires": { - "lunr": "^2.3.9", - "marked": "^4.0.16", - "minimatch": "^5.1.0", - "shiki": "^0.10.1" - }, - "dependencies": { - "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "vscode-oniguruma": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", - "dev": true - }, - "vscode-textmate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", - "dev": true - }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } } } diff --git a/package.json b/package.json index 4f99567..0712cff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "extrajs", - "version": "0.25.0", + "version": "0.26.0", "description": "Javascript helpers for lazy people.", "keywords": [ "javascript", @@ -33,14 +33,14 @@ "prepublishOnly": "npm run build" }, "devDependencies": { - "@types/mocha": "^9.0.0", - "@types/node": "^18.0.0", + "@types/mocha": "^10.0.0", + "@types/node": "^20.0.0", "mocha": "^10.0.0", "ts-node": "^10.0.0", - "typedoc": "^0.23.0", - "typescript": "~4.7.0" + "typedoc": "^0.24.0", + "typescript": "~5.1.3" }, "engines": { - "node": ">=16" + "node": ">=18" } } From 0731900b73a99328928cbab72ac12215966698f1 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Sun, 25 Jun 2023 20:13:00 -0400 Subject: [PATCH 05/33] update tsconfig & typings --- src/class/Array.class.ts | 2 +- src/class/Object.class.ts | 10 +++++----- tsconfig.json | 14 ++++++-------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index 0b1d358..76b91e9 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -308,7 +308,7 @@ export class xjs_Array { */ static freezeDeep(arr: readonly T[]): readonly T[] { Object.freeze(arr) - arr.forEach((el) => { if (!Object.isFrozen(el)) xjs_Object.freezeDeep(el) }) + arr.forEach((el) => { if (!Object.isFrozen(el)) xjs_Object.freezeDeep(el) }) return arr } diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index 8ba383d..8f82b1d 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -56,10 +56,10 @@ export class xjs_Object { if (xjs_Object.typeOf(a) === 'function' || xjs_Object.typeOf(b) === 'function') throw new TypeError('Function arguments to xjs.Object.is are not yet supported.') if (a instanceof Array && b instanceof Array) return xjs_Array.is(a, b) // else, it will be 'object' - return Object.entries(a).every(([a_key, a_value]) => - Object.entries(b).some(([b_key, b_value]) => a_key === b_key && predicate(a_value, b_value)) - ) && Object.entries(b).every(([b_key, b_value]) => - Object.entries(a).some(([a_key, a_value]) => a_key === b_key && predicate(a_value, b_value)) + return Object.entries(a as Record).every(([a_key, a_value]) => + Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && predicate(a_value, b_value)) + ) && Object.entries(b as Record).every(([b_key, b_value]) => + Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && predicate(a_value, b_value)) ) } @@ -251,7 +251,7 @@ export class xjs_Object { Object.freeze(thing) if (xjs_Object.typeOf(thing) === 'object') { for (let key in thing) { - if (!Object.isFrozen(thing[key])) xjs_Object.freezeDeep(thing[key]) + if (!Object.isFrozen(thing[key])) xjs_Object.freezeDeep(thing[key]) } } return thing diff --git a/tsconfig.json b/tsconfig.json index 3af7f5c..07c2449 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,18 +9,16 @@ "strict": true, // Modules - "module": "ES2020", - "moduleResolution": "Node", + "module": "node16", // Emit - "declaration": true, - "importsNotUsedAsValues": "error", - "noEmitOnError": true, - "outDir": "./dist/", + "declaration": true, + "noEmitOnError": true, + "outDir": "./dist/", // Language and Environment - "target": "ES2022", - "useDefineForClassFields": false, + "target": "es2022", + "useDefineForClassFields": false, // instance fields using `[[define]]` semantics don’t play nicely with constructor parameter fields // Completeness "skipLibCheck": true, From 06b85b6bb995816d9a41f1d3f715a83ed61ce954 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 10:33:51 -0400 Subject: [PATCH 06/33] fresh install eslint & plugins --- package-lock.json | 1280 ++++++++++++++++++++++++++++++++++++++++++--- package.json | 3 + 2 files changed, 1217 insertions(+), 66 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4af92c..f4c9ad1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,9 @@ "devDependencies": { "@types/mocha": "^10.0.0", "@types/node": "^20.0.0", + "@typescript-eslint/eslint-plugin": "^5.61.0", + "@typescript-eslint/parser": "^5.61.0", + "eslint": "^8.44.0", "mocha": "^10.0.0", "ts-node": "^10.0.0", "typedoc": "^0.24.0", @@ -20,6 +23,15 @@ "node": ">=18" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -32,6 +44,95 @@ "node": ">=12" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", @@ -57,6 +158,41 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -81,6 +217,12 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, "node_modules/@types/mocha": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", @@ -88,15 +230,209 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz", + "integrity": "sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==", "dev": true }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz", + "integrity": "sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.61.0", + "@typescript-eslint/type-utils": "5.61.0", + "@typescript-eslint/utils": "5.61.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.61.0.tgz", + "integrity": "sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.61.0", + "@typescript-eslint/types": "5.61.0", + "@typescript-eslint/typescript-estree": "5.61.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.61.0.tgz", + "integrity": "sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.61.0", + "@typescript-eslint/visitor-keys": "5.61.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.61.0.tgz", + "integrity": "sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.61.0", + "@typescript-eslint/utils": "5.61.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.61.0.tgz", + "integrity": "sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.61.0.tgz", + "integrity": "sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.61.0", + "@typescript-eslint/visitor-keys": "5.61.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.61.0.tgz", + "integrity": "sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.61.0", + "@typescript-eslint/types": "5.61.0", + "@typescript-eslint/typescript-estree": "5.61.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.61.0.tgz", + "integrity": "sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.61.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -105,6 +441,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-walk": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", @@ -114,6 +459,22 @@ "node": ">=0.4.0" } }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -178,6 +539,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -194,12 +564,13 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -220,6 +591,15 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -248,18 +628,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -287,6 +655,18 @@ "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -328,6 +708,20 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -345,12 +739,6 @@ } } }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/decamelize": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", @@ -363,6 +751,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -372,6 +766,30 @@ "node": ">=0.3.1" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -399,6 +817,256 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -436,6 +1104,25 @@ "flat": "cli.js" } }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -486,39 +1173,58 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { - "node": "*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -537,6 +1243,40 @@ "he": "bin/he" } }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -604,6 +1344,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -625,6 +1374,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -637,12 +1392,37 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -658,20 +1438,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lunr": { @@ -698,16 +1496,38 @@ "node": ">= 12" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" + "node": "*" } }, "node_modules/mocha": { @@ -750,12 +1570,54 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/ms": { + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/nanoid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", @@ -768,6 +1630,18 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -786,6 +1660,23 @@ "wrappy": "1" } }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -816,6 +1707,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -834,6 +1737,24 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -846,6 +1767,44 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -876,6 +1835,63 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -896,6 +1912,21 @@ } ] }, + "node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -905,6 +1936,27 @@ "randombytes": "^2.1.0" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/shiki": { "version": "0.14.3", "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", @@ -917,6 +1969,15 @@ "vscode-textmate": "^8.0.0" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -956,20 +2017,23 @@ } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1034,6 +2098,51 @@ "node": ">=0.3.1" } }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typedoc": { "version": "0.24.8", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", @@ -1055,6 +2164,15 @@ "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" } }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/typedoc/node_modules/minimatch": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.2.tgz", @@ -1071,9 +2189,9 @@ } }, "node_modules/typescript": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", - "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -1083,6 +2201,15 @@ "node": ">=14.17" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -1101,6 +2228,21 @@ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -1139,6 +2281,12 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index 0712cff..efdd987 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,9 @@ "devDependencies": { "@types/mocha": "^10.0.0", "@types/node": "^20.0.0", + "@typescript-eslint/eslint-plugin": "^5.61.0", + "@typescript-eslint/parser": "^5.61.0", + "eslint": "^8.44.0", "mocha": "^10.0.0", "ts-node": "^10.0.0", "typedoc": "^0.24.0", From aa3760f6784466eae981d47eedb956fbb58e38cb Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 15:45:32 -0400 Subject: [PATCH 07/33] add eslint configs --- .editorconfig | 16 ++++ .eslintignore | 2 + .eslintrc.json | 225 +++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + tsconfig.json | 13 +-- 5 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintignore create mode 100644 .eslintrc.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..555ff2e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig: https://EditorConfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = tab +indent_style = tab +insert_final_newline = true +max_line_length = off +trim_trailing_whitespace = true + +[**/package{,-lock}.json] +indent_size = 2 +indent_style = space diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..1f04cba --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +/dist/ +/docs/api/ diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..8f6a656 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,225 @@ +{ + "env": { + "es2021": true, + "node": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": {"sourceType": "module"}, + "plugins": ["@typescript-eslint"], + "reportUnusedDisableDirectives": true, + "root": true, + "extends": [ + "eslint:recommended", // https://github.com/eslint/eslint/blob/main/conf/eslint-recommended.js + "plugin:@typescript-eslint/eslint-recommended", // https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslint-recommended.ts + "plugin:@typescript-eslint/recommended" // https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/recommended.ts + ], + "rules": { + /* # Overrides of Recommended Rules */ + "no-irregular-whitespace": ["error", { + "skipStrings": false, // disallow in strings + "skipComments": true // allow in comments + }], + "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], // allow smart-tabs + "@typescript-eslint/no-unused-vars": "off", // ts(6196) & tsconfig(noUnusedLocals, noUnusedParameters) + + /* # File Conventions (should be consistent with `/.editorconfig` file) */ + "eol-last": "error", + "linebreak-style": "error", + "no-trailing-spaces": "error", + + /* # Layout & Formatting */ + /* ## Indentation, Spacing, and Alignment */ + "arrow-spacing": "error", + "comma-spacing": "error", // NOTE: "@typescript-eslint/comma-spacing" is defective + "dot-location": ["error", "property"], + "func-call-spacing": "off", + "@typescript-eslint/func-call-spacing": "warn", + "generator-star-spacing": ["error", "both"], + "indent": ["error", "tab", { // NOTE: "@typescript-eslint/indent" is defective + "SwitchCase": 1, + "flatTernaryExpressions": true + }], + "key-spacing": ["error", { + "align": "value", + "mode": "minimum" + }], + "keyword-spacing": "off", + "@typescript-eslint/keyword-spacing": "error", + "rest-spread-spacing": "error", + "semi-spacing": "error", + "space-before-blocks": "off", + "@typescript-eslint/space-before-blocks": "error", + "space-before-function-paren": "off", + "@typescript-eslint/space-before-function-paren": ["warn", { + "anonymous": "always", + "asyncArrow": "always", + "named": "never" + }], + "space-infix-ops": "off", + "@typescript-eslint/space-infix-ops": "error", + "space-unary-ops": "error", + "switch-colon-spacing": "error", + "template-curly-spacing": ["error", "always"], + "template-tag-spacing": "error", + "yield-star-spacing": ["error", "both"], + + /* ## Grouping Structure Style */ + "array-bracket-newline": ["error", "consistent"], // FIXME: require line breaks exactly when there exist line breaks between elements (ignoring inside elements) + "array-bracket-spacing": "warn", + "array-element-newline": ["error", "consistent"], + "arrow-body-style": "error", + "brace-style": "off", + "@typescript-eslint/brace-style": "error", + "computed-property-spacing": "error", + "curly": "error", + "function-call-argument-newline": ["error", "consistent"], + "function-paren-newline": "error", + "func-style": ["error", "declaration", {"allowArrowFunctions": true}], + "lines-between-class-members": "off", + "@typescript-eslint/lines-between-class-members": ["error", "always", {"exceptAfterSingleLine": true}], + "no-useless-computed-key": ["error", {"enforceForClassMembers": true}], + "object-curly-newline": ["error", { + "ObjectExpression": {"multiline": true}, + "ObjectPattern": {"multiline": true}, + "ImportDeclaration": {"multiline": true, "minProperties": 2}, + "ExportDeclaration": {"multiline": true, "minProperties": 2} + }], + "object-curly-spacing": "off", + "@typescript-eslint/object-curly-spacing": "warn", + "object-property-newline": ["error", {"allowAllPropertiesOnSameLine": true}], + "object-shorthand": ["error", "properties", {"avoidQuotes": true}], + "padded-blocks": ["error", "never"], + "quote-props": ["error", "consistent-as-needed"], + "space-in-parens": "warn", + + /* ## Operator Style */ + "arrow-parens": "error", + "comma-dangle": "off", + "@typescript-eslint/comma-dangle": ["error", "always-multiline"], + "comma-style": "error", + "dot-notation": "error", + "implicit-arrow-linebreak": "error", + "new-parens": "error", + "operator-linebreak": ["error", "before", { + "overrides": { + "=": "none", + "*=": "none", + "/=": "none", + "%=": "none", + "+=": "none", + "-=": "none", + "<<=": "none", + ">>=": "none", + ">>>=": "none", + "&=": "none", + "^=": "none", + "|=": "none", + "**=": "none", + "&&=": "none", + "||=": "none", + "??=": "none", + ":": "ignore" + } + }], + "quotes": ["error", "single"], + "semi": "off", + "@typescript-eslint/semi": "error", + "semi-style": "error", + "wrap-iife": ["error", "inside", {"functionPrototypeMethods": true}], + + /* # Best Practices */ + /* ## Preferred Operators */ + "eqeqeq": "error", + "no-useless-concat": "error", + "operator-assignment": "error", + "prefer-object-spread": "error", + "prefer-template": "error", + + /* ## Variable Declarations */ + "init-declarations": "off", + "@typescript-eslint/init-declarations": "error", + "no-shadow": "off", + "@typescript-eslint/no-shadow": "error", + "no-use-before-define": "off", + "@typescript-eslint/no-use-before-define": ["error", {"ignoreTypeReferences": false}], + "one-var": ["error", "never"], + + /* ## Function Design */ + "default-param-last": "off", + "@typescript-eslint/default-param-last": "error", + "func-names": ["error", "never"], + "no-return-await": "error", + "no-useless-constructor": "off", + "@typescript-eslint/no-useless-constructor": "error", + "prefer-arrow-callback": ["error", {"allowUnboundThis": false}] + }, + "overrides": [ + { + "files": ["*.{cts,mts,ts}"], + "parserOptions": { + "project": [ + "./tsconfig.json", + "./test/tsconfig.json", + "./tree-sitter-counterpoint/tsconfig.json", + "./tree-sitter-counterpoint/test/tsconfig.json" + ] + }, + "rules": { + /* # Overrides of Recommended Rules */ + "@typescript-eslint/no-explicit-any": ["error", {"fixToUnknown": true}], // report as errors & quickfix `any` to `unknown` + "@typescript-eslint/no-inferrable-types": "off", // don’t rely on TypeScript inference + "@typescript-eslint/no-non-null-assertion": "off", // non-null assertions can be useful + + /* # Layout & Formatting */ + /* ## Indentation, Spacing, and Alignment */ + "@typescript-eslint/type-annotation-spacing": "error", + + /* ## Grouping Structure Style */ + "@typescript-eslint/adjacent-overload-signatures": "error", + "@typescript-eslint/member-delimiter-style": ["error", { + "overrides": { + "typeLiteral": { + "multiline": {"delimiter": "comma"}, + "singleline": {"delimiter": "comma"} + } + } + }], + + /* ## Operator Style */ + "dot-notation": "off", + "@typescript-eslint/dot-notation": "error", // needed here due to `parserOptions.project` + + /* ## Type Annotations */ + "@typescript-eslint/array-type": ["error", { + "default": "array-simple", + "readonly": "array" + }], + "@typescript-eslint/consistent-generic-constructors": "error", + "@typescript-eslint/consistent-indexed-object-style": "error", + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/consistent-type-imports": "error", + "@typescript-eslint/explicit-function-return-type": ["error", { + "allowExpressions": true, + "allowHigherOrderFunctions": false + }], + "@typescript-eslint/no-import-type-side-effects": "error", + + /* # Best Practices */ + /* ## Conciseness */ + "@typescript-eslint/no-unnecessary-condition": "error", + "@typescript-eslint/no-unnecessary-type-arguments": "error", + + /* ## Function Design */ + "no-return-await": "off", + "@typescript-eslint/return-await": "error", // needed here due to `parserOptions.project` // NOTE: overrides "no-return-await" (despite different name) + + /* ## Strictness */ + "@typescript-eslint/explicit-member-accessibility": "error", + "@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error", + "@typescript-eslint/no-unnecessary-type-assertion": "error", + "@typescript-eslint/non-nullable-type-assertion-style": "error", + "@typescript-eslint/prefer-readonly": "error" + } + } + ] +} diff --git a/package.json b/package.json index efdd987..37d6265 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "url": "git+https://github.com/chharvey/extrajs.git" }, "scripts": { + "predist": "eslint . --ext .cjs,.cts,.js,.mjs,.mts,.ts", "dist": "tsc", "test": "mocha -r ts-node/esm --loader='ts-node/esm' './test/*.ts'", "docs": "typedoc", diff --git a/tsconfig.json b/tsconfig.json index 07c2449..ef4e125 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,13 @@ { "compilerOptions": { // Type Checking - "exactOptionalPropertyTypes": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "strict": true, + "exactOptionalPropertyTypes": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true, // Modules "module": "node16", From 458174b225caa207e4fc59f4e4f0d3820ff6fbff Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:15:25 -0400 Subject: [PATCH 08/33] style: update formatting & whitespace --- src/class/Array.class.ts | 204 ++++++------ src/class/BigInt.class.ts | 62 ++-- src/class/Date.class.ts | 200 ++++++------ src/class/IndexOutOfBoundsError.class.ts | 6 +- src/class/Map.class.ts | 32 +- src/class/Math.class.ts | 145 ++++---- src/class/NaNError.class.ts | 4 +- src/class/Number.class.ts | 76 +++-- src/class/Object.class.ts | 399 ++++++++++++----------- src/class/Promise.class.ts | 16 +- src/class/Set.class.ts | 40 +-- src/class/String.class.ts | 44 +-- test/Array.test.ts | 182 +++++------ test/BigInt.test.ts | 34 +- test/Date.test.ts | 38 +-- test/Map.test.ts | 8 +- test/Math.test.ts | 118 +++---- test/Number.test.ts | 55 ++-- test/Object.test.ts | 92 +++--- test/Promise.test.ts | 16 +- test/Set.test.ts | 66 ++-- test/String.test.ts | 28 +- 22 files changed, 955 insertions(+), 910 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index 76b91e9..fcf7d4d 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -20,9 +20,11 @@ export class xjs_Array { * @throws {IndexOutOfBoundsError} if the index is out of bounds (or if the returned value is `undefined`) */ static get(arr: T[], index: number): T { - xjs_Number.assertType(index) - if (arr[index] === void 0) throw new IndexOutOfBoundsError(index) - return arr[index] + xjs_Number.assertType(index); + if (arr[index] === void 0) { + throw new IndexOutOfBoundsError(index); + } + return arr[index]; } /** @@ -58,31 +60,37 @@ export class xjs_Array { */ static contains(larger: readonly T[], smaller: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { if (smaller.length > larger.length) { - throw new RangeError('First argument cannot be smaller than the second. Try switching the arguments.') + throw new RangeError('First argument cannot be smaller than the second. Try switching the arguments.'); + } + if (xjs_Array.is(smaller, [], predicate)) { + return true; } - if (xjs_Array.is(smaller, [] , predicate)) return true - if (xjs_Array.is(smaller, larger, predicate)) return true - return larger.map((_el, i) => larger.slice(i, i+smaller.length)).some((sub) => xjs_Array.is(smaller, sub, predicate)) + if (xjs_Array.is(smaller, larger, predicate)) { + return true; + } + return larger.map((_el, i) => larger.slice(i, i + smaller.length)).some((sub) => xjs_Array.is(smaller, sub, predicate)); } - /** - * Test whether two arrays have “the same” elements. - * + /** + * Test whether two arrays have “the same” elements. + * * Note: Use this method only if providing a predicate. * If testing for “same-value-zero” equality (the default predicate), use * Node.js’s built-in `assert.deepStrictEqual()` instead. * - * Shortcut of {@link xjs_Object.is}, but for arrays. - * Warning: passing in sparse arrays can yield unexpected results. + * Shortcut of {@link xjs_Object.is}, but for arrays. + * Warning: passing in sparse arrays can yield unexpected results. * @typeparam T - the type of elements in `a` and `b` - * @param a the first array - * @param b the second array + * @param a the first array + * @param b the second array * @param predicate check the “sameness” of corresponding elements of `a` and `b` - * @returns Are corresponding elements the same, i.e. replaceable? - */ + * @returns Are corresponding elements the same, i.e. replaceable? + */ static is(a: readonly T[], b: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { - if (a === b) return true - return a.length === b.length && a.every((el, i) => xjs_Object.sameValueZero(el, b[i]) || predicate(el, b[i])) + if (a === b) { + return true; + } + return a.length === b.length && a.every((el, i) => xjs_Object.sameValueZero(el, b[i]) || predicate(el, b[i])); } /** @@ -105,13 +113,12 @@ export class xjs_Array { */ static isSubarrayOf(a: readonly T[], b: readonly U[], predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { return a.length <= b.length && ( - a.length === 0 || xjs_Array.is(a, b, predicate) || - a.map((t) => - b.findIndex((u) => predicate(u, t)) // indices of `b`’s elements in the order in which they appear in `a` - ).every((n, i, indices) => - n >= 0 && (i === 0 || indices[i] > indices[i-1]) // indices must all be 0+ and increasing (all of `a`’s elements are present in `b` and in the right order) - ) - ) + a.length === 0 + || xjs_Array.is(a, b, predicate) + || a + .map((t) => b.findIndex((u) => predicate(u, t))) // indices of `b`’s elements in the order in which they appear in `a` + .every((n, i, indices) => n >= 0 && (i === 0 || indices[i] > indices[i - 1])) // indices must all be 0+ and increasing (all of `a`’s elements are present in `b` and in the right order) + ); } /** @@ -124,7 +131,7 @@ export class xjs_Array { * @returns exactly `xjs_Array.isSubarrayOf(b, a, predicate)` */ static isSuperarrayOf(a: readonly T[], b: readonly U[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { - return xjs_Array.isSubarrayOf(b, a, predicate) + return xjs_Array.isSubarrayOf(b, a, predicate); } /** @@ -137,8 +144,7 @@ export class xjs_Array { * @returns Is `a` a consecutive subarray of `b`? */ static isConsecutiveSubarrayOf(a: readonly T[], b: readonly U[], predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { - return xjs_Array.isSubarrayOf(a, b, predicate) && - b.map((_el, i) => b.slice(i, i+a.length)).some((sub) => xjs_Array.is(a, sub, predicate)) + return xjs_Array.isSubarrayOf(a, b, predicate) && b.map((_el, i) => b.slice(i, i + a.length)).some((sub) => xjs_Array.is(a, sub, predicate)); } /** @@ -151,7 +157,7 @@ export class xjs_Array { * @returns exactly `xjs_Array.isConsecutiveSubarrayOf(b, a, predicate)` */ static isConsecutiveSuperarrayOf(a: readonly T[], b: readonly U[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { - return xjs_Array.isConsecutiveSubarrayOf(b, a, predicate) + return xjs_Array.isConsecutiveSubarrayOf(b, a, predicate); } /** @@ -162,9 +168,11 @@ export class xjs_Array { * @throws {RangeError} if the array is empty */ static peek(arr: readonly T[]): T { - if (!arr.length) throw new RangeError('Cannot peek an empty array.') - return arr[arr.length - 1] - // return arr.slice(-1)[0] + if (!arr.length) { + throw new RangeError('Cannot peek an empty array.'); + } + return arr[arr.length - 1]; + // return arr.slice(-1)[0]; } /** @@ -175,9 +183,9 @@ export class xjs_Array { * @param this_arg object to use as `this` when executing `predicate` * @returns a new array with the elements that pass the test; if no elements pass, an empty array is returned */ - static async filterAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise|boolean, this_arg: unknown = null): Promise { - let tests: boolean[] = await Promise.all(arr.map((el, i) => predicate.call(this_arg, el, i, arr))) - return arr.filter((_, i) => tests[i]) + static async filterAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise | boolean, this_arg: unknown = null): Promise { + let tests: boolean[] = await Promise.all(arr.map((el, i) => predicate.call(this_arg, el, i, arr))); + return arr.filter((_, i) => tests[i]); } /** @@ -188,8 +196,8 @@ export class xjs_Array { * @param this_arg object to use as `this` when executing `predicate` * @returns the item found, or `null` if none is found */ - static async findAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise|boolean, this_arg: unknown = null): Promise { - return (await xjs_Array.filterAsync(arr, predicate, this_arg))[0] || null + static async findAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise | boolean, this_arg: unknown = null): Promise { + return (await xjs_Array.filterAsync(arr, predicate, this_arg))[0] || null; } /** @@ -279,7 +287,7 @@ export class xjs_Array { * @throws {Error} if one iteration throws an error */ static mapAggregated(array: readonly T[], callback: (item: T, i: number, src: readonly T[]) => U): U[] { - const results: ([U, true] | [Error, false])[] = array.map((it, i, src) => { + const results: Array<[U, true] | [Error, false]> = array.map((it, i, src) => { try { return [callback(it, i, src), true]; } catch (err) { @@ -296,58 +304,64 @@ export class xjs_Array { } } - /** - * Deep freeze an array, and return the result. - * - * Shortcut of {@link xjs_Object.freezeDeep}, but for arrays. - * Warning: passing in a sparse array can yield unexpected results. - * *Note: This function is impure, modifying the given argument.* - * @param arr the array to freeze - * @returns the given array, with everything frozen - * @deprecated use interface `readonly T[]` instead - */ - static freezeDeep(arr: readonly T[]): readonly T[] { - Object.freeze(arr) - arr.forEach((el) => { if (!Object.isFrozen(el)) xjs_Object.freezeDeep(el) }) - return arr - } + /** + * Deep freeze an array, and return the result. + * + * Shortcut of {@link xjs_Object.freezeDeep}, but for arrays. + * Warning: passing in a sparse array can yield unexpected results. + * *Note: This function is impure, modifying the given argument.* + * @param arr the array to freeze + * @returns the given array, with everything frozen + * @deprecated use interface `readonly T[]` instead + */ + static freezeDeep(arr: readonly T[]): readonly T[] { + Object.freeze(arr); + arr.forEach((el) => { + if (!Object.isFrozen(el)) { + xjs_Object.freezeDeep(el); + } + }); + return arr; + } - /** - * WARNING:EXPERIMENTAL - * Deep clone an array, and return the result. - * - * Shortcut of {@link xjs_Object.cloneDeep}, but for arrays. - * Warning: passing in a sparse array can yield unexpected results. + /** + * WARNING:EXPERIMENTAL + * Deep clone an array, and return the result. + * + * Shortcut of {@link xjs_Object.cloneDeep}, but for arrays. + * Warning: passing in a sparse array can yield unexpected results. * @typeparam T - the type of elements in `arr` - * @param arr the array to clone - * @returns an exact copy of the given array - */ - static cloneDeep(arr: readonly T[]): T[] { - return arr.map((el) => xjs_Object.cloneDeep(el)) - } + * @param arr the array to clone + * @returns an exact copy of the given array + */ + static cloneDeep(arr: readonly T[]): T[] { + return arr.map((el) => xjs_Object.cloneDeep(el)); + } - /** - * Make a copy of an array, and then remove duplicate entries. - * - * "Duplicate entries" are entries that considered "the same" by - * the provided predicate, or if none is given, - * {@link xjs_Object.sameValueZero}. - * Only duplicate entries are removed; the order of non-duplicates is preserved. + /** + * Make a copy of an array, and then remove duplicate entries. + * + * "Duplicate entries" are entries that considered "the same" by + * the provided predicate, or if none is given, + * {@link xjs_Object.sameValueZero}. + * Only duplicate entries are removed; the order of non-duplicates is preserved. * @typeparam T - the type of elements in `arr` - * @param arr an array to use - * @param predicate check the “sameness” of elements in the array - * @returns a new array, with duplicates removed - * @deprecated use `[...new Set(arr)]` instead - */ - static removeDuplicates(arr: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): T[] { - const returned: T[] = arr.slice() - for (let i = 0; i < returned.length; i++) { - for (let j = i + 1; j < returned.length; j++) { - if (predicate(returned[i], returned[j])) returned.splice(j, 1) - } - } - return returned - } + * @param arr an array to use + * @param predicate check the “sameness” of elements in the array + * @returns a new array, with duplicates removed + * @deprecated use `[...new Set(arr)]` instead + */ + static removeDuplicates(arr: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): T[] { + const returned: T[] = arr.slice(); + for (let i = 0; i < returned.length; i++) { + for (let j = i + 1; j < returned.length; j++) { + if (predicate(returned[i], returned[j])) { + returned.splice(j, 1); + } + } + } + return returned; + } /** * Remove the ‘holes’ in an array. @@ -372,9 +386,11 @@ export class xjs_Array { * the returned array might have a smaller `length` than the argument */ static densify(arr: readonly T[]): T[] { - const newarr: T[] = [] - arr.forEach((el) => { newarr.push(el) }) // `Array#forEach` does not iterate over holes in sparse arrays - return newarr + const newarr: T[] = []; + arr.forEach((el) => { // `Array#forEach` does not iterate over holes in sparse arrays + newarr.push(el); + }); + return newarr; } /** @@ -398,13 +414,15 @@ export class xjs_Array { * the returned array will have the same length as the argument */ static fillHoles(arr: readonly T[], value: T): T[] { - const newarr: T[] = arr.slice() + const newarr: T[] = arr.slice(); for (let i = 0; i < newarr.length; i++) { // `Array#forEach` does not iterate over holes in sparse arrays - if (newarr[i] === void 0) newarr[i] = value + if (newarr[i] === void 0) { + newarr[i] = value; + } } - return newarr + return newarr; } - private constructor() {} + private constructor() {} } diff --git a/src/class/BigInt.class.ts b/src/class/BigInt.class.ts index fe15bc0..39094bd 100644 --- a/src/class/BigInt.class.ts +++ b/src/class/BigInt.class.ts @@ -1,4 +1,4 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {NumericType} from './Number.class.js'; @@ -37,42 +37,44 @@ export class xjs_BigInt { * @param type one of the string literals listed above * @throws {AssertionError} if the argument does not match the described type */ - static assertType(int: bigint, type?: NumericType|'integer'|'natural'|'whole'|'float'|'positive'|'negative'|'non-positive'|'non-negative'|'non-zero'|'finite'|'infinite'): void { - if (type === void 0) return; + static assertType(int: bigint, type?: NumericType | 'integer' | 'natural' | 'whole' | 'float' | 'positive' | 'negative' | 'non-positive' | 'non-negative' | 'non-zero' | 'finite' | 'infinite'): void { + if (type === void 0) { + return; + } if (typeof type === 'string') { console.warn(new Error(` - WARNING: Argument \`'${type}'\` was sent into \`xjs.Number.assertType\`. + WARNING: Argument \`'${ type }'\` was sent into \`xjs.Number.assertType\`. Sending a string argument is deprecated; use a member of enum \`NumericType\` instead. - `.trim())) + `.trim())); return xjs_BigInt.assertType(int, new Map([ - ['integer' , NumericType.INTEGER ], - ['natural' , NumericType.NATURAL ], - ['whole' , NumericType.WHOLE ], - ['float' , NumericType.FLOAT ], - ['positive' , NumericType.POSITIVE ], - ['negative' , NumericType.NEGATIVE ], - ['non-positive' , NumericType.NONPOSITIVE], - ['non-negative' , NumericType.NONNEGATIVE], - ['non-zero' , NumericType.NONZERO ], - ['finite' , NumericType.FINITE ], - ['infinite' , NumericType.INFINITE ], - ]).get(type)) + ['integer', NumericType.INTEGER], + ['natural', NumericType.NATURAL], + ['whole', NumericType.WHOLE], + ['float', NumericType.FLOAT], + ['positive', NumericType.POSITIVE], + ['negative', NumericType.NEGATIVE], + ['non-positive', NumericType.NONPOSITIVE], + ['non-negative', NumericType.NONNEGATIVE], + ['non-zero', NumericType.NONZERO], + ['finite', NumericType.FINITE], + ['infinite', NumericType.INFINITE], + ]).get(type)); } return new Map void>([ - [NumericType.INTEGER , (_n: bigint) => {} ], - [NumericType.NATURAL , ( n: bigint) => xjs_BigInt.assertType(n, NumericType.NONNEGATIVE) ], - [NumericType.WHOLE , ( n: bigint) => xjs_BigInt.assertType(n, NumericType.POSITIVE ) ], - [NumericType.FLOAT , (_n: bigint) => assert.ok(false , 'BigInts cannot be non-integers.')], - [NumericType.POSITIVE , ( n: bigint) => assert.ok(0n < n , `${n} must be positive.` )], - [NumericType.NEGATIVE , ( n: bigint) => assert.ok(n < 0n, `${n} must be negative.` )], - [NumericType.NONPOSITIVE , ( n: bigint) => assert.ok(n <= 0n, `${n} must not be positive.` )], - [NumericType.NONNEGATIVE , ( n: bigint) => assert.ok(0n <= n , `${n} must not be negative.` )], - [NumericType.NONZERO , ( n: bigint) => assert.ok(n !== 0n, `${n} must not be zero.` )], - [NumericType.FINITE , (_n: bigint) => {} ], - [NumericType.INFINITE , (_n: bigint) => assert.ok(false , 'BigInts cannot be infinite.' )], - ]).get(type) !(int) + [NumericType.INTEGER, (_n: bigint) => {}], + [NumericType.NATURAL, ( n: bigint) => xjs_BigInt.assertType(n, NumericType.NONNEGATIVE)], + [NumericType.WHOLE, ( n: bigint) => xjs_BigInt.assertType(n, NumericType.POSITIVE)], + [NumericType.FLOAT, (_n: bigint) => assert.ok(false, 'BigInts cannot be non-integers.')], + [NumericType.POSITIVE, ( n: bigint) => assert.ok(0n < n, `${ n } must be positive.`)], + [NumericType.NEGATIVE, ( n: bigint) => assert.ok(n < 0n, `${ n } must be negative.`)], + [NumericType.NONPOSITIVE, ( n: bigint) => assert.ok(n <= 0n, `${ n } must not be positive.`)], + [NumericType.NONNEGATIVE, ( n: bigint) => assert.ok(0n <= n, `${ n } must not be negative.`)], + [NumericType.NONZERO, ( n: bigint) => assert.ok(n !== 0n, `${ n } must not be zero.`)], + [NumericType.FINITE, (_n: bigint) => {}], + [NumericType.INFINITE, (_n: bigint) => assert.ok(false, 'BigInts cannot be infinite.')], + ]).get(type)!(int); } - private constructor() {} + private constructor() {} } diff --git a/src/class/Date.class.ts b/src/class/Date.class.ts index 7f67e65..e8daebc 100644 --- a/src/class/Date.class.ts +++ b/src/class/Date.class.ts @@ -4,111 +4,111 @@ * Does not extend the native Date class. */ export class xjs_Date { - /** - * The list of full month names in English. - */ - static readonly MONTH_NAMES = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', - ] + /** + * The list of full month names in English. + */ + static readonly MONTH_NAMES = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; - /** - * The list of full day names in English. - */ - static readonly DAY_NAMES = [ - 'Sundary', - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', - ] + /** + * The list of full day names in English. + */ + static readonly DAY_NAMES = [ + 'Sundary', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ]; - /** - * Return whether two dates occur on the same 24-hour day. - * - * That is, if both dates have the same year, same month, *and* same day (date of the month). - * @param date1 the first date - * @param date2 the second date - * @returns does 'YYYY-MM-DD' of `date1` equal 'YYYY-MM-DD' of `date2`? - */ - static sameDate(date1: Date, date2: Date): boolean { - return date1.toISOString().slice(0,10) === date2.toISOString().slice(0,10) - } + /** + * Return whether two dates occur on the same 24-hour day. + * + * That is, if both dates have the same year, same month, *and* same day (date of the month). + * @param date1 the first date + * @param date2 the second date + * @returns does 'YYYY-MM-DD' of `date1` equal 'YYYY-MM-DD' of `date2`? + */ + static sameDate(date1: Date, date2: Date): boolean { + return date1.toISOString().slice(0, 10) === date2.toISOString().slice(0, 10); + } - /** - * Return the percentage of the day that has passed at the given time. - * - * For example: - * - `00:00` => 0.00 - * - `06:00` => 0.25 - * - `12:00` => 0.50 - * - `18:00` => 0.75 - * @param date a Date object - * @returns the proportion - */ - static timeProportion(date: Date): number { - let millis = date.getUTCMilliseconds() / 1000 - let seconds = (date.getUTCSeconds() + millis) / 60 - let minutes = (date.getUTCMinutes() + seconds) / 60 - let hours = (date.getUTCHours () + minutes) / 24 - return hours - } + /** + * Return the percentage of the day that has passed at the given time. + * + * For example: + * - `00:00` => 0.00 + * - `06:00` => 0.25 + * - `12:00` => 0.50 + * - `18:00` => 0.75 + * @param date a Date object + * @returns the proportion + */ + static timeProportion(date: Date): number { + let millis = date.getUTCMilliseconds() / 1000; + let seconds = (date.getUTCSeconds() + millis) / 60; + let minutes = (date.getUTCMinutes() + seconds) / 60; + let hours = (date.getUTCHours () + minutes) / 24; + return hours; + } - /** - * Format a date, using PHP-based formatting options. - * - * The following options are supported (with examples): - * - `'Y-m-d'` : '2017-08-05' - * - `'j M Y'` : '5 Aug 2017' - * - `'d F Y'` : '05 August 2017' - * - `'l, j F, Y'` : 'Friday, 5 August, 2017' - * - `'j M'` : '5 Aug' - * - `'M Y'` : 'Aug 2017' - * - `'M j'` : 'Aug 5' - * - `'M j, Y'` : 'Aug 5, 2017' - * - `'F j, Y'` : 'August 5, 2017' - * - `'M'` : 'Aug' - * - `'H:i'` : '21:33' - * - `'g:ia'` : '9:33pm' - * - `'default'` : '2017-08-06T01:33:00.000Z' ({@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString|Date#toISOString}) - * @see http://php.net/manual/en/function.date.php - * @param date the date to format - * @param format one of the enumerated options listed in the description - * @returns a string representing the given date in the given format - */ - static format(date: Date, format: string): string { - const MONTHS = xjs_Date.MONTH_NAMES - const leadingZero = (n: number, r: number = 10) => `0${n.toString(r)}`.slice(-2) - const defaultFormatter = (date: Date) => date.toISOString() + /** + * Format a date, using PHP-based formatting options. + * + * The following options are supported (with examples): + * - `'Y-m-d'` : '2017-08-05' + * - `'j M Y'` : '5 Aug 2017' + * - `'d F Y'` : '05 August 2017' + * - `'l, j F, Y'` : 'Friday, 5 August, 2017' + * - `'j M'` : '5 Aug' + * - `'M Y'` : 'Aug 2017' + * - `'M j'` : 'Aug 5' + * - `'M j, Y'` : 'Aug 5, 2017' + * - `'F j, Y'` : 'August 5, 2017' + * - `'M'` : 'Aug' + * - `'H:i'` : '21:33' + * - `'g:ia'` : '9:33pm' + * - `'default'` : '2017-08-06T01:33:00.000Z' ({@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString|Date#toISOString}) + * @see http://php.net/manual/en/function.date.php + * @param date the date to format + * @param format one of the enumerated options listed in the description + * @returns a string representing the given date in the given format + */ + static format(date: Date, format: string): string { + const MONTHS = xjs_Date.MONTH_NAMES; + const leadingZero = (n: number, r: number = 10) => `0${ n.toString(r) }`.slice(-2); + const defaultFormatter = (date: Date) => date.toISOString(); return (new Map string>([ - ['Y-m-d' , (date: Date) => `${date.getUTCFullYear()}-${leadingZero(date.getUTCMonth()+1)}-${leadingZero(date.getUTCDate())}`], - ['j M Y' , (date: Date) => `${date.getUTCDate()} ${MONTHS[date.getUTCMonth()].slice(0,3)} ${date.getUTCFullYear()}`], - ['d F Y' , (date: Date) => `${leadingZero(date.getUTCDate())} ${MONTHS[date.getUTCMonth()]} ${date.getUTCFullYear()}`], - ['l, j F, Y' , (date: Date) => `${xjs_Date.DAY_NAMES[date.getUTCDay()]}, ${date.getUTCDate()} ${MONTHS[date.getUTCMonth()]}, ${date.getUTCFullYear()}`], - ['j M' , (date: Date) => `${date.getUTCDate()} ${MONTHS[date.getUTCMonth()].slice(0,3)}`], - ['M Y' , (date: Date) => `${MONTHS[date.getUTCMonth()].slice(0,3)} ${date.getUTCFullYear()}`], - ['M j' , (date: Date) => `${MONTHS[date.getUTCMonth()].slice(0,3)} ${date.getUTCDate()}`], - ['M j, Y' , (date: Date) => `${MONTHS[date.getUTCMonth()].slice(0,3)} ${date.getUTCDate()}, ${date.getUTCFullYear()}`], - ['F j, Y' , (date: Date) => `${MONTHS[date.getUTCMonth()]} ${date.getUTCDate()}, ${date.getUTCFullYear()}`], - ['M' , (date: Date) => `${MONTHS[date.getUTCMonth()].slice(0,3)}`], - ['H:i' , (date: Date) => `${(date.getUTCHours() < 10) ? '0' : ''}${date.getUTCHours()}:${(date.getUTCMinutes() < 10) ? '0' : ''}${date.getUTCMinutes()}`], - ['g:ia' , (date: Date) => `${(date.getUTCHours() - 1)%12 + 1}:${(date.getUTCMinutes() < 10) ? '0' : ''}${date.getUTCMinutes()}${(date.getUTCHours() < 12) ? 'am' : 'pm'}`], - ['default' , defaultFormatter], - ]).get(format || 'default') || defaultFormatter)(date) - } + ['Y-m-d', (date: Date) => `${ date.getUTCFullYear() }-${ leadingZero(date.getUTCMonth() + 1) }-${ leadingZero(date.getUTCDate()) }`], + ['j M Y', (date: Date) => `${ date.getUTCDate() } ${ MONTHS[date.getUTCMonth()].slice(0, 3) } ${ date.getUTCFullYear() }`], + ['d F Y', (date: Date) => `${ leadingZero(date.getUTCDate()) } ${ MONTHS[date.getUTCMonth()] } ${ date.getUTCFullYear() }`], + ['l, j F, Y', (date: Date) => `${ xjs_Date.DAY_NAMES[date.getUTCDay()] }, ${ date.getUTCDate() } ${ MONTHS[date.getUTCMonth()] }, ${ date.getUTCFullYear() }`], + ['j M', (date: Date) => `${ date.getUTCDate() } ${ MONTHS[date.getUTCMonth()].slice(0, 3) }`], + ['M Y', (date: Date) => `${ MONTHS[date.getUTCMonth()].slice(0, 3) } ${ date.getUTCFullYear() }`], + ['M j', (date: Date) => `${ MONTHS[date.getUTCMonth()].slice(0, 3) } ${ date.getUTCDate() }`], + ['M j, Y', (date: Date) => `${ MONTHS[date.getUTCMonth()].slice(0, 3) } ${ date.getUTCDate() }, ${ date.getUTCFullYear() }`], + ['F j, Y', (date: Date) => `${ MONTHS[date.getUTCMonth()] } ${ date.getUTCDate() }, ${ date.getUTCFullYear() }`], + ['M', (date: Date) => `${ MONTHS[date.getUTCMonth()].slice(0, 3) }`], + ['H:i', (date: Date) => `${ (date.getUTCHours() < 10) ? '0' : '' }${ date.getUTCHours() }:${ (date.getUTCMinutes() < 10) ? '0' : '' }${ date.getUTCMinutes() }`], + ['g:ia', (date: Date) => `${ (date.getUTCHours() - 1) % 12 + 1 }:${ (date.getUTCMinutes() < 10) ? '0' : '' }${ date.getUTCMinutes() }${ (date.getUTCHours() < 12) ? 'am' : 'pm' }`], + ['default', defaultFormatter], + ]).get(format || 'default') || defaultFormatter)(date); + } - private constructor() {} + private constructor() {} } diff --git a/src/class/IndexOutOfBoundsError.class.ts b/src/class/IndexOutOfBoundsError.class.ts index 7f28e3a..d952958 100644 --- a/src/class/IndexOutOfBoundsError.class.ts +++ b/src/class/IndexOutOfBoundsError.class.ts @@ -15,8 +15,8 @@ export class IndexOutOfBoundsError extends RangeError { * @param index the index that is out of bounds */ constructor(index: number); - constructor(i: string|number = 'Index out of bounds.') { - super((typeof i === 'string') ? i : `Index \`${(xjs_Number.assertType(i), i)}\` out of bounds.`) - this.name = 'IndexOutOfBoundsError' + constructor(i: string | number = 'Index out of bounds.') { + super((typeof i === 'string') ? i : `Index \`${ (xjs_Number.assertType(i), i) }\` out of bounds.`); + this.name = 'IndexOutOfBoundsError'; } } diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index 296735e..166a780 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -24,19 +24,19 @@ export class xjs_Map { /** check the “sameness” of corresponding values of `a` and `b` */ values = xjs_Object.sameValueZero, }: { - keys ?: (x: K, y: K) => boolean, - values ?: (x: V, y: V) => boolean, + keys?: (x: K, y: K) => boolean, + values?: (x: V, y: V) => boolean, } = { - keys : xjs_Object.sameValueZero, - values : xjs_Object.sameValueZero, + keys: xjs_Object.sameValueZero, + values: xjs_Object.sameValueZero, }): boolean { - if (a === b) return true - return a.size === b.size && [...a].every(([a_key, a_value]) => - [...b].some(([b_key, b_value]) => - xjs_Object.sameValueZero(a_key , b_key ) && keys (a_key , b_key ) && - xjs_Object.sameValueZero(a_value, b_value) && values(a_value, b_value) - ) - ) + if (a === b) { + return true; + } + return a.size === b.size && [...a].every(([a_key, a_value]) => [...b].some(([b_key, b_value]) => ( + xjs_Object.sameValueZero(a_key, b_key) && keys (a_key, b_key) + && xjs_Object.sameValueZero(a_value, b_value) && values(a_value, b_value) + ))); } /** @@ -50,7 +50,7 @@ export class xjs_Map { * @returns a new map with the entries that pass the test; if no entries pass, an empty map is returned */ static filter(map: ReadonlyMap, predicate: (value: V, key: K, map: ReadonlyMap) => boolean, this_arg: unknown = null): Map { - return new Map([...map].filter((entry) => predicate.call(this_arg, entry[1], entry[0], map))) + return new Map([...map].filter((entry) => predicate.call(this_arg, entry[1], entry[0], map))); } /** @@ -64,7 +64,7 @@ export class xjs_Map { * @returns the value found, or `null` if none is found */ static find(map: ReadonlyMap, predicate: (value: V, key: K, map: ReadonlyMap) => boolean, this_arg: unknown = null): V | null { - return [...xjs_Map.filter(map, predicate, this_arg)].map((entry) => entry[1])[0] || null + return [...xjs_Map.filter(map, predicate, this_arg)].map((entry) => entry[1])[0] || null; } /** @@ -78,7 +78,7 @@ export class xjs_Map { * @returns the key found, or `null` if none is found */ static findKey(map: ReadonlyMap, predicate: (key: K, index: number, map: ReadonlyMap) => boolean, this_arg: unknown = null): K | null { - return [...map.keys()].find((key, i) => predicate.call(this_arg, key, i, map)) || null + return [...map.keys()].find((key, i) => predicate.call(this_arg, key, i, map)) || null; } /** @@ -93,7 +93,7 @@ export class xjs_Map { * @returns a new Map with the same keys and transformed values obtained from `callback` */ static mapValues(map: ReadonlyMap, callback: (value: V, key: K, map: ReadonlyMap) => T, this_arg: unknown = null): Map { - return new Map([...map].map(([key, value]) => [key, callback.call(this_arg, value, key, map)] as [K, T])) + return new Map([...map].map(([key, value]) => [key, callback.call(this_arg, value, key, map)] as [K, T])); } /** @@ -108,7 +108,7 @@ export class xjs_Map { * @returns a new Map with transformed keys obtained from `callback` and the same values */ static mapKeys(map: ReadonlyMap, callback: (value: V, key: K, map: ReadonlyMap) => T, this_arg: unknown = null): Map { - return new Map([...map].map(([key, value]) => [callback.call(this_arg, value, key, map), value] as [T, V])) + return new Map([...map].map(([key, value]) => [callback.call(this_arg, value, key, map), value] as [T, V])); } /** diff --git a/src/class/Math.class.ts b/src/class/Math.class.ts index 538bf40..55a5f3e 100644 --- a/src/class/Math.class.ts +++ b/src/class/Math.class.ts @@ -1,4 +1,7 @@ -import {xjs_Number, NumericType} from './Number.class.js'; +import { + xjs_Number, + NumericType, +} from './Number.class.js'; import {xjs_BigInt} from './BigInt.class.js'; @@ -19,10 +22,10 @@ export class xjs_Math { * @returns are `x` and `y` within `epsilon` distance apart? */ static approx(x: number, y: number, epsilon: number = Number.EPSILON): boolean { - xjs_Number.assertType(x) - xjs_Number.assertType(y) - xjs_Number.assertType(epsilon) - return Math.abs(x - y) < epsilon + xjs_Number.assertType(x); + xjs_Number.assertType(y); + xjs_Number.assertType(epsilon); + return Math.abs(x - y) < epsilon; } /** @@ -34,7 +37,7 @@ export class xjs_Math { * @returns exactly `interpolateArithmetic(x, y, w)` */ static average(x: number, y: number, w = 0.5): number { - return xjs_Math.interpolateArithmetic(x, y, w) + return xjs_Math.interpolateArithmetic(x, y, w); } /** @@ -44,8 +47,10 @@ export class xjs_Math { * @throws if no arguments are supplied */ static minBigInt(...ints: bigint[]): bigint { - if (!ints.length) throw new Error('No arguments supplied.') - return ints.reduce((a, b) => a < b ? a : b) + if (!ints.length) { + throw new Error('No arguments supplied.'); + } + return ints.reduce((a, b) => a < b ? a : b); } /** @@ -55,8 +60,10 @@ export class xjs_Math { * @throws if no arguments are supplied */ static maxBigInt(...ints: bigint[]): bigint { - if (!ints.length) throw new Error('No arguments supplied.') - return ints.reduce((a, b) => a < b ? b : a) + if (!ints.length) { + throw new Error('No arguments supplied.'); + } + return ints.reduce((a, b) => a < b ? b : a); } /** @@ -73,10 +80,10 @@ export class xjs_Math { * @returns `Math.min(Math.max(min, x), max)` */ static clamp(min: number, val: number, max: number): number { - xjs_Number.assertType(min) - xjs_Number.assertType(val) - xjs_Number.assertType(max) - return (min <= max) ? Math.min(Math.max(min, val), max) : xjs_Math.clamp(max, val, min) + xjs_Number.assertType(min); + xjs_Number.assertType(val); + xjs_Number.assertType(max); + return (min <= max) ? Math.min(Math.max(min, val), max) : xjs_Math.clamp(max, val, min); } /** @@ -87,7 +94,7 @@ export class xjs_Math { * @returns the clamped value */ static clampBigInt(min: bigint, val: bigint, max: bigint): bigint { - return (min <= max) ? xjs_Math.minBigInt(xjs_Math.maxBigInt(min, val), max) : xjs_Math.clampBigInt(max, val, min) + return (min <= max) ? xjs_Math.minBigInt(xjs_Math.maxBigInt(min, val), max) : xjs_Math.clampBigInt(max, val, min); } /** @@ -103,8 +110,8 @@ export class xjs_Math { * @throws {NaNError} if one of the numbers is `NaN` */ static meanArithmetic(...nums: number[]): number { - nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)) // NB re-throw - return nums.reduce((x, y) => x + y) * (1 / nums.length) + nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)); // NB re-throw + return nums.reduce((x, y) => x + y) * (1 / nums.length); } /** @@ -120,8 +127,8 @@ export class xjs_Math { * @throws {NaNError} if one of the numbers is `NaN` */ static meanGeometric(...nums: number[]): number { - nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)) // NB re-throw - return Math.abs(nums.reduce((x, y) => x * y)) ** (1 / nums.length) + nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)); // NB re-throw + return Math.abs(nums.reduce((x, y) => x * y)) ** (1 / nums.length); } /** @@ -137,8 +144,8 @@ export class xjs_Math { * @throws {NaNError} if one of the numbers is `NaN` */ static meanHarmonic(...nums: number[]): number { - nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)) // NB re-throw - return 1 / xjs_Math.meanArithmetic(...nums.map((x) => 1 / x)) + nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)); // NB re-throw + return 1 / xjs_Math.meanArithmetic(...nums.map((x) => 1 / x)); } /** @@ -165,10 +172,10 @@ export class xjs_Math { * @throws {NaNError} if an argument is `NaN` */ static interpolateArithmetic(a: number, b: number, p: number = 0.5): number { - xjs_Number.assertType(a, NumericType.FINITE) - xjs_Number.assertType(b, NumericType.FINITE) - xjs_Number.assertType(p, NumericType.FINITE) - return a * (1 - p) + (b * p) // equally, `(b - a) * p + a` + xjs_Number.assertType(a, NumericType.FINITE); + xjs_Number.assertType(b, NumericType.FINITE); + xjs_Number.assertType(p, NumericType.FINITE); + return a * (1 - p) + (b * p); // equally, `(b - a) * p + a` } /** @@ -195,10 +202,10 @@ export class xjs_Math { * @throws {NaNError} if an argument is `NaN` */ static interpolateGeometric(a: number, b: number, p: number = 0.5): number { - xjs_Number.assertType(a, NumericType.FINITE) - xjs_Number.assertType(b, NumericType.FINITE) - xjs_Number.assertType(p, NumericType.FINITE) - return a ** (1 - p) * b ** p // equally, `a * (b / a) ** p` + xjs_Number.assertType(a, NumericType.FINITE); + xjs_Number.assertType(b, NumericType.FINITE); + xjs_Number.assertType(p, NumericType.FINITE); + return a ** (1 - p) * b ** p; // equally, `a * (b / a) ** p` } /** @@ -225,10 +232,10 @@ export class xjs_Math { * @throws {NaNError} if an argument is `NaN` */ static interpolateHarmonic(a: number, b: number, p: number = 0.5): number { - xjs_Number.assertType(a, NumericType.FINITE) - xjs_Number.assertType(b, NumericType.FINITE) - xjs_Number.assertType(p, NumericType.FINITE) - return 1 / xjs_Math.interpolateArithmetic(1/a, 1/b, p) // equally, `(a * b) / ((a - b) * p + b)` + xjs_Number.assertType(a, NumericType.FINITE); + xjs_Number.assertType(b, NumericType.FINITE); + xjs_Number.assertType(p, NumericType.FINITE); + return 1 / xjs_Math.interpolateArithmetic(1 / a, 1 / b, p); // equally, `(a * b) / ((a - b) * p + b)` } /** @@ -242,47 +249,47 @@ export class xjs_Math { * @returns exactly `((x % n) + n) % n` * @throws {Error} if `n` is not a positive integer */ - static mod(x: number, n: number|bigint): number { - xjs_Number.assertType(x, NumericType.FINITE) + static mod(x: number, n: number | bigint): number { + xjs_Number.assertType(x, NumericType.FINITE); if (typeof n === 'number') { - xjs_Number.assertType(n, NumericType.WHOLE) + xjs_Number.assertType(n, NumericType.WHOLE); } else { - xjs_BigInt.assertType(n, NumericType.WHOLE) + xjs_BigInt.assertType(n, NumericType.WHOLE); } - n = Number(n) - return ((x % n) + n) % n + n = Number(n); + return ((x % n) + n) % n; } - /** - * Return the `n`th tetration of `x`. - * - * Tetration is considered the next hyperoperation after exponentiation - * (which follows multiplication, following addition). - * For example, `tetrate(5, 3)` returns the result of `5 ** 5 ** 5`: repeated exponentiation. - * (Note that with ambiguous grouping, `a ** b ** c` is equal to `a ** (b ** c)`.) - * If there were a native JavaScript operator for tetration, - * it might be a triple-asterisk: `5 *** 3`. - * - * Currently, there is only support for non-negative integer hyperexponents. - * Negative numbers and non-integers are not yet allowed. - * - * ```js - * tetrate(5, 3) // returns 5 ** 5 ** 5 // equal to 5 ** (5 ** 5) - * tetrate(5, 1) // returns 5 - * tetrate(5, 0) // returns 1 - * ``` - * - * @param x the root, any number - * @param n the hyper-exponent to which the root is raised, a non-negative integer - * @returns informally, `x *** n` - * @throws {Error} if `n` is not a non-negative integer - */ - static tetrate(x: number, n: number): number { - xjs_Number.assertType(x, NumericType.FINITE) - xjs_Number.assertType(n, NumericType.NATURAL) - return (n === 0) ? 1 : x ** xjs_Math.tetrate(x, n - 1) - } + /** + * Return the `n`th tetration of `x`. + * + * Tetration is considered the next hyperoperation after exponentiation + * (which follows multiplication, following addition). + * For example, `tetrate(5, 3)` returns the result of `5 ** 5 ** 5`: repeated exponentiation. + * (Note that with ambiguous grouping, `a ** b ** c` is equal to `a ** (b ** c)`.) + * If there were a native JavaScript operator for tetration, + * it might be a triple-asterisk: `5 *** 3`. + * + * Currently, there is only support for non-negative integer hyperexponents. + * Negative numbers and non-integers are not yet allowed. + * + * ```js + * tetrate(5, 3) // returns 5 ** 5 ** 5 // equal to 5 ** (5 ** 5) + * tetrate(5, 1) // returns 5 + * tetrate(5, 0) // returns 1 + * ``` + * + * @param x the root, any number + * @param n the hyper-exponent to which the root is raised, a non-negative integer + * @returns informally, `x *** n` + * @throws {Error} if `n` is not a non-negative integer + */ + static tetrate(x: number, n: number): number { + xjs_Number.assertType(x, NumericType.FINITE); + xjs_Number.assertType(n, NumericType.NATURAL); + return (n === 0) ? 1 : x ** xjs_Math.tetrate(x, n - 1); + } - private constructor() {} + private constructor() {} } diff --git a/src/class/NaNError.class.ts b/src/class/NaNError.class.ts index 7569c09..38e4b43 100644 --- a/src/class/NaNError.class.ts +++ b/src/class/NaNError.class.ts @@ -7,7 +7,7 @@ export class NaNError extends RangeError { * @param message Optional. A human-readable description of the error. */ constructor(message: string = 'Unacceptable argument `NaN`.') { - super(message) - this.name = 'NaNError' + super(message); + this.name = 'NaNError'; } } diff --git a/src/class/Number.class.ts b/src/class/Number.class.ts index fa88302..66f4a16 100644 --- a/src/class/Number.class.ts +++ b/src/class/Number.class.ts @@ -1,4 +1,4 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {NaNError} from './NaNError.class.js'; import {xjs_Object} from './Object.class.js'; @@ -27,7 +27,7 @@ export class xjs_Number { /** * An immutable RegExp instance, representing a string in Number format. */ - static readonly REGEXP: Readonly = /^-?(?:\d+(?:\.\d+)?|\.\d+)$/ + static readonly REGEXP: Readonly = /^-?(?:\d+(?:\.\d+)?|\.\d+)$/; /** * Verify the type of number given, throwing if it does not match. @@ -58,41 +58,45 @@ export class xjs_Number { * @throws {AssertionError} if the argument does not match the described type * @throws {NaNError} if the argument is `NaN` */ - static assertType(num: number, type?: NumericType|'integer'|'natural'|'whole'|'float'|'positive'|'negative'|'non-positive'|'non-negative'|'non-zero'|'finite'|'infinite'): void { - if (Number.isNaN(num)) throw new NaNError() - if (type === void 0) return; + static assertType(num: number, type?: NumericType | 'integer' | 'natural' | 'whole' | 'float' | 'positive' | 'negative' | 'non-positive' | 'non-negative' | 'non-zero' | 'finite' | 'infinite'): void { + if (Number.isNaN(num)) { + throw new NaNError(); + } + if (type === void 0) { + return; + } if (typeof type === 'string') { console.warn(new Error(` - WARNING: Argument \`'${type}'\` was sent into \`xjs.Number.assertType\`. + WARNING: Argument \`'${ type }'\` was sent into \`xjs.Number.assertType\`. Sending a string argument is deprecated; use a member of enum \`NumericType\` instead. - `.trim())) + `.trim())); return xjs_Number.assertType(num, new Map([ - ['integer' , NumericType.INTEGER ], - ['natural' , NumericType.NATURAL ], - ['whole' , NumericType.WHOLE ], - ['float' , NumericType.FLOAT ], - ['positive' , NumericType.POSITIVE ], - ['negative' , NumericType.NEGATIVE ], - ['non-positive' , NumericType.NONPOSITIVE], - ['non-negative' , NumericType.NONNEGATIVE], - ['non-zero' , NumericType.NONZERO ], - ['finite' , NumericType.FINITE ], - ['infinite' , NumericType.INFINITE ], - ]).get(type)) + ['integer', NumericType.INTEGER], + ['natural', NumericType.NATURAL], + ['whole', NumericType.WHOLE], + ['float', NumericType.FLOAT], + ['positive', NumericType.POSITIVE], + ['negative', NumericType.NEGATIVE], + ['non-positive', NumericType.NONPOSITIVE], + ['non-negative', NumericType.NONNEGATIVE], + ['non-zero', NumericType.NONZERO], + ['finite', NumericType.FINITE], + ['infinite', NumericType.INFINITE], + ]).get(type)); } return new Map void>([ - [NumericType.INTEGER , (n: number) => assert.ok( Number.isInteger(n) , `${n} must be an integer.` )], - [NumericType.NATURAL , (n: number) => assert.ok( Number.isInteger(n) && 0 <= n, `${n} must be a non-negative integer.`)], - [NumericType.WHOLE , (n: number) => assert.ok( Number.isInteger(n) && 0 < n, `${n} must be a positive integer.` )], - [NumericType.FLOAT , (n: number) => assert.ok(!Number.isInteger(n) , `${n} must not be an integer.` )], - [NumericType.POSITIVE , (n: number) => assert.ok(0 < n , `${n} must be a positive number.` )], - [NumericType.NEGATIVE , (n: number) => assert.ok(n < 0 , `${n} must be a negative number.` )], - [NumericType.NONPOSITIVE , (n: number) => assert.ok(n <= 0 , `${n} must not be a positive number.` )], - [NumericType.NONNEGATIVE , (n: number) => assert.ok(0 <= n , `${n} must not be a negative number.` )], - [NumericType.NONZERO , (n: number) => assert.ok(n !== 0 , `${n} must not be zero.` )], - [NumericType.FINITE , (n: number) => assert.ok( Number.isFinite(n) , `${n} must be a finite number.` )], - [NumericType.INFINITE , (n: number) => assert.ok(!Number.isFinite(n) , `${n} must be an infinite number.` )], - ]).get(type) !(num) + [NumericType.INTEGER, (n: number) => assert.ok(Number.isInteger(n), `${ n } must be an integer.`)], + [NumericType.NATURAL, (n: number) => assert.ok(Number.isInteger(n) && 0 <= n, `${ n } must be a non-negative integer.`)], + [NumericType.WHOLE, (n: number) => assert.ok(Number.isInteger(n) && 0 < n, `${ n } must be a positive integer.`)], + [NumericType.FLOAT, (n: number) => assert.ok(!Number.isInteger(n), `${ n } must not be an integer.`)], + [NumericType.POSITIVE, (n: number) => assert.ok(0 < n, `${ n } must be a positive number.`)], + [NumericType.NEGATIVE, (n: number) => assert.ok(n < 0, `${ n } must be a negative number.`)], + [NumericType.NONPOSITIVE, (n: number) => assert.ok(n <= 0, `${ n } must not be a positive number.`)], + [NumericType.NONNEGATIVE, (n: number) => assert.ok(0 <= n, `${ n } must not be a negative number.`)], + [NumericType.NONZERO, (n: number) => assert.ok(n !== 0, `${ n } must not be zero.`)], + [NumericType.FINITE, (n: number) => assert.ok(Number.isFinite(n), `${ n } must be a finite number.`)], + [NumericType.INFINITE, (n: number) => assert.ok(!Number.isFinite(n), `${ n } must be an infinite number.`)], + ]).get(type) !(num); } /** @@ -109,14 +113,14 @@ export class xjs_Number { * @returns one of the strings described above * @throws {RangeError} if the given arguemnt was not a finite number */ - static typeOf(num: number): 'integer'|'float' { - console.warn('`xjs.Number.typeOf` is DEPRECATED: use `xjs.Number.assertType` instead.') + static typeOf(num: number): 'integer' | 'float' { + console.warn('`xjs.Number.typeOf` is DEPRECATED: use `xjs.Number.assertType` instead.'); if (['NaN', 'infinite'].includes(xjs_Object.typeOf(num))) { - throw new RangeError('Argument must be a finite number.') + throw new RangeError('Argument must be a finite number.'); } - return (Number.isInteger(num)) ? 'integer' : 'float' + return (Number.isInteger(num)) ? 'integer' : 'float'; } - private constructor() {} + private constructor() {} } diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index 8f82b1d..e42ff83 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -49,18 +49,23 @@ export class xjs_Object { * @throws {TypeError} if either `a` or `b` is a function (not supported) */ static is(a: T, b: T, predicate: (x: any, y: any) => boolean = xjs_Object.sameValueZero): boolean { - if (a === b) return true + if (a === b) { + return true; + } if (['string', 'number', 'boolean', 'null', 'undefined'].includes(xjs_Object.typeOf(a))) { - return xjs_Object.sameValueZero(a, b) + return xjs_Object.sameValueZero(a, b); + } + if (xjs_Object.typeOf(a) === 'function' || xjs_Object.typeOf(b) === 'function') { + throw new TypeError('Function arguments to xjs.Object.is are not yet supported.'); + } + if (a instanceof Array && b instanceof Array) { + return xjs_Array.is(a, b); } - if (xjs_Object.typeOf(a) === 'function' || xjs_Object.typeOf(b) === 'function') throw new TypeError('Function arguments to xjs.Object.is are not yet supported.') - if (a instanceof Array && b instanceof Array) return xjs_Array.is(a, b) // else, it will be 'object' - return Object.entries(a as Record).every(([a_key, a_value]) => - Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && predicate(a_value, b_value)) - ) && Object.entries(b as Record).every(([b_key, b_value]) => - Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && predicate(a_value, b_value)) - ) + return ( + Object.entries(a as Record).every(([a_key, a_value]) => Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && predicate(a_value, b_value))) + && Object.entries(b as Record).every(([b_key, b_value]) => Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && predicate(a_value, b_value))) + ); } /** @@ -75,7 +80,7 @@ export class xjs_Object { * @returns exactly `a === b || Object.is(a, b)` */ static sameValueZero(a: unknown, b: unknown): boolean { - return a === b || Object.is(a, b) + return a === b || Object.is(a, b); } /** @@ -113,41 +118,41 @@ export class xjs_Object { * ```js * // What is the date of the 1st Tuesday of November, 2018? * let call_me = xjs.Object.switch('November', { - * 'January' : (n: number) => [ 2, 9, 16, 23, 30][n - 1], - * 'February' : (n: number) => [ 6. 13. 20, 27, NaN][n - 1], - * 'March' : (n: number) => [ 6, 13, 20, 27, NaN][n - 1], - * 'April' : (n: number) => [ 3, 10, 17, 24, NaN][n - 1], - * 'May' : (n: number) => [ 1, 8, 15, 22, 29][n - 1], - * 'June' : (n: number) => [ 5, 12, 19, 26, NaN][n - 1], - * 'July' : (n: number) => [ 3, 10, 17, 24, 31][n - 1], - * 'August' : (n: number) => [ 7, 14, 21, 28, NaN][n - 1], - * 'September': (n: number) => [ 4, 11, 18, 25, NaN][n - 1], - * 'October' : (n: number) => [ 2, 9, 16, 23, 30][n - 1], - * 'November' : (n: number) => [ 6, 13, 20, 27, NaN][n - 1], - * 'December' : (n: number) => [ 4, 11, 18, 25, NaN][n - 1], - * 'default' : (n: number) => NaN, - * }) // returns a function taking `n` and returning one of `[6,13,20,27,NaN]` - * call_me(1) // returns the number `6` + * 'January': (n: number) => [ 2, 9, 16, 23, 30][n - 1], + * 'February': (n: number) => [ 6. 13. 20, 27, NaN][n - 1], + * 'March': (n: number) => [ 6, 13, 20, 27, NaN][n - 1], + * 'April': (n: number) => [ 3, 10, 17, 24, NaN][n - 1], + * 'May': (n: number) => [ 1, 8, 15, 22, 29][n - 1], + * 'June': (n: number) => [ 5, 12, 19, 26, NaN][n - 1], + * 'July': (n: number) => [ 3, 10, 17, 24, 31][n - 1], + * 'August': (n: number) => [ 7, 14, 21, 28, NaN][n - 1], + * 'September': (n: number) => [ 4, 11, 18, 25, NaN][n - 1], + * 'October': (n: number) => [ 2, 9, 16, 23, 30][n - 1], + * 'November': (n: number) => [ 6, 13, 20, 27, NaN][n - 1], + * 'December': (n: number) => [ 4, 11, 18, 25, NaN][n - 1], + * 'default': (n: number) => NaN, + * }); // returns a function taking `n` and returning one of `[6,13,20,27,NaN]` + * call_me(1); // returns the number `6` * ``` * * DEPRECATION WARNING: This method is deprecated. Instead, use a built-in Map: * ```js * // What is the date of the 1st Tuesday of November, 2018? * let call_me: (n: number) => number = new Map number>([ - * ['January' , (n: number) => [ 2, 9, 16, 23, 30][n - 1]], - * ['February' , (n: number) => [ 6. 13. 20, 27, NaN][n - 1]], - * ['March' , (n: number) => [ 6, 13, 20, 27, NaN][n - 1]], - * ['April' , (n: number) => [ 3, 10, 17, 24, NaN][n - 1]], - * ['May' , (n: number) => [ 1, 8, 15, 22, 29][n - 1]], - * ['June' , (n: number) => [ 5, 12, 19, 26, NaN][n - 1]], - * ['July' , (n: number) => [ 3, 10, 17, 24, 31][n - 1]], - * ['August' , (n: number) => [ 7, 14, 21, 28, NaN][n - 1]], - * ['September' , (n: number) => [ 4, 11, 18, 25, NaN][n - 1]], - * ['October' , (n: number) => [ 2, 9, 16, 23, 30][n - 1]], - * ['November' , (n: number) => [ 6, 13, 20, 27, NaN][n - 1]], - * ['December' , (n: number) => [ 4, 11, 18, 25, NaN][n - 1]], - * ]).get('November') // returns a function taking `n` and returning one of `[6,13,20,27,NaN]` - * call_me(1) // returns the number `6` + * ['January', (n: number) => [ 2, 9, 16, 23, 30][n - 1]], + * ['February', (n: number) => [ 6. 13. 20, 27, NaN][n - 1]], + * ['March', (n: number) => [ 6, 13, 20, 27, NaN][n - 1]], + * ['April', (n: number) => [ 3, 10, 17, 24, NaN][n - 1]], + * ['May', (n: number) => [ 1, 8, 15, 22, 29][n - 1]], + * ['June', (n: number) => [ 5, 12, 19, 26, NaN][n - 1]], + * ['July', (n: number) => [ 3, 10, 17, 24, 31][n - 1]], + * ['August', (n: number) => [ 7, 14, 21, 28, NaN][n - 1]], + * ['September', (n: number) => [ 4, 11, 18, 25, NaN][n - 1]], + * ['October', (n: number) => [ 2, 9, 16, 23, 30][n - 1]], + * ['November', (n: number) => [ 6, 13, 20, 27, NaN][n - 1]], + * ['December', (n: number) => [ 4, 11, 18, 25, NaN][n - 1]], + * ]).get('November'); // returns a function taking `n` and returning one of `[6,13,20,27,NaN]` + * call_me(1); // returns the number `6` * ``` * * @typeparam T - the type of value returned by the looked-up function @@ -157,174 +162,178 @@ export class xjs_Object { * @throws {ReferenceError} when failing to find a lookup value */ static switch(key: string, dictionary: { [index: string]: (this: any, ...args: any[]) => T }): (this: any, ...args: any[]) => T { - let returned: (this: any, ...args: any[]) => T = dictionary[key] + let returned: (this: any, ...args: any[]) => T = dictionary[key]; if (!returned) { - console.warn(`Key '${key}' cannot be found. Using key 'default'…`) - returned = dictionary['default'] || null - if (!returned) throw new ReferenceError(`No default key found.`) + console.warn(`Key '${ key }' cannot be found. Using key 'default'…`); + returned = dictionary['default'] || null; + if (!returned) { + throw new ReferenceError('No default key found.'); + } } - return returned + return returned; } - /** - * Return the type of a thing. - * - * Similar to the `typeof` primitive operator, but more refined. - * Note: this method should only be used at runtime — - * TypeScript is much better at checking types, and can do so at compile time. - * - * Warning! passing undeclared variables will throw a `ReferenceError`! - * - * ```js - * typeof null // 'object' :( - * typeof [] // 'object' - * typeof NaN // 'number' - * typeof Infinity // 'number' - * xjs.typeOf(null) // 'null' - * xjs.typeOf([]) // 'array' - * xjs.typeOf(NaN) // 'NaN' - * xjs.typeOf(Infinity) // 'infinite' - * - * var x; - * typeof x; // 'undefined' - * typeof y; // 'undefined' - * xjs.typeOf(x); // 'undefined' - * xjs.typeOf(y); // Uncaught ReferenceError: y is not defined - * ``` - * - * @see {@link https://github.com/zaggino/z-schema/blob/bddb0b25daa0c96119e84b121d7306b1a7871594/src/Utils.js#L12|Credit to @zaggino} - * @param thing anything - * @returns the type of the thing - */ + /** + * Return the type of a thing. + * + * Similar to the `typeof` primitive operator, but more refined. + * Note: this method should only be used at runtime — + * TypeScript is much better at checking types, and can do so at compile time. + * + * Warning! passing undeclared variables will throw a `ReferenceError`! + * + * ```js + * typeof null // 'object' :( + * typeof [] // 'object' + * typeof NaN // 'number' + * typeof Infinity // 'number' + * xjs.typeOf(null) // 'null' + * xjs.typeOf([]) // 'array' + * xjs.typeOf(NaN) // 'NaN' + * xjs.typeOf(Infinity) // 'infinite' + * + * var x; + * typeof x; // 'undefined' + * typeof y; // 'undefined' + * xjs.typeOf(x); // 'undefined' + * xjs.typeOf(y); // Uncaught ReferenceError: y is not defined + * ``` + * + * @see {@link https://github.com/zaggino/z-schema/blob/bddb0b25daa0c96119e84b121d7306b1a7871594/src/Utils.js#L12|Credit to @zaggino} + * @param thing anything + * @returns the type of the thing + */ static typeOf(thing: unknown): string { return (new Map string>([ - ['object', (arg: unknown) => (arg === null) ? 'null' - : (Array.isArray(arg)) ? 'array' - : 'object' - ], - ['number', (arg: number) => (Number.isNaN(arg)) ? 'NaN' - : (!Number.isFinite(arg)) ? 'infinite' - : 'number' - ], - ['bigint' , () => 'bigint'], - ['function' , () => 'function'], - ['string' , () => 'string'], - ['boolean' , () => 'boolean'], - ['undefined' , () => 'undefined'], - ]).get(typeof thing) || ((arg: unknown) => typeof arg))(thing) + ['object', (arg: unknown) => (arg === null) ? 'null' : (Array.isArray(arg)) ? 'array' : 'object'], + ['number', (arg: number) => (Number.isNaN(arg)) ? 'NaN' : (!Number.isFinite(arg)) ? 'infinite' : 'number'], + ['bigint', () => 'bigint'], + ['function', () => 'function'], + ['string', () => 'string'], + ['boolean', () => 'boolean'], + ['undefined', () => 'undefined'], + ]).get(typeof thing) || ((arg: unknown) => typeof arg))(thing); } - /** - * WARNING:EXPERIMENTAL - * Return the name of an object’s constructing class or function. - * - * This method reveals the most specific class that the native `instanceof` operator would reveal. - * This method can be passed either complex values (objects, arrays, functions) or primitive values. - * Technically, primitives do not have constructing functions, but they can be wrapped with object constructors. - * For example, calling `instanceOf(3)` will return `Number`, even though `3` was not constructed via the `Number` class. - * @param thing anything except `null` or `undefined` - * @returns the name of the constructing function - * @throws {TypeError} if `null` or `undefined` is passed - */ - static instanceOf(thing: unknown): string { - if (thing === null || thing === undefined) throw new TypeError(`\`${thing}\` does not have a construtor.`) - return (thing as any).__proto__.constructor.name - } + /** + * WARNING:EXPERIMENTAL + * Return the name of an object’s constructing class or function. + * + * This method reveals the most specific class that the native `instanceof` operator would reveal. + * This method can be passed either complex values (objects, arrays, functions) or primitive values. + * Technically, primitives do not have constructing functions, but they can be wrapped with object constructors. + * For example, calling `instanceOf(3)` will return `Number`, even though `3` was not constructed via the `Number` class. + * @param thing anything except `null` or `undefined` + * @returns the name of the constructing function + * @throws {TypeError} if `null` or `undefined` is passed + */ + static instanceOf(thing: unknown): string { + if (thing === null || thing === undefined) { + throw new TypeError(`\`${ thing }\` does not have a construtor.`); + } + return (thing as any).__proto__.constructor.name; + } - /** - * Deep freeze an object, and return the result. - * - * *Note: This function is impure, modifying the given argument.* - * If an array or object is passed, - * **Recursively** call - * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze|Object.freeze} - * on every property and sub-property of the given parameter. - * Else, return the given argument. - * If the argument is an array, it is faster to use {@link xjs_Array.freezeDeep}. + /** + * Deep freeze an object, and return the result. + * + * *Note: This function is impure, modifying the given argument.* + * If an array or object is passed, + * **Recursively** call + * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze|Object.freeze} + * on every property and sub-property of the given parameter. + * Else, return the given argument. + * If the argument is an array, it is faster to use {@link xjs_Array.freezeDeep}. * @typeparam T - the type of `thing` - * @param thing any value to freeze - * @returns the given value, with everything frozen - * @deprecated use interface `Readonly` instead - */ - static freezeDeep(thing: Readonly): Readonly { - if (thing instanceof Array) return xjs_Array.freezeDeep(thing) as unknown as T // HACK https://stackoverflow.com/a/18736071/ - Object.freeze(thing) - if (xjs_Object.typeOf(thing) === 'object') { - for (let key in thing) { - if (!Object.isFrozen(thing[key])) xjs_Object.freezeDeep(thing[key]) - } - } - return thing - } + * @param thing any value to freeze + * @returns the given value, with everything frozen + * @deprecated use interface `Readonly` instead + */ + static freezeDeep(thing: Readonly): Readonly { + if (thing instanceof Array) { + return xjs_Array.freezeDeep(thing) as unknown as T; // HACK https://stackoverflow.com/a/18736071/ + } + Object.freeze(thing); + if (xjs_Object.typeOf(thing) === 'object') { + for (let key in thing) { + if (!Object.isFrozen(thing[key])) { + xjs_Object.freezeDeep(thing[key]); + } + } + } + return thing; + } - /** - * WARNING:EXPERIMENTAL - * Deep clone an object, and return the result. - * - * If an array or object is passed, - * This method is **recursively** called, cloning properties and sub-properties of the given parameter. - * The returned result is an object, that when passed with the original as arguments of - * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is|Object.is}, - * `true` would be returned. The new object would be “replaceable” with its cloner. - * If a primitive value is passed, the original argument is returned. - * If the argument is an array, it is faster to use {@link xjs_Array.cloneDeep}. - * - * This method provides a deeper clone than `Object.assign()`: whereas `Object.assign()` only - * copies the top-level properties, this method recursively clones into all sub-levels. - * - * ```js - * var x = { first: 1, second: { value: 2 }, third: [1, '2', { v:3 }] } - * - * // Object.assign x into y: - * var y = Object.assign({}, x) // returns { first: x.first, second: x.second, third: x.third } - * - * // you can reassign properties of `y` without affecting `x`: - * y.first = 'one' - * y.second = 2 - * console.log(y) // returns { first: 'one', second: 2, third: x.third } - * console.log(x) // returns { first: 1, second: { value: 2 }, third: [1, '2', { v:3 }] } - * - * // however you cannot mutate properties of `y` without affecting `x`: - * y.third[0] = 'one' - * y.third[1] = 2 - * y.third[2].v = [3] - * console.log(y) // returns { first: 'one', second: 2, third: ['one', 2, { v:[3] }] } - * console.log(x) // returns { first: 1, second: { value: 2 }, third: ['one', 2, { v:[3] }] } - * - * // xjs.Object.cloneDeep x into y: - * var z = xjs.Object.cloneDeep(x) // returns { first: 1, second: { value: 2 }, third: [1, '2', {v:3}] } - * - * // as with Object.assign, you can reassign properties of `z` without affecting `x`: - * z.first = 'one' - * z.second = 2 - * console.log(z) // returns { first: 'one', second: 2, third: [1, '2', {v:3}] } - * console.log(x) // returns { first: 1, second: { value: 2 }, third: [1, '2', { v:3 }] } - * - * // but unlike Object.assign, you can mutate properties of `z` without affecting `x`: - * z.third[0] = 'one' - * z.third[1] = 2 - * z.third[2].v = [3] - * console.log(z) // returns { first: 'one', second: 2, third: ['one', 2, { v:[3] }] } - * console.log(x) // returns { first: 1, second: { value: 2 }, third: [1, '2', { v:3 }] } - * ``` - * + /** + * WARNING:EXPERIMENTAL + * Deep clone an object, and return the result. + * + * If an array or object is passed, + * This method is **recursively** called, cloning properties and sub-properties of the given parameter. + * The returned result is an object, that when passed with the original as arguments of + * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is|Object.is}, + * `true` would be returned. The new object would be “replaceable” with its cloner. + * If a primitive value is passed, the original argument is returned. + * If the argument is an array, it is faster to use {@link xjs_Array.cloneDeep}. + * + * This method provides a deeper clone than `Object.assign()`: whereas `Object.assign()` only + * copies the top-level properties, this method recursively clones into all sub-levels. + * + * ```js + * var x = { first: 1, second: { value: 2 }, third: [1, '2', { v:3 }] } + * + * // Object.assign x into y: + * var y = Object.assign({}, x) // returns { first: x.first, second: x.second, third: x.third } + * + * // you can reassign properties of `y` without affecting `x`: + * y.first = 'one' + * y.second = 2 + * console.log(y) // returns { first: 'one', second: 2, third: x.third } + * console.log(x) // returns { first: 1, second: { value: 2 }, third: [1, '2', { v:3 }] } + * + * // however you cannot mutate properties of `y` without affecting `x`: + * y.third[0] = 'one' + * y.third[1] = 2 + * y.third[2].v = [3] + * console.log(y) // returns { first: 'one', second: 2, third: ['one', 2, { v:[3] }] } + * console.log(x) // returns { first: 1, second: { value: 2 }, third: ['one', 2, { v:[3] }] } + * + * // xjs.Object.cloneDeep x into y: + * var z = xjs.Object.cloneDeep(x) // returns { first: 1, second: { value: 2 }, third: [1, '2', {v:3}] } + * + * // as with Object.assign, you can reassign properties of `z` without affecting `x`: + * z.first = 'one' + * z.second = 2 + * console.log(z) // returns { first: 'one', second: 2, third: [1, '2', {v:3}] } + * console.log(x) // returns { first: 1, second: { value: 2 }, third: [1, '2', { v:3 }] } + * + * // but unlike Object.assign, you can mutate properties of `z` without affecting `x`: + * z.third[0] = 'one' + * z.third[1] = 2 + * z.third[2].v = [3] + * console.log(z) // returns { first: 'one', second: 2, third: ['one', 2, { v:[3] }] } + * console.log(x) // returns { first: 1, second: { value: 2 }, third: [1, '2', { v:3 }] } + * ``` + * * @typeparam T - the type of `thing` - * @param thing any value to clone - * @returns an exact copy of the given value, but with nothing equal via `===` (unless the value given is primitive) - */ - static cloneDeep(thing: T): T { - if (thing instanceof Array) return xjs_Array.cloneDeep(thing) as unknown as T // HACK https://stackoverflow.com/a/18736071/ - if (xjs_Object.typeOf(thing) === 'object') { - const returned: { [index: string]: unknown } = {} - for (let key in thing) { - returned[key] = xjs_Object.cloneDeep(thing[key]) - } - return returned as unknown as T - } else { - return thing - } - } + * @param thing any value to clone + * @returns an exact copy of the given value, but with nothing equal via `===` (unless the value given is primitive) + */ + static cloneDeep(thing: T): T { + if (thing instanceof Array) { + return xjs_Array.cloneDeep(thing) as unknown as T; // HACK https://stackoverflow.com/a/18736071/ + } + if (xjs_Object.typeOf(thing) === 'object') { + const returned: { [index: string]: unknown } = {}; + for (let key in thing) { + returned[key] = xjs_Object.cloneDeep(thing[key]); + } + return returned as unknown as T; + } else { + return thing; + } + } - private constructor() {} + private constructor() {} } diff --git a/src/class/Promise.class.ts b/src/class/Promise.class.ts index b81960b..aef8714 100644 --- a/src/class/Promise.class.ts +++ b/src/class/Promise.class.ts @@ -25,17 +25,15 @@ export class xjs_Promise { static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise ]): Promise; static async any(values: [T0 | Promise, T1 | Promise ]): Promise; static async any(values: [T0 | Promise ]): Promise; - static async any(values: (T | Promise)[]): Promise; + static async any(values: Array>): Promise; static async any(values: unknown[]): Promise { - return Promise.all(values.map((p) => (!(p instanceof Promise)) ? Promise.reject(p) : - p.then( - (val) => Promise.reject (val), - (err) => Promise.resolve(err), - ) - )).then( + return Promise.all(values.map((p) => (!(p instanceof Promise)) ? Promise.reject(p) : p.then( + (val) => Promise.reject (val), + (err) => Promise.resolve(err), + ))).then( (errors) => Promise.reject (errors), - (value ) => Promise.resolve(value ), - ) + (value) => Promise.resolve(value), + ); } diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index 8665833..373a840 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -19,10 +19,12 @@ export class xjs_Set { * @returns Are corresponding elements the same, i.e. replaceable? */ static is(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { - if (a === b) return true - return a.size === b.size && - [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || predicate(a_el, b_el))) && - [...b].every((b_el) => [...a].some((a_el) => xjs_Object.sameValueZero(b_el, a_el) || predicate(b_el, a_el))) + if (a === b) { + return true; + } + return a.size === b.size + && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || predicate(a_el, b_el))) + && [...b].every((b_el) => [...a].some((a_el) => xjs_Object.sameValueZero(b_el, a_el) || predicate(b_el, a_el))); } /** @@ -35,7 +37,7 @@ export class xjs_Set { * @returns a new set with the elements that pass the test; if no elements pass, an empty set is returned */ static filter(set: Set, predicate: (element: T, index: T, set: Set) => boolean, this_arg: unknown = null): Set { - return new Set([...set].filter((el) => predicate.call(this_arg, el, el, set))) + return new Set([...set].filter((el) => predicate.call(this_arg, el, el, set))); } /** @@ -47,8 +49,8 @@ export class xjs_Set { * @param this_arg object to use as `this` when executing `predicate` * @returns the item found, or `null` if none is found */ - static find(set: Set, predicate: (element: T, index: T, set: Set) => boolean, this_arg: unknown = null): T|null { - return [...xjs_Set.filter(set, predicate, this_arg)][0] || null + static find(set: Set, predicate: (element: T, index: T, set: Set) => boolean, this_arg: unknown = null): T | null { + return [...xjs_Set.filter(set, predicate, this_arg)][0] || null; } /** @@ -62,7 +64,7 @@ export class xjs_Set { * @returns a new Set with transformed elements obtained from `callback` */ static map(set: Set, callback: (element: T, index: T, set: Set) => U, this_arg: unknown = null): Set { - return new Set([...set].map((el) => callback.call(this_arg, el, el, set))) + return new Set([...set].map((el) => callback.call(this_arg, el, el, set))); } /** @@ -79,7 +81,7 @@ export class xjs_Set { * @returns Is `a` a subset of `b`? */ static isSubsetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { - return xjs_Array.isSubarrayOf([...a].sort(), [...b].sort(), predicate) + return xjs_Array.isSubarrayOf([...a].sort(), [...b].sort(), predicate); } /** @@ -93,7 +95,7 @@ export class xjs_Set { * @returns exactly `xjs.Set.isSubsetOf(b, a, predicate)` */ static isSupersetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { - return xjs_Set.isSubsetOf(b, a, predicate) + return xjs_Set.isSubsetOf(b, a, predicate); } /** @@ -106,8 +108,8 @@ export class xjs_Set { * @param comparator a comparator function * @returns a new Set containing the elements present in either `a` or `b` (or both) */ - static union(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set { - const returned: Set = new Set(a) + static union(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set { + const returned = new Set(a); b.forEach((el) => { if (!comparator) { returned.add(el); @@ -115,7 +117,7 @@ export class xjs_Set { xjs_Set.add(returned, el, comparator); } }); - return returned + return returned; } /** @@ -128,9 +130,9 @@ export class xjs_Set { * @param comparator a comparator function * @returns a new Set containing the elements present only in both `a` and `b` */ - static intersection(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T & U, b: T & U) => boolean): Set; + static intersection(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T & U, b: T & U) => boolean): Set; static intersection(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T, b: T) => boolean): Set { - const returned: Set = new Set(); + const returned = new Set(); b.forEach((el) => { if (!comparator) { if (a.has(el)) { @@ -142,7 +144,7 @@ export class xjs_Set { } } }); - return returned + return returned; } /** @@ -157,7 +159,7 @@ export class xjs_Set { */ static difference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set; static difference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T, b: T) => boolean): Set { - const returned: Set = new Set(); + const returned = new Set(); a.forEach((el) => { if (!comparator) { if (!b.has(el)) { @@ -169,7 +171,7 @@ export class xjs_Set { } } }); - return returned + return returned; } /** @@ -186,7 +188,7 @@ export class xjs_Set { * @param comparator a comparator function * @returns a new Set containing the elements present only in `a` or only in `b`, but not both */ - static symmetricDifference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set { + static symmetricDifference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set { return xjs_Set.difference( xjs_Set.union(a, b, comparator), xjs_Set.intersection(a, b, comparator), diff --git a/src/class/String.class.ts b/src/class/String.class.ts index cea9f95..967a612 100644 --- a/src/class/String.class.ts +++ b/src/class/String.class.ts @@ -27,29 +27,29 @@ export type TemplateTag = * Does not extend the native String class. */ export class xjs_String { - /** - * Convert a thing into a string. - * - * If the argument is an array, it is joined. - * If it is an object, `JSON.stringify` is called on it. - * This method calls `.toString()` on everything else, except `null` and `undefined`, - * which are converted to the strings `'null'` and `'undefined'` respectively. - * Useful for JSON objects where the value could be a single string or an array of strings. - * @param thing anything to convert - * @returns a string version of the argument - */ + /** + * Convert a thing into a string. + * + * If the argument is an array, it is joined. + * If it is an object, `JSON.stringify` is called on it. + * This method calls `.toString()` on everything else, except `null` and `undefined`, + * which are converted to the strings `'null'` and `'undefined'` respectively. + * Useful for JSON objects where the value could be a single string or an array of strings. + * @param thing anything to convert + * @returns a string version of the argument + */ static stringify(thing: unknown): string { return new Map string>([ - ['object' , (arg: object) => JSON.stringify(arg)], - ['array' , (arg: unknown[]) => arg.join('')], - ['function' , (arg: Function) => arg.toString()], - ['string' , (arg: string) => arg], - ['number' , (arg: number) => arg.toString()], - ['boolean' , (arg: boolean) => arg.toString()], - ['null' , (arg: null) => `${arg}`], - ['undefined' , (arg: void) => `${arg}`], - ['default' , (arg: unknown) => `${arg}`], - ]).get(xjs_Object.typeOf(thing)) !(thing) + ['object', (arg: object) => JSON.stringify(arg)], + ['array', (arg: unknown[]) => arg.join('')], + ['function', (arg: Function) => arg.toString()], + ['string', (arg: string) => arg], + ['number', (arg: number) => arg.toString()], + ['boolean', (arg: boolean) => arg.toString()], + ['null', (arg: null) => `${ arg }`], + ['undefined', (arg: void) => `${ arg }`], + ['default', (arg: unknown) => `${ arg }`], + ]).get(xjs_Object.typeOf(thing))!(thing); } /** @@ -85,5 +85,5 @@ export class xjs_String { } - private constructor() {} + private constructor() {} } diff --git a/test/Array.test.ts b/test/Array.test.ts index 09522c9..bf6d0f6 100644 --- a/test/Array.test.ts +++ b/test/Array.test.ts @@ -1,110 +1,110 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {xjs_Array} from '../src/class/Array.class.js'; describe('xjs.Array', () => { describe('.is(readonly T[], readonly T[], ((T, T) -> boolean)?): boolean', () => { it('only checks one level of depth.', () => { assert.ok(!xjs_Array.is( - [1, 'two', [3, 'three'], { v: 4, val: 'four' }, [5, 'five']], - [1, 'two', [3, 'three'], { v: 4, val: 'four' }, [5, 'five']], - )) + [1, 'two', [3, 'three'], {v: 4, val: 'four'}, [5, 'five']], + [1, 'two', [3, 'three'], {v: 4, val: 'four'}, [5, 'five']], + )); assert.ok(!xjs_Array.is( - [1, 'two', [3, 'three'], { v: 4, val: 'four' }, [5, 'five']], - [1, 'two', [3, 'three'], { v: 4, val: 'four' }, [5, 'five'], [6, 'six', [6,'six'], { six: 6 }]], - )) + [1, 'two', [3, 'three'], {v: 4, val: 'four'}, [5, 'five']], + [1, 'two', [3, 'three'], {v: 4, val: 'four'}, [5, 'five'], [6, 'six', [6, 'six'], {six: 6}]], + )); assert.ok(!xjs_Array.is( - [1, 'two', { value: 3 }, ['four']], - [['four'], 1, 'two', { value: 3 }], - )) - }) - }) + [1, 'two', {value: 3}, ['four']], + [['four'], 1, 'two', {value: 3}], + )); + }); + }); describe('.densify(readonly T[]): T[]', () => { it('removes empty element slots.', () => { - const x: readonly (number|void)[] = [, 42, , 48, ,] - assert.deepStrictEqual(xjs_Array.densify(x), [42,48]) - }) + const x: readonly (number | void)[] = [, 42, , 48, ,]; + assert.deepStrictEqual(xjs_Array.densify(x), [42, 48]); + }); it('does not remove `undefined` elements.', () => { - const x: readonly (number|void)[] = [void 0, 42, void 0, 48, void 0,] - assert.notDeepStrictEqual(x, [ , 42, , 48, ,]) - assert.deepStrictEqual(xjs_Array.densify(x), x) - }) - }) + const x: readonly (number | void)[] = [void 0, 42, void 0, 48, void 0,]; + assert.notDeepStrictEqual(x, [ , 42, , 48, ,]); + assert.deepStrictEqual(xjs_Array.densify(x), x); + }); + }); describe('.fillHoles(readonly T[], T): T[]', () => { it('fills empty slots with given value.', () => { - const x: readonly (number|void)[] = [, 42, , 48, ,] - assert.deepStrictEqual(xjs_Array.fillHoles(x, 0), [0, 42, 0, 48, 0]) - }) - }) + const x: readonly (number | void)[] = [, 42, , 48, ,]; + assert.deepStrictEqual(xjs_Array.fillHoles(x, 0), [0, 42, 0, 48, 0]); + }); + }); describe('.isSubarrayOf(readonly T[], readonly U[], ((U, U) -> boolean)?): boolean', () => { it('is true if elements of the first are in the second, in the same order.', () => { - const x: number[] = [3,4] - assert.ok( xjs_Array.isSubarrayOf(x, [0,1,2,0,3,4])) - assert.ok( xjs_Array.isSubarrayOf(x, [3,4,5] )) - assert.ok( xjs_Array.isSubarrayOf(x, [3,3,4,4] )) - assert.ok( xjs_Array.isSubarrayOf(x, [3,4] )) - assert.ok( xjs_Array.isSubarrayOf(x, [3,0,1,4] )) - assert.ok( xjs_Array.isSubarrayOf(x, [3,0,4,1] )) - assert.ok(!xjs_Array.isSubarrayOf(x, [3] )) - assert.ok(!xjs_Array.isSubarrayOf(x, [0,1,3,0,2,5])) - assert.ok(!xjs_Array.isSubarrayOf(x, [2,4] )) - assert.ok(!xjs_Array.isSubarrayOf(x, [4,3] )) - assert.ok(!xjs_Array.isSubarrayOf(x, [0] )) - }) - }) + const x: number[] = [3, 4]; + assert.ok( xjs_Array.isSubarrayOf(x, [0, 1, 2, 0, 3, 4])); + assert.ok( xjs_Array.isSubarrayOf(x, [3, 4, 5])); + assert.ok( xjs_Array.isSubarrayOf(x, [3, 3, 4, 4])); + assert.ok( xjs_Array.isSubarrayOf(x, [3, 4])); + assert.ok( xjs_Array.isSubarrayOf(x, [3, 0, 1, 4])); + assert.ok( xjs_Array.isSubarrayOf(x, [3, 0, 4, 1])); + assert.ok(!xjs_Array.isSubarrayOf(x, [3])); + assert.ok(!xjs_Array.isSubarrayOf(x, [0, 1, 3, 0, 2, 5])); + assert.ok(!xjs_Array.isSubarrayOf(x, [2, 4])); + assert.ok(!xjs_Array.isSubarrayOf(x, [4, 3])); + assert.ok(!xjs_Array.isSubarrayOf(x, [0])); + }); + }); describe('.isSuperarrayOf(readonly T[], readonly U[], ((T, T) -> boolean)?): boolean', () => { it('is true if elements of the second are in the first, in the same order.', () => { - const x: number[] = [0,1,2,0,3,4] - assert.ok( xjs_Array.isSuperarrayOf(x, [3,4] )) - assert.ok( xjs_Array.isSuperarrayOf(x, [0,1,2] )) - assert.ok( xjs_Array.isSuperarrayOf(x, [0,1,2,0,3,4] )) - assert.ok( xjs_Array.isSuperarrayOf(x, [0,3,4] )) - assert.ok( xjs_Array.isSuperarrayOf(x, [1] )) - assert.ok( xjs_Array.isSuperarrayOf(x, [] )) - assert.ok( xjs_Array.isSuperarrayOf(x, [2,4] )) - assert.ok(!xjs_Array.isSuperarrayOf(x, [2,5] )) - assert.ok(!xjs_Array.isSuperarrayOf(x, [4,0] )) - assert.ok(!xjs_Array.isSuperarrayOf(x, [4,3] )) - assert.ok(!xjs_Array.isSuperarrayOf(x, [0,1,2,0,3,4,5])) - }) - }) + const x: number[] = [0, 1, 2, 0, 3, 4]; + assert.ok( xjs_Array.isSuperarrayOf(x, [3, 4])); + assert.ok( xjs_Array.isSuperarrayOf(x, [0, 1, 2])); + assert.ok( xjs_Array.isSuperarrayOf(x, [0, 1, 2, 0, 3, 4])); + assert.ok( xjs_Array.isSuperarrayOf(x, [0, 3, 4])); + assert.ok( xjs_Array.isSuperarrayOf(x, [1])); + assert.ok( xjs_Array.isSuperarrayOf(x, [])); + assert.ok( xjs_Array.isSuperarrayOf(x, [2, 4])); + assert.ok(!xjs_Array.isSuperarrayOf(x, [2, 5])); + assert.ok(!xjs_Array.isSuperarrayOf(x, [4, 0])); + assert.ok(!xjs_Array.isSuperarrayOf(x, [4, 3])); + assert.ok(!xjs_Array.isSuperarrayOf(x, [0, 1, 2, 0, 3, 4, 5])); + }); + }); describe('.isConsecutiveSubarrayOf(readonly T[], readonly U[], ((U, U) -> boolean)?): boolean', () => { it('is true if the first is consecutively in the second.', () => { - const x: number[] = [3,4] - assert.ok( xjs_Array.isConsecutiveSubarrayOf(x, [0,1,2,0,3,4])) - assert.ok( xjs_Array.isConsecutiveSubarrayOf(x, [3,4,5] )) - assert.ok( xjs_Array.isConsecutiveSubarrayOf(x, [3,3,4,4] )) - assert.ok( xjs_Array.isConsecutiveSubarrayOf(x, [3,4] )) - assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [3,0,1,4] )) - assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [3,0,4,1] )) - assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [3] )) - assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [0,1,3,0,2,5])) - assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [2,4] )) - assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [4,3] )) - assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [0] )) - }) - }) + const x: number[] = [3, 4]; + assert.ok( xjs_Array.isConsecutiveSubarrayOf(x, [0, 1, 2, 0, 3, 4])); + assert.ok( xjs_Array.isConsecutiveSubarrayOf(x, [3, 4, 5])); + assert.ok( xjs_Array.isConsecutiveSubarrayOf(x, [3, 3, 4, 4])); + assert.ok( xjs_Array.isConsecutiveSubarrayOf(x, [3, 4])); + assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [3, 0, 1, 4])); + assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [3, 0, 4, 1])); + assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [3])); + assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [0, 1, 3, 0, 2, 5])); + assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [2, 4])); + assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [4, 3])); + assert.ok(!xjs_Array.isConsecutiveSubarrayOf(x, [0])); + }); + }); describe('.isConsecutiveSuperarrayOf(readonly T[], readonly U[], ((T, T) -> boolean)?): boolean', () => { it('is true if the second is consecutively in the first.', () => { - const x: number[] = [0,1,2,0,3,4] - assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [3,4] )) - assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [0,1,2] )) - assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [0,1,2,0,3,4] )) - assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [0,3,4] )) - assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [1] )) - assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [] )) - assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [2,4] )) - assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [2,5] )) - assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [4,0] )) - assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [4,3] )) - assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [0,1,2,0,3,4,5])) - }) - }) + const x: number[] = [0, 1, 2, 0, 3, 4]; + assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [3, 4])); + assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [0, 1, 2])); + assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [0, 1, 2, 0, 3, 4])); + assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [0, 3, 4])); + assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [1])); + assert.ok( xjs_Array.isConsecutiveSuperarrayOf(x, [])); + assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [2, 4])); + assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [2, 5])); + assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [4, 0])); + assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [4, 3])); + assert.ok(!xjs_Array.isConsecutiveSuperarrayOf(x, [0, 1, 2, 0, 3, 4, 5])); + }); + }); describe('.forEachAggregated', () => { it('acts like Array#forEach if no errors.', () => { @@ -137,7 +137,7 @@ describe('xjs.Array', () => { times++; if (n === 2) { throw new RangeError(`${ n } is even.`); - }; + } }), (err) => { assert.ok(err instanceof RangeError); assert.strictEqual(err.message, '2 is even.'); @@ -149,7 +149,7 @@ describe('xjs.Array', () => { assert.throws(() => xjs_Array.forEachAggregated([1, 2, 3, 4], (n) => { if (n % 2 === 0) { throw new RangeError(`${ n } is even.`); - }; + } }), (err) => { assert.ok(err instanceof AggregateError); assert.strictEqual(err.errors.length, 2); @@ -168,9 +168,8 @@ describe('xjs.Array', () => { new RangeError(`${ n } is even.`), new RangeError(`${ n } is a multiple of 4.`), ]) - : new RangeError(`${ n } is even.`) - ; - }; + : new RangeError(`${ n } is even.`); + } }), (err) => { assert.ok(err instanceof AggregateError); assert.strictEqual(err.errors.length, 4); @@ -218,7 +217,7 @@ describe('xjs.Array', () => { times++; if (n === 2) { throw new RangeError(`${ n } is even.`); - }; + } return n * 2; }), (err) => { assert.ok(err instanceof RangeError); @@ -231,7 +230,7 @@ describe('xjs.Array', () => { assert.throws(() => xjs_Array.mapAggregated([1, 2, 3, 4], (n) => { if (n % 2 === 0) { throw new RangeError(`${ n } is even.`); - }; + } return n * 2; }), (err) => { assert.ok(err instanceof AggregateError); @@ -251,9 +250,8 @@ describe('xjs.Array', () => { new RangeError(`${ n } is even.`), new RangeError(`${ n } is a multiple of 4.`), ]) - : new RangeError(`${ n } is even.`) - ; - }; + : new RangeError(`${ n } is even.`); + } return n * 2; }), (err) => { assert.ok(err instanceof AggregateError); @@ -279,7 +277,7 @@ describe('xjs.Array', () => { assert.deepStrictEqual( xjs_Array.mapAggregated(['hello', 'world'], (str) => new TypeError(str)), ['hello', 'world'].map((str) => new TypeError(str)), - ) + ); }); }); -}) +}); diff --git a/test/BigInt.test.ts b/test/BigInt.test.ts index cd3fdb9..53304f3 100644 --- a/test/BigInt.test.ts +++ b/test/BigInt.test.ts @@ -1,31 +1,31 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {xjs_BigInt} from '../src/class/BigInt.class.js'; import {NumericType} from '../src/class/Number.class.js'; describe('xjs.BigInt', () => { describe('.assertType(bigint, NumericType?): void', () => { it('returns `void` if no type is given.', () => { - assert.ifError(xjs_BigInt.assertType(42n)) - }) + assert.ifError(xjs_BigInt.assertType(42n)); + }); it('returns `void` if correct.', () => { new Map([ - [NumericType.NATURAL , [42n, 0n, -0n]], - [NumericType.WHOLE , [42n]], + [NumericType.NATURAL, [42n, 0n, -0n]], + [NumericType.WHOLE, [42n]], ]).forEach((numbers, type) => { numbers.forEach((n) => { - assert.ifError(xjs_BigInt.assertType(n, type)) - }) - }) - }) + assert.ifError(xjs_BigInt.assertType(n, type)); + }); + }); + }); it('throws if incorrect.', () => { new Map([ - [NumericType.NATURAL , [-42n]], - [NumericType.WHOLE , [-42n, 0n, -0n]], + [NumericType.NATURAL, [-42n]], + [NumericType.WHOLE, [-42n, 0n, -0n]], ]).forEach((numbers, type) => { numbers.forEach((n) => { - assert.throws(() => xjs_BigInt.assertType(n, type), assert.AssertionError) - }) - }) - }) - }) -}) + assert.throws(() => xjs_BigInt.assertType(n, type), assert.AssertionError); + }); + }); + }); + }); +}); diff --git a/test/Date.test.ts b/test/Date.test.ts index 7206422..5cdbbf6 100644 --- a/test/Date.test.ts +++ b/test/Date.test.ts @@ -1,24 +1,24 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {xjs_Date} from '../src/class/Date.class.js'; describe('xjs.Date', () => { describe('.format(Date, string): string', () => { it('formats a date in the given format.', () => { - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'Y-m-d' ), '1970-01-01') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'j M Y' ), '1 Jan 1970') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'd F Y' ), '01 January 1970') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'l, j F, Y' ), 'Thursday, 1 January, 1970') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'j M' ), '1 Jan') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'M Y' ), 'Jan 1970') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'M j' ), 'Jan 1') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'M j, Y' ), 'Jan 1, 1970') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'F j, Y' ), 'January 1, 1970') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'M' ), 'Jan') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'H:i' ), '00:00') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'g:ia' ), '0:00am') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'default' ), '1970-01-01T00:00:00.000Z') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'invalid-format'), '1970-01-01T00:00:00.000Z') - assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), '' ), '1970-01-01T00:00:00.000Z') - }) - }) -}) + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'Y-m-d'), '1970-01-01'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'j M Y'), '1 Jan 1970'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'd F Y'), '01 January 1970'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'l, j F, Y'), 'Thursday, 1 January, 1970'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'j M'), '1 Jan'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'M Y'), 'Jan 1970'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'M j'), 'Jan 1'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'M j, Y'), 'Jan 1, 1970'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'F j, Y'), 'January 1, 1970'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'M'), 'Jan'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'H:i'), '00:00'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'g:ia'), '0:00am'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'default'), '1970-01-01T00:00:00.000Z'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), 'invalid-format'), '1970-01-01T00:00:00.000Z'); + assert.strictEqual(xjs_Date.format(new Date('1970-01-01T00:00:00Z'), ''), '1970-01-01T00:00:00.000Z'); + }); + }); +}); diff --git a/test/Map.test.ts b/test/Map.test.ts index 239caed..d01977c 100644 --- a/test/Map.test.ts +++ b/test/Map.test.ts @@ -9,7 +9,7 @@ describe('xjs.Map', () => { describe('.has', () => { it('tests keys by equality.', () => { const key: Key = {id: 42}; - const my_map: Map = new Map([ + const my_map = new Map([ [key, true], ]); assert.ok(!my_map.has({id: 42}), 'does not contain an equal (but non-identical) key.'); @@ -22,7 +22,7 @@ describe('xjs.Map', () => { describe('.get', () => { it('gets equivalent keys.', () => { const key: Key = {id: 42}; - const my_map: Map = new Map([ + const my_map = new Map([ [key, true], ]); assert.strictEqual(my_map.get({id: 42}), undefined, 'does not get equal (but non-identical) keys.'); @@ -35,7 +35,7 @@ describe('xjs.Map', () => { describe('.set', () => { it('sets equivalent keys.', () => { const key: Key = {id: 42}; - const my_map: Map = new Map([ + const my_map = new Map([ [key, true], ]); my_map.set({id: 42}, false); @@ -52,7 +52,7 @@ describe('xjs.Map', () => { describe('.delete', () => { it('deletes equivalent keys.', () => { const key: Key = {id: 42}; - const my_map: Map = new Map([ + const my_map = new Map([ [key, true], [{id: 43}, true], [{id: 44}, true], diff --git a/test/Math.test.ts b/test/Math.test.ts index 90d1f1d..a6302ea 100644 --- a/test/Math.test.ts +++ b/test/Math.test.ts @@ -1,89 +1,89 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {xjs_Math} from '../src/class/Math.class.js'; import {NaNError} from '../src/class/NaNError.class.js'; describe('xjs.Math', () => { - describe('.mod(number, number|bigint): number', () => { + describe('.mod(number, number | bigint): number', () => { it('acts like `x % y` for positive `x`.', () => { - assert.strictEqual(xjs_Math.mod( 8, 6), 2) - }) + assert.strictEqual(xjs_Math.mod(8, 6), 2); + }); it('acts like `x % y + y` for negative `x`.', () => { - assert.strictEqual(xjs_Math.mod(-8, 6), 4) - }) + assert.strictEqual(xjs_Math.mod(-8, 6), 4); + }); it('throws when `b` is `0`.', () => { - assert.throws(() => xjs_Math.mod(8, 0), assert.AssertionError) - }) - it('throws when `b` is a non-integer.', ()=> { - assert.throws(() => xjs_Math.mod(8, 0.5), assert.AssertionError) - }) - }) + assert.throws(() => xjs_Math.mod(8, 0), assert.AssertionError); + }); + it('throws when `b` is a non-integer.', () => { + assert.throws(() => xjs_Math.mod(8, 0.5), assert.AssertionError); + }); + }); describe('.clamp(number, number, number): number', () => { it('clamps a number between bounds.', () => { - assert.strictEqual(xjs_Math.clamp(1, 3, 5), 3) - assert.strictEqual(xjs_Math.clamp(3, 1, 5), 3) - assert.strictEqual(xjs_Math.clamp(1, 5, 3), 3) - assert.strictEqual(xjs_Math.clamp(5, 3, 1), 3) - }) - }) + assert.strictEqual(xjs_Math.clamp(1, 3, 5), 3); + assert.strictEqual(xjs_Math.clamp(3, 1, 5), 3); + assert.strictEqual(xjs_Math.clamp(1, 5, 3), 3); + assert.strictEqual(xjs_Math.clamp(5, 3, 1), 3); + }); + }); describe('.meanArithmetic(...number[]): number', () => { it('returs the arithmetic mean of all arguments.', () => { - assert.strictEqual(xjs_Math.meanArithmetic(10, 15, 20), 15) // (10 + 15 + 20) / 3 - }) + assert.strictEqual(xjs_Math.meanArithmetic(10, 15, 20), 15); // (10 + 15 + 20) / 3 + }); it('throws when ±`Infinity` or `NaN` is received.', () => { - assert.throws(() => xjs_Math.meanArithmetic(10, 18, 20, Infinity), assert.AssertionError) - assert.throws(() => xjs_Math.meanArithmetic(10, 18, 20, NaN ), NaNError) - }) - }) + assert.throws(() => xjs_Math.meanArithmetic(10, 18, 20, Infinity), assert.AssertionError); + assert.throws(() => xjs_Math.meanArithmetic(10, 18, 20, NaN), NaNError); + }); + }); describe('.meanGeometric(...number[]): number', () => { it('returs the geometric mean of all arguments.', () => { - assert.strictEqual(xjs_Math.meanGeometric(3, 4, 18), 6) // (3 * 4 * 18) ** (1/3) - }) + assert.strictEqual(xjs_Math.meanGeometric(3, 4, 18), 6); // (3 * 4 * 18) ** (1/3) + }); it('throws when ±`Infinity` or `NaN` is received.', () => { - assert.throws(() => xjs_Math.meanGeometric(10, 18, 20, Infinity), assert.AssertionError) - assert.throws(() => xjs_Math.meanGeometric(10, 18, 20, NaN ), NaNError) - }) - }) + assert.throws(() => xjs_Math.meanGeometric(10, 18, 20, Infinity), assert.AssertionError); + assert.throws(() => xjs_Math.meanGeometric(10, 18, 20, NaN), NaNError); + }); + }); describe('.meanHarmonic(...number[]): number', () => { it('returs the harmonic mean of all arguments.', () => { - assert.strictEqual(xjs_Math.meanHarmonic(9, 27, 54), 18) // 3 / (1/9 + 1/27 + 1/54) - }) + assert.strictEqual(xjs_Math.meanHarmonic(9, 27, 54), 18); // 3 / (1/9 + 1/27 + 1/54) + }); it('throws when ±`Infinity` or `NaN` is received.', () => { - assert.throws(() => xjs_Math.meanHarmonic(10, 18, 20, Infinity), assert.AssertionError) - assert.throws(() => xjs_Math.meanHarmonic(10, 18, 20, NaN ), NaNError) - }) - }) + assert.throws(() => xjs_Math.meanHarmonic(10, 18, 20, Infinity), assert.AssertionError); + assert.throws(() => xjs_Math.meanHarmonic(10, 18, 20, NaN), NaNError); + }); + }); describe('.interpolateArithmetic(number, number, number?): number', () => { it('computes arithmetic interpolation.', () => { - assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, 0.7), 17) - assert.strictEqual(xjs_Math.interpolateArithmetic(20, 10, 0.7), 13) - assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, 0.0), 10) - assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, 1.0), 20) - assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, 1.3), 23) - assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, -0.3), 7) - }) + assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, 0.7), 17); + assert.strictEqual(xjs_Math.interpolateArithmetic(20, 10, 0.7), 13); + assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, 0.0), 10); + assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, 1.0), 20); + assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, 1.3), 23); + assert.strictEqual(xjs_Math.interpolateArithmetic(10, 20, -0.3), 7); + }); it('throws when ±`Infinity` or `NaN` is received.', () => { - assert.throws(() => xjs_Math.interpolateArithmetic(Infinity, 0), assert.AssertionError) - assert.throws(() => xjs_Math.interpolateArithmetic(NaN , 0), NaNError) - }) - }) + assert.throws(() => xjs_Math.interpolateArithmetic(Infinity, 0), assert.AssertionError); + assert.throws(() => xjs_Math.interpolateArithmetic(NaN, 0), NaNError); + }); + }); describe('.interpolateGeometric(number, number, number?): number', () => { it('computes geometric interpolation.', () => { - assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, 0.7) * 1000) / 1000, 16.245) - assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(20, 10, 0.7) * 1000) / 1000, 12.311) - assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, 0.0) * 1000) / 1000, 10 ) - assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, 1.0) * 1000) / 1000, 20 ) - assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, 1.3) * 1000) / 1000, 24.623) - assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, -0.3) * 1000) / 1000, 8.123) - }) + assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, 0.7) * 1000) / 1000, 16.245); + assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(20, 10, 0.7) * 1000) / 1000, 12.311); + assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, 0.0) * 1000) / 1000, 10); + assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, 1.0) * 1000) / 1000, 20); + assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, 1.3) * 1000) / 1000, 24.623); + assert.strictEqual(Math.round(xjs_Math.interpolateGeometric(10, 20, -0.3) * 1000) / 1000, 8.123); + }); it('throws when ±`Infinity` or `NaN` is received.', () => { - assert.throws(() => xjs_Math.interpolateGeometric(Infinity, 0), assert.AssertionError) - assert.throws(() => xjs_Math.interpolateGeometric(NaN , 0), NaNError) - }) - }) -}) + assert.throws(() => xjs_Math.interpolateGeometric(Infinity, 0), assert.AssertionError); + assert.throws(() => xjs_Math.interpolateGeometric(NaN, 0), NaNError); + }); + }); +}); diff --git a/test/Number.test.ts b/test/Number.test.ts index 61f9eac..e7876bb 100644 --- a/test/Number.test.ts +++ b/test/Number.test.ts @@ -1,40 +1,43 @@ -import * as assert from 'assert' -import {xjs_Number, NumericType} from '../src/class/Number.class.js'; +import * as assert from 'assert'; +import { + xjs_Number, + NumericType, +} from '../src/class/Number.class.js'; import {NaNError} from '../src/class/NaNError.class.js'; describe('xjs.Number', () => { describe('.assertType(number, NumericType?): void', () => { it('returns `void` if no type is given.', () => { - assert.ifError(xjs_Number.assertType(42.24)) - }) + assert.ifError(xjs_Number.assertType(42.24)); + }); it('returns `void` if correct.', () => { new Map([ - [NumericType.INTEGER , [42, -42, 0, -0, 24.00, -24.00]], - [NumericType.NATURAL , [42, 0, -0, 24.00]], - [NumericType.WHOLE , [42, 24.00]], - [NumericType.FLOAT , [42.24, -42.24]], - [NumericType.INFINITE , [Infinity, -Infinity]], + [NumericType.INTEGER, [42, -42, 0, -0, 24.00, -24.00]], + [NumericType.NATURAL, [42, 0, -0, 24.00]], + [NumericType.WHOLE, [42, 24.00]], + [NumericType.FLOAT, [42.24, -42.24]], + [NumericType.INFINITE, [Infinity, -Infinity]], ]).forEach((numbers, type) => { numbers.forEach((n) => { - assert.ifError(xjs_Number.assertType(n, type)) - }) - }) - }) + assert.ifError(xjs_Number.assertType(n, type)); + }); + }); + }); it('throws if incorrect.', () => { new Map([ - [NumericType.INTEGER , [42.24, -42.24]], - [NumericType.NATURAL , [-42, -24.00, 42.24, -42.24]], - [NumericType.WHOLE , [-42, 0, -0, -24.00]], - [NumericType.FLOAT , [42, -42]], - [NumericType.INFINITE , [42, -42, 0, -0, 24.00, -24.00, 42.24, -42.24]], + [NumericType.INTEGER, [42.24, -42.24]], + [NumericType.NATURAL, [-42, -24.00, 42.24, -42.24]], + [NumericType.WHOLE, [-42, 0, -0, -24.00]], + [NumericType.FLOAT, [42, -42]], + [NumericType.INFINITE, [42, -42, 0, -0, 24.00, -24.00, 42.24, -42.24]], ]).forEach((numbers, type) => { numbers.forEach((n) => { - assert.throws(() => xjs_Number.assertType(n, type), assert.AssertionError) - }) - }) - }) + assert.throws(() => xjs_Number.assertType(n, type), assert.AssertionError); + }); + }); + }); it('throws if `NaN` is received.', () => { - assert.throws(() => xjs_Number.assertType(NaN, NumericType.POSITIVE), NaNError) - }) - }) -}) + assert.throws(() => xjs_Number.assertType(NaN, NumericType.POSITIVE), NaNError); + }); + }); +}); diff --git a/test/Object.test.ts b/test/Object.test.ts index ec8de6f..2c2c896 100644 --- a/test/Object.test.ts +++ b/test/Object.test.ts @@ -1,59 +1,65 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {xjs_Object} from '../src/class/Object.class.js'; describe('xjs.Object', () => { describe('.is(T, T, ((any, any) => boolean)?): boolean', () => { it('only checks one level of depth.', () => { - type T = {val: string[]}|string[]|number - const x: {[s: string]: T} = { a: 1, b: ['1'], c: { val: ['one'] } } - const y: {[s: string]: T} = { a: 1, b: ['1'], c: { val: ['one'] } } - assert.strictEqual(xjs_Object.is(x, y), false) - assert.strictEqual(xjs_Object.is(x, y, (x_a: unknown, y_a: unknown) => (assert.deepStrictEqual(x_a, y_a), true)), true) - assert.strictEqual(xjs_Object.is(x, y, (x_a: T , y_a: T ) => (assert.deepStrictEqual(x_a, y_a), true)), true) - }) - }) + type T = {val: string[]} | string[] | number; + const x: {[s: string]: T} = {a: 1, b: ['1'], c: {val: ['one']}}; + const y: {[s: string]: T} = {a: 1, b: ['1'], c: {val: ['one']}}; + assert.strictEqual(xjs_Object.is(x, y), false); + assert.strictEqual(xjs_Object.is(x, y, (x_a: unknown, y_a: unknown) => (assert.deepStrictEqual(x_a, y_a), true)), true); + assert.strictEqual(xjs_Object.is(x, y, (x_a: T, y_a: T) => (assert.deepStrictEqual(x_a, y_a), true)), true); + }); + }); describe('.typeOf(unknown): string', () => { it('returns a more refined result than `typeof` operator.', () => { - assert.strictEqual(xjs_Object.typeOf(null) , 'null' ) - assert.strictEqual(xjs_Object.typeOf([]) , 'array' ) - assert.strictEqual(xjs_Object.typeOf([false, 0, NaN, '', null, true, Infinity, 'true', {}, [] ]) , 'array' ) - assert.strictEqual(xjs_Object.typeOf(NaN) , 'NaN' ) - assert.strictEqual(xjs_Object.typeOf(Infinity) , 'infinite' ) - assert.strictEqual(xjs_Object.typeOf(-42 / 0) , 'infinite' ) - assert.strictEqual(xjs_Object.typeOf(42) , 'number' ) - assert.strictEqual(xjs_Object.typeOf(21 + 21) , 'number' ) - assert.strictEqual(xjs_Object.typeOf(true) , 'boolean' ) - assert.strictEqual(xjs_Object.typeOf('true') , 'string' ) - assert.strictEqual(xjs_Object.typeOf(class { constructor() {} }) , 'function' ) - assert.strictEqual(xjs_Object.typeOf(function () { return 'true' }) , 'function' ) - assert.strictEqual(xjs_Object.typeOf(() => 'true') , 'function' ) - assert.strictEqual(xjs_Object.typeOf(undefined) , 'undefined') - assert.strictEqual(xjs_Object.typeOf((() => { let x; return x; })()) , 'undefined') - }) - }) + assert.strictEqual(xjs_Object.typeOf(null), 'null'); + assert.strictEqual(xjs_Object.typeOf([]), 'array'); + assert.strictEqual(xjs_Object.typeOf([false, 0, NaN, '', null, true, Infinity, 'true', {}, []]), 'array'); + assert.strictEqual(xjs_Object.typeOf(NaN), 'NaN'); + assert.strictEqual(xjs_Object.typeOf(Infinity), 'infinite'); + assert.strictEqual(xjs_Object.typeOf(-42 / 0), 'infinite'); + assert.strictEqual(xjs_Object.typeOf(42), 'number'); + assert.strictEqual(xjs_Object.typeOf(21 + 21), 'number'); + assert.strictEqual(xjs_Object.typeOf(true), 'boolean'); + assert.strictEqual(xjs_Object.typeOf('true'), 'string'); + assert.strictEqual(xjs_Object.typeOf(class { constructor() {} }), 'function'); // eslint-disable-line @typescript-eslint/brace-style + assert.strictEqual(xjs_Object.typeOf(function () { return 'true'; }), 'function'); // eslint-disable-line prefer-arrow-callback, @typescript-eslint/brace-style + assert.strictEqual(xjs_Object.typeOf(() => 'true'), 'function'); + assert.strictEqual(xjs_Object.typeOf(undefined), 'undefined'); + assert.strictEqual(xjs_Object.typeOf((() => { let x; return x; })()), 'undefined'); // eslint-disable-line @typescript-eslint/brace-style + }); + }); describe('.freezeDeep(Readonly): Readonly', () => { it('freezes an object and its properties, recursively.', () => { - const x: any = {first: 1, second: {value: 2}, third: [1, '2', {val: 3}]} + const x: any = {first: 1, second: {value: 2}, third: [1, '2', {val: 3}]}; xjs_Object.freezeDeep(x); - assert.throws(() => { x.fourth = {v: ['4']} }, TypeError) - assert.throws(() => { x.third.push(['4']) }, TypeError) - assert.throws(() => { x.third[2].val = 'three' }, TypeError) - }) + assert.throws(() => { + x.fourth = {v: ['4']}; + }, TypeError); + assert.throws(() => { + x.third.push(['4']); + }, TypeError); + assert.throws(() => { + x.third[2].val = 'three'; + }, TypeError); + }); it('returns the same argument.', () => { - const x = {first: 1, second: {value: 2}, third: [1, '2', {val: 3}]} - const y = xjs_Object.freezeDeep(x) - assert.strictEqual(x, y) - }) - }) + const x = {first: 1, second: {value: 2}, third: [1, '2', {val: 3}]}; + const y = xjs_Object.freezeDeep(x); + assert.strictEqual(x, y); + }); + }); describe('.cloneDeep(T): T', () => { it('returns a cloned object.', () => { - const x = {first: 1, second: {value: 2}, third: [1, '2', {val: 3}]} - const y = xjs_Object.cloneDeep(x) - assert.notStrictEqual(x, y) - assert.deepStrictEqual(x, y) - }) - }) -}) + const x = {first: 1, second: {value: 2}, third: [1, '2', {val: 3}]}; + const y = xjs_Object.cloneDeep(x); + assert.notStrictEqual(x, y); + assert.deepStrictEqual(x, y); + }); + }); +}); diff --git a/test/Promise.test.ts b/test/Promise.test.ts index ac8afcf..1297a66 100644 --- a/test/Promise.test.ts +++ b/test/Promise.test.ts @@ -1,4 +1,4 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {xjs_Promise} from '../src/class/Promise.class.js'; describe('xjs.Promise', () => { @@ -7,17 +7,17 @@ describe('xjs.Promise', () => { assert.strictEqual(await xjs_Promise.any([ Promise.resolve('string1'), Promise.resolve('string2'), - ]), 'string1') + ]), 'string1'); assert.strictEqual(await xjs_Promise.any([ Promise.reject(new Error('an error')), Promise.resolve('a string'), - ]), 'a string') - }) + ]), 'a string'); + }); it('rejects with an array of reasons if all items reject.', async () => { await assert.rejects(xjs_Promise.any([ Promise.reject(new Error('error1')), Promise.reject(new Error('error2')), - ]), Array) - }) - }) -}) + ]), Array); + }); + }); +}); diff --git a/test/Set.test.ts b/test/Set.test.ts index 3678adc..8f04394 100644 --- a/test/Set.test.ts +++ b/test/Set.test.ts @@ -1,40 +1,40 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {xjs_Set} from '../src/class/Set.class.js'; describe('xjs.Set', () => { describe('.isSubsetOf(ReadonlySet, ReadonlySet, ((U, U) -> boolean)?): boolean', () => { it('is true if elements of the first are in the second.', () => { - const x: Set = new Set([3,4]) - assert.ok( xjs_Set.isSubsetOf(x, new Set([0,1,2,0,3,4]))) - assert.ok( xjs_Set.isSubsetOf(x, new Set([3,4,5] ))) - assert.ok( xjs_Set.isSubsetOf(x, new Set([3,3,4,4] ))) - assert.ok( xjs_Set.isSubsetOf(x, new Set([3,4] ))) - assert.ok( xjs_Set.isSubsetOf(x, new Set([3,0,1,4] ))) - assert.ok( xjs_Set.isSubsetOf(x, new Set([3,0,4,1] ))) - assert.ok( xjs_Set.isSubsetOf(x, new Set([4,3] ))) - assert.ok(!xjs_Set.isSubsetOf(x, new Set([3] ))) - assert.ok(!xjs_Set.isSubsetOf(x, new Set([0,1,3,0,2,5]))) - assert.ok(!xjs_Set.isSubsetOf(x, new Set([2,4] ))) - assert.ok(!xjs_Set.isSubsetOf(x, new Set([0] ))) - }) - }) + const x = new Set([3, 4]); + assert.ok( xjs_Set.isSubsetOf(x, new Set([0, 1, 2, 0, 3, 4]))); + assert.ok( xjs_Set.isSubsetOf(x, new Set([3, 4, 5]))); + assert.ok( xjs_Set.isSubsetOf(x, new Set([3, 3, 4, 4]))); + assert.ok( xjs_Set.isSubsetOf(x, new Set([3, 4]))); + assert.ok( xjs_Set.isSubsetOf(x, new Set([3, 0, 1, 4]))); + assert.ok( xjs_Set.isSubsetOf(x, new Set([3, 0, 4, 1]))); + assert.ok( xjs_Set.isSubsetOf(x, new Set([4, 3]))); + assert.ok(!xjs_Set.isSubsetOf(x, new Set([3]))); + assert.ok(!xjs_Set.isSubsetOf(x, new Set([0, 1, 3, 0, 2, 5]))); + assert.ok(!xjs_Set.isSubsetOf(x, new Set([2, 4]))); + assert.ok(!xjs_Set.isSubsetOf(x, new Set([0]))); + }); + }); describe('.isSupersetOf(ReadonlySet, ReadonlySet, ((T, T) -> boolean)?): boolean', () => { it('is true if elements of the second are in the first.', () => { - const x: Set = new Set([0,1,2,0,3,4]) - assert.ok( xjs_Set.isSupersetOf(x, new Set([3,4] ))) - assert.ok( xjs_Set.isSupersetOf(x, new Set([0,1,2] ))) - assert.ok( xjs_Set.isSupersetOf(x, new Set([0,1,2,0,3,4] ))) - assert.ok( xjs_Set.isSupersetOf(x, new Set([0,3,4] ))) - assert.ok( xjs_Set.isSupersetOf(x, new Set([1] ))) - assert.ok( xjs_Set.isSupersetOf(x, new Set([] ))) - assert.ok( xjs_Set.isSupersetOf(x, new Set([2,4] ))) - assert.ok( xjs_Set.isSupersetOf(x, new Set([4,0] ))) - assert.ok( xjs_Set.isSupersetOf(x, new Set([4,3] ))) - assert.ok(!xjs_Set.isSupersetOf(x, new Set([2,5] ))) - assert.ok(!xjs_Set.isSupersetOf(x, new Set([0,1,2,0,3,4,5]))) - }) - }) + const x = new Set([0, 1, 2, 0, 3, 4]); + assert.ok( xjs_Set.isSupersetOf(x, new Set([3, 4]))); + assert.ok( xjs_Set.isSupersetOf(x, new Set([0, 1, 2]))); + assert.ok( xjs_Set.isSupersetOf(x, new Set([0, 1, 2, 0, 3, 4]))); + assert.ok( xjs_Set.isSupersetOf(x, new Set([0, 3, 4]))); + assert.ok( xjs_Set.isSupersetOf(x, new Set([1]))); + assert.ok( xjs_Set.isSupersetOf(x, new Set([]))); + assert.ok( xjs_Set.isSupersetOf(x, new Set([2, 4]))); + assert.ok( xjs_Set.isSupersetOf(x, new Set([4, 0]))); + assert.ok( xjs_Set.isSupersetOf(x, new Set([4, 3]))); + assert.ok(!xjs_Set.isSupersetOf(x, new Set([2, 5]))); + assert.ok(!xjs_Set.isSupersetOf(x, new Set([0, 1, 2, 0, 3, 4, 5]))); + }); + }); context('Equality Methods', () => { @@ -44,7 +44,7 @@ describe('xjs.Set', () => { describe('.has', () => { it('tests elements by equality.', () => { const el: El = {id: 42}; - const my_set: Set = new Set([el]); + const my_set = new Set([el]); assert.ok(!my_set.has({id: 42}), 'does not contain an equal (but non-identical) element.'); assert.ok(xjs_Set.has(my_set, {id: 42}, comparator), 'contains an equal element.'); assert.ok(xjs_Set.has(my_set, el, comparator), 'contains an identical element.'); @@ -55,7 +55,7 @@ describe('xjs.Set', () => { describe('.add', () => { it('adds equivalent elements.', () => { const el: El = {id: 42}; - const my_set: Set = new Set([el]); + const my_set = new Set([el]); my_set.add({id: 42}); assert.strictEqual(my_set.size, 2, 'adds an equal (but non-identical) element.'); xjs_Set.add(my_set, {id: 42}, comparator); @@ -70,7 +70,7 @@ describe('xjs.Set', () => { describe('.delete', () => { it('deletes equivalent elements.', () => { const el: El = {id: 42}; - const my_set: Set = new Set([el, {id: 43}, {id: 44}]); + const my_set = new Set([el, {id: 43}, {id: 44}]); my_set.delete({id: 42}); assert.strictEqual(my_set.size, 3, 'does not delete an equal (but non-identical) element.'); xjs_Set.delete(my_set, {id: 43}, comparator); @@ -82,4 +82,4 @@ describe('xjs.Set', () => { }); }); }); -}) +}); diff --git a/test/String.test.ts b/test/String.test.ts index 609e23a..4ae5dc9 100644 --- a/test/String.test.ts +++ b/test/String.test.ts @@ -1,22 +1,20 @@ -import * as assert from 'assert' +import * as assert from 'assert'; import {xjs_String} from '../src/class/String.class.js'; -import type { - TemplateTag, -} from '../src/class/String.class.js'; +import type {TemplateTag} from '../src/class/String.class.js'; describe('xjs.String', () => { describe('.stringify(unknown): string', () => { it('is similar to `#toString()`.', () => { - assert.strictEqual(xjs_String.stringify({ an: 'object' }) , '{"an":"object"}') - assert.strictEqual(xjs_String.stringify(['abc', 'def']) , 'abcdef') - assert.strictEqual(xjs_String.stringify(() => 'a function'), "() => 'a function'") - assert.strictEqual(xjs_String.stringify('ghi') , 'ghi') - assert.strictEqual(xjs_String.stringify(123) , '123') - assert.strictEqual(xjs_String.stringify(false) , 'false') - assert.strictEqual(xjs_String.stringify(null) , 'null') - assert.strictEqual(xjs_String.stringify(undefined) , 'undefined') - }) - }) + assert.strictEqual(xjs_String.stringify({an: 'object'}), '{"an":"object"}'); + assert.strictEqual(xjs_String.stringify(['abc', 'def']), 'abcdef'); + assert.strictEqual(xjs_String.stringify(() => 'a function'), '() => \'a function\''); + assert.strictEqual(xjs_String.stringify('ghi'), 'ghi'); + assert.strictEqual(xjs_String.stringify(123), '123'); + assert.strictEqual(xjs_String.stringify(false), 'false'); + assert.strictEqual(xjs_String.stringify(null), 'null'); + assert.strictEqual(xjs_String.stringify(undefined), 'undefined'); + }); + }); describe('.dedent', () => { it('type-checks.', () => { @@ -31,4 +29,4 @@ describe('xjs.String', () => { `, '\nthis will be\ndedented by\nup to\n\t3 tabs\n'); }); }); -}) +}); From e93a68e398ae0754f6566d6adb55dbff54f0d8c7 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:28:50 -0400 Subject: [PATCH 09/33] style: add access modifiers --- src/class/Array.class.ts | 34 ++++++++++++------------ src/class/BigInt.class.ts | 2 +- src/class/Date.class.ts | 10 +++---- src/class/IndexOutOfBoundsError.class.ts | 6 ++--- src/class/Map.class.ts | 22 +++++++-------- src/class/Math.class.ts | 28 +++++++++---------- src/class/NaNError.class.ts | 2 +- src/class/Number.class.ts | 6 ++--- src/class/Object.class.ts | 14 +++++----- src/class/Promise.class.ts | 24 ++++++++--------- src/class/Set.class.ts | 30 ++++++++++----------- src/class/String.class.ts | 4 +-- test/Object.test.ts | 2 +- 13 files changed, 92 insertions(+), 92 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index fcf7d4d..cff7c48 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -19,7 +19,7 @@ export class xjs_Array { * @throws {NaNError} if the given index is `NaN` * @throws {IndexOutOfBoundsError} if the index is out of bounds (or if the returned value is `undefined`) */ - static get(arr: T[], index: number): T { + public static get(arr: T[], index: number): T { xjs_Number.assertType(index); if (arr[index] === void 0) { throw new IndexOutOfBoundsError(index); @@ -58,7 +58,7 @@ export class xjs_Array { * @throws {RangeError} if the second array is larger than the first * @deprecated use {@link xjs_Array.isConsecutiveSuperarrayOf} instead. */ - static contains(larger: readonly T[], smaller: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static contains(larger: readonly T[], smaller: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { if (smaller.length > larger.length) { throw new RangeError('First argument cannot be smaller than the second. Try switching the arguments.'); } @@ -86,7 +86,7 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Are corresponding elements the same, i.e. replaceable? */ - static is(a: readonly T[], b: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static is(a: readonly T[], b: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { if (a === b) { return true; } @@ -111,7 +111,7 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Is `a` a subarray of `b`? */ - static isSubarrayOf(a: readonly T[], b: readonly U[], predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { + public static isSubarrayOf(a: readonly T[], b: readonly U[], predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { return a.length <= b.length && ( a.length === 0 || xjs_Array.is(a, b, predicate) @@ -130,7 +130,7 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns exactly `xjs_Array.isSubarrayOf(b, a, predicate)` */ - static isSuperarrayOf(a: readonly T[], b: readonly U[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static isSuperarrayOf(a: readonly T[], b: readonly U[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { return xjs_Array.isSubarrayOf(b, a, predicate); } @@ -143,7 +143,7 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Is `a` a consecutive subarray of `b`? */ - static isConsecutiveSubarrayOf(a: readonly T[], b: readonly U[], predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { + public static isConsecutiveSubarrayOf(a: readonly T[], b: readonly U[], predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { return xjs_Array.isSubarrayOf(a, b, predicate) && b.map((_el, i) => b.slice(i, i + a.length)).some((sub) => xjs_Array.is(a, sub, predicate)); } @@ -156,7 +156,7 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns exactly `xjs_Array.isConsecutiveSubarrayOf(b, a, predicate)` */ - static isConsecutiveSuperarrayOf(a: readonly T[], b: readonly U[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static isConsecutiveSuperarrayOf(a: readonly T[], b: readonly U[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { return xjs_Array.isConsecutiveSubarrayOf(b, a, predicate); } @@ -167,7 +167,7 @@ export class xjs_Array { * @returns the last entry of the array, if the array is nonempty * @throws {RangeError} if the array is empty */ - static peek(arr: readonly T[]): T { + public static peek(arr: readonly T[]): T { if (!arr.length) { throw new RangeError('Cannot peek an empty array.'); } @@ -183,7 +183,7 @@ export class xjs_Array { * @param this_arg object to use as `this` when executing `predicate` * @returns a new array with the elements that pass the test; if no elements pass, an empty array is returned */ - static async filterAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise | boolean, this_arg: unknown = null): Promise { + public static async filterAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise | boolean, this_arg: unknown = null): Promise { let tests: boolean[] = await Promise.all(arr.map((el, i) => predicate.call(this_arg, el, i, arr))); return arr.filter((_, i) => tests[i]); } @@ -196,7 +196,7 @@ export class xjs_Array { * @param this_arg object to use as `this` when executing `predicate` * @returns the item found, or `null` if none is found */ - static async findAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise | boolean, this_arg: unknown = null): Promise { + public static async findAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise | boolean, this_arg: unknown = null): Promise { return (await xjs_Array.filterAsync(arr, predicate, this_arg))[0] || null; } @@ -228,7 +228,7 @@ export class xjs_Array { * @throws {AggregateError} if two or more iterations throws an error * @throws {Error} if one iteration throws an error */ - static forEachAggregated(array: readonly T[], callback: (item: T, i: number, src: readonly T[]) => void): void { + public static forEachAggregated(array: readonly T[], callback: (item: T, i: number, src: readonly T[]) => void): void { const errors: readonly Error[] = array.map((it, i, src) => { try { callback.call(null, it, i, src); @@ -286,7 +286,7 @@ export class xjs_Array { * @throws {AggregateError} if two or more iterations throws an error * @throws {Error} if one iteration throws an error */ - static mapAggregated(array: readonly T[], callback: (item: T, i: number, src: readonly T[]) => U): U[] { + public static mapAggregated(array: readonly T[], callback: (item: T, i: number, src: readonly T[]) => U): U[] { const results: Array<[U, true] | [Error, false]> = array.map((it, i, src) => { try { return [callback(it, i, src), true]; @@ -314,7 +314,7 @@ export class xjs_Array { * @returns the given array, with everything frozen * @deprecated use interface `readonly T[]` instead */ - static freezeDeep(arr: readonly T[]): readonly T[] { + public static freezeDeep(arr: readonly T[]): readonly T[] { Object.freeze(arr); arr.forEach((el) => { if (!Object.isFrozen(el)) { @@ -334,7 +334,7 @@ export class xjs_Array { * @param arr the array to clone * @returns an exact copy of the given array */ - static cloneDeep(arr: readonly T[]): T[] { + public static cloneDeep(arr: readonly T[]): T[] { return arr.map((el) => xjs_Object.cloneDeep(el)); } @@ -351,7 +351,7 @@ export class xjs_Array { * @returns a new array, with duplicates removed * @deprecated use `[...new Set(arr)]` instead */ - static removeDuplicates(arr: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): T[] { + public static removeDuplicates(arr: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): T[] { const returned: T[] = arr.slice(); for (let i = 0; i < returned.length; i++) { for (let j = i + 1; j < returned.length; j++) { @@ -385,7 +385,7 @@ export class xjs_Array { * @returns a copy of the given array, but with no ‘holes’; * the returned array might have a smaller `length` than the argument */ - static densify(arr: readonly T[]): T[] { + public static densify(arr: readonly T[]): T[] { const newarr: T[] = []; arr.forEach((el) => { // `Array#forEach` does not iterate over holes in sparse arrays newarr.push(el); @@ -413,7 +413,7 @@ export class xjs_Array { * @returns a copy of the given array, but with all holes and `undefined`s filled; * the returned array will have the same length as the argument */ - static fillHoles(arr: readonly T[], value: T): T[] { + public static fillHoles(arr: readonly T[], value: T): T[] { const newarr: T[] = arr.slice(); for (let i = 0; i < newarr.length; i++) { // `Array#forEach` does not iterate over holes in sparse arrays if (newarr[i] === void 0) { diff --git a/src/class/BigInt.class.ts b/src/class/BigInt.class.ts index 39094bd..f4b9535 100644 --- a/src/class/BigInt.class.ts +++ b/src/class/BigInt.class.ts @@ -37,7 +37,7 @@ export class xjs_BigInt { * @param type one of the string literals listed above * @throws {AssertionError} if the argument does not match the described type */ - static assertType(int: bigint, type?: NumericType | 'integer' | 'natural' | 'whole' | 'float' | 'positive' | 'negative' | 'non-positive' | 'non-negative' | 'non-zero' | 'finite' | 'infinite'): void { + public static assertType(int: bigint, type?: NumericType | 'integer' | 'natural' | 'whole' | 'float' | 'positive' | 'negative' | 'non-positive' | 'non-negative' | 'non-zero' | 'finite' | 'infinite'): void { if (type === void 0) { return; } diff --git a/src/class/Date.class.ts b/src/class/Date.class.ts index e8daebc..9376a9a 100644 --- a/src/class/Date.class.ts +++ b/src/class/Date.class.ts @@ -7,7 +7,7 @@ export class xjs_Date { /** * The list of full month names in English. */ - static readonly MONTH_NAMES = [ + public static readonly MONTH_NAMES = [ 'January', 'February', 'March', @@ -25,7 +25,7 @@ export class xjs_Date { /** * The list of full day names in English. */ - static readonly DAY_NAMES = [ + public static readonly DAY_NAMES = [ 'Sundary', 'Monday', 'Tuesday', @@ -43,7 +43,7 @@ export class xjs_Date { * @param date2 the second date * @returns does 'YYYY-MM-DD' of `date1` equal 'YYYY-MM-DD' of `date2`? */ - static sameDate(date1: Date, date2: Date): boolean { + public static sameDate(date1: Date, date2: Date): boolean { return date1.toISOString().slice(0, 10) === date2.toISOString().slice(0, 10); } @@ -58,7 +58,7 @@ export class xjs_Date { * @param date a Date object * @returns the proportion */ - static timeProportion(date: Date): number { + public static timeProportion(date: Date): number { let millis = date.getUTCMilliseconds() / 1000; let seconds = (date.getUTCSeconds() + millis) / 60; let minutes = (date.getUTCMinutes() + seconds) / 60; @@ -88,7 +88,7 @@ export class xjs_Date { * @param format one of the enumerated options listed in the description * @returns a string representing the given date in the given format */ - static format(date: Date, format: string): string { + public static format(date: Date, format: string): string { const MONTHS = xjs_Date.MONTH_NAMES; const leadingZero = (n: number, r: number = 10) => `0${ n.toString(r) }`.slice(-2); const defaultFormatter = (date: Date) => date.toISOString(); diff --git a/src/class/IndexOutOfBoundsError.class.ts b/src/class/IndexOutOfBoundsError.class.ts index d952958..1cec5f4 100644 --- a/src/class/IndexOutOfBoundsError.class.ts +++ b/src/class/IndexOutOfBoundsError.class.ts @@ -9,13 +9,13 @@ export class IndexOutOfBoundsError extends RangeError { * Construct a new IndexOutOfBoundsError object. * @param message Optional. A human-readable description of the error. */ - constructor(message?: string); + public constructor(message?: string); /** * Construct a new IndexOutOfBoundsError object. * @param index the index that is out of bounds */ - constructor(index: number); - constructor(i: string | number = 'Index out of bounds.') { + public constructor(index: number); + public constructor(i: string | number = 'Index out of bounds.') { super((typeof i === 'string') ? i : `Index \`${ (xjs_Number.assertType(i), i) }\` out of bounds.`); this.name = 'IndexOutOfBoundsError'; } diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index 166a780..69b276b 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -18,7 +18,7 @@ export class xjs_Map { * @param b the second map * @returns Are corresponding pairs the same, i.e. replaceable? */ - static is(a: ReadonlyMap, b: ReadonlyMap, { + public static is(a: ReadonlyMap, b: ReadonlyMap, { /** check the “sameness” of corresponding keys of `a` and `b` */ keys = xjs_Object.sameValueZero, /** check the “sameness” of corresponding values of `a` and `b` */ @@ -49,7 +49,7 @@ export class xjs_Map { * @param this_arg object to use as `this` when executing `predicate` * @returns a new map with the entries that pass the test; if no entries pass, an empty map is returned */ - static filter(map: ReadonlyMap, predicate: (value: V, key: K, map: ReadonlyMap) => boolean, this_arg: unknown = null): Map { + public static filter(map: ReadonlyMap, predicate: (value: V, key: K, map: ReadonlyMap) => boolean, this_arg: unknown = null): Map { return new Map([...map].filter((entry) => predicate.call(this_arg, entry[1], entry[0], map))); } @@ -63,7 +63,7 @@ export class xjs_Map { * @param this_arg object to use as `this` when executing `predicate` * @returns the value found, or `null` if none is found */ - static find(map: ReadonlyMap, predicate: (value: V, key: K, map: ReadonlyMap) => boolean, this_arg: unknown = null): V | null { + public static find(map: ReadonlyMap, predicate: (value: V, key: K, map: ReadonlyMap) => boolean, this_arg: unknown = null): V | null { return [...xjs_Map.filter(map, predicate, this_arg)].map((entry) => entry[1])[0] || null; } @@ -77,7 +77,7 @@ export class xjs_Map { * @param this_arg object to use as `this` when executing `predicate` * @returns the key found, or `null` if none is found */ - static findKey(map: ReadonlyMap, predicate: (key: K, index: number, map: ReadonlyMap) => boolean, this_arg: unknown = null): K | null { + public static findKey(map: ReadonlyMap, predicate: (key: K, index: number, map: ReadonlyMap) => boolean, this_arg: unknown = null): K | null { return [...map.keys()].find((key, i) => predicate.call(this_arg, key, i, map)) || null; } @@ -92,7 +92,7 @@ export class xjs_Map { * @param this_arg object to use as `this` when executing `callback` * @returns a new Map with the same keys and transformed values obtained from `callback` */ - static mapValues(map: ReadonlyMap, callback: (value: V, key: K, map: ReadonlyMap) => T, this_arg: unknown = null): Map { + public static mapValues(map: ReadonlyMap, callback: (value: V, key: K, map: ReadonlyMap) => T, this_arg: unknown = null): Map { return new Map([...map].map(([key, value]) => [key, callback.call(this_arg, value, key, map)] as [K, T])); } @@ -107,7 +107,7 @@ export class xjs_Map { * @param this_arg object to use as `this` when executing `callback` * @returns a new Map with transformed keys obtained from `callback` and the same values */ - static mapKeys(map: ReadonlyMap, callback: (value: V, key: K, map: ReadonlyMap) => T, this_arg: unknown = null): Map { + public static mapKeys(map: ReadonlyMap, callback: (value: V, key: K, map: ReadonlyMap) => T, this_arg: unknown = null): Map { return new Map([...map].map(([key, value]) => [callback.call(this_arg, value, key, map), value] as [T, V])); } @@ -118,7 +118,7 @@ export class xjs_Map { * @param value the value * @returns the value */ - static tee(map: Map, key: K, value: V): V { + public static tee(map: Map, key: K, value: V): V { map.set(key, value); return value; } @@ -130,7 +130,7 @@ export class xjs_Map { * @param comparator a comparator function of keys * @return Does the set have the given key? */ - static has(map: ReadonlyMap, key: K, comparator: (a: K, b: K) => boolean): boolean { + public static has(map: ReadonlyMap, key: K, comparator: (a: K, b: K) => boolean): boolean { return [...map.keys()].some((k) => comparator.call(null, k, key)); } @@ -141,7 +141,7 @@ export class xjs_Map { * @param comparator a comparator function of keys * @return the value corresponding to the key */ - static get(map: ReadonlyMap, key: K, comparator: (a: K, b: K) => boolean): V | undefined { + public static get(map: ReadonlyMap, key: K, comparator: (a: K, b: K) => boolean): V | undefined { return [...map].find(([k, _]) => comparator.call(null, k, key))?.[1]; } @@ -152,7 +152,7 @@ export class xjs_Map { * @param comparator a comparator function of keys * @return the mutated map */ - static set(map: Map, key: K, value: V, comparator: (a: K, b: K) => boolean): Map { + public static set(map: Map, key: K, value: V, comparator: (a: K, b: K) => boolean): Map { const foundkey: K | undefined = [...map.keys()].find((k) => comparator.call(null, k, key)); return map.set((foundkey === undefined) ? key : foundkey, value); } @@ -164,7 +164,7 @@ export class xjs_Map { * @param comparator a comparator function of keys * @return Was the map mutated? */ - static delete(map: Map, key: K, comparator: (a: K, b: K) => boolean): boolean { + public static delete(map: Map, key: K, comparator: (a: K, b: K) => boolean): boolean { const foundkey: K | undefined = [...map.keys()].find((k) => comparator.call(null, k, key)); return map.delete((foundkey === undefined) ? key : foundkey); } diff --git a/src/class/Math.class.ts b/src/class/Math.class.ts index 55a5f3e..ef6b9dd 100644 --- a/src/class/Math.class.ts +++ b/src/class/Math.class.ts @@ -21,7 +21,7 @@ export class xjs_Math { * @param epsilon the interval of refinement * @returns are `x` and `y` within `epsilon` distance apart? */ - static approx(x: number, y: number, epsilon: number = Number.EPSILON): boolean { + public static approx(x: number, y: number, epsilon: number = Number.EPSILON): boolean { xjs_Number.assertType(x); xjs_Number.assertType(y); xjs_Number.assertType(epsilon); @@ -36,7 +36,7 @@ export class xjs_Math { * @param w weight of 2nd number; between 0–1 * @returns exactly `interpolateArithmetic(x, y, w)` */ - static average(x: number, y: number, w = 0.5): number { + public static average(x: number, y: number, w = 0.5): number { return xjs_Math.interpolateArithmetic(x, y, w); } @@ -46,7 +46,7 @@ export class xjs_Math { * @returns the minimum argument * @throws if no arguments are supplied */ - static minBigInt(...ints: bigint[]): bigint { + public static minBigInt(...ints: bigint[]): bigint { if (!ints.length) { throw new Error('No arguments supplied.'); } @@ -59,7 +59,7 @@ export class xjs_Math { * @returns the maximum argument * @throws if no arguments are supplied */ - static maxBigInt(...ints: bigint[]): bigint { + public static maxBigInt(...ints: bigint[]): bigint { if (!ints.length) { throw new Error('No arguments supplied.'); } @@ -79,7 +79,7 @@ export class xjs_Math { * @param max - the upper bound * @returns `Math.min(Math.max(min, x), max)` */ - static clamp(min: number, val: number, max: number): number { + public static clamp(min: number, val: number, max: number): number { xjs_Number.assertType(min); xjs_Number.assertType(val); xjs_Number.assertType(max); @@ -93,7 +93,7 @@ export class xjs_Math { * @param max - the upper bound * @returns the clamped value */ - static clampBigInt(min: bigint, val: bigint, max: bigint): bigint { + public static clampBigInt(min: bigint, val: bigint, max: bigint): bigint { return (min <= max) ? xjs_Math.minBigInt(xjs_Math.maxBigInt(min, val), max) : xjs_Math.clampBigInt(max, val, min); } @@ -109,7 +109,7 @@ export class xjs_Math { * @throws {Error} if one of the numbers is not finite * @throws {NaNError} if one of the numbers is `NaN` */ - static meanArithmetic(...nums: number[]): number { + public static meanArithmetic(...nums: number[]): number { nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)); // NB re-throw return nums.reduce((x, y) => x + y) * (1 / nums.length); } @@ -126,7 +126,7 @@ export class xjs_Math { * @throws {Error} if one of the numbers is not finite * @throws {NaNError} if one of the numbers is `NaN` */ - static meanGeometric(...nums: number[]): number { + public static meanGeometric(...nums: number[]): number { nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)); // NB re-throw return Math.abs(nums.reduce((x, y) => x * y)) ** (1 / nums.length); } @@ -143,7 +143,7 @@ export class xjs_Math { * @throws {Error} if one of the numbers is not finite * @throws {NaNError} if one of the numbers is `NaN` */ - static meanHarmonic(...nums: number[]): number { + public static meanHarmonic(...nums: number[]): number { nums.forEach((n) => xjs_Number.assertType(n, NumericType.FINITE)); // NB re-throw return 1 / xjs_Math.meanArithmetic(...nums.map((x) => 1 / x)); } @@ -171,7 +171,7 @@ export class xjs_Math { * @throws {Error} if `a`, `b`, or `p` is not a finite number * @throws {NaNError} if an argument is `NaN` */ - static interpolateArithmetic(a: number, b: number, p: number = 0.5): number { + public static interpolateArithmetic(a: number, b: number, p: number = 0.5): number { xjs_Number.assertType(a, NumericType.FINITE); xjs_Number.assertType(b, NumericType.FINITE); xjs_Number.assertType(p, NumericType.FINITE); @@ -201,7 +201,7 @@ export class xjs_Math { * @throws {Error} if `a`, `b`, or `p` is not a finite number * @throws {NaNError} if an argument is `NaN` */ - static interpolateGeometric(a: number, b: number, p: number = 0.5): number { + public static interpolateGeometric(a: number, b: number, p: number = 0.5): number { xjs_Number.assertType(a, NumericType.FINITE); xjs_Number.assertType(b, NumericType.FINITE); xjs_Number.assertType(p, NumericType.FINITE); @@ -231,7 +231,7 @@ export class xjs_Math { * @throws {Error} if `a`, `b`, or `p` is not a finite number * @throws {NaNError} if an argument is `NaN` */ - static interpolateHarmonic(a: number, b: number, p: number = 0.5): number { + public static interpolateHarmonic(a: number, b: number, p: number = 0.5): number { xjs_Number.assertType(a, NumericType.FINITE); xjs_Number.assertType(b, NumericType.FINITE); xjs_Number.assertType(p, NumericType.FINITE); @@ -249,7 +249,7 @@ export class xjs_Math { * @returns exactly `((x % n) + n) % n` * @throws {Error} if `n` is not a positive integer */ - static mod(x: number, n: number | bigint): number { + public static mod(x: number, n: number | bigint): number { xjs_Number.assertType(x, NumericType.FINITE); if (typeof n === 'number') { xjs_Number.assertType(n, NumericType.WHOLE); @@ -284,7 +284,7 @@ export class xjs_Math { * @returns informally, `x *** n` * @throws {Error} if `n` is not a non-negative integer */ - static tetrate(x: number, n: number): number { + public static tetrate(x: number, n: number): number { xjs_Number.assertType(x, NumericType.FINITE); xjs_Number.assertType(n, NumericType.NATURAL); return (n === 0) ? 1 : x ** xjs_Math.tetrate(x, n - 1); diff --git a/src/class/NaNError.class.ts b/src/class/NaNError.class.ts index 38e4b43..89ccd90 100644 --- a/src/class/NaNError.class.ts +++ b/src/class/NaNError.class.ts @@ -6,7 +6,7 @@ export class NaNError extends RangeError { * Construct a new NaNError object. * @param message Optional. A human-readable description of the error. */ - constructor(message: string = 'Unacceptable argument `NaN`.') { + public constructor(message: string = 'Unacceptable argument `NaN`.') { super(message); this.name = 'NaNError'; } diff --git a/src/class/Number.class.ts b/src/class/Number.class.ts index 66f4a16..8a16f86 100644 --- a/src/class/Number.class.ts +++ b/src/class/Number.class.ts @@ -27,7 +27,7 @@ export class xjs_Number { /** * An immutable RegExp instance, representing a string in Number format. */ - static readonly REGEXP: Readonly = /^-?(?:\d+(?:\.\d+)?|\.\d+)$/; + public static readonly REGEXP: Readonly = /^-?(?:\d+(?:\.\d+)?|\.\d+)$/; /** * Verify the type of number given, throwing if it does not match. @@ -58,7 +58,7 @@ export class xjs_Number { * @throws {AssertionError} if the argument does not match the described type * @throws {NaNError} if the argument is `NaN` */ - static assertType(num: number, type?: NumericType | 'integer' | 'natural' | 'whole' | 'float' | 'positive' | 'negative' | 'non-positive' | 'non-negative' | 'non-zero' | 'finite' | 'infinite'): void { + public static assertType(num: number, type?: NumericType | 'integer' | 'natural' | 'whole' | 'float' | 'positive' | 'negative' | 'non-positive' | 'non-negative' | 'non-zero' | 'finite' | 'infinite'): void { if (Number.isNaN(num)) { throw new NaNError(); } @@ -113,7 +113,7 @@ export class xjs_Number { * @returns one of the strings described above * @throws {RangeError} if the given arguemnt was not a finite number */ - static typeOf(num: number): 'integer' | 'float' { + public static typeOf(num: number): 'integer' | 'float' { console.warn('`xjs.Number.typeOf` is DEPRECATED: use `xjs.Number.assertType` instead.'); if (['NaN', 'infinite'].includes(xjs_Object.typeOf(num))) { throw new RangeError('Argument must be a finite number.'); diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index e42ff83..ac7538a 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -48,7 +48,7 @@ export class xjs_Object { * @returns Are corresponding properties the same, i.e. replaceable? * @throws {TypeError} if either `a` or `b` is a function (not supported) */ - static is(a: T, b: T, predicate: (x: any, y: any) => boolean = xjs_Object.sameValueZero): boolean { + public static is(a: T, b: T, predicate: (x: any, y: any) => boolean = xjs_Object.sameValueZero): boolean { if (a === b) { return true; } @@ -79,7 +79,7 @@ export class xjs_Object { * @param b the second thing * @returns exactly `a === b || Object.is(a, b)` */ - static sameValueZero(a: unknown, b: unknown): boolean { + public static sameValueZero(a: unknown, b: unknown): boolean { return a === b || Object.is(a, b); } @@ -161,7 +161,7 @@ export class xjs_Object { * @returns the looked-up function, returning * @throws {ReferenceError} when failing to find a lookup value */ - static switch(key: string, dictionary: { [index: string]: (this: any, ...args: any[]) => T }): (this: any, ...args: any[]) => T { + public static switch(key: string, dictionary: { [index: string]: (this: any, ...args: any[]) => T }): (this: any, ...args: any[]) => T { let returned: (this: any, ...args: any[]) => T = dictionary[key]; if (!returned) { console.warn(`Key '${ key }' cannot be found. Using key 'default'…`); @@ -203,7 +203,7 @@ export class xjs_Object { * @param thing anything * @returns the type of the thing */ - static typeOf(thing: unknown): string { + public static typeOf(thing: unknown): string { return (new Map string>([ ['object', (arg: unknown) => (arg === null) ? 'null' : (Array.isArray(arg)) ? 'array' : 'object'], ['number', (arg: number) => (Number.isNaN(arg)) ? 'NaN' : (!Number.isFinite(arg)) ? 'infinite' : 'number'], @@ -227,7 +227,7 @@ export class xjs_Object { * @returns the name of the constructing function * @throws {TypeError} if `null` or `undefined` is passed */ - static instanceOf(thing: unknown): string { + public static instanceOf(thing: unknown): string { if (thing === null || thing === undefined) { throw new TypeError(`\`${ thing }\` does not have a construtor.`); } @@ -249,7 +249,7 @@ export class xjs_Object { * @returns the given value, with everything frozen * @deprecated use interface `Readonly` instead */ - static freezeDeep(thing: Readonly): Readonly { + public static freezeDeep(thing: Readonly): Readonly { if (thing instanceof Array) { return xjs_Array.freezeDeep(thing) as unknown as T; // HACK https://stackoverflow.com/a/18736071/ } @@ -319,7 +319,7 @@ export class xjs_Object { * @param thing any value to clone * @returns an exact copy of the given value, but with nothing equal via `===` (unless the value given is primitive) */ - static cloneDeep(thing: T): T { + public static cloneDeep(thing: T): T { if (thing instanceof Array) { return xjs_Array.cloneDeep(thing) as unknown as T; // HACK https://stackoverflow.com/a/18736071/ } diff --git a/src/class/Promise.class.ts b/src/class/Promise.class.ts index aef8714..933ebff 100644 --- a/src/class/Promise.class.ts +++ b/src/class/Promise.class.ts @@ -15,18 +15,18 @@ export class xjs_Promise { * @returns A new Promise. * @deprecated Use native [Promise.any](https://tc39.es/ecma262/#sec-promise.any) instead. */ - static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise, T6 | Promise, T7 | Promise, T8 | Promise, T9 | Promise]): Promise; - static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise, T6 | Promise, T7 | Promise, T8 | Promise ]): Promise; - static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise, T6 | Promise, T7 | Promise ]): Promise; - static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise, T6 | Promise ]): Promise; - static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise ]): Promise; - static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise ]): Promise; - static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise ]): Promise; - static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise ]): Promise; - static async any(values: [T0 | Promise, T1 | Promise ]): Promise; - static async any(values: [T0 | Promise ]): Promise; - static async any(values: Array>): Promise; - static async any(values: unknown[]): Promise { + public static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise, T6 | Promise, T7 | Promise, T8 | Promise, T9 | Promise]): Promise; + public static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise, T6 | Promise, T7 | Promise, T8 | Promise ]): Promise; + public static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise, T6 | Promise, T7 | Promise ]): Promise; + public static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise, T6 | Promise ]): Promise; + public static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise, T5 | Promise ]): Promise; + public static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise , T4 | Promise ]): Promise; + public static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise, T3 | Promise ]): Promise; + public static async any(values: [T0 | Promise, T1 | Promise, T2 | Promise ]): Promise; + public static async any(values: [T0 | Promise, T1 | Promise ]): Promise; + public static async any(values: [T0 | Promise ]): Promise; + public static async any(values: Array>): Promise; + public static async any(values: unknown[]): Promise { return Promise.all(values.map((p) => (!(p instanceof Promise)) ? Promise.reject(p) : p.then( (val) => Promise.reject (val), (err) => Promise.resolve(err), diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index 373a840..cb3590e 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -18,7 +18,7 @@ export class xjs_Set { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Are corresponding elements the same, i.e. replaceable? */ - static is(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static is(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { if (a === b) { return true; } @@ -36,7 +36,7 @@ export class xjs_Set { * @param this_arg object to use as `this` when executing `predicate` * @returns a new set with the elements that pass the test; if no elements pass, an empty set is returned */ - static filter(set: Set, predicate: (element: T, index: T, set: Set) => boolean, this_arg: unknown = null): Set { + public static filter(set: Set, predicate: (element: T, index: T, set: Set) => boolean, this_arg: unknown = null): Set { return new Set([...set].filter((el) => predicate.call(this_arg, el, el, set))); } @@ -49,7 +49,7 @@ export class xjs_Set { * @param this_arg object to use as `this` when executing `predicate` * @returns the item found, or `null` if none is found */ - static find(set: Set, predicate: (element: T, index: T, set: Set) => boolean, this_arg: unknown = null): T | null { + public static find(set: Set, predicate: (element: T, index: T, set: Set) => boolean, this_arg: unknown = null): T | null { return [...xjs_Set.filter(set, predicate, this_arg)][0] || null; } @@ -63,7 +63,7 @@ export class xjs_Set { * @param this_arg object to use as `this` when executing `callback` * @returns a new Set with transformed elements obtained from `callback` */ - static map(set: Set, callback: (element: T, index: T, set: Set) => U, this_arg: unknown = null): Set { + public static map(set: Set, callback: (element: T, index: T, set: Set) => U, this_arg: unknown = null): Set { return new Set([...set].map((el) => callback.call(this_arg, el, el, set))); } @@ -80,7 +80,7 @@ export class xjs_Set { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Is `a` a subset of `b`? */ - static isSubsetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { + public static isSubsetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { return xjs_Array.isSubarrayOf([...a].sort(), [...b].sort(), predicate); } @@ -94,7 +94,7 @@ export class xjs_Set { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns exactly `xjs.Set.isSubsetOf(b, a, predicate)` */ - static isSupersetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static isSupersetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { return xjs_Set.isSubsetOf(b, a, predicate); } @@ -108,7 +108,7 @@ export class xjs_Set { * @param comparator a comparator function * @returns a new Set containing the elements present in either `a` or `b` (or both) */ - static union(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set { + public static union(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set { const returned = new Set(a); b.forEach((el) => { if (!comparator) { @@ -130,8 +130,8 @@ export class xjs_Set { * @param comparator a comparator function * @returns a new Set containing the elements present only in both `a` and `b` */ - static intersection(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T & U, b: T & U) => boolean): Set; - static intersection(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T, b: T) => boolean): Set { + public static intersection(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T & U, b: T & U) => boolean): Set; + public static intersection(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T, b: T) => boolean): Set { const returned = new Set(); b.forEach((el) => { if (!comparator) { @@ -157,8 +157,8 @@ export class xjs_Set { * @param comparator a comparator function * @returns a new Set containing the elements present only in `a` */ - static difference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set; - static difference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T, b: T) => boolean): Set { + public static difference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set; + public static difference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T, b: T) => boolean): Set { const returned = new Set(); a.forEach((el) => { if (!comparator) { @@ -188,7 +188,7 @@ export class xjs_Set { * @param comparator a comparator function * @returns a new Set containing the elements present only in `a` or only in `b`, but not both */ - static symmetricDifference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set { + public static symmetricDifference(a: ReadonlySet, b: ReadonlySet, comparator?: (a: T | U, b: T | U) => boolean): Set { return xjs_Set.difference( xjs_Set.union(a, b, comparator), xjs_Set.intersection(a, b, comparator), @@ -203,7 +203,7 @@ export class xjs_Set { * @param comparator a comparator function * @return Does the set have the given element? */ - static has(set: ReadonlySet, element: T, comparator: (a: T, b: T) => boolean): boolean { + public static has(set: ReadonlySet, element: T, comparator: (a: T, b: T) => boolean): boolean { return [...set].some((e) => comparator.call(null, e, element)); } @@ -214,7 +214,7 @@ export class xjs_Set { * @param comparator a comparator function * @return the mutated set */ - static add(set: Set, element: T, comparator: (a: T, b: T) => boolean): typeof set { + public static add(set: Set, element: T, comparator: (a: T, b: T) => boolean): typeof set { const foundel: boolean = [...set].some((e) => comparator.call(null, e, element)); return (!foundel) ? set.add(element) : set; } @@ -226,7 +226,7 @@ export class xjs_Set { * @param comparator a comparator function * @return Was the set mutated? */ - static delete(set: Set, element: T, comparator: (a: T, b: T) => boolean): boolean { + public static delete(set: Set, element: T, comparator: (a: T, b: T) => boolean): boolean { const foundel: T | undefined = [...set].find((e) => comparator.call(null, e, element)); return set.delete((foundel === undefined) ? element : foundel); } diff --git a/src/class/String.class.ts b/src/class/String.class.ts index 967a612..c5c41d6 100644 --- a/src/class/String.class.ts +++ b/src/class/String.class.ts @@ -38,7 +38,7 @@ export class xjs_String { * @param thing anything to convert * @returns a string version of the argument */ - static stringify(thing: unknown): string { + public static stringify(thing: unknown): string { return new Map string>([ ['object', (arg: object) => JSON.stringify(arg)], ['array', (arg: unknown[]) => arg.join('')], @@ -72,7 +72,7 @@ export class xjs_String { * `); * @returns a string with each line dedented by the determined number of tabs */ - static dedent(strings: TemplateStringsArray, ...interps: unknown[]): string { + public static dedent(strings: TemplateStringsArray, ...interps: unknown[]): string { const matched: RegExpMatchArray | null = strings[0].match(/\n\t*/); const n: number = matched && matched[0] ? matched[0].slice(1).length : 0; function replace(s: string, n: number): string { diff --git a/test/Object.test.ts b/test/Object.test.ts index 2c2c896..f264a92 100644 --- a/test/Object.test.ts +++ b/test/Object.test.ts @@ -25,7 +25,7 @@ describe('xjs.Object', () => { assert.strictEqual(xjs_Object.typeOf(21 + 21), 'number'); assert.strictEqual(xjs_Object.typeOf(true), 'boolean'); assert.strictEqual(xjs_Object.typeOf('true'), 'string'); - assert.strictEqual(xjs_Object.typeOf(class { constructor() {} }), 'function'); // eslint-disable-line @typescript-eslint/brace-style + assert.strictEqual(xjs_Object.typeOf(class { public constructor() {} }), 'function'); // eslint-disable-line @typescript-eslint/brace-style assert.strictEqual(xjs_Object.typeOf(function () { return 'true'; }), 'function'); // eslint-disable-line prefer-arrow-callback, @typescript-eslint/brace-style assert.strictEqual(xjs_Object.typeOf(() => 'true'), 'function'); assert.strictEqual(xjs_Object.typeOf(undefined), 'undefined'); From e486716199d761c347cec37af1f3a75dd16066aa Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:39:15 -0400 Subject: [PATCH 10/33] style: update empty functions --- src/class/Array.class.ts | 1 + src/class/BigInt.class.ts | 5 +++-- src/class/Date.class.ts | 1 + src/class/Map.class.ts | 1 + src/class/Math.class.ts | 1 + src/class/Number.class.ts | 1 + src/class/Object.class.ts | 1 + src/class/Promise.class.ts | 1 + src/class/Set.class.ts | 1 + src/class/String.class.ts | 1 + test/Object.test.ts | 2 +- 11 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index cff7c48..4defa54 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -424,5 +424,6 @@ export class xjs_Array { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/BigInt.class.ts b/src/class/BigInt.class.ts index f4b9535..deb7eb3 100644 --- a/src/class/BigInt.class.ts +++ b/src/class/BigInt.class.ts @@ -61,7 +61,7 @@ export class xjs_BigInt { ]).get(type)); } return new Map void>([ - [NumericType.INTEGER, (_n: bigint) => {}], + [NumericType.INTEGER, (_n: bigint) => assert.ok(true, 'BigInts are always integers.')], [NumericType.NATURAL, ( n: bigint) => xjs_BigInt.assertType(n, NumericType.NONNEGATIVE)], [NumericType.WHOLE, ( n: bigint) => xjs_BigInt.assertType(n, NumericType.POSITIVE)], [NumericType.FLOAT, (_n: bigint) => assert.ok(false, 'BigInts cannot be non-integers.')], @@ -70,11 +70,12 @@ export class xjs_BigInt { [NumericType.NONPOSITIVE, ( n: bigint) => assert.ok(n <= 0n, `${ n } must not be positive.`)], [NumericType.NONNEGATIVE, ( n: bigint) => assert.ok(0n <= n, `${ n } must not be negative.`)], [NumericType.NONZERO, ( n: bigint) => assert.ok(n !== 0n, `${ n } must not be zero.`)], - [NumericType.FINITE, (_n: bigint) => {}], + [NumericType.FINITE, (_n: bigint) => assert.ok(true, 'BigInts are always finite.')], [NumericType.INFINITE, (_n: bigint) => assert.ok(false, 'BigInts cannot be infinite.')], ]).get(type)!(int); } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Date.class.ts b/src/class/Date.class.ts index 9376a9a..88bdeeb 100644 --- a/src/class/Date.class.ts +++ b/src/class/Date.class.ts @@ -110,5 +110,6 @@ export class xjs_Date { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index 69b276b..95dd9cb 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -170,5 +170,6 @@ export class xjs_Map { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Math.class.ts b/src/class/Math.class.ts index ef6b9dd..3ceb3a0 100644 --- a/src/class/Math.class.ts +++ b/src/class/Math.class.ts @@ -291,5 +291,6 @@ export class xjs_Math { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Number.class.ts b/src/class/Number.class.ts index 8a16f86..5712e53 100644 --- a/src/class/Number.class.ts +++ b/src/class/Number.class.ts @@ -122,5 +122,6 @@ export class xjs_Number { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index ac7538a..197237a 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -335,5 +335,6 @@ export class xjs_Object { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Promise.class.ts b/src/class/Promise.class.ts index 933ebff..1f166ca 100644 --- a/src/class/Promise.class.ts +++ b/src/class/Promise.class.ts @@ -37,5 +37,6 @@ export class xjs_Promise { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index cb3590e..410a305 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -232,5 +232,6 @@ export class xjs_Set { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/String.class.ts b/src/class/String.class.ts index c5c41d6..bae2eb6 100644 --- a/src/class/String.class.ts +++ b/src/class/String.class.ts @@ -85,5 +85,6 @@ export class xjs_String { } + // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/test/Object.test.ts b/test/Object.test.ts index f264a92..b2c7fa6 100644 --- a/test/Object.test.ts +++ b/test/Object.test.ts @@ -25,7 +25,7 @@ describe('xjs.Object', () => { assert.strictEqual(xjs_Object.typeOf(21 + 21), 'number'); assert.strictEqual(xjs_Object.typeOf(true), 'boolean'); assert.strictEqual(xjs_Object.typeOf('true'), 'string'); - assert.strictEqual(xjs_Object.typeOf(class { public constructor() {} }), 'function'); // eslint-disable-line @typescript-eslint/brace-style + assert.strictEqual(xjs_Object.typeOf(class { public constructor() {} }), 'function'); // eslint-disable-line @typescript-eslint/brace-style, @typescript-eslint/no-useless-constructor, @typescript-eslint/no-empty-function assert.strictEqual(xjs_Object.typeOf(function () { return 'true'; }), 'function'); // eslint-disable-line prefer-arrow-callback, @typescript-eslint/brace-style assert.strictEqual(xjs_Object.typeOf(() => 'true'), 'function'); assert.strictEqual(xjs_Object.typeOf(undefined), 'undefined'); From 7ccc820dd68efeb78462cd3567d2052635c48fd3 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:45:52 -0400 Subject: [PATCH 11/33] style: update variable/param declarations --- src/class/Array.class.ts | 4 ++-- src/class/Date.class.ts | 34 +++++++++++++++++----------------- src/class/Object.class.ts | 8 ++++---- src/class/String.class.ts | 6 +++--- test/Object.test.ts | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index 4defa54..b0cd00c 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -184,7 +184,7 @@ export class xjs_Array { * @returns a new array with the elements that pass the test; if no elements pass, an empty array is returned */ public static async filterAsync(arr: T[], predicate: (ele: T, idx: number, ary: T[]) => Promise | boolean, this_arg: unknown = null): Promise { - let tests: boolean[] = await Promise.all(arr.map((el, i) => predicate.call(this_arg, el, i, arr))); + const tests: boolean[] = await Promise.all(arr.map((el, i) => predicate.call(this_arg, el, i, arr))); return arr.filter((_, i) => tests[i]); } @@ -377,7 +377,7 @@ export class xjs_Array { * Note that accessor notation is not sufficient to detect sparseness: calling `new Array(4)[0]` * will return `undefined`, even though `undefined` is not an element in the array. * - * For example, `let arr = ['a', 'b', , 'd']` is a sparse array because `arr[2]` has not been defined. + * For example, `const arr = ['a', 'b', , 'd']` is a sparse array because `arr[2]` has not been defined. * Evaluating `arr[2]` will yield `undefined`, even though it has not been explicitly declared so. * * @typeparam T - the type of elements in `arr` diff --git a/src/class/Date.class.ts b/src/class/Date.class.ts index 88bdeeb..d3080e1 100644 --- a/src/class/Date.class.ts +++ b/src/class/Date.class.ts @@ -59,10 +59,10 @@ export class xjs_Date { * @returns the proportion */ public static timeProportion(date: Date): number { - let millis = date.getUTCMilliseconds() / 1000; - let seconds = (date.getUTCSeconds() + millis) / 60; - let minutes = (date.getUTCMinutes() + seconds) / 60; - let hours = (date.getUTCHours () + minutes) / 24; + const millis = date.getUTCMilliseconds() / 1000; + const seconds = (date.getUTCSeconds() + millis) / 60; + const minutes = (date.getUTCMinutes() + seconds) / 60; + const hours = (date.getUTCHours () + minutes) / 24; return hours; } @@ -91,20 +91,20 @@ export class xjs_Date { public static format(date: Date, format: string): string { const MONTHS = xjs_Date.MONTH_NAMES; const leadingZero = (n: number, r: number = 10) => `0${ n.toString(r) }`.slice(-2); - const defaultFormatter = (date: Date) => date.toISOString(); + const defaultFormatter = (d: Date) => d.toISOString(); return (new Map string>([ - ['Y-m-d', (date: Date) => `${ date.getUTCFullYear() }-${ leadingZero(date.getUTCMonth() + 1) }-${ leadingZero(date.getUTCDate()) }`], - ['j M Y', (date: Date) => `${ date.getUTCDate() } ${ MONTHS[date.getUTCMonth()].slice(0, 3) } ${ date.getUTCFullYear() }`], - ['d F Y', (date: Date) => `${ leadingZero(date.getUTCDate()) } ${ MONTHS[date.getUTCMonth()] } ${ date.getUTCFullYear() }`], - ['l, j F, Y', (date: Date) => `${ xjs_Date.DAY_NAMES[date.getUTCDay()] }, ${ date.getUTCDate() } ${ MONTHS[date.getUTCMonth()] }, ${ date.getUTCFullYear() }`], - ['j M', (date: Date) => `${ date.getUTCDate() } ${ MONTHS[date.getUTCMonth()].slice(0, 3) }`], - ['M Y', (date: Date) => `${ MONTHS[date.getUTCMonth()].slice(0, 3) } ${ date.getUTCFullYear() }`], - ['M j', (date: Date) => `${ MONTHS[date.getUTCMonth()].slice(0, 3) } ${ date.getUTCDate() }`], - ['M j, Y', (date: Date) => `${ MONTHS[date.getUTCMonth()].slice(0, 3) } ${ date.getUTCDate() }, ${ date.getUTCFullYear() }`], - ['F j, Y', (date: Date) => `${ MONTHS[date.getUTCMonth()] } ${ date.getUTCDate() }, ${ date.getUTCFullYear() }`], - ['M', (date: Date) => `${ MONTHS[date.getUTCMonth()].slice(0, 3) }`], - ['H:i', (date: Date) => `${ (date.getUTCHours() < 10) ? '0' : '' }${ date.getUTCHours() }:${ (date.getUTCMinutes() < 10) ? '0' : '' }${ date.getUTCMinutes() }`], - ['g:ia', (date: Date) => `${ (date.getUTCHours() - 1) % 12 + 1 }:${ (date.getUTCMinutes() < 10) ? '0' : '' }${ date.getUTCMinutes() }${ (date.getUTCHours() < 12) ? 'am' : 'pm' }`], + ['Y-m-d', (d: Date) => `${ d.getUTCFullYear() }-${ leadingZero(d.getUTCMonth() + 1) }-${ leadingZero(d.getUTCDate()) }`], + ['j M Y', (d: Date) => `${ d.getUTCDate() } ${ MONTHS[d.getUTCMonth()].slice(0, 3) } ${ d.getUTCFullYear() }`], + ['d F Y', (d: Date) => `${ leadingZero(d.getUTCDate()) } ${ MONTHS[d.getUTCMonth()] } ${ d.getUTCFullYear() }`], + ['l, j F, Y', (d: Date) => `${ xjs_Date.DAY_NAMES[d.getUTCDay()] }, ${ d.getUTCDate() } ${ MONTHS[d.getUTCMonth()] }, ${ d.getUTCFullYear() }`], + ['j M', (d: Date) => `${ d.getUTCDate() } ${ MONTHS[d.getUTCMonth()].slice(0, 3) }`], + ['M Y', (d: Date) => `${ MONTHS[d.getUTCMonth()].slice(0, 3) } ${ d.getUTCFullYear() }`], + ['M j', (d: Date) => `${ MONTHS[d.getUTCMonth()].slice(0, 3) } ${ d.getUTCDate() }`], + ['M j, Y', (d: Date) => `${ MONTHS[d.getUTCMonth()].slice(0, 3) } ${ d.getUTCDate() }, ${ d.getUTCFullYear() }`], + ['F j, Y', (d: Date) => `${ MONTHS[d.getUTCMonth()] } ${ d.getUTCDate() }, ${ d.getUTCFullYear() }`], + ['M', (d: Date) => `${ MONTHS[d.getUTCMonth()].slice(0, 3) }`], + ['H:i', (d: Date) => `${ (d.getUTCHours() < 10) ? '0' : '' }${ d.getUTCHours() }:${ (d.getUTCMinutes() < 10) ? '0' : '' }${ d.getUTCMinutes() }`], + ['g:ia', (d: Date) => `${ (d.getUTCHours() - 1) % 12 + 1 }:${ (d.getUTCMinutes() < 10) ? '0' : '' }${ d.getUTCMinutes() }${ (d.getUTCHours() < 12) ? 'am' : 'pm' }`], ['default', defaultFormatter], ]).get(format || 'default') || defaultFormatter)(date); } diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index 197237a..28be990 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -117,7 +117,7 @@ export class xjs_Object { * * ```js * // What is the date of the 1st Tuesday of November, 2018? - * let call_me = xjs.Object.switch('November', { + * const call_me = xjs.Object.switch('November', { * 'January': (n: number) => [ 2, 9, 16, 23, 30][n - 1], * 'February': (n: number) => [ 6. 13. 20, 27, NaN][n - 1], * 'March': (n: number) => [ 6, 13, 20, 27, NaN][n - 1], @@ -138,7 +138,7 @@ export class xjs_Object { * DEPRECATION WARNING: This method is deprecated. Instead, use a built-in Map: * ```js * // What is the date of the 1st Tuesday of November, 2018? - * let call_me: (n: number) => number = new Map number>([ + * const call_me: (n: number) => number = new Map number>([ * ['January', (n: number) => [ 2, 9, 16, 23, 30][n - 1]], * ['February', (n: number) => [ 6. 13. 20, 27, NaN][n - 1]], * ['March', (n: number) => [ 6, 13, 20, 27, NaN][n - 1]], @@ -255,7 +255,7 @@ export class xjs_Object { } Object.freeze(thing); if (xjs_Object.typeOf(thing) === 'object') { - for (let key in thing) { + for (const key in thing) { if (!Object.isFrozen(thing[key])) { xjs_Object.freezeDeep(thing[key]); } @@ -325,7 +325,7 @@ export class xjs_Object { } if (xjs_Object.typeOf(thing) === 'object') { const returned: { [index: string]: unknown } = {}; - for (let key in thing) { + for (const key in thing) { returned[key] = xjs_Object.cloneDeep(thing[key]); } return returned as unknown as T; diff --git a/src/class/String.class.ts b/src/class/String.class.ts index bae2eb6..e6aac3a 100644 --- a/src/class/String.class.ts +++ b/src/class/String.class.ts @@ -74,13 +74,13 @@ export class xjs_String { */ public static dedent(strings: TemplateStringsArray, ...interps: unknown[]): string { const matched: RegExpMatchArray | null = strings[0].match(/\n\t*/); - const n: number = matched && matched[0] ? matched[0].slice(1).length : 0; + const num: number = matched && matched[0] ? matched[0].slice(1).length : 0; function replace(s: string, n: number): string { return (n <= 0) ? s : s.replace(new RegExp(`\\n\\t{0,${ Math.floor(n) }}`, 'g'), '\n'); } return [ - ...interps.flatMap((interp, i) => [replace(strings[i], n), interp]), - replace(strings[strings.length - 1], n), // strings.lastItem + ...interps.flatMap((interp, i) => [replace(strings[i], num), interp]), + replace(strings[strings.length - 1], num), // strings.lastItem ].join(''); } diff --git a/test/Object.test.ts b/test/Object.test.ts index b2c7fa6..e893310 100644 --- a/test/Object.test.ts +++ b/test/Object.test.ts @@ -29,7 +29,7 @@ describe('xjs.Object', () => { assert.strictEqual(xjs_Object.typeOf(function () { return 'true'; }), 'function'); // eslint-disable-line prefer-arrow-callback, @typescript-eslint/brace-style assert.strictEqual(xjs_Object.typeOf(() => 'true'), 'function'); assert.strictEqual(xjs_Object.typeOf(undefined), 'undefined'); - assert.strictEqual(xjs_Object.typeOf((() => { let x; return x; })()), 'undefined'); // eslint-disable-line @typescript-eslint/brace-style + assert.strictEqual(xjs_Object.typeOf((() => { let x; return x; })()), 'undefined'); // eslint-disable-line @typescript-eslint/brace-style, @typescript-eslint/init-declarations }); }); From ca4cd9f3afef59555a202a2bc76b2b0591872d60 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:53:07 -0400 Subject: [PATCH 12/33] style: function return types --- src/class/Date.class.ts | 4 ++-- test/Array.test.ts | 2 +- test/Map.test.ts | 2 +- test/Set.test.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/class/Date.class.ts b/src/class/Date.class.ts index d3080e1..21f413c 100644 --- a/src/class/Date.class.ts +++ b/src/class/Date.class.ts @@ -90,8 +90,8 @@ export class xjs_Date { */ public static format(date: Date, format: string): string { const MONTHS = xjs_Date.MONTH_NAMES; - const leadingZero = (n: number, r: number = 10) => `0${ n.toString(r) }`.slice(-2); - const defaultFormatter = (d: Date) => d.toISOString(); + const leadingZero = (n: number, r: number = 10): string => `0${ n.toString(r) }`.slice(-2); + const defaultFormatter = (d: Date): string => d.toISOString(); return (new Map string>([ ['Y-m-d', (d: Date) => `${ d.getUTCFullYear() }-${ leadingZero(d.getUTCMonth() + 1) }-${ leadingZero(d.getUTCDate()) }`], ['j M Y', (d: Date) => `${ d.getUTCDate() } ${ MONTHS[d.getUTCMonth()].slice(0, 3) } ${ d.getUTCFullYear() }`], diff --git a/test/Array.test.ts b/test/Array.test.ts index bf6d0f6..d24ddf2 100644 --- a/test/Array.test.ts +++ b/test/Array.test.ts @@ -201,7 +201,7 @@ describe('xjs.Array', () => { }); it('callback params.', () => { const array = [10, 20, 30, 40]; - const mapper = (n: number, i: number, src: readonly number[]) => [ + const mapper = (n: number, i: number, src: readonly number[]): [string, string, string] => [ n.toString(), i.toString(), src.toString(), diff --git a/test/Map.test.ts b/test/Map.test.ts index d01977c..51120c6 100644 --- a/test/Map.test.ts +++ b/test/Map.test.ts @@ -4,7 +4,7 @@ import {xjs_Map} from '../src/class/Map.class.js'; describe('xjs.Map', () => { context('Equality Methods', () => { type Key = {id: number}; - const comparator = (a: Key, b: Key) => a.id === b.id; + const comparator = (a: Key, b: Key): boolean => a.id === b.id; describe('.has', () => { it('tests keys by equality.', () => { diff --git a/test/Set.test.ts b/test/Set.test.ts index 8f04394..870ffc9 100644 --- a/test/Set.test.ts +++ b/test/Set.test.ts @@ -39,7 +39,7 @@ describe('xjs.Set', () => { context('Equality Methods', () => { type El = {id: number}; - const comparator = (a: El, b: El) => a.id === b.id; + const comparator = (a: El, b: El): boolean => a.id === b.id; describe('.has', () => { it('tests elements by equality.', () => { From a21407706a08e42e6bd5a52e48aa343f380584d0 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:55:10 -0400 Subject: [PATCH 13/33] style: indexed object style --- src/class/Object.class.ts | 4 ++-- test/Array.test.ts | 2 +- test/Object.test.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index 28be990..46061d1 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -161,7 +161,7 @@ export class xjs_Object { * @returns the looked-up function, returning * @throws {ReferenceError} when failing to find a lookup value */ - public static switch(key: string, dictionary: { [index: string]: (this: any, ...args: any[]) => T }): (this: any, ...args: any[]) => T { + public static switch(key: string, dictionary: Record T>): (this: any, ...args: any[]) => T { let returned: (this: any, ...args: any[]) => T = dictionary[key]; if (!returned) { console.warn(`Key '${ key }' cannot be found. Using key 'default'…`); @@ -324,7 +324,7 @@ export class xjs_Object { return xjs_Array.cloneDeep(thing) as unknown as T; // HACK https://stackoverflow.com/a/18736071/ } if (xjs_Object.typeOf(thing) === 'object') { - const returned: { [index: string]: unknown } = {}; + const returned: Record = {}; for (const key in thing) { returned[key] = xjs_Object.cloneDeep(thing[key]); } diff --git a/test/Array.test.ts b/test/Array.test.ts index d24ddf2..e624feb 100644 --- a/test/Array.test.ts +++ b/test/Array.test.ts @@ -115,7 +115,7 @@ describe('xjs.Array', () => { assert.strictEqual(times, 4); }); it('callback params.', () => { - const results: Record = { + const results: Record<'n' | 'i' | 's', string[]> = { n: [], i: [], s: [], diff --git a/test/Object.test.ts b/test/Object.test.ts index e893310..5934448 100644 --- a/test/Object.test.ts +++ b/test/Object.test.ts @@ -5,8 +5,8 @@ describe('xjs.Object', () => { describe('.is(T, T, ((any, any) => boolean)?): boolean', () => { it('only checks one level of depth.', () => { type T = {val: string[]} | string[] | number; - const x: {[s: string]: T} = {a: 1, b: ['1'], c: {val: ['one']}}; - const y: {[s: string]: T} = {a: 1, b: ['1'], c: {val: ['one']}}; + const x: Record = {a: 1, b: ['1'], c: {val: ['one']}}; + const y: Record = {a: 1, b: ['1'], c: {val: ['one']}}; assert.strictEqual(xjs_Object.is(x, y), false); assert.strictEqual(xjs_Object.is(x, y, (x_a: unknown, y_a: unknown) => (assert.deepStrictEqual(x_a, y_a), true)), true); assert.strictEqual(xjs_Object.is(x, y, (x_a: T, y_a: T) => (assert.deepStrictEqual(x_a, y_a), true)), true); From c3eaa20508db05ee9d48185716b12da9472c4f57 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:39:23 -0400 Subject: [PATCH 14/33] =?UTF-8?q?feat:=20don=E2=80=99t=20use=20`any`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/class/Object.class.ts | 27 +++++++++++++++------------ src/class/String.class.ts | 20 ++++++++++---------- test/Object.test.ts | 9 +++++++-- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index 46061d1..a3c3e9f 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -48,7 +48,7 @@ export class xjs_Object { * @returns Are corresponding properties the same, i.e. replaceable? * @throws {TypeError} if either `a` or `b` is a function (not supported) */ - public static is(a: T, b: T, predicate: (x: any, y: any) => boolean = xjs_Object.sameValueZero): boolean { + public static is(a: T, b: T, predicate: (x: T[keyof T], y: T[keyof T]) => boolean = xjs_Object.sameValueZero): boolean { if (a === b) { return true; } @@ -63,8 +63,8 @@ export class xjs_Object { } // else, it will be 'object' return ( - Object.entries(a as Record).every(([a_key, a_value]) => Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && predicate(a_value, b_value))) - && Object.entries(b as Record).every(([b_key, b_value]) => Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && predicate(a_value, b_value))) + Object.entries(a as Record).every(([a_key, a_value]) => Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && predicate(a_value, b_value))) + && Object.entries(b as Record).every(([b_key, b_value]) => Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && predicate(a_value, b_value))) ); } @@ -161,6 +161,7 @@ export class xjs_Object { * @returns the looked-up function, returning * @throws {ReferenceError} when failing to find a lookup value */ + /* eslint-disable @typescript-eslint/no-explicit-any */ public static switch(key: string, dictionary: Record T>): (this: any, ...args: any[]) => T { let returned: (this: any, ...args: any[]) => T = dictionary[key]; if (!returned) { @@ -172,6 +173,7 @@ export class xjs_Object { } return returned; } + /* eslint-enable @typescript-eslint/no-explicit-any */ /** * Return the type of a thing. @@ -204,14 +206,14 @@ export class xjs_Object { * @returns the type of the thing */ public static typeOf(thing: unknown): string { - return (new Map string>([ - ['object', (arg: unknown) => (arg === null) ? 'null' : (Array.isArray(arg)) ? 'array' : 'object'], - ['number', (arg: number) => (Number.isNaN(arg)) ? 'NaN' : (!Number.isFinite(arg)) ? 'infinite' : 'number'], - ['bigint', () => 'bigint'], - ['function', () => 'function'], - ['string', () => 'string'], - ['boolean', () => 'boolean'], - ['undefined', () => 'undefined'], + return (new Map string>([ + ['object', (arg) => (arg === null) ? 'null' : (Array.isArray(arg)) ? 'array' : 'object'], + ['number', (arg) => (Number.isNaN(arg)) ? 'NaN' : (!Number.isFinite(arg)) ? 'infinite' : 'number'], + ['bigint', () => 'bigint'], + ['function', () => 'function'], + ['string', () => 'string'], + ['boolean', () => 'boolean'], + ['undefined', () => 'undefined'], ]).get(typeof thing) || ((arg: unknown) => typeof arg))(thing); } @@ -231,7 +233,8 @@ export class xjs_Object { if (thing === null || thing === undefined) { throw new TypeError(`\`${ thing }\` does not have a construtor.`); } - return (thing as any).__proto__.constructor.name; + // @ts-expect-error --- if not null/undefined, it should have a `__proto__` + return thing.__proto__.constructor.name; } /** diff --git a/src/class/String.class.ts b/src/class/String.class.ts index e6aac3a..710d910 100644 --- a/src/class/String.class.ts +++ b/src/class/String.class.ts @@ -39,16 +39,16 @@ export class xjs_String { * @returns a string version of the argument */ public static stringify(thing: unknown): string { - return new Map string>([ - ['object', (arg: object) => JSON.stringify(arg)], - ['array', (arg: unknown[]) => arg.join('')], - ['function', (arg: Function) => arg.toString()], - ['string', (arg: string) => arg], - ['number', (arg: number) => arg.toString()], - ['boolean', (arg: boolean) => arg.toString()], - ['null', (arg: null) => `${ arg }`], - ['undefined', (arg: void) => `${ arg }`], - ['default', (arg: unknown) => `${ arg }`], + return new Map string>([ + ['object', (arg) => JSON.stringify(arg as object)], + ['array', (arg) => (arg as unknown[]).join('')], + ['function', (arg) => (arg as Function).toString()], // eslint-disable-line @typescript-eslint/ban-types + ['string', (arg) => arg as string], + ['number', (arg) => (arg as number).toString()], + ['boolean', (arg) => (arg as boolean).toString()], + ['null', (arg) => `${ arg as null }`], + ['undefined', (arg) => `${ arg as void }`], + ['default', (arg) => `${ arg }`], ]).get(xjs_Object.typeOf(thing))!(thing); } diff --git a/test/Object.test.ts b/test/Object.test.ts index 5934448..5214d50 100644 --- a/test/Object.test.ts +++ b/test/Object.test.ts @@ -2,7 +2,7 @@ import * as assert from 'assert'; import {xjs_Object} from '../src/class/Object.class.js'; describe('xjs.Object', () => { - describe('.is(T, T, ((any, any) => boolean)?): boolean', () => { + describe('.is(T, T, ((T[keyof T], T[keyof T]) => boolean)?): boolean', () => { it('only checks one level of depth.', () => { type T = {val: string[]} | string[] | number; const x: Record = {a: 1, b: ['1'], c: {val: ['one']}}; @@ -35,7 +35,12 @@ describe('xjs.Object', () => { describe('.freezeDeep(Readonly): Readonly', () => { it('freezes an object and its properties, recursively.', () => { - const x: any = {first: 1, second: {value: 2}, third: [1, '2', {val: 3}]}; + const x: { + first: number, + second: Record, + third: [a: number, b: string, c: {val: unknown}, d?: [string]], + fourth?: unknown, + } = {first: 1, second: {value: 2}, third: [1, '2', {val: 3}]}; xjs_Object.freezeDeep(x); assert.throws(() => { x.fourth = {v: ['4']}; From 17da986a17c0016e87ed68061a3fd51708fe2f7b Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:42:15 -0400 Subject: [PATCH 15/33] fix: no-unnecessary condition --- src/class/Object.class.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index a3c3e9f..c945587 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -161,19 +161,17 @@ export class xjs_Object { * @returns the looked-up function, returning * @throws {ReferenceError} when failing to find a lookup value */ - /* eslint-disable @typescript-eslint/no-explicit-any */ - public static switch(key: string, dictionary: Record T>): (this: any, ...args: any[]) => T { - let returned: (this: any, ...args: any[]) => T = dictionary[key]; + public static switch(key: string, dictionary: Record T) | undefined>): (this: any, ...args: any[]) => T { // eslint-disable-line @typescript-eslint/no-explicit-any + let returned = dictionary[key]; if (!returned) { console.warn(`Key '${ key }' cannot be found. Using key 'default'…`); - returned = dictionary['default'] || null; + returned = dictionary['default']; if (!returned) { throw new ReferenceError('No default key found.'); } } return returned; } - /* eslint-enable @typescript-eslint/no-explicit-any */ /** * Return the type of a thing. From 2b1cf9693295fbb4237a6d9da01632f4190427d4 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:46:42 -0400 Subject: [PATCH 16/33] fix: allow sparse arrays for test --- test/Array.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/Array.test.ts b/test/Array.test.ts index e624feb..a1d3289 100644 --- a/test/Array.test.ts +++ b/test/Array.test.ts @@ -20,6 +20,7 @@ describe('xjs.Array', () => { }); describe('.densify(readonly T[]): T[]', () => { + /* eslint-disable no-sparse-arrays, @typescript-eslint/comma-dangle */ it('removes empty element slots.', () => { const x: readonly (number | void)[] = [, 42, , 48, ,]; assert.deepStrictEqual(xjs_Array.densify(x), [42, 48]); @@ -29,13 +30,16 @@ describe('xjs.Array', () => { assert.notDeepStrictEqual(x, [ , 42, , 48, ,]); assert.deepStrictEqual(xjs_Array.densify(x), x); }); + /* eslint-enable no-sparse-arrays, @typescript-eslint/comma-dangle */ }); describe('.fillHoles(readonly T[], T): T[]', () => { + /* eslint-disable no-sparse-arrays */ it('fills empty slots with given value.', () => { const x: readonly (number | void)[] = [, 42, , 48, ,]; assert.deepStrictEqual(xjs_Array.fillHoles(x, 0), [0, 42, 0, 48, 0]); }); + /* eslint-enable no-sparse-arrays */ }); describe('.isSubarrayOf(readonly T[], readonly U[], ((U, U) -> boolean)?): boolean', () => { From 3a49d3752f74da7672dd068ffa7bae2d71a9e936 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Fri, 7 Jul 2023 21:49:11 -0400 Subject: [PATCH 17/33] feat!: remove string params from {BigInt,Number}#assertType --- src/class/BigInt.class.ts | 43 +++++++++++---------------------------- src/class/Number.class.ts | 43 +++++++++++---------------------------- 2 files changed, 24 insertions(+), 62 deletions(-) diff --git a/src/class/BigInt.class.ts b/src/class/BigInt.class.ts index deb7eb3..a6affbd 100644 --- a/src/class/BigInt.class.ts +++ b/src/class/BigInt.class.ts @@ -37,41 +37,22 @@ export class xjs_BigInt { * @param type one of the string literals listed above * @throws {AssertionError} if the argument does not match the described type */ - public static assertType(int: bigint, type?: NumericType | 'integer' | 'natural' | 'whole' | 'float' | 'positive' | 'negative' | 'non-positive' | 'non-negative' | 'non-zero' | 'finite' | 'infinite'): void { + public static assertType(int: bigint, type?: NumericType): void { if (type === void 0) { return; } - if (typeof type === 'string') { - console.warn(new Error(` - WARNING: Argument \`'${ type }'\` was sent into \`xjs.Number.assertType\`. - Sending a string argument is deprecated; use a member of enum \`NumericType\` instead. - `.trim())); - return xjs_BigInt.assertType(int, new Map([ - ['integer', NumericType.INTEGER], - ['natural', NumericType.NATURAL], - ['whole', NumericType.WHOLE], - ['float', NumericType.FLOAT], - ['positive', NumericType.POSITIVE], - ['negative', NumericType.NEGATIVE], - ['non-positive', NumericType.NONPOSITIVE], - ['non-negative', NumericType.NONNEGATIVE], - ['non-zero', NumericType.NONZERO], - ['finite', NumericType.FINITE], - ['infinite', NumericType.INFINITE], - ]).get(type)); - } return new Map void>([ - [NumericType.INTEGER, (_n: bigint) => assert.ok(true, 'BigInts are always integers.')], - [NumericType.NATURAL, ( n: bigint) => xjs_BigInt.assertType(n, NumericType.NONNEGATIVE)], - [NumericType.WHOLE, ( n: bigint) => xjs_BigInt.assertType(n, NumericType.POSITIVE)], - [NumericType.FLOAT, (_n: bigint) => assert.ok(false, 'BigInts cannot be non-integers.')], - [NumericType.POSITIVE, ( n: bigint) => assert.ok(0n < n, `${ n } must be positive.`)], - [NumericType.NEGATIVE, ( n: bigint) => assert.ok(n < 0n, `${ n } must be negative.`)], - [NumericType.NONPOSITIVE, ( n: bigint) => assert.ok(n <= 0n, `${ n } must not be positive.`)], - [NumericType.NONNEGATIVE, ( n: bigint) => assert.ok(0n <= n, `${ n } must not be negative.`)], - [NumericType.NONZERO, ( n: bigint) => assert.ok(n !== 0n, `${ n } must not be zero.`)], - [NumericType.FINITE, (_n: bigint) => assert.ok(true, 'BigInts are always finite.')], - [NumericType.INFINITE, (_n: bigint) => assert.ok(false, 'BigInts cannot be infinite.')], + [NumericType.INTEGER, (_n) => assert.ok(true, 'BigInts are always integers.')], + [NumericType.NATURAL, ( n) => xjs_BigInt.assertType(n, NumericType.NONNEGATIVE)], + [NumericType.WHOLE, ( n) => xjs_BigInt.assertType(n, NumericType.POSITIVE)], + [NumericType.FLOAT, (_n) => assert.ok(false, 'BigInts cannot be non-integers.')], + [NumericType.POSITIVE, ( n) => assert.ok(0n < n, `${ n } must be positive.`)], + [NumericType.NEGATIVE, ( n) => assert.ok(n < 0n, `${ n } must be negative.`)], + [NumericType.NONPOSITIVE, ( n) => assert.ok(n <= 0n, `${ n } must not be positive.`)], + [NumericType.NONNEGATIVE, ( n) => assert.ok(0n <= n, `${ n } must not be negative.`)], + [NumericType.NONZERO, ( n) => assert.ok(n !== 0n, `${ n } must not be zero.`)], + [NumericType.FINITE, (_n) => assert.ok(true, 'BigInts are always finite.')], + [NumericType.INFINITE, (_n) => assert.ok(false, 'BigInts cannot be infinite.')], ]).get(type)!(int); } diff --git a/src/class/Number.class.ts b/src/class/Number.class.ts index 5712e53..b37d7ef 100644 --- a/src/class/Number.class.ts +++ b/src/class/Number.class.ts @@ -58,44 +58,25 @@ export class xjs_Number { * @throws {AssertionError} if the argument does not match the described type * @throws {NaNError} if the argument is `NaN` */ - public static assertType(num: number, type?: NumericType | 'integer' | 'natural' | 'whole' | 'float' | 'positive' | 'negative' | 'non-positive' | 'non-negative' | 'non-zero' | 'finite' | 'infinite'): void { + public static assertType(num: number, type?: NumericType): void { if (Number.isNaN(num)) { throw new NaNError(); } if (type === void 0) { return; } - if (typeof type === 'string') { - console.warn(new Error(` - WARNING: Argument \`'${ type }'\` was sent into \`xjs.Number.assertType\`. - Sending a string argument is deprecated; use a member of enum \`NumericType\` instead. - `.trim())); - return xjs_Number.assertType(num, new Map([ - ['integer', NumericType.INTEGER], - ['natural', NumericType.NATURAL], - ['whole', NumericType.WHOLE], - ['float', NumericType.FLOAT], - ['positive', NumericType.POSITIVE], - ['negative', NumericType.NEGATIVE], - ['non-positive', NumericType.NONPOSITIVE], - ['non-negative', NumericType.NONNEGATIVE], - ['non-zero', NumericType.NONZERO], - ['finite', NumericType.FINITE], - ['infinite', NumericType.INFINITE], - ]).get(type)); - } return new Map void>([ - [NumericType.INTEGER, (n: number) => assert.ok(Number.isInteger(n), `${ n } must be an integer.`)], - [NumericType.NATURAL, (n: number) => assert.ok(Number.isInteger(n) && 0 <= n, `${ n } must be a non-negative integer.`)], - [NumericType.WHOLE, (n: number) => assert.ok(Number.isInteger(n) && 0 < n, `${ n } must be a positive integer.`)], - [NumericType.FLOAT, (n: number) => assert.ok(!Number.isInteger(n), `${ n } must not be an integer.`)], - [NumericType.POSITIVE, (n: number) => assert.ok(0 < n, `${ n } must be a positive number.`)], - [NumericType.NEGATIVE, (n: number) => assert.ok(n < 0, `${ n } must be a negative number.`)], - [NumericType.NONPOSITIVE, (n: number) => assert.ok(n <= 0, `${ n } must not be a positive number.`)], - [NumericType.NONNEGATIVE, (n: number) => assert.ok(0 <= n, `${ n } must not be a negative number.`)], - [NumericType.NONZERO, (n: number) => assert.ok(n !== 0, `${ n } must not be zero.`)], - [NumericType.FINITE, (n: number) => assert.ok(Number.isFinite(n), `${ n } must be a finite number.`)], - [NumericType.INFINITE, (n: number) => assert.ok(!Number.isFinite(n), `${ n } must be an infinite number.`)], + [NumericType.INTEGER, (n) => assert.ok(Number.isInteger(n), `${ n } must be an integer.`)], + [NumericType.NATURAL, (n) => assert.ok(Number.isInteger(n) && 0 <= n, `${ n } must be a non-negative integer.`)], + [NumericType.WHOLE, (n) => assert.ok(Number.isInteger(n) && 0 < n, `${ n } must be a positive integer.`)], + [NumericType.FLOAT, (n) => assert.ok(!Number.isInteger(n), `${ n } must not be an integer.`)], + [NumericType.POSITIVE, (n) => assert.ok(0 < n, `${ n } must be a positive number.`)], + [NumericType.NEGATIVE, (n) => assert.ok(n < 0, `${ n } must be a negative number.`)], + [NumericType.NONPOSITIVE, (n) => assert.ok(n <= 0, `${ n } must not be a positive number.`)], + [NumericType.NONNEGATIVE, (n) => assert.ok(0 <= n, `${ n } must not be a negative number.`)], + [NumericType.NONZERO, (n) => assert.ok(n !== 0, `${ n } must not be zero.`)], + [NumericType.FINITE, (n) => assert.ok(Number.isFinite(n), `${ n } must be a finite number.`)], + [NumericType.INFINITE, (n) => assert.ok(!Number.isFinite(n), `${ n } must be an infinite number.`)], ]).get(type) !(num); } From 4a741fdf4196edc23e07fc474d39706566e3654b Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 26 Jul 2023 22:19:18 -0400 Subject: [PATCH 18/33] feat: create Heap data structure new file: src/Heap.ts new file: test/Heap.test.ts --- src/Heap.ts | 260 ++++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 2 + test/Heap.test.ts | 146 ++++++++++++++++++++++++++ 3 files changed, 408 insertions(+) create mode 100644 src/Heap.ts create mode 100644 test/Heap.test.ts diff --git a/src/Heap.ts b/src/Heap.ts new file mode 100644 index 0000000..aa2b7b0 --- /dev/null +++ b/src/Heap.ts @@ -0,0 +1,260 @@ +import { + NumericType, + xjs_Number, +} from './class/Number.class.js'; + +/** + * A comparator function takes two values and returns a number indicating their “order”. + * + * - If the returned value is less than 0, the left-hand value is “less than” the right-hand value. + * - If the returned value is greater than 0, the left-hand value is “greater than” the right-hand value. + * - If the returned value is equal to 0, the two values are “equal”. + * + * @typeParam U the type of value to compare + * @param left the left-hand value + * @param right the right-hand value + * @return a number listed above + */ +type Comparator = (left: U, right: U) => number; + +/** + * Return the indices of the left- and right-hand children of a given node’s index. + * @param index the given node’s index + * @return the children indices + */ +function child_indices_of(index: number): [number, number] { + xjs_Number.assertType(index, NumericType.NATURAL); + return [index * 2 + 1, index * 2 + 2]; +} + +/** + * Return the parent index of the given node’s index. + * @param index the given node’s index + * @return the parent index + */ +function parent_index_of(index: number): number { + xjs_Number.assertType(index, NumericType.WHOLE); + return Math.floor((index - 1) / 2); +} + +/** + * A max binary heap. + * + * A heap data structure is a tree with the property that every parent node’s value is + * greater than or equal to (for a max heap) the values of its children nodes. + * (For a min heap, parents would be less than or equal to each of their children.) + * Every node in a binary heap has 2 children or less. + * Being a tree, every node in a heap has exactly one parent, + * with the exception of the root node, which has no parent. + * + * @see https://en.wikipedia.org/wiki/Heap_(data_structure) + * @typeparam T the type of node value in this Heap + */ +export class Heap { + /** + * Internal implementation of this Heap. + * + * This class is implemented with a JS Array, defining node relationships implicitly. + * Specifically, given a parent node with index `i`, + * its two child nodes have indices `2 * i + 1` and `2 * i + 2`. + * Using an array is more performant than having nodes hold explicit references to their children. + */ + readonly #internal: T[] = []; + + public constructor( + private readonly comparator: Comparator, + ...initial_items: readonly T[] + ) { + if (initial_items.length > 0) { + if (initial_items.length === 1) { + this.push(initial_items[0]); + } else { + // see https://en.wikipedia.org/wiki/Binary_heap + // This takes `O(n * log n)` time. It’s slow! + false && initial_items.forEach((item) => this.push(item)); // eslint-disable-line @typescript-eslint/no-unnecessary-condition + // This takes `O(n)` time. A little faster. + this.#internal = [...initial_items]; + for (let i = Math.floor(this.#internal.length / 2) - 1; i >= 0; i--) { + this.#siftDown(i); + } + } + } + } + + /** The number of nodes in this Heap. */ + public get count(): number { + return this.#internal.length; + } + + /** + * Return a shallow copy of this Heap’s internal implementation. + * The returned array is only a copy, so mutating it will not mutate this Heap. + * However, the array’s items are the same references as this Heap’s nodes, + * so any mutations of them will be observed. + * @return a copy of this Heap’s array + */ + public inspect(): T[] { + return [...this.#internal]; + } + + /** + * Return the maximal node in this Heap, without modifying the Heap. + * @returns the maximal node + * @throws {Error} if this Heap is empty + */ + public peek(): T { + if (this.#internal.length > 0) { + return this.#internal[0]; + } else { + throw new Error('Heap is empty.'); + } + } + + /** + * Add the given items to this Heap and return this Heap. + * @param nodes the items to add + * @returns `this` + */ + public push(...nodes: readonly T[]): this { + nodes.forEach((node) => { + this.#internal.push(node); + this.#siftUp(this.#internal.length - 1); // TODO: this.#internal.lastIndex + }); + return this; + } + + /** + * Remove the maximal node from this Heap. + * @returns `[this, node]`, where `node` is the maximal node + * @throws {Error} if this Heap is empty + */ + public pop(): [this, T] { + if (this.#internal.length > 0) { + this.#internalSwap(0, this.#internal.length - 1); // TODO: this.#internal.lastIndex + const popped: T = this.#internal.pop()!; + this.#siftDown(0); + return [this, popped]; + } else { + throw new Error('Cannot pop from empty Heap.'); + } + } + + /** + * Remove the first node that satisfies the given predicate. + * @param predicate a function to find nodes + * @returns `[this, node]`, where `node` is the removed node + * @throws {Error} if no node satisfies the predicate + */ + public remove(predicate: (node: T, src: this) => boolean): [this, T] { + if (this.#internal.length > 0) { + const found_node: T | undefined = this.#internal.find((item) => predicate(item, this)); + if (found_node !== undefined) { + const found_index: number = this.#internal.indexOf(found_node); + if (found_index >= 0) { + this.#internalDelete(found_index); + return [this, found_node]; + } + } + throw new Error('No nodes were found to remove.'); + } else { + throw new Error('Cannot remove from empty Heap.'); + } + } + + /** + * Remove all nodes that satisfy the given predicate. + * @param predicate a function to find nodes + * @returns `[this, nodes]`, where `nodes` is a list of the removed nodes + */ + public removeAll(predicate: (node: T, src: this) => boolean): [this, T[]] { + if (this.#internal.length > 0) { + const found_node_entries: readonly [number, T][] = [...this.#internal.entries()].filter(([_, item]) => predicate(item, this)); + [...found_node_entries].reverse().forEach(([found_index]) => this.#internalDelete(found_index)); + return [this, found_node_entries.map(([_, found_node]) => found_node)]; + } else { + throw new Error('Cannot remove from empty Heap.'); + } + } + + /** + * Remove all nodes from this Heap. + * @returns `this` + */ + public clear(): this { + this.#internal.length = 0; + return this; + } + + #internalSwap(index_a: number, index_b: number): void { + [this.#internal[index_a], this.#internal[index_b]] = [this.#internal[index_b], this.#internal[index_a]]; + } + + #internalDelete(index: number): void { + xjs_Number.assertType(index, NumericType.NATURAL); + if (index >= this.#internal.length) { + throw new RangeError(`Index out of bounds. Got: ${ index } but expected less than ${ this.#internal.length }`); + } + const found_node: T = this.#internal[index]; + const last_index: number = this.#internal.length - 1; + if (index !== last_index) { + const replacement_node: T = this.#internal[last_index]; + this.#internalSwap(index, last_index); + this.#internal.pop(); + if (this.comparator(replacement_node, found_node) > 0) { + this.#siftUp(index); + } else if (this.comparator(replacement_node, found_node) < 0) { + this.#siftDown(index); + } + } else { + this.#internal.pop(); + } + } + + #siftUp(index: number): void { + xjs_Number.assertType(index, NumericType.NATURAL); + if (index >= this.#internal.length) { + throw new RangeError(`Index out of bounds. Got: ${ index } but expected less than ${ this.#internal.length }`); + } + if (index === 0) { + // the root node cannot be sifted + return; + } + + const parent_index: number = parent_index_of(index); + if (this.comparator(this.#internal[parent_index], this.#internal[index]) < 0) { + // the parameter does not satisfy the heap property + this.#internalSwap(parent_index, index); + return this.#siftUp(parent_index); + } + } + + #siftDown(index: number): void { + xjs_Number.assertType(index, NumericType.NATURAL); + if (index >= this.#internal.length) { + throw new RangeError(`Index out of bounds. Got: ${ index } but expected less than ${ this.#internal.length }`); + } + if (index === this.#internal.length - 1) { + // the last node cannot be sifted + return; + } + + const [left_child_index, right_child_index]: [number, number] = child_indices_of(index); + const left_child: T | undefined = this.#internal[left_child_index]; + const right_child: T | undefined = this.#internal[right_child_index]; + + // find the largest child node + let largest_index: number = index; + if (left_child && this.comparator(left_child, this.#internal[largest_index]) > 0) { + largest_index = left_child_index; + } + if (right_child && this.comparator(right_child, this.#internal[largest_index]) > 0) { + largest_index = right_child_index; + } + + if (largest_index !== index) { + // the parameter does not satisfy the heap property + this.#internalSwap(index, largest_index); + return this.#siftDown(largest_index); + } + } +} diff --git a/src/index.ts b/src/index.ts index 199e214..964a11a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,3 +20,5 @@ export {TemplateTag} from './class/String.class.js'; export {IndexOutOfBoundsError} from './class/IndexOutOfBoundsError.class.js'; export {NaNError} from './class/NaNError.class.js'; + +export {Heap} from './Heap.js'; diff --git a/test/Heap.test.ts b/test/Heap.test.ts new file mode 100644 index 0000000..3f7ed94 --- /dev/null +++ b/test/Heap.test.ts @@ -0,0 +1,146 @@ +/* eslint-disable arrow-body-style */ +import * as assert from 'assert'; +import {Heap} from '../src/index.js'; + + + +function assert__shallowEqual(arr1: readonly T[], arr2: typeof arr1): void { + try { + return assert.strictEqual(arr1, arr2, 'The arguments should be strict-equal.'); + } catch { + assert.strictEqual(arr1.length, arr2.length, 'The arrays should be the same length.'); + return arr1.forEach((item1, i) => assert.strictEqual(item1, arr2[i], `Index ${ i } should be strict-equal.`)); + } +} + + + +specify('assert__shallowEqual', () => { + const arr = [1, 2, 3] as const; + assert__shallowEqual(arr, arr); + assert__shallowEqual(arr, [...arr]); + assert__shallowEqual([1, 2, 3], [1, 2, 3]); + return assert.throws(() => assert__shallowEqual([[1], [2], [3]], [[1], [2], [3]]), /Index 0 should be strict-equal\./); +}); + + + +describe('Heap', () => { + type NodeType = { + readonly priority: number, + readonly name: string, + }; + const comparator = (a: NodeType, b: NodeType): number => a.priority - b.priority; + const items: readonly NodeType[] = [ + {priority: 1, name: 'a'}, + {priority: 2, name: 'b'}, + {priority: 3, name: 'c'}, + ]; + + + describe('.constructor(Comparator, ...T[])', () => { + it('creates a heap with nodes prepopulated.', () => { + const h = new Heap(comparator, ...items); + assert.strictEqual(h.count, 3); + return assert__shallowEqual(h.inspect(), [items[2], items[1], items[0]]); + }); + }); + + + describe('.peek()', () => { + it('returns the maximal node without removing it.', () => { + return assert.strictEqual(new Heap(comparator, ...items).peek(), items[2]); + }); + + it('throws when the heap is empty.', () => { + return assert.throws(() => new Heap(comparator).peek(), /Heap is empty\./); + }); + }); + + + describe('.push(...T[])', () => { + it('sifts up each node after pushing.', () => { + const h = new Heap(comparator); + h.push(items[0], items[1]); + assert__shallowEqual(h.inspect(), [items[1], items[0]]); + h.push(items[2]); + return assert__shallowEqual(h.inspect(), [items[2], items[0], items[1]]); + }); + }); + + + describe('.pop()', () => { + it('returns the maximal node while removing it.', () => { + const h = new Heap(comparator, ...items); + assert.strictEqual(h.pop()[1], items[2]); + return assert.strictEqual(h.count, 2); + }); + + it('sifts down after popping.', () => { + const h = new Heap(comparator, ...items); + assert__shallowEqual(h.inspect(), [items[2], items[1], items[0]]); + h.pop(); + return assert__shallowEqual(h.inspect(), [items[1], items[0]]); + }); + + it('throws when the heap is empty.', () => { + return assert.throws(() => new Heap(comparator).pop(), /Cannot pop from empty Heap\./); + }); + }); + + + describe('.remove((T) => boolean)', () => { + it('removes the first node (if any) satisfying the predicate.', () => { + const h = new Heap(comparator, ...items); + assert__shallowEqual(h.inspect(), [items[2], items[1], items[0]]); + + assert.strictEqual(h.remove((node) => node.priority < 3)[1], items[1]); + assert.strictEqual(h.count, 2); + return assert__shallowEqual(h.inspect(), [items[2], items[0]]); + }); + + it('throws when no node matches.', () => { + return assert.throws(() => new Heap(comparator, ...items).remove((node) => node.priority > 3), /No nodes were found to remove\./); + }); + + it('throws when the heap is empty.', () => { + return assert.throws(() => new Heap(comparator).remove((node) => 'priority' in node), /Cannot remove from empty Heap\./); + }); + }); + + + describe('.removeAll((T) => boolean)', () => { + it('removes all nodes satisfying the predicate.', () => { + const h = new Heap(comparator, ...items); + assert__shallowEqual(h.inspect(), [items[2], items[1], items[0]]); + + assert.deepStrictEqual(h.removeAll((node) => node.priority < 3)[1], [items[1], items[0]]); + assert.strictEqual(h.count, 1); + return assert__shallowEqual(h.inspect(), [items[2]]); + }); + + it('returns empty array when no node matches.', () => { + return assert.deepStrictEqual(new Heap(comparator, ...items).removeAll((node) => node.priority > 3)[1], []); + }); + + it('throws when the heap is empty.', () => { + return assert.throws(() => new Heap(comparator).removeAll((node) => 'priority' in node), /Cannot remove from empty Heap\./); + }); + }); + + + describe('.clear()', () => { + it('removes all nodes in the heap.', () => { + const h = new Heap(comparator, ...items); + assert__shallowEqual(h.inspect(), [items[2], items[1], items[0]]); + + assert.strictEqual(h.clear(), h); + assert.strictEqual(h.count, 0); + return assert__shallowEqual(h.inspect(), []); + }); + + it('does not throw when the heap is empty.', () => { + new Heap(comparator).clear(); // assert does not throw + }); + }); +}); From 0ac503608a619f88abe30e8d2fe696021d87e05c Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Mon, 31 Jul 2023 19:56:18 -0400 Subject: [PATCH 19/33] feat: add Heap#resift --- src/Heap.ts | 24 +++++++++++++++++++++--- test/Heap.test.ts | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/Heap.ts b/src/Heap.ts index aa2b7b0..aef2c2b 100644 --- a/src/Heap.ts +++ b/src/Heap.ts @@ -61,6 +61,11 @@ export class Heap { */ readonly #internal: T[] = []; + /** + * Construct a new Heap object. + * @param comparator a {@link Comparator} function comparing nodes’ values + * @param initial_items any optional items to start with + */ public constructor( private readonly comparator: Comparator, ...initial_items: readonly T[] @@ -74,9 +79,7 @@ export class Heap { false && initial_items.forEach((item) => this.push(item)); // eslint-disable-line @typescript-eslint/no-unnecessary-condition // This takes `O(n)` time. A little faster. this.#internal = [...initial_items]; - for (let i = Math.floor(this.#internal.length / 2) - 1; i >= 0; i--) { - this.#siftDown(i); - } + this.resift(); } } } @@ -176,6 +179,21 @@ export class Heap { } } + /** + * Reorders the nodes in this Heap to a valid arrangement. + * Should be called whenever one or more nodes have changed/mutated + * in a way that affects this Heap’s “max heap” property + * (that is, that every node should be greater than its children). + * If the nodes are already in a valid order, nothing is changed. + * @return `this` + */ + public resift(): this { + for (let i = Math.floor(this.#internal.length / 2) - 1; i >= 0; i--) { + this.#siftDown(i); + } + return this; + } + /** * Remove all nodes from this Heap. * @returns `this` diff --git a/test/Heap.test.ts b/test/Heap.test.ts index 3f7ed94..5903676 100644 --- a/test/Heap.test.ts +++ b/test/Heap.test.ts @@ -129,6 +129,28 @@ describe('Heap', () => { }); + describe('.resift()', () => { + it('reorders the nodes correctly.', () => { + type MutableNodeType = {-readonly [K in keyof NodeType]: NodeType[K]}; + const mut_items: readonly MutableNodeType[] = items.map((item) => ({...item})); + const h1 = new Heap(comparator, ...mut_items); + const h2 = new Heap(comparator).push(...mut_items); + assert__shallowEqual(h1.inspect(), [mut_items[2], mut_items[1], mut_items[0]]); + assert__shallowEqual(h2.inspect(), [mut_items[2], mut_items[0], mut_items[1]]); + mut_items[2].priority = 0; + assert__shallowEqual(h1.resift().inspect(), [mut_items[1], mut_items[2], mut_items[0]]); + return assert__shallowEqual(h2.resift().inspect(), [mut_items[1], mut_items[0], mut_items[2]]); + }); + + it('does not reorder if not necessary.', () => { + const h = new Heap(comparator, ...items); + const expected = [items[2], items[1], items[0]]; + assert__shallowEqual(h.inspect(), expected); + return assert__shallowEqual(h.resift().inspect(), expected); + }); + }); + + describe('.clear()', () => { it('removes all nodes in the heap.', () => { const h = new Heap(comparator, ...items); From f1ecb7284c4d35e193c00575fdeddbcc28c6dbae Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Mon, 4 Sep 2023 23:12:02 -0400 Subject: [PATCH 20/33] feat: add `Heap#remove{,All}` overloads --- src/Heap.ts | 27 +++++++++++++++++++++++---- test/Heap.test.ts | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/Heap.ts b/src/Heap.ts index aef2c2b..40341c2 100644 --- a/src/Heap.ts +++ b/src/Heap.ts @@ -142,15 +142,23 @@ export class Heap { } } + /** + * Remove the given node. + * @param node the node to remove + * @returns `[this, node]`, where `node` is the removed node + * @throws {Error} if the node is not in this Heap + */ + public remove(node: T): [this, T]; /** * Remove the first node that satisfies the given predicate. * @param predicate a function to find nodes * @returns `[this, node]`, where `node` is the removed node * @throws {Error} if no node satisfies the predicate */ - public remove(predicate: (node: T, src: this) => boolean): [this, T] { + public remove(predicate: (node: T, src: this) => boolean): [this, T]; + public remove(arg: T | ((node: T, src: this) => boolean)): [this, T] { if (this.#internal.length > 0) { - const found_node: T | undefined = this.#internal.find((item) => predicate(item, this)); + const found_node: T | undefined = (arg instanceof Function) ? this.#internal.find((item) => arg(item, this)) : arg; if (found_node !== undefined) { const found_index: number = this.#internal.indexOf(found_node); if (found_index >= 0) { @@ -164,14 +172,25 @@ export class Heap { } } + /** + * Remove all of the given nodes. + * @param nodes the nodes to remove + * @returns `[this, nodes]`, where `nodes` is a list of the removed nodes + */ + public removeAll(nodes: readonly T[]): [this, T[]]; /** * Remove all nodes that satisfy the given predicate. * @param predicate a function to find nodes * @returns `[this, nodes]`, where `nodes` is a list of the removed nodes */ - public removeAll(predicate: (node: T, src: this) => boolean): [this, T[]] { + public removeAll(predicate: (node: T, src: this) => boolean): [this, T[]]; + public removeAll(arg: readonly T[] | ((node: T, src: this) => boolean)): [this, T[]] { if (this.#internal.length > 0) { - const found_node_entries: readonly [number, T][] = [...this.#internal.entries()].filter(([_, item]) => predicate(item, this)); + const found_node_entries: readonly [number, T][] = [...this.#internal.entries()].filter(( + (arg instanceof Function) + ? (entry) => arg(entry[1], this) + : (entry) => arg.includes(entry[1]) + )); [...found_node_entries].reverse().forEach(([found_index]) => this.#internalDelete(found_index)); return [this, found_node_entries.map(([_, found_node]) => found_node)]; } else { diff --git a/test/Heap.test.ts b/test/Heap.test.ts index 5903676..302e377 100644 --- a/test/Heap.test.ts +++ b/test/Heap.test.ts @@ -31,11 +31,13 @@ describe('Heap', () => { readonly name: string, }; const comparator = (a: NodeType, b: NodeType): number => a.priority - b.priority; - const items: readonly NodeType[] = [ + const items = [ {priority: 1, name: 'a'}, {priority: 2, name: 'b'}, {priority: 3, name: 'c'}, - ]; + ] as const; + const comparator_simple = (a: number, b: number): number => a - b; + const items_simple = [1, 2, 3] as const; describe('.constructor(Comparator, ...T[])', () => { @@ -89,6 +91,26 @@ describe('Heap', () => { }); + describe('.remove(T)', () => { + it('removes the first node (if any) identical to the argument.', () => { + const h = new Heap(comparator_simple, ...items_simple); + assert__shallowEqual(h.inspect(), [3, 2, 1]); + + assert.strictEqual(h.remove(2)[1], 2); + assert.strictEqual(h.count, 2); + return assert__shallowEqual(h.inspect(), [3, 1]); + }); + + it('throws when no node matches.', () => { + return assert.throws(() => new Heap(comparator_simple, ...items_simple).remove(4), /No nodes were found to remove\./); + }); + + it('throws when the heap is empty.', () => { + return assert.throws(() => new Heap(comparator_simple).remove(3), /Cannot remove from empty Heap\./); + }); + }); + + describe('.remove((T) => boolean)', () => { it('removes the first node (if any) satisfying the predicate.', () => { const h = new Heap(comparator, ...items); @@ -109,6 +131,26 @@ describe('Heap', () => { }); + describe('.removeAll(readonly T[])', () => { + it('removes all nodes identical to the arguments.', () => { + const h = new Heap(comparator_simple, ...items_simple); + assert__shallowEqual(h.inspect(), [3, 2, 1]); + + assert.deepStrictEqual(h.removeAll([1, 2])[1], [2, 1]); // note difference in order + assert.strictEqual(h.count, 1); + return assert__shallowEqual(h.inspect(), [3]); + }); + + it('returns empty array when no node matches.', () => { + return assert.deepStrictEqual(new Heap(comparator_simple, ...items_simple).removeAll([4])[1], []); + }); + + it('throws when the heap is empty.', () => { + return assert.throws(() => new Heap(comparator_simple).removeAll([1, 2, 3]), /Cannot remove from empty Heap\./); + }); + }); + + describe('.removeAll((T) => boolean)', () => { it('removes all nodes satisfying the predicate.', () => { const h = new Heap(comparator, ...items); From e76aa45e9bb006f4c96ceb586cbcd6a2ef59cc86 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 6 Sep 2023 00:04:48 -0400 Subject: [PATCH 21/33] refac: simplify implementation of `xjs_Map.forEachAggregated` --- src/class/Array.class.ts | 2 +- src/class/Map.class.ts | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index c52a6dd..d95d723 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -279,7 +279,7 @@ export class xjs_Array { * @throws {Error} if one iteration throws an error */ static mapAggregated(array: readonly T[], callback: (item: T, i: number, src: typeof array) => U): U[] { - const results: ([U, true] | [Error, false])[] = array.map((it, i, src) => { + const results: readonly ([U, true] | [Error, false])[] = array.map((it, i, src) => { try { return [callback(it, i, src), true]; } catch (err) { diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index b054f52..7409994 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -204,16 +204,14 @@ export class xjs_Map { * @throws {Error} if one iteration throws an error */ static forEachAggregated(map: ReadonlyMap, callback: (value: V, key: K, src: typeof map) => void): void { - const accumulator: Array = []; - map.forEach((value, key, src) => { + const errors: readonly Error[] = [...map.entries()].map(([key, value]) => { try { - callback.call(null, value, key, src); - accumulator.push(null); + callback.call(null, value, key, map); + return null; } catch (err) { - accumulator.push((err instanceof Error) ? err : new Error(`${ err }`)); + return (err instanceof Error) ? err : new Error(`${ err }`); } - }); - const errors: readonly Error[] = accumulator.filter((e): e is Error => e instanceof Error); + }).filter((e): e is Error => e instanceof Error); if (errors.length) { throw (errors.length === 1) ? errors[0] From 18ed871a309f3af1bf55bf3c6421412ab104a95d Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Sun, 10 Mar 2024 21:16:30 -0400 Subject: [PATCH 22/33] feat: add LinkedList & Queue --- src/LinkedList.ts | 191 ++++++++++++++++++++++++++++++++++++++++ src/Queue.ts | 105 ++++++++++++++++++++++ src/class/Math.class.ts | 11 +++ src/index.ts | 9 ++ test/LinkedList.test.ts | 157 +++++++++++++++++++++++++++++++++ test/Queue.test.ts | 155 ++++++++++++++++++++++++++++++++ 6 files changed, 628 insertions(+) create mode 100644 src/LinkedList.ts create mode 100644 src/Queue.ts create mode 100644 test/LinkedList.test.ts create mode 100644 test/Queue.test.ts diff --git a/src/LinkedList.ts b/src/LinkedList.ts new file mode 100644 index 0000000..a5c5fc2 --- /dev/null +++ b/src/LinkedList.ts @@ -0,0 +1,191 @@ +import {xjs_Math} from './class/Math.class.js'; +import {IndexOutOfBoundsError} from './class/IndexOutOfBoundsError.class.js'; + + + +class LLItem { + public next: LLItem | null = null; + public constructor(public readonly value: T) {} +} + + + +export interface ReadonlyLinkedList { + readonly length: number; + + readonly firstItem: T; + + [Symbol.iterator](): IterableIterator; + + get(index: number): T; + + findFirstIndex(item: T): number; + findFirstIndex(items: ReadonlySet): number; + findFirstIndex(predicate: (it: T, i: number, this_: this) => boolean): number; +} + + + +export class LinkedList implements ReadonlyLinkedList { + #length: number = 0; + #first: LLItem | null = null; + + + public constructor(...items: readonly T[]) { + if (items.length) { + this.#first = new LLItem(items[0]); + let current: LLItem = this.#first; + items.slice(1).forEach((it) => { + current.next = new LLItem(it); + current = current.next; + }); + this.#length = items.length; + } + } + + + public get length(): number { + return this.#length; + } + + public get firstItem(): T { + if (this.length) { + return this.#first!.value; + } else { + throw new IndexOutOfBoundsError(0); + } + } + + + * #entries(): IterableIterator<[number, T]> { + let current: Readonly> | null = this.#first; + for (let i = 0; i < this.length; i++) { + yield [i, current!.value]; + if (i < this.length - 1) { + current = current!.next; + } + } + } + + public * [Symbol.iterator](): IterableIterator { + return yield * [...this.#entries()].map((entry) => entry[1]); + // TODO: once `Iterator.prototype.map` is standardized: + // return yield * this.#entries().map((entry) => entry[1]); + } + + #normalizeIndex(index: number): number { + return index >= 0 ? index : index + this.length; + } + + #getLLItem(index: number): LLItem { + index = this.#normalizeIndex(index); + if (this.length && xjs_Math.isInRange(index, 0, this.length - 1)) { + let current: Readonly> = this.#first!; + for (let i = 0; i < this.length; i++) { + if (i === index) { + return current; + } + if (i < this.length - 1) { + current = current.next!; + } + } + } + throw new IndexOutOfBoundsError(index); + } + + public get(index: number): T { + return this.#getLLItem(index).value; + } + + public findFirstIndex(item: T): number; + public findFirstIndex(items: ReadonlySet): number; + public findFirstIndex(predicate: (it: T, i: number, this_: this) => boolean): number; + public findFirstIndex(arg: T | ReadonlySet | ((it: T, i: number, this_: this) => boolean)): number { + if (arg instanceof Function) { + for (const [i, it] of this.#entries()) { + if (arg.call(null, it, i, this)) { + return i; + } + } + throw new Error(`No indices in ${ this }} satisfy predicate ${ arg }}.`); + } else if (arg instanceof Set) { + return this.findFirstIndex((it) => arg.has(it)); + } else { + return this.findFirstIndex(new Set([arg as T])); + } + } + + public prepend(...items: T[]): this { + if (items.length) { + const new_ = new LinkedList(...items); + const new_first: Readonly> = new_.#first!; + if (this.length) { + new_.#getLLItem(new_.length - 1).next = this.#first; + } + this.#first = new_first; + this.#length += items.length; + } + return this; + } + + public append(...items: T[]): this { + if (items.length) { + const new_first: Readonly> = new LinkedList(...items).#first!; + if (this.length) { + this.#getLLItem(this.length - 1).next = new_first; + } else { + this.#first = new_first; + } + this.#length += items.length; + } + return this; + } + + public delete(index: number): [this, T] { + index = this.#normalizeIndex(index); + if (this.length && xjs_Math.isInRange(index, 0, this.length - 1)) { + let removed: Readonly> = this.#first!; + if (index === 0) { + this.#first = removed.next; + } else { + const prev: LLItem = this.#getLLItem(index - 1); + removed = prev.next!; + prev.next = removed.next; + } + this.#length -= 1; + return [this, removed.value]; + } else { + throw new IndexOutOfBoundsError(index); + } + } + + public shift(n: number = 1): [this, LinkedList] { + const removed = new LinkedList(); + if (xjs_Math.isInRange(n, 0, this.length)) { + if (n > 0) { + let current: Readonly> = this.#first!; + for (let i = 0; i < n; i++) { + removed.append(current.value); + if (i < n - 1) { + current = current.next!; + } + } + if (current.next) { + this.#first = current.next; + this.#length -= n; + } else { + this.clear(); + } + } + return [this, removed]; + } else { + throw new IndexOutOfBoundsError(n); + } + } + + public clear(): this { + this.#first = null; + this.#length = 0; + return this; + } +} diff --git a/src/Queue.ts b/src/Queue.ts new file mode 100644 index 0000000..244a5c1 --- /dev/null +++ b/src/Queue.ts @@ -0,0 +1,105 @@ +import {LinkedList} from './LinkedList.js'; + + + +function throw_error(e: Error): never { + throw e; +} + + + +/** + * A First-In-First-Out (FIFO) data structure. + * The first element added to the queue will be the first one to be removed. + * + * This base class only allows the following operations: + * - `peek()`: inspect the first item without removing it + * - `push()`: append an item to the queue + * - `pop()`: remove the first item from the queue + * + * @typeparam T : the type of items in this Queue + */ +export class Queue { + protected readonly internal: LinkedList; + + public constructor(...items: readonly T[]) { + this.internal = new LinkedList(...items); + } + + public peek(): T { + return (!this.internal.length) + ? throw_error(new Error('Queue is empty.')) + : this.internal.get(0); + } + + public push(...items: readonly T[]): this { + this.internal.append(...items); + return this; + } + + public pop(): [this, T] { + return (!this.internal.length) + ? throw_error(new Error('Cannot pop from empty queue.')) + : [this, this.internal.shift()[1].firstItem]; + } +} + + + +/** + * A ReadableQueue is a queue that is “transparent”: its items can all be seen at once. + * It offers the additonal operations: + * - `length`: the number of items in the queue + * - `isEmpty`: does the queue have 0 items? + * - `items`: inspect a copy of the entire queue as an array + * - `get()`: inspect an arbitrary item in the queue + * + * @typeparam T : the type of items in this ReadableQueue + */ +export class ReadableQueue extends Queue { + public get length(): number { + return this.internal.length; + } + + public get isEmpty(): boolean { + return this.length === 0; + } + + public get items(): T[] { + return [...this.internal]; + } + + public get(index: number): T { + return this.internal.get(index); + } +} + + + +/** + * A DeletableQueue is a queue from which items may be removed outside of the normal `pop()` method. + * It offers the additonal operations: + * - `delete()`: remove an arbitrary item from the queue by index + * - `remove()`: remove an arbitrary item from the queue + * - `clear()`: remove all items from the queue + * + * @typeparam T : the type of items in this DeletableQueue + */ +export class DeletableQueue extends ReadableQueue { + public delete(index: number): [this, T] { + return [this, this.internal.delete(index)[1]]; + } + + public remove(item: T): [this, T]; + public remove(predicate: (it: T) => boolean): [this, T]; + public remove(arg: T | ((it: T) => boolean)): [this, T] { + return arg instanceof Function + ? this.delete(this.internal.findFirstIndex((it) => arg.call(null, it))) + : this.delete(this.internal.findFirstIndex(arg)); + } + + public clear(): this { + this.internal.clear(); + return this; + } +} diff --git a/src/class/Math.class.ts b/src/class/Math.class.ts index 3ceb3a0..09f1455 100644 --- a/src/class/Math.class.ts +++ b/src/class/Math.class.ts @@ -97,6 +97,17 @@ export class xjs_Math { return (min <= max) ? xjs_Math.minBigInt(xjs_Math.maxBigInt(min, val), max) : xjs_Math.clampBigInt(max, val, min); } + /** + * Tests whether a given value is within a certain range, inclusive. + * @param val the value to test + * @param min the minimum + * @param max the maximum + * @return is `val` equal to or between `min` and `max`? + */ + public static isInRange(val: number, min: number, max: number): boolean { + return min <= val && val <= max; + } + /** * Return the arithmetic mean of a set of numbers. * diff --git a/src/index.ts b/src/index.ts index 964a11a..8f14ba0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,4 +21,13 @@ export {TemplateTag} from './class/String.class.js'; export {IndexOutOfBoundsError} from './class/IndexOutOfBoundsError.class.js'; export {NaNError} from './class/NaNError.class.js'; +export { + ReadonlyLinkedList, + LinkedList, +} from './LinkedList.js'; +export { + Queue, + ReadableQueue, + DeletableQueue, +} from './Queue.js'; export {Heap} from './Heap.js'; diff --git a/test/LinkedList.test.ts b/test/LinkedList.test.ts new file mode 100644 index 0000000..1b3cff3 --- /dev/null +++ b/test/LinkedList.test.ts @@ -0,0 +1,157 @@ +/* eslint-disable arrow-body-style */ +import * as assert from 'assert'; +import { + LinkedList, + type ReadonlyLinkedList, +} from '../src/index.js'; + + + +const items = ['a', 'b', 'c'] as const; + + + +describe('LinkedList', () => { + describe('.constructor(...T[])', () => { + it('creates a linked list prepopulated.', () => { + const list: ReadonlyLinkedList = new LinkedList(...items); + assert.strictEqual(list.length, 3); + return assert.deepStrictEqual([...list], items); + }); + }); + + + describe('.get(number)', () => { + it('returns the item at the given index.', () => { + return assert.strictEqual(new LinkedList(...items).get(2), items[2]); + }); + + it('throws when the index is out of bounds.', () => { + return assert.throws(() => new LinkedList(...items).get(3), /Index `3` out of bounds\./); + }); + + it('throws when the list is empty.', () => { + return assert.throws(() => new LinkedList().get(2), /Index `2` out of bounds\./); + }); + }); + + + context('findFirstIndex', () => { + const list: ReadonlyLinkedList = new LinkedList(...items); + + describe('.findFirstIndex(T)', () => { + it('finds index by item.', () => { + return assert.strictEqual(list.findFirstIndex('b'), 1); + }); + }); + + describe('.findFirstIndex(ReadonlySet)', () => { + it('finds first index of any given item.', () => { + return assert.strictEqual(list.findFirstIndex(new Set(['d', 'b', 'e'])), 1); + }); + }); + + describe('.findFirstIndex((T, number, this) => boolean)', () => { + it('finds first index by predicate.', () => { + assert.strictEqual(list.findFirstIndex((it) => it.codePointAt(0) === items[1].codePointAt(0)), 1); + return assert.strictEqual(list.findFirstIndex((_, i) => i === 1), 1); + }); + + it('predicate allows mutating list if it’s mutable.', () => { + return assert.strictEqual(new LinkedList(...items).findFirstIndex((it, _, src) => { + src.append('d'); + return it === 'd'; + }), 3); + }); + }); + }); + + + describe('.prepend()', () => { + it('returns the original modified list.', () => { + const list = new LinkedList(...items); + return assert.strictEqual(list.prepend('d'), list); + }); + + it('puts items at the beginning of the list.', () => { + const list: ReadonlyLinkedList = new LinkedList(...items).prepend('d'); + assert.strictEqual(list.length, items.length + 1); + return assert.deepStrictEqual([...list], ['d', ...items]); + }); + }); + + + describe('.append()', () => { + it('returns the original modified list.', () => { + const list = new LinkedList(...items); + return assert.strictEqual(list.append('d'), list); + }); + + it('puts items at the end of the list.', () => { + const list: ReadonlyLinkedList = new LinkedList(...items).append('d'); + assert.strictEqual(list.length, items.length + 1); + return assert.deepStrictEqual([...list], [...items, 'd']); + }); + }); + + + describe('.delete()', () => { + it('returns the original modified list.', () => { + const list = new LinkedList(...items); + return assert.strictEqual(list.delete(1)[0], list); + }); + + it('removes the item at the given index.', () => { + const [list, removed]: [ReadonlyLinkedList, string] = new LinkedList(...items).delete(1); + assert.strictEqual(list.length, items.length - 1); + return assert.deepStrictEqual( + [[...list], removed], + [[items[0], items[2]], items[1]], + ); + }); + + it('throws when the index is out of bounds.', () => { + return assert.throws(() => new LinkedList(...items).delete(3), /Index `3` out of bounds\./); + }); + + it('throws when the list is empty.', () => { + return assert.throws(() => new LinkedList().delete(2), /Index `2` out of bounds\./); + }); + }); + + + describe('.shift(number)', () => { + it('returns the original modified list.', () => { + const list = new LinkedList(...items); + return assert.strictEqual(list.shift(1)[0], list); + }); + + it('removes items from the beginning of the list and shifts remaining items towards the start.', () => { + for (let i = 0; i < items.length + 1; i++) { + const [remaining, removed]: [ReadonlyLinkedList, ReadonlyLinkedList] = new LinkedList(...items).shift(i); + assert.deepStrictEqual( + [[...remaining], [...removed]], + [items.slice(i), items.slice(0, i)], + ); + } + }); + + it('throws when count is out of range.', () => { + return assert.throws(() => new LinkedList(...items).shift(4), /Index `4` out of bounds\./); + }); + }); + + + describe('.clear()', () => { + it('returns the original modified list.', () => { + const list = new LinkedList(...items); + return assert.strictEqual(list.clear(), list); + }); + + it('removes all items from the list.', () => { + const list: ReadonlyLinkedList = new LinkedList(...items).clear(); + assert.strictEqual(list.length, 0); + return assert.deepStrictEqual([...list], []); + }); + }); +}); diff --git a/test/Queue.test.ts b/test/Queue.test.ts new file mode 100644 index 0000000..7055458 --- /dev/null +++ b/test/Queue.test.ts @@ -0,0 +1,155 @@ +/* eslint-disable arrow-body-style */ +import * as assert from 'assert'; +import { + Queue, + ReadableQueue, + DeletableQueue, +} from '../src/index.js'; + + + +const items = ['a', 'b', 'c'] as const; + + + +describe('Queue', () => { + describe('.peek()', () => { + it('does not modify the queue.', () => { + const queue = new Queue(...items); + queue.peek(); + return assert.strictEqual(queue.pop()[1], items[0]); + }); + + it('returs the first item in the queue.', () => { + return assert.strictEqual(new Queue(...items).peek(), items[0]); + }); + + it('throws when the queue is empty.', () => { + return assert.throws(() => new Queue().peek(), /Queue is empty\./); + }); + }); + + + describe('.push()', () => { + it('returns the original modified queue.', () => { + const queue = new Queue(); + return assert.strictEqual(queue.push('d'), queue); + }); + + it('puts items at the end of the queue.', () => { + const queue = new Queue().push('d'); + return assert.strictEqual(queue.pop()[1], 'd'); + }); + }); + + + describe('.pop()', () => { + it('returns the original modified queue.', () => { + const queue = new Queue(...items); + return assert.strictEqual(queue.pop()[0], queue); + }); + + it('removes the first item.', () => { + const [queue, removed]: [Queue, string] = new Queue(...items).pop(); + const remaining = [queue.pop()[1], queue.pop()[1]]; + return assert.deepStrictEqual( + [removed, remaining], + [items[0], [items[1], items[2]]], + ); + }); + + it('throws when the queue is empty.', () => { + return assert.throws(() => new Queue().pop(), /Cannot pop from empty queue\./); + }); + }); +}); + + + +describe('ReadableQueue', () => { + describe('.get(number)', () => { + it('returns the item at the given index.', () => { + return assert.strictEqual(new ReadableQueue(...items).get(1), items[1]); + }); + + it('throws when the index is out of bounds.', () => { + return assert.throws(() => new ReadableQueue(...items).get(3), /Index `3` out of bounds\./); + }); + + it('throws when the queue is empty.', () => { + return assert.throws(() => new ReadableQueue().get(2), /Index `2` out of bounds\./); + }); + }); +}); + + + +describe('DeletableQueue', () => { + describe('.delete(number)', () => { + it('returns the original modified queue.', () => { + const queue = new DeletableQueue(...items); + return assert.strictEqual(queue.delete(1)[0], queue); + }); + + it('removes the item at the given index.', () => { + const [queue, removed]: [DeletableQueue, string] = new DeletableQueue(...items).delete(1); + assert.strictEqual(queue.length, items.length - 1); + return assert.deepStrictEqual( + [queue.items, removed], + [[items[0], items[2]], items[1]], + ); + }); + + it('throws when the index is out of bounds.', () => { + return assert.throws(() => new DeletableQueue(...items).delete(3), /Index `3` out of bounds\./); + }); + + it('throws when the queue is empty.', () => { + return assert.throws(() => new DeletableQueue().delete(2), /Index `2` out of bounds\./); + }); + }); + + + context('remove', () => { + describe('.remove(T)', () => { + it('returns the original modified queue.', () => { + const queue = new DeletableQueue(...items); + return assert.strictEqual(queue.remove(items[1])[0], queue); + }); + + it('removes the given item.', () => { + const [queue, removed]: [DeletableQueue, string] = new DeletableQueue(...items).remove(items[1]); + assert.strictEqual(queue.length, items.length - 1); + return assert.deepStrictEqual( + [queue.items, removed], + [[items[0], items[2]], items[1]], + ); + }); + }); + + describe('.remove((T) => boolean)', () => { + it('removes the first item satisfying the predicate.', () => { + const [queue, removed]: [DeletableQueue, string] = new DeletableQueue(...items).remove((it) => it.codePointAt(0) === items[1].codePointAt(0)); + assert.strictEqual(queue.length, items.length - 1); + return assert.deepStrictEqual( + [queue.items, removed], + [[items[0], items[2]], items[1]], + ); + }); + }); + }); + + + describe('.clear()', () => { + it('returns the original modified queue.', () => { + const queue = new DeletableQueue(...items); + return assert.strictEqual(queue.clear(), queue); + }); + + it('removes all items from the queue.', () => { + const queue = new DeletableQueue(...items).clear(); + assert.strictEqual(queue.length, 0); + return assert.deepStrictEqual(queue.items, []); + }); + }); +}); From 39a04361b4bd7e0af6df2d93ac432d5050f5a651 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Sun, 10 Mar 2024 21:35:52 -0400 Subject: [PATCH 23/33] refactor: move throw_error to utils --- src/Heap.ts | 13 ++++++++----- src/LinkedList.ts | 9 ++++----- src/Queue.ts | 7 +------ src/utils-private.ts | 3 +++ 4 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 src/utils-private.ts diff --git a/src/Heap.ts b/src/Heap.ts index 40341c2..11fe5f0 100644 --- a/src/Heap.ts +++ b/src/Heap.ts @@ -2,6 +2,9 @@ import { NumericType, xjs_Number, } from './class/Number.class.js'; +import {throw_error} from './utils-private.js'; + + /** * A comparator function takes two values and returns a number indicating their “order”. @@ -37,6 +40,8 @@ function parent_index_of(index: number): number { return Math.floor((index - 1) / 2); } + + /** * A max binary heap. * @@ -106,11 +111,9 @@ export class Heap { * @throws {Error} if this Heap is empty */ public peek(): T { - if (this.#internal.length > 0) { - return this.#internal[0]; - } else { - throw new Error('Heap is empty.'); - } + return this.#internal.length > 0 + ? this.#internal[0] + : throw_error(new Error('Heap is empty.')); } /** diff --git a/src/LinkedList.ts b/src/LinkedList.ts index a5c5fc2..8613b83 100644 --- a/src/LinkedList.ts +++ b/src/LinkedList.ts @@ -1,5 +1,6 @@ import {xjs_Math} from './class/Math.class.js'; import {IndexOutOfBoundsError} from './class/IndexOutOfBoundsError.class.js'; +import {throw_error} from './utils-private.js'; @@ -49,11 +50,9 @@ export class LinkedList implements ReadonlyLinkedList { } public get firstItem(): T { - if (this.length) { - return this.#first!.value; - } else { - throw new IndexOutOfBoundsError(0); - } + return this.length + ? this.#first!.value + : throw_error(new IndexOutOfBoundsError(0)); } diff --git a/src/Queue.ts b/src/Queue.ts index 244a5c1..3cefc62 100644 --- a/src/Queue.ts +++ b/src/Queue.ts @@ -1,10 +1,5 @@ import {LinkedList} from './LinkedList.js'; - - - -function throw_error(e: Error): never { - throw e; -} +import {throw_error} from './utils-private.js'; diff --git a/src/utils-private.ts b/src/utils-private.ts new file mode 100644 index 0000000..cd60150 --- /dev/null +++ b/src/utils-private.ts @@ -0,0 +1,3 @@ +export function throw_error(e: Error): never { + throw e; +} From bce991015b44de623298e2ac8d58307813a61b52 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Sun, 10 Mar 2024 21:38:42 -0400 Subject: [PATCH 24/33] refactor: use IndexOutOfBoundsError --- src/Heap.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Heap.ts b/src/Heap.ts index 11fe5f0..cdb77c2 100644 --- a/src/Heap.ts +++ b/src/Heap.ts @@ -1,3 +1,4 @@ +import {IndexOutOfBoundsError} from './class/IndexOutOfBoundsError.class.js'; import { NumericType, xjs_Number, @@ -232,7 +233,7 @@ export class Heap { #internalDelete(index: number): void { xjs_Number.assertType(index, NumericType.NATURAL); if (index >= this.#internal.length) { - throw new RangeError(`Index out of bounds. Got: ${ index } but expected less than ${ this.#internal.length }`); + throw new IndexOutOfBoundsError(index); } const found_node: T = this.#internal[index]; const last_index: number = this.#internal.length - 1; @@ -253,7 +254,7 @@ export class Heap { #siftUp(index: number): void { xjs_Number.assertType(index, NumericType.NATURAL); if (index >= this.#internal.length) { - throw new RangeError(`Index out of bounds. Got: ${ index } but expected less than ${ this.#internal.length }`); + throw new IndexOutOfBoundsError(index); } if (index === 0) { // the root node cannot be sifted @@ -271,7 +272,7 @@ export class Heap { #siftDown(index: number): void { xjs_Number.assertType(index, NumericType.NATURAL); if (index >= this.#internal.length) { - throw new RangeError(`Index out of bounds. Got: ${ index } but expected less than ${ this.#internal.length }`); + throw new IndexOutOfBoundsError(index); } if (index === this.#internal.length - 1) { // the last node cannot be sifted From 9494c59fedf6ac8df66b794cbc08f81516991d0f Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Sun, 10 Mar 2024 21:44:33 -0400 Subject: [PATCH 25/33] feat: add EmptyStructureError --- src/EmptyStructureError.ts | 14 +++++++++++++ src/Heap.ts | 41 +++++++++++++++++++++----------------- src/Queue.ts | 5 +++-- src/index.ts | 2 ++ test/Heap.test.ts | 17 +++++++++------- test/Queue.test.ts | 5 +++-- 6 files changed, 55 insertions(+), 29 deletions(-) create mode 100644 src/EmptyStructureError.ts diff --git a/src/EmptyStructureError.ts b/src/EmptyStructureError.ts new file mode 100644 index 0000000..a009554 --- /dev/null +++ b/src/EmptyStructureError.ts @@ -0,0 +1,14 @@ + +/** + * An error that is thrown when trying to access items in an empty data structure. + */ +export class EmptyStructureError extends Error { + /** + * Construct a new EmptyStructureError object. + * @param message Optional. A human-readable description of the error. + */ + public constructor(message: string = 'Empty data struture.') { + super(message); + this.name = 'EmptyStructureError'; + } +} diff --git a/src/Heap.ts b/src/Heap.ts index cdb77c2..0c23078 100644 --- a/src/Heap.ts +++ b/src/Heap.ts @@ -3,6 +3,7 @@ import { NumericType, xjs_Number, } from './class/Number.class.js'; +import {EmptyStructureError} from './EmptyStructureError.js'; import {throw_error} from './utils-private.js'; @@ -108,13 +109,13 @@ export class Heap { /** * Return the maximal node in this Heap, without modifying the Heap. - * @returns the maximal node - * @throws {Error} if this Heap is empty + * @returns the maximal node + * @throws {EmptyStructureError} if this Heap is empty */ public peek(): T { return this.#internal.length > 0 ? this.#internal[0] - : throw_error(new Error('Heap is empty.')); + : throw_error(new EmptyStructureError('Heap is empty.')); } /** @@ -132,8 +133,8 @@ export class Heap { /** * Remove the maximal node from this Heap. - * @returns `[this, node]`, where `node` is the maximal node - * @throws {Error} if this Heap is empty + * @returns `[this, node]`, where `node` is the maximal node + * @throws {EmptyStructureError} if this Heap is empty */ public pop(): [this, T] { if (this.#internal.length > 0) { @@ -142,22 +143,24 @@ export class Heap { this.#siftDown(0); return [this, popped]; } else { - throw new Error('Cannot pop from empty Heap.'); + throw new EmptyStructureError('Cannot pop from empty Heap.'); } } /** * Remove the given node. - * @param node the node to remove - * @returns `[this, node]`, where `node` is the removed node - * @throws {Error} if the node is not in this Heap + * @param node the node to remove + * @returns `[this, node]`, where `node` is the removed node + * @throws {Error} if the node is not in this Heap + * @throws {EmptyStructureError} if this Heap is empty */ public remove(node: T): [this, T]; /** * Remove the first node that satisfies the given predicate. - * @param predicate a function to find nodes - * @returns `[this, node]`, where `node` is the removed node - * @throws {Error} if no node satisfies the predicate + * @param predicate a function to find nodes + * @returns `[this, node]`, where `node` is the removed node + * @throws {Error} if no node satisfies the predicate + * @throws {EmptyStructureError} if this Heap is empty */ public remove(predicate: (node: T, src: this) => boolean): [this, T]; public remove(arg: T | ((node: T, src: this) => boolean)): [this, T] { @@ -172,20 +175,22 @@ export class Heap { } throw new Error('No nodes were found to remove.'); } else { - throw new Error('Cannot remove from empty Heap.'); + throw new EmptyStructureError('Cannot remove from empty Heap.'); } } /** * Remove all of the given nodes. - * @param nodes the nodes to remove - * @returns `[this, nodes]`, where `nodes` is a list of the removed nodes + * @param nodes the nodes to remove + * @returns `[this, nodes]`, where `nodes` is a list of the removed nodes + * @throws {EmptyStructureError} if this Heap is empty */ public removeAll(nodes: readonly T[]): [this, T[]]; /** * Remove all nodes that satisfy the given predicate. - * @param predicate a function to find nodes - * @returns `[this, nodes]`, where `nodes` is a list of the removed nodes + * @param predicate a function to find nodes + * @returns `[this, nodes]`, where `nodes` is a list of the removed nodes + * @throws {EmptyStructureError} if this Heap is empty */ public removeAll(predicate: (node: T, src: this) => boolean): [this, T[]]; public removeAll(arg: readonly T[] | ((node: T, src: this) => boolean)): [this, T[]] { @@ -198,7 +203,7 @@ export class Heap { [...found_node_entries].reverse().forEach(([found_index]) => this.#internalDelete(found_index)); return [this, found_node_entries.map(([_, found_node]) => found_node)]; } else { - throw new Error('Cannot remove from empty Heap.'); + throw new EmptyStructureError('Cannot remove from empty Heap.'); } } diff --git a/src/Queue.ts b/src/Queue.ts index 3cefc62..1556ecb 100644 --- a/src/Queue.ts +++ b/src/Queue.ts @@ -1,3 +1,4 @@ +import {EmptyStructureError} from './EmptyStructureError.js'; import {LinkedList} from './LinkedList.js'; import {throw_error} from './utils-private.js'; @@ -23,7 +24,7 @@ export class Queue { public peek(): T { return (!this.internal.length) - ? throw_error(new Error('Queue is empty.')) + ? throw_error(new EmptyStructureError('Queue is empty.')) : this.internal.get(0); } @@ -34,7 +35,7 @@ export class Queue { public pop(): [this, T] { return (!this.internal.length) - ? throw_error(new Error('Cannot pop from empty queue.')) + ? throw_error(new EmptyStructureError('Cannot pop from empty queue.')) : [this, this.internal.shift()[1].firstItem]; } } diff --git a/src/index.ts b/src/index.ts index 8f14ba0..b41f23b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,3 +31,5 @@ export { DeletableQueue, } from './Queue.js'; export {Heap} from './Heap.js'; + +export {EmptyStructureError} from './EmptyStructureError.js'; diff --git a/test/Heap.test.ts b/test/Heap.test.ts index 302e377..63b06bf 100644 --- a/test/Heap.test.ts +++ b/test/Heap.test.ts @@ -1,6 +1,9 @@ /* eslint-disable arrow-body-style */ import * as assert from 'assert'; -import {Heap} from '../src/index.js'; +import { + EmptyStructureError, + Heap, +} from '../src/index.js'; @@ -55,7 +58,7 @@ describe('Heap', () => { }); it('throws when the heap is empty.', () => { - return assert.throws(() => new Heap(comparator).peek(), /Heap is empty\./); + return assert.throws(() => new Heap(comparator).peek(), EmptyStructureError); }); }); @@ -86,7 +89,7 @@ describe('Heap', () => { }); it('throws when the heap is empty.', () => { - return assert.throws(() => new Heap(comparator).pop(), /Cannot pop from empty Heap\./); + return assert.throws(() => new Heap(comparator).pop(), EmptyStructureError); }); }); @@ -106,7 +109,7 @@ describe('Heap', () => { }); it('throws when the heap is empty.', () => { - return assert.throws(() => new Heap(comparator_simple).remove(3), /Cannot remove from empty Heap\./); + return assert.throws(() => new Heap(comparator_simple).remove(3), EmptyStructureError); }); }); @@ -126,7 +129,7 @@ describe('Heap', () => { }); it('throws when the heap is empty.', () => { - return assert.throws(() => new Heap(comparator).remove((node) => 'priority' in node), /Cannot remove from empty Heap\./); + return assert.throws(() => new Heap(comparator).remove((node) => 'priority' in node), EmptyStructureError); }); }); @@ -146,7 +149,7 @@ describe('Heap', () => { }); it('throws when the heap is empty.', () => { - return assert.throws(() => new Heap(comparator_simple).removeAll([1, 2, 3]), /Cannot remove from empty Heap\./); + return assert.throws(() => new Heap(comparator_simple).removeAll([1, 2, 3]), EmptyStructureError); }); }); @@ -166,7 +169,7 @@ describe('Heap', () => { }); it('throws when the heap is empty.', () => { - return assert.throws(() => new Heap(comparator).removeAll((node) => 'priority' in node), /Cannot remove from empty Heap\./); + return assert.throws(() => new Heap(comparator).removeAll((node) => 'priority' in node), EmptyStructureError); }); }); diff --git a/test/Queue.test.ts b/test/Queue.test.ts index 7055458..5ca0864 100644 --- a/test/Queue.test.ts +++ b/test/Queue.test.ts @@ -1,6 +1,7 @@ /* eslint-disable arrow-body-style */ import * as assert from 'assert'; import { + EmptyStructureError, Queue, ReadableQueue, DeletableQueue, @@ -25,7 +26,7 @@ describe('Queue', () => { }); it('throws when the queue is empty.', () => { - return assert.throws(() => new Queue().peek(), /Queue is empty\./); + return assert.throws(() => new Queue().peek(), EmptyStructureError); }); }); @@ -59,7 +60,7 @@ describe('Queue', () => { }); it('throws when the queue is empty.', () => { - return assert.throws(() => new Queue().pop(), /Cannot pop from empty queue\./); + return assert.throws(() => new Queue().pop(), EmptyStructureError); }); }); }); From 160877fdfc900346de7fdc0a4e2ba930f0ace70a Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:25:23 -0400 Subject: [PATCH 26/33] perf: use xjs.Set.has() as condition for xjs.Set.add() --- src/class/Set.class.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index 410a305..a5e1d5d 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -215,8 +215,7 @@ export class xjs_Set { * @return the mutated set */ public static add(set: Set, element: T, comparator: (a: T, b: T) => boolean): typeof set { - const foundel: boolean = [...set].some((e) => comparator.call(null, e, element)); - return (!foundel) ? set.add(element) : set; + return xjs_Set.has(set, element, comparator) ? set : set.add(element); } /** From f3ce5df15931a534b2aab9cd945a41649514a0ab Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 10 Apr 2024 13:31:44 -0400 Subject: [PATCH 27/33] build: fresh install --- package-lock.json | 707 +++++++++++++++++++++++++--------------------- package.json | 10 +- 2 files changed, 384 insertions(+), 333 deletions(-) diff --git a/package-lock.json b/package-lock.json index f4c9ad1..7353a94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,13 +11,13 @@ "devDependencies": { "@types/mocha": "^10.0.0", "@types/node": "^20.0.0", - "@typescript-eslint/eslint-plugin": "^5.61.0", - "@typescript-eslint/parser": "^5.61.0", - "eslint": "^8.44.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0", "mocha": "^10.0.0", "ts-node": "^10.0.0", - "typedoc": "^0.24.0", - "typescript": "~5.1.3" + "typedoc": "^0.25.0", + "typescript": "~5.4.0" }, "engines": { "node": ">=18" @@ -60,18 +60,18 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", - "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -91,29 +91,73 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -128,15 +172,15 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" @@ -194,9 +238,9 @@ } }, "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true }, "node_modules/@tsconfig/node12": { @@ -218,56 +262,60 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/mocha": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", - "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", "dev": true }, "node_modules/@types/node": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz", - "integrity": "sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==", - "dev": true + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz", - "integrity": "sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz", + "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.61.0", - "@typescript-eslint/type-utils": "5.61.0", - "@typescript-eslint/utils": "5.61.0", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.6.0", + "@typescript-eslint/type-utils": "7.6.0", + "@typescript-eslint/utils": "7.6.0", + "@typescript-eslint/visitor-keys": "7.6.0", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -276,25 +324,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.61.0.tgz", - "integrity": "sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz", + "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.61.0", - "@typescript-eslint/types": "5.61.0", - "@typescript-eslint/typescript-estree": "5.61.0", + "@typescript-eslint/scope-manager": "7.6.0", + "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/visitor-keys": "7.6.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -303,16 +352,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.61.0.tgz", - "integrity": "sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz", + "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.61.0", - "@typescript-eslint/visitor-keys": "5.61.0" + "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/visitor-keys": "7.6.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -320,25 +369,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.61.0.tgz", - "integrity": "sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz", + "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.61.0", - "@typescript-eslint/utils": "5.61.0", + "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/utils": "7.6.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -347,12 +396,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.61.0.tgz", - "integrity": "sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz", + "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -360,21 +409,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.61.0.tgz", - "integrity": "sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz", + "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.61.0", - "@typescript-eslint/visitor-keys": "5.61.0", + "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/visitor-keys": "7.6.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -387,52 +437,57 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.61.0.tgz", - "integrity": "sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz", + "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.61.0", - "@typescript-eslint/types": "5.61.0", - "@typescript-eslint/typescript-estree": "5.61.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.6.0", + "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/typescript-estree": "7.6.0", + "semver": "^7.6.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.61.0.tgz", - "integrity": "sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz", + "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.61.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "7.6.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -451,9 +506,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, "engines": { "node": ">=0.4.0" @@ -494,9 +549,9 @@ } }, "node_modules/ansi-sequence-parser": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", - "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", "dev": true }, "node_modules/ansi-styles": { @@ -555,22 +610,24 @@ "dev": true }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -797,9 +854,9 @@ "dev": true }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -818,27 +875,28 @@ } }, "node_modules/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -848,7 +906,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -860,7 +917,6 @@ "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -874,22 +930,25 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -898,35 +957,32 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=4.0" + "node": "*" } }, "node_modules/espree": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", - "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { "acorn": "^8.9.0", @@ -952,15 +1008,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -973,7 +1020,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -982,15 +1029,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1007,9 +1045,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", - "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1047,9 +1085,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1105,12 +1143,13 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { @@ -1118,9 +1157,9 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/fs.realpath": { @@ -1130,9 +1169,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1153,20 +1192,19 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1184,10 +1222,22 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1244,9 +1294,9 @@ } }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -1392,6 +1442,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1405,11 +1461,20 @@ "dev": true }, "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1519,21 +1584,24 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", + "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", "dev": true, "dependencies": { "ansi-colors": "4.1.1", @@ -1543,13 +1611,12 @@ "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "8.1.0", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -1564,19 +1631,6 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" } }, "node_modules/mocha/node_modules/minimatch": { @@ -1618,30 +1672,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1777,9 +1813,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -1869,6 +1905,48 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -1913,9 +1991,9 @@ ] }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1958,9 +2036,9 @@ } }, "node_modules/shiki": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", - "integrity": "sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==", + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", + "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", "dev": true, "dependencies": { "ansi-sequence-parser": "^1.1.0", @@ -2046,10 +2124,22 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -2098,27 +2188,6 @@ "node": ">=0.3.1" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -2144,54 +2213,30 @@ } }, "node_modules/typedoc": { - "version": "0.24.8", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", - "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", + "version": "0.25.13", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.13.tgz", + "integrity": "sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.3.0", - "minimatch": "^9.0.0", - "shiki": "^0.14.1" + "minimatch": "^9.0.3", + "shiki": "^0.14.7" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 14.14" + "node": ">= 16" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" - } - }, - "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.2.tgz", - "integrity": "sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x" } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -2201,6 +2246,12 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index 37d6265..c37359e 100644 --- a/package.json +++ b/package.json @@ -36,13 +36,13 @@ "devDependencies": { "@types/mocha": "^10.0.0", "@types/node": "^20.0.0", - "@typescript-eslint/eslint-plugin": "^5.61.0", - "@typescript-eslint/parser": "^5.61.0", - "eslint": "^8.44.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0", "mocha": "^10.0.0", "ts-node": "^10.0.0", - "typedoc": "^0.24.0", - "typescript": "~5.1.3" + "typedoc": "^0.25.0", + "typescript": "~5.4.0" }, "engines": { "node": ">=18" From feeb2d4de2d63f3d78aba1379c80910be86ca4de Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:04:52 -0400 Subject: [PATCH 28/33] build: remove unused eslint directives --- src/class/Array.class.ts | 1 - src/class/BigInt.class.ts | 1 - src/class/Date.class.ts | 1 - src/class/Map.class.ts | 1 - src/class/Math.class.ts | 1 - src/class/Number.class.ts | 1 - src/class/Object.class.ts | 1 - src/class/Promise.class.ts | 1 - src/class/Set.class.ts | 1 - src/class/String.class.ts | 1 - test/Object.test.ts | 2 +- 11 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index 12f1f35..3199f2f 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -424,6 +424,5 @@ export class xjs_Array { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/BigInt.class.ts b/src/class/BigInt.class.ts index a6affbd..9fb88cd 100644 --- a/src/class/BigInt.class.ts +++ b/src/class/BigInt.class.ts @@ -57,6 +57,5 @@ export class xjs_BigInt { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Date.class.ts b/src/class/Date.class.ts index 21f413c..3e5132a 100644 --- a/src/class/Date.class.ts +++ b/src/class/Date.class.ts @@ -110,6 +110,5 @@ export class xjs_Date { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index 491c656..80d683b 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -217,6 +217,5 @@ export class xjs_Map { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Math.class.ts b/src/class/Math.class.ts index 09f1455..e1f7fbb 100644 --- a/src/class/Math.class.ts +++ b/src/class/Math.class.ts @@ -302,6 +302,5 @@ export class xjs_Math { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Number.class.ts b/src/class/Number.class.ts index b37d7ef..a6dab5d 100644 --- a/src/class/Number.class.ts +++ b/src/class/Number.class.ts @@ -103,6 +103,5 @@ export class xjs_Number { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index c945587..fd0dac8 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -336,6 +336,5 @@ export class xjs_Object { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Promise.class.ts b/src/class/Promise.class.ts index 1f166ca..933ebff 100644 --- a/src/class/Promise.class.ts +++ b/src/class/Promise.class.ts @@ -37,6 +37,5 @@ export class xjs_Promise { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index 410a305..cb3590e 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -232,6 +232,5 @@ export class xjs_Set { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/src/class/String.class.ts b/src/class/String.class.ts index 710d910..7cb322c 100644 --- a/src/class/String.class.ts +++ b/src/class/String.class.ts @@ -85,6 +85,5 @@ export class xjs_String { } - // eslint-disable-next-line @typescript-eslint/no-empty-function --- we want the constructor to be private private constructor() {} } diff --git a/test/Object.test.ts b/test/Object.test.ts index 5214d50..dcea7da 100644 --- a/test/Object.test.ts +++ b/test/Object.test.ts @@ -25,7 +25,7 @@ describe('xjs.Object', () => { assert.strictEqual(xjs_Object.typeOf(21 + 21), 'number'); assert.strictEqual(xjs_Object.typeOf(true), 'boolean'); assert.strictEqual(xjs_Object.typeOf('true'), 'string'); - assert.strictEqual(xjs_Object.typeOf(class { public constructor() {} }), 'function'); // eslint-disable-line @typescript-eslint/brace-style, @typescript-eslint/no-useless-constructor, @typescript-eslint/no-empty-function + assert.strictEqual(xjs_Object.typeOf(class { public constructor() {} }), 'function'); // eslint-disable-line @typescript-eslint/brace-style, @typescript-eslint/no-useless-constructor assert.strictEqual(xjs_Object.typeOf(function () { return 'true'; }), 'function'); // eslint-disable-line prefer-arrow-callback, @typescript-eslint/brace-style assert.strictEqual(xjs_Object.typeOf(() => 'true'), 'function'); assert.strictEqual(xjs_Object.typeOf(undefined), 'undefined'); From 070793b8143369f552a3908b81adf7d83c469e7a Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:06:49 -0400 Subject: [PATCH 29/33] docs: update broken links --- src/class/Array.class.ts | 2 +- src/class/Map.class.ts | 1 + src/class/Math.class.ts | 2 +- src/class/Object.class.ts | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index 3199f2f..0acc828 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -39,7 +39,7 @@ export class xjs_Array { * Warning: passing in sparse arrays can yield unexpected results. * * Elements are compared via the provided predicate. - * If no predicate is provided, this method uses the default predicate {@link xjs_Object._sameValueZero}. + * If no predicate is provided, this method uses the default predicate {@link xjs_Object.sameValueZero}. * * ```js * 'twofoursix'.includes('wofo')===true diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index 80d683b..8756565 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -1,4 +1,5 @@ import {xjs_Object} from './Object.class.js'; +import type {xjs_Set} from './Set.class.js'; /** diff --git a/src/class/Math.class.ts b/src/class/Math.class.ts index e1f7fbb..088d1e7 100644 --- a/src/class/Math.class.ts +++ b/src/class/Math.class.ts @@ -87,7 +87,7 @@ export class xjs_Math { } /** - * {@link xjx_Math.clamp}, but for `bigint` types. + * {@link xjs_Math.clamp}, but for `bigint` types. * @param min - the lower bound * @param val - the value to clamp between the bounds * @param max - the upper bound diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index fd0dac8..83511ed 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -17,13 +17,13 @@ export class xjs_Object { * This function tests the properties of two arguemnts, using the provided predicate. * Arguments must be of the same type. * If both are primitives, this method checks - * {@link xjs_Object._sameValueZero|Same-Value-Zero Equality}. + * {@link xjs_Object.sameValueZero|Same-Value-Zero Equality}. * If either are functions, this method throws an TypeError — functions are not supported at this time. * If both arguments are arrays, it is faster and more robust to use {@link xjs_Array.is}. * If both are objects or arrays, this method checks the properties (or elements) of each, * comparing them with the provided predicate. * - * If no predicate is provided, this method uses the default predicate {@link xjs_Object._sameValueZero}. + * If no predicate is provided, this method uses the default predicate {@link xjs_Object.sameValueZero}. * * Note: This method does not deep-check equality within the objects’ properties (or arrays’ elements). * To check deeper, I suggest using Node.js’s native From a2dcec37bcc5e2ffc99c588783e8aad72bb6d7ee Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:40:47 -0400 Subject: [PATCH 30/33] refactor: xjs.Set.is uses xjs.Set.isSubsetOf --- src/class/Set.class.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index a5e1d5d..275265f 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -1,5 +1,5 @@ import {xjs_Object} from './Object.class.js'; -import {xjs_Array} from './Array.class.js'; +import type {xjs_Array} from './Array.class.js'; /** @@ -23,8 +23,8 @@ export class xjs_Set { return true; } return a.size === b.size - && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || predicate(a_el, b_el))) - && [...b].every((b_el) => [...a].some((a_el) => xjs_Object.sameValueZero(b_el, a_el) || predicate(b_el, a_el))); + && xjs_Set.isSubsetOf(a, b, predicate) + && xjs_Set.isSubsetOf(b, a, predicate); } /** @@ -70,8 +70,7 @@ export class xjs_Set { /** * Return whether `a` is a subset of `b`: whether all elements of `a` are in `b`. * - * Note that if `a` is an empty set, or if `a` and `b` are “the same” (as determined by `predicate`), - * this method returns `true`. + * Note that if `a` is an empty set, this method returns `true`. * @see https://github.com/tc39/proposal-set-methods * @typeparam T - the type of elements in `a` * @typeparam U - the type of elements in `b` @@ -81,7 +80,10 @@ export class xjs_Set { * @returns Is `a` a subset of `b`? */ public static isSubsetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { - return xjs_Array.isSubarrayOf([...a].sort(), [...b].sort(), predicate); + if (a === b || a.size === 0) { + return true; + } + return a.size <= b.size && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || predicate(a_el, b_el))); } /** From 1e51e7659b94a6f4a00496ebc58d1b68ee9429f2 Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:12:36 -0400 Subject: [PATCH 31/33] refactor: simplify condition --- src/class/Array.class.ts | 5 +---- src/class/Set.class.ts | 12 ++---------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index 12f1f35..a538aab 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -87,10 +87,7 @@ export class xjs_Array { * @returns Are corresponding elements the same, i.e. replaceable? */ public static is(a: readonly T[], b: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { - if (a === b) { - return true; - } - return a.length === b.length && a.every((el, i) => xjs_Object.sameValueZero(el, b[i]) || predicate(el, b[i])); + return a === b || a.length === b.length && a.every((el, i) => xjs_Object.sameValueZero(el, b[i]) || predicate(el, b[i])); } /** diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index 275265f..160bf1b 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -19,12 +19,7 @@ export class xjs_Set { * @returns Are corresponding elements the same, i.e. replaceable? */ public static is(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { - if (a === b) { - return true; - } - return a.size === b.size - && xjs_Set.isSubsetOf(a, b, predicate) - && xjs_Set.isSubsetOf(b, a, predicate); + return a === b || a.size === b.size && xjs_Set.isSubsetOf(a, b, predicate) && xjs_Set.isSubsetOf(b, a, predicate); } /** @@ -80,10 +75,7 @@ export class xjs_Set { * @returns Is `a` a subset of `b`? */ public static isSubsetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { - if (a === b || a.size === 0) { - return true; - } - return a.size <= b.size && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || predicate(a_el, b_el))); + return a === b || a.size === 0 || a.size <= b.size && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || predicate(a_el, b_el))); } /** From 830b622d80ff9286097ab3bdabdd4221f35d55da Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:24:04 -0400 Subject: [PATCH 32/33] refactor: remove predicate parameter defaults --- src/class/Array.class.ts | 20 ++++++++++---------- src/class/Map.class.ts | 18 ++++++++---------- src/class/Object.class.ts | 6 +++--- src/class/Set.class.ts | 8 ++++---- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index a538aab..ae22bbc 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -58,7 +58,7 @@ export class xjs_Array { * @throws {RangeError} if the second array is larger than the first * @deprecated use {@link xjs_Array.isConsecutiveSuperarrayOf} instead. */ - public static contains(larger: readonly T[], smaller: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static contains(larger: readonly T[], smaller: readonly T[], predicate?: (x: T, y: T) => boolean): boolean { if (smaller.length > larger.length) { throw new RangeError('First argument cannot be smaller than the second. Try switching the arguments.'); } @@ -86,8 +86,8 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Are corresponding elements the same, i.e. replaceable? */ - public static is(a: readonly T[], b: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { - return a === b || a.length === b.length && a.every((el, i) => xjs_Object.sameValueZero(el, b[i]) || predicate(el, b[i])); + public static is(a: readonly T[], b: readonly T[], predicate?: (x: T, y: T) => boolean): boolean { + return a === b || a.length === b.length && a.every((el, i) => xjs_Object.sameValueZero(el, b[i]) || !!predicate?.(el, b[i])); } /** @@ -108,12 +108,12 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Is `a` a subarray of `b`? */ - public static isSubarrayOf(a: readonly T[], b: readonly U[], predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { + public static isSubarrayOf(a: readonly T[], b: readonly U[], predicate?: (x: U, y: U) => boolean): boolean { return a.length <= b.length && ( a.length === 0 || xjs_Array.is(a, b, predicate) || a - .map((t) => b.findIndex((u) => predicate(u, t))) // indices of `b`’s elements in the order in which they appear in `a` + .map((t) => b.findIndex((u) => xjs_Object.sameValueZero(u, t) || !!predicate?.(u, t))) // indices of `b`’s elements in the order in which they appear in `a` .every((n, i, indices) => n >= 0 && (i === 0 || indices[i] > indices[i - 1])) // indices must all be 0+ and increasing (all of `a`’s elements are present in `b` and in the right order) ); } @@ -127,7 +127,7 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns exactly `xjs_Array.isSubarrayOf(b, a, predicate)` */ - public static isSuperarrayOf(a: readonly T[], b: readonly U[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static isSuperarrayOf(a: readonly T[], b: readonly U[], predicate?: (x: T, y: T) => boolean): boolean { return xjs_Array.isSubarrayOf(b, a, predicate); } @@ -140,7 +140,7 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Is `a` a consecutive subarray of `b`? */ - public static isConsecutiveSubarrayOf(a: readonly T[], b: readonly U[], predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { + public static isConsecutiveSubarrayOf(a: readonly T[], b: readonly U[], predicate?: (x: U, y: U) => boolean): boolean { return xjs_Array.isSubarrayOf(a, b, predicate) && b.map((_el, i) => b.slice(i, i + a.length)).some((sub) => xjs_Array.is(a, sub, predicate)); } @@ -153,7 +153,7 @@ export class xjs_Array { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns exactly `xjs_Array.isConsecutiveSubarrayOf(b, a, predicate)` */ - public static isConsecutiveSuperarrayOf(a: readonly T[], b: readonly U[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static isConsecutiveSuperarrayOf(a: readonly T[], b: readonly U[], predicate?: (x: T, y: T) => boolean): boolean { return xjs_Array.isConsecutiveSubarrayOf(b, a, predicate); } @@ -348,11 +348,11 @@ export class xjs_Array { * @returns a new array, with duplicates removed * @deprecated use `[...new Set(arr)]` instead */ - public static removeDuplicates(arr: readonly T[], predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): T[] { + public static removeDuplicates(arr: readonly T[], predicate?: (x: T, y: T) => boolean): T[] { const returned: T[] = arr.slice(); for (let i = 0; i < returned.length; i++) { for (let j = i + 1; j < returned.length; j++) { - if (predicate(returned[i], returned[j])) { + if (xjs_Object.sameValueZero(returned[i], returned[j]) || !!predicate?.(returned[i], returned[j])) { returned.splice(j, 1); } } diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index 491c656..cfcedbc 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -16,23 +16,21 @@ export class xjs_Map { * @typeparam V - the type of values in the maps * @param a the first map * @param b the second map + * @param predicates for checking equality for keys/values * @returns Are corresponding pairs the same, i.e. replaceable? */ public static is(a: ReadonlyMap, b: ReadonlyMap, { - /** check the “sameness” of corresponding keys of `a` and `b` */ - keys = xjs_Object.sameValueZero, - /** check the “sameness” of corresponding values of `a` and `b` */ - values = xjs_Object.sameValueZero, + keys, + values, }: { + /** check the “sameness” of corresponding keys of `a` and `b` */ keys?: (x: K, y: K) => boolean, + /** check the “sameness” of corresponding values of `a` and `b` */ values?: (x: V, y: V) => boolean, - } = { - keys: xjs_Object.sameValueZero, - values: xjs_Object.sameValueZero, - }): boolean { + } = {}): boolean { return a === b || a.size === b.size && [...a].every(([a_key, a_val]) => [...b].some(([b_key, b_val]) => ( - (xjs_Object.sameValueZero(a_key, b_key) || keys (a_key, b_key)) - && (xjs_Object.sameValueZero(a_val, b_val) || values(a_val, b_val)) + (xjs_Object.sameValueZero(a_key, b_key) || !!keys?.(a_key, b_key)) + && (xjs_Object.sameValueZero(a_val, b_val) || !!values?.(a_val, b_val)) ))); } diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index c945587..97bdc45 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -48,7 +48,7 @@ export class xjs_Object { * @returns Are corresponding properties the same, i.e. replaceable? * @throws {TypeError} if either `a` or `b` is a function (not supported) */ - public static is(a: T, b: T, predicate: (x: T[keyof T], y: T[keyof T]) => boolean = xjs_Object.sameValueZero): boolean { + public static is(a: T, b: T, predicate?: (x: T[keyof T], y: T[keyof T]) => boolean): boolean { if (a === b) { return true; } @@ -63,8 +63,8 @@ export class xjs_Object { } // else, it will be 'object' return ( - Object.entries(a as Record).every(([a_key, a_value]) => Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && predicate(a_value, b_value))) - && Object.entries(b as Record).every(([b_key, b_value]) => Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && predicate(a_value, b_value))) + Object.entries(a as Record).every(([a_key, a_value]) => Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && (xjs_Object.sameValueZero(a_value, b_value) || !!predicate?.(a_value, b_value)))) + && Object.entries(b as Record).every(([b_key, b_value]) => Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && (xjs_Object.sameValueZero(a_value, b_value) || !!predicate?.(a_value, b_value)))) ); } diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index 160bf1b..5de5e14 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -18,7 +18,7 @@ export class xjs_Set { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Are corresponding elements the same, i.e. replaceable? */ - public static is(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static is(a: ReadonlySet, b: ReadonlySet, predicate?: (x: T, y: T) => boolean): boolean { return a === b || a.size === b.size && xjs_Set.isSubsetOf(a, b, predicate) && xjs_Set.isSubsetOf(b, a, predicate); } @@ -74,8 +74,8 @@ export class xjs_Set { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns Is `a` a subset of `b`? */ - public static isSubsetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: U, y: U) => boolean = xjs_Object.sameValueZero): boolean { - return a === b || a.size === 0 || a.size <= b.size && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || predicate(a_el, b_el))); + public static isSubsetOf(a: ReadonlySet, b: ReadonlySet, predicate?: (x: U, y: U) => boolean): boolean { + return a === b || a.size === 0 || a.size <= b.size && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || !!predicate?.(a_el, b_el))); } /** @@ -88,7 +88,7 @@ export class xjs_Set { * @param predicate check the “sameness” of corresponding elements of `a` and `b` * @returns exactly `xjs.Set.isSubsetOf(b, a, predicate)` */ - public static isSupersetOf(a: ReadonlySet, b: ReadonlySet, predicate: (x: T, y: T) => boolean = xjs_Object.sameValueZero): boolean { + public static isSupersetOf(a: ReadonlySet, b: ReadonlySet, predicate?: (x: T, y: T) => boolean): boolean { return xjs_Set.isSubsetOf(b, a, predicate); } From f038c063760525c1dfc2406b0a5fdb041790697a Mon Sep 17 00:00:00 2001 From: Chris Harvey <1362083+chharvey@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:31:46 -0400 Subject: [PATCH 33/33] fix: call predicate with null context --- src/class/Array.class.ts | 6 +++--- src/class/Map.class.ts | 4 ++-- src/class/Object.class.ts | 4 ++-- src/class/Set.class.ts | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/class/Array.class.ts b/src/class/Array.class.ts index ae22bbc..30dad71 100644 --- a/src/class/Array.class.ts +++ b/src/class/Array.class.ts @@ -87,7 +87,7 @@ export class xjs_Array { * @returns Are corresponding elements the same, i.e. replaceable? */ public static is(a: readonly T[], b: readonly T[], predicate?: (x: T, y: T) => boolean): boolean { - return a === b || a.length === b.length && a.every((el, i) => xjs_Object.sameValueZero(el, b[i]) || !!predicate?.(el, b[i])); + return a === b || a.length === b.length && a.every((el, i) => xjs_Object.sameValueZero(el, b[i]) || !!predicate?.call(null, el, b[i])); } /** @@ -113,7 +113,7 @@ export class xjs_Array { a.length === 0 || xjs_Array.is(a, b, predicate) || a - .map((t) => b.findIndex((u) => xjs_Object.sameValueZero(u, t) || !!predicate?.(u, t))) // indices of `b`’s elements in the order in which they appear in `a` + .map((t) => b.findIndex((u) => xjs_Object.sameValueZero(u, t) || !!predicate?.call(null, u, t))) // indices of `b`’s elements in the order in which they appear in `a` .every((n, i, indices) => n >= 0 && (i === 0 || indices[i] > indices[i - 1])) // indices must all be 0+ and increasing (all of `a`’s elements are present in `b` and in the right order) ); } @@ -352,7 +352,7 @@ export class xjs_Array { const returned: T[] = arr.slice(); for (let i = 0; i < returned.length; i++) { for (let j = i + 1; j < returned.length; j++) { - if (xjs_Object.sameValueZero(returned[i], returned[j]) || !!predicate?.(returned[i], returned[j])) { + if (xjs_Object.sameValueZero(returned[i], returned[j]) || !!predicate?.call(null, returned[i], returned[j])) { returned.splice(j, 1); } } diff --git a/src/class/Map.class.ts b/src/class/Map.class.ts index cfcedbc..5828667 100644 --- a/src/class/Map.class.ts +++ b/src/class/Map.class.ts @@ -29,8 +29,8 @@ export class xjs_Map { values?: (x: V, y: V) => boolean, } = {}): boolean { return a === b || a.size === b.size && [...a].every(([a_key, a_val]) => [...b].some(([b_key, b_val]) => ( - (xjs_Object.sameValueZero(a_key, b_key) || !!keys?.(a_key, b_key)) - && (xjs_Object.sameValueZero(a_val, b_val) || !!values?.(a_val, b_val)) + (xjs_Object.sameValueZero(a_key, b_key) || !!keys ?.call(null, a_key, b_key)) + && (xjs_Object.sameValueZero(a_val, b_val) || !!values?.call(null, a_val, b_val)) ))); } diff --git a/src/class/Object.class.ts b/src/class/Object.class.ts index 97bdc45..364524c 100644 --- a/src/class/Object.class.ts +++ b/src/class/Object.class.ts @@ -63,8 +63,8 @@ export class xjs_Object { } // else, it will be 'object' return ( - Object.entries(a as Record).every(([a_key, a_value]) => Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && (xjs_Object.sameValueZero(a_value, b_value) || !!predicate?.(a_value, b_value)))) - && Object.entries(b as Record).every(([b_key, b_value]) => Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && (xjs_Object.sameValueZero(a_value, b_value) || !!predicate?.(a_value, b_value)))) + Object.entries(a as Record).every(([a_key, a_value]) => Object.entries(b as Record).some(([b_key, b_value]) => a_key === b_key && (xjs_Object.sameValueZero(a_value, b_value) || !!predicate?.call(null, a_value, b_value)))) + && Object.entries(b as Record).every(([b_key, b_value]) => Object.entries(a as Record).some(([a_key, a_value]) => a_key === b_key && (xjs_Object.sameValueZero(a_value, b_value) || !!predicate?.call(null, a_value, b_value)))) ); } diff --git a/src/class/Set.class.ts b/src/class/Set.class.ts index 5de5e14..761e6c1 100644 --- a/src/class/Set.class.ts +++ b/src/class/Set.class.ts @@ -75,7 +75,7 @@ export class xjs_Set { * @returns Is `a` a subset of `b`? */ public static isSubsetOf(a: ReadonlySet, b: ReadonlySet, predicate?: (x: U, y: U) => boolean): boolean { - return a === b || a.size === 0 || a.size <= b.size && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || !!predicate?.(a_el, b_el))); + return a === b || a.size === 0 || a.size <= b.size && [...a].every((a_el) => [...b].some((b_el) => xjs_Object.sameValueZero(a_el, b_el) || !!predicate?.call(null, a_el, b_el))); } /**