@jbrowse/jexl 3.0.2 → 3.1.0

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.
Files changed (76) hide show
  1. package/README.md +11 -2
  2. package/dist/Expression.d.ts +16 -6
  3. package/dist/Expression.js +34 -8
  4. package/dist/Expression.js.map +1 -1
  5. package/dist/Jexl.d.ts +13 -12
  6. package/dist/Jexl.js +31 -30
  7. package/dist/Jexl.js.map +1 -1
  8. package/dist/Lexer.d.ts +9 -8
  9. package/dist/Lexer.js +58 -18
  10. package/dist/Lexer.js.map +1 -1
  11. package/dist/evaluator/Evaluator.d.ts +20 -34
  12. package/dist/evaluator/Evaluator.js +19 -64
  13. package/dist/evaluator/Evaluator.js.map +1 -1
  14. package/dist/evaluator/compile.d.ts +27 -0
  15. package/dist/evaluator/compile.js +261 -0
  16. package/dist/evaluator/compile.js.map +1 -0
  17. package/dist/grammar.d.ts +29 -9
  18. package/dist/grammar.js +19 -3
  19. package/dist/grammar.js.map +1 -1
  20. package/dist/parser/Parser.d.ts +5 -7
  21. package/dist/parser/Parser.js +17 -2
  22. package/dist/parser/Parser.js.map +1 -1
  23. package/dist/parser/handlers.d.ts +0 -6
  24. package/dist/parser/handlers.js +54 -46
  25. package/dist/parser/handlers.js.map +1 -1
  26. package/dist/parser/states.d.ts +2 -2
  27. package/dist/parser/states.js +0 -20
  28. package/dist/parser/states.js.map +1 -1
  29. package/dist/types.d.ts +18 -7
  30. package/esm/Expression.d.ts +16 -6
  31. package/esm/Expression.js +34 -8
  32. package/esm/Expression.js.map +1 -1
  33. package/esm/Jexl.d.ts +13 -12
  34. package/esm/Jexl.js +31 -30
  35. package/esm/Jexl.js.map +1 -1
  36. package/esm/Lexer.d.ts +9 -8
  37. package/esm/Lexer.js +58 -18
  38. package/esm/Lexer.js.map +1 -1
  39. package/esm/evaluator/Evaluator.d.ts +20 -34
  40. package/esm/evaluator/Evaluator.js +19 -31
  41. package/esm/evaluator/Evaluator.js.map +1 -1
  42. package/esm/evaluator/compile.d.ts +27 -0
  43. package/esm/evaluator/compile.js +258 -0
  44. package/esm/evaluator/compile.js.map +1 -0
  45. package/esm/grammar.d.ts +29 -9
  46. package/esm/grammar.js +18 -3
  47. package/esm/grammar.js.map +1 -1
  48. package/esm/parser/Parser.d.ts +5 -7
  49. package/esm/parser/Parser.js +17 -2
  50. package/esm/parser/Parser.js.map +1 -1
  51. package/esm/parser/handlers.d.ts +0 -6
  52. package/esm/parser/handlers.js +54 -45
  53. package/esm/parser/handlers.js.map +1 -1
  54. package/esm/parser/states.d.ts +2 -2
  55. package/esm/parser/states.js +0 -20
  56. package/esm/parser/states.js.map +1 -1
  57. package/esm/types.d.ts +18 -7
  58. package/package.json +25 -28
  59. package/src/Expression.ts +33 -13
  60. package/src/Jexl.ts +59 -21
  61. package/src/Lexer.ts +60 -27
  62. package/src/evaluator/Evaluator.ts +27 -44
  63. package/src/evaluator/compile.ts +310 -0
  64. package/src/grammar.ts +66 -17
  65. package/src/parser/Parser.ts +24 -20
  66. package/src/parser/handlers.ts +96 -73
  67. package/src/parser/states.ts +2 -22
  68. package/src/types.ts +22 -7
  69. package/CHANGELOG.md +0 -249
  70. package/dist/evaluator/handlers.d.ts +0 -112
  71. package/dist/evaluator/handlers.js +0 -208
  72. package/dist/evaluator/handlers.js.map +0 -1
  73. package/esm/evaluator/handlers.d.ts +0 -112
  74. package/esm/evaluator/handlers.js +0 -194
  75. package/esm/evaluator/handlers.js.map +0 -1
  76. package/src/evaluator/handlers.ts +0 -212
@@ -1,194 +0,0 @@
1
- /*
2
- * Jexl
3
- * Copyright 2020 Tom Shawver
4
- */
5
- const poolNames = {
6
- functions: 'Jexl Function'
7
- };
8
- /**
9
- * Evaluates an ArrayLiteral by returning its value, with each element
10
- * independently run through the evaluator.
11
- * @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
12
- * ObjectLiteral as the top node
13
- * @returns {[]} an array of evaluated values.
14
- * @private
15
- */
16
- export function ArrayLiteral(ast) {
17
- return this.evalArray(ast.value);
18
- }
19
- /**
20
- * Evaluates a BinaryExpression node by running the Grammar's evaluator for
21
- * the given operator. Note that binary expressions support two types of
22
- * evaluators: `eval` is called with the left and right operands pre-evaluated.
23
- * `evalOnDemand`, if it exists, will be called with the left and right operands
24
- * each individually wrapped in an object with an "eval" function that returns
25
- * the resulting value. This allows the binary expression to evaluate the
26
- * operands conditionally.
27
- * @param {{type: 'BinaryExpression', operator: <string>, left: {},
28
- * right: {}}} ast An expression tree with a BinaryExpression as the top
29
- * node
30
- * @returns {*} the value of the BinaryExpression.
31
- * @private
32
- */
33
- export function BinaryExpression(ast) {
34
- const grammarOp = this._grammar.elements[ast.operator];
35
- if (grammarOp.evalOnDemand) {
36
- const wrap = (subAst) => ({ eval: () => this.eval(subAst) });
37
- return grammarOp.evalOnDemand(wrap(ast.left), wrap(ast.right));
38
- }
39
- const left = this.eval(ast.left);
40
- const right = this.eval(ast.right);
41
- return grammarOp.eval(left, right);
42
- }
43
- /**
44
- * Evaluates a ConditionalExpression node by first evaluating its test branch,
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.
48
- * @param {{type: 'ConditionalExpression', test: {}, consequent: {},
49
- * alternate: {}}} ast An expression tree with a ConditionalExpression as
50
- * the top node
51
- * @private
52
- */
53
- export function ConditionalExpression(ast) {
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);
59
- }
60
- /**
61
- * Evaluates a FilterExpression by applying bracket notation for array/object access.
62
- * Note: Relative filtering (with leading dot) is not supported.
63
- * @param {{type: 'FilterExpression', relative: <boolean>, expr: {},
64
- * subject: {}}} ast An expression tree with a FilterExpression as the top
65
- * node
66
- * @returns {*} the value at the specified index/property.
67
- * @private
68
- */
69
- export function FilterExpression(ast) {
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];
76
- }
77
- /**
78
- * Evaluates an Identifier by either stemming from the evaluated 'from'
79
- * expression tree or accessing the context provided when this Evaluator was
80
- * constructed.
81
- * @param {{type: 'Identifier', value: <string>, [from]: {}}} ast An expression
82
- * tree with an Identifier as the top node
83
- * @returns {*} the identifier's value.
84
- * @private
85
- */
86
- export function Identifier(ast) {
87
- if (!ast.from) {
88
- const contextSource = ast.relative ? this._relContext : this._context;
89
- return contextSource[ast.value];
90
- }
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];
97
- }
98
- /**
99
- * Evaluates a Literal by returning its value property.
100
- * @param {{type: 'Literal', value: <string|number|boolean>}} ast An expression
101
- * tree with a Literal as its only node
102
- * @returns {string|number|boolean} The value of the Literal node
103
- * @private
104
- */
105
- export function Literal(ast) {
106
- return ast.value;
107
- }
108
- /**
109
- * Evaluates a TemplateLiteral by evaluating each interpolated expression
110
- * and concatenating all parts into a final string.
111
- * @param {{type: 'TemplateLiteral', parts: Array<{}>}} ast An expression
112
- * tree with a TemplateLiteral as the top node
113
- * @returns {string} the final interpolated string
114
- * @private
115
- */
116
- export function TemplateLiteral(ast) {
117
- const values = ast.parts.map((part) => {
118
- if (part.type === 'static') {
119
- return part.value;
120
- }
121
- const result = this.eval(part.value);
122
- if (result == null) {
123
- return '';
124
- }
125
- return String(result);
126
- });
127
- return values.join('');
128
- }
129
- /**
130
- * Evaluates an ObjectLiteral by returning its value, with each key
131
- * independently run through the evaluator.
132
- * @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
133
- * ObjectLiteral as the top node
134
- * @returns {{}} a map of evaluated values.
135
- * @private
136
- */
137
- export function ObjectLiteral(ast) {
138
- return this.evalMap(ast.value);
139
- }
140
- /**
141
- * Evaluates a FunctionCall node by applying the supplied arguments to a
142
- * function defined in one of the grammar's function pools.
143
- * @param {{type: 'FunctionCall', name: <string>}} ast An
144
- * expression tree with a FunctionCall as the top node
145
- * @returns {*} the value of the function call.
146
- * @private
147
- */
148
- export function FunctionCall(ast) {
149
- const poolName = poolNames[ast.pool];
150
- if (!poolName) {
151
- throw new Error(`Corrupt AST: Pool '${ast.pool}' not found`);
152
- }
153
- const pool = this._grammar[ast.pool];
154
- const func = pool?.[ast.name];
155
- if (!func) {
156
- throw new Error(`${poolName} ${ast.name} is not defined.`);
157
- }
158
- const args = this.evalArray(ast.args || []);
159
- return func(...args);
160
- }
161
- /**
162
- * Evaluates a Unary expression by passing the right side through the
163
- * operator's eval function.
164
- * @param {{type: 'UnaryExpression', operator: <string>, right: {}}} ast An
165
- * expression tree with a UnaryExpression as the top node
166
- * @returns {*} the value of the UnaryExpression.
167
- * @constructor
168
- */
169
- export function UnaryExpression(ast) {
170
- const right = this.eval(ast.right);
171
- return this._grammar.elements[ast.operator].eval(right);
172
- }
173
- /**
174
- * Evaluates a SequenceExpression by evaluating each expression in order
175
- * and returning the value of the last expression.
176
- */
177
- export function SequenceExpression(ast) {
178
- let lastValue;
179
- for (const expr of ast.expressions) {
180
- lastValue = this.eval(expr);
181
- }
182
- return lastValue;
183
- }
184
- /**
185
- * Evaluates an AssignmentExpression by evaluating the right side
186
- * and assigning it to the variable name on the left side.
187
- */
188
- export function AssignmentExpression(ast) {
189
- const value = this.eval(ast.right);
190
- const varName = ast.left.value;
191
- this._context[varName] = value;
192
- return value;
193
- }
194
- //# sourceMappingURL=handlers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/evaluator/handlers.ts"],"names":[],"mappings":"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"}
@@ -1,212 +0,0 @@
1
- /*
2
- * Jexl
3
- * Copyright 2020 Tom Shawver
4
- */
5
-
6
- import type { AstNode } from '../types.ts'
7
- import type Evaluator from './Evaluator.ts'
8
-
9
- const poolNames: Record<string, string> = {
10
- functions: 'Jexl Function'
11
- }
12
-
13
- /**
14
- * Evaluates an ArrayLiteral by returning its value, with each element
15
- * independently run through the evaluator.
16
- * @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
17
- * ObjectLiteral as the top node
18
- * @returns {[]} an array of evaluated values.
19
- * @private
20
- */
21
- export function ArrayLiteral(this: Evaluator, ast: any) {
22
- return this.evalArray(ast.value)
23
- }
24
-
25
- /**
26
- * Evaluates a BinaryExpression node by running the Grammar's evaluator for
27
- * the given operator. Note that binary expressions support two types of
28
- * evaluators: `eval` is called with the left and right operands pre-evaluated.
29
- * `evalOnDemand`, if it exists, will be called with the left and right operands
30
- * each individually wrapped in an object with an "eval" function that returns
31
- * the resulting value. This allows the binary expression to evaluate the
32
- * operands conditionally.
33
- * @param {{type: 'BinaryExpression', operator: <string>, left: {},
34
- * right: {}}} ast An expression tree with a BinaryExpression as the top
35
- * node
36
- * @returns {*} the value of the BinaryExpression.
37
- * @private
38
- */
39
- export function BinaryExpression(this: Evaluator, ast: any) {
40
- const grammarOp = this._grammar.elements[ast.operator]
41
- if (grammarOp.evalOnDemand) {
42
- const wrap = (subAst: AstNode) => ({ eval: () => this.eval(subAst) })
43
- return grammarOp.evalOnDemand(wrap(ast.left), wrap(ast.right))
44
- }
45
- const left = this.eval(ast.left)
46
- const right = this.eval(ast.right)
47
- return grammarOp.eval(left, right)
48
- }
49
-
50
- /**
51
- * Evaluates a ConditionalExpression node by first evaluating its test branch,
52
- * and returning the consequent branch if the test is truthy, or the alternate
53
- * branch if it is not. If there is no consequent branch, the test result will
54
- * be used instead.
55
- * @param {{type: 'ConditionalExpression', test: {}, consequent: {},
56
- * alternate: {}}} ast An expression tree with a ConditionalExpression as
57
- * the top node
58
- * @private
59
- */
60
- export function ConditionalExpression(this: Evaluator, ast: any) {
61
- const res = this.eval(ast.test)
62
- if (res) {
63
- return ast.consequent ? this.eval(ast.consequent) : res
64
- }
65
- return this.eval(ast.alternate)
66
- }
67
-
68
- /**
69
- * Evaluates a FilterExpression by applying bracket notation for array/object access.
70
- * Note: Relative filtering (with leading dot) is not supported.
71
- * @param {{type: 'FilterExpression', relative: <boolean>, expr: {},
72
- * subject: {}}} ast An expression tree with a FilterExpression as the top
73
- * node
74
- * @returns {*} the value at the specified index/property.
75
- * @private
76
- */
77
- export function FilterExpression(this: Evaluator, ast: any) {
78
- const subject = this.eval(ast.subject)
79
- if (ast.relative) {
80
- throw new Error('Relative filter expressions are not supported')
81
- }
82
- const index = this.eval(ast.expr)
83
- return subject?.[index]
84
- }
85
-
86
- /**
87
- * Evaluates an Identifier by either stemming from the evaluated 'from'
88
- * expression tree or accessing the context provided when this Evaluator was
89
- * constructed.
90
- * @param {{type: 'Identifier', value: <string>, [from]: {}}} ast An expression
91
- * tree with an Identifier as the top node
92
- * @returns {*} the identifier's value.
93
- * @private
94
- */
95
- export function Identifier(this: Evaluator, ast: any) {
96
- if (!ast.from) {
97
- const contextSource = ast.relative ? this._relContext : this._context
98
- return contextSource[ast.value]
99
- }
100
- const context = this.eval(ast.from)
101
- if (context == null) {
102
- return undefined
103
- }
104
- const ctx = Array.isArray(context) ? context[0] : context
105
- return ctx?.[ast.value]
106
- }
107
-
108
- /**
109
- * Evaluates a Literal by returning its value property.
110
- * @param {{type: 'Literal', value: <string|number|boolean>}} ast An expression
111
- * tree with a Literal as its only node
112
- * @returns {string|number|boolean} The value of the Literal node
113
- * @private
114
- */
115
- export function Literal(this: Evaluator, ast: any) {
116
- return ast.value
117
- }
118
-
119
- /**
120
- * Evaluates a TemplateLiteral by evaluating each interpolated expression
121
- * and concatenating all parts into a final string.
122
- * @param {{type: 'TemplateLiteral', parts: Array<{}>}} ast An expression
123
- * tree with a TemplateLiteral as the top node
124
- * @returns {string} the final interpolated string
125
- * @private
126
- */
127
- export function TemplateLiteral(this: Evaluator, ast: any) {
128
- const values = ast.parts.map((part: any) => {
129
- if (part.type === 'static') {
130
- return part.value
131
- }
132
- const result = this.eval(part.value)
133
- if (result == null) {
134
- return ''
135
- }
136
- return String(result)
137
- })
138
-
139
- return values.join('')
140
- }
141
-
142
- /**
143
- * Evaluates an ObjectLiteral by returning its value, with each key
144
- * independently run through the evaluator.
145
- * @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
146
- * ObjectLiteral as the top node
147
- * @returns {{}} a map of evaluated values.
148
- * @private
149
- */
150
- export function ObjectLiteral(this: Evaluator, ast: any) {
151
- return this.evalMap(ast.value)
152
- }
153
-
154
- /**
155
- * Evaluates a FunctionCall node by applying the supplied arguments to a
156
- * function defined in one of the grammar's function pools.
157
- * @param {{type: 'FunctionCall', name: <string>}} ast An
158
- * expression tree with a FunctionCall as the top node
159
- * @returns {*} the value of the function call.
160
- * @private
161
- */
162
- export function FunctionCall(this: Evaluator, ast: any) {
163
- const poolName = poolNames[ast.pool]
164
- if (!poolName) {
165
- throw new Error(`Corrupt AST: Pool '${ast.pool}' not found`)
166
- }
167
- const pool = (this._grammar as any)[ast.pool]
168
- const func = pool?.[ast.name]
169
- if (!func) {
170
- throw new Error(`${poolName} ${ast.name} is not defined.`)
171
- }
172
- const args = this.evalArray(ast.args || [])
173
- return func(...args)
174
- }
175
-
176
- /**
177
- * Evaluates a Unary expression by passing the right side through the
178
- * operator's eval function.
179
- * @param {{type: 'UnaryExpression', operator: <string>, right: {}}} ast An
180
- * expression tree with a UnaryExpression as the top node
181
- * @returns {*} the value of the UnaryExpression.
182
- * @constructor
183
- */
184
- export function UnaryExpression(this: Evaluator, ast: any) {
185
- const right = this.eval(ast.right)
186
- return this._grammar.elements[ast.operator].eval(right)
187
- }
188
-
189
- /**
190
- * Evaluates a SequenceExpression by evaluating each expression in order
191
- * and returning the value of the last expression.
192
- */
193
- export function SequenceExpression(this: Evaluator, ast: any) {
194
- let lastValue: any
195
-
196
- for (const expr of ast.expressions) {
197
- lastValue = this.eval(expr)
198
- }
199
-
200
- return lastValue
201
- }
202
-
203
- /**
204
- * Evaluates an AssignmentExpression by evaluating the right side
205
- * and assigning it to the variable name on the left side.
206
- */
207
- export function AssignmentExpression(this: Evaluator, ast: any) {
208
- const value = this.eval(ast.right)
209
- const varName = ast.left.value
210
- this._context[varName] = value
211
- return value
212
- }