@jbrowse/jexl 4.0.1 → 5.0.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.
- package/README.md +163 -20
- package/dist/Expression.d.ts +16 -0
- package/dist/Expression.js +28 -4
- package/dist/Expression.js.map +1 -1
- package/dist/Jexl.d.ts +20 -8
- package/dist/Jexl.js +34 -15
- package/dist/Jexl.js.map +1 -1
- package/dist/Lexer.d.ts +4 -3
- package/dist/Lexer.js +29 -21
- package/dist/Lexer.js.map +1 -1
- package/dist/analyze.d.ts +84 -0
- package/dist/analyze.js +259 -0
- package/dist/analyze.js.map +1 -0
- package/dist/check.d.ts +109 -0
- package/dist/check.js +1267 -0
- package/dist/check.js.map +1 -0
- package/dist/collections.d.ts +3 -0
- package/dist/collections.js +140 -0
- package/dist/collections.js.map +1 -0
- package/dist/conditions.d.ts +62 -0
- package/dist/conditions.js +207 -0
- package/dist/conditions.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/evaluator/compile.d.ts +10 -7
- package/dist/evaluator/compile.js +274 -97
- package/dist/evaluator/compile.js.map +1 -1
- package/dist/grammar.d.ts +19 -9
- package/dist/grammar.js +66 -40
- package/dist/grammar.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/operators.d.ts +34 -0
- package/dist/operators.js +131 -0
- package/dist/operators.js.map +1 -0
- package/dist/parser/Parser.d.ts +48 -91
- package/dist/parser/Parser.js +347 -221
- package/dist/parser/Parser.js.map +1 -1
- package/dist/types.d.ts +11 -5
- package/esm/Expression.d.ts +16 -0
- package/esm/Expression.js +28 -4
- package/esm/Expression.js.map +1 -1
- package/esm/Jexl.d.ts +20 -8
- package/esm/Jexl.js +34 -15
- package/esm/Jexl.js.map +1 -1
- package/esm/Lexer.d.ts +4 -3
- package/esm/Lexer.js +29 -21
- package/esm/Lexer.js.map +1 -1
- package/esm/analyze.d.ts +84 -0
- package/esm/analyze.js +256 -0
- package/esm/analyze.js.map +1 -0
- package/esm/check.d.ts +109 -0
- package/esm/check.js +1260 -0
- package/esm/check.js.map +1 -0
- package/esm/collections.d.ts +3 -0
- package/esm/collections.js +137 -0
- package/esm/collections.js.map +1 -0
- package/esm/conditions.d.ts +62 -0
- package/esm/conditions.js +200 -0
- package/esm/conditions.js.map +1 -0
- package/esm/errors.d.ts +5 -0
- package/esm/errors.js +14 -0
- package/esm/errors.js.map +1 -0
- package/esm/evaluator/compile.d.ts +10 -7
- package/esm/evaluator/compile.js +274 -97
- package/esm/evaluator/compile.js.map +1 -1
- package/esm/grammar.d.ts +19 -9
- package/esm/grammar.js +66 -39
- package/esm/grammar.js.map +1 -1
- package/esm/index.d.ts +9 -0
- package/esm/index.js +4 -0
- package/esm/index.js.map +1 -1
- package/esm/operators.d.ts +34 -0
- package/esm/operators.js +123 -0
- package/esm/operators.js.map +1 -0
- package/esm/parser/Parser.d.ts +48 -91
- package/esm/parser/Parser.js +349 -192
- package/esm/parser/Parser.js.map +1 -1
- package/esm/types.d.ts +11 -5
- package/package.json +1 -1
- package/src/Expression.ts +34 -4
- package/src/Jexl.ts +52 -16
- package/src/Lexer.ts +32 -21
- package/src/analyze.ts +378 -0
- package/src/check.ts +1682 -0
- package/src/collections.ts +148 -0
- package/src/conditions.ts +262 -0
- package/src/errors.ts +15 -0
- package/src/evaluator/compile.ts +332 -100
- package/src/grammar.ts +123 -42
- package/src/index.ts +15 -0
- package/src/operators.ts +151 -0
- package/src/parser/Parser.ts +389 -199
- package/src/types.ts +13 -3
- package/dist/parser/handlers.d.ts +0 -115
- package/dist/parser/handlers.js +0 -352
- package/dist/parser/handlers.js.map +0 -1
- package/dist/parser/states.d.ts +0 -47
- package/dist/parser/states.js +0 -176
- package/dist/parser/states.js.map +0 -1
- package/esm/parser/handlers.d.ts +0 -115
- package/esm/parser/handlers.js +0 -328
- package/esm/parser/handlers.js.map +0 -1
- package/esm/parser/states.d.ts +0 -47
- package/esm/parser/states.js +0 -140
- package/esm/parser/states.js.map +0 -1
- package/src/parser/handlers.ts +0 -372
- package/src/parser/states.ts +0 -159
package/README.md
CHANGED
|
@@ -9,6 +9,12 @@ Major changes include
|
|
|
9
9
|
- Remove array filtering expressions
|
|
10
10
|
- Added template strings
|
|
11
11
|
- Added multiple expression evaluation
|
|
12
|
+
- Added lambdas and collection functions (`any(xs, x => x > 1)`)
|
|
13
|
+
- Added host hooks for member and name resolution
|
|
14
|
+
- Added `analyze()`, which reports what an expression reads without running it
|
|
15
|
+
- Added `check()`, which checks an expression against a host's fields and
|
|
16
|
+
functions, and `print()`, which renders a parsed expression back to text
|
|
17
|
+
- Added bcftools-style list operators, regex matching (`~`) and aggregates
|
|
12
18
|
|
|
13
19
|
## Quick Examples
|
|
14
20
|
|
|
@@ -54,9 +60,10 @@ jexl.eval('assoc[1].first', context)
|
|
|
54
60
|
| Type | Examples |
|
|
55
61
|
| ---------------- | ---------------------------------------------------- |
|
|
56
62
|
| Booleans | `true`, `false` |
|
|
63
|
+
| Null | `null` |
|
|
57
64
|
| Strings | `"Hello \"user\""`, `'Hey there!'` |
|
|
58
65
|
| Template Strings | `` `Hello ${name}` ``, `` `Total: ${price * qty}` `` |
|
|
59
|
-
| Numerics | `6`, `-7.2`,
|
|
66
|
+
| Numerics | `6`, `-7.2`, `.5`, `1e3`, `-5e-8` |
|
|
60
67
|
| Objects | `{hello: "world!"}` |
|
|
61
68
|
| Arrays | `['hello', 'world!']` |
|
|
62
69
|
|
|
@@ -89,7 +96,10 @@ jexl.eval('`Price: \\$100`')
|
|
|
89
96
|
|
|
90
97
|
- Arithmetic: `+`, `-`, `*`, `/`, `//` (floor division), `%`, `^` (power)
|
|
91
98
|
- Comparison: `==`, `!=`, `>`, `>=`, `<`, `<=`, `in`
|
|
92
|
-
-
|
|
99
|
+
- Regular expression match: `~`, `!~` (`name ~ '^BRCA'`; a leading `(?i)`
|
|
100
|
+
ignores case)
|
|
101
|
+
- Logical: `&&`, `||`, `??` (`a ?? b` is `b` only when `a` is `null` or
|
|
102
|
+
`undefined`, so `score ?? 0` keeps a real 0)
|
|
93
103
|
- Assignment: `=` (assigns a value to a bare variable name; `a.b = 1` is not
|
|
94
104
|
supported)
|
|
95
105
|
|
|
@@ -97,6 +107,67 @@ jexl.eval('`Price: \\$100`')
|
|
|
97
107
|
|
|
98
108
|
**Sequence:** `;` (separates multiple expressions)
|
|
99
109
|
|
|
110
|
+
From loosest to tightest:
|
|
111
|
+
|
|
112
|
+
| Operators | Groups |
|
|
113
|
+
| ------------------------------------------------- | ------------------ |
|
|
114
|
+
| `;` | |
|
|
115
|
+
| `=`, lambdas | right to left |
|
|
116
|
+
| `? :` | right to left |
|
|
117
|
+
| `\|\|`, `??` | left to right |
|
|
118
|
+
| `&&` | left to right |
|
|
119
|
+
| `==`, `!=`, `>`, `>=`, `<`, `<=`, `in`, `~`, `!~` | left to right |
|
|
120
|
+
| `+`, `-` | left to right |
|
|
121
|
+
| `*`, `/`, `//` | left to right |
|
|
122
|
+
| `%`, `^` | `^` from the right |
|
|
123
|
+
| prefix `!`, `-` | |
|
|
124
|
+
| `.`, `[]`, calls | left to right |
|
|
125
|
+
|
|
126
|
+
As in JavaScript, `??` does not mix with `&&` or `||` without parentheses:
|
|
127
|
+
`a ?? b || c` is a syntax error, `(a ?? b) || c` is not.
|
|
128
|
+
|
|
129
|
+
### Lists
|
|
130
|
+
|
|
131
|
+
Operators read a list the way bcftools reads a multi-valued VCF tag.
|
|
132
|
+
|
|
133
|
+
A comparison holds when it holds for any value of the list, and `!=` and `!~`
|
|
134
|
+
hold when no value matches, so each stays the negation of `==` and `~`:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
const context = {
|
|
138
|
+
AF: [0.01, 0.2],
|
|
139
|
+
FILTER: ['PASS'],
|
|
140
|
+
CSQ: ['T|missense_variant|MODERATE', 'T|synonymous_variant|LOW']
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
jexl.eval('AF > 0.05', context) // true: the second allele's frequency is
|
|
144
|
+
jexl.eval("FILTER != 'PASS'", context) // false
|
|
145
|
+
jexl.eval("CSQ ~ 'missense_variant'", context) // true
|
|
146
|
+
jexl.eval("['DEL'] in ['DEL', 'INS']") // true
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Arithmetic pairs lists value by value, and a single value, or a list of one,
|
|
150
|
+
pairs with every value of the other side:
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
jexl.eval('AC / AN', { AC: [2, 4], AN: [10] }) // [0.2, 0.4]
|
|
154
|
+
jexl.eval('DP + 1', { DP: [25] }) // [26]
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`in` finds a substring of a string, a member of a list or Set, or a key of an
|
|
158
|
+
object or Map, so a host can hand an expression a gene list loaded from a file
|
|
159
|
+
as a Set: `name in genes`.
|
|
160
|
+
|
|
161
|
+
`sum`, `mean`, `median`, `min` and `max` aggregate a list, reading each value
|
|
162
|
+
through an optional lambda. They skip missing values, and count a boolean as 1
|
|
163
|
+
or 0, which makes `mean` of a test the fraction that pass:
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
jexl.eval('min(DV / DP) > 0.3', context) // bcftools MIN(DV/DP)>0.3
|
|
167
|
+
jexl.eval('count(samples, s => s.GQ > 90)', context) // bcftools N_PASS(GQ>90)
|
|
168
|
+
jexl.eval('mean(samples, s => s.GQ > 90)', context) // bcftools F_PASS(GQ>90)
|
|
169
|
+
```
|
|
170
|
+
|
|
100
171
|
### Identifiers
|
|
101
172
|
|
|
102
173
|
Access context variables by name. Use dot notation or brackets for nested properties:
|
|
@@ -112,21 +183,25 @@ jexl.eval('name.first', context) // "Malory"
|
|
|
112
183
|
jexl.eval('name["last"]', context) // "Archer"
|
|
113
184
|
jexl.eval('exes[2]', context) // "Burt"
|
|
114
185
|
jexl.eval('exes[lastEx - 1]', context) // "Len"
|
|
186
|
+
jexl.eval('exes.length', context) // 3
|
|
115
187
|
```
|
|
116
188
|
|
|
189
|
+
A name chained off an array reads the array itself, so `exes.length` is 3 and
|
|
190
|
+
`list.name` is `undefined`; index the element you mean, `list[0].name`.
|
|
191
|
+
|
|
117
192
|
### Functions
|
|
118
193
|
|
|
119
194
|
Call functions in expressions:
|
|
120
195
|
|
|
121
196
|
```javascript
|
|
122
|
-
jexl.addFunction('
|
|
123
|
-
jexl.addFunction('
|
|
197
|
+
jexl.addFunction('log10', Math.log10)
|
|
198
|
+
jexl.addFunction('round', Math.round)
|
|
124
199
|
|
|
125
|
-
jexl.eval('
|
|
126
|
-
//
|
|
200
|
+
jexl.eval('round(log10(1234))')
|
|
201
|
+
// 3
|
|
127
202
|
|
|
128
|
-
jexl.eval('
|
|
129
|
-
//
|
|
203
|
+
jexl.eval('-log10(pvalue) > threshold', { pvalue: 1e-9, threshold: 8 })
|
|
204
|
+
// true
|
|
130
205
|
```
|
|
131
206
|
|
|
132
207
|
Functions live in one global pool and have no receiver, so a call written
|
|
@@ -144,9 +219,27 @@ jexl.eval("split(refName, ' ')[0]", { refName: 'chr1 description' }) // "chr1"
|
|
|
144
219
|
Note that this is a naming convention, not method dispatch: `a.b(x)` calls the
|
|
145
220
|
function named `b` in the pool, never a method on the value of `a`.
|
|
146
221
|
|
|
222
|
+
### Lambdas
|
|
223
|
+
|
|
224
|
+
`x => body` and `(a, b) => body` are functions a registered function can call.
|
|
225
|
+
A parameter shadows the context variable of the same name; any other name reads
|
|
226
|
+
the context. A lambda body cannot assign.
|
|
227
|
+
|
|
228
|
+
Jexl registers `any`, `all`, `count`, `map`, `filter`, `find`, `sort` and
|
|
229
|
+
`reduce`, each taking a list and a lambda, and the aggregates above. A lone value counts as a list of one
|
|
230
|
+
and a missing value as an empty list, which suits VCF INFO fields:
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
jexl.eval('any(feature.INFO.AF, af => af > 0.05)', context)
|
|
234
|
+
jexl.eval('map(xs, (x, i) => x * i)', { xs: [1, 2, 3] }) // [0, 2, 6]
|
|
235
|
+
jexl.eval('xs.filter(x => x > 1)', { xs: [1, 2, 3] }) // [2, 3]
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
A host function of the same name replaces the built-in one.
|
|
239
|
+
|
|
147
240
|
### Variable Assignment
|
|
148
241
|
|
|
149
|
-
Assign values to variables using `=` (no `let`, `var`, or `const` needed).
|
|
242
|
+
Assign values to variables using `=` (no `let`, `var`, or `const` needed). An assignment returns the assigned value, and the variable lasts for the rest of that evaluation. The context is never written to, so one context object can be reused across evaluations:
|
|
150
243
|
|
|
151
244
|
```javascript
|
|
152
245
|
jexl.eval('x = 5')
|
|
@@ -158,13 +251,14 @@ jexl.eval('x = 5; x * 2')
|
|
|
158
251
|
jexl.eval('x = 5; y = 10; x + y')
|
|
159
252
|
// 15
|
|
160
253
|
|
|
161
|
-
const context = {}
|
|
162
|
-
jexl.eval('
|
|
163
|
-
//
|
|
164
|
-
// context is
|
|
254
|
+
const context = { x: 1 }
|
|
255
|
+
jexl.eval('y = x * 2; x = y + 1; x', context)
|
|
256
|
+
// 3
|
|
257
|
+
// context is still { x: 1 }
|
|
165
258
|
```
|
|
166
259
|
|
|
167
|
-
Separate multiple expressions with semicolons. The result is the value of the
|
|
260
|
+
Separate multiple expressions with semicolons. The result is the value of the
|
|
261
|
+
last expression.
|
|
168
262
|
|
|
169
263
|
## API
|
|
170
264
|
|
|
@@ -190,15 +284,14 @@ jexl.addFunction('lower', (str) => str.toLowerCase())
|
|
|
190
284
|
|
|
191
285
|
// Add multiple functions
|
|
192
286
|
jexl.addFunctions({
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
abs: Math.abs
|
|
287
|
+
abs: Math.abs,
|
|
288
|
+
sqrt: Math.sqrt
|
|
196
289
|
})
|
|
197
290
|
|
|
198
291
|
// Use in expressions
|
|
199
292
|
jexl.eval('round(3.7)') // 4
|
|
200
293
|
jexl.eval('lower(name)', { name: 'HELLO' }) // "hello"
|
|
201
|
-
jexl.eval('
|
|
294
|
+
jexl.eval('sqrt(abs(-16))') // 4
|
|
202
295
|
```
|
|
203
296
|
|
|
204
297
|
### Adding Custom Operators
|
|
@@ -214,11 +307,61 @@ jexl.addBinaryOp(
|
|
|
214
307
|
jexl.eval('"Hello" ~= "hello"') // true
|
|
215
308
|
|
|
216
309
|
// Add a unary operator
|
|
217
|
-
jexl.addUnaryOp('
|
|
310
|
+
jexl.addUnaryOp('#', (right) => Math.floor(right))
|
|
218
311
|
|
|
219
|
-
jexl.eval('
|
|
312
|
+
jexl.eval('#3.7') // 3
|
|
220
313
|
```
|
|
221
314
|
|
|
315
|
+
### Resolving Names Through the Host
|
|
316
|
+
|
|
317
|
+
When the values in a context keep their fields behind an accessor, a Jexl instance can resolve names itself instead of reading plain properties. Both hooks are fixed when the instance is constructed.
|
|
318
|
+
|
|
319
|
+
```javascript
|
|
320
|
+
import { Jexl } from '@jbrowse/jexl'
|
|
321
|
+
|
|
322
|
+
const jexl = new Jexl({
|
|
323
|
+
// `a.b` and `a[k]`, on any value that isn't null or undefined
|
|
324
|
+
getMember: (subject, key) =>
|
|
325
|
+
subject instanceof Feature ? subject.get(key) : subject[key],
|
|
326
|
+
// a bare name, asked once per name as an expression compiles; returning
|
|
327
|
+
// undefined keeps the plain `context[name]` read
|
|
328
|
+
variableReader: (name) =>
|
|
329
|
+
name === 'feature'
|
|
330
|
+
? undefined
|
|
331
|
+
: (context) => context.feature.get(name) ?? context[name]
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
const expr = jexl.compile('feature.score > 10 && -log10(pvalue) > 2')
|
|
335
|
+
const context = { feature: undefined }
|
|
336
|
+
for (const feature of features) {
|
|
337
|
+
context.feature = feature
|
|
338
|
+
expr.eval(context)
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
A name the expression assigns reads the assignment once it has run, and goes through `variableReader` before then.
|
|
343
|
+
|
|
344
|
+
### Analyzing Expressions
|
|
345
|
+
|
|
346
|
+
`analyze` reports what an expression reads, without evaluating it or needing
|
|
347
|
+
its functions registered:
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
const expr = jexl.compile("get(feature, 'score') > 10 ? feature.name : 'n/a'")
|
|
351
|
+
expr.analyze({ accessors: { get: [] }, row: 'feature' })
|
|
352
|
+
// {
|
|
353
|
+
// variables: ['feature'],
|
|
354
|
+
// fields: [{ path: ['score'] }, { path: ['name'] }],
|
|
355
|
+
// bare: false,
|
|
356
|
+
// ...
|
|
357
|
+
// }
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
`accessors` names functions that read a path off their first argument, so
|
|
361
|
+
`get(feature, 'score')` and `feature.score` both read the field `score`. An
|
|
362
|
+
expression with no `variables` is a constant; one whose `bare` is true is only
|
|
363
|
+
a path, which a host can read without jexl.
|
|
364
|
+
|
|
222
365
|
## License
|
|
223
366
|
|
|
224
367
|
MIT License, same as TomFrost/Jexl
|
package/dist/Expression.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import Lexer from './Lexer.ts';
|
|
2
|
+
import type { AnalyzeOptions } from './analyze.ts';
|
|
3
|
+
import type { CheckOptions } from './check.ts';
|
|
2
4
|
import type { CompiledNode } from './evaluator/compile.ts';
|
|
3
5
|
import type { Grammar } from './grammar.ts';
|
|
4
6
|
import type { AstNode } from './types.ts';
|
|
@@ -36,5 +38,19 @@ declare class Expression {
|
|
|
36
38
|
* @throws {*} on error
|
|
37
39
|
*/
|
|
38
40
|
eval(context?: {}): import("./types.ts").JexlValue;
|
|
41
|
+
/** The expression text this Expression was made from. */
|
|
42
|
+
get source(): string;
|
|
43
|
+
/** The parsed tree, or null for an expression with no tokens. */
|
|
44
|
+
get ast(): AstNode | null;
|
|
45
|
+
/**
|
|
46
|
+
* Lists what the expression reads from its context, without evaluating it.
|
|
47
|
+
* See {@link analyze}.
|
|
48
|
+
*/
|
|
49
|
+
analyze(options?: AnalyzeOptions): import("./analyze.ts").Analysis;
|
|
50
|
+
/**
|
|
51
|
+
* Checks the expression against a host's fields and functions, without
|
|
52
|
+
* evaluating it. See {@link check}.
|
|
53
|
+
*/
|
|
54
|
+
check(options?: CheckOptions): import("./check.ts").CheckResult;
|
|
39
55
|
}
|
|
40
56
|
export default Expression;
|
package/dist/Expression.js
CHANGED
|
@@ -8,6 +8,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
const Lexer_ts_1 = __importDefault(require("./Lexer.js"));
|
|
11
|
+
const analyze_ts_1 = require("./analyze.js");
|
|
12
|
+
const check_ts_1 = require("./check.js");
|
|
11
13
|
const compile_ts_1 = require("./evaluator/compile.js");
|
|
12
14
|
const Parser_ts_1 = __importDefault(require("./parser/Parser.js"));
|
|
13
15
|
class Expression {
|
|
@@ -42,10 +44,7 @@ class Expression {
|
|
|
42
44
|
* @returns {Expression} this Expression instance, for convenience
|
|
43
45
|
*/
|
|
44
46
|
compile() {
|
|
45
|
-
|
|
46
|
-
const tokens = this._lexer.tokenize(this._exprStr);
|
|
47
|
-
parser.addTokens(tokens);
|
|
48
|
-
this._ast = parser.complete();
|
|
47
|
+
this._ast = new Parser_ts_1.default(this._grammar, this._lexer).parse(this._exprStr);
|
|
49
48
|
// lower the tree to closures once, here, so that eval() is just a call
|
|
50
49
|
this._fn = this._ast ? (0, compile_ts_1.compileAst)(this._ast, this._grammar) : null;
|
|
51
50
|
this._compiled = true;
|
|
@@ -68,6 +67,31 @@ class Expression {
|
|
|
68
67
|
}
|
|
69
68
|
return this._fn(context);
|
|
70
69
|
}
|
|
70
|
+
/** The expression text this Expression was made from. */
|
|
71
|
+
get source() {
|
|
72
|
+
return this._exprStr;
|
|
73
|
+
}
|
|
74
|
+
/** The parsed tree, or null for an expression with no tokens. */
|
|
75
|
+
get ast() {
|
|
76
|
+
if (!this._compiled) {
|
|
77
|
+
this.compile();
|
|
78
|
+
}
|
|
79
|
+
return this._ast;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Lists what the expression reads from its context, without evaluating it.
|
|
83
|
+
* See {@link analyze}.
|
|
84
|
+
*/
|
|
85
|
+
analyze(options) {
|
|
86
|
+
return (0, analyze_ts_1.analyze)(this.ast, options);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Checks the expression against a host's fields and functions, without
|
|
90
|
+
* evaluating it. See {@link check}.
|
|
91
|
+
*/
|
|
92
|
+
check(options) {
|
|
93
|
+
return (0, check_ts_1.check)(this.ast, options);
|
|
94
|
+
}
|
|
71
95
|
}
|
|
72
96
|
exports.default = Expression;
|
|
73
97
|
//# sourceMappingURL=Expression.js.map
|
package/dist/Expression.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Expression.js","sourceRoot":"","sources":["../src/Expression.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AAEH,0DAA8B;AAC9B,uDAAmD;AACnD,mEAAuC;
|
|
1
|
+
{"version":3,"file":"Expression.js","sourceRoot":"","sources":["../src/Expression.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AAEH,0DAA8B;AAC9B,6CAAsC;AACtC,yCAAkC;AAClC,uDAAmD;AACnD,mEAAuC;AAQvC,MAAM,UAAU;IACd,QAAQ,CAAS;IACjB,QAAQ,CAAQ;IAChB;;oDAEgD;IAChD,IAAI,CAAgB;IACpB,MAAM,CAAO;IACb,SAAS,GAAG,KAAK,CAAA;IACjB,2EAA2E;IAC3E,GAAG,GAAwB,IAAI,CAAA;IAE/B;;;;;;;OAOG;IACH,YAAY,OAAgB,EAAE,OAAe,EAAE,KAAa;QAC1D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,KAAK,IAAI,IAAI,kBAAK,CAAC,OAAO,CAAC,CAAA;IAC3C,CAAC;IAED;;;;;OAKG;IACH,OAAO;QACL,IAAI,CAAC,IAAI,GAAG,IAAI,mBAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACvE,uEAAuE;QACvE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAA,uBAAU,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAClE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QACrB,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,GAAG,EAAE;QACf,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;QACD,qEAAqE;QACrE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1B,CAAC;IAED,yDAAyD;IACzD,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IAED,iEAAiE;IACjE,IAAI,GAAG;QACL,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,OAAwB;QAC9B,OAAO,IAAA,oBAAO,EAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACnC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAsB;QAC1B,OAAO,IAAA,gBAAK,EAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACjC,CAAC;CACF;AAED,kBAAe,UAAU,CAAA"}
|
package/dist/Jexl.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import Expression from './Expression.ts';
|
|
2
2
|
import Lexer from './Lexer.ts';
|
|
3
|
-
import type { BinaryOpEvalOnDemand, Grammar, GrammarElement, GrammarFn, UncheckedFn } from './grammar.ts';
|
|
3
|
+
import type { BinaryOpEvalOnDemand, GetMember, Grammar, GrammarElement, GrammarFn, UncheckedFn, VariableReader } from './grammar.ts';
|
|
4
4
|
import type { JexlValue } from './types.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Hooks for a host whose values keep their fields behind an accessor. Both are
|
|
7
|
+
* fixed at construction, since a compiled expression binds them.
|
|
8
|
+
*/
|
|
9
|
+
export interface JexlOptions {
|
|
10
|
+
/** Resolves `a.b` and `a[k]`. */
|
|
11
|
+
getMember?: GetMember;
|
|
12
|
+
/** Resolves a bare name, such as a field of the current row. */
|
|
13
|
+
variableReader?: VariableReader;
|
|
14
|
+
}
|
|
5
15
|
/**
|
|
6
16
|
* Jexl is the Javascript Expression Language, capable of parsing and
|
|
7
17
|
* evaluating basic to complex expression strings, combined with advanced
|
|
@@ -11,7 +21,8 @@ import type { JexlValue } from './types.ts';
|
|
|
11
21
|
declare class Jexl {
|
|
12
22
|
_grammar: Grammar;
|
|
13
23
|
_lexer: Lexer;
|
|
14
|
-
|
|
24
|
+
_compiled: Map<string, Expression>;
|
|
25
|
+
constructor({ getMember, variableReader }?: JexlOptions);
|
|
15
26
|
/**
|
|
16
27
|
* Adds a binary operator to Jexl at the specified precedence. The higher the
|
|
17
28
|
* precedence, the earlier the operator is applied in the order of operations.
|
|
@@ -59,12 +70,10 @@ declare class Jexl {
|
|
|
59
70
|
*/
|
|
60
71
|
addUnaryOp(operator: string, fn: UncheckedFn): void;
|
|
61
72
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* @param {string} expression The Jexl expression to be compiled
|
|
67
|
-
* @returns {Expression} The compiled Expression object
|
|
73
|
+
* Compiles an expression string, or returns the Expression this instance
|
|
74
|
+
* already compiled from the same string. Adding or removing an operator
|
|
75
|
+
* empties the cache, since a compiled expression binds its operators;
|
|
76
|
+
* functions are looked up per call and leave it alone.
|
|
68
77
|
*/
|
|
69
78
|
compile(expression: string): Expression;
|
|
70
79
|
/**
|
|
@@ -74,6 +83,8 @@ declare class Jexl {
|
|
|
74
83
|
* @returns {Expression} The Expression object representing the given string
|
|
75
84
|
*/
|
|
76
85
|
createExpression(expression: string): Expression;
|
|
86
|
+
/** Parses an expression string, or throws a JexlSyntaxError. */
|
|
87
|
+
parse(expression: string): import("./types.ts").AstNode | null;
|
|
77
88
|
/**
|
|
78
89
|
* Retrieves a previously set expression function.
|
|
79
90
|
* @param {string} name The name of the expression function
|
|
@@ -109,6 +120,7 @@ declare class Jexl {
|
|
|
109
120
|
* @private
|
|
110
121
|
*/
|
|
111
122
|
_addGrammarElement(str: string, obj: GrammarElement): void;
|
|
123
|
+
_grammarChanged(): void;
|
|
112
124
|
}
|
|
113
125
|
declare const jexlInstance: Jexl;
|
|
114
126
|
export default jexlInstance;
|
package/dist/Jexl.js
CHANGED
|
@@ -11,6 +11,7 @@ exports.Jexl = void 0;
|
|
|
11
11
|
const Expression_ts_1 = __importDefault(require("./Expression.js"));
|
|
12
12
|
const Lexer_ts_1 = __importDefault(require("./Lexer.js"));
|
|
13
13
|
const grammar_ts_1 = require("./grammar.js");
|
|
14
|
+
const MAX_COMPILED = 10_000;
|
|
14
15
|
/**
|
|
15
16
|
* Jexl is the Javascript Expression Language, capable of parsing and
|
|
16
17
|
* evaluating basic to complex expression strings, combined with advanced
|
|
@@ -22,24 +23,30 @@ class Jexl {
|
|
|
22
23
|
// shared by every Expression this instance creates, so that the expensive
|
|
23
24
|
// element-splitting regex is built once rather than per compile
|
|
24
25
|
_lexer;
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
_compiled = new Map();
|
|
27
|
+
constructor({ getMember, variableReader } = {}) {
|
|
28
|
+
this._grammar = { ...(0, grammar_ts_1.getGrammar)(), getMember, variableReader };
|
|
27
29
|
this._lexer = new Lexer_ts_1.default(this._grammar);
|
|
28
30
|
this.expr = this.expr.bind(this);
|
|
29
31
|
}
|
|
30
32
|
addBinaryOp(operator, precedence, fn, manualEval) {
|
|
33
|
+
// replacing `-` keeps its prefix form, which is a separate operation
|
|
34
|
+
const previous = this._grammar.elements[operator];
|
|
35
|
+
const unaryEval = previous?.type === 'binaryOp' ? previous.unaryEval : undefined;
|
|
31
36
|
// the overloads above pair `fn` with `manualEval`; the implementation
|
|
32
37
|
// signature can't express that correlation, hence the assertions
|
|
33
38
|
this._addGrammarElement(operator, manualEval
|
|
34
39
|
? {
|
|
35
40
|
type: 'binaryOp',
|
|
36
41
|
precedence,
|
|
37
|
-
evalOnDemand: fn
|
|
42
|
+
evalOnDemand: fn,
|
|
43
|
+
unaryEval
|
|
38
44
|
}
|
|
39
45
|
: {
|
|
40
46
|
type: 'binaryOp',
|
|
41
47
|
precedence,
|
|
42
|
-
eval: fn
|
|
48
|
+
eval: fn,
|
|
49
|
+
unaryEval
|
|
43
50
|
});
|
|
44
51
|
}
|
|
45
52
|
/**
|
|
@@ -80,16 +87,21 @@ class Jexl {
|
|
|
80
87
|
});
|
|
81
88
|
}
|
|
82
89
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* @param {string} expression The Jexl expression to be compiled
|
|
88
|
-
* @returns {Expression} The compiled Expression object
|
|
90
|
+
* Compiles an expression string, or returns the Expression this instance
|
|
91
|
+
* already compiled from the same string. Adding or removing an operator
|
|
92
|
+
* empties the cache, since a compiled expression binds its operators;
|
|
93
|
+
* functions are looked up per call and leave it alone.
|
|
89
94
|
*/
|
|
90
95
|
compile(expression) {
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
let compiled = this._compiled.get(expression);
|
|
97
|
+
if (!compiled) {
|
|
98
|
+
compiled = this.createExpression(expression).compile();
|
|
99
|
+
if (this._compiled.size >= MAX_COMPILED) {
|
|
100
|
+
this._compiled.delete(this._compiled.keys().next().value);
|
|
101
|
+
}
|
|
102
|
+
this._compiled.set(expression, compiled);
|
|
103
|
+
}
|
|
104
|
+
return compiled;
|
|
93
105
|
}
|
|
94
106
|
/**
|
|
95
107
|
* Constructs an Expression object from a Jexl expression string.
|
|
@@ -100,6 +112,10 @@ class Jexl {
|
|
|
100
112
|
createExpression(expression) {
|
|
101
113
|
return new Expression_ts_1.default(this._grammar, expression, this._lexer);
|
|
102
114
|
}
|
|
115
|
+
/** Parses an expression string, or throws a JexlSyntaxError. */
|
|
116
|
+
parse(expression) {
|
|
117
|
+
return this.compile(expression).ast;
|
|
118
|
+
}
|
|
103
119
|
/**
|
|
104
120
|
* Retrieves a previously set expression function.
|
|
105
121
|
* @param {string} name The name of the expression function
|
|
@@ -117,8 +133,7 @@ class Jexl {
|
|
|
117
133
|
* @throws {*} on error
|
|
118
134
|
*/
|
|
119
135
|
eval(expression, context = {}) {
|
|
120
|
-
|
|
121
|
-
return exprObj.eval(context);
|
|
136
|
+
return this.compile(expression).eval(context);
|
|
122
137
|
}
|
|
123
138
|
/**
|
|
124
139
|
* A JavaScript template literal to allow expressions to be defined by the
|
|
@@ -152,7 +167,7 @@ class Jexl {
|
|
|
152
167
|
const elem = this._grammar.elements[operator];
|
|
153
168
|
if (elem?.type === 'binaryOp' || elem?.type === 'unaryOp') {
|
|
154
169
|
Reflect.deleteProperty(this._grammar.elements, operator);
|
|
155
|
-
this.
|
|
170
|
+
this._grammarChanged();
|
|
156
171
|
}
|
|
157
172
|
}
|
|
158
173
|
/**
|
|
@@ -164,7 +179,11 @@ class Jexl {
|
|
|
164
179
|
*/
|
|
165
180
|
_addGrammarElement(str, obj) {
|
|
166
181
|
this._grammar.elements[str] = obj;
|
|
182
|
+
this._grammarChanged();
|
|
183
|
+
}
|
|
184
|
+
_grammarChanged() {
|
|
167
185
|
this._lexer._clearCache();
|
|
186
|
+
this._compiled.clear();
|
|
168
187
|
}
|
|
169
188
|
}
|
|
170
189
|
exports.Jexl = Jexl;
|
package/dist/Jexl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Jexl.js","sourceRoot":"","sources":["../src/Jexl.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AAEH,oEAAwC;AACxC,0DAA8B;AAC9B,6CAAyC;
|
|
1
|
+
{"version":3,"file":"Jexl.js","sourceRoot":"","sources":["../src/Jexl.ts"],"names":[],"mappings":"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"}
|
package/dist/Lexer.d.ts
CHANGED
|
@@ -78,10 +78,11 @@ declare class Lexer {
|
|
|
78
78
|
* @throws {Error} if the provided string is not a valid expression element.
|
|
79
79
|
* @private
|
|
80
80
|
*/
|
|
81
|
-
_createToken(element: string): Token;
|
|
81
|
+
_createToken(element: string, offset?: number): Token;
|
|
82
82
|
/**
|
|
83
83
|
* Escapes a string so that it can be treated as a string literal within a
|
|
84
|
-
* regular expression.
|
|
84
|
+
* regular expression. A word such as `in` also stops matching inside a
|
|
85
|
+
* longer name.
|
|
85
86
|
* @param {string} str The string to be escaped
|
|
86
87
|
* @returns {string} the RegExp-escaped string.
|
|
87
88
|
* @see https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
|
|
@@ -126,7 +127,7 @@ declare class Lexer {
|
|
|
126
127
|
* @private
|
|
127
128
|
*/
|
|
128
129
|
_unquote(str: string): string;
|
|
129
|
-
_parseTemplateString(str: string): TemplatePart[];
|
|
130
|
+
_parseTemplateString(str: string, offset?: number): TemplatePart[];
|
|
130
131
|
_unescapeTemplateString(str: string): string;
|
|
131
132
|
}
|
|
132
133
|
export default Lexer;
|