diff --git a/package-lock.json b/package-lock.json index 16cfebb..a112ee6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "tiny-pattern-ts", "version": "0.1.8", "license": "MIT", + "dependencies": { + "type-fest": "^5.9.0" + }, "devDependencies": { "@arethetypeswrong/cli": "^0.18.5", "@runwisp/pubv": "^1.5.1", @@ -4622,6 +4625,18 @@ "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/test-exclude": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", @@ -4705,6 +4720,21 @@ "license": "0BSD", "optional": true }, + "node_modules/type-fest": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.9.0.tgz", + "integrity": "sha512-yANm3Jr3GiJ1qgJlxGAVxTOIcEOk1rhQHamlXtnrCK7EHP4HeM9OGxtMg/W7HFdrVzw/ZWJKGVIJusVH85sLtw==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", diff --git a/package.json b/package.json index b68565c..16be35b 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,9 @@ "setup": "npm run setup:git-commit-message", "setup:git-commit-message": "git config commit.template commit-message-template" }, + "dependencies": { + "type-fest": "^5.9.0" + }, "devDependencies": { "@arethetypeswrong/cli": "^0.18.5", "@runwisp/pubv": "^1.5.1", diff --git a/src/primitive.ts b/src/primitive.ts new file mode 100644 index 0000000..04d411b --- /dev/null +++ b/src/primitive.ts @@ -0,0 +1,61 @@ +import type { Simplify, ValueOf } from "type-fest"; + +type UnaryFn = (shape: T) => R; + +// ============================================================================ +// ✔️ Exhaustive +// ❌ ReturnsStrict +// ============================================================================ +type PatternPrimitiveUnion = { + [K in T]: UnaryFn; +}; + +type PatternReturns< + P extends Record>, +> = ReturnType>; + +export const getPrimitiveUnionMatcherW: () => < + P extends PatternPrimitiveUnion, +>( + pattern: Simplify

, +) => UnaryFn> = () => (pattern) => (shape) => + // oxlint-disable-next-line typescript/no-explicit-any typescript/no-unsafe-type-assertion + (pattern[shape] as any)(shape); + +// ============================================================================ +// ✔️ Exhaustive +// ✔️ ReturnsStrict +// ============================================================================ +export const getPrimitiveUnionMatcher: () => ( + pattern: Simplify>, +) => UnaryFn = getPrimitiveUnionMatcherW; + +// ============================================================================ +// ❌ Exhaustive +// ✔️ ReturnsStrict +// ============================================================================ +type PatternPrimitiveUnionPartial = + | PatternPrimitiveUnion + | (Partial> & { + _: UnaryFn; + }); + +export const getPrimitiveUnionMatcherPartial: () => < + R, +>( + pattern: Simplify>, +) => UnaryFn = () => (pattern) => (shape) => + // oxlint-disable-next-line typescript/no-explicit-any typescript/no-unsafe-type-assertion + (pattern[shape] ?? (pattern as any)["_"])(shape); + +// ============================================================================ +// ❌ Exhaustive +// ❌ ReturnsStrict +// ============================================================================ +export const getPrimitiveUnionMatcherPartialW: < + T extends string | number, +>() =>

>( + pattern: Simplify

, + + // oxlint-disable-next-line typescript/no-explicit-any typescript/no-unsafe-type-assertion +) => UnaryFn> = getPrimitiveUnionMatcherPartial as any;