-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFormula.js
52 lines (47 loc) · 1.42 KB
/
Formula.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
const ctxFn = [ 'Math', 'eval', 'parseInt', 'parseFloat', 'isNaN', 'isFinite' ]
/** Formula class safe eval. Will try to clear context to prevent injection.
* Keep Math formula and ES6 syntax
*/
class Formula {
constructor() {
// Remove unecessary functions
var keys = []
Object.getOwnPropertyNames(window).forEach(k => {
if (ctxFn.indexOf(k) < 0 && k !== 'Math' && /^[a-z,A-Z,$,_]/.test(k)) {
keys.push(k)
}
})
// Code to evaluate formula
var lines = [`
var mainFn = function(e) {
var `+ keys.join(',') +`;
var attr = e.data.attr;
var result;
try { result = eval(e.data.formula); }
catch(e) { result = { error: e.message } }
return result
}
self.addEventListener("message", function(event) {
self.postMessage(mainFn(event));
});`];
this.code_ = URL.createObjectURL(new Blob(lines, { type: 'text/javascript' }));
}
/** Eval formula
* @param {string} formula
* @param {Object} attr list of key/value attribut
* @param {function} cback
*/
eval(formula, attr, cback) {
// Clear attributes
attr = JSON.parse(JSON.stringify(attr || {}))
// Create a worker
const worker = new Worker(this.code_);
worker.addEventListener('message', function (e) {
cback(e.data);
worker.terminate();
}.bind(this));
// Execute
worker.postMessage({ formula, attr })
}
}
export default Formula