Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 9x 2x 3x 1x 1x 3x 1x 9x 9x 9x 9x 5x 5x 5x 5x 5x 5x 5x 5x 5x 9x 9x 2x 2x 1x 1x 1x 1x 1x 9x 9x 1x 1x 1x 1x 9x 9x 9x 9x 1x 1x 1x 1x 1x 1x 1x | import { P, type Matcher, type Pattern } from "./pattern.ts";
type Cases<R> = readonly (readonly [Matcher<unknown>, (value: unknown) => R])[];
interface MatchBuilder<T, R> {
with<U extends T, V>(
pattern: Matcher<U>,
handler: (value: U) => V,
): MatchBuilder<T, R | V>;
exhaustive(): R;
otherwise(handler: (value: T) => R): R;
}
const buildMatch = <T, R>(value: T, cases: Cases<R>): MatchBuilder<T, R> => {
const apply = (): R | undefined => {
for (const [matcher, handler] of cases) {
if (matcher.matches(value)) {
return handler(value);
}
}
return undefined;
};
const builder = {
with<U extends T, V>(
pattern: Matcher<U>,
handler: (value: U) => V,
): MatchBuilder<T, R | V> {
const nextCases: Cases<R | V> = [
...cases,
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
[pattern, handler as (value: unknown) => R | V],
];
return buildMatch(value, nextCases);
},
exhaustive(): R {
const result = apply();
if (result === undefined) {
throw new Error(
"tiny-pattern-ts: match.exhaustive() called with no matching case",
);
}
return result;
},
otherwise(handler: (value: T) => R): R {
for (const [matcher, run] of cases) {
if (matcher.matches(value)) {
return run(value);
}
}
return handler(value);
},
};
return builder;
};
export const match = <T>(value: T): MatchBuilder<T, never> =>
buildMatch<T, never>(value, []);
export type { Matcher, Pattern };
export { P };
|