@jbrowse/jexl 2.3.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/LICENSE.txt +1 -0
- package/README.md +77 -85
- package/dist/Expression.d.ts +2 -12
- package/dist/Expression.js +5 -27
- package/dist/Expression.js.map +1 -1
- package/dist/Jexl.d.ts +6 -40
- package/dist/Jexl.js +7 -49
- package/dist/Jexl.js.map +1 -1
- package/dist/Lexer.js +3 -1
- package/dist/Lexer.js.map +1 -1
- package/dist/evaluator/Evaluator.d.ts +14 -55
- package/dist/evaluator/Evaluator.js +14 -73
- package/dist/evaluator/Evaluator.js.map +1 -1
- package/dist/evaluator/handlers.d.ts +19 -18
- package/dist/evaluator/handlers.js +54 -62
- package/dist/evaluator/handlers.js.map +1 -1
- package/dist/grammar.d.ts +3 -4
- package/dist/grammar.js +16 -39
- package/dist/grammar.js.map +1 -1
- package/dist/parser/Parser.js +16 -3
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/states.js +7 -3
- package/dist/parser/states.js.map +1 -1
- package/esm/Expression.d.ts +2 -12
- package/esm/Expression.js +5 -27
- package/esm/Expression.js.map +1 -1
- package/esm/Jexl.d.ts +6 -40
- package/esm/Jexl.js +7 -49
- package/esm/Jexl.js.map +1 -1
- package/esm/Lexer.js +3 -1
- package/esm/Lexer.js.map +1 -1
- package/esm/evaluator/Evaluator.d.ts +14 -55
- package/esm/evaluator/Evaluator.js +14 -73
- package/esm/evaluator/Evaluator.js.map +1 -1
- package/esm/evaluator/handlers.d.ts +19 -18
- package/esm/evaluator/handlers.js +54 -62
- package/esm/evaluator/handlers.js.map +1 -1
- package/esm/grammar.d.ts +3 -4
- package/esm/grammar.js +16 -39
- package/esm/grammar.js.map +1 -1
- package/esm/parser/Parser.js +16 -3
- package/esm/parser/Parser.js.map +1 -1
- package/esm/parser/states.js +7 -3
- package/esm/parser/states.js.map +1 -1
- package/package.json +10 -8
- package/src/Expression.ts +5 -36
- package/src/Jexl.ts +7 -54
- package/src/Lexer.ts +3 -1
- package/src/evaluator/Evaluator.ts +14 -92
- package/src/evaluator/handlers.ts +54 -68
- package/src/grammar.ts +17 -38
- package/src/parser/Parser.ts +13 -3
- package/src/parser/states.ts +7 -3
- package/src/types.ts +4 -1
- package/dist/PromiseSync.d.ts +0 -13
- package/dist/PromiseSync.js +0 -80
- package/dist/PromiseSync.js.map +0 -1
- package/esm/PromiseSync.d.ts +0 -13
- package/esm/PromiseSync.js +0 -78
- package/esm/PromiseSync.js.map +0 -1
- package/src/PromiseSync.ts +0 -86
|
@@ -3,7 +3,6 @@ interface Grammar {
|
|
|
3
3
|
elements: Record<string, any>;
|
|
4
4
|
[key: string]: any;
|
|
5
5
|
}
|
|
6
|
-
type PromiseConstructor = typeof Promise | any;
|
|
7
6
|
/**
|
|
8
7
|
* The Evaluator takes a Jexl expression tree as generated by the
|
|
9
8
|
* {@link Parser} and calculates its value within a given context. The
|
|
@@ -15,78 +14,38 @@ type PromiseConstructor = typeof Promise | any;
|
|
|
15
14
|
* @param {{}} grammar A grammar object against which to evaluate the expression
|
|
16
15
|
* tree
|
|
17
16
|
* @param {{}} [context] A map of variable keys to their values. This will be
|
|
18
|
-
* accessed to resolve the value of each non-relative identifier.
|
|
19
|
-
* Promise values will be passed to the expression as their resolved
|
|
20
|
-
* value.
|
|
17
|
+
* accessed to resolve the value of each non-relative identifier.
|
|
21
18
|
* @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
|
|
22
19
|
* to resolve the value of a relative identifier.
|
|
23
|
-
* @param {function} promise A constructor for the Promise class to be used;
|
|
24
|
-
* probably either Promise or PromiseSync.
|
|
25
20
|
*/
|
|
26
21
|
declare class Evaluator {
|
|
27
22
|
_grammar: Grammar;
|
|
28
23
|
_context: any;
|
|
29
24
|
_relContext: any;
|
|
30
|
-
|
|
31
|
-
constructor(grammar: Grammar, context?: any, relativeContext?: any, promise?: PromiseConstructor);
|
|
25
|
+
constructor(grammar: Grammar, context?: any, relativeContext?: any);
|
|
32
26
|
/**
|
|
33
27
|
* Evaluates an expression tree within the configured context.
|
|
34
28
|
* @param {{}} ast An expression tree object
|
|
35
|
-
* @returns {
|
|
29
|
+
* @returns {*} the resulting value of the expression.
|
|
36
30
|
*/
|
|
37
31
|
eval(ast: AstNode): any;
|
|
38
32
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
33
|
+
* Evaluates each expression within an array, and delivers the response as an
|
|
34
|
+
* array with the resulting values at the same indexes as their originating
|
|
35
|
+
* expressions.
|
|
42
36
|
* @param {Array<string>} arr An array of expression strings to be evaluated
|
|
43
|
-
* @returns {
|
|
37
|
+
* @returns {Array<{}>} the result array
|
|
44
38
|
*/
|
|
45
|
-
evalArray(arr: AstNode[]): any;
|
|
39
|
+
evalArray(arr: AstNode[]): any[];
|
|
46
40
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* as their value.
|
|
41
|
+
* Evaluates each expression within a map, and delivers the response as a map
|
|
42
|
+
* with the same keys, but with the evaluated result for each as their value.
|
|
50
43
|
* @param {{}} map A map of expression names to expression trees to be
|
|
51
44
|
* evaluated
|
|
52
|
-
* @returns {
|
|
45
|
+
* @returns {{}} the result map.
|
|
53
46
|
*/
|
|
54
|
-
evalMap(map: Record<string, AstNode>):
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* The intent is for the subject to be an array of subjects that will be
|
|
58
|
-
* individually used as the relative context against the provided expression
|
|
59
|
-
* tree. Only the elements whose expressions result in a truthy value will be
|
|
60
|
-
* included in the resulting array.
|
|
61
|
-
*
|
|
62
|
-
* If the subject is not an array of values, it will be converted to a single-
|
|
63
|
-
* element array before running the filter.
|
|
64
|
-
* @param {*} subject The value to be filtered usually an array. If this value is
|
|
65
|
-
* not an array, it will be converted to an array with this value as the
|
|
66
|
-
* only element.
|
|
67
|
-
* @param {{}} expr The expression tree to run against each subject. If the
|
|
68
|
-
* tree evaluates to a truthy result, then the value will be included in
|
|
69
|
-
* the returned array otherwise, it will be eliminated.
|
|
70
|
-
* @returns {Promise<Array>} resolves with an array of values that passed the
|
|
71
|
-
* expression filter.
|
|
72
|
-
* @private
|
|
73
|
-
*/
|
|
74
|
-
_filterRelative(subject: any, expr: AstNode): any;
|
|
75
|
-
/**
|
|
76
|
-
* Applies a static filter expression to a subject value. If the filter
|
|
77
|
-
* expression evaluates to boolean true, the subject is returned if false,
|
|
78
|
-
* undefined.
|
|
79
|
-
*
|
|
80
|
-
* For any other resulting value of the expression, this function will attempt
|
|
81
|
-
* to respond with the property at that name or index of the subject.
|
|
82
|
-
* @param {*} subject The value to be filtered. Usually an Array (for which
|
|
83
|
-
* the expression would generally resolve to a numeric index) or an
|
|
84
|
-
* Object (for which the expression would generally resolve to a string
|
|
85
|
-
* indicating a property name)
|
|
86
|
-
* @param {{}} expr The expression tree to run against the subject
|
|
87
|
-
* @returns {Promise<*>} resolves with the value of the drill-down.
|
|
88
|
-
* @private
|
|
89
|
-
*/
|
|
90
|
-
_filterStatic(subject: any, expr: AstNode): any;
|
|
47
|
+
evalMap(map: Record<string, AstNode>): {
|
|
48
|
+
[k: string]: any;
|
|
49
|
+
};
|
|
91
50
|
}
|
|
92
51
|
export default Evaluator;
|
|
@@ -49,104 +49,45 @@ const handlers = __importStar(require("./handlers.js"));
|
|
|
49
49
|
* @param {{}} grammar A grammar object against which to evaluate the expression
|
|
50
50
|
* tree
|
|
51
51
|
* @param {{}} [context] A map of variable keys to their values. This will be
|
|
52
|
-
* accessed to resolve the value of each non-relative identifier.
|
|
53
|
-
* Promise values will be passed to the expression as their resolved
|
|
54
|
-
* value.
|
|
52
|
+
* accessed to resolve the value of each non-relative identifier.
|
|
55
53
|
* @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
|
|
56
54
|
* to resolve the value of a relative identifier.
|
|
57
|
-
* @param {function} promise A constructor for the Promise class to be used;
|
|
58
|
-
* probably either Promise or PromiseSync.
|
|
59
55
|
*/
|
|
60
56
|
class Evaluator {
|
|
61
|
-
constructor(grammar, context, relativeContext
|
|
57
|
+
constructor(grammar, context, relativeContext) {
|
|
62
58
|
this._grammar = grammar;
|
|
63
59
|
this._context = context || {};
|
|
64
60
|
this._relContext = relativeContext || this._context;
|
|
65
|
-
this.Promise = promise;
|
|
66
61
|
}
|
|
67
62
|
/**
|
|
68
63
|
* Evaluates an expression tree within the configured context.
|
|
69
64
|
* @param {{}} ast An expression tree object
|
|
70
|
-
* @returns {
|
|
65
|
+
* @returns {*} the resulting value of the expression.
|
|
71
66
|
*/
|
|
72
67
|
eval(ast) {
|
|
73
|
-
return
|
|
74
|
-
return handlers[ast.type].call(this, ast);
|
|
75
|
-
});
|
|
68
|
+
return handlers[ast.type].call(this, ast);
|
|
76
69
|
}
|
|
77
70
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
71
|
+
* Evaluates each expression within an array, and delivers the response as an
|
|
72
|
+
* array with the resulting values at the same indexes as their originating
|
|
73
|
+
* expressions.
|
|
81
74
|
* @param {Array<string>} arr An array of expression strings to be evaluated
|
|
82
|
-
* @returns {
|
|
75
|
+
* @returns {Array<{}>} the result array
|
|
83
76
|
*/
|
|
84
77
|
evalArray(arr) {
|
|
85
|
-
return
|
|
78
|
+
return arr.map((elem) => this.eval(elem));
|
|
86
79
|
}
|
|
87
80
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* as their value.
|
|
81
|
+
* Evaluates each expression within a map, and delivers the response as a map
|
|
82
|
+
* with the same keys, but with the evaluated result for each as their value.
|
|
91
83
|
* @param {{}} map A map of expression names to expression trees to be
|
|
92
84
|
* evaluated
|
|
93
|
-
* @returns {
|
|
85
|
+
* @returns {{}} the result map.
|
|
94
86
|
*/
|
|
95
87
|
evalMap(map) {
|
|
96
88
|
const entries = Object.entries(map);
|
|
97
|
-
const
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Applies a filter expression with relative identifier elements to a subject.
|
|
102
|
-
* The intent is for the subject to be an array of subjects that will be
|
|
103
|
-
* individually used as the relative context against the provided expression
|
|
104
|
-
* tree. Only the elements whose expressions result in a truthy value will be
|
|
105
|
-
* included in the resulting array.
|
|
106
|
-
*
|
|
107
|
-
* If the subject is not an array of values, it will be converted to a single-
|
|
108
|
-
* element array before running the filter.
|
|
109
|
-
* @param {*} subject The value to be filtered usually an array. If this value is
|
|
110
|
-
* not an array, it will be converted to an array with this value as the
|
|
111
|
-
* only element.
|
|
112
|
-
* @param {{}} expr The expression tree to run against each subject. If the
|
|
113
|
-
* tree evaluates to a truthy result, then the value will be included in
|
|
114
|
-
* the returned array otherwise, it will be eliminated.
|
|
115
|
-
* @returns {Promise<Array>} resolves with an array of values that passed the
|
|
116
|
-
* expression filter.
|
|
117
|
-
* @private
|
|
118
|
-
*/
|
|
119
|
-
_filterRelative(subject, expr) {
|
|
120
|
-
const arr = Array.isArray(subject)
|
|
121
|
-
? subject
|
|
122
|
-
: subject == null
|
|
123
|
-
? []
|
|
124
|
-
: [subject];
|
|
125
|
-
const promises = arr.map((elem) => new Evaluator(this._grammar, this._context, elem, this.Promise).eval(expr));
|
|
126
|
-
return this.Promise.all(promises).then((values) => arr.filter((_, idx) => values[idx]));
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Applies a static filter expression to a subject value. If the filter
|
|
130
|
-
* expression evaluates to boolean true, the subject is returned if false,
|
|
131
|
-
* undefined.
|
|
132
|
-
*
|
|
133
|
-
* For any other resulting value of the expression, this function will attempt
|
|
134
|
-
* to respond with the property at that name or index of the subject.
|
|
135
|
-
* @param {*} subject The value to be filtered. Usually an Array (for which
|
|
136
|
-
* the expression would generally resolve to a numeric index) or an
|
|
137
|
-
* Object (for which the expression would generally resolve to a string
|
|
138
|
-
* indicating a property name)
|
|
139
|
-
* @param {{}} expr The expression tree to run against the subject
|
|
140
|
-
* @returns {Promise<*>} resolves with the value of the drill-down.
|
|
141
|
-
* @private
|
|
142
|
-
*/
|
|
143
|
-
_filterStatic(subject, expr) {
|
|
144
|
-
return this.eval(expr).then((res) => {
|
|
145
|
-
if (typeof res === 'boolean') {
|
|
146
|
-
return res ? subject : undefined;
|
|
147
|
-
}
|
|
148
|
-
return subject?.[res];
|
|
149
|
-
});
|
|
89
|
+
const vals = entries.map(([_, ast]) => this.eval(ast));
|
|
90
|
+
return Object.fromEntries(entries.map(([key], idx) => [key, vals[idx]]));
|
|
150
91
|
}
|
|
151
92
|
}
|
|
152
93
|
exports.default = Evaluator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../../src/evaluator/Evaluator.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,wDAAyC;
|
|
1
|
+
{"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../../src/evaluator/Evaluator.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,wDAAyC;AASzC;;;;;;;;;;;;;;GAcG;AACH,MAAM,SAAS;IAKb,YAAY,OAAgB,EAAE,OAAa,EAAE,eAAqB;QAChE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,IAAI,EAAE,CAAA;QAC7B,IAAI,CAAC,WAAW,GAAG,eAAe,IAAI,IAAI,CAAC,QAAQ,CAAA;IACrD,CAAC;IAED;;;;OAIG;IACH,IAAI,CAAC,GAAY;QACf,OAAQ,QAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IACpD,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,GAAc;QACtB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACpD,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAA4B;QAClC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACnC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QACtD,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1E,CAAC;CACF;AAED,kBAAe,SAAS,CAAA"}
|
|
@@ -4,30 +4,30 @@ import type Evaluator from './Evaluator.ts';
|
|
|
4
4
|
* independently run through the evaluator.
|
|
5
5
|
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
6
6
|
* ObjectLiteral as the top node
|
|
7
|
-
* @returns {
|
|
7
|
+
* @returns {[]} an array of evaluated values.
|
|
8
8
|
* @private
|
|
9
9
|
*/
|
|
10
|
-
export declare function ArrayLiteral(this: Evaluator, ast: any): any;
|
|
10
|
+
export declare function ArrayLiteral(this: Evaluator, ast: any): any[];
|
|
11
11
|
/**
|
|
12
12
|
* Evaluates a BinaryExpression node by running the Grammar's evaluator for
|
|
13
13
|
* the given operator. Note that binary expressions support two types of
|
|
14
14
|
* evaluators: `eval` is called with the left and right operands pre-evaluated.
|
|
15
15
|
* `evalOnDemand`, if it exists, will be called with the left and right operands
|
|
16
16
|
* each individually wrapped in an object with an "eval" function that returns
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* the resulting value. This allows the binary expression to evaluate the
|
|
18
|
+
* operands conditionally.
|
|
19
19
|
* @param {{type: 'BinaryExpression', operator: <string>, left: {},
|
|
20
20
|
* right: {}}} ast An expression tree with a BinaryExpression as the top
|
|
21
21
|
* node
|
|
22
|
-
* @returns {
|
|
22
|
+
* @returns {*} the value of the BinaryExpression.
|
|
23
23
|
* @private
|
|
24
24
|
*/
|
|
25
25
|
export declare function BinaryExpression(this: Evaluator, ast: any): any;
|
|
26
26
|
/**
|
|
27
27
|
* Evaluates a ConditionalExpression node by first evaluating its test branch,
|
|
28
|
-
* and
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* and returning the consequent branch if the test is truthy, or the alternate
|
|
29
|
+
* branch if it is not. If there is no consequent branch, the test result will
|
|
30
|
+
* be used instead.
|
|
31
31
|
* @param {{type: 'ConditionalExpression', test: {}, consequent: {},
|
|
32
32
|
* alternate: {}}} ast An expression tree with a ConditionalExpression as
|
|
33
33
|
* the top node
|
|
@@ -35,11 +35,12 @@ export declare function BinaryExpression(this: Evaluator, ast: any): any;
|
|
|
35
35
|
*/
|
|
36
36
|
export declare function ConditionalExpression(this: Evaluator, ast: any): any;
|
|
37
37
|
/**
|
|
38
|
-
* Evaluates a FilterExpression by applying
|
|
38
|
+
* Evaluates a FilterExpression by applying bracket notation for array/object access.
|
|
39
|
+
* Note: Relative filtering (with leading dot) is not supported.
|
|
39
40
|
* @param {{type: 'FilterExpression', relative: <boolean>, expr: {},
|
|
40
41
|
* subject: {}}} ast An expression tree with a FilterExpression as the top
|
|
41
42
|
* node
|
|
42
|
-
* @returns {
|
|
43
|
+
* @returns {*} the value at the specified index/property.
|
|
43
44
|
* @private
|
|
44
45
|
*/
|
|
45
46
|
export declare function FilterExpression(this: Evaluator, ast: any): any;
|
|
@@ -49,8 +50,7 @@ export declare function FilterExpression(this: Evaluator, ast: any): any;
|
|
|
49
50
|
* constructed.
|
|
50
51
|
* @param {{type: 'Identifier', value: <string>, [from]: {}}} ast An expression
|
|
51
52
|
* tree with an Identifier as the top node
|
|
52
|
-
* @returns {
|
|
53
|
-
* will resolve with the identifier's value.
|
|
53
|
+
* @returns {*} the identifier's value.
|
|
54
54
|
* @private
|
|
55
55
|
*/
|
|
56
56
|
export declare function Identifier(this: Evaluator, ast: any): any;
|
|
@@ -67,7 +67,7 @@ export declare function Literal(this: Evaluator, ast: any): any;
|
|
|
67
67
|
* and concatenating all parts into a final string.
|
|
68
68
|
* @param {{type: 'TemplateLiteral', parts: Array<{}>}} ast An expression
|
|
69
69
|
* tree with a TemplateLiteral as the top node
|
|
70
|
-
* @returns {
|
|
70
|
+
* @returns {string} the final interpolated string
|
|
71
71
|
* @private
|
|
72
72
|
*/
|
|
73
73
|
export declare function TemplateLiteral(this: Evaluator, ast: any): any;
|
|
@@ -76,17 +76,18 @@ export declare function TemplateLiteral(this: Evaluator, ast: any): any;
|
|
|
76
76
|
* independently run through the evaluator.
|
|
77
77
|
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
78
78
|
* ObjectLiteral as the top node
|
|
79
|
-
* @returns {
|
|
79
|
+
* @returns {{}} a map of evaluated values.
|
|
80
80
|
* @private
|
|
81
81
|
*/
|
|
82
|
-
export declare function ObjectLiteral(this: Evaluator, ast: any):
|
|
82
|
+
export declare function ObjectLiteral(this: Evaluator, ast: any): {
|
|
83
|
+
[k: string]: any;
|
|
84
|
+
};
|
|
83
85
|
/**
|
|
84
86
|
* Evaluates a FunctionCall node by applying the supplied arguments to a
|
|
85
87
|
* function defined in one of the grammar's function pools.
|
|
86
88
|
* @param {{type: 'FunctionCall', name: <string>}} ast An
|
|
87
89
|
* expression tree with a FunctionCall as the top node
|
|
88
|
-
* @returns {
|
|
89
|
-
* will resolve with the resulting value.
|
|
90
|
+
* @returns {*} the value of the function call.
|
|
90
91
|
* @private
|
|
91
92
|
*/
|
|
92
93
|
export declare function FunctionCall(this: Evaluator, ast: any): any;
|
|
@@ -95,7 +96,7 @@ export declare function FunctionCall(this: Evaluator, ast: any): any;
|
|
|
95
96
|
* operator's eval function.
|
|
96
97
|
* @param {{type: 'UnaryExpression', operator: <string>, right: {}}} ast An
|
|
97
98
|
* expression tree with a UnaryExpression as the top node
|
|
98
|
-
* @returns {
|
|
99
|
+
* @returns {*} the value of the UnaryExpression.
|
|
99
100
|
* @constructor
|
|
100
101
|
*/
|
|
101
102
|
export declare function UnaryExpression(this: Evaluator, ast: any): any;
|
|
@@ -17,15 +17,14 @@ exports.UnaryExpression = UnaryExpression;
|
|
|
17
17
|
exports.SequenceExpression = SequenceExpression;
|
|
18
18
|
exports.AssignmentExpression = AssignmentExpression;
|
|
19
19
|
const poolNames = {
|
|
20
|
-
functions: 'Jexl Function'
|
|
21
|
-
transforms: 'Transform'
|
|
20
|
+
functions: 'Jexl Function'
|
|
22
21
|
};
|
|
23
22
|
/**
|
|
24
23
|
* Evaluates an ArrayLiteral by returning its value, with each element
|
|
25
24
|
* independently run through the evaluator.
|
|
26
25
|
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
27
26
|
* ObjectLiteral as the top node
|
|
28
|
-
* @returns {
|
|
27
|
+
* @returns {[]} an array of evaluated values.
|
|
29
28
|
* @private
|
|
30
29
|
*/
|
|
31
30
|
function ArrayLiteral(ast) {
|
|
@@ -37,12 +36,12 @@ function ArrayLiteral(ast) {
|
|
|
37
36
|
* evaluators: `eval` is called with the left and right operands pre-evaluated.
|
|
38
37
|
* `evalOnDemand`, if it exists, will be called with the left and right operands
|
|
39
38
|
* each individually wrapped in an object with an "eval" function that returns
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* the resulting value. This allows the binary expression to evaluate the
|
|
40
|
+
* operands conditionally.
|
|
42
41
|
* @param {{type: 'BinaryExpression', operator: <string>, left: {},
|
|
43
42
|
* right: {}}} ast An expression tree with a BinaryExpression as the top
|
|
44
43
|
* node
|
|
45
|
-
* @returns {
|
|
44
|
+
* @returns {*} the value of the BinaryExpression.
|
|
46
45
|
* @private
|
|
47
46
|
*/
|
|
48
47
|
function BinaryExpression(ast) {
|
|
@@ -51,44 +50,43 @@ function BinaryExpression(ast) {
|
|
|
51
50
|
const wrap = (subAst) => ({ eval: () => this.eval(subAst) });
|
|
52
51
|
return grammarOp.evalOnDemand(wrap(ast.left), wrap(ast.right));
|
|
53
52
|
}
|
|
54
|
-
|
|
53
|
+
const left = this.eval(ast.left);
|
|
54
|
+
const right = this.eval(ast.right);
|
|
55
|
+
return grammarOp.eval(left, right);
|
|
55
56
|
}
|
|
56
57
|
/**
|
|
57
58
|
* Evaluates a ConditionalExpression node by first evaluating its test branch,
|
|
58
|
-
* and
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* and returning the consequent branch if the test is truthy, or the alternate
|
|
60
|
+
* branch if it is not. If there is no consequent branch, the test result will
|
|
61
|
+
* be used instead.
|
|
61
62
|
* @param {{type: 'ConditionalExpression', test: {}, consequent: {},
|
|
62
63
|
* alternate: {}}} ast An expression tree with a ConditionalExpression as
|
|
63
64
|
* the top node
|
|
64
65
|
* @private
|
|
65
66
|
*/
|
|
66
67
|
function ConditionalExpression(ast) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return res;
|
|
73
|
-
}
|
|
74
|
-
return this.eval(ast.alternate);
|
|
75
|
-
});
|
|
68
|
+
const res = this.eval(ast.test);
|
|
69
|
+
if (res) {
|
|
70
|
+
return ast.consequent ? this.eval(ast.consequent) : res;
|
|
71
|
+
}
|
|
72
|
+
return this.eval(ast.alternate);
|
|
76
73
|
}
|
|
77
74
|
/**
|
|
78
|
-
* Evaluates a FilterExpression by applying
|
|
75
|
+
* Evaluates a FilterExpression by applying bracket notation for array/object access.
|
|
76
|
+
* Note: Relative filtering (with leading dot) is not supported.
|
|
79
77
|
* @param {{type: 'FilterExpression', relative: <boolean>, expr: {},
|
|
80
78
|
* subject: {}}} ast An expression tree with a FilterExpression as the top
|
|
81
79
|
* node
|
|
82
|
-
* @returns {
|
|
80
|
+
* @returns {*} the value at the specified index/property.
|
|
83
81
|
* @private
|
|
84
82
|
*/
|
|
85
83
|
function FilterExpression(ast) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
const subject = this.eval(ast.subject);
|
|
85
|
+
if (ast.relative) {
|
|
86
|
+
throw new Error('Relative filter expressions are not supported');
|
|
87
|
+
}
|
|
88
|
+
const index = this.eval(ast.expr);
|
|
89
|
+
return subject?.[index];
|
|
92
90
|
}
|
|
93
91
|
/**
|
|
94
92
|
* Evaluates an Identifier by either stemming from the evaluated 'from'
|
|
@@ -96,8 +94,7 @@ function FilterExpression(ast) {
|
|
|
96
94
|
* constructed.
|
|
97
95
|
* @param {{type: 'Identifier', value: <string>, [from]: {}}} ast An expression
|
|
98
96
|
* tree with an Identifier as the top node
|
|
99
|
-
* @returns {
|
|
100
|
-
* will resolve with the identifier's value.
|
|
97
|
+
* @returns {*} the identifier's value.
|
|
101
98
|
* @private
|
|
102
99
|
*/
|
|
103
100
|
function Identifier(ast) {
|
|
@@ -105,13 +102,12 @@ function Identifier(ast) {
|
|
|
105
102
|
const contextSource = ast.relative ? this._relContext : this._context;
|
|
106
103
|
return contextSource[ast.value];
|
|
107
104
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
});
|
|
105
|
+
const context = this.eval(ast.from);
|
|
106
|
+
if (context == null) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const ctx = Array.isArray(context) ? context[0] : context;
|
|
110
|
+
return ctx?.[ast.value];
|
|
115
111
|
}
|
|
116
112
|
/**
|
|
117
113
|
* Evaluates a Literal by returning its value property.
|
|
@@ -128,29 +124,28 @@ function Literal(ast) {
|
|
|
128
124
|
* and concatenating all parts into a final string.
|
|
129
125
|
* @param {{type: 'TemplateLiteral', parts: Array<{}>}} ast An expression
|
|
130
126
|
* tree with a TemplateLiteral as the top node
|
|
131
|
-
* @returns {
|
|
127
|
+
* @returns {string} the final interpolated string
|
|
132
128
|
* @private
|
|
133
129
|
*/
|
|
134
130
|
function TemplateLiteral(ast) {
|
|
135
|
-
const
|
|
131
|
+
const values = ast.parts.map((part) => {
|
|
136
132
|
if (part.type === 'static') {
|
|
137
|
-
return
|
|
133
|
+
return part.value;
|
|
138
134
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
});
|
|
135
|
+
const result = this.eval(part.value);
|
|
136
|
+
if (result == null) {
|
|
137
|
+
return '';
|
|
138
|
+
}
|
|
139
|
+
return String(result);
|
|
145
140
|
});
|
|
146
|
-
return
|
|
141
|
+
return values.join('');
|
|
147
142
|
}
|
|
148
143
|
/**
|
|
149
144
|
* Evaluates an ObjectLiteral by returning its value, with each key
|
|
150
145
|
* independently run through the evaluator.
|
|
151
146
|
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
152
147
|
* ObjectLiteral as the top node
|
|
153
|
-
* @returns {
|
|
148
|
+
* @returns {{}} a map of evaluated values.
|
|
154
149
|
* @private
|
|
155
150
|
*/
|
|
156
151
|
function ObjectLiteral(ast) {
|
|
@@ -161,8 +156,7 @@ function ObjectLiteral(ast) {
|
|
|
161
156
|
* function defined in one of the grammar's function pools.
|
|
162
157
|
* @param {{type: 'FunctionCall', name: <string>}} ast An
|
|
163
158
|
* expression tree with a FunctionCall as the top node
|
|
164
|
-
* @returns {
|
|
165
|
-
* will resolve with the resulting value.
|
|
159
|
+
* @returns {*} the value of the function call.
|
|
166
160
|
* @private
|
|
167
161
|
*/
|
|
168
162
|
function FunctionCall(ast) {
|
|
@@ -175,18 +169,20 @@ function FunctionCall(ast) {
|
|
|
175
169
|
if (!func) {
|
|
176
170
|
throw new Error(`${poolName} ${ast.name} is not defined.`);
|
|
177
171
|
}
|
|
178
|
-
|
|
172
|
+
const args = this.evalArray(ast.args || []);
|
|
173
|
+
return func(...args);
|
|
179
174
|
}
|
|
180
175
|
/**
|
|
181
176
|
* Evaluates a Unary expression by passing the right side through the
|
|
182
177
|
* operator's eval function.
|
|
183
178
|
* @param {{type: 'UnaryExpression', operator: <string>, right: {}}} ast An
|
|
184
179
|
* expression tree with a UnaryExpression as the top node
|
|
185
|
-
* @returns {
|
|
180
|
+
* @returns {*} the value of the UnaryExpression.
|
|
186
181
|
* @constructor
|
|
187
182
|
*/
|
|
188
183
|
function UnaryExpression(ast) {
|
|
189
|
-
|
|
184
|
+
const right = this.eval(ast.right);
|
|
185
|
+
return this._grammar.elements[ast.operator].eval(right);
|
|
190
186
|
}
|
|
191
187
|
/**
|
|
192
188
|
* Evaluates a SequenceExpression by evaluating each expression in order
|
|
@@ -194,23 +190,19 @@ function UnaryExpression(ast) {
|
|
|
194
190
|
*/
|
|
195
191
|
function SequenceExpression(ast) {
|
|
196
192
|
let lastValue;
|
|
197
|
-
let promise = this.Promise.resolve();
|
|
198
193
|
for (const expr of ast.expressions) {
|
|
199
|
-
|
|
200
|
-
lastValue = val;
|
|
201
|
-
}));
|
|
194
|
+
lastValue = this.eval(expr);
|
|
202
195
|
}
|
|
203
|
-
return
|
|
196
|
+
return lastValue;
|
|
204
197
|
}
|
|
205
198
|
/**
|
|
206
199
|
* Evaluates an AssignmentExpression by evaluating the right side
|
|
207
200
|
* and assigning it to the variable name on the left side.
|
|
208
201
|
*/
|
|
209
202
|
function AssignmentExpression(ast) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
});
|
|
203
|
+
const value = this.eval(ast.right);
|
|
204
|
+
const varName = ast.left.value;
|
|
205
|
+
this._context[varName] = value;
|
|
206
|
+
return value;
|
|
215
207
|
}
|
|
216
208
|
//# sourceMappingURL=handlers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/evaluator/handlers.ts"],"names":[],"mappings":";AAAA;;;GAGG;;
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/evaluator/handlers.ts"],"names":[],"mappings":"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"}
|
package/dist/grammar.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ export interface BinaryOp {
|
|
|
3
3
|
precedence: number;
|
|
4
4
|
eval?: (left: any, right: any) => any;
|
|
5
5
|
evalOnDemand?: (left: {
|
|
6
|
-
eval: () =>
|
|
6
|
+
eval: () => any;
|
|
7
7
|
}, right: {
|
|
8
|
-
eval: () =>
|
|
9
|
-
}) =>
|
|
8
|
+
eval: () => any;
|
|
9
|
+
}) => any;
|
|
10
10
|
}
|
|
11
11
|
export interface UnaryOp {
|
|
12
12
|
type: 'unaryOp';
|
|
@@ -20,6 +20,5 @@ export type GrammarElement = BinaryOp | UnaryOp | SimpleElement;
|
|
|
20
20
|
export interface Grammar {
|
|
21
21
|
elements: Record<string, GrammarElement>;
|
|
22
22
|
functions: Record<string, (...args: any[]) => any>;
|
|
23
|
-
transforms: Record<string, (val: any, ...args: any[]) => any>;
|
|
24
23
|
}
|
|
25
24
|
export declare const getGrammar: () => Grammar;
|