@jbrowse/jexl 2.3.1 → 3.0.1
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 +76 -74
- 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/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/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/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/package.json +2 -1
- package/src/Expression.ts +5 -36
- package/src/Jexl.ts +7 -54
- package/src/evaluator/Evaluator.ts +14 -92
- package/src/evaluator/handlers.ts +54 -68
- package/src/grammar.ts +17 -38
- 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
|
@@ -12,9 +12,6 @@ interface Grammar {
|
|
|
12
12
|
[key: string]: any
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
|
16
|
-
type PromiseConstructor = typeof Promise | any
|
|
17
|
-
|
|
18
15
|
/**
|
|
19
16
|
* The Evaluator takes a Jexl expression tree as generated by the
|
|
20
17
|
* {@link Parser} and calculates its value within a given context. The
|
|
@@ -26,127 +23,52 @@ type PromiseConstructor = typeof Promise | any
|
|
|
26
23
|
* @param {{}} grammar A grammar object against which to evaluate the expression
|
|
27
24
|
* tree
|
|
28
25
|
* @param {{}} [context] A map of variable keys to their values. This will be
|
|
29
|
-
* accessed to resolve the value of each non-relative identifier.
|
|
30
|
-
* Promise values will be passed to the expression as their resolved
|
|
31
|
-
* value.
|
|
26
|
+
* accessed to resolve the value of each non-relative identifier.
|
|
32
27
|
* @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
|
|
33
28
|
* to resolve the value of a relative identifier.
|
|
34
|
-
* @param {function} promise A constructor for the Promise class to be used;
|
|
35
|
-
* probably either Promise or PromiseSync.
|
|
36
29
|
*/
|
|
37
30
|
class Evaluator {
|
|
38
31
|
_grammar: Grammar
|
|
39
32
|
_context: any
|
|
40
33
|
_relContext: any
|
|
41
|
-
Promise: PromiseConstructor
|
|
42
34
|
|
|
43
|
-
constructor(
|
|
44
|
-
grammar: Grammar,
|
|
45
|
-
context?: any,
|
|
46
|
-
relativeContext?: any,
|
|
47
|
-
promise: PromiseConstructor = Promise
|
|
48
|
-
) {
|
|
35
|
+
constructor(grammar: Grammar, context?: any, relativeContext?: any) {
|
|
49
36
|
this._grammar = grammar
|
|
50
37
|
this._context = context || {}
|
|
51
38
|
this._relContext = relativeContext || this._context
|
|
52
|
-
this.Promise = promise
|
|
53
39
|
}
|
|
54
40
|
|
|
55
41
|
/**
|
|
56
42
|
* Evaluates an expression tree within the configured context.
|
|
57
43
|
* @param {{}} ast An expression tree object
|
|
58
|
-
* @returns {
|
|
44
|
+
* @returns {*} the resulting value of the expression.
|
|
59
45
|
*/
|
|
60
46
|
eval(ast: AstNode) {
|
|
61
|
-
return
|
|
62
|
-
return (handlers as any)[ast.type].call(this, ast)
|
|
63
|
-
})
|
|
47
|
+
return (handlers as any)[ast.type].call(this, ast)
|
|
64
48
|
}
|
|
65
49
|
|
|
66
50
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
51
|
+
* Evaluates each expression within an array, and delivers the response as an
|
|
52
|
+
* array with the resulting values at the same indexes as their originating
|
|
53
|
+
* expressions.
|
|
70
54
|
* @param {Array<string>} arr An array of expression strings to be evaluated
|
|
71
|
-
* @returns {
|
|
55
|
+
* @returns {Array<{}>} the result array
|
|
72
56
|
*/
|
|
73
57
|
evalArray(arr: AstNode[]) {
|
|
74
|
-
return
|
|
58
|
+
return arr.map((elem: AstNode) => this.eval(elem))
|
|
75
59
|
}
|
|
76
60
|
|
|
77
61
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* as their value.
|
|
62
|
+
* Evaluates each expression within a map, and delivers the response as a map
|
|
63
|
+
* with the same keys, but with the evaluated result for each as their value.
|
|
81
64
|
* @param {{}} map A map of expression names to expression trees to be
|
|
82
65
|
* evaluated
|
|
83
|
-
* @returns {
|
|
66
|
+
* @returns {{}} the result map.
|
|
84
67
|
*/
|
|
85
68
|
evalMap(map: Record<string, AstNode>) {
|
|
86
69
|
const entries = Object.entries(map)
|
|
87
|
-
const
|
|
88
|
-
return
|
|
89
|
-
Object.fromEntries(entries.map(([key], idx) => [key, vals[idx]]))
|
|
90
|
-
)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Applies a filter expression with relative identifier elements to a subject.
|
|
95
|
-
* The intent is for the subject to be an array of subjects that will be
|
|
96
|
-
* individually used as the relative context against the provided expression
|
|
97
|
-
* tree. Only the elements whose expressions result in a truthy value will be
|
|
98
|
-
* included in the resulting array.
|
|
99
|
-
*
|
|
100
|
-
* If the subject is not an array of values, it will be converted to a single-
|
|
101
|
-
* element array before running the filter.
|
|
102
|
-
* @param {*} subject The value to be filtered usually an array. If this value is
|
|
103
|
-
* not an array, it will be converted to an array with this value as the
|
|
104
|
-
* only element.
|
|
105
|
-
* @param {{}} expr The expression tree to run against each subject. If the
|
|
106
|
-
* tree evaluates to a truthy result, then the value will be included in
|
|
107
|
-
* the returned array otherwise, it will be eliminated.
|
|
108
|
-
* @returns {Promise<Array>} resolves with an array of values that passed the
|
|
109
|
-
* expression filter.
|
|
110
|
-
* @private
|
|
111
|
-
*/
|
|
112
|
-
_filterRelative(subject: any, expr: AstNode) {
|
|
113
|
-
const arr = Array.isArray(subject)
|
|
114
|
-
? subject
|
|
115
|
-
: subject == null
|
|
116
|
-
? []
|
|
117
|
-
: [subject]
|
|
118
|
-
|
|
119
|
-
const promises = arr.map((elem) =>
|
|
120
|
-
new Evaluator(this._grammar, this._context, elem, this.Promise).eval(expr)
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
return this.Promise.all(promises).then((values: any[]) =>
|
|
124
|
-
arr.filter((_, idx) => values[idx])
|
|
125
|
-
)
|
|
126
|
-
}
|
|
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: any, expr: AstNode) {
|
|
144
|
-
return this.eval(expr).then((res: any) => {
|
|
145
|
-
if (typeof res === 'boolean') {
|
|
146
|
-
return res ? subject : undefined
|
|
147
|
-
}
|
|
148
|
-
return subject?.[res]
|
|
149
|
-
})
|
|
70
|
+
const vals = entries.map(([_, ast]) => this.eval(ast))
|
|
71
|
+
return Object.fromEntries(entries.map(([key], idx) => [key, vals[idx]]))
|
|
150
72
|
}
|
|
151
73
|
}
|
|
152
74
|
|
|
@@ -7,8 +7,7 @@ import type { AstNode } from '../types.ts'
|
|
|
7
7
|
import type Evaluator from './Evaluator.ts'
|
|
8
8
|
|
|
9
9
|
const poolNames: Record<string, string> = {
|
|
10
|
-
functions: 'Jexl Function'
|
|
11
|
-
transforms: 'Transform'
|
|
10
|
+
functions: 'Jexl Function'
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -16,7 +15,7 @@ const poolNames: Record<string, string> = {
|
|
|
16
15
|
* independently run through the evaluator.
|
|
17
16
|
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
18
17
|
* ObjectLiteral as the top node
|
|
19
|
-
* @returns {
|
|
18
|
+
* @returns {[]} an array of evaluated values.
|
|
20
19
|
* @private
|
|
21
20
|
*/
|
|
22
21
|
export function ArrayLiteral(this: Evaluator, ast: any) {
|
|
@@ -29,12 +28,12 @@ export function ArrayLiteral(this: Evaluator, ast: any) {
|
|
|
29
28
|
* evaluators: `eval` is called with the left and right operands pre-evaluated.
|
|
30
29
|
* `evalOnDemand`, if it exists, will be called with the left and right operands
|
|
31
30
|
* each individually wrapped in an object with an "eval" function that returns
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* the resulting value. This allows the binary expression to evaluate the
|
|
32
|
+
* operands conditionally.
|
|
34
33
|
* @param {{type: 'BinaryExpression', operator: <string>, left: {},
|
|
35
34
|
* right: {}}} ast An expression tree with a BinaryExpression as the top
|
|
36
35
|
* node
|
|
37
|
-
* @returns {
|
|
36
|
+
* @returns {*} the value of the BinaryExpression.
|
|
38
37
|
* @private
|
|
39
38
|
*/
|
|
40
39
|
export function BinaryExpression(this: Evaluator, ast: any) {
|
|
@@ -43,48 +42,45 @@ export function BinaryExpression(this: Evaluator, ast: any) {
|
|
|
43
42
|
const wrap = (subAst: AstNode) => ({ eval: () => this.eval(subAst) })
|
|
44
43
|
return grammarOp.evalOnDemand(wrap(ast.left), wrap(ast.right))
|
|
45
44
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
)
|
|
45
|
+
const left = this.eval(ast.left)
|
|
46
|
+
const right = this.eval(ast.right)
|
|
47
|
+
return grammarOp.eval(left, right)
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
/**
|
|
52
51
|
* Evaluates a ConditionalExpression node by first evaluating its test branch,
|
|
53
|
-
* and
|
|
54
|
-
*
|
|
55
|
-
*
|
|
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.
|
|
56
55
|
* @param {{type: 'ConditionalExpression', test: {}, consequent: {},
|
|
57
56
|
* alternate: {}}} ast An expression tree with a ConditionalExpression as
|
|
58
57
|
* the top node
|
|
59
58
|
* @private
|
|
60
59
|
*/
|
|
61
60
|
export function ConditionalExpression(this: Evaluator, ast: any) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return res
|
|
68
|
-
}
|
|
69
|
-
return this.eval(ast.alternate)
|
|
70
|
-
})
|
|
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)
|
|
71
66
|
}
|
|
72
67
|
|
|
73
68
|
/**
|
|
74
|
-
* Evaluates a FilterExpression by applying
|
|
69
|
+
* Evaluates a FilterExpression by applying bracket notation for array/object access.
|
|
70
|
+
* Note: Relative filtering (with leading dot) is not supported.
|
|
75
71
|
* @param {{type: 'FilterExpression', relative: <boolean>, expr: {},
|
|
76
72
|
* subject: {}}} ast An expression tree with a FilterExpression as the top
|
|
77
73
|
* node
|
|
78
|
-
* @returns {
|
|
74
|
+
* @returns {*} the value at the specified index/property.
|
|
79
75
|
* @private
|
|
80
76
|
*/
|
|
81
77
|
export function FilterExpression(this: Evaluator, ast: any) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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]
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
/**
|
|
@@ -93,8 +89,7 @@ export function FilterExpression(this: Evaluator, ast: any) {
|
|
|
93
89
|
* constructed.
|
|
94
90
|
* @param {{type: 'Identifier', value: <string>, [from]: {}}} ast An expression
|
|
95
91
|
* tree with an Identifier as the top node
|
|
96
|
-
* @returns {
|
|
97
|
-
* will resolve with the identifier's value.
|
|
92
|
+
* @returns {*} the identifier's value.
|
|
98
93
|
* @private
|
|
99
94
|
*/
|
|
100
95
|
export function Identifier(this: Evaluator, ast: any) {
|
|
@@ -102,13 +97,12 @@ export function Identifier(this: Evaluator, ast: any) {
|
|
|
102
97
|
const contextSource = ast.relative ? this._relContext : this._context
|
|
103
98
|
return contextSource[ast.value]
|
|
104
99
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
})
|
|
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]
|
|
112
106
|
}
|
|
113
107
|
|
|
114
108
|
/**
|
|
@@ -127,23 +121,22 @@ export function Literal(this: Evaluator, ast: any) {
|
|
|
127
121
|
* and concatenating all parts into a final string.
|
|
128
122
|
* @param {{type: 'TemplateLiteral', parts: Array<{}>}} ast An expression
|
|
129
123
|
* tree with a TemplateLiteral as the top node
|
|
130
|
-
* @returns {
|
|
124
|
+
* @returns {string} the final interpolated string
|
|
131
125
|
* @private
|
|
132
126
|
*/
|
|
133
127
|
export function TemplateLiteral(this: Evaluator, ast: any) {
|
|
134
|
-
const
|
|
128
|
+
const values = ast.parts.map((part: any) => {
|
|
135
129
|
if (part.type === 'static') {
|
|
136
|
-
return
|
|
130
|
+
return part.value
|
|
137
131
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
})
|
|
132
|
+
const result = this.eval(part.value)
|
|
133
|
+
if (result == null) {
|
|
134
|
+
return ''
|
|
135
|
+
}
|
|
136
|
+
return String(result)
|
|
144
137
|
})
|
|
145
138
|
|
|
146
|
-
return
|
|
139
|
+
return values.join('')
|
|
147
140
|
}
|
|
148
141
|
|
|
149
142
|
/**
|
|
@@ -151,7 +144,7 @@ export function TemplateLiteral(this: Evaluator, ast: any) {
|
|
|
151
144
|
* independently run through the evaluator.
|
|
152
145
|
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
153
146
|
* ObjectLiteral as the top node
|
|
154
|
-
* @returns {
|
|
147
|
+
* @returns {{}} a map of evaluated values.
|
|
155
148
|
* @private
|
|
156
149
|
*/
|
|
157
150
|
export function ObjectLiteral(this: Evaluator, ast: any) {
|
|
@@ -163,8 +156,7 @@ export function ObjectLiteral(this: Evaluator, ast: any) {
|
|
|
163
156
|
* function defined in one of the grammar's function pools.
|
|
164
157
|
* @param {{type: 'FunctionCall', name: <string>}} ast An
|
|
165
158
|
* expression tree with a FunctionCall as the top node
|
|
166
|
-
* @returns {
|
|
167
|
-
* will resolve with the resulting value.
|
|
159
|
+
* @returns {*} the value of the function call.
|
|
168
160
|
* @private
|
|
169
161
|
*/
|
|
170
162
|
export function FunctionCall(this: Evaluator, ast: any) {
|
|
@@ -177,7 +169,8 @@ export function FunctionCall(this: Evaluator, ast: any) {
|
|
|
177
169
|
if (!func) {
|
|
178
170
|
throw new Error(`${poolName} ${ast.name} is not defined.`)
|
|
179
171
|
}
|
|
180
|
-
|
|
172
|
+
const args = this.evalArray(ast.args || [])
|
|
173
|
+
return func(...args)
|
|
181
174
|
}
|
|
182
175
|
|
|
183
176
|
/**
|
|
@@ -185,13 +178,12 @@ export function FunctionCall(this: Evaluator, ast: any) {
|
|
|
185
178
|
* operator's eval function.
|
|
186
179
|
* @param {{type: 'UnaryExpression', operator: <string>, right: {}}} ast An
|
|
187
180
|
* expression tree with a UnaryExpression as the top node
|
|
188
|
-
* @returns {
|
|
181
|
+
* @returns {*} the value of the UnaryExpression.
|
|
189
182
|
* @constructor
|
|
190
183
|
*/
|
|
191
184
|
export function UnaryExpression(this: Evaluator, ast: any) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
)
|
|
185
|
+
const right = this.eval(ast.right)
|
|
186
|
+
return this._grammar.elements[ast.operator].eval(right)
|
|
195
187
|
}
|
|
196
188
|
|
|
197
189
|
/**
|
|
@@ -200,17 +192,12 @@ export function UnaryExpression(this: Evaluator, ast: any) {
|
|
|
200
192
|
*/
|
|
201
193
|
export function SequenceExpression(this: Evaluator, ast: any) {
|
|
202
194
|
let lastValue: any
|
|
203
|
-
let promise = this.Promise.resolve()
|
|
204
195
|
|
|
205
196
|
for (const expr of ast.expressions) {
|
|
206
|
-
|
|
207
|
-
this.eval(expr).then((val: any) => {
|
|
208
|
-
lastValue = val
|
|
209
|
-
})
|
|
210
|
-
)
|
|
197
|
+
lastValue = this.eval(expr)
|
|
211
198
|
}
|
|
212
199
|
|
|
213
|
-
return
|
|
200
|
+
return lastValue
|
|
214
201
|
}
|
|
215
202
|
|
|
216
203
|
/**
|
|
@@ -218,9 +205,8 @@ export function SequenceExpression(this: Evaluator, ast: any) {
|
|
|
218
205
|
* and assigning it to the variable name on the left side.
|
|
219
206
|
*/
|
|
220
207
|
export function AssignmentExpression(this: Evaluator, ast: any) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
})
|
|
208
|
+
const value = this.eval(ast.right)
|
|
209
|
+
const varName = ast.left.value
|
|
210
|
+
this._context[varName] = value
|
|
211
|
+
return value
|
|
226
212
|
}
|
package/src/grammar.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface BinaryOp {
|
|
|
9
9
|
type: 'binaryOp'
|
|
10
10
|
precedence: number
|
|
11
11
|
eval?: (left: any, right: any) => any
|
|
12
|
-
evalOnDemand?: (left: { eval: () =>
|
|
12
|
+
evalOnDemand?: (left: { eval: () => any }, right: { eval: () => any }) => any
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export interface UnaryOp {
|
|
@@ -27,7 +27,6 @@ export type GrammarElement = BinaryOp | UnaryOp | SimpleElement
|
|
|
27
27
|
export interface Grammar {
|
|
28
28
|
elements: Record<string, GrammarElement>
|
|
29
29
|
functions: Record<string, (...args: any[]) => any>
|
|
30
|
-
transforms: Record<string, (val: any, ...args: any[]) => any>
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
export const getGrammar = (): Grammar => ({
|
|
@@ -40,7 +39,6 @@ export const getGrammar = (): Grammar => ({
|
|
|
40
39
|
'.': { type: 'dot' },
|
|
41
40
|
'[': { type: 'openBracket' },
|
|
42
41
|
']': { type: 'closeBracket' },
|
|
43
|
-
'|': { type: 'pipe' },
|
|
44
42
|
'{': { type: 'openCurl' },
|
|
45
43
|
'}': { type: 'closeCurl' },
|
|
46
44
|
':': { type: 'colon' },
|
|
@@ -118,20 +116,22 @@ export const getGrammar = (): Grammar => ({
|
|
|
118
116
|
type: 'binaryOp',
|
|
119
117
|
precedence: 10,
|
|
120
118
|
evalOnDemand: (left, right) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return
|
|
124
|
-
}
|
|
119
|
+
const leftVal = left.eval()
|
|
120
|
+
if (!leftVal) {
|
|
121
|
+
return leftVal
|
|
122
|
+
}
|
|
123
|
+
return right.eval()
|
|
125
124
|
}
|
|
126
125
|
},
|
|
127
126
|
'||': {
|
|
128
127
|
type: 'binaryOp',
|
|
129
128
|
precedence: 10,
|
|
130
129
|
evalOnDemand: (left, right) => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return
|
|
134
|
-
}
|
|
130
|
+
const leftVal = left.eval()
|
|
131
|
+
if (leftVal) {
|
|
132
|
+
return leftVal
|
|
133
|
+
}
|
|
134
|
+
return right.eval()
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
in: {
|
|
@@ -169,32 +169,11 @@ export const getGrammar = (): Grammar => ({
|
|
|
169
169
|
* All of these are pre-evaluated to their actual values before calling
|
|
170
170
|
* the function.
|
|
171
171
|
*
|
|
172
|
-
* The Jexl function should return
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* appropriate when the function would normally return a value, but
|
|
178
|
-
* cannot due to some other failure.
|
|
179
|
-
*/
|
|
180
|
-
functions: {},
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* A map of transform names to transform functions. A transform function
|
|
184
|
-
* takes one ore more arguemnts:
|
|
185
|
-
*
|
|
186
|
-
* - {*} val: A value to be transformed
|
|
187
|
-
* - {*} ...args: A variable number of arguments passed to this transform.
|
|
188
|
-
* All of these are pre-evaluated to their actual values before calling
|
|
189
|
-
* the function.
|
|
190
|
-
*
|
|
191
|
-
* The transform function should return either the transformed value, or
|
|
192
|
-
* a Promises/A+ Promise object that resolves with the value and rejects
|
|
193
|
-
* or throws only when an unrecoverable error occurs. Transforms should
|
|
194
|
-
* generally return undefined when they don't make sense to be used on the
|
|
195
|
-
* given value type, rather than throw/reject. An error is only
|
|
196
|
-
* appropriate when the transform would normally return a value, but
|
|
197
|
-
* cannot due to some other failure.
|
|
172
|
+
* The Jexl function should return the resulting value, or throw when an
|
|
173
|
+
* unrecoverable error occurs. Functions should generally return undefined
|
|
174
|
+
* when they don't make sense to be used on the given value type, rather
|
|
175
|
+
* than throw. An error is only appropriate when the function would normally
|
|
176
|
+
* return a value, but cannot due to some other failure.
|
|
198
177
|
*/
|
|
199
|
-
|
|
178
|
+
functions: {}
|
|
200
179
|
})
|
package/src/types.ts
CHANGED
|
@@ -104,4 +104,7 @@ export type AstNodeUnion =
|
|
|
104
104
|
| SequenceExpression
|
|
105
105
|
| AssignmentExpression
|
|
106
106
|
|
|
107
|
-
export type NodeByType<T extends AstNodeUnion['type']> = Extract<
|
|
107
|
+
export type NodeByType<T extends AstNodeUnion['type']> = Extract<
|
|
108
|
+
AstNodeUnion,
|
|
109
|
+
{ type: T }
|
|
110
|
+
>
|
package/dist/PromiseSync.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
declare class PromiseSync<T = unknown> {
|
|
2
|
-
value?: T;
|
|
3
|
-
error?: unknown;
|
|
4
|
-
constructor(fn: (resolve: (val: T) => void, reject: (error: unknown) => void) => void);
|
|
5
|
-
catch<TResult = never>(rejected: (error: unknown) => TResult): PromiseSync<T | TResult>;
|
|
6
|
-
then<TResult1 = T, TResult2 = never>(resolved: (val: T) => TResult1, rejected?: (error: unknown) => TResult2): PromiseSync<TResult1 | TResult2>;
|
|
7
|
-
_reject(error: unknown): void;
|
|
8
|
-
_resolve(val: any): void;
|
|
9
|
-
static all<T>(vals: (PromiseSync<T> | T)[]): PromiseSync<T[]>;
|
|
10
|
-
static resolve<T>(val?: T): PromiseSync<T>;
|
|
11
|
-
static reject(error: unknown): PromiseSync<never>;
|
|
12
|
-
}
|
|
13
|
-
export default PromiseSync;
|
package/dist/PromiseSync.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Jexl
|
|
4
|
-
* Copyright 2020 Tom Shawver
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
class PromiseSync {
|
|
8
|
-
constructor(fn) {
|
|
9
|
-
fn(this._resolve.bind(this), this._reject.bind(this));
|
|
10
|
-
}
|
|
11
|
-
catch(rejected) {
|
|
12
|
-
if (this.error) {
|
|
13
|
-
try {
|
|
14
|
-
this._resolve(rejected(this.error));
|
|
15
|
-
}
|
|
16
|
-
catch (e) {
|
|
17
|
-
this._reject(e);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return this;
|
|
21
|
-
}
|
|
22
|
-
// eslint-disable-next-line unicorn/no-thenable
|
|
23
|
-
then(resolved, rejected) {
|
|
24
|
-
if (!this.error) {
|
|
25
|
-
try {
|
|
26
|
-
this._resolve(resolved(this.value));
|
|
27
|
-
}
|
|
28
|
-
catch (e) {
|
|
29
|
-
this._reject(e);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (rejected) {
|
|
33
|
-
this.catch(rejected);
|
|
34
|
-
}
|
|
35
|
-
return this;
|
|
36
|
-
}
|
|
37
|
-
_reject(error) {
|
|
38
|
-
this.value = undefined;
|
|
39
|
-
this.error = error;
|
|
40
|
-
}
|
|
41
|
-
_resolve(val) {
|
|
42
|
-
if (val instanceof PromiseSync) {
|
|
43
|
-
if (val.error) {
|
|
44
|
-
this._reject(val.error);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
this._resolve(val.value);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
this.value = val;
|
|
52
|
-
this.error = undefined;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
static all(vals) {
|
|
56
|
-
return new PromiseSync((resolve) => {
|
|
57
|
-
const resolved = vals.map((val) => {
|
|
58
|
-
while (val instanceof PromiseSync) {
|
|
59
|
-
if (val.error) {
|
|
60
|
-
if (val.error instanceof Error) {
|
|
61
|
-
throw val.error;
|
|
62
|
-
}
|
|
63
|
-
throw new Error(typeof val.error === 'string' ? val.error : JSON.stringify(val.error));
|
|
64
|
-
}
|
|
65
|
-
val = val.value;
|
|
66
|
-
}
|
|
67
|
-
return val;
|
|
68
|
-
});
|
|
69
|
-
resolve(resolved);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
static resolve(val) {
|
|
73
|
-
return new PromiseSync((resolve) => { resolve(val); });
|
|
74
|
-
}
|
|
75
|
-
static reject(error) {
|
|
76
|
-
return new PromiseSync((_, reject) => { reject(error); });
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
exports.default = PromiseSync;
|
|
80
|
-
//# sourceMappingURL=PromiseSync.js.map
|
package/dist/PromiseSync.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PromiseSync.js","sourceRoot":"","sources":["../src/PromiseSync.ts"],"names":[],"mappings":"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"}
|
package/esm/PromiseSync.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
declare class PromiseSync<T = unknown> {
|
|
2
|
-
value?: T;
|
|
3
|
-
error?: unknown;
|
|
4
|
-
constructor(fn: (resolve: (val: T) => void, reject: (error: unknown) => void) => void);
|
|
5
|
-
catch<TResult = never>(rejected: (error: unknown) => TResult): PromiseSync<T | TResult>;
|
|
6
|
-
then<TResult1 = T, TResult2 = never>(resolved: (val: T) => TResult1, rejected?: (error: unknown) => TResult2): PromiseSync<TResult1 | TResult2>;
|
|
7
|
-
_reject(error: unknown): void;
|
|
8
|
-
_resolve(val: any): void;
|
|
9
|
-
static all<T>(vals: (PromiseSync<T> | T)[]): PromiseSync<T[]>;
|
|
10
|
-
static resolve<T>(val?: T): PromiseSync<T>;
|
|
11
|
-
static reject(error: unknown): PromiseSync<never>;
|
|
12
|
-
}
|
|
13
|
-
export default PromiseSync;
|