@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;
|
|
@@ -14,104 +14,45 @@ import * as handlers from "./handlers.js";
|
|
|
14
14
|
* @param {{}} grammar A grammar object against which to evaluate the expression
|
|
15
15
|
* tree
|
|
16
16
|
* @param {{}} [context] A map of variable keys to their values. This will be
|
|
17
|
-
* accessed to resolve the value of each non-relative identifier.
|
|
18
|
-
* Promise values will be passed to the expression as their resolved
|
|
19
|
-
* value.
|
|
17
|
+
* accessed to resolve the value of each non-relative identifier.
|
|
20
18
|
* @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
|
|
21
19
|
* to resolve the value of a relative identifier.
|
|
22
|
-
* @param {function} promise A constructor for the Promise class to be used;
|
|
23
|
-
* probably either Promise or PromiseSync.
|
|
24
20
|
*/
|
|
25
21
|
class Evaluator {
|
|
26
|
-
constructor(grammar, context, relativeContext
|
|
22
|
+
constructor(grammar, context, relativeContext) {
|
|
27
23
|
this._grammar = grammar;
|
|
28
24
|
this._context = context || {};
|
|
29
25
|
this._relContext = relativeContext || this._context;
|
|
30
|
-
this.Promise = promise;
|
|
31
26
|
}
|
|
32
27
|
/**
|
|
33
28
|
* Evaluates an expression tree within the configured context.
|
|
34
29
|
* @param {{}} ast An expression tree object
|
|
35
|
-
* @returns {
|
|
30
|
+
* @returns {*} the resulting value of the expression.
|
|
36
31
|
*/
|
|
37
32
|
eval(ast) {
|
|
38
|
-
return
|
|
39
|
-
return handlers[ast.type].call(this, ast);
|
|
40
|
-
});
|
|
33
|
+
return handlers[ast.type].call(this, ast);
|
|
41
34
|
}
|
|
42
35
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
36
|
+
* Evaluates each expression within an array, and delivers the response as an
|
|
37
|
+
* array with the resulting values at the same indexes as their originating
|
|
38
|
+
* expressions.
|
|
46
39
|
* @param {Array<string>} arr An array of expression strings to be evaluated
|
|
47
|
-
* @returns {
|
|
40
|
+
* @returns {Array<{}>} the result array
|
|
48
41
|
*/
|
|
49
42
|
evalArray(arr) {
|
|
50
|
-
return
|
|
43
|
+
return arr.map((elem) => this.eval(elem));
|
|
51
44
|
}
|
|
52
45
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* as their value.
|
|
46
|
+
* Evaluates each expression within a map, and delivers the response as a map
|
|
47
|
+
* with the same keys, but with the evaluated result for each as their value.
|
|
56
48
|
* @param {{}} map A map of expression names to expression trees to be
|
|
57
49
|
* evaluated
|
|
58
|
-
* @returns {
|
|
50
|
+
* @returns {{}} the result map.
|
|
59
51
|
*/
|
|
60
52
|
evalMap(map) {
|
|
61
53
|
const entries = Object.entries(map);
|
|
62
|
-
const
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Applies a filter expression with relative identifier elements to a subject.
|
|
67
|
-
* The intent is for the subject to be an array of subjects that will be
|
|
68
|
-
* individually used as the relative context against the provided expression
|
|
69
|
-
* tree. Only the elements whose expressions result in a truthy value will be
|
|
70
|
-
* included in the resulting array.
|
|
71
|
-
*
|
|
72
|
-
* If the subject is not an array of values, it will be converted to a single-
|
|
73
|
-
* element array before running the filter.
|
|
74
|
-
* @param {*} subject The value to be filtered usually an array. If this value is
|
|
75
|
-
* not an array, it will be converted to an array with this value as the
|
|
76
|
-
* only element.
|
|
77
|
-
* @param {{}} expr The expression tree to run against each subject. If the
|
|
78
|
-
* tree evaluates to a truthy result, then the value will be included in
|
|
79
|
-
* the returned array otherwise, it will be eliminated.
|
|
80
|
-
* @returns {Promise<Array>} resolves with an array of values that passed the
|
|
81
|
-
* expression filter.
|
|
82
|
-
* @private
|
|
83
|
-
*/
|
|
84
|
-
_filterRelative(subject, expr) {
|
|
85
|
-
const arr = Array.isArray(subject)
|
|
86
|
-
? subject
|
|
87
|
-
: subject == null
|
|
88
|
-
? []
|
|
89
|
-
: [subject];
|
|
90
|
-
const promises = arr.map((elem) => new Evaluator(this._grammar, this._context, elem, this.Promise).eval(expr));
|
|
91
|
-
return this.Promise.all(promises).then((values) => arr.filter((_, idx) => values[idx]));
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Applies a static filter expression to a subject value. If the filter
|
|
95
|
-
* expression evaluates to boolean true, the subject is returned if false,
|
|
96
|
-
* undefined.
|
|
97
|
-
*
|
|
98
|
-
* For any other resulting value of the expression, this function will attempt
|
|
99
|
-
* to respond with the property at that name or index of the subject.
|
|
100
|
-
* @param {*} subject The value to be filtered. Usually an Array (for which
|
|
101
|
-
* the expression would generally resolve to a numeric index) or an
|
|
102
|
-
* Object (for which the expression would generally resolve to a string
|
|
103
|
-
* indicating a property name)
|
|
104
|
-
* @param {{}} expr The expression tree to run against the subject
|
|
105
|
-
* @returns {Promise<*>} resolves with the value of the drill-down.
|
|
106
|
-
* @private
|
|
107
|
-
*/
|
|
108
|
-
_filterStatic(subject, expr) {
|
|
109
|
-
return this.eval(expr).then((res) => {
|
|
110
|
-
if (typeof res === 'boolean') {
|
|
111
|
-
return res ? subject : undefined;
|
|
112
|
-
}
|
|
113
|
-
return subject?.[res];
|
|
114
|
-
});
|
|
54
|
+
const vals = entries.map(([_, ast]) => this.eval(ast));
|
|
55
|
+
return Object.fromEntries(entries.map(([key], idx) => [key, vals[idx]]));
|
|
115
56
|
}
|
|
116
57
|
}
|
|
117
58
|
export default Evaluator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../../src/evaluator/Evaluator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../../src/evaluator/Evaluator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;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,eAAe,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;
|
|
@@ -3,15 +3,14 @@
|
|
|
3
3
|
* Copyright 2020 Tom Shawver
|
|
4
4
|
*/
|
|
5
5
|
const poolNames = {
|
|
6
|
-
functions: 'Jexl Function'
|
|
7
|
-
transforms: 'Transform'
|
|
6
|
+
functions: 'Jexl Function'
|
|
8
7
|
};
|
|
9
8
|
/**
|
|
10
9
|
* Evaluates an ArrayLiteral by returning its value, with each element
|
|
11
10
|
* independently run through the evaluator.
|
|
12
11
|
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
13
12
|
* ObjectLiteral as the top node
|
|
14
|
-
* @returns {
|
|
13
|
+
* @returns {[]} an array of evaluated values.
|
|
15
14
|
* @private
|
|
16
15
|
*/
|
|
17
16
|
export function ArrayLiteral(ast) {
|
|
@@ -23,12 +22,12 @@ export function ArrayLiteral(ast) {
|
|
|
23
22
|
* evaluators: `eval` is called with the left and right operands pre-evaluated.
|
|
24
23
|
* `evalOnDemand`, if it exists, will be called with the left and right operands
|
|
25
24
|
* each individually wrapped in an object with an "eval" function that returns
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* the resulting value. This allows the binary expression to evaluate the
|
|
26
|
+
* operands conditionally.
|
|
28
27
|
* @param {{type: 'BinaryExpression', operator: <string>, left: {},
|
|
29
28
|
* right: {}}} ast An expression tree with a BinaryExpression as the top
|
|
30
29
|
* node
|
|
31
|
-
* @returns {
|
|
30
|
+
* @returns {*} the value of the BinaryExpression.
|
|
32
31
|
* @private
|
|
33
32
|
*/
|
|
34
33
|
export function BinaryExpression(ast) {
|
|
@@ -37,44 +36,43 @@ export function BinaryExpression(ast) {
|
|
|
37
36
|
const wrap = (subAst) => ({ eval: () => this.eval(subAst) });
|
|
38
37
|
return grammarOp.evalOnDemand(wrap(ast.left), wrap(ast.right));
|
|
39
38
|
}
|
|
40
|
-
|
|
39
|
+
const left = this.eval(ast.left);
|
|
40
|
+
const right = this.eval(ast.right);
|
|
41
|
+
return grammarOp.eval(left, right);
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
43
44
|
* Evaluates a ConditionalExpression node by first evaluating its test branch,
|
|
44
|
-
* and
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* and returning the consequent branch if the test is truthy, or the alternate
|
|
46
|
+
* branch if it is not. If there is no consequent branch, the test result will
|
|
47
|
+
* be used instead.
|
|
47
48
|
* @param {{type: 'ConditionalExpression', test: {}, consequent: {},
|
|
48
49
|
* alternate: {}}} ast An expression tree with a ConditionalExpression as
|
|
49
50
|
* the top node
|
|
50
51
|
* @private
|
|
51
52
|
*/
|
|
52
53
|
export function ConditionalExpression(ast) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return res;
|
|
59
|
-
}
|
|
60
|
-
return this.eval(ast.alternate);
|
|
61
|
-
});
|
|
54
|
+
const res = this.eval(ast.test);
|
|
55
|
+
if (res) {
|
|
56
|
+
return ast.consequent ? this.eval(ast.consequent) : res;
|
|
57
|
+
}
|
|
58
|
+
return this.eval(ast.alternate);
|
|
62
59
|
}
|
|
63
60
|
/**
|
|
64
|
-
* Evaluates a FilterExpression by applying
|
|
61
|
+
* Evaluates a FilterExpression by applying bracket notation for array/object access.
|
|
62
|
+
* Note: Relative filtering (with leading dot) is not supported.
|
|
65
63
|
* @param {{type: 'FilterExpression', relative: <boolean>, expr: {},
|
|
66
64
|
* subject: {}}} ast An expression tree with a FilterExpression as the top
|
|
67
65
|
* node
|
|
68
|
-
* @returns {
|
|
66
|
+
* @returns {*} the value at the specified index/property.
|
|
69
67
|
* @private
|
|
70
68
|
*/
|
|
71
69
|
export function FilterExpression(ast) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
const subject = this.eval(ast.subject);
|
|
71
|
+
if (ast.relative) {
|
|
72
|
+
throw new Error('Relative filter expressions are not supported');
|
|
73
|
+
}
|
|
74
|
+
const index = this.eval(ast.expr);
|
|
75
|
+
return subject?.[index];
|
|
78
76
|
}
|
|
79
77
|
/**
|
|
80
78
|
* Evaluates an Identifier by either stemming from the evaluated 'from'
|
|
@@ -82,8 +80,7 @@ export function FilterExpression(ast) {
|
|
|
82
80
|
* constructed.
|
|
83
81
|
* @param {{type: 'Identifier', value: <string>, [from]: {}}} ast An expression
|
|
84
82
|
* tree with an Identifier as the top node
|
|
85
|
-
* @returns {
|
|
86
|
-
* will resolve with the identifier's value.
|
|
83
|
+
* @returns {*} the identifier's value.
|
|
87
84
|
* @private
|
|
88
85
|
*/
|
|
89
86
|
export function Identifier(ast) {
|
|
@@ -91,13 +88,12 @@ export function Identifier(ast) {
|
|
|
91
88
|
const contextSource = ast.relative ? this._relContext : this._context;
|
|
92
89
|
return contextSource[ast.value];
|
|
93
90
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
});
|
|
91
|
+
const context = this.eval(ast.from);
|
|
92
|
+
if (context == null) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
const ctx = Array.isArray(context) ? context[0] : context;
|
|
96
|
+
return ctx?.[ast.value];
|
|
101
97
|
}
|
|
102
98
|
/**
|
|
103
99
|
* Evaluates a Literal by returning its value property.
|
|
@@ -114,29 +110,28 @@ export function Literal(ast) {
|
|
|
114
110
|
* and concatenating all parts into a final string.
|
|
115
111
|
* @param {{type: 'TemplateLiteral', parts: Array<{}>}} ast An expression
|
|
116
112
|
* tree with a TemplateLiteral as the top node
|
|
117
|
-
* @returns {
|
|
113
|
+
* @returns {string} the final interpolated string
|
|
118
114
|
* @private
|
|
119
115
|
*/
|
|
120
116
|
export function TemplateLiteral(ast) {
|
|
121
|
-
const
|
|
117
|
+
const values = ast.parts.map((part) => {
|
|
122
118
|
if (part.type === 'static') {
|
|
123
|
-
return
|
|
119
|
+
return part.value;
|
|
124
120
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
121
|
+
const result = this.eval(part.value);
|
|
122
|
+
if (result == null) {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
return String(result);
|
|
131
126
|
});
|
|
132
|
-
return
|
|
127
|
+
return values.join('');
|
|
133
128
|
}
|
|
134
129
|
/**
|
|
135
130
|
* Evaluates an ObjectLiteral by returning its value, with each key
|
|
136
131
|
* independently run through the evaluator.
|
|
137
132
|
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
138
133
|
* ObjectLiteral as the top node
|
|
139
|
-
* @returns {
|
|
134
|
+
* @returns {{}} a map of evaluated values.
|
|
140
135
|
* @private
|
|
141
136
|
*/
|
|
142
137
|
export function ObjectLiteral(ast) {
|
|
@@ -147,8 +142,7 @@ export function ObjectLiteral(ast) {
|
|
|
147
142
|
* function defined in one of the grammar's function pools.
|
|
148
143
|
* @param {{type: 'FunctionCall', name: <string>}} ast An
|
|
149
144
|
* expression tree with a FunctionCall as the top node
|
|
150
|
-
* @returns {
|
|
151
|
-
* will resolve with the resulting value.
|
|
145
|
+
* @returns {*} the value of the function call.
|
|
152
146
|
* @private
|
|
153
147
|
*/
|
|
154
148
|
export function FunctionCall(ast) {
|
|
@@ -161,18 +155,20 @@ export function FunctionCall(ast) {
|
|
|
161
155
|
if (!func) {
|
|
162
156
|
throw new Error(`${poolName} ${ast.name} is not defined.`);
|
|
163
157
|
}
|
|
164
|
-
|
|
158
|
+
const args = this.evalArray(ast.args || []);
|
|
159
|
+
return func(...args);
|
|
165
160
|
}
|
|
166
161
|
/**
|
|
167
162
|
* Evaluates a Unary expression by passing the right side through the
|
|
168
163
|
* operator's eval function.
|
|
169
164
|
* @param {{type: 'UnaryExpression', operator: <string>, right: {}}} ast An
|
|
170
165
|
* expression tree with a UnaryExpression as the top node
|
|
171
|
-
* @returns {
|
|
166
|
+
* @returns {*} the value of the UnaryExpression.
|
|
172
167
|
* @constructor
|
|
173
168
|
*/
|
|
174
169
|
export function UnaryExpression(ast) {
|
|
175
|
-
|
|
170
|
+
const right = this.eval(ast.right);
|
|
171
|
+
return this._grammar.elements[ast.operator].eval(right);
|
|
176
172
|
}
|
|
177
173
|
/**
|
|
178
174
|
* Evaluates a SequenceExpression by evaluating each expression in order
|
|
@@ -180,23 +176,19 @@ export function UnaryExpression(ast) {
|
|
|
180
176
|
*/
|
|
181
177
|
export function SequenceExpression(ast) {
|
|
182
178
|
let lastValue;
|
|
183
|
-
let promise = this.Promise.resolve();
|
|
184
179
|
for (const expr of ast.expressions) {
|
|
185
|
-
|
|
186
|
-
lastValue = val;
|
|
187
|
-
}));
|
|
180
|
+
lastValue = this.eval(expr);
|
|
188
181
|
}
|
|
189
|
-
return
|
|
182
|
+
return lastValue;
|
|
190
183
|
}
|
|
191
184
|
/**
|
|
192
185
|
* Evaluates an AssignmentExpression by evaluating the right side
|
|
193
186
|
* and assigning it to the variable name on the left side.
|
|
194
187
|
*/
|
|
195
188
|
export function AssignmentExpression(ast) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
});
|
|
189
|
+
const value = this.eval(ast.right);
|
|
190
|
+
const varName = ast.left.value;
|
|
191
|
+
this._context[varName] = value;
|
|
192
|
+
return value;
|
|
201
193
|
}
|
|
202
194
|
//# sourceMappingURL=handlers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/evaluator/handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,SAAS,GAA2B;IACxC,SAAS,EAAE,eAAe;
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/evaluator/handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,SAAS,GAA2B;IACxC,SAAS,EAAE,eAAe;CAC3B,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAkB,GAAQ;IACpD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AAClC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAAkB,GAAQ;IACxD,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACtD,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,CAAC,MAAe,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACrE,OAAO,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAClC,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACpC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAkB,GAAQ;IAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;IACzD,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;AACjC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAkB,GAAQ;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACjC,OAAO,OAAO,EAAE,CAAC,KAAK,CAAC,CAAA;AACzB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAkB,GAAQ;IAClD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAA;QACrE,OAAO,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACjC,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACnC,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IACzD,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AACzB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAkB,GAAQ;IAC/C,OAAO,GAAG,CAAC,KAAK,CAAA;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAkB,GAAQ;IACvD,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE;QACzC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,KAAK,CAAA;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpC,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,OAAO,EAAE,CAAA;QACX,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACxB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAkB,GAAQ;IACrD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AAChC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAkB,GAAQ;IACpD,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,CAAC,IAAI,aAAa,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,IAAI,GAAI,IAAI,CAAC,QAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,IAAI,GAAG,CAAC,IAAI,kBAAkB,CAAC,CAAA;IAC5D,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;IAC3C,OAAO,IAAI,CAAC,GAAG,IAAI,CAAC,CAAA;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAkB,GAAQ;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAClC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAkB,GAAQ;IAC1D,IAAI,SAAc,CAAA;IAElB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC7B,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAkB,GAAQ;IAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAClC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAA;IAC9B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,KAAK,CAAA;IAC9B,OAAO,KAAK,CAAA;AACd,CAAC"}
|
package/esm/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;
|