@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.
Files changed (110) hide show
  1. package/README.md +163 -20
  2. package/dist/Expression.d.ts +16 -0
  3. package/dist/Expression.js +28 -4
  4. package/dist/Expression.js.map +1 -1
  5. package/dist/Jexl.d.ts +20 -8
  6. package/dist/Jexl.js +34 -15
  7. package/dist/Jexl.js.map +1 -1
  8. package/dist/Lexer.d.ts +4 -3
  9. package/dist/Lexer.js +29 -21
  10. package/dist/Lexer.js.map +1 -1
  11. package/dist/analyze.d.ts +84 -0
  12. package/dist/analyze.js +259 -0
  13. package/dist/analyze.js.map +1 -0
  14. package/dist/check.d.ts +109 -0
  15. package/dist/check.js +1267 -0
  16. package/dist/check.js.map +1 -0
  17. package/dist/collections.d.ts +3 -0
  18. package/dist/collections.js +140 -0
  19. package/dist/collections.js.map +1 -0
  20. package/dist/conditions.d.ts +62 -0
  21. package/dist/conditions.js +207 -0
  22. package/dist/conditions.js.map +1 -0
  23. package/dist/errors.d.ts +5 -0
  24. package/dist/errors.js +18 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/evaluator/compile.d.ts +10 -7
  27. package/dist/evaluator/compile.js +274 -97
  28. package/dist/evaluator/compile.js.map +1 -1
  29. package/dist/grammar.d.ts +19 -9
  30. package/dist/grammar.js +66 -40
  31. package/dist/grammar.js.map +1 -1
  32. package/dist/index.d.ts +9 -0
  33. package/dist/index.js +16 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/operators.d.ts +34 -0
  36. package/dist/operators.js +131 -0
  37. package/dist/operators.js.map +1 -0
  38. package/dist/parser/Parser.d.ts +48 -91
  39. package/dist/parser/Parser.js +347 -221
  40. package/dist/parser/Parser.js.map +1 -1
  41. package/dist/types.d.ts +11 -5
  42. package/esm/Expression.d.ts +16 -0
  43. package/esm/Expression.js +28 -4
  44. package/esm/Expression.js.map +1 -1
  45. package/esm/Jexl.d.ts +20 -8
  46. package/esm/Jexl.js +34 -15
  47. package/esm/Jexl.js.map +1 -1
  48. package/esm/Lexer.d.ts +4 -3
  49. package/esm/Lexer.js +29 -21
  50. package/esm/Lexer.js.map +1 -1
  51. package/esm/analyze.d.ts +84 -0
  52. package/esm/analyze.js +256 -0
  53. package/esm/analyze.js.map +1 -0
  54. package/esm/check.d.ts +109 -0
  55. package/esm/check.js +1260 -0
  56. package/esm/check.js.map +1 -0
  57. package/esm/collections.d.ts +3 -0
  58. package/esm/collections.js +137 -0
  59. package/esm/collections.js.map +1 -0
  60. package/esm/conditions.d.ts +62 -0
  61. package/esm/conditions.js +200 -0
  62. package/esm/conditions.js.map +1 -0
  63. package/esm/errors.d.ts +5 -0
  64. package/esm/errors.js +14 -0
  65. package/esm/errors.js.map +1 -0
  66. package/esm/evaluator/compile.d.ts +10 -7
  67. package/esm/evaluator/compile.js +274 -97
  68. package/esm/evaluator/compile.js.map +1 -1
  69. package/esm/grammar.d.ts +19 -9
  70. package/esm/grammar.js +66 -39
  71. package/esm/grammar.js.map +1 -1
  72. package/esm/index.d.ts +9 -0
  73. package/esm/index.js +4 -0
  74. package/esm/index.js.map +1 -1
  75. package/esm/operators.d.ts +34 -0
  76. package/esm/operators.js +123 -0
  77. package/esm/operators.js.map +1 -0
  78. package/esm/parser/Parser.d.ts +48 -91
  79. package/esm/parser/Parser.js +349 -192
  80. package/esm/parser/Parser.js.map +1 -1
  81. package/esm/types.d.ts +11 -5
  82. package/package.json +1 -1
  83. package/src/Expression.ts +34 -4
  84. package/src/Jexl.ts +52 -16
  85. package/src/Lexer.ts +32 -21
  86. package/src/analyze.ts +378 -0
  87. package/src/check.ts +1682 -0
  88. package/src/collections.ts +148 -0
  89. package/src/conditions.ts +262 -0
  90. package/src/errors.ts +15 -0
  91. package/src/evaluator/compile.ts +332 -100
  92. package/src/grammar.ts +123 -42
  93. package/src/index.ts +15 -0
  94. package/src/operators.ts +151 -0
  95. package/src/parser/Parser.ts +389 -199
  96. package/src/types.ts +13 -3
  97. package/dist/parser/handlers.d.ts +0 -115
  98. package/dist/parser/handlers.js +0 -352
  99. package/dist/parser/handlers.js.map +0 -1
  100. package/dist/parser/states.d.ts +0 -47
  101. package/dist/parser/states.js +0 -176
  102. package/dist/parser/states.js.map +0 -1
  103. package/esm/parser/handlers.d.ts +0 -115
  104. package/esm/parser/handlers.js +0 -328
  105. package/esm/parser/handlers.js.map +0 -1
  106. package/esm/parser/states.d.ts +0 -47
  107. package/esm/parser/states.js +0 -140
  108. package/esm/parser/states.js.map +0 -1
  109. package/src/parser/handlers.ts +0 -372
  110. 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`, `5`, `-3.14159` |
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
- - Logical: `&&`, `||`
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('min', Math.min)
123
- jexl.addFunction('max', Math.max)
197
+ jexl.addFunction('log10', Math.log10)
198
+ jexl.addFunction('round', Math.round)
124
199
 
125
- jexl.eval('min(5, 2, 9)')
126
- // 2
200
+ jexl.eval('round(log10(1234))')
201
+ // 3
127
202
 
128
- jexl.eval('max(temperature, threshold)')
129
- // evaluates with context
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). Assignments mutate the context and return the assigned value:
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('x = 5; y = x * 2; y', context)
163
- // 10
164
- // context is now { x: 5, y: 10 }
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 last expression:
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
- min: Math.min,
194
- max: Math.max,
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('max(1, 5, 3)') // 5
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('~', (right) => Math.floor(right))
310
+ jexl.addUnaryOp('#', (right) => Math.floor(right))
218
311
 
219
- jexl.eval('~3.7') // 3
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
@@ -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;
@@ -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
- const parser = new Parser_ts_1.default(this._grammar, this._lexer);
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
@@ -1 +1 @@
1
- {"version":3,"file":"Expression.js","sourceRoot":"","sources":["../src/Expression.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AAEH,0DAA8B;AAC9B,uDAAmD;AACnD,mEAAuC;AAMvC,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,MAAM,MAAM,GAAG,IAAI,mBAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAClD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACxB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QAC7B,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;CACF;AAED,kBAAe,UAAU,CAAA"}
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
- constructor();
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
- * Creates an Expression object from the given Jexl expression string, and
63
- * immediately compiles it. The returned Expression object can then be
64
- * evaluated multiple times with new contexts, without generating any
65
- * additional string processing overhead.
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
- constructor() {
26
- this._grammar = (0, grammar_ts_1.getGrammar)();
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
- * Creates an Expression object from the given Jexl expression string, and
84
- * immediately compiles it. The returned Expression object can then be
85
- * evaluated multiple times with new contexts, without generating any
86
- * additional string processing overhead.
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
- const exprObj = this.createExpression(expression);
92
- return exprObj.compile();
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
- const exprObj = this.createExpression(expression);
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._lexer._clearCache();
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":"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"}
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;