ts-pattern
Advanced tools
Comparing version 0.2.0 to 0.2.1
@@ -1,118 +0,8 @@ | ||
import { ValueOf, LeastUpperBound, ExcludeIfContainsNever, UnionToIntersection } from './types/helpers'; | ||
import { Pattern, __, when, not, select } from './types/Pattern'; | ||
import { Match } from './types/Match'; | ||
/** | ||
* # Pattern matching | ||
**/ | ||
declare enum PatternType { | ||
String = "@match/string", | ||
Number = "@match/number", | ||
Boolean = "@match/boolean", | ||
Guard = "@match/guard", | ||
Not = "@match/not", | ||
Select = "@match/select" | ||
} | ||
export { Pattern, __, when, not, select }; | ||
/** | ||
* ### Catch All wildcard | ||
* `__` is wildcard pattern, matching **any value**. | ||
* | ||
* `__.string` is wildcard pattern matching any **string**. | ||
* | ||
* `__.number` is wildcard pattern matching any **number**. | ||
* | ||
* `__.boolean` is wildcard pattern matching any **boolean**. | ||
* @example | ||
* match(value) | ||
* .with(__, () => 'will always match') | ||
* .with(__.string, () => 'will match on strings only') | ||
* .with(__.number, () => 'will match on numbers only') | ||
* .with(__.boolean, () => 'will match on booleans only') | ||
*/ | ||
export declare const __: { | ||
readonly string: PatternType.String; | ||
readonly number: PatternType.Number; | ||
readonly boolean: PatternType.Boolean; | ||
}; | ||
/** type alias for the catch all string */ | ||
declare type __ = typeof __; | ||
declare type Primitives = number | boolean | string | undefined | null | symbol | bigint; | ||
/** | ||
* GuardValue returns the value guarded by a type guard function. | ||
*/ | ||
declare type GuardValue<F> = F extends (value: any) => value is infer b ? b : F extends (value: infer a) => unknown ? a : never; | ||
declare type GuardFunction<a> = (value: a) => unknown; | ||
declare type GuardPattern<a> = { | ||
__patternKind: PatternType.Guard; | ||
__when: GuardFunction<a>; | ||
}; | ||
declare type NotPattern<a> = { | ||
__patternKind: PatternType.Not; | ||
__pattern: Pattern<a>; | ||
}; | ||
declare type SelectPattern<k extends string> = { | ||
__patternKind: PatternType.Select; | ||
__key: k; | ||
}; | ||
declare type SpecialPattern<a> = a extends number ? typeof __.number | __ : a extends string ? typeof __.string | __ : a extends boolean ? typeof __.boolean | __ : __; | ||
/** | ||
* ### Pattern | ||
* Patterns can be any (nested) javascript value. | ||
* They can also be "wildcards", using type constructors | ||
*/ | ||
export declare type Pattern<a> = SelectPattern<string> | GuardPattern<a> | NotPattern<a | any> | SpecialPattern<a> | (a extends Primitives ? a : a extends [infer b, infer c, infer d, infer e, infer f] ? [Pattern<b>, Pattern<c>, Pattern<d>, Pattern<e>, Pattern<f>] : a extends [infer b, infer c, infer d, infer e] ? [Pattern<b>, Pattern<c>, Pattern<d>, Pattern<e>] : a extends [infer b, infer c, infer d] ? [Pattern<b>, Pattern<c>, Pattern<d>] : a extends [infer b, infer c] ? [Pattern<b>, Pattern<c>] : a extends (infer b)[] ? Pattern<b>[] : a extends Map<infer k, infer v> ? Map<k, Pattern<v>> : a extends Set<infer v> ? Set<Pattern<v>> : a extends object ? { | ||
[k in keyof a]?: Pattern<a[k]>; | ||
} : a); | ||
/** | ||
* ### InvertPattern | ||
* Since patterns have special wildcard values, we need a way | ||
* to transform a pattern into the type of value it represents | ||
*/ | ||
declare type InvertPattern<p> = p extends typeof __.number ? number : p extends typeof __.string ? string : p extends typeof __.boolean ? boolean : p extends SelectPattern<string> ? __ : p extends __ ? __ : p extends GuardPattern<infer pb> ? GuardValue<p['__when']> : p extends NotPattern<infer pb> ? { | ||
valueKind: PatternType.Not; | ||
value: InvertPattern<pb>; | ||
} : p extends Primitives ? p : p extends [infer pb, infer pc, infer pd, infer pe, infer pf] ? [InvertPattern<pb>, InvertPattern<pc>, InvertPattern<pd>, InvertPattern<pe>, InvertPattern<pf>] : p extends [infer pb, infer pc, infer pd, infer pe] ? [InvertPattern<pb>, InvertPattern<pc>, InvertPattern<pd>, InvertPattern<pe>] : p extends [infer pb, infer pc, infer pd] ? [InvertPattern<pb>, InvertPattern<pc>, InvertPattern<pd>] : p extends [infer pb, infer pc] ? [InvertPattern<pb>, InvertPattern<pc>] : p extends (infer pp)[] ? InvertPattern<pp>[] : p extends Map<infer pk, infer pv> ? Map<pk, InvertPattern<pv>> : p extends Set<infer pv> ? Set<InvertPattern<pv>> : p extends object ? { | ||
[k in keyof p]: InvertPattern<p[k]>; | ||
} : p; | ||
declare type ExtractMostPreciseValue<a, b> = b extends [] ? [] : [a, b] extends [[infer a1, infer a2, infer a3, infer a4, infer a5] | infer otherBranches, [infer b1, infer b2, infer b3, infer b4, infer b5]] ? [ExtractMostPreciseValue<a1, b1>, ExtractMostPreciseValue<a2, b2>, ExtractMostPreciseValue<a3, b3>, ExtractMostPreciseValue<a4, b4>, ExtractMostPreciseValue<a5, b5>] : [a, b] extends [[infer a1, infer a2, infer a3, infer a4] | infer otherBranches, [infer b1, infer b2, infer b3, infer b4]] ? [ExtractMostPreciseValue<a1, b1>, ExtractMostPreciseValue<a2, b2>, ExtractMostPreciseValue<a3, b3>, ExtractMostPreciseValue<a4, b4>] : [a, b] extends [[infer a1, infer a2, infer a3] | infer otherBranches, [infer b1, infer b2, infer b3]] ? [ExtractMostPreciseValue<a1, b1>, ExtractMostPreciseValue<a2, b2>, ExtractMostPreciseValue<a3, b3>] : [a, b] extends [[infer a1, infer a2] | infer otherBranches, [infer b1, infer b2]] ? [ExtractMostPreciseValue<a1, b1>, ExtractMostPreciseValue<a2, b2>] : [a, b] extends [(infer a1)[], (infer b1)[]] ? ExtractMostPreciseValue<a1, b1>[] : [a, b] extends [Map<infer ak, infer av>, Map<infer bk, infer bv>] ? Map<ExtractMostPreciseValue<ak, bk>, ExtractMostPreciseValue<av, bv>> : [a, b] extends [Set<infer av>, Set<infer bv>] ? Set<ExtractMostPreciseValue<av, bv>> : b extends __ ? a : b extends { | ||
valueKind: PatternType.Not; | ||
value: infer b1; | ||
} ? Exclude<a, b1> : b extends object ? ObjectExtractMostPreciseValue<a, b> : LeastUpperBound<a, b>; | ||
declare type ObjectExtractMostPreciseValue<a, b> = b extends a ? b : a extends b ? a : ExcludeIfContainsNever<{ | ||
[k in keyof Required<a>]: k extends keyof b ? ExtractMostPreciseValue<a[k], b[k]> : a[k]; | ||
}>; | ||
declare type MatchedValue<a, p extends Pattern<a>> = ExtractMostPreciseValue<a, InvertPattern<p>> extends never ? a : ExtractMostPreciseValue<a, InvertPattern<p>>; | ||
declare type FindSelected<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected1<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected1<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected2<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected2<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected3<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected3<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected4<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected4<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected5<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected5<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : never; | ||
declare type ToHandler<a, b, c> = (value: a, selections: UnionToIntersection<FindSelected<a, b>>) => c; | ||
declare type PatternHandler<a, b extends Pattern<a>, c> = ToHandler<MatchedValue<a, b>, b, c>; | ||
export declare const when: <a>(predicate: GuardFunction<a>) => GuardPattern<a>; | ||
export declare const not: <a>(pattern: Pattern<a>) => NotPattern<a>; | ||
export declare const select: <k extends string>(key: k) => SelectPattern<k>; | ||
declare type Unset = '@match/unset'; | ||
declare type PickReturnValue<a, b> = a extends Unset ? b : a; | ||
/** | ||
* ### match | ||
@@ -123,39 +13,1 @@ * Entry point to create pattern matching code branches. It returns an | ||
export declare const match: <a, b = "@match/unset">(value: a) => Match<a, b>; | ||
/** | ||
* ### Match | ||
* An interface to create a pattern matching close. | ||
*/ | ||
declare type Match<a, b> = { | ||
/** | ||
* ### Match.with | ||
* If the data matches the pattern provided as first argument, | ||
* use this branch and execute the handler function. | ||
**/ | ||
with: <p extends Pattern<a>, c>(pattern: p, handler: PatternHandler<a, p, PickReturnValue<b, c>>) => Match<a, PickReturnValue<b, c>>; | ||
/** | ||
* ### Match.when | ||
* When the first function returns a truthy value, | ||
* use this branch and execute the handler function. | ||
**/ | ||
when: <p extends (value: a) => unknown, c>(predicate: p, handler: (value: GuardValue<p>) => PickReturnValue<b, c>) => Match<a, PickReturnValue<b, c>>; | ||
/** | ||
* ### Match.withWhen | ||
* When the data matches the pattern provided as first argument, | ||
* and the predicate function provided as second argument returns a truthy value, | ||
* use this branch and execute the handler function. | ||
**/ | ||
withWhen: <pat extends Pattern<a>, pred extends (value: MatchedValue<a, pat>) => unknown, c>(pattern: pat, predicate: pred, handler: (value: GuardValue<pred>) => PickReturnValue<b, c>) => Match<a, PickReturnValue<b, c>>; | ||
/** | ||
* ### Match.otherwise | ||
* Catch-all branch. | ||
* | ||
* Equivalent to `.with(__)` | ||
**/ | ||
otherwise: <c>(handler: () => PickReturnValue<b, c>) => Match<a, PickReturnValue<b, c>>; | ||
/** | ||
* ### Match.run | ||
* Runs the pattern matching and return a value. | ||
* */ | ||
run: () => b; | ||
}; | ||
export {}; |
128
lib/index.js
@@ -24,48 +24,8 @@ "use strict"; | ||
exports.match = exports.select = exports.not = exports.when = exports.__ = void 0; | ||
var Pattern_1 = require("./types/Pattern"); | ||
exports.__ = Pattern_1.__; | ||
exports.when = Pattern_1.when; | ||
exports.not = Pattern_1.not; | ||
exports.select = Pattern_1.select; | ||
/** | ||
* # Pattern matching | ||
**/ | ||
var PatternType; | ||
(function (PatternType) { | ||
PatternType["String"] = "@match/string"; | ||
PatternType["Number"] = "@match/number"; | ||
PatternType["Boolean"] = "@match/boolean"; | ||
PatternType["Guard"] = "@match/guard"; | ||
PatternType["Not"] = "@match/not"; | ||
PatternType["Select"] = "@match/select"; | ||
})(PatternType || (PatternType = {})); | ||
/** | ||
* ### Catch All wildcard | ||
* `__` is wildcard pattern, matching **any value**. | ||
* | ||
* `__.string` is wildcard pattern matching any **string**. | ||
* | ||
* `__.number` is wildcard pattern matching any **number**. | ||
* | ||
* `__.boolean` is wildcard pattern matching any **boolean**. | ||
* @example | ||
* match(value) | ||
* .with(__, () => 'will always match') | ||
* .with(__.string, () => 'will match on strings only') | ||
* .with(__.number, () => 'will match on numbers only') | ||
* .with(__.boolean, () => 'will match on booleans only') | ||
*/ | ||
exports.__ = { | ||
string: PatternType.String, | ||
number: PatternType.Number, | ||
boolean: PatternType.Boolean | ||
}; | ||
exports.when = function (predicate) { return ({ | ||
__patternKind: PatternType.Guard, | ||
__when: predicate | ||
}); }; | ||
exports.not = function (pattern) { return ({ | ||
__patternKind: PatternType.Not, | ||
__pattern: pattern | ||
}); }; | ||
exports.select = function (key) { return ({ | ||
__patternKind: PatternType.Select, | ||
__key: key | ||
}); }; | ||
/** | ||
* ### match | ||
@@ -86,6 +46,16 @@ * Entry point to create pattern matching code branches. It returns an | ||
var builder = function (value, patterns) { return ({ | ||
"with": function (pattern, handler) { | ||
"with": function (pattern) { | ||
var args = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
args[_i - 1] = arguments[_i]; | ||
} | ||
var handler = args[args.length - 1]; | ||
var predicates = args.slice(0, -1); | ||
var doesMatch = function (value) { | ||
return Boolean(matchPattern(pattern)(value) && | ||
predicates.every(function (predicate) { return predicate(value); })); | ||
}; | ||
return builder(value, __spread(patterns, [ | ||
{ | ||
test: matchPattern(pattern), | ||
test: doesMatch, | ||
handler: handler, | ||
@@ -105,18 +75,6 @@ select: selectWithPattern(pattern) | ||
}, | ||
withWhen: function (pattern, predicate, handler) { | ||
var doesMatch = function (value) { | ||
return Boolean(matchPattern(pattern)(value) && predicate(value)); | ||
}; | ||
return builder(value, __spread(patterns, [ | ||
{ | ||
test: doesMatch, | ||
handler: handler, | ||
select: function () { return ({}); } | ||
}, | ||
])); | ||
}, | ||
otherwise: function (handler) { | ||
return builder(value, __spread(patterns, [ | ||
{ | ||
test: matchPattern(exports.__), | ||
test: matchPattern(Pattern_1.__), | ||
handler: handler, | ||
@@ -144,3 +102,3 @@ select: function () { return ({}); } | ||
return (pattern && | ||
pattern.__patternKind === PatternType.Guard && | ||
pattern.__patternKind === Pattern_1.PatternType.Guard && | ||
typeof pattern.__when === 'function'); | ||
@@ -150,17 +108,20 @@ }; | ||
var pattern = x; | ||
return pattern && pattern.__patternKind === PatternType.Not; | ||
return pattern && pattern.__patternKind === Pattern_1.PatternType.Not; | ||
}; | ||
var isSelectPattern = function (x) { | ||
var pattern = x; | ||
return pattern && pattern.__patternKind === PatternType.Select; | ||
return pattern && pattern.__patternKind === Pattern_1.PatternType.Select; | ||
}; | ||
var isListPattern = function (x) { | ||
return Array.isArray(x) && x.length === 1; | ||
}; | ||
// tells us if the value matches a given pattern. | ||
var matchPattern = function (pattern) { return function (value) { | ||
if (pattern === exports.__ || isSelectPattern(pattern)) | ||
if (pattern === Pattern_1.__ || isSelectPattern(pattern)) | ||
return true; | ||
if (pattern === exports.__.string) | ||
if (pattern === Pattern_1.__.string) | ||
return typeof value === 'string'; | ||
if (pattern === exports.__.boolean) | ||
if (pattern === Pattern_1.__.boolean) | ||
return typeof value === 'boolean'; | ||
if (pattern === exports.__.number) { | ||
if (pattern === Pattern_1.__.number) { | ||
return typeof value === 'number' && !Number.isNaN(value); | ||
@@ -172,12 +133,10 @@ } | ||
return !matchPattern(pattern.__pattern)(value); | ||
if (isListPattern(pattern) && Array.isArray(value)) | ||
return value.every(function (v) { return matchPattern(pattern[0])(v); }); | ||
if (typeof pattern !== typeof value) | ||
return false; | ||
if (Array.isArray(pattern) && Array.isArray(value)) { | ||
return pattern.length === 1 | ||
? value.every(function (v) { return matchPattern(pattern[0])(v); }) | ||
: pattern.length === value.length | ||
? value.every(function (v, i) { | ||
return pattern[i] ? matchPattern(pattern[i])(v) : false; | ||
}) | ||
: false; | ||
return pattern.length === value.length | ||
? pattern.every(function (subPattern, i) { return matchPattern(subPattern)(value[i]); }) | ||
: false; | ||
} | ||
@@ -196,3 +155,3 @@ if (value instanceof Map && pattern instanceof Map) { | ||
? patternValues.every(function (subPattern) { | ||
return Object.values(exports.__).includes(subPattern) | ||
return Object.values(Pattern_1.__).includes(subPattern) | ||
? matchPattern([subPattern])(allValues_1) | ||
@@ -215,8 +174,17 @@ : value.has(subPattern); | ||
return _a = {}, _a[pattern.__key] = value, _a; | ||
if (isListPattern(pattern) && Array.isArray(value)) | ||
return value | ||
.map(function (v) { return selectWithPattern(pattern[0])(v); }) | ||
.reduce(function (acc, selections) { | ||
return Object.keys(selections).reduce(function (acc, key) { | ||
acc[key] = (acc[key] || []).concat([selections[key]]); | ||
return acc; | ||
}, acc); | ||
}, {}); | ||
if (Array.isArray(pattern) && Array.isArray(value)) | ||
return pattern.length === 1 | ||
? value.reduce(function (acc, v) { return Object.assign(acc, selectWithPattern(pattern[0])(v)); }, {}) | ||
: pattern.length === value.length | ||
? value.reduce(function (acc, v, i) { return Object.assign(acc, selectWithPattern(pattern[i])(v)); }, {}) | ||
: {}; | ||
return pattern.length <= value.length | ||
? pattern.reduce(function (acc, subPattern, i) { | ||
return Object.assign(acc, selectWithPattern(subPattern)(value[i])); | ||
}, {}) | ||
: {}; | ||
if (isObject(pattern) && isObject(value)) | ||
@@ -223,0 +191,0 @@ return Object.keys(pattern).reduce(function (acc, k) { |
{ | ||
"name": "ts-pattern", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "Typescript pattern matching library", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24215
14
436
1