This repository has been archived by the owner on Jun 30, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
90 lines (83 loc) · 1.91 KB
/
index.js
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
const condMark = {
symbol: {
type: 'condition',
name: '__mark__' + Math.random()
},
add(fn) {
let { name, type } = this.symbol;
let addon = { [name]: type };
return Object.assign((...args) => fn(...args), addon);
},
check(fn) {
if (!fn) return false;
let { name, type } = this.symbol;
return fn[name] === type;
}
}
function getArgTypes(def) {
let args = String(def).match(/\((.+)\) (=>|\{)/) || [];
args = (args[1] || '').split(/, /);
return args.map(arg => {
let type = 'normal';
if (/^\[\s*\]$|^\{\s*\}$/.test(arg)) {
type = 'empty';
}
else if (/^_+$/.test(arg)) {
type = 'any';
}
return {
name: type, value: arg
}
});
}
function toGroup(defs) {
return defs.reduce((group, def, i) => {
let next = defs[i + 1];
condMark.check(def) || group.push({
def: def,
cond: condMark.check(next) ? next : null
});
return group;
}, []);
}
function matchArgs(args, typeList) {
for (let i = 0; i < typeList.length; ++i) {
let type = typeList[i], arg = args[i];
if (type.name === 'empty') {
return (JSON.stringify(arg) === type.value);
}
return true;
}
}
function makeGuard(cond) {
switch (typeof cond) {
case 'function': return cond;
case 'boolean': return () => cond;
default: return () => false;
}
}
function when(cond) {
let guard = makeGuard(cond);
return condMark.add(guard);
}
function match(...defs) {
let groups = toGroup(defs);
let typeList = defs.map(getArgTypes);
return (...args) => {
let argsLength = args.length;
for (let i = 0; i < groups.length; ++i) {
let { def, cond } = groups[i];
if (argsLength !== def.length) {
continue;
}
if (cond && !cond(...args)) {
continue;
}
if (matchArgs(args, typeList[i])) {
return def(...args);
}
}
}
}
exports.when = when;
exports.match = match;