/
enforce.js
85 lines (70 loc) · 2.18 KB
/
enforce.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
import compounds from 'compounds';
import { RUN_RULE } from 'enforceKeywords';
import runner from 'enforceRunner';
import isRule from 'isRule';
import proxySupported from 'proxySupported';
import rules from 'rules';
const rulesObject = Object.assign(rules(), compounds);
let rulesList = proxySupported() ? null : Object.keys(rulesObject);
const Enforce = value => {
const target = proxySupported() ? enforce : {};
const proxy = genRuleProxy(target, ruleName => (...args) => {
runner(rulesObject[ruleName], value, args);
return proxy;
});
return proxy;
};
const enforce = genRuleProxy(Enforce, bindLazyRule);
enforce.extend = customRules => {
Object.assign(rulesObject, customRules);
if (!proxySupported()) {
rulesList = Object.keys(rulesObject);
genRuleProxy(Enforce, bindLazyRule);
}
return enforce;
};
export default enforce;
// Creates a proxy object that has access to all the rules
function genRuleProxy(target, output) {
if (proxySupported()) {
return new Proxy(target, {
get: (target, fnName) => {
if (!isRule(rulesObject, fnName)) {
return target[fnName];
}
return output(fnName);
},
});
} else {
/**
* This method is REALLY not recommended as it is slow and iterates over
* all the rules for each direct enforce reference. We only use it as a
* lightweight alternative for the much faster proxy interface
*/
return rulesList.reduce((target, fnName) => {
return Object.defineProperties(target, {
[fnName]: { get: () => output(fnName), configurable: true },
});
}, target);
}
}
// Initiates a chain of functions directly from the `enforce`
// function - that's even though we do not have any closure
// there to store that data.
function bindLazyRule(ruleName) {
const registeredRules = [];
const addFn = fnName => (...args) => {
registeredRules.push(
Object.defineProperty(
value => rulesObject[fnName](value, ...args),
'name',
{ value: fnName }
)
);
const returnvalue = genRuleProxy({}, addFn);
return Object.assign(returnvalue, {
[RUN_RULE]: registeredRules,
});
};
return addFn(ruleName);
}