Eric Bower
·
23 Feb 24
matcher.ts
1import type { AnyAction } from "./types.ts";
2
3type ActionType = string;
4type GuardPredicate<G extends T, T = unknown> = (arg: T) => arg is G;
5type Predicate<Guard extends AnyAction = AnyAction> = (
6 action: Guard,
7) => boolean;
8type StringableActionCreator<A extends AnyAction = AnyAction> = {
9 (...args: unknown[]): A;
10 toString(): string;
11};
12type SubPattern<Guard extends AnyAction = AnyAction> =
13 | Predicate<Guard>
14 | StringableActionCreator
15 | ActionType;
16export type Pattern = SubPattern | SubPattern[];
17type ActionSubPattern<Guard extends AnyAction = AnyAction> =
18 | GuardPredicate<Guard, AnyAction>
19 | StringableActionCreator<Guard>
20 | Predicate<Guard>
21 | ActionType;
22export type ActionPattern<Guard extends AnyAction = AnyAction> =
23 | ActionSubPattern<Guard>
24 | ActionSubPattern<Guard>[];
25
26export function matcher(pattern: ActionPattern): Predicate {
27 if (pattern === "*") {
28 return function (input) {
29 return !!input;
30 };
31 }
32
33 if (typeof pattern === "string") {
34 return function (input) {
35 return pattern === input.type;
36 };
37 }
38
39 if (Array.isArray(pattern)) {
40 return function (input) {
41 return pattern.some((p) => matcher(p)(input));
42 };
43 }
44
45 if (typeof pattern === "function" && Object.hasOwn(pattern, "toString")) {
46 return function (input) {
47 return pattern.toString() === input.type;
48 };
49 }
50
51 if (typeof pattern === "function") {
52 return function (input) {
53 return pattern(input) as boolean;
54 };
55 }
56
57 throw new Error("invalid pattern");
58}