-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.ts
101 lines (82 loc) · 2.55 KB
/
mod.ts
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import { equal } from "https://deno.land/[email protected]/testing/asserts.ts";
import { fnv1a } from "./helpers.ts";
// Match result
type Payload = unknown[];
type Context = unknown;
type Operator = string;
type Unit = [boolean, unknown?];
type Operation = [Operator, ...Payload];
type Match = (input: Operation, context: Context) => Unit;
type Matcher = (payload: Payload, context: Context, match: Match) => Unit;
// Default matchers
export const defaultMatchers: Record<Operator, Matcher> = {
// Equals
"=": ([value], context) => [equal(context, value)],
// Greater than
">": ([value], context) => [(context as number) > (value as number)],
// Less than
"<": ([value], context) => [(context as number) < (value as number)],
// Regex match
"~": (
[value],
context,
) => [new RegExp(value as string, "i").test(context as string)],
// Match opposite condition
"!": ([value], context, match) => [!match(value as Operation, context)[0]],
// Match a property inside the object
".": ([key, value], context, match) =>
match(
value as Operation,
(context as Record<string, Context>)[key as string],
),
// Match percentage
"%": ([namespace, begin, end], context) => {
// Compute the hash
const hash = fnv1a(`${(namespace as string)}|${(context as string)}`) /
2 ** 32;
// Compute availability based on the percentage and hash
return [(begin as number) <= hash && hash < (end as number)];
},
// Value
"@": ([value]) => [true, value],
// Match every condition
"&": (payload, context, match) => {
// Keep the value so we can return it
let matched: Unit = [false];
// Find the value
for (const current of (payload as Operation[])) {
// Look for a value
matched = match(current, context);
// Return only
if (!matched[0]) {
return [false];
}
}
// Everything was succesful
return matched;
},
// Match any condition
"|": (payload, context, match) => {
// Find the value
for (const current of (payload as Operation[])) {
// Look for a value
const matched = match(current, context);
// Return only
if (matched[0]) {
return matched;
}
}
// Nothing was found
return [false];
},
};
// Create a custom match
export const create = (
matchers: Record<Operator, Matcher> = defaultMatchers,
): Match => {
// Match
const match = ([type, ...payload]: Operation, context: Context): Unit =>
matchers[type] ? matchers[type](payload, context, match) : [false];
// Return match
return match;
};