From 0d7c2bfe9db03d3253118e72910e01fe0f9921cc Mon Sep 17 00:00:00 2001 From: Daniel Rocha Date: Wed, 6 Sep 2023 23:26:37 +0200 Subject: [PATCH] fix: add `exactOptional()` superstruct type (#100) --- .github/workflows/build-lint-test.yml | 1 + jest.config.js | 2 +- package.json | 10 +- src/JsonRpcRequest.ts | 31 +- src/api.ts | 17 +- src/index.ts | 2 + src/internal/types.ts | 9 +- src/rpc-handler.test.ts | 4 +- src/superstruct.test-d.ts | 20 ++ src/superstruct.test.ts | 72 ++++ src/superstruct.ts | 105 ++++++ yarn.lock | 461 ++++++++++++++++++++++++-- 12 files changed, 673 insertions(+), 61 deletions(-) create mode 100644 src/superstruct.test-d.ts create mode 100644 src/superstruct.test.ts create mode 100644 src/superstruct.ts diff --git a/.github/workflows/build-lint-test.yml b/.github/workflows/build-lint-test.yml index 8e82268fa..213569e9c 100644 --- a/.github/workflows/build-lint-test.yml +++ b/.github/workflows/build-lint-test.yml @@ -89,6 +89,7 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'yarn' - run: yarn --immutable --immutable-cache + - run: yarn build - run: yarn test - name: Require clean working directory shell: bash diff --git a/jest.config.js b/jest.config.js index 83e15048b..699da9a93 100644 --- a/jest.config.js +++ b/jest.config.js @@ -22,7 +22,7 @@ module.exports = { collectCoverage: true, // An array of glob patterns indicating a set of files for which coverage information should be collected - collectCoverageFrom: ['./src/**/*.ts'], + collectCoverageFrom: ['./src/**/*.ts', '!./src/**/*.test-d.ts'], // The directory where Jest should output its coverage files coverageDirectory: 'coverage', diff --git a/package.json b/package.json index b5656aaff..73793ad23 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "lint:fix": "yarn lint:eslint --fix && yarn lint:constraints --fix && yarn lint:misc --write && yarn lint:dependencies && yarn lint:changelog", "lint:misc": "prettier '**/*.json' '**/*.md' '!CHANGELOG.md' '**/*.yml' '!.yarnrc.yml' --ignore-path .gitignore --no-error-on-unmatched-pattern", "prepack": "./scripts/prepack.sh", - "test": "jest && jest-it-up", + "test": "yarn test:source && yarn test:types", + "test:source": "jest && jest-it-up", + "test:types": "tsd", "test:watch": "jest --watch" }, "dependencies": { @@ -40,7 +42,7 @@ "@metamask/rpc-methods": "^0.38.1-flask.1", "@metamask/snaps-controllers": "^0.38.2-flask.1", "@metamask/snaps-utils": "^0.38.2-flask.1", - "@metamask/utils": "^8.0.0", + "@metamask/utils": "^8.1.0", "@types/uuid": "^9.0.1", "superstruct": "^1.0.3", "uuid": "^9.0.0" @@ -73,6 +75,7 @@ "rimraf": "^3.0.2", "ts-jest": "^28.0.7", "ts-node": "^10.7.0", + "tsd": "^0.29.0", "typedoc": "^0.23.15", "typescript": "~4.8.4" }, @@ -96,5 +99,8 @@ "@metamask/rpc-methods>@metamask/permission-controller>@metamask/controller-utils>ethereumjs-util>ethereum-cryptography>keccak": false, "@metamask/rpc-methods>@metamask/permission-controller>@metamask/controller-utils>ethereumjs-util>ethereum-cryptography>secp256k1": false } + }, + "tsd": { + "directory": "src" } } diff --git a/src/JsonRpcRequest.ts b/src/JsonRpcRequest.ts index 9fb193af9..9e9f258c1 100644 --- a/src/JsonRpcRequest.ts +++ b/src/JsonRpcRequest.ts @@ -1,30 +1,17 @@ import { JsonStruct } from '@metamask/utils'; import type { Infer } from 'superstruct'; -import { - array, - literal, - nullable, - number, - object, - record, - string, - union, -} from 'superstruct'; +import { array, literal, number, record, string, union } from 'superstruct'; -const Common = { +import { exactOptional, object } from './superstruct'; + +export const JsonRpcRequestStruct = object({ jsonrpc: literal('2.0'), - id: nullable(union([string(), number()])), + id: union([string(), number(), literal(null)]), method: string(), -}; - -const Params = { - params: union([array(JsonStruct), record(string(), JsonStruct)]), -}; - -export const JsonRpcRequestStruct = union([ - object({ ...Common }), - object({ ...Common, ...Params }), -]); + params: exactOptional( + union([array(JsonStruct), record(string(), JsonStruct)]), + ), +}); /** * JSON-RPC request type. diff --git a/src/api.ts b/src/api.ts index ac8bfb1b7..8b1525e30 100644 --- a/src/api.ts +++ b/src/api.ts @@ -5,13 +5,13 @@ import { array, enums, literal, - object, record, string, union, nullable, } from 'superstruct'; +import { exactOptional, object } from './superstruct'; import { UuidStruct } from './utils'; /** @@ -98,15 +98,12 @@ export const KeyringRequestStruct = object({ /** * Inner request sent by the client application. */ - request: union([ - object({ - method: string(), - }), - object({ - method: string(), - params: union([array(JsonStruct), record(string(), JsonStruct)]), - }), - ]), + request: object({ + method: string(), + params: exactOptional( + union([array(JsonStruct), record(string(), JsonStruct)]), + ), + }), }); /** diff --git a/src/index.ts b/src/index.ts index 75fe0edc2..6a134f613 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,5 @@ export * from './rpc-handler'; export * from './KeyringSnapControllerClient'; export * from './KeyringSnapRpcClient'; export * from './internal'; +export * from './snap-utils'; +export * from './superstruct'; diff --git a/src/internal/types.ts b/src/internal/types.ts index 8747b7acb..11e7f91d8 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -1,20 +1,21 @@ import type { Infer } from 'superstruct'; -import { boolean, object, optional, string, number } from 'superstruct'; +import { boolean, string, number } from 'superstruct'; import { KeyringAccountStruct } from '../api'; +import { exactOptional, object } from '../superstruct'; export const InternalAccountStruct = object({ ...KeyringAccountStruct.schema, metadata: object({ - snap: optional( + name: string(), + snap: exactOptional( object({ id: string(), enabled: boolean(), name: string(), }), ), - name: string(), - lastSelected: optional(number()), + lastSelected: exactOptional(number()), keyring: object({ type: string(), }), diff --git a/src/rpc-handler.test.ts b/src/rpc-handler.test.ts index 9b02841d9..6bafb230a 100644 --- a/src/rpc-handler.test.ts +++ b/src/rpc-handler.test.ts @@ -146,7 +146,9 @@ describe('keyringRpcDispatcher', () => { await expect( handleKeyringRequest(keyring, request as unknown as JsonRpcRequest), - ).rejects.toThrow('Expected the value to satisfy a union of'); + ).rejects.toThrow( + 'At path: method -- Expected a string, but received: undefined', + ); }); it('should call keyring_getAccount', async () => { diff --git a/src/superstruct.test-d.ts b/src/superstruct.test-d.ts new file mode 100644 index 000000000..601c9da13 --- /dev/null +++ b/src/superstruct.test-d.ts @@ -0,0 +1,20 @@ +import type { Infer } from 'superstruct'; +import { boolean, number, optional, string } from 'superstruct'; +import { expectAssignable, expectNotAssignable } from 'tsd'; + +import { exactOptional, object } from '.'; + +const exactOptionalObject = object({ + a: number(), + b: optional(string()), + c: exactOptional(boolean()), +}); + +type ExactOptionalObject = Infer; + +expectAssignable({ a: 0 }); +expectAssignable({ a: 0, b: 'test' }); +expectAssignable({ a: 0, b: 'test', c: true }); +expectAssignable({ a: 0, b: undefined }); +expectNotAssignable({ a: 0, b: 'test', c: 0 }); +expectNotAssignable({ a: 0, b: 'test', c: undefined }); diff --git a/src/superstruct.test.ts b/src/superstruct.test.ts new file mode 100644 index 000000000..dd0c5582f --- /dev/null +++ b/src/superstruct.test.ts @@ -0,0 +1,72 @@ +import { is, literal, max, number, string, union } from 'superstruct'; + +import { exactOptional, object } from '.'; + +describe('superstruct', () => { + describe('exactOptional', () => { + const simpleStruct = object({ + foo: exactOptional(string()), + }); + + it.each([ + { struct: simpleStruct, obj: {}, expected: true }, + { struct: simpleStruct, obj: { foo: undefined }, expected: false }, + { struct: simpleStruct, obj: { foo: 'hi' }, expected: true }, + { struct: simpleStruct, obj: { bar: 'hi' }, expected: false }, + { struct: simpleStruct, obj: { foo: 1 }, expected: false }, + ])( + 'returns $expected for is($obj, )', + ({ struct, obj, expected }) => { + expect(is(obj, struct)).toBe(expected); + }, + ); + + const nestedStruct = object({ + foo: object({ + bar: exactOptional(string()), + }), + }); + + it.each([ + { struct: nestedStruct, obj: { foo: {} }, expected: true }, + { struct: nestedStruct, obj: { foo: { bar: 'hi' } }, expected: true }, + { + struct: nestedStruct, + obj: { foo: { bar: undefined } }, + expected: false, + }, + ])( + 'returns $expected for is($obj, )', + ({ struct, obj, expected }) => { + expect(is(obj, struct)).toBe(expected); + }, + ); + + const structWithUndef = object({ + foo: exactOptional(union([string(), literal(undefined)])), + }); + + it.each([ + { struct: structWithUndef, obj: {}, expected: true }, + { struct: structWithUndef, obj: { foo: undefined }, expected: true }, + { struct: structWithUndef, obj: { foo: 'hi' }, expected: true }, + { struct: structWithUndef, obj: { bar: 'hi' }, expected: false }, + { struct: structWithUndef, obj: { foo: 1 }, expected: false }, + ])( + 'returns $expected for is($obj, )', + ({ struct, obj, expected }) => { + expect(is(obj, struct)).toBe(expected); + }, + ); + + it('should support refinements', () => { + const struct = object({ + foo: exactOptional(max(number(), 0)), + }); + + expect(is({ foo: 0 }, struct)).toBe(true); + expect(is({ foo: -1 }, struct)).toBe(true); + expect(is({ foo: 1 }, struct)).toBe(false); + }); + }); +}); diff --git a/src/superstruct.ts b/src/superstruct.ts new file mode 100644 index 000000000..481c626f7 --- /dev/null +++ b/src/superstruct.ts @@ -0,0 +1,105 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { + type Infer, + type Context, + Struct, + object as stObject, +} from 'superstruct'; +import type { + ObjectSchema, + OmitBy, + Optionalize, + PickBy, + Simplify, +} from 'superstruct/dist/utils'; + +declare const ExactOptionalSymbol: unique symbol; + +export type ExactOptionalTag = { + type: typeof ExactOptionalSymbol; +}; + +/** + * Exclude a type from the properties of a type. + * + * ```ts + * type Foo = { a: string | null; b: number }; + * type Bar = ExcludeType; + * // Bar = { a: string, b: number } + * ``` + */ +export type ExcludeType = { + [K in keyof T]: Exclude; +}; + +/** + * Make optional all properties that have the `ExactOptionalTag` type. + * + * ```ts + * type Foo = { a: string | ExactOptionalTag; b: number}; + * type Bar = ExactOptionalize; + * // Bar = { a?: string; b: number} + * ``` + */ +export type ExactOptionalize = OmitBy & + Partial, ExactOptionalTag>>; + +/** + * Infer a type from an superstruct object schema. + */ +export type ObjectType = Simplify< + ExactOptionalize }>> +>; + +/** + * Change the return type of a superstruct object struct to support exact + * optional properties. + * + * @param schema - The object schema. + * @returns A struct representing an object with a known set of properties. + */ +export function object( + schema: S, +): Struct, S> { + return stObject(schema) as any; +} + +/** + * Check if the current property is present in its parent object. + * + * @param ctx - The context to check. + * @returns `true` if the property is present, `false` otherwise. + */ +function hasOptional(ctx: Context): boolean { + const property: string = ctx.path[ctx.path.length - 1]; + const parent: Record = ctx.branch[ctx.branch.length - 2]; + + return property in parent; +} + +/** + * Augment a struct to allow exact-optional values. Exact-optional values can + * be omitted but cannot be `undefined`. + * + * ```ts + * const foo = object({ bar: exactOptional(string()) }); + * type Foo = Infer; + * // Foo = { bar?: string } + * ``` + * + * @param struct - The struct to augment. + * @returns The augmented struct. + */ +export function exactOptional( + struct: Struct, +): Struct { + return new Struct({ + ...struct, + + validator: (value, ctx) => + !hasOptional(ctx) || struct.validator(value, ctx), + + refiner: (value, ctx) => + !hasOptional(ctx) || struct.refiner(value as T, ctx), + }); +} diff --git a/yarn.lock b/yarn.lock index 666e4cf3a..2fb83c901 100644 --- a/yarn.lock +++ b/yarn.lock @@ -809,6 +809,15 @@ __metadata: languageName: node linkType: hard +"@jest/schemas@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/schemas@npm:29.6.3" + dependencies: + "@sinclair/typebox": ^0.27.8 + checksum: 910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 + languageName: node + linkType: hard + "@jest/source-map@npm:^28.1.2": version: 28.1.2 resolution: "@jest/source-map@npm:28.1.2" @@ -1133,7 +1142,7 @@ __metadata: "@metamask/rpc-methods": ^0.38.1-flask.1 "@metamask/snaps-controllers": ^0.38.2-flask.1 "@metamask/snaps-utils": ^0.38.2-flask.1 - "@metamask/utils": ^8.0.0 + "@metamask/utils": ^8.1.0 "@types/jest": ^28.1.6 "@types/node": ^16 "@types/uuid": ^9.0.1 @@ -1156,6 +1165,7 @@ __metadata: superstruct: ^1.0.3 ts-jest: ^28.0.7 ts-node: ^10.7.0 + tsd: ^0.29.0 typedoc: ^0.23.15 typescript: ~4.8.4 uuid: ^9.0.0 @@ -1618,6 +1628,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 + languageName: node + linkType: hard + "@sinonjs/commons@npm:^1.7.0": version: 1.8.6 resolution: "@sinonjs/commons@npm:1.8.6" @@ -1680,6 +1697,13 @@ __metadata: languageName: node linkType: hard +"@tsd/typescript@npm:~5.2.2": + version: 5.2.2 + resolution: "@tsd/typescript@npm:5.2.2" + checksum: b72d6311356a1fabcd78ffeb878a6ba3d51804d02fefdc6cf36ae8957d97b13823b9e396f550e37c2d1b405b6ad0fa190f4ec791bc6d730b02b22e39b33a4c76 + languageName: node + linkType: hard + "@types/babel__core@npm:^7.1.14": version: 7.20.1 resolution: "@types/babel__core@npm:7.20.1" @@ -1746,6 +1770,23 @@ __metadata: languageName: node linkType: hard +"@types/eslint@npm:^7.2.13": + version: 7.29.0 + resolution: "@types/eslint@npm:7.29.0" + dependencies: + "@types/estree": "*" + "@types/json-schema": "*" + checksum: df13991c554954353ce8f3bb03e19da6cc71916889443d68d178d4f858b561ba4cc4a4f291c6eb9eebb7f864b12b9b9313051b3a8dfea3e513dadf3188a77bdf + languageName: node + linkType: hard + +"@types/estree@npm:*": + version: 1.0.1 + resolution: "@types/estree@npm:1.0.1" + checksum: e9aa175eacb797216fafce4d41e8202c7a75555bc55232dee0f9903d7171f8f19f0ae7d5191bb1a88cb90e65468be508c0df850a9fb81b4433b293a5a749899d + languageName: node + linkType: hard + "@types/graceful-fs@npm:^4.1.3": version: 4.1.6 resolution: "@types/graceful-fs@npm:4.1.6" @@ -1790,7 +1831,7 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:^7.0.9": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.9": version: 7.0.12 resolution: "@types/json-schema@npm:7.0.12" checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293 @@ -1811,6 +1852,13 @@ __metadata: languageName: node linkType: hard +"@types/minimist@npm:^1.2.0": + version: 1.2.2 + resolution: "@types/minimist@npm:1.2.2" + checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d + languageName: node + linkType: hard + "@types/ms@npm:*": version: 0.7.31 resolution: "@types/ms@npm:0.7.31" @@ -1832,6 +1880,13 @@ __metadata: languageName: node linkType: hard +"@types/normalize-package-data@npm:^2.4.0": + version: 2.4.1 + resolution: "@types/normalize-package-data@npm:2.4.1" + checksum: e87bccbf11f95035c89a132b52b79ce69a1e3652fe55962363063c9c0dae0fe2477ebc585e03a9652adc6f381d24ba5589cc5e51849df4ced3d3e004a7d40ed5 + languageName: node + linkType: hard + "@types/parse-json@npm:^4.0.0": version: 4.0.0 resolution: "@types/parse-json@npm:4.0.0" @@ -2360,6 +2415,13 @@ __metadata: languageName: node linkType: hard +"arrify@npm:^1.0.1": + version: 1.0.1 + resolution: "arrify@npm:1.0.1" + checksum: 745075dd4a4624ff0225c331dacb99be501a515d39bcb7c84d24660314a6ec28e68131b137e6f7e16318170842ce97538cd298fc4cd6b2cc798e0b957f2747e7 + languageName: node + linkType: hard + "arrify@npm:^2.0.1": version: 2.0.1 resolution: "arrify@npm:2.0.1" @@ -2736,6 +2798,17 @@ __metadata: languageName: node linkType: hard +"camelcase-keys@npm:^6.2.2": + version: 6.2.2 + resolution: "camelcase-keys@npm:6.2.2" + dependencies: + camelcase: ^5.3.1 + map-obj: ^4.0.0 + quick-lru: ^4.0.1 + checksum: 43c9af1adf840471e54c68ab3e5fe8a62719a6b7dbf4e2e86886b7b0ff96112c945736342b837bd2529ec9d1c7d1934e5653318478d98e0cf22c475c04658e2a + languageName: node + linkType: hard + "camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" @@ -2768,7 +2841,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2": +"chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: @@ -3091,6 +3164,23 @@ __metadata: languageName: node linkType: hard +"decamelize-keys@npm:^1.1.0": + version: 1.1.1 + resolution: "decamelize-keys@npm:1.1.1" + dependencies: + decamelize: ^1.1.0 + map-obj: ^1.0.0 + checksum: fc645fe20b7bda2680bbf9481a3477257a7f9304b1691036092b97ab04c0ab53e3bf9fcc2d2ae382536568e402ec41fb11e1d4c3836a9abe2d813dd9ef4311e0 + languageName: node + linkType: hard + +"decamelize@npm:^1.1.0, decamelize@npm:^1.2.0": + version: 1.2.0 + resolution: "decamelize@npm:1.2.0" + checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa + languageName: node + linkType: hard + "dedent@npm:^0.7.0": version: 0.7.0 resolution: "dedent@npm:0.7.0" @@ -3247,6 +3337,13 @@ __metadata: languageName: node linkType: hard +"diff-sequences@npm:^29.6.3": + version: 29.6.3 + resolution: "diff-sequences@npm:29.6.3" + checksum: f4914158e1f2276343d98ff5b31fc004e7304f5470bf0f1adb2ac6955d85a531a6458d33e87667f98f6ae52ebd3891bb47d420bb48a5bd8b7a27ee25b20e33aa + languageName: node + linkType: hard + "diff@npm:^4.0.1": version: 4.0.2 resolution: "diff@npm:4.0.2" @@ -3503,6 +3600,22 @@ __metadata: languageName: node linkType: hard +"eslint-formatter-pretty@npm:^4.1.0": + version: 4.1.0 + resolution: "eslint-formatter-pretty@npm:4.1.0" + dependencies: + "@types/eslint": ^7.2.13 + ansi-escapes: ^4.2.1 + chalk: ^4.1.0 + eslint-rule-docs: ^1.1.5 + log-symbols: ^4.0.0 + plur: ^4.0.0 + string-width: ^4.2.0 + supports-hyperlinks: ^2.0.0 + checksum: e8e0cd3843513fff32a70b036dd349fdab81d73b5e522f23685181c907a1faf2b2ebcae1688dc71d0fc026184011792f7e39b833d349df18fe2baea00d017901 + languageName: node + linkType: hard + "eslint-import-resolver-node@npm:^0.3.7": version: 0.3.7 resolution: "eslint-import-resolver-node@npm:0.3.7" @@ -3639,6 +3752,13 @@ __metadata: languageName: node linkType: hard +"eslint-rule-docs@npm:^1.1.5": + version: 1.1.235 + resolution: "eslint-rule-docs@npm:1.1.235" + checksum: b163596f9a05568e287b2c78f51a280092122a2e43c45fa2c200f0bd3f61877af186c641dab97620978bec96d9e2cfb621e51728044d9efe42ddc24f5a594b26 + languageName: node + linkType: hard + "eslint-scope@npm:^5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" @@ -4313,7 +4433,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.1.0": +"globby@npm:^11.0.1, globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: @@ -4386,6 +4506,13 @@ __metadata: languageName: node linkType: hard +"hard-rejection@npm:^2.1.0": + version: 2.1.0 + resolution: "hard-rejection@npm:2.1.0" + checksum: 7baaf80a0c7fff4ca79687b4060113f1529589852152fa935e6787a2bc96211e784ad4588fb3048136ff8ffc9dfcf3ae385314a5b24db32de20bea0d1597f9dc + languageName: node + linkType: hard + "has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": version: 1.0.2 resolution: "has-bigints@npm:1.0.2" @@ -4487,6 +4614,22 @@ __metadata: languageName: node linkType: hard +"hosted-git-info@npm:^2.1.4": + version: 2.8.9 + resolution: "hosted-git-info@npm:2.8.9" + checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd + languageName: node + linkType: hard + +"hosted-git-info@npm:^4.0.1": + version: 4.1.0 + resolution: "hosted-git-info@npm:4.1.0" + dependencies: + lru-cache: ^6.0.0 + checksum: c3f87b3c2f7eb8c2748c8f49c0c2517c9a95f35d26f4bf54b2a8cba05d2e668f3753548b6ea366b18ec8dadb4e12066e19fa382a01496b0ffa0497eb23cbe461 + languageName: node + linkType: hard + "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" @@ -4671,6 +4814,13 @@ __metadata: languageName: node linkType: hard +"irregular-plurals@npm:^3.2.0": + version: 3.5.0 + resolution: "irregular-plurals@npm:3.5.0" + checksum: 5b663091dc89155df7b2e9d053e8fb11941a0c4be95c4b6549ed3ea020489fdf4f75ea586c915b5b543704252679a5a6e8c6c3587da5ac3fc57b12da90a9aee7 + languageName: node + linkType: hard + "is-array-buffer@npm:^3.0.1, is-array-buffer@npm:^3.0.2": version: 3.0.2 resolution: "is-array-buffer@npm:3.0.2" @@ -4724,12 +4874,12 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.11.0, is-core-module@npm:^2.12.0, is-core-module@npm:^2.12.1, is-core-module@npm:^2.4.0": - version: 2.12.1 - resolution: "is-core-module@npm:2.12.1" +"is-core-module@npm:^2.11.0, is-core-module@npm:^2.12.1, is-core-module@npm:^2.13.0, is-core-module@npm:^2.4.0, is-core-module@npm:^2.5.0": + version: 2.13.0 + resolution: "is-core-module@npm:2.13.0" dependencies: has: ^1.0.3 - checksum: f04ea30533b5e62764e7b2e049d3157dc0abd95ef44275b32489ea2081176ac9746ffb1cdb107445cf1ff0e0dfcad522726ca27c27ece64dadf3795428b8e468 + checksum: 053ab101fb390bfeb2333360fd131387bed54e476b26860dc7f5a700bbf34a0ec4454f7c8c4d43e8a0030957e4b3db6e16d35e1890ea6fb654c833095e040355 languageName: node linkType: hard @@ -4859,6 +5009,13 @@ __metadata: languageName: node linkType: hard +"is-plain-obj@npm:^1.1.0": + version: 1.1.0 + resolution: "is-plain-obj@npm:1.1.0" + checksum: 0ee04807797aad50859652a7467481816cbb57e5cc97d813a7dcd8915da8195dc68c436010bf39d195226cde6a2d352f4b815f16f26b7bf486a5754290629931 + languageName: node + linkType: hard + "is-plain-obj@npm:^4.1.0": version: 4.1.0 resolution: "is-plain-obj@npm:4.1.0" @@ -4939,6 +5096,13 @@ __metadata: languageName: node linkType: hard +"is-unicode-supported@npm:^0.1.0": + version: 0.1.0 + resolution: "is-unicode-supported@npm:0.1.0" + checksum: a2aab86ee7712f5c2f999180daaba5f361bdad1efadc9610ff5b8ab5495b86e4f627839d085c6530363c6d6d4ecbde340fb8e54bdb83da4ba8e0865ed5513c52 + languageName: node + linkType: hard + "is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -5150,6 +5314,18 @@ __metadata: languageName: node linkType: hard +"jest-diff@npm:^29.0.3": + version: 29.6.4 + resolution: "jest-diff@npm:29.6.4" + dependencies: + chalk: ^4.0.0 + diff-sequences: ^29.6.3 + jest-get-type: ^29.6.3 + pretty-format: ^29.6.3 + checksum: e205c45ab6dbcc660dc2a682cddb20f6a3cbbbdecd2821cce2050619f96dbd7560ee25f7f51d42c302596aeaddbea54390b78be3ab639340d24d67e4d270a8b0 + languageName: node + linkType: hard + "jest-docblock@npm:^28.1.1": version: 28.1.1 resolution: "jest-docblock@npm:28.1.1" @@ -5193,6 +5369,13 @@ __metadata: languageName: node linkType: hard +"jest-get-type@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-get-type@npm:29.6.3" + checksum: 88ac9102d4679d768accae29f1e75f592b760b44277df288ad76ce5bf038c3f5ce3719dea8aa0f035dac30e9eb034b848ce716b9183ad7cc222d029f03e92205 + languageName: node + linkType: hard + "jest-haste-map@npm:^28.1.3": version: 28.1.3 resolution: "jest-haste-map@npm:28.1.3" @@ -5635,6 +5818,13 @@ __metadata: languageName: node linkType: hard +"kind-of@npm:^6.0.3": + version: 6.0.3 + resolution: "kind-of@npm:6.0.3" + checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b + languageName: node + linkType: hard + "kleur@npm:^3.0.3": version: 3.0.3 resolution: "kleur@npm:3.0.3" @@ -5705,6 +5895,16 @@ __metadata: languageName: node linkType: hard +"log-symbols@npm:^4.0.0": + version: 4.1.0 + resolution: "log-symbols@npm:4.1.0" + dependencies: + chalk: ^4.1.0 + is-unicode-supported: ^0.1.0 + checksum: fce1497b3135a0198803f9f07464165e9eb83ed02ceb2273930a6f8a508951178d8cf4f0378e9d28300a2ed2bc49050995d2bd5f53ab716bb15ac84d58c6ef74 + languageName: node + linkType: hard + "loose-envify@npm:^1.0.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -5819,6 +6019,20 @@ __metadata: languageName: node linkType: hard +"map-obj@npm:^1.0.0": + version: 1.0.1 + resolution: "map-obj@npm:1.0.1" + checksum: 9949e7baec2a336e63b8d4dc71018c117c3ce6e39d2451ccbfd3b8350c547c4f6af331a4cbe1c83193d7c6b786082b6256bde843db90cb7da2a21e8fcc28afed + languageName: node + linkType: hard + +"map-obj@npm:^4.0.0": + version: 4.3.0 + resolution: "map-obj@npm:4.3.0" + checksum: fbc554934d1a27a1910e842bc87b177b1a556609dd803747c85ece420692380827c6ae94a95cce4407c054fa0964be3bf8226f7f2cb2e9eeee432c7c1985684e + languageName: node + linkType: hard + "marked@npm:^4.2.12": version: 4.3.0 resolution: "marked@npm:4.3.0" @@ -5839,6 +6053,26 @@ __metadata: languageName: node linkType: hard +"meow@npm:^9.0.0": + version: 9.0.0 + resolution: "meow@npm:9.0.0" + dependencies: + "@types/minimist": ^1.2.0 + camelcase-keys: ^6.2.2 + decamelize: ^1.2.0 + decamelize-keys: ^1.1.0 + hard-rejection: ^2.1.0 + minimist-options: 4.1.0 + normalize-package-data: ^3.0.0 + read-pkg-up: ^7.0.1 + redent: ^3.0.0 + trim-newlines: ^3.0.0 + type-fest: ^0.18.0 + yargs-parser: ^20.2.3 + checksum: 99799c47247f4daeee178e3124f6ef6f84bde2ba3f37652865d5d8f8b8adcf9eedfc551dd043e2455cd8206545fd848e269c0c5ab6b594680a0ad4d3617c9639 + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -5884,6 +6118,13 @@ __metadata: languageName: node linkType: hard +"min-indent@npm:^1.0.0": + version: 1.0.1 + resolution: "min-indent@npm:1.0.1" + checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 + languageName: node + linkType: hard + "minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": version: 1.0.1 resolution: "minimalistic-assert@npm:1.0.1" @@ -5925,6 +6166,17 @@ __metadata: languageName: node linkType: hard +"minimist-options@npm:4.1.0": + version: 4.1.0 + resolution: "minimist-options@npm:4.1.0" + dependencies: + arrify: ^1.0.1 + is-plain-obj: ^1.1.0 + kind-of: ^6.0.3 + checksum: 8c040b3068811e79de1140ca2b708d3e203c8003eb9a414c1ab3cd467fc5f17c9ca02a5aef23bedc51a7f8bfbe77f87e9a7e31ec81fba304cda675b019496f4e + languageName: node + linkType: hard + "minimist@npm:^1.2.0, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" @@ -6155,6 +6407,30 @@ __metadata: languageName: node linkType: hard +"normalize-package-data@npm:^2.5.0": + version: 2.5.0 + resolution: "normalize-package-data@npm:2.5.0" + dependencies: + hosted-git-info: ^2.1.4 + resolve: ^1.10.0 + semver: 2 || 3 || 4 || 5 + validate-npm-package-license: ^3.0.1 + checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 + languageName: node + linkType: hard + +"normalize-package-data@npm:^3.0.0": + version: 3.0.3 + resolution: "normalize-package-data@npm:3.0.3" + dependencies: + hosted-git-info: ^4.0.1 + is-core-module: ^2.5.0 + semver: ^7.3.4 + validate-npm-package-license: ^3.0.1 + checksum: bbcee00339e7c26fdbc760f9b66d429258e2ceca41a5df41f5df06cc7652de8d82e8679ff188ca095cad8eff2b6118d7d866af2b68400f74602fbcbce39c160a + languageName: node + linkType: hard + "normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" @@ -6494,6 +6770,15 @@ __metadata: languageName: node linkType: hard +"plur@npm:^4.0.0": + version: 4.0.0 + resolution: "plur@npm:4.0.0" + dependencies: + irregular-plurals: ^3.2.0 + checksum: fea2e903efca67cc5c7a8952fca3db46ae8d9e9353373b406714977e601a5d3b628bcb043c3ad2126c6ff0e73d8020bf43af30a72dd087eff1ec240eb13b90e1 + languageName: node + linkType: hard + "postcss@npm:^8.1.10": version: 8.4.24 resolution: "postcss@npm:8.4.24" @@ -6557,6 +6842,17 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^29.6.3": + version: 29.6.3 + resolution: "pretty-format@npm:29.6.3" + dependencies: + "@jest/schemas": ^29.6.3 + ansi-styles: ^5.0.0 + react-is: ^18.0.0 + checksum: 4e1c0db48e65571c22e80ff92123925ff8b3a2a89b71c3a1683cfde711004d492de32fe60c6bc10eea8bf6c678e5cbe544ac6c56cb8096e1eb7caf856928b1c4 + languageName: node + linkType: hard + "process-nextick-args@npm:~1.0.6": version: 1.0.7 resolution: "process-nextick-args@npm:1.0.7" @@ -6653,6 +6949,13 @@ __metadata: languageName: node linkType: hard +"quick-lru@npm:^4.0.1": + version: 4.0.1 + resolution: "quick-lru@npm:4.0.1" + checksum: bea46e1abfaa07023e047d3cf1716a06172c4947886c053ede5c50321893711577cb6119360f810cc3ffcd70c4d7db4069c3cee876b358ceff8596e062bd1154 + languageName: node + linkType: hard + "randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" @@ -6686,6 +6989,29 @@ __metadata: languageName: node linkType: hard +"read-pkg-up@npm:^7.0.0, read-pkg-up@npm:^7.0.1": + version: 7.0.1 + resolution: "read-pkg-up@npm:7.0.1" + dependencies: + find-up: ^4.1.0 + read-pkg: ^5.2.0 + type-fest: ^0.8.1 + checksum: e4e93ce70e5905b490ca8f883eb9e48b5d3cebc6cd4527c25a0d8f3ae2903bd4121c5ab9c5a3e217ada0141098eeb661313c86fa008524b089b8ed0b7f165e44 + languageName: node + linkType: hard + +"read-pkg@npm:^5.2.0": + version: 5.2.0 + resolution: "read-pkg@npm:5.2.0" + dependencies: + "@types/normalize-package-data": ^2.4.0 + normalize-package-data: ^2.5.0 + parse-json: ^5.0.0 + type-fest: ^0.6.0 + checksum: eb696e60528b29aebe10e499ba93f44991908c57d70f2d26f369e46b8b9afc208ef11b4ba64f67630f31df8b6872129e0a8933c8c53b7b4daf0eace536901222 + languageName: node + linkType: hard + "readable-stream@npm:2.3.3": version: 2.3.3 resolution: "readable-stream@npm:2.3.3" @@ -6745,6 +7071,16 @@ __metadata: languageName: node linkType: hard +"redent@npm:^3.0.0": + version: 3.0.0 + resolution: "redent@npm:3.0.0" + dependencies: + indent-string: ^4.0.0 + strip-indent: ^3.0.0 + checksum: fa1ef20404a2d399235e83cc80bd55a956642e37dd197b4b612ba7327bf87fa32745aeb4a1634b2bab25467164ab4ed9c15be2c307923dd08b0fe7c52431ae6b + languageName: node + linkType: hard + "regexp.prototype.flags@npm:^1.4.3": version: 1.5.0 resolution: "regexp.prototype.flags@npm:1.5.0" @@ -6800,29 +7136,29 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.18.1, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2": - version: 1.22.3 - resolution: "resolve@npm:1.22.3" +"resolve@npm:^1.10.0, resolve@npm:^1.18.1, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2": + version: 1.22.4 + resolution: "resolve@npm:1.22.4" dependencies: - is-core-module: ^2.12.0 + is-core-module: ^2.13.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374 + checksum: 23f25174c2736ce24c6d918910e0d1f89b6b38fefa07a995dff864acd7863d59a7f049e691f93b4b2ee29696303390d921552b6d1b841ed4a8101f517e1d0124 languageName: node linkType: hard -"resolve@patch:resolve@^1.18.1#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.2#~builtin": - version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=07638b" +"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.18.1#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.2#~builtin": + version: 1.22.4 + resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=07638b" dependencies: - is-core-module: ^2.12.0 + is-core-module: ^2.13.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665 + checksum: c45f2545fdc4d21883861b032789e20aa67a2f2692f68da320cc84d5724cd02f2923766c5354b3210897e88f1a7b3d6d2c7c22faeead8eed7078e4c783a444bc languageName: node linkType: hard @@ -6985,7 +7321,16 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.x, semver@npm:^7.0.0, semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4": +"semver@npm:2 || 3 || 4 || 5": + version: 5.7.2 + resolution: "semver@npm:5.7.2" + bin: + semver: bin/semver + checksum: fb4ab5e0dd1c22ce0c937ea390b4a822147a9c53dbd2a9a0132f12fe382902beef4fbf12cf51bb955248d8d15874ce8cd89532569756384f994309825f10b686 + languageName: node + linkType: hard + +"semver@npm:7.x, semver@npm:^7.0.0, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4": version: 7.5.4 resolution: "semver@npm:7.5.4" dependencies: @@ -7189,6 +7534,16 @@ __metadata: languageName: node linkType: hard +"spdx-correct@npm:^3.0.0": + version: 3.2.0 + resolution: "spdx-correct@npm:3.2.0" + dependencies: + spdx-expression-parse: ^3.0.0 + spdx-license-ids: ^3.0.0 + checksum: e9ae98d22f69c88e7aff5b8778dc01c361ef635580e82d29e5c60a6533cc8f4d820803e67d7432581af0cc4fb49973125076ee3b90df191d153e223c004193b2 + languageName: node + linkType: hard + "spdx-exceptions@npm:^2.1.0": version: 2.3.0 resolution: "spdx-exceptions@npm:2.3.0" @@ -7196,7 +7551,7 @@ __metadata: languageName: node linkType: hard -"spdx-expression-parse@npm:^3.0.1": +"spdx-expression-parse@npm:^3.0.0, spdx-expression-parse@npm:^3.0.1": version: 3.0.1 resolution: "spdx-expression-parse@npm:3.0.1" dependencies: @@ -7392,6 +7747,15 @@ __metadata: languageName: node linkType: hard +"strip-indent@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-indent@npm:3.0.0" + dependencies: + min-indent: ^1.0.0 + checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 + languageName: node + linkType: hard + "strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -7562,6 +7926,13 @@ __metadata: languageName: node linkType: hard +"trim-newlines@npm:^3.0.0": + version: 3.0.1 + resolution: "trim-newlines@npm:3.0.1" + checksum: b530f3fadf78e570cf3c761fb74fef655beff6b0f84b29209bac6c9622db75ad1417f4a7b5d54c96605dcd72734ad44526fef9f396807b90839449eb543c6206 + languageName: node + linkType: hard + "ts-jest@npm:^28.0.7": version: 28.0.8 resolution: "ts-jest@npm:28.0.8" @@ -7645,6 +8016,23 @@ __metadata: languageName: node linkType: hard +"tsd@npm:^0.29.0": + version: 0.29.0 + resolution: "tsd@npm:0.29.0" + dependencies: + "@tsd/typescript": ~5.2.2 + eslint-formatter-pretty: ^4.1.0 + globby: ^11.0.1 + jest-diff: ^29.0.3 + meow: ^9.0.0 + path-exists: ^4.0.0 + read-pkg-up: ^7.0.0 + bin: + tsd: dist/cli.js + checksum: 66b5f5f04c46b4c5cea28faba54d7372cdf3126876d968958eb3fb8dab0247ef50a466f10d59c6aea60751c35a518a594a06eecdb5e274cb8d739f804fc62da1 + languageName: node + linkType: hard + "tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" @@ -7686,6 +8074,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^0.18.0": + version: 0.18.1 + resolution: "type-fest@npm:0.18.1" + checksum: e96dcee18abe50ec82dab6cbc4751b3a82046da54c52e3b2d035b3c519732c0b3dd7a2fa9df24efd1a38d953d8d4813c50985f215f1957ee5e4f26b0fe0da395 + languageName: node + linkType: hard + "type-fest@npm:^0.20.2": version: 0.20.2 resolution: "type-fest@npm:0.20.2" @@ -7700,6 +8095,20 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^0.6.0": + version: 0.6.0 + resolution: "type-fest@npm:0.6.0" + checksum: b2188e6e4b21557f6e92960ec496d28a51d68658018cba8b597bd3ef757721d1db309f120ae987abeeda874511d14b776157ff809f23c6d1ce8f83b9b2b7d60f + languageName: node + linkType: hard + +"type-fest@npm:^0.8.1": + version: 0.8.1 + resolution: "type-fest@npm:0.8.1" + checksum: d61c4b2eba24009033ae4500d7d818a94fd6d1b481a8111612ee141400d5f1db46f199c014766b9fa9b31a6a7374d96fc748c6d688a78a3ce5a33123839becb7 + languageName: node + linkType: hard + "typed-array-length@npm:^1.0.4": version: 1.0.4 resolution: "typed-array-length@npm:1.0.4" @@ -7848,6 +8257,16 @@ __metadata: languageName: node linkType: hard +"validate-npm-package-license@npm:^3.0.1": + version: 3.0.4 + resolution: "validate-npm-package-license@npm:3.0.4" + dependencies: + spdx-correct: ^3.0.0 + spdx-expression-parse: ^3.0.0 + checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad + languageName: node + linkType: hard + "validate-npm-package-name@npm:^5.0.0": version: 5.0.0 resolution: "validate-npm-package-name@npm:5.0.0" @@ -8036,7 +8455,7 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^20.2.2": +"yargs-parser@npm:^20.2.2, yargs-parser@npm:^20.2.3": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9" checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3