-
Notifications
You must be signed in to change notification settings - Fork 0
/
expressions.js
101 lines (78 loc) · 2.72 KB
/
expressions.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
91
92
93
94
95
96
97
98
99
100
101
var slice = Array.prototype.slice;
var strings = require('./strings');
var formatterParser = require('./formatters');
var propertyChains = require('./property-chains');
var valueProperty = '_value_';
var cache = {};
exports.globals = {};
exports.parse = function(expr, globals, formatters) {
if (typeof expr !== 'string') {
throw new TypeError('Invalid expr, must be type String');
}
var extraArgs = slice.call(arguments, 3);
var cacheKey = expr + '|' + extraArgs.join(',');
// Returns the cached function for this expression if it exists.
var func = cache[cacheKey];
if (func) {
return func;
}
var original = expr;
var isSetter = (extraArgs[0] === valueProperty);
expr = strings.pullOutStrings(expr);
expr = formatterParser.parseFormatters(expr);
expr = propertyChains.parseExpression(expr, getVariables(globals, extraArgs));
if (!isSetter) {
var lines = expr.split('\n');
lines[lines.length - 1] = 'return ' + lines[lines.length - 1];
expr = lines.join('\n');
}
expr = strings.putInStrings(expr);
func = compileExpression(original, expr, globals, formatters, extraArgs);
func.expr = expr;
cache[cacheKey] = func;
return func;
};
exports.parseSetter = function(expr, globals, formatters, extraArgs) {
var extraArgs = slice.call(arguments, 3);
if (expr.charAt(0) === '!') {
// Allow '!prop' to become 'prop = !value'
expr = expr.slice(1).replace(/(\s*\||$)/, ' = !_value_$1');
} else {
expr = expr.replace(/(\s*\||$)/, ' = _value_$1');
}
// Add _value_ as the first extra argument
return exports.parse.apply(exports, [expr, globals, formatters, valueProperty].concat(extraArgs));
};
function getVariables(globals, extraArgs) {
var variables = {};
Object.keys(exports.globals).forEach(function(key) {
variables[key] = exports.globals[key];
});
if (globals) {
Object.keys(globals).forEach(function(key) {
variables[key] = globals[key];
});
}
extraArgs.forEach(function(key) {
variables[key] = null;
});
return variables;
}
function compileExpression(original, expr, globals, formatters, extraArgs) {
var func, args = ['_globals_', '_formatters_'].concat(extraArgs).concat(expr);
try {
func = Function.apply(null, args);
} catch (e) {
// Throws an error if the expression was not valid JavaScript
throw new Error('Bad expression: ' + original + '\n' + 'Compiled expression:\n' + expr + '\n' + e.message);
}
return bindArguments(func, globals, formatters);
}
// a custom "bind" function to bind arguments to a function without binding the context
function bindArguments(func) {
function binder() {
return func.apply(this, args.concat(slice.call(arguments)));
}
var args = slice.call(arguments, 1);
return binder;
}