@jbrowse/jexl 2.3.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 +222 -0
- package/LICENSE.txt +19 -0
- package/README.md +216 -0
- package/dist/Expression.d.ts +38 -0
- package/dist/Expression.js +75 -0
- package/dist/Expression.js.map +1 -0
- package/dist/Jexl.d.ts +148 -0
- package/dist/Jexl.js +208 -0
- package/dist/Jexl.js.map +1 -0
- package/dist/Lexer.d.ts +130 -0
- package/dist/Lexer.js +321 -0
- package/dist/Lexer.js.map +1 -0
- package/dist/PromiseSync.d.ts +13 -0
- package/dist/PromiseSync.js +80 -0
- package/dist/PromiseSync.js.map +1 -0
- package/dist/evaluator/Evaluator.d.ts +92 -0
- package/dist/evaluator/Evaluator.js +153 -0
- package/dist/evaluator/Evaluator.js.map +1 -0
- package/dist/evaluator/handlers.d.ts +111 -0
- package/dist/evaluator/handlers.js +216 -0
- package/dist/evaluator/handlers.js.map +1 -0
- package/dist/grammar.d.ts +25 -0
- package/dist/grammar.js +179 -0
- package/dist/grammar.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +1 -0
- package/dist/parser/Parser.d.ts +112 -0
- package/dist/parser/Parser.js +233 -0
- package/dist/parser/Parser.js.map +1 -0
- package/dist/parser/handlers.d.ts +112 -0
- package/dist/parser/handlers.js +302 -0
- package/dist/parser/handlers.js.map +1 -0
- package/dist/parser/states.d.ts +47 -0
- package/dist/parser/states.js +195 -0
- package/dist/parser/states.js.map +1 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/esm/Expression.d.ts +38 -0
- package/esm/Expression.js +70 -0
- package/esm/Expression.js.map +1 -0
- package/esm/Jexl.d.ts +148 -0
- package/esm/Jexl.js +202 -0
- package/esm/Jexl.js.map +1 -0
- package/esm/Lexer.d.ts +130 -0
- package/esm/Lexer.js +319 -0
- package/esm/Lexer.js.map +1 -0
- package/esm/PromiseSync.d.ts +13 -0
- package/esm/PromiseSync.js +78 -0
- package/esm/PromiseSync.js.map +1 -0
- package/esm/evaluator/Evaluator.d.ts +92 -0
- package/esm/evaluator/Evaluator.js +118 -0
- package/esm/evaluator/Evaluator.js.map +1 -0
- package/esm/evaluator/handlers.d.ts +111 -0
- package/esm/evaluator/handlers.js +202 -0
- package/esm/evaluator/handlers.js.map +1 -0
- package/esm/grammar.d.ts +25 -0
- package/esm/grammar.js +175 -0
- package/esm/grammar.js.map +1 -0
- package/esm/index.d.ts +5 -0
- package/esm/index.js +9 -0
- package/esm/index.js.map +1 -0
- package/esm/parser/Parser.d.ts +112 -0
- package/esm/parser/Parser.js +198 -0
- package/esm/parser/Parser.js.map +1 -0
- package/esm/parser/handlers.d.ts +112 -0
- package/esm/parser/handlers.js +280 -0
- package/esm/parser/handlers.js.map +1 -0
- package/esm/parser/states.d.ts +47 -0
- package/esm/parser/states.js +159 -0
- package/esm/parser/states.js.map +1 -0
- package/esm/types.d.ts +77 -0
- package/esm/types.js +6 -0
- package/esm/types.js.map +1 -0
- package/package.json +67 -0
- package/src/Expression.ts +95 -0
- package/src/Jexl.ts +232 -0
- package/src/Lexer.ts +344 -0
- package/src/PromiseSync.ts +86 -0
- package/src/evaluator/Evaluator.ts +153 -0
- package/src/evaluator/handlers.ts +226 -0
- package/src/grammar.ts +200 -0
- package/src/index.ts +10 -0
- package/src/parser/Parser.ts +235 -0
- package/src/parser/handlers.ts +309 -0
- package/src/parser/states.ts +177 -0
- package/src/types.ts +107 -0
package/esm/Lexer.js
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Jexl
|
|
3
|
+
* Copyright 2020 Tom Shawver
|
|
4
|
+
*/
|
|
5
|
+
const numericRegex = /^-?(?:(?:[0-9]*\.[0-9]+)|[0-9]+)$/;
|
|
6
|
+
const identRegex = /^[a-zA-Zа-яА-Я_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF$][a-zA-Zа-яА-Я0-9_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF$]*$/;
|
|
7
|
+
const escEscRegex = /\\\\/;
|
|
8
|
+
const whitespaceRegex = /^\s*$/;
|
|
9
|
+
const preOpRegexElems = [
|
|
10
|
+
// Template strings
|
|
11
|
+
'`(?:[^`\\\\]|\\\\.)*`',
|
|
12
|
+
// Strings
|
|
13
|
+
String.raw `'(?:(?:\\')|[^'])*'`,
|
|
14
|
+
String.raw `"(?:(?:\\")|[^"])*"`,
|
|
15
|
+
// Whitespace
|
|
16
|
+
String.raw `\s+`,
|
|
17
|
+
// Booleans
|
|
18
|
+
String.raw `\btrue\b`,
|
|
19
|
+
String.raw `\bfalse\b`
|
|
20
|
+
];
|
|
21
|
+
const postOpRegexElems = [
|
|
22
|
+
// Identifiers
|
|
23
|
+
'[a-zA-Zа-яА-Я_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\\$][a-zA-Z0-9а-яА-Я_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\\$]*',
|
|
24
|
+
// Numerics (without negative symbol)
|
|
25
|
+
String.raw `(?:(?:[0-9]*\.[0-9]+)|[0-9]+)`
|
|
26
|
+
];
|
|
27
|
+
const minusNegatesAfter = new Set([
|
|
28
|
+
'binaryOp',
|
|
29
|
+
'unaryOp',
|
|
30
|
+
'openParen',
|
|
31
|
+
'openBracket',
|
|
32
|
+
'question',
|
|
33
|
+
'colon'
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Lexer is a collection of stateless, statically-accessed functions for the
|
|
37
|
+
* lexical parsing of a Jexl string. Its responsibility is to identify the
|
|
38
|
+
* "parts of speech" of a Jexl expression, and tokenize and label each, but
|
|
39
|
+
* to do only the most minimal syntax checking; the only errors the Lexer
|
|
40
|
+
* should be concerned with are if it's unable to identify the utility of
|
|
41
|
+
* any of its tokens. Errors stemming from these tokens not being in a
|
|
42
|
+
* sensible configuration should be left for the Parser to handle.
|
|
43
|
+
* @type {{}}
|
|
44
|
+
*/
|
|
45
|
+
class Lexer {
|
|
46
|
+
constructor(grammar) {
|
|
47
|
+
this._escQuoteRegexCache = new Map();
|
|
48
|
+
this._grammar = grammar;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Splits a Jexl expression string into an array of expression elements.
|
|
52
|
+
* @param {string} str A Jexl expression string
|
|
53
|
+
* @returns {Array<string>} An array of substrings defining the functional
|
|
54
|
+
* elements of the expression.
|
|
55
|
+
*/
|
|
56
|
+
getElements(str) {
|
|
57
|
+
const regex = this._getSplitRegex();
|
|
58
|
+
return str.split(regex).filter(Boolean);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Converts an array of expression elements into an array of tokens. Note that
|
|
62
|
+
* the resulting array may not equal the element array in length, as any
|
|
63
|
+
* elements that consist only of whitespace get appended to the previous
|
|
64
|
+
* token's "raw" property. For the structure of a token object, please see
|
|
65
|
+
* {@link Lexer#tokenize}.
|
|
66
|
+
* @param {Array<string>} elements An array of Jexl expression elements to be
|
|
67
|
+
* converted to tokens
|
|
68
|
+
* @returns {Array<{type, value, raw}>} an array of token objects.
|
|
69
|
+
*/
|
|
70
|
+
getTokens(elements) {
|
|
71
|
+
const tokens = [];
|
|
72
|
+
let negate = false;
|
|
73
|
+
for (let i = 0; i < elements.length; i++) {
|
|
74
|
+
if (this._isWhitespace(elements[i])) {
|
|
75
|
+
if (tokens.length) {
|
|
76
|
+
tokens[tokens.length - 1].raw += elements[i];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (elements[i] === '-' && this._isNegative(tokens)) {
|
|
80
|
+
negate = true;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
if (negate) {
|
|
84
|
+
elements[i] = '-' + elements[i];
|
|
85
|
+
negate = false;
|
|
86
|
+
}
|
|
87
|
+
tokens.push(this._createToken(elements[i]));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Catch a - at the end of the string. Let the parser handle that issue.
|
|
91
|
+
if (negate) {
|
|
92
|
+
tokens.push(this._createToken('-'));
|
|
93
|
+
}
|
|
94
|
+
return tokens;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Converts a Jexl string into an array of tokens. Each token is an object
|
|
98
|
+
* in the following format:
|
|
99
|
+
*
|
|
100
|
+
* {
|
|
101
|
+
* type: <string>,
|
|
102
|
+
* [name]: <string>,
|
|
103
|
+
* value: <boolean|number|string>,
|
|
104
|
+
* raw: <string>
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* Type is one of the following:
|
|
108
|
+
*
|
|
109
|
+
* literal, identifier, binaryOp, unaryOp
|
|
110
|
+
*
|
|
111
|
+
* OR, if the token is a control character its type is the name of the element
|
|
112
|
+
* defined in the Grammar.
|
|
113
|
+
*
|
|
114
|
+
* Name appears only if the token is a control string found in
|
|
115
|
+
* {@link grammar#elements}, and is set to the name of the element.
|
|
116
|
+
*
|
|
117
|
+
* Value is the value of the token in the correct type (boolean or numeric as
|
|
118
|
+
* appropriate). Raw is the string representation of this value taken directly
|
|
119
|
+
* from the expression string, including any trailing spaces.
|
|
120
|
+
* @param {string} str The Jexl string to be tokenized
|
|
121
|
+
* @returns {Array<{type, value, raw}>} an array of token objects.
|
|
122
|
+
* @throws {Error} if the provided string contains an invalid token.
|
|
123
|
+
*/
|
|
124
|
+
tokenize(str) {
|
|
125
|
+
const elements = this.getElements(str);
|
|
126
|
+
return this.getTokens(elements);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Creates a new token object from an element of a Jexl string. See
|
|
130
|
+
* {@link Lexer#tokenize} for a description of the token object.
|
|
131
|
+
* @param {string} element The element from which a token should be made
|
|
132
|
+
* @returns {{value: number|boolean|string, [name]: string, type: string,
|
|
133
|
+
* raw: string}} a token object describing the provided element.
|
|
134
|
+
* @throws {Error} if the provided string is not a valid expression element.
|
|
135
|
+
* @private
|
|
136
|
+
*/
|
|
137
|
+
_createToken(element) {
|
|
138
|
+
const token = {
|
|
139
|
+
type: 'literal',
|
|
140
|
+
value: element,
|
|
141
|
+
raw: element
|
|
142
|
+
};
|
|
143
|
+
if (element.startsWith('`')) {
|
|
144
|
+
token.type = 'templateString';
|
|
145
|
+
token.value = this._parseTemplateString(element);
|
|
146
|
+
return token;
|
|
147
|
+
}
|
|
148
|
+
else if (element.startsWith('"') || element.startsWith("'")) {
|
|
149
|
+
token.value = this._unquote(element);
|
|
150
|
+
}
|
|
151
|
+
else if (numericRegex.exec(element)) {
|
|
152
|
+
token.value = parseFloat(element);
|
|
153
|
+
}
|
|
154
|
+
else if (element === 'true' || element === 'false') {
|
|
155
|
+
token.value = element === 'true';
|
|
156
|
+
}
|
|
157
|
+
else if (this._grammar.elements[element]) {
|
|
158
|
+
token.type = this._grammar.elements[element].type;
|
|
159
|
+
}
|
|
160
|
+
else if (identRegex.exec(element)) {
|
|
161
|
+
token.type = 'identifier';
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
throw new Error(`Invalid expression token: ${element}`);
|
|
165
|
+
}
|
|
166
|
+
return token;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Escapes a string so that it can be treated as a string literal within a
|
|
170
|
+
* regular expression.
|
|
171
|
+
* @param {string} str The string to be escaped
|
|
172
|
+
* @returns {string} the RegExp-escaped string.
|
|
173
|
+
* @see https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
|
|
174
|
+
* @private
|
|
175
|
+
*/
|
|
176
|
+
_escapeRegExp(str) {
|
|
177
|
+
str = str.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`);
|
|
178
|
+
if (identRegex.exec(str)) {
|
|
179
|
+
str = String.raw `\b` + str + String.raw `\b`;
|
|
180
|
+
}
|
|
181
|
+
return str;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Gets a RegEx object appropriate for splitting a Jexl string into its core
|
|
185
|
+
* elements.
|
|
186
|
+
* @returns {RegExp} An element-splitting RegExp object
|
|
187
|
+
* @private
|
|
188
|
+
*/
|
|
189
|
+
_getSplitRegex() {
|
|
190
|
+
if (!this._splitRegex) {
|
|
191
|
+
// Sort by most characters to least, then regex escape each
|
|
192
|
+
const elemArray = Object.keys(this._grammar.elements)
|
|
193
|
+
.sort((a, b) => {
|
|
194
|
+
return b.length - a.length;
|
|
195
|
+
})
|
|
196
|
+
.map((elem) => {
|
|
197
|
+
return this._escapeRegExp(elem);
|
|
198
|
+
});
|
|
199
|
+
this._splitRegex = new RegExp('(' +
|
|
200
|
+
[
|
|
201
|
+
preOpRegexElems.join('|'),
|
|
202
|
+
elemArray.join('|'),
|
|
203
|
+
postOpRegexElems.join('|')
|
|
204
|
+
].join('|') +
|
|
205
|
+
')');
|
|
206
|
+
}
|
|
207
|
+
return this._splitRegex;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Determines whether the addition of a '-' token should be interpreted as a
|
|
211
|
+
* negative symbol for an upcoming number, given an array of tokens already
|
|
212
|
+
* processed.
|
|
213
|
+
* @param {Array<Object>} tokens An array of tokens already processed
|
|
214
|
+
* @returns {boolean} true if adding a '-' should be considered a negative
|
|
215
|
+
* symbol; false otherwise
|
|
216
|
+
* @private
|
|
217
|
+
*/
|
|
218
|
+
_isNegative(tokens) {
|
|
219
|
+
if (!tokens.length) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
return minusNegatesAfter.has(tokens[tokens.length - 1].type);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* A utility function to determine if a string consists of only space
|
|
226
|
+
* characters.
|
|
227
|
+
* @param {string} str A string to be tested
|
|
228
|
+
* @returns {boolean} true if the string is empty or consists of only spaces;
|
|
229
|
+
* false otherwise.
|
|
230
|
+
* @private
|
|
231
|
+
*/
|
|
232
|
+
_isWhitespace(str) {
|
|
233
|
+
return !!whitespaceRegex.exec(str);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Removes the beginning and trailing quotes from a string, unescapes any
|
|
237
|
+
* escaped quotes on its interior, and unescapes any escaped escape
|
|
238
|
+
* characters. Note that this function is not defensive; it assumes that the
|
|
239
|
+
* provided string is not empty, and that its first and last characters are
|
|
240
|
+
* actually quotes.
|
|
241
|
+
* @param {string} str A string whose first and last characters are quotes
|
|
242
|
+
* @returns {string} a string with the surrounding quotes stripped and escapes
|
|
243
|
+
* properly processed.
|
|
244
|
+
* @private
|
|
245
|
+
*/
|
|
246
|
+
_unquote(str) {
|
|
247
|
+
const quote = str[0];
|
|
248
|
+
let escQuoteRegex = this._escQuoteRegexCache.get(quote);
|
|
249
|
+
if (!escQuoteRegex) {
|
|
250
|
+
escQuoteRegex = new RegExp('\\\\' + quote, 'g');
|
|
251
|
+
this._escQuoteRegexCache.set(quote, escQuoteRegex);
|
|
252
|
+
}
|
|
253
|
+
return str
|
|
254
|
+
.slice(1, -1)
|
|
255
|
+
.replace(escQuoteRegex, quote)
|
|
256
|
+
.replace(escEscRegex, '\\');
|
|
257
|
+
}
|
|
258
|
+
_parseTemplateString(str) {
|
|
259
|
+
const parts = [];
|
|
260
|
+
let current = 1;
|
|
261
|
+
let staticStart = 1;
|
|
262
|
+
while (current < str.length - 1) {
|
|
263
|
+
if (str[current] === '\\') {
|
|
264
|
+
current += 2;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (str[current] === '$' && str[current + 1] === '{') {
|
|
268
|
+
if (current > staticStart) {
|
|
269
|
+
parts.push({
|
|
270
|
+
type: 'static',
|
|
271
|
+
value: str.slice(staticStart, current)
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
let braceDepth = 1;
|
|
275
|
+
const interpStart = current + 2;
|
|
276
|
+
current += 2;
|
|
277
|
+
while (current < str.length && braceDepth > 0) {
|
|
278
|
+
if (str[current] === '\\') {
|
|
279
|
+
current += 2;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (str[current] === '{') {
|
|
283
|
+
braceDepth++;
|
|
284
|
+
}
|
|
285
|
+
if (str[current] === '}') {
|
|
286
|
+
braceDepth--;
|
|
287
|
+
}
|
|
288
|
+
current++;
|
|
289
|
+
}
|
|
290
|
+
if (braceDepth !== 0) {
|
|
291
|
+
throw new Error(`Unclosed interpolation in template string: ${str}`);
|
|
292
|
+
}
|
|
293
|
+
parts.push({
|
|
294
|
+
type: 'interpolation',
|
|
295
|
+
value: str.slice(interpStart, current - 1)
|
|
296
|
+
});
|
|
297
|
+
staticStart = current;
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
current++;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (current > staticStart) {
|
|
304
|
+
parts.push({
|
|
305
|
+
type: 'static',
|
|
306
|
+
value: str.slice(staticStart, current)
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
return parts;
|
|
310
|
+
}
|
|
311
|
+
_unescapeTemplateString(str) {
|
|
312
|
+
return str
|
|
313
|
+
.replaceAll('\\`', '`')
|
|
314
|
+
.replaceAll(String.raw `\$`, '$')
|
|
315
|
+
.replaceAll('\\\\', '\\');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
export default Lexer;
|
|
319
|
+
//# sourceMappingURL=Lexer.js.map
|
package/esm/Lexer.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Lexer.js","sourceRoot":"","sources":["../src/Lexer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,YAAY,GAAG,mCAAmC,CAAA;AACxD,MAAM,UAAU,GACd,sHAAsH,CAAA;AACxH,MAAM,WAAW,GAAG,MAAM,CAAA;AAC1B,MAAM,eAAe,GAAG,OAAO,CAAA;AAC/B,MAAM,eAAe,GAAG;IACtB,mBAAmB;IACnB,uBAAuB;IACvB,UAAU;IACV,MAAM,CAAC,GAAG,CAAA,qBAAqB;IAC/B,MAAM,CAAC,GAAG,CAAA,qBAAqB;IAC/B,aAAa;IACb,MAAM,CAAC,GAAG,CAAA,KAAK;IACf,WAAW;IACX,MAAM,CAAC,GAAG,CAAA,UAAU;IACpB,MAAM,CAAC,GAAG,CAAA,WAAW;CACtB,CAAA;AACD,MAAM,gBAAgB,GAAG;IACvB,cAAc;IACd,wHAAwH;IACxH,qCAAqC;IACrC,MAAM,CAAC,GAAG,CAAA,+BAA+B;CAC1C,CAAA;AACD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,UAAU;IACV,SAAS;IACT,WAAW;IACX,aAAa;IACb,UAAU;IACV,OAAO;CACR,CAAC,CAAA;AAMF;;;;;;;;;GASG;AACH,MAAM,KAAK;IAKT,YAAY,OAAgB;QAF5B,wBAAmB,GAAG,IAAI,GAAG,EAAkB,CAAA;QAG7C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;IACzB,CAAC;IAED;;;;;OAKG;IACH,WAAW,CAAC,GAAW;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QACnC,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACzC,CAAC;IAED;;;;;;;;;OASG;IACH,SAAS,CAAC,QAAkB;QAC1B,MAAM,MAAM,GAAY,EAAE,CAAA;QAC1B,IAAI,MAAM,GAAG,KAAK,CAAA;QAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAA;gBAC9C,CAAC;YACH,CAAC;iBAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3D,MAAM,GAAG,IAAI,CAAA;YACf,CAAC;iBAAM,CAAC;gBACN,IAAI,MAAM,EAAE,CAAC;oBACX,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;oBAC/B,MAAM,GAAG,KAAK,CAAA;gBAChB,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC7C,CAAC;QACH,CAAC;QACD,wEAAwE;QACxE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;QACrC,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,QAAQ,CAAC,GAAW;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;QACtC,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IACjC,CAAC;IAED;;;;;;;;OAQG;IACH,YAAY,CAAC,OAAe;QAC1B,MAAM,KAAK,GAAU;YACnB,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,OAAO;SACb,CAAA;QACD,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,GAAG,gBAAgB,CAAA;YAC7B,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAChD,OAAO,KAAK,CAAA;QACd,CAAC;aAAM,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9D,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QACtC,CAAC;aAAM,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC;aAAM,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACrD,KAAK,CAAC,KAAK,GAAG,OAAO,KAAK,MAAM,CAAA;QAClC,CAAC;aAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3C,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAA;QACnD,CAAC;aAAM,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAA;QAC3B,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAA;QACzD,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;;;;;OAOG;IACH,aAAa,CAAC,GAAW;QACvB,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAAG,CAAA,KAAK,CAAC,CAAA;QAC5D,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA,IAAI,GAAG,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA,IAAI,CAAA;QAC7C,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED;;;;;OAKG;IACH,cAAc;QACZ,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,2DAA2D;YAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;iBAClD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACb,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAA;YAC5B,CAAC,CAAC;iBACD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBACZ,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;YACjC,CAAC,CAAC,CAAA;YACJ,IAAI,CAAC,WAAW,GAAG,IAAI,MAAM,CAC3B,GAAG;gBACD;oBACE,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;oBACzB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;oBACnB,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC;iBAC3B,CAAC,IAAI,CAAC,GAAG,CAAC;gBACX,GAAG,CACN,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;IAED;;;;;;;;OAQG;IACH,WAAW,CAAC,MAAe;QACzB,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IAC9D,CAAC;IAED;;;;;;;OAOG;IACH,aAAa,CAAC,GAAW;QACvB,OAAO,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACpC,CAAC;IAED;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,GAAW;QAClB,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;QACpB,IAAI,aAAa,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACvD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,aAAa,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,KAAK,EAAE,GAAG,CAAC,CAAA;YAC/C,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;QACpD,CAAC;QACD,OAAO,GAAG;aACP,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;aACZ,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC;aAC7B,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,oBAAoB,CAAC,GAAW;QAC9B,MAAM,KAAK,GAA0D,EAAE,CAAA;QACvE,IAAI,OAAO,GAAG,CAAC,CAAA;QACf,IAAI,WAAW,GAAG,CAAC,CAAA;QAEnB,OAAO,OAAO,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC,CAAA;gBACZ,SAAQ;YACV,CAAC;YAED,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACrD,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;oBAC1B,KAAK,CAAC,IAAI,CAAC;wBACT,IAAI,EAAE,QAAQ;wBACd,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC;qBACvC,CAAC,CAAA;gBACJ,CAAC;gBAED,IAAI,UAAU,GAAG,CAAC,CAAA;gBAClB,MAAM,WAAW,GAAG,OAAO,GAAG,CAAC,CAAA;gBAC/B,OAAO,IAAI,CAAC,CAAA;gBAEZ,OAAO,OAAO,GAAG,GAAG,CAAC,MAAM,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;oBAC9C,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;wBAC1B,OAAO,IAAI,CAAC,CAAA;wBACZ,SAAQ;oBACV,CAAC;oBACD,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;wBACzB,UAAU,EAAE,CAAA;oBACd,CAAC;oBACD,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;wBACzB,UAAU,EAAE,CAAA;oBACd,CAAC;oBACD,OAAO,EAAE,CAAA;gBACX,CAAC;gBAED,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;oBACrB,MAAM,IAAI,KAAK,CAAC,8CAA8C,GAAG,EAAE,CAAC,CAAA;gBACtE,CAAC;gBAED,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,eAAe;oBACrB,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,GAAG,CAAC,CAAC;iBAC3C,CAAC,CAAA;gBAEF,WAAW,GAAG,OAAO,CAAA;YACvB,CAAC;iBAAM,CAAC;gBACN,OAAO,EAAE,CAAA;YACX,CAAC;QACH,CAAC;QAED,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC;aACvC,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAED,uBAAuB,CAAC,GAAW;QACjC,OAAO,GAAG;aACP,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC;aACtB,UAAU,CAAC,MAAM,CAAC,GAAG,CAAA,IAAI,EAAE,GAAG,CAAC;aAC/B,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAC7B,CAAC;CACF;AAED,eAAe,KAAK,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
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;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Jexl
|
|
3
|
+
* Copyright 2020 Tom Shawver
|
|
4
|
+
*/
|
|
5
|
+
class PromiseSync {
|
|
6
|
+
constructor(fn) {
|
|
7
|
+
fn(this._resolve.bind(this), this._reject.bind(this));
|
|
8
|
+
}
|
|
9
|
+
catch(rejected) {
|
|
10
|
+
if (this.error) {
|
|
11
|
+
try {
|
|
12
|
+
this._resolve(rejected(this.error));
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
this._reject(e);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
// eslint-disable-next-line unicorn/no-thenable
|
|
21
|
+
then(resolved, rejected) {
|
|
22
|
+
if (!this.error) {
|
|
23
|
+
try {
|
|
24
|
+
this._resolve(resolved(this.value));
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
this._reject(e);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (rejected) {
|
|
31
|
+
this.catch(rejected);
|
|
32
|
+
}
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
_reject(error) {
|
|
36
|
+
this.value = undefined;
|
|
37
|
+
this.error = error;
|
|
38
|
+
}
|
|
39
|
+
_resolve(val) {
|
|
40
|
+
if (val instanceof PromiseSync) {
|
|
41
|
+
if (val.error) {
|
|
42
|
+
this._reject(val.error);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this._resolve(val.value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.value = val;
|
|
50
|
+
this.error = undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
static all(vals) {
|
|
54
|
+
return new PromiseSync((resolve) => {
|
|
55
|
+
const resolved = vals.map((val) => {
|
|
56
|
+
while (val instanceof PromiseSync) {
|
|
57
|
+
if (val.error) {
|
|
58
|
+
if (val.error instanceof Error) {
|
|
59
|
+
throw val.error;
|
|
60
|
+
}
|
|
61
|
+
throw new Error(typeof val.error === 'string' ? val.error : JSON.stringify(val.error));
|
|
62
|
+
}
|
|
63
|
+
val = val.value;
|
|
64
|
+
}
|
|
65
|
+
return val;
|
|
66
|
+
});
|
|
67
|
+
resolve(resolved);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
static resolve(val) {
|
|
71
|
+
return new PromiseSync((resolve) => { resolve(val); });
|
|
72
|
+
}
|
|
73
|
+
static reject(error) {
|
|
74
|
+
return new PromiseSync((_, reject) => { reject(error); });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export default PromiseSync;
|
|
78
|
+
//# sourceMappingURL=PromiseSync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromiseSync.js","sourceRoot":"","sources":["../src/PromiseSync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { AstNode } from '../types.ts';
|
|
2
|
+
interface Grammar {
|
|
3
|
+
elements: Record<string, any>;
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
}
|
|
6
|
+
type PromiseConstructor = typeof Promise | any;
|
|
7
|
+
/**
|
|
8
|
+
* The Evaluator takes a Jexl expression tree as generated by the
|
|
9
|
+
* {@link Parser} and calculates its value within a given context. The
|
|
10
|
+
* collection of transforms, context, and a relative context to be used as the
|
|
11
|
+
* root for relative identifiers, are all specific to an Evaluator instance.
|
|
12
|
+
* When any of these things change, a new instance is required. However, a
|
|
13
|
+
* single instance can be used to simultaneously evaluate many different
|
|
14
|
+
* expressions, and does not have to be reinstantiated for each.
|
|
15
|
+
* @param {{}} grammar A grammar object against which to evaluate the expression
|
|
16
|
+
* tree
|
|
17
|
+
* @param {{}} [context] A map of variable keys to their values. This will be
|
|
18
|
+
* accessed to resolve the value of each non-relative identifier. Any
|
|
19
|
+
* Promise values will be passed to the expression as their resolved
|
|
20
|
+
* value.
|
|
21
|
+
* @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
|
|
22
|
+
* to resolve the value of a relative identifier.
|
|
23
|
+
* @param {function} promise A constructor for the Promise class to be used;
|
|
24
|
+
* probably either Promise or PromiseSync.
|
|
25
|
+
*/
|
|
26
|
+
declare class Evaluator {
|
|
27
|
+
_grammar: Grammar;
|
|
28
|
+
_context: any;
|
|
29
|
+
_relContext: any;
|
|
30
|
+
Promise: PromiseConstructor;
|
|
31
|
+
constructor(grammar: Grammar, context?: any, relativeContext?: any, promise?: PromiseConstructor);
|
|
32
|
+
/**
|
|
33
|
+
* Evaluates an expression tree within the configured context.
|
|
34
|
+
* @param {{}} ast An expression tree object
|
|
35
|
+
* @returns {Promise<*>} resolves with the resulting value of the expression.
|
|
36
|
+
*/
|
|
37
|
+
eval(ast: AstNode): any;
|
|
38
|
+
/**
|
|
39
|
+
* Simultaneously evaluates each expression within an array, and delivers the
|
|
40
|
+
* response as an array with the resulting values at the same indexes as their
|
|
41
|
+
* originating expressions.
|
|
42
|
+
* @param {Array<string>} arr An array of expression strings to be evaluated
|
|
43
|
+
* @returns {Promise<Array<{}>>} resolves with the result array
|
|
44
|
+
*/
|
|
45
|
+
evalArray(arr: AstNode[]): any;
|
|
46
|
+
/**
|
|
47
|
+
* Simultaneously evaluates each expression within a map, and delivers the
|
|
48
|
+
* response as a map with the same keys, but with the evaluated result for each
|
|
49
|
+
* as their value.
|
|
50
|
+
* @param {{}} map A map of expression names to expression trees to be
|
|
51
|
+
* evaluated
|
|
52
|
+
* @returns {Promise<{}>} resolves with the result map.
|
|
53
|
+
*/
|
|
54
|
+
evalMap(map: Record<string, AstNode>): any;
|
|
55
|
+
/**
|
|
56
|
+
* Applies a filter expression with relative identifier elements to a subject.
|
|
57
|
+
* The intent is for the subject to be an array of subjects that will be
|
|
58
|
+
* individually used as the relative context against the provided expression
|
|
59
|
+
* tree. Only the elements whose expressions result in a truthy value will be
|
|
60
|
+
* included in the resulting array.
|
|
61
|
+
*
|
|
62
|
+
* If the subject is not an array of values, it will be converted to a single-
|
|
63
|
+
* element array before running the filter.
|
|
64
|
+
* @param {*} subject The value to be filtered usually an array. If this value is
|
|
65
|
+
* not an array, it will be converted to an array with this value as the
|
|
66
|
+
* only element.
|
|
67
|
+
* @param {{}} expr The expression tree to run against each subject. If the
|
|
68
|
+
* tree evaluates to a truthy result, then the value will be included in
|
|
69
|
+
* the returned array otherwise, it will be eliminated.
|
|
70
|
+
* @returns {Promise<Array>} resolves with an array of values that passed the
|
|
71
|
+
* expression filter.
|
|
72
|
+
* @private
|
|
73
|
+
*/
|
|
74
|
+
_filterRelative(subject: any, expr: AstNode): any;
|
|
75
|
+
/**
|
|
76
|
+
* Applies a static filter expression to a subject value. If the filter
|
|
77
|
+
* expression evaluates to boolean true, the subject is returned if false,
|
|
78
|
+
* undefined.
|
|
79
|
+
*
|
|
80
|
+
* For any other resulting value of the expression, this function will attempt
|
|
81
|
+
* to respond with the property at that name or index of the subject.
|
|
82
|
+
* @param {*} subject The value to be filtered. Usually an Array (for which
|
|
83
|
+
* the expression would generally resolve to a numeric index) or an
|
|
84
|
+
* Object (for which the expression would generally resolve to a string
|
|
85
|
+
* indicating a property name)
|
|
86
|
+
* @param {{}} expr The expression tree to run against the subject
|
|
87
|
+
* @returns {Promise<*>} resolves with the value of the drill-down.
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
_filterStatic(subject: any, expr: AstNode): any;
|
|
91
|
+
}
|
|
92
|
+
export default Evaluator;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Jexl
|
|
3
|
+
* Copyright 2020 Tom Shawver
|
|
4
|
+
*/
|
|
5
|
+
import * as handlers from "./handlers.js";
|
|
6
|
+
/**
|
|
7
|
+
* The Evaluator takes a Jexl expression tree as generated by the
|
|
8
|
+
* {@link Parser} and calculates its value within a given context. The
|
|
9
|
+
* collection of transforms, context, and a relative context to be used as the
|
|
10
|
+
* root for relative identifiers, are all specific to an Evaluator instance.
|
|
11
|
+
* When any of these things change, a new instance is required. However, a
|
|
12
|
+
* single instance can be used to simultaneously evaluate many different
|
|
13
|
+
* expressions, and does not have to be reinstantiated for each.
|
|
14
|
+
* @param {{}} grammar A grammar object against which to evaluate the expression
|
|
15
|
+
* tree
|
|
16
|
+
* @param {{}} [context] A map of variable keys to their values. This will be
|
|
17
|
+
* accessed to resolve the value of each non-relative identifier. Any
|
|
18
|
+
* Promise values will be passed to the expression as their resolved
|
|
19
|
+
* value.
|
|
20
|
+
* @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
|
|
21
|
+
* to resolve the value of a relative identifier.
|
|
22
|
+
* @param {function} promise A constructor for the Promise class to be used;
|
|
23
|
+
* probably either Promise or PromiseSync.
|
|
24
|
+
*/
|
|
25
|
+
class Evaluator {
|
|
26
|
+
constructor(grammar, context, relativeContext, promise = Promise) {
|
|
27
|
+
this._grammar = grammar;
|
|
28
|
+
this._context = context || {};
|
|
29
|
+
this._relContext = relativeContext || this._context;
|
|
30
|
+
this.Promise = promise;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Evaluates an expression tree within the configured context.
|
|
34
|
+
* @param {{}} ast An expression tree object
|
|
35
|
+
* @returns {Promise<*>} resolves with the resulting value of the expression.
|
|
36
|
+
*/
|
|
37
|
+
eval(ast) {
|
|
38
|
+
return this.Promise.resolve().then(() => {
|
|
39
|
+
return handlers[ast.type].call(this, ast);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Simultaneously evaluates each expression within an array, and delivers the
|
|
44
|
+
* response as an array with the resulting values at the same indexes as their
|
|
45
|
+
* originating expressions.
|
|
46
|
+
* @param {Array<string>} arr An array of expression strings to be evaluated
|
|
47
|
+
* @returns {Promise<Array<{}>>} resolves with the result array
|
|
48
|
+
*/
|
|
49
|
+
evalArray(arr) {
|
|
50
|
+
return this.Promise.all(arr.map((elem) => this.eval(elem)));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Simultaneously evaluates each expression within a map, and delivers the
|
|
54
|
+
* response as a map with the same keys, but with the evaluated result for each
|
|
55
|
+
* as their value.
|
|
56
|
+
* @param {{}} map A map of expression names to expression trees to be
|
|
57
|
+
* evaluated
|
|
58
|
+
* @returns {Promise<{}>} resolves with the result map.
|
|
59
|
+
*/
|
|
60
|
+
evalMap(map) {
|
|
61
|
+
const entries = Object.entries(map);
|
|
62
|
+
const promises = entries.map(([_, ast]) => this.eval(ast));
|
|
63
|
+
return this.Promise.all(promises).then((vals) => Object.fromEntries(entries.map(([key], idx) => [key, vals[idx]])));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Applies a filter expression with relative identifier elements to a subject.
|
|
67
|
+
* The intent is for the subject to be an array of subjects that will be
|
|
68
|
+
* individually used as the relative context against the provided expression
|
|
69
|
+
* tree. Only the elements whose expressions result in a truthy value will be
|
|
70
|
+
* included in the resulting array.
|
|
71
|
+
*
|
|
72
|
+
* If the subject is not an array of values, it will be converted to a single-
|
|
73
|
+
* element array before running the filter.
|
|
74
|
+
* @param {*} subject The value to be filtered usually an array. If this value is
|
|
75
|
+
* not an array, it will be converted to an array with this value as the
|
|
76
|
+
* only element.
|
|
77
|
+
* @param {{}} expr The expression tree to run against each subject. If the
|
|
78
|
+
* tree evaluates to a truthy result, then the value will be included in
|
|
79
|
+
* the returned array otherwise, it will be eliminated.
|
|
80
|
+
* @returns {Promise<Array>} resolves with an array of values that passed the
|
|
81
|
+
* expression filter.
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
_filterRelative(subject, expr) {
|
|
85
|
+
const arr = Array.isArray(subject)
|
|
86
|
+
? subject
|
|
87
|
+
: subject == null
|
|
88
|
+
? []
|
|
89
|
+
: [subject];
|
|
90
|
+
const promises = arr.map((elem) => new Evaluator(this._grammar, this._context, elem, this.Promise).eval(expr));
|
|
91
|
+
return this.Promise.all(promises).then((values) => arr.filter((_, idx) => values[idx]));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Applies a static filter expression to a subject value. If the filter
|
|
95
|
+
* expression evaluates to boolean true, the subject is returned if false,
|
|
96
|
+
* undefined.
|
|
97
|
+
*
|
|
98
|
+
* For any other resulting value of the expression, this function will attempt
|
|
99
|
+
* to respond with the property at that name or index of the subject.
|
|
100
|
+
* @param {*} subject The value to be filtered. Usually an Array (for which
|
|
101
|
+
* the expression would generally resolve to a numeric index) or an
|
|
102
|
+
* Object (for which the expression would generally resolve to a string
|
|
103
|
+
* indicating a property name)
|
|
104
|
+
* @param {{}} expr The expression tree to run against the subject
|
|
105
|
+
* @returns {Promise<*>} resolves with the value of the drill-down.
|
|
106
|
+
* @private
|
|
107
|
+
*/
|
|
108
|
+
_filterStatic(subject, expr) {
|
|
109
|
+
return this.eval(expr).then((res) => {
|
|
110
|
+
if (typeof res === 'boolean') {
|
|
111
|
+
return res ? subject : undefined;
|
|
112
|
+
}
|
|
113
|
+
return subject?.[res];
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export default Evaluator;
|
|
118
|
+
//# sourceMappingURL=Evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../../src/evaluator/Evaluator.ts"],"names":[],"mappings":"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"}
|