@jbrowse/jexl 3.3.0 → 4.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/dist/Expression.js +1 -2
- package/dist/Expression.js.map +1 -1
- package/dist/Jexl.d.ts +2 -2
- package/dist/Lexer.d.ts +10 -8
- package/dist/Lexer.js +46 -35
- package/dist/Lexer.js.map +1 -1
- package/dist/evaluator/compile.d.ts +6 -4
- package/dist/evaluator/compile.js +91 -55
- package/dist/evaluator/compile.js.map +1 -1
- package/dist/grammar.js +1 -1
- package/dist/parser/Parser.d.ts +2 -9
- package/dist/parser/Parser.js +2 -12
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/handlers.d.ts +6 -3
- package/dist/parser/handlers.js +45 -28
- package/dist/parser/handlers.js.map +1 -1
- package/dist/parser/states.js +3 -5
- package/dist/parser/states.js.map +1 -1
- package/dist/types.d.ts +0 -3
- package/esm/Expression.js +1 -2
- package/esm/Expression.js.map +1 -1
- package/esm/Jexl.d.ts +2 -2
- package/esm/Lexer.d.ts +10 -8
- package/esm/Lexer.js +46 -35
- package/esm/Lexer.js.map +1 -1
- package/esm/evaluator/compile.d.ts +6 -4
- package/esm/evaluator/compile.js +91 -55
- package/esm/evaluator/compile.js.map +1 -1
- package/esm/grammar.js +1 -1
- package/esm/parser/Parser.d.ts +2 -9
- package/esm/parser/Parser.js +2 -12
- package/esm/parser/Parser.js.map +1 -1
- package/esm/parser/handlers.d.ts +6 -3
- package/esm/parser/handlers.js +45 -28
- package/esm/parser/handlers.js.map +1 -1
- package/esm/parser/states.js +3 -5
- package/esm/parser/states.js.map +1 -1
- package/esm/types.d.ts +0 -3
- package/package.json +2 -1
- package/src/Expression.ts +1 -2
- package/src/Jexl.ts +2 -2
- package/src/Lexer.ts +47 -36
- package/src/evaluator/compile.ts +108 -71
- package/src/grammar.ts +1 -1
- package/src/parser/Parser.ts +2 -13
- package/src/parser/handlers.ts +48 -31
- package/src/parser/states.ts +3 -5
- package/src/types.ts +0 -3
- package/dist/evaluator/Evaluator.d.ts +0 -37
- package/dist/evaluator/Evaluator.js +0 -49
- package/dist/evaluator/Evaluator.js.map +0 -1
- package/esm/evaluator/Evaluator.d.ts +0 -37
- package/esm/evaluator/Evaluator.js +0 -47
- package/esm/evaluator/Evaluator.js.map +0 -1
- package/src/evaluator/Evaluator.ts +0 -58
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/parser/handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,+EAA+E;AAC/E,8DAA8D;AAC9D,OAAO,MAAM,MAAM,aAAa,CAAA;AAkBhC;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAe,GAAmB;IACtD,IAAI,GAAG,EAAE,CAAC;QACR,CAAC;QAAC,IAAI,CAAC,OAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAChD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,IAAI,GAAiB;QACzB,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,EAAE;KACV,CAAA;IACD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAe,GAAmB;IACxD,IAAI,GAAG,EAAE,CAAC;QACR,CAAC;QAAC,IAAI,CAAC,OAAwB,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjD,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAe,KAAY;IACjD,IAAI,KAAK,CAAC,KAAK,KAAK,GAAG,EAAE,CAAC;QACxB,sEAAsE;QACtE,
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/parser/handlers.ts"],"names":[],"mappings":"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"}
|
package/esm/parser/states.js
CHANGED
|
@@ -77,10 +77,6 @@ export const states = {
|
|
|
77
77
|
colon: { toState: 'objVal' }
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
|
-
postArgs: {
|
|
81
|
-
tokenTypes: afterOperand,
|
|
82
|
-
completable: true
|
|
83
|
-
},
|
|
84
80
|
identifier: {
|
|
85
81
|
tokenTypes: {
|
|
86
82
|
...afterOperand,
|
|
@@ -111,7 +107,9 @@ export const states = {
|
|
|
111
107
|
subHandler: h.argVal,
|
|
112
108
|
endStates: {
|
|
113
109
|
comma: 'argVal',
|
|
114
|
-
|
|
110
|
+
// a call's result is an ordinary operand: it can be operated on or
|
|
111
|
+
// drilled into, but not called again, since only a name can be called
|
|
112
|
+
closeParen: 'expectBinOp'
|
|
115
113
|
}
|
|
116
114
|
},
|
|
117
115
|
objVal: {
|
package/esm/parser/states.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"states.js","sourceRoot":"","sources":["../../src/parser/states.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,CAAC,MAAM,eAAe,CAAA;AAmBlC;;;;;GAKG;AACH,MAAM,YAAY,GAAqC;IACrD,QAAQ,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE;IACtC,GAAG,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE;IAC5B,WAAW,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE;IAClC,QAAQ,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC,YAAY,EAAE;IAC5D,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE;CACpC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,MAAM,MAAM,GAAW;IAC5B,aAAa,EAAE;QACb,UAAU,EAAE;YACV,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE;YACnC,cAAc,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE;YAC1C,UAAU,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE;YACrC,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE;YACvC,QAAQ,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;YAC1D,GAAG,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE;YAC5B,WAAW,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,UAAU,EAAE;SAC5D;KACF;IACD,WAAW,EAAE;QACX,UAAU,EAAE,YAAY;QACxB,WAAW,EAAE,IAAI;KAClB;IACD,YAAY,EAAE;QACZ,UAAU,EAAE;YACV,OAAO,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;YAC1D,UAAU,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;YAC7D,SAAS,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE;SACtC;KACF;IACD,eAAe,EAAE;QACf,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE;SAC7B;KACF;IACD,
|
|
1
|
+
{"version":3,"file":"states.js","sourceRoot":"","sources":["../../src/parser/states.ts"],"names":[],"mappings":"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"}
|
package/esm/types.d.ts
CHANGED
|
@@ -23,7 +23,6 @@ export interface Identifier extends AstNode {
|
|
|
23
23
|
type: 'Identifier';
|
|
24
24
|
value: string;
|
|
25
25
|
from?: AstNode;
|
|
26
|
-
relative?: boolean;
|
|
27
26
|
}
|
|
28
27
|
export interface BinaryExpression extends AstNode {
|
|
29
28
|
type: 'BinaryExpression';
|
|
@@ -59,12 +58,10 @@ export interface FunctionCall extends AstNode {
|
|
|
59
58
|
type: 'FunctionCall';
|
|
60
59
|
name: string;
|
|
61
60
|
args: AstNode[];
|
|
62
|
-
pool: 'functions';
|
|
63
61
|
}
|
|
64
62
|
export interface FilterExpression extends AstNode {
|
|
65
63
|
type: 'FilterExpression';
|
|
66
64
|
expr: AstNode;
|
|
67
|
-
relative: boolean;
|
|
68
65
|
subject: AstNode;
|
|
69
66
|
}
|
|
70
67
|
export interface ConditionalExpression extends AstNode {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/jexl",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "A fork of the jexl lang for jbrowse",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
17
|
"test": "vitest",
|
|
18
|
+
"bench": "vitest bench --run",
|
|
18
19
|
"coverage": "pnpm test --coverage",
|
|
19
20
|
"clean": "rimraf dist esm",
|
|
20
21
|
"format": "prettier --write .",
|
package/src/Expression.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import Lexer from './Lexer.ts'
|
|
7
|
-
import Evaluator from './evaluator/Evaluator.ts'
|
|
8
7
|
import { compileAst } from './evaluator/compile.ts'
|
|
9
8
|
import Parser from './parser/Parser.ts'
|
|
10
9
|
|
|
@@ -71,7 +70,7 @@ class Expression {
|
|
|
71
70
|
if (!this._fn) {
|
|
72
71
|
return undefined
|
|
73
72
|
}
|
|
74
|
-
return this._fn(
|
|
73
|
+
return this._fn(context)
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
|
package/src/Jexl.ts
CHANGED
|
@@ -40,9 +40,9 @@ class Jexl {
|
|
|
40
40
|
* Adds a binary operator to Jexl at the specified precedence. The higher the
|
|
41
41
|
* precedence, the earlier the operator is applied in the order of operations.
|
|
42
42
|
* For example, * has a higher precedence than +, because multiplication comes
|
|
43
|
-
* before
|
|
43
|
+
* before addition.
|
|
44
44
|
*
|
|
45
|
-
* Please see grammar.
|
|
45
|
+
* Please see grammar.ts for a listing of all default operators and their
|
|
46
46
|
* precedence values in order to choose the appropriate precedence for the
|
|
47
47
|
* new operator.
|
|
48
48
|
* @param {string} operator The operator string to be added
|
package/src/Lexer.ts
CHANGED
|
@@ -6,13 +6,26 @@
|
|
|
6
6
|
import type { Grammar } from './grammar.ts'
|
|
7
7
|
import type { TemplatePart, Token } from './types.ts'
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
// what an identifier and a number look like, written once: the split regex
|
|
10
|
+
// below carves elements out of the expression with these, and _createToken
|
|
11
|
+
// then re-tests the elements it produced. Two spellings of either would
|
|
12
|
+
// disagree on some input, and each disagreement is an "Invalid expression
|
|
13
|
+
// token" for something the splitter was happy to produce.
|
|
14
|
+
const identChars = String.raw`a-zA-Zа-яА-Я_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF$`
|
|
15
|
+
const identPattern = `[${identChars}][${identChars}0-9]*`
|
|
16
|
+
// unsigned: whether a leading '-' negates is decided separately, in getTokens
|
|
17
|
+
const numberPattern = String.raw`(?:(?:[0-9]*\.[0-9]+)|[0-9]+)`
|
|
18
|
+
|
|
19
|
+
const numericRegex = new RegExp(`^-?${numberPattern}$`)
|
|
20
|
+
const identRegex = new RegExp(`^${identPattern}$`)
|
|
12
21
|
const escEscRegex = /\\\\/g
|
|
13
22
|
// a string literal opens with one of exactly two quote characters, so the two
|
|
14
23
|
// unescaping regexes can just be named rather than built and cached per quote
|
|
15
24
|
const escQuoteRegex = { "'": /\\'/g, '"': /\\"/g }
|
|
25
|
+
// the escapes a template string's static text recognizes. One pass, so the
|
|
26
|
+
// backslash an escaped backslash yields can't be re-read as the start of the
|
|
27
|
+
// escape that follows it
|
|
28
|
+
const templateEscRegex = /\\([`$\\])/g
|
|
16
29
|
const whitespaceRegex = /^\s*$/
|
|
17
30
|
const preOpRegexElems = [
|
|
18
31
|
// Template strings
|
|
@@ -26,12 +39,7 @@ const preOpRegexElems = [
|
|
|
26
39
|
String.raw`\btrue\b`,
|
|
27
40
|
String.raw`\bfalse\b`
|
|
28
41
|
]
|
|
29
|
-
const postOpRegexElems = [
|
|
30
|
-
// Identifiers
|
|
31
|
-
'[a-zA-Zа-яА-Я_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\\$][a-zA-Z0-9а-яА-Я_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\\$]*',
|
|
32
|
-
// Numerics (without negative symbol)
|
|
33
|
-
String.raw`(?:(?:[0-9]*\.[0-9]+)|[0-9]+)`
|
|
34
|
-
]
|
|
42
|
+
const postOpRegexElems = [identPattern, numberPattern]
|
|
35
43
|
const unaryMinusToken = (): Token => ({
|
|
36
44
|
type: 'unaryOp',
|
|
37
45
|
value: '-',
|
|
@@ -49,14 +57,16 @@ const minusNegatesAfter = new Set([
|
|
|
49
57
|
])
|
|
50
58
|
|
|
51
59
|
/**
|
|
52
|
-
* Lexer
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
+
* Lexer handles the lexical parsing of a Jexl string. Its responsibility is to
|
|
61
|
+
* identify the "parts of speech" of a Jexl expression, and tokenize and label
|
|
62
|
+
* each, but to do only the most minimal syntax checking; the only errors the
|
|
63
|
+
* Lexer should be concerned with are if it's unable to identify the utility of
|
|
64
|
+
* any of its tokens. Errors stemming from these tokens not being in a sensible
|
|
65
|
+
* configuration should be left for the Parser to handle.
|
|
66
|
+
*
|
|
67
|
+
* An instance is bound to one grammar and memoizes the regex that splits an
|
|
68
|
+
* expression into elements, which is expensive to build; {@link #_clearCache}
|
|
69
|
+
* discards it when the grammar's elements change.
|
|
60
70
|
*/
|
|
61
71
|
class Lexer {
|
|
62
72
|
_grammar: Grammar
|
|
@@ -98,37 +108,43 @@ class Lexer {
|
|
|
98
108
|
*/
|
|
99
109
|
getTokens(elements: string[]) {
|
|
100
110
|
const tokens: Token[] = []
|
|
101
|
-
|
|
111
|
+
// a prefix minus, held back until the element it applies to is known. It
|
|
112
|
+
// carries its own raw so that whitespace arriving before that element ("-
|
|
113
|
+
// 1") accumulates on the minus rather than on the token before it, which
|
|
114
|
+
// is what lets the parser's error messages quote the expression verbatim.
|
|
115
|
+
let pendingMinus: Token | undefined
|
|
102
116
|
for (const element of elements) {
|
|
103
117
|
if (this._isWhitespace(element)) {
|
|
104
|
-
const last = tokens.at(-1)
|
|
118
|
+
const last = pendingMinus ?? tokens.at(-1)
|
|
105
119
|
if (last) {
|
|
106
120
|
last.raw += element
|
|
107
121
|
}
|
|
108
122
|
} else if (element === '-' && this._isNegative(tokens)) {
|
|
109
123
|
// a second prefix minus in a row ("- -x"): emit the pending one as a
|
|
110
124
|
// unary operator so this one can negate whatever comes next
|
|
111
|
-
if (
|
|
112
|
-
tokens.push(
|
|
125
|
+
if (pendingMinus) {
|
|
126
|
+
tokens.push(pendingMinus)
|
|
113
127
|
}
|
|
114
|
-
|
|
115
|
-
} else if (
|
|
116
|
-
negate = false
|
|
128
|
+
pendingMinus = unaryMinusToken()
|
|
129
|
+
} else if (pendingMinus) {
|
|
117
130
|
if (numericRegex.exec(element)) {
|
|
118
131
|
// fold the sign into the number, so "-1" stays a single literal
|
|
119
|
-
|
|
132
|
+
const token = this._createToken('-' + element)
|
|
133
|
+
token.raw = pendingMinus.raw + element
|
|
134
|
+
tokens.push(token)
|
|
120
135
|
} else {
|
|
121
136
|
// anything else gets a standalone prefix operator, letting "-x",
|
|
122
137
|
// "-(a + b)" and "-foo.bar" negate a computed value
|
|
123
|
-
tokens.push(
|
|
138
|
+
tokens.push(pendingMinus, this._createToken(element))
|
|
124
139
|
}
|
|
140
|
+
pendingMinus = undefined
|
|
125
141
|
} else {
|
|
126
142
|
tokens.push(this._createToken(element))
|
|
127
143
|
}
|
|
128
144
|
}
|
|
129
145
|
// Catch a - at the end of the string. Let the parser handle that issue.
|
|
130
|
-
if (
|
|
131
|
-
tokens.push(
|
|
146
|
+
if (pendingMinus) {
|
|
147
|
+
tokens.push(pendingMinus)
|
|
132
148
|
}
|
|
133
149
|
return tokens
|
|
134
150
|
}
|
|
@@ -256,10 +272,8 @@ class Lexer {
|
|
|
256
272
|
* @private
|
|
257
273
|
*/
|
|
258
274
|
_isNegative(tokens: Token[]) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
return minusNegatesAfter.has(tokens[tokens.length - 1]!.type)
|
|
275
|
+
const last = tokens.at(-1)
|
|
276
|
+
return !last || minusNegatesAfter.has(last.type)
|
|
263
277
|
}
|
|
264
278
|
|
|
265
279
|
/**
|
|
@@ -366,10 +380,7 @@ class Lexer {
|
|
|
366
380
|
}
|
|
367
381
|
|
|
368
382
|
_unescapeTemplateString(str: string) {
|
|
369
|
-
return str
|
|
370
|
-
.replaceAll('\\`', '`')
|
|
371
|
-
.replaceAll(String.raw`\$`, '$')
|
|
372
|
-
.replaceAll('\\\\', '\\')
|
|
383
|
+
return str.replaceAll(templateEscRegex, '$1')
|
|
373
384
|
}
|
|
374
385
|
}
|
|
375
386
|
|
package/src/evaluator/compile.ts
CHANGED
|
@@ -5,13 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
import type { Grammar } from '../grammar.ts'
|
|
7
7
|
import type { AstNode, AstNodeUnion, JexlValue } from '../types.ts'
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
/** The variables an expression is evaluated against. */
|
|
10
|
+
export type Context = Record<string, JexlValue>
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
|
-
* An AST node lowered to a closure. Calling it with
|
|
12
|
-
*
|
|
13
|
+
* An AST node lowered to a closure. Calling it with a context produces the
|
|
14
|
+
* node's value. The grammar is captured when the closure is built, so it is not
|
|
15
|
+
* a parameter.
|
|
13
16
|
*/
|
|
14
|
-
export type CompiledNode = (
|
|
17
|
+
export type CompiledNode = (context: Context) => JexlValue
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Writes a key that a plain assignment would mishandle. Storing to
|
|
@@ -20,11 +23,7 @@ export type CompiledNode = (ev: Evaluator) => JexlValue
|
|
|
20
23
|
* re-pointed the target's prototype). Defining the property instead matches
|
|
21
24
|
* what `JSON.parse('{"__proto__":1}')` produces: an ordinary own property.
|
|
22
25
|
*/
|
|
23
|
-
function defineOwn(
|
|
24
|
-
target: Record<string, JexlValue>,
|
|
25
|
-
key: string,
|
|
26
|
-
value: JexlValue
|
|
27
|
-
) {
|
|
26
|
+
function defineOwn(target: Context, key: string, value: JexlValue) {
|
|
28
27
|
Object.defineProperty(target, key, {
|
|
29
28
|
value,
|
|
30
29
|
writable: true,
|
|
@@ -33,14 +32,40 @@ function defineOwn(
|
|
|
33
32
|
})
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
function assignOwn(
|
|
37
|
-
target: Record<string, JexlValue>,
|
|
38
|
-
key: string,
|
|
39
|
-
value: JexlValue
|
|
40
|
-
) {
|
|
35
|
+
function assignOwn(target: Context, key: string, value: JexlValue) {
|
|
41
36
|
target[key] = value
|
|
42
37
|
}
|
|
43
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The key a bracket index that is neither a string nor a number reads under:
|
|
41
|
+
* its string form, when it has one worth using.
|
|
42
|
+
*
|
|
43
|
+
* A boolean and an array of primitives do — `['a']` is the key `'a'`, exactly
|
|
44
|
+
* as JS would index by it. A plain object does not, since '[object Object]' is
|
|
45
|
+
* not a key anything is stored under, so it and an array holding one answer
|
|
46
|
+
* `undefined` instead; indexing by either reached that lookup and missed
|
|
47
|
+
* anyway. null and undefined are the same case.
|
|
48
|
+
*/
|
|
49
|
+
function indexKey(value: JexlValue): string | undefined {
|
|
50
|
+
if (typeof value === 'boolean') {
|
|
51
|
+
return String(value)
|
|
52
|
+
}
|
|
53
|
+
return Array.isArray(value) && value.every(isKeyPart)
|
|
54
|
+
? value.join(',')
|
|
55
|
+
: undefined
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isKeyPart(
|
|
59
|
+
value: JexlValue
|
|
60
|
+
): value is string | number | boolean | null | undefined {
|
|
61
|
+
return (
|
|
62
|
+
value == null ||
|
|
63
|
+
typeof value === 'string' ||
|
|
64
|
+
typeof value === 'number' ||
|
|
65
|
+
typeof value === 'boolean'
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
44
69
|
/** Renders an interpolated value for a template literal. */
|
|
45
70
|
function stringify(value: JexlValue) {
|
|
46
71
|
if (value == null) {
|
|
@@ -88,21 +113,17 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
88
113
|
case 'Identifier': {
|
|
89
114
|
const name = node.value
|
|
90
115
|
if (!node.from) {
|
|
91
|
-
return
|
|
92
|
-
? (ev) => ev._relContext[name]
|
|
93
|
-
: (ev) => ev._context[name]
|
|
116
|
+
return (ctx) => ctx[name]
|
|
94
117
|
}
|
|
95
118
|
const from = compileAst(node.from, grammar)
|
|
96
|
-
return (
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
119
|
+
return (ctx) => {
|
|
120
|
+
const subject = from(ctx)
|
|
121
|
+
if (subject == null) {
|
|
99
122
|
return undefined
|
|
100
123
|
}
|
|
101
124
|
// an identifier chained off an array reads through its first element
|
|
102
|
-
const
|
|
103
|
-
return
|
|
104
|
-
? undefined
|
|
105
|
-
: (ctx as Record<string, JexlValue>)[name]
|
|
125
|
+
const target = Array.isArray(subject) ? subject[0] : subject
|
|
126
|
+
return target == null ? undefined : (target as Context)[name]
|
|
106
127
|
}
|
|
107
128
|
}
|
|
108
129
|
|
|
@@ -119,18 +140,18 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
119
140
|
if (evalOnDemand) {
|
|
120
141
|
// operands stay unevaluated behind an `eval` thunk, so operators such
|
|
121
142
|
// as && and || can short-circuit
|
|
122
|
-
return (
|
|
123
|
-
evalOnDemand({ eval: () => left(
|
|
143
|
+
return (ctx) =>
|
|
144
|
+
evalOnDemand({ eval: () => left(ctx) }, { eval: () => right(ctx) })
|
|
124
145
|
}
|
|
125
146
|
const fn = op.eval
|
|
126
147
|
if (!fn) {
|
|
127
|
-
return (
|
|
128
|
-
left(
|
|
129
|
-
right(
|
|
148
|
+
return (ctx) => {
|
|
149
|
+
left(ctx)
|
|
150
|
+
right(ctx)
|
|
130
151
|
return undefined
|
|
131
152
|
}
|
|
132
153
|
}
|
|
133
|
-
return (
|
|
154
|
+
return (ctx) => fn(left(ctx), right(ctx))
|
|
134
155
|
}
|
|
135
156
|
|
|
136
157
|
case 'UnaryExpression': {
|
|
@@ -144,12 +165,12 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
144
165
|
: undefined
|
|
145
166
|
if (!fn) {
|
|
146
167
|
// the operand is still evaluated for an unknown operator, as before
|
|
147
|
-
return (
|
|
148
|
-
right(
|
|
168
|
+
return (ctx) => {
|
|
169
|
+
right(ctx)
|
|
149
170
|
return undefined
|
|
150
171
|
}
|
|
151
172
|
}
|
|
152
|
-
return (
|
|
173
|
+
return (ctx) => fn(right(ctx))
|
|
153
174
|
}
|
|
154
175
|
|
|
155
176
|
case 'ConditionalExpression': {
|
|
@@ -160,44 +181,60 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
160
181
|
const alternate = node.alternate
|
|
161
182
|
? compileAst(node.alternate, grammar)
|
|
162
183
|
: undefined
|
|
163
|
-
return (
|
|
164
|
-
const res = test(
|
|
184
|
+
return (ctx) => {
|
|
185
|
+
const res = test(ctx)
|
|
165
186
|
if (res) {
|
|
166
187
|
// an omitted consequent ("a ?: b") yields the test result
|
|
167
|
-
return consequent ? consequent(
|
|
188
|
+
return consequent ? consequent(ctx) : res
|
|
168
189
|
}
|
|
169
|
-
return alternate ? alternate(
|
|
190
|
+
return alternate ? alternate(ctx) : undefined
|
|
170
191
|
}
|
|
171
192
|
}
|
|
172
193
|
|
|
173
194
|
case 'FilterExpression': {
|
|
174
|
-
if (node.relative) {
|
|
175
|
-
// thrown on evaluation rather than compilation, as before
|
|
176
|
-
return () => {
|
|
177
|
-
throw new Error('Relative filter expressions are not supported')
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
195
|
const subject = compileAst(node.subject, grammar)
|
|
181
196
|
const index = compileAst(node.expr, grammar)
|
|
182
|
-
return (
|
|
183
|
-
const subjectVal = subject(
|
|
184
|
-
const indexVal = index(
|
|
197
|
+
return (ctx) => {
|
|
198
|
+
const subjectVal = subject(ctx)
|
|
199
|
+
const indexVal = index(ctx)
|
|
185
200
|
if (subjectVal == null) {
|
|
186
201
|
return undefined
|
|
187
202
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
203
|
+
if (typeof indexVal === 'string' || typeof indexVal === 'number') {
|
|
204
|
+
return (subjectVal as Record<string | number, JexlValue>)[indexVal]
|
|
205
|
+
}
|
|
206
|
+
// A value with a meaningful string form is indexed by it, which is what
|
|
207
|
+
// JS does and what this did until the evaluator was lowered to closures
|
|
208
|
+
// — the tree-walking version was a bare `subject?.[index]`. Answering
|
|
209
|
+
// `undefined` for everything else reads as a deliberate strictness and
|
|
210
|
+
// is not: nothing wanted it, and the shape it rejects is common.
|
|
211
|
+
//
|
|
212
|
+
// That shape is a one-element array. Every `@gmod/vcf` INFO value is a
|
|
213
|
+
// list — `Number=1` included, so `CLNSIG=Pathogenic` parses to
|
|
214
|
+
// `['Pathogenic']` — and the natural way to colour by one is a lookup
|
|
215
|
+
// table indexed by it. The miss is silent, because such an expression
|
|
216
|
+
// always carries a `|| fallback` for the values it has no entry for,
|
|
217
|
+
// and that fallback then answers for every record.
|
|
218
|
+
//
|
|
219
|
+
// A multi-valued list still misses — `['a','b']` is the key 'a,b' —
|
|
220
|
+
// which is the honest answer rather than a lucky one: reading through
|
|
221
|
+
// to the first element would be the index guessing which value was
|
|
222
|
+
// meant. `Identifier` above does read through a one-element array, but
|
|
223
|
+
// it is navigating rather than selecting, so it has nothing to guess.
|
|
224
|
+
const key = indexKey(indexVal)
|
|
225
|
+
return key === undefined
|
|
226
|
+
? undefined
|
|
227
|
+
: (subjectVal as Record<string, JexlValue>)[key]
|
|
191
228
|
}
|
|
192
229
|
}
|
|
193
230
|
|
|
194
231
|
case 'ArrayLiteral': {
|
|
195
232
|
const items = node.value.map((item) => compileAst(item, grammar))
|
|
196
233
|
const len = items.length
|
|
197
|
-
return (
|
|
234
|
+
return (ctx) => {
|
|
198
235
|
const out: JexlValue[] = new Array(len)
|
|
199
236
|
for (let i = 0; i < len; i++) {
|
|
200
|
-
out[i] = items[i]!(
|
|
237
|
+
out[i] = items[i]!(ctx)
|
|
201
238
|
}
|
|
202
239
|
return out
|
|
203
240
|
}
|
|
@@ -210,10 +247,10 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
210
247
|
const len = keys.length
|
|
211
248
|
// resolved once, here, so the common case keeps its plain store
|
|
212
249
|
const store = keys.includes('__proto__') ? defineOwn : assignOwn
|
|
213
|
-
return (
|
|
250
|
+
return (ctx) => {
|
|
214
251
|
const out: Record<string, JexlValue> = {}
|
|
215
252
|
for (let i = 0; i < len; i++) {
|
|
216
|
-
store(out, keys[i]!, values[i]!(
|
|
253
|
+
store(out, keys[i]!, values[i]!(ctx))
|
|
217
254
|
}
|
|
218
255
|
return out
|
|
219
256
|
}
|
|
@@ -221,18 +258,18 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
221
258
|
|
|
222
259
|
case 'TemplateLiteral': {
|
|
223
260
|
// every part renders to a string, so these are narrower than CompiledNode
|
|
224
|
-
const parts = node.parts.map((part): ((
|
|
261
|
+
const parts = node.parts.map((part): ((ctx: Context) => string) => {
|
|
225
262
|
if (part.type === 'static') {
|
|
226
263
|
const { value } = part
|
|
227
264
|
return () => value
|
|
228
265
|
}
|
|
229
266
|
const expr = compileAst(part.value, grammar)
|
|
230
|
-
return (
|
|
267
|
+
return (ctx) => stringify(expr(ctx))
|
|
231
268
|
})
|
|
232
|
-
return (
|
|
269
|
+
return (ctx) => {
|
|
233
270
|
let out = ''
|
|
234
271
|
for (const part of parts) {
|
|
235
|
-
out += part(
|
|
272
|
+
out += part(ctx)
|
|
236
273
|
}
|
|
237
274
|
return out
|
|
238
275
|
}
|
|
@@ -245,8 +282,8 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
245
282
|
// and `constructor` aren't callable as Jexl functions. Resolved per call
|
|
246
283
|
// rather than baked in, since functions are routinely registered after
|
|
247
284
|
// an expression has been compiled.
|
|
248
|
-
const lookup = (
|
|
249
|
-
const { functions } =
|
|
285
|
+
const lookup = () => {
|
|
286
|
+
const { functions } = grammar
|
|
250
287
|
if (!Object.hasOwn(functions, name)) {
|
|
251
288
|
throw new Error(`Jexl Function ${name} is not defined.`)
|
|
252
289
|
}
|
|
@@ -256,15 +293,15 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
256
293
|
// argument array and needs no spread
|
|
257
294
|
switch (args.length) {
|
|
258
295
|
case 0: {
|
|
259
|
-
return (
|
|
296
|
+
return () => lookup()()
|
|
260
297
|
}
|
|
261
298
|
case 1: {
|
|
262
299
|
const [a0] = args as [CompiledNode]
|
|
263
|
-
return (
|
|
300
|
+
return (ctx) => lookup()(a0(ctx))
|
|
264
301
|
}
|
|
265
302
|
case 2: {
|
|
266
303
|
const [a0, a1] = args as [CompiledNode, CompiledNode]
|
|
267
|
-
return (
|
|
304
|
+
return (ctx) => lookup()(a0(ctx), a1(ctx))
|
|
268
305
|
}
|
|
269
306
|
case 3: {
|
|
270
307
|
const [a0, a1, a2] = args as [
|
|
@@ -272,16 +309,16 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
272
309
|
CompiledNode,
|
|
273
310
|
CompiledNode
|
|
274
311
|
]
|
|
275
|
-
return (
|
|
312
|
+
return (ctx) => lookup()(a0(ctx), a1(ctx), a2(ctx))
|
|
276
313
|
}
|
|
277
314
|
default: {
|
|
278
315
|
const len = args.length
|
|
279
|
-
return (
|
|
316
|
+
return (ctx) => {
|
|
280
317
|
const vals: JexlValue[] = new Array(len)
|
|
281
318
|
for (let i = 0; i < len; i++) {
|
|
282
|
-
vals[i] = args[i]!(
|
|
319
|
+
vals[i] = args[i]!(ctx)
|
|
283
320
|
}
|
|
284
|
-
return lookup(
|
|
321
|
+
return lookup()(...vals)
|
|
285
322
|
}
|
|
286
323
|
}
|
|
287
324
|
}
|
|
@@ -290,10 +327,10 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
290
327
|
case 'SequenceExpression': {
|
|
291
328
|
const exprs = node.expressions.map((expr) => compileAst(expr, grammar))
|
|
292
329
|
const len = exprs.length
|
|
293
|
-
return (
|
|
330
|
+
return (ctx) => {
|
|
294
331
|
let last: JexlValue
|
|
295
332
|
for (let i = 0; i < len; i++) {
|
|
296
|
-
last = exprs[i]!(
|
|
333
|
+
last = exprs[i]!(ctx)
|
|
297
334
|
}
|
|
298
335
|
return last
|
|
299
336
|
}
|
|
@@ -303,9 +340,9 @@ export function compileAst(ast: AstNode, grammar: Grammar): CompiledNode {
|
|
|
303
340
|
const name = node.left.value
|
|
304
341
|
const right = compileAst(node.right!, grammar)
|
|
305
342
|
const store = name === '__proto__' ? defineOwn : assignOwn
|
|
306
|
-
return (
|
|
307
|
-
const value = right(
|
|
308
|
-
store(
|
|
343
|
+
return (ctx) => {
|
|
344
|
+
const value = right(ctx)
|
|
345
|
+
store(ctx, name, value)
|
|
309
346
|
return value
|
|
310
347
|
}
|
|
311
348
|
}
|
package/src/grammar.ts
CHANGED
|
@@ -231,7 +231,7 @@ export const getGrammar = (): Grammar => ({
|
|
|
231
231
|
|
|
232
232
|
/**
|
|
233
233
|
* A map of function names to javascript functions. A Jexl function
|
|
234
|
-
* takes zero
|
|
234
|
+
* takes zero or more arguments:
|
|
235
235
|
*
|
|
236
236
|
* - {*} ...args: A variable number of arguments passed to this function.
|
|
237
237
|
* All of these are pre-evaluated to their actual values before calling
|