@jmespath-community/jmespath 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -8
- package/dist/cli.cjs +2816 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.mjs +857 -244
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +849 -268
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +86 -34
- package/dist/index.d.ts +86 -34
- package/dist/index.esm.js +850 -242
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +5 -1
- package/dist/index.esm.min.js.map +1 -1
- package/dist/index.mjs +850 -242
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +852 -273
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +5 -1
- package/dist/index.umd.min.js.map +1 -1
- package/package.json +41 -6
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,89 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { parseArgs } from 'util';
|
|
3
2
|
import * as fs from 'fs';
|
|
3
|
+
import { parseArgs } from 'util';
|
|
4
4
|
|
|
5
5
|
// package.json
|
|
6
6
|
var package_default = {
|
|
7
7
|
name: "@jmespath-community/jmespath",
|
|
8
|
-
version: "1.
|
|
8
|
+
version: "1.4.0"};
|
|
9
|
+
|
|
10
|
+
// src/utils/ast.ts
|
|
11
|
+
var CHILD_PROPS = ["left", "right", "condition", "child", "operand", "trueExpr", "falseExpr", "expression"];
|
|
12
|
+
function pushChildren(node, stack) {
|
|
13
|
+
const n = node;
|
|
14
|
+
for (const prop of CHILD_PROPS) {
|
|
15
|
+
const val = n[prop];
|
|
16
|
+
if (val && typeof val === "object" && "type" in val) {
|
|
17
|
+
stack.push(val);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(n.children)) {
|
|
21
|
+
for (const item of n.children) {
|
|
22
|
+
if (!item) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
stack.push(item);
|
|
26
|
+
if (item.type === "KeyValuePair" && item.value) {
|
|
27
|
+
stack.push(item.value);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (Array.isArray(n.bindings)) {
|
|
32
|
+
for (const item of n.bindings) {
|
|
33
|
+
if (!item) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
stack.push(item);
|
|
37
|
+
if (item.reference) {
|
|
38
|
+
stack.push(item.reference);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function forEachNode(root, visitor) {
|
|
44
|
+
const stack = [root];
|
|
45
|
+
while (stack.length > 0) {
|
|
46
|
+
const current = stack.pop();
|
|
47
|
+
if (!current) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
if (visitor(current) === false) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
pushChildren(current, stack);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function countNodes(root) {
|
|
57
|
+
let count = 0;
|
|
58
|
+
forEachNode(root, () => {
|
|
59
|
+
count += 1;
|
|
60
|
+
return true;
|
|
61
|
+
});
|
|
62
|
+
return count;
|
|
63
|
+
}
|
|
64
|
+
function findDisallowedFunction(root, options) {
|
|
65
|
+
const { allowedFunctions, disallowedFunctions } = options;
|
|
66
|
+
if (!allowedFunctions && !disallowedFunctions) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
let violation = null;
|
|
70
|
+
forEachNode(root, (node) => {
|
|
71
|
+
if (node.type !== "Function") {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
const name = node.name;
|
|
75
|
+
if (allowedFunctions && !allowedFunctions.includes(name)) {
|
|
76
|
+
violation = `Function '${name}' is not allowed`;
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (disallowedFunctions && disallowedFunctions.includes(name)) {
|
|
80
|
+
violation = `Function '${name}' is disallowed`;
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
});
|
|
85
|
+
return violation;
|
|
86
|
+
}
|
|
9
87
|
|
|
10
88
|
// src/utils/index.ts
|
|
11
89
|
var isObject = (obj) => {
|
|
@@ -56,9 +134,6 @@ var isFalse = (obj) => {
|
|
|
56
134
|
if (Array.isArray(obj)) {
|
|
57
135
|
return obj.length === 0;
|
|
58
136
|
}
|
|
59
|
-
if (obj === null) {
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
137
|
return Object.keys(obj).length === 0;
|
|
63
138
|
}
|
|
64
139
|
return false;
|
|
@@ -103,111 +178,28 @@ var notZero = (n) => {
|
|
|
103
178
|
};
|
|
104
179
|
var add = (left, right) => {
|
|
105
180
|
ensureNumbers(left, right);
|
|
106
|
-
|
|
107
|
-
return result;
|
|
181
|
+
return left + right;
|
|
108
182
|
};
|
|
109
183
|
var sub = (left, right) => {
|
|
110
184
|
ensureNumbers(left, right);
|
|
111
|
-
|
|
112
|
-
return result;
|
|
185
|
+
return left - right;
|
|
113
186
|
};
|
|
114
187
|
var mul = (left, right) => {
|
|
115
188
|
ensureNumbers(left, right);
|
|
116
|
-
|
|
117
|
-
return result;
|
|
189
|
+
return left * right;
|
|
118
190
|
};
|
|
119
191
|
var divide = (left, right) => {
|
|
120
192
|
ensureNumbers(left, right);
|
|
121
|
-
|
|
122
|
-
return result;
|
|
193
|
+
return left / notZero(right);
|
|
123
194
|
};
|
|
124
195
|
var div = (left, right) => {
|
|
125
196
|
ensureNumbers(left, right);
|
|
126
|
-
|
|
127
|
-
return result;
|
|
197
|
+
return Math.floor(left / notZero(right));
|
|
128
198
|
};
|
|
129
199
|
var mod = (left, right) => {
|
|
130
200
|
ensureNumbers(left, right);
|
|
131
|
-
|
|
132
|
-
return result;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
// src/utils/strings.ts
|
|
136
|
-
var findFirst = (subject, sub2, start, end) => {
|
|
137
|
-
if (!subject || !sub2) {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
start = Math.max(ensureInteger(start = start || 0), 0);
|
|
141
|
-
end = Math.min(ensureInteger(end = end || subject.length), subject.length);
|
|
142
|
-
const offset = subject.slice(start, end).indexOf(sub2);
|
|
143
|
-
return offset === -1 ? null : offset + start;
|
|
144
|
-
};
|
|
145
|
-
var findLast = (subject, sub2, start, end) => {
|
|
146
|
-
if (!subject || !sub2) {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
start = Math.max(ensureInteger(start = start || 0), 0);
|
|
150
|
-
end = Math.min(ensureInteger(end = end || subject.length), subject.length);
|
|
151
|
-
const offset = subject.slice(start, end).lastIndexOf(sub2);
|
|
152
|
-
const result = offset === -1 ? null : offset + start;
|
|
153
|
-
return result;
|
|
154
|
-
};
|
|
155
|
-
var lower = (subject) => subject.toLowerCase();
|
|
156
|
-
var ensurePadFuncParams = (name, width, padding) => {
|
|
157
|
-
padding = padding || " ";
|
|
158
|
-
if (padding.length > 1) {
|
|
159
|
-
throw new Error(`invalid value, ${name} expects its 'pad' parameter to be a valid string with a single codepoint`);
|
|
160
|
-
}
|
|
161
|
-
ensurePositiveInteger(width);
|
|
162
|
-
return padding;
|
|
163
|
-
};
|
|
164
|
-
var padLeft = (subject, width, padding) => {
|
|
165
|
-
padding = ensurePadFuncParams("pad_left", width, padding);
|
|
166
|
-
return subject && subject.padStart(width, padding) || "";
|
|
167
|
-
};
|
|
168
|
-
var padRight = (subject, width, padding) => {
|
|
169
|
-
padding = ensurePadFuncParams("pad_right", width, padding);
|
|
170
|
-
return subject && subject.padEnd(width, padding) || "";
|
|
171
|
-
};
|
|
172
|
-
var replace = (subject, string, by, count) => {
|
|
173
|
-
if (count === 0) {
|
|
174
|
-
return subject;
|
|
175
|
-
}
|
|
176
|
-
if (!count) {
|
|
177
|
-
return subject.split(string).join(by);
|
|
178
|
-
}
|
|
179
|
-
ensurePositiveInteger(count);
|
|
180
|
-
[...Array(count).keys()].map(() => subject = subject.replace(string, by));
|
|
181
|
-
return subject;
|
|
182
|
-
};
|
|
183
|
-
var split = (subject, search2, count) => {
|
|
184
|
-
if (subject.length == 0 && search2.length === 0) {
|
|
185
|
-
return [];
|
|
186
|
-
}
|
|
187
|
-
if (count === null || count === void 0) {
|
|
188
|
-
return subject.split(search2);
|
|
189
|
-
}
|
|
190
|
-
ensurePositiveInteger(count);
|
|
191
|
-
if (count === 0) {
|
|
192
|
-
return [subject];
|
|
193
|
-
}
|
|
194
|
-
const split2 = subject.split(search2);
|
|
195
|
-
return [...split2.slice(0, count), split2.slice(count).join(search2)];
|
|
196
|
-
};
|
|
197
|
-
var trim = (subject, chars) => {
|
|
198
|
-
return trimLeft(trimRight(subject, chars), chars);
|
|
199
|
-
};
|
|
200
|
-
var trimLeft = (subject, chars) => {
|
|
201
|
-
return trimImpl(subject, (list) => new RegExp(`^[${list}]*(.*?)`), chars);
|
|
202
|
-
};
|
|
203
|
-
var trimRight = (subject, chars) => {
|
|
204
|
-
return trimImpl(subject, (list) => new RegExp(`(.*?)[${list}]*$`), chars);
|
|
205
|
-
};
|
|
206
|
-
var trimImpl = (subject, regExper, chars) => {
|
|
207
|
-
const pattern = chars ? chars.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&") : "\\s\x85";
|
|
208
|
-
return subject.replace(regExper(pattern), "$1");
|
|
201
|
+
return left % right;
|
|
209
202
|
};
|
|
210
|
-
var upper = (subject) => subject.toUpperCase();
|
|
211
203
|
|
|
212
204
|
// src/Lexer.ts
|
|
213
205
|
var basicTokens = {
|
|
@@ -388,7 +380,7 @@ var StreamLexer = class {
|
|
|
388
380
|
}
|
|
389
381
|
this._current += 1;
|
|
390
382
|
const literal = stream.slice(start + 1, this._current - 1);
|
|
391
|
-
return replace(
|
|
383
|
+
return literal.replace(/\\(['\\])/g, "$1");
|
|
392
384
|
}
|
|
393
385
|
consumeNumber(stream) {
|
|
394
386
|
const start = this._current;
|
|
@@ -553,14 +545,25 @@ var bindingPower = {
|
|
|
553
545
|
var TokenParser = class _TokenParser {
|
|
554
546
|
index = 0;
|
|
555
547
|
tokens = [];
|
|
548
|
+
depth = 0;
|
|
549
|
+
maxDepth;
|
|
550
|
+
nodeCount = 0;
|
|
551
|
+
maxNodes;
|
|
556
552
|
parse(expression2, options) {
|
|
557
553
|
this.loadTokens(expression2, options || { enable_legacy_literals: false });
|
|
558
554
|
this.index = 0;
|
|
555
|
+
this.depth = 0;
|
|
556
|
+
this.nodeCount = 0;
|
|
557
|
+
this.maxDepth = options?.maxDepth;
|
|
558
|
+
this.maxNodes = options?.maxNodes;
|
|
559
559
|
const ast = this.expression(0);
|
|
560
560
|
if (this.lookahead(0) !== "EOF" /* TOK_EOF */) {
|
|
561
561
|
const token = this.lookaheadToken(0);
|
|
562
562
|
this.errorToken(token, `Syntax error: unexpected token type: ${token.type}, value: ${token.value}`);
|
|
563
563
|
}
|
|
564
|
+
if (this.maxNodes !== void 0 && countNodes(ast) > this.maxNodes) {
|
|
565
|
+
throw new Error(`Expression exceeds maximum allowed node count of ${this.maxNodes}`);
|
|
566
|
+
}
|
|
564
567
|
return ast;
|
|
565
568
|
}
|
|
566
569
|
loadTokens(expression2, options) {
|
|
@@ -568,16 +571,32 @@ var TokenParser = class _TokenParser {
|
|
|
568
571
|
this.tokens.push({ type: "EOF" /* TOK_EOF */, value: "", start: expression2.length });
|
|
569
572
|
}
|
|
570
573
|
expression(rbp) {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
574
|
+
if (this.maxDepth !== void 0 && this.depth >= this.maxDepth) {
|
|
575
|
+
throw new Error(`Expression exceeds maximum allowed depth of ${this.maxDepth}`);
|
|
576
|
+
}
|
|
577
|
+
this.depth += 1;
|
|
578
|
+
this.trackNode();
|
|
579
|
+
try {
|
|
580
|
+
const leftToken = this.lookaheadToken(0);
|
|
576
581
|
this.advance();
|
|
577
|
-
left = this.
|
|
578
|
-
currentTokenType = this.lookahead(0);
|
|
582
|
+
let left = this.nud(leftToken);
|
|
583
|
+
let currentTokenType = this.lookahead(0);
|
|
584
|
+
while (rbp < bindingPower[currentTokenType]) {
|
|
585
|
+
this.trackNode();
|
|
586
|
+
this.advance();
|
|
587
|
+
left = this.led(currentTokenType, left);
|
|
588
|
+
currentTokenType = this.lookahead(0);
|
|
589
|
+
}
|
|
590
|
+
return left;
|
|
591
|
+
} finally {
|
|
592
|
+
this.depth -= 1;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
trackNode() {
|
|
596
|
+
this.nodeCount += 1;
|
|
597
|
+
if (this.maxNodes !== void 0 && this.nodeCount > this.maxNodes) {
|
|
598
|
+
throw new Error(`Expression exceeds maximum allowed node count of ${this.maxNodes}`);
|
|
579
599
|
}
|
|
580
|
-
return left;
|
|
581
600
|
}
|
|
582
601
|
lookahead(offset) {
|
|
583
602
|
return this.tokens[this.index + offset].type;
|
|
@@ -804,9 +823,13 @@ var TokenParser = class _TokenParser {
|
|
|
804
823
|
right
|
|
805
824
|
};
|
|
806
825
|
if (right.type === "Slice") {
|
|
826
|
+
const rhs = this.parseProjectionRHS(bindingPower.Star);
|
|
827
|
+
if (rhs.type === "Identity") {
|
|
828
|
+
return indexExpr;
|
|
829
|
+
}
|
|
807
830
|
return {
|
|
808
831
|
left: indexExpr,
|
|
809
|
-
right:
|
|
832
|
+
right: rhs,
|
|
810
833
|
type: "Projection"
|
|
811
834
|
};
|
|
812
835
|
}
|
|
@@ -966,6 +989,83 @@ var TokenParser = class _TokenParser {
|
|
|
966
989
|
var Parser = new TokenParser();
|
|
967
990
|
var Parser_default = Parser;
|
|
968
991
|
|
|
992
|
+
// src/utils/strings.ts
|
|
993
|
+
var findFirst = (subject, sub2, start, end) => {
|
|
994
|
+
if (!subject || !sub2) {
|
|
995
|
+
return null;
|
|
996
|
+
}
|
|
997
|
+
const s = Math.max(ensureInteger(start ?? 0), 0);
|
|
998
|
+
const e = Math.min(ensureInteger(end ?? subject.length), subject.length);
|
|
999
|
+
const offset = subject.slice(s, e).indexOf(sub2);
|
|
1000
|
+
return offset === -1 ? null : offset + s;
|
|
1001
|
+
};
|
|
1002
|
+
var findLast = (subject, sub2, start, end) => {
|
|
1003
|
+
if (!subject || !sub2) {
|
|
1004
|
+
return null;
|
|
1005
|
+
}
|
|
1006
|
+
const s = Math.max(ensureInteger(start ?? 0), 0);
|
|
1007
|
+
const e = Math.min(ensureInteger(end ?? subject.length), subject.length);
|
|
1008
|
+
const offset = subject.slice(s, e).lastIndexOf(sub2);
|
|
1009
|
+
return offset === -1 ? null : offset + s;
|
|
1010
|
+
};
|
|
1011
|
+
var lower = (subject) => subject.toLowerCase();
|
|
1012
|
+
var ensurePadFuncParams = (name, width, padding = " ") => {
|
|
1013
|
+
if (padding.length > 1) {
|
|
1014
|
+
throw new Error(`invalid value, ${name} expects its 'pad' parameter to be a valid string with a single codepoint`);
|
|
1015
|
+
}
|
|
1016
|
+
ensurePositiveInteger(width);
|
|
1017
|
+
return padding;
|
|
1018
|
+
};
|
|
1019
|
+
var padLeft = (subject, width, padding) => {
|
|
1020
|
+
padding = ensurePadFuncParams("pad_left", width, padding);
|
|
1021
|
+
return subject && subject.padStart(width, padding) || "";
|
|
1022
|
+
};
|
|
1023
|
+
var padRight = (subject, width, padding) => {
|
|
1024
|
+
padding = ensurePadFuncParams("pad_right", width, padding);
|
|
1025
|
+
return subject && subject.padEnd(width, padding) || "";
|
|
1026
|
+
};
|
|
1027
|
+
var replace = (subject, string, by, count) => {
|
|
1028
|
+
if (count === 0) {
|
|
1029
|
+
return subject;
|
|
1030
|
+
}
|
|
1031
|
+
if (!count) {
|
|
1032
|
+
return subject.split(string).join(by);
|
|
1033
|
+
}
|
|
1034
|
+
ensurePositiveInteger(count);
|
|
1035
|
+
while (count-- > 0 && subject.includes(string)) {
|
|
1036
|
+
subject = subject.replace(string, by);
|
|
1037
|
+
}
|
|
1038
|
+
return subject;
|
|
1039
|
+
};
|
|
1040
|
+
var split = (subject, search2, count) => {
|
|
1041
|
+
if (subject.length == 0 && search2.length === 0) {
|
|
1042
|
+
return [];
|
|
1043
|
+
}
|
|
1044
|
+
if (count === null || count === void 0) {
|
|
1045
|
+
return subject.split(search2);
|
|
1046
|
+
}
|
|
1047
|
+
ensurePositiveInteger(count);
|
|
1048
|
+
if (count === 0) {
|
|
1049
|
+
return [subject];
|
|
1050
|
+
}
|
|
1051
|
+
const split2 = subject.split(search2);
|
|
1052
|
+
return [...split2.slice(0, count), split2.slice(count).join(search2)];
|
|
1053
|
+
};
|
|
1054
|
+
var trim = (subject, chars) => {
|
|
1055
|
+
return trimLeft(trimRight(subject, chars), chars);
|
|
1056
|
+
};
|
|
1057
|
+
var trimLeft = (subject, chars) => {
|
|
1058
|
+
return trimImpl(subject, (list) => new RegExp(`^[${list}]*(.*?)`), chars);
|
|
1059
|
+
};
|
|
1060
|
+
var trimRight = (subject, chars) => {
|
|
1061
|
+
return trimImpl(subject, (list) => new RegExp(`(.*?)[${list}]*$`), chars);
|
|
1062
|
+
};
|
|
1063
|
+
var trimImpl = (subject, regExper, chars) => {
|
|
1064
|
+
const pattern = chars ? chars.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&") : "\\s\x85";
|
|
1065
|
+
return subject.replace(regExper(pattern), "$1");
|
|
1066
|
+
};
|
|
1067
|
+
var upper = (subject) => subject.toUpperCase();
|
|
1068
|
+
|
|
969
1069
|
// src/utils/text.ts
|
|
970
1070
|
var Text = class _Text {
|
|
971
1071
|
_text;
|
|
@@ -976,7 +1076,11 @@ var Text = class _Text {
|
|
|
976
1076
|
return this._text;
|
|
977
1077
|
}
|
|
978
1078
|
get length() {
|
|
979
|
-
|
|
1079
|
+
let count = 0;
|
|
1080
|
+
for (const _ of this._text) {
|
|
1081
|
+
count += 1;
|
|
1082
|
+
}
|
|
1083
|
+
return count;
|
|
980
1084
|
}
|
|
981
1085
|
compareTo(other) {
|
|
982
1086
|
return _Text.compare(this, new _Text(other));
|
|
@@ -1011,6 +1115,12 @@ var Text = class _Text {
|
|
|
1011
1115
|
var createMathFunction = (mathFn) => ([value]) => mathFn(value);
|
|
1012
1116
|
var createStringFunction = (stringFn) => ([subject]) => stringFn(subject);
|
|
1013
1117
|
var createObjectFunction = (objFn) => ([obj]) => objFn(obj);
|
|
1118
|
+
var ARRAY_SUBTYPES = {
|
|
1119
|
+
[8 /* TYPE_ARRAY_NUMBER */]: 0 /* TYPE_NUMBER */,
|
|
1120
|
+
[10 /* TYPE_ARRAY_OBJECT */]: 4 /* TYPE_OBJECT */,
|
|
1121
|
+
[9 /* TYPE_ARRAY_STRING */]: 2 /* TYPE_STRING */,
|
|
1122
|
+
[11 /* TYPE_ARRAY_ARRAY */]: 3 /* TYPE_ARRAY */
|
|
1123
|
+
};
|
|
1014
1124
|
var Runtime = class {
|
|
1015
1125
|
_interpreter;
|
|
1016
1126
|
_functionTable;
|
|
@@ -1328,34 +1438,18 @@ var Runtime = class {
|
|
|
1328
1438
|
if (expected === 1 /* TYPE_ANY */) {
|
|
1329
1439
|
return true;
|
|
1330
1440
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
if (actual === 3 /* TYPE_ARRAY */) {
|
|
1336
|
-
let subtype;
|
|
1337
|
-
if (expected === 8 /* TYPE_ARRAY_NUMBER */) {
|
|
1338
|
-
subtype = 0 /* TYPE_NUMBER */;
|
|
1339
|
-
} else if (expected === 10 /* TYPE_ARRAY_OBJECT */) {
|
|
1340
|
-
subtype = 4 /* TYPE_OBJECT */;
|
|
1341
|
-
} else if (expected === 9 /* TYPE_ARRAY_STRING */) {
|
|
1342
|
-
subtype = 2 /* TYPE_STRING */;
|
|
1343
|
-
} else if (expected === 11 /* TYPE_ARRAY_ARRAY */) {
|
|
1344
|
-
subtype = 3 /* TYPE_ARRAY */;
|
|
1345
|
-
}
|
|
1346
|
-
const array = argValue;
|
|
1347
|
-
for (let i = 0; i < array.length; i += 1) {
|
|
1348
|
-
const typeName = this.getTypeName(array[i]);
|
|
1349
|
-
if (typeName !== void 0 && subtype !== void 0 && !this.typeMatches(typeName, subtype, array[i])) {
|
|
1350
|
-
return false;
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
return true;
|
|
1441
|
+
const subtype = ARRAY_SUBTYPES[expected];
|
|
1442
|
+
if (subtype !== void 0) {
|
|
1443
|
+
if (actual !== 3 /* TYPE_ARRAY */) {
|
|
1444
|
+
return false;
|
|
1354
1445
|
}
|
|
1355
|
-
|
|
1356
|
-
return
|
|
1446
|
+
const array = argValue;
|
|
1447
|
+
return array.every((item) => {
|
|
1448
|
+
const typeName = this.getTypeName(item);
|
|
1449
|
+
return typeName === void 0 || this.typeMatches(typeName, subtype, item);
|
|
1450
|
+
});
|
|
1357
1451
|
}
|
|
1358
|
-
return
|
|
1452
|
+
return actual === expected;
|
|
1359
1453
|
}
|
|
1360
1454
|
getTypeName(obj) {
|
|
1361
1455
|
if (obj === null) {
|
|
@@ -1419,9 +1513,8 @@ var Runtime = class {
|
|
|
1419
1513
|
}
|
|
1420
1514
|
return null;
|
|
1421
1515
|
};
|
|
1422
|
-
functionEndsWith = (
|
|
1423
|
-
|
|
1424
|
-
return searchStr.includes(suffix, searchStr.length - suffix.length);
|
|
1516
|
+
functionEndsWith = ([searchStr, suffix]) => {
|
|
1517
|
+
return searchStr.endsWith(suffix);
|
|
1425
1518
|
};
|
|
1426
1519
|
functionFindFirst = this.createFindFunction(findFirst);
|
|
1427
1520
|
functionFindLast = this.createFindFunction(findLast);
|
|
@@ -1435,21 +1528,24 @@ var Runtime = class {
|
|
|
1435
1528
|
};
|
|
1436
1529
|
}
|
|
1437
1530
|
functionFromItems = ([array]) => {
|
|
1438
|
-
|
|
1439
|
-
if (pair.length
|
|
1531
|
+
for (const pair of array) {
|
|
1532
|
+
if (pair.length !== 2 || typeof pair[0] !== "string") {
|
|
1440
1533
|
throw new Error("invalid value, each array must contain two elements, a pair of string and value");
|
|
1441
1534
|
}
|
|
1442
|
-
}
|
|
1535
|
+
}
|
|
1443
1536
|
return Object.fromEntries(array);
|
|
1444
1537
|
};
|
|
1445
1538
|
functionGroupBy = ([array, exprefNode]) => {
|
|
1446
1539
|
const keyFunction = this.createKeyFunction(exprefNode, [2 /* TYPE_STRING */]);
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
const
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1540
|
+
const groups = {};
|
|
1541
|
+
for (const item of array) {
|
|
1542
|
+
const key = keyFunction(item);
|
|
1543
|
+
if (!groups[key]) {
|
|
1544
|
+
groups[key] = [];
|
|
1545
|
+
}
|
|
1546
|
+
groups[key].push(item);
|
|
1547
|
+
}
|
|
1548
|
+
return groups;
|
|
1453
1549
|
};
|
|
1454
1550
|
functionItems = ([inputValue]) => {
|
|
1455
1551
|
return Object.entries(inputValue);
|
|
@@ -1512,12 +1608,7 @@ var Runtime = class {
|
|
|
1512
1608
|
return maxRecord || null;
|
|
1513
1609
|
};
|
|
1514
1610
|
functionMerge = (resolvedArgs) => {
|
|
1515
|
-
|
|
1516
|
-
for (let i = 0; i < resolvedArgs.length; i += 1) {
|
|
1517
|
-
const current = resolvedArgs[i];
|
|
1518
|
-
merged = Object.assign(merged, current);
|
|
1519
|
-
}
|
|
1520
|
-
return merged;
|
|
1611
|
+
return Object.assign({}, ...resolvedArgs);
|
|
1521
1612
|
};
|
|
1522
1613
|
functionMin = ([inputValue]) => {
|
|
1523
1614
|
if (!inputValue.length) {
|
|
@@ -1553,12 +1644,7 @@ var Runtime = class {
|
|
|
1553
1644
|
return minRecord || null;
|
|
1554
1645
|
};
|
|
1555
1646
|
functionNotNull = (resolvedArgs) => {
|
|
1556
|
-
|
|
1557
|
-
if (this.getTypeName(resolvedArgs[i]) !== 7 /* TYPE_NULL */) {
|
|
1558
|
-
return resolvedArgs[i];
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
return null;
|
|
1647
|
+
return resolvedArgs.find((arg) => arg !== null) ?? null;
|
|
1562
1648
|
};
|
|
1563
1649
|
functionPadLeft = this.createPadFunction(padLeft);
|
|
1564
1650
|
functionPadRight = this.createPadFunction(padRight);
|
|
@@ -1586,12 +1672,12 @@ var Runtime = class {
|
|
|
1586
1672
|
if (typeName === 2 /* TYPE_STRING */) {
|
|
1587
1673
|
return new Text(inputValue).reverse();
|
|
1588
1674
|
}
|
|
1589
|
-
const reversedArray = inputValue
|
|
1675
|
+
const reversedArray = [...inputValue];
|
|
1590
1676
|
reversedArray.reverse();
|
|
1591
1677
|
return reversedArray;
|
|
1592
1678
|
};
|
|
1593
1679
|
functionSort = ([inputValue]) => {
|
|
1594
|
-
if (inputValue.length
|
|
1680
|
+
if (inputValue.length <= 1) {
|
|
1595
1681
|
return inputValue;
|
|
1596
1682
|
}
|
|
1597
1683
|
if (typeof inputValue[0] === "string") {
|
|
@@ -1600,8 +1686,8 @@ var Runtime = class {
|
|
|
1600
1686
|
return [...inputValue].sort();
|
|
1601
1687
|
};
|
|
1602
1688
|
functionSortBy = (resolvedArgs) => {
|
|
1603
|
-
const sortedArray = resolvedArgs[0]
|
|
1604
|
-
if (sortedArray.length
|
|
1689
|
+
const sortedArray = [...resolvedArgs[0]];
|
|
1690
|
+
if (sortedArray.length <= 1) {
|
|
1605
1691
|
return sortedArray;
|
|
1606
1692
|
}
|
|
1607
1693
|
const interpreter = this._interpreter;
|
|
@@ -1636,10 +1722,7 @@ var Runtime = class {
|
|
|
1636
1722
|
return inputValue.reduce((x, y) => x + y, 0);
|
|
1637
1723
|
};
|
|
1638
1724
|
functionToArray = ([inputValue]) => {
|
|
1639
|
-
|
|
1640
|
-
return inputValue;
|
|
1641
|
-
}
|
|
1642
|
-
return [inputValue];
|
|
1725
|
+
return Array.isArray(inputValue) ? inputValue : [inputValue];
|
|
1643
1726
|
};
|
|
1644
1727
|
functionToNumber = ([inputValue]) => {
|
|
1645
1728
|
const typeName = this.getTypeName(inputValue);
|
|
@@ -1656,10 +1739,7 @@ var Runtime = class {
|
|
|
1656
1739
|
return null;
|
|
1657
1740
|
};
|
|
1658
1741
|
functionToString = ([inputValue]) => {
|
|
1659
|
-
|
|
1660
|
-
return inputValue;
|
|
1661
|
-
}
|
|
1662
|
-
return JSON.stringify(inputValue);
|
|
1742
|
+
return typeof inputValue === "string" ? inputValue : JSON.stringify(inputValue);
|
|
1663
1743
|
};
|
|
1664
1744
|
functionTrim = this.createTrimFunction(trim);
|
|
1665
1745
|
functionTrimLeft = this.createTrimFunction(trimLeft);
|
|
@@ -1672,27 +1752,16 @@ var Runtime = class {
|
|
|
1672
1752
|
};
|
|
1673
1753
|
}
|
|
1674
1754
|
functionType = ([inputValue]) => {
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
return "string";
|
|
1680
|
-
case 3 /* TYPE_ARRAY */:
|
|
1681
|
-
return "array";
|
|
1682
|
-
case 4 /* TYPE_OBJECT */:
|
|
1683
|
-
return "object";
|
|
1684
|
-
case 5 /* TYPE_BOOLEAN */:
|
|
1685
|
-
return "boolean";
|
|
1686
|
-
case 7 /* TYPE_NULL */:
|
|
1687
|
-
return "null";
|
|
1688
|
-
default:
|
|
1689
|
-
throw new Error("invalid-type");
|
|
1755
|
+
const type = this.getTypeName(inputValue);
|
|
1756
|
+
const name = type !== void 0 ? this.TYPE_NAME_TABLE[type] : void 0;
|
|
1757
|
+
if (!name) {
|
|
1758
|
+
throw new Error("invalid-type");
|
|
1690
1759
|
}
|
|
1760
|
+
return name;
|
|
1691
1761
|
};
|
|
1692
1762
|
functionZip = (array) => {
|
|
1693
1763
|
const length = Math.min(...array.map((arr) => arr.length));
|
|
1694
|
-
|
|
1695
|
-
return result;
|
|
1764
|
+
return Array.from({ length }, (_, index) => array.map((arr) => arr[index]));
|
|
1696
1765
|
};
|
|
1697
1766
|
};
|
|
1698
1767
|
|
|
@@ -1726,23 +1795,108 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
1726
1795
|
runtime;
|
|
1727
1796
|
_rootValue = null;
|
|
1728
1797
|
_scope;
|
|
1729
|
-
|
|
1798
|
+
_options;
|
|
1799
|
+
_depth = 0;
|
|
1800
|
+
_deadline = 0;
|
|
1801
|
+
constructor(options) {
|
|
1730
1802
|
this.runtime = new Runtime(this);
|
|
1731
1803
|
this._scope = new ScopeChain();
|
|
1804
|
+
if (options) {
|
|
1805
|
+
this._options = options;
|
|
1806
|
+
this._deadline = options.timeoutMs !== void 0 ? Date.now() + options.timeoutMs : 0;
|
|
1807
|
+
}
|
|
1732
1808
|
}
|
|
1733
1809
|
withScope(scope) {
|
|
1734
|
-
const interpreter = new _TreeInterpreter();
|
|
1810
|
+
const interpreter = new _TreeInterpreter(this._options);
|
|
1735
1811
|
interpreter.runtime._functionTable = this.runtime._functionTable;
|
|
1736
1812
|
interpreter._rootValue = this._rootValue;
|
|
1737
1813
|
interpreter._scope = this._scope.withScope(scope);
|
|
1814
|
+
interpreter._depth = this._depth;
|
|
1815
|
+
interpreter._deadline = this._deadline;
|
|
1738
1816
|
return interpreter;
|
|
1739
1817
|
}
|
|
1740
|
-
search(node, value) {
|
|
1818
|
+
search(node, value, options) {
|
|
1819
|
+
if (options?.maxNodes !== void 0 && countNodes(node) > options.maxNodes) {
|
|
1820
|
+
throw new Error(`Expression exceeds maximum allowed node count of ${options.maxNodes}`);
|
|
1821
|
+
}
|
|
1741
1822
|
this._rootValue = value;
|
|
1742
1823
|
this._scope = emptyScopeChain;
|
|
1743
|
-
|
|
1824
|
+
this._options = options;
|
|
1825
|
+
this._depth = 0;
|
|
1826
|
+
this._deadline = options?.timeoutMs !== void 0 ? Date.now() + options.timeoutMs : 0;
|
|
1827
|
+
const result = this.visit(node, value);
|
|
1828
|
+
this.checkOutputSize(result);
|
|
1829
|
+
return result;
|
|
1830
|
+
}
|
|
1831
|
+
checkOutputSize(val) {
|
|
1832
|
+
const max = this._options?.maxOutputSize;
|
|
1833
|
+
if (max === void 0 || val == null) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
const size = Array.isArray(val) || typeof val === "string" ? val.length : typeof val === "object" ? Object.keys(val).length : 0;
|
|
1837
|
+
if (size > max) {
|
|
1838
|
+
throw new Error(`Output size exceeds maximum allowed size of ${max}`);
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
collect(target, item) {
|
|
1842
|
+
target.push(item);
|
|
1843
|
+
if (this._options?.maxOutputSize !== void 0 && target.length > this._options.maxOutputSize) {
|
|
1844
|
+
throw new Error(`Output size exceeds maximum allowed size of ${this._options.maxOutputSize}`);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
evaluateProjectionItems(items, right) {
|
|
1848
|
+
const collected = [];
|
|
1849
|
+
if (right.type === "Field") {
|
|
1850
|
+
const key = right.name;
|
|
1851
|
+
for (let i = 0; i < items.length; i++) {
|
|
1852
|
+
if (this._deadline > 0 && Date.now() >= this._deadline) {
|
|
1853
|
+
throw new Error(`Query execution timed out after ${this._options?.timeoutMs}ms`);
|
|
1854
|
+
}
|
|
1855
|
+
const elem = items[i];
|
|
1856
|
+
if (!elem || typeof elem !== "object" || Array.isArray(elem)) {
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1859
|
+
const val = elem[key];
|
|
1860
|
+
if (val !== void 0 && val !== null) {
|
|
1861
|
+
this.collect(collected, val);
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
return collected;
|
|
1865
|
+
}
|
|
1866
|
+
if (right.type === "Identity") {
|
|
1867
|
+
for (let i = 0; i < items.length; i++) {
|
|
1868
|
+
const elem = items[i];
|
|
1869
|
+
if (elem !== null) {
|
|
1870
|
+
this.collect(collected, elem);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
return collected;
|
|
1874
|
+
}
|
|
1875
|
+
for (const elem of items) {
|
|
1876
|
+
const current = this.visit(right, elem);
|
|
1877
|
+
if (current !== null) {
|
|
1878
|
+
this.collect(collected, current);
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
return collected;
|
|
1744
1882
|
}
|
|
1745
1883
|
visit(node, value) {
|
|
1884
|
+
if (this._options) {
|
|
1885
|
+
if (this._options.maxDepth !== void 0 && this._depth >= this._options.maxDepth) {
|
|
1886
|
+
throw new Error(`Evaluation exceeds maximum allowed depth of ${this._options.maxDepth}`);
|
|
1887
|
+
}
|
|
1888
|
+
if (this._deadline > 0 && Date.now() >= this._deadline) {
|
|
1889
|
+
throw new Error(`Query execution timed out after ${this._options.timeoutMs}ms`);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
this._depth += 1;
|
|
1893
|
+
try {
|
|
1894
|
+
return this.evaluateNode(node, value);
|
|
1895
|
+
} finally {
|
|
1896
|
+
this._depth -= 1;
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
evaluateNode(node, value) {
|
|
1746
1900
|
switch (node.type) {
|
|
1747
1901
|
case "Ternary": {
|
|
1748
1902
|
const condition = this.visit(node.condition, value);
|
|
@@ -1758,16 +1912,11 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
1758
1912
|
}
|
|
1759
1913
|
return value[identifier] ?? null;
|
|
1760
1914
|
case "LetExpression": {
|
|
1761
|
-
const
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
...scope,
|
|
1767
|
-
...reference
|
|
1768
|
-
};
|
|
1769
|
-
});
|
|
1770
|
-
return this.withScope(scope).visit(expression2, value);
|
|
1915
|
+
const scope = {};
|
|
1916
|
+
for (const binding of node.bindings) {
|
|
1917
|
+
Object.assign(scope, this.visit(binding, value));
|
|
1918
|
+
}
|
|
1919
|
+
return this.withScope(scope).visit(node.expression, value);
|
|
1771
1920
|
}
|
|
1772
1921
|
case "Binding": {
|
|
1773
1922
|
const { variable, reference } = node;
|
|
@@ -1799,51 +1948,27 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
1799
1948
|
return null;
|
|
1800
1949
|
}
|
|
1801
1950
|
const { start, stop, step } = this.computeSliceParams(value.length, node);
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
return this.slice(value, start, stop, step);
|
|
1808
|
-
}
|
|
1951
|
+
const target = typeof value === "string" ? [...value] : value;
|
|
1952
|
+
const sliced = this.slice(target, start, stop, step);
|
|
1953
|
+
const res = typeof value === "string" ? sliced.join("") : sliced;
|
|
1954
|
+
this.checkOutputSize(res);
|
|
1955
|
+
return res;
|
|
1809
1956
|
}
|
|
1810
1957
|
case "Projection": {
|
|
1811
1958
|
const { left, right } = node;
|
|
1812
|
-
|
|
1813
|
-
if (left.type === "IndexExpression" && left.right.type === "Slice") {
|
|
1814
|
-
allowString = true;
|
|
1815
|
-
}
|
|
1959
|
+
const allowString = left.type === "IndexExpression" && left.right.type === "Slice";
|
|
1816
1960
|
const base = this.visit(left, value);
|
|
1817
1961
|
if (allowString && typeof base === "string") {
|
|
1818
1962
|
return this.visit(right, base);
|
|
1819
1963
|
}
|
|
1820
|
-
|
|
1821
|
-
return null;
|
|
1822
|
-
}
|
|
1823
|
-
const collected = [];
|
|
1824
|
-
for (const elem of base) {
|
|
1825
|
-
const current = this.visit(right, elem);
|
|
1826
|
-
if (current !== null) {
|
|
1827
|
-
collected.push(current);
|
|
1828
|
-
}
|
|
1829
|
-
}
|
|
1830
|
-
return collected;
|
|
1964
|
+
return Array.isArray(base) ? this.evaluateProjectionItems(base, right) : null;
|
|
1831
1965
|
}
|
|
1832
1966
|
case "ValueProjection": {
|
|
1833
|
-
const
|
|
1834
|
-
const base = this.visit(left, value);
|
|
1967
|
+
const base = this.visit(node.left, value);
|
|
1835
1968
|
if (base === null || typeof base !== "object" || Array.isArray(base)) {
|
|
1836
1969
|
return null;
|
|
1837
1970
|
}
|
|
1838
|
-
|
|
1839
|
-
const values = Object.values(base);
|
|
1840
|
-
for (const elem of values) {
|
|
1841
|
-
const current = this.visit(right, elem);
|
|
1842
|
-
if (current !== null) {
|
|
1843
|
-
collected.push(current);
|
|
1844
|
-
}
|
|
1845
|
-
}
|
|
1846
|
-
return collected;
|
|
1971
|
+
return this.evaluateProjectionItems(Object.values(base), node.right);
|
|
1847
1972
|
}
|
|
1848
1973
|
case "FilterProjection": {
|
|
1849
1974
|
const { left, right, condition } = node;
|
|
@@ -1852,14 +1977,42 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
1852
1977
|
return null;
|
|
1853
1978
|
}
|
|
1854
1979
|
const results = [];
|
|
1980
|
+
if (right.type === "Field") {
|
|
1981
|
+
const key = right.name;
|
|
1982
|
+
for (let i = 0; i < base.length; i++) {
|
|
1983
|
+
const elem = base[i];
|
|
1984
|
+
if (isFalse(this.visit(condition, elem))) {
|
|
1985
|
+
continue;
|
|
1986
|
+
}
|
|
1987
|
+
if (!elem || typeof elem !== "object" || Array.isArray(elem)) {
|
|
1988
|
+
continue;
|
|
1989
|
+
}
|
|
1990
|
+
const val = elem[key];
|
|
1991
|
+
if (val !== void 0 && val !== null) {
|
|
1992
|
+
this.collect(results, val);
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
return results;
|
|
1996
|
+
}
|
|
1997
|
+
if (right.type === "Identity") {
|
|
1998
|
+
for (let i = 0; i < base.length; i++) {
|
|
1999
|
+
const elem = base[i];
|
|
2000
|
+
if (isFalse(this.visit(condition, elem))) {
|
|
2001
|
+
continue;
|
|
2002
|
+
}
|
|
2003
|
+
if (elem !== null) {
|
|
2004
|
+
this.collect(results, elem);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
return results;
|
|
2008
|
+
}
|
|
1855
2009
|
for (const elem of base) {
|
|
1856
|
-
|
|
1857
|
-
if (isFalse(matched)) {
|
|
2010
|
+
if (isFalse(this.visit(condition, elem))) {
|
|
1858
2011
|
continue;
|
|
1859
2012
|
}
|
|
1860
2013
|
const result = this.visit(right, elem);
|
|
1861
2014
|
if (result !== null) {
|
|
1862
|
-
|
|
2015
|
+
this.collect(results, result);
|
|
1863
2016
|
}
|
|
1864
2017
|
}
|
|
1865
2018
|
return results;
|
|
@@ -1923,7 +2076,9 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
1923
2076
|
}
|
|
1924
2077
|
case "Flatten": {
|
|
1925
2078
|
const original = this.visit(node.child, value);
|
|
1926
|
-
|
|
2079
|
+
const res = Array.isArray(original) ? original.flat() : null;
|
|
2080
|
+
this.checkOutputSize(res);
|
|
2081
|
+
return res;
|
|
1927
2082
|
}
|
|
1928
2083
|
case "Root":
|
|
1929
2084
|
return this._rootValue;
|
|
@@ -1932,6 +2087,7 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
1932
2087
|
for (const child of node.children) {
|
|
1933
2088
|
collected.push(this.visit(child, value));
|
|
1934
2089
|
}
|
|
2090
|
+
this.checkOutputSize(collected);
|
|
1935
2091
|
return collected;
|
|
1936
2092
|
}
|
|
1937
2093
|
case "MultiSelectHash": {
|
|
@@ -1939,6 +2095,7 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
1939
2095
|
for (const child of node.children) {
|
|
1940
2096
|
collected[child.name] = this.visit(child.value, value);
|
|
1941
2097
|
}
|
|
2098
|
+
this.checkOutputSize(collected);
|
|
1942
2099
|
return collected;
|
|
1943
2100
|
}
|
|
1944
2101
|
case "OrExpression": {
|
|
@@ -1962,11 +2119,19 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
1962
2119
|
case "Pipe":
|
|
1963
2120
|
return this.visit(node.right, this.visit(node.left, value));
|
|
1964
2121
|
case "Function": {
|
|
2122
|
+
if (this._options?.allowedFunctions && !this._options.allowedFunctions.includes(node.name)) {
|
|
2123
|
+
throw new Error(`Function '${node.name}' is not allowed`);
|
|
2124
|
+
}
|
|
2125
|
+
if (this._options?.disallowedFunctions && this._options.disallowedFunctions.includes(node.name)) {
|
|
2126
|
+
throw new Error(`Function '${node.name}' is disallowed`);
|
|
2127
|
+
}
|
|
1965
2128
|
const args2 = [];
|
|
1966
2129
|
for (const child of node.children) {
|
|
1967
2130
|
args2.push(this.visit(child, value));
|
|
1968
2131
|
}
|
|
1969
|
-
|
|
2132
|
+
const res = this.runtime.callFunction(node.name, args2);
|
|
2133
|
+
this.checkOutputSize(res);
|
|
2134
|
+
return res;
|
|
1970
2135
|
}
|
|
1971
2136
|
case "ExpressionReference":
|
|
1972
2137
|
return {
|
|
@@ -2004,14 +2169,19 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
2004
2169
|
return nextActualValue;
|
|
2005
2170
|
}
|
|
2006
2171
|
slice(collection, start, end, step) {
|
|
2007
|
-
|
|
2172
|
+
if (step === 1) {
|
|
2173
|
+
return collection.slice(start, end);
|
|
2174
|
+
}
|
|
2175
|
+
const len = Math.ceil(Math.abs(start - end) / Math.abs(step));
|
|
2176
|
+
const result = new Array(len);
|
|
2177
|
+
let idx = 0;
|
|
2008
2178
|
if (step > 0) {
|
|
2009
2179
|
for (let i = start; i < end; i += step) {
|
|
2010
|
-
result
|
|
2180
|
+
result[idx++] = collection[i];
|
|
2011
2181
|
}
|
|
2012
2182
|
} else {
|
|
2013
2183
|
for (let i = start; i > end; i += step) {
|
|
2014
|
-
result
|
|
2184
|
+
result[idx++] = collection[i];
|
|
2015
2185
|
}
|
|
2016
2186
|
}
|
|
2017
2187
|
return result;
|
|
@@ -2020,10 +2190,397 @@ var TreeInterpreter = class _TreeInterpreter {
|
|
|
2020
2190
|
var TreeInterpreterInstance = new TreeInterpreter();
|
|
2021
2191
|
var TreeInterpreter_default = TreeInterpreterInstance;
|
|
2022
2192
|
|
|
2193
|
+
// src/Stream.ts
|
|
2194
|
+
async function* toAsyncIterable(source) {
|
|
2195
|
+
if (source == null) {
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
if (typeof source !== "object" && typeof source !== "function") {
|
|
2199
|
+
throw new TypeError("Invalid stream source: expected AsyncIterable, Iterable, or ReadableStream");
|
|
2200
|
+
}
|
|
2201
|
+
if (Symbol.asyncIterator in source) {
|
|
2202
|
+
for await (const chunk of source) {
|
|
2203
|
+
yield chunk;
|
|
2204
|
+
}
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
if (typeof source.getReader === "function") {
|
|
2208
|
+
const reader = source.getReader();
|
|
2209
|
+
try {
|
|
2210
|
+
while (true) {
|
|
2211
|
+
const { done, value } = await reader.read();
|
|
2212
|
+
if (done) {
|
|
2213
|
+
break;
|
|
2214
|
+
}
|
|
2215
|
+
yield value;
|
|
2216
|
+
}
|
|
2217
|
+
} finally {
|
|
2218
|
+
reader.releaseLock();
|
|
2219
|
+
}
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
if (Symbol.iterator in source) {
|
|
2223
|
+
for (const chunk of source) {
|
|
2224
|
+
yield chunk;
|
|
2225
|
+
}
|
|
2226
|
+
return;
|
|
2227
|
+
}
|
|
2228
|
+
throw new TypeError("Invalid stream source: expected AsyncIterable, Iterable, or ReadableStream");
|
|
2229
|
+
}
|
|
2230
|
+
function parseItem(str, parseJson) {
|
|
2231
|
+
if (parseJson === true) {
|
|
2232
|
+
return JSON.parse(str);
|
|
2233
|
+
}
|
|
2234
|
+
if (parseJson === "auto") {
|
|
2235
|
+
try {
|
|
2236
|
+
return JSON.parse(str);
|
|
2237
|
+
} catch {
|
|
2238
|
+
return str;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
return str;
|
|
2242
|
+
}
|
|
2243
|
+
async function* normalizeSource(source, options) {
|
|
2244
|
+
const parseJson = options?.parseJson ?? "auto";
|
|
2245
|
+
const flatten = options?.flattenChunks ?? true;
|
|
2246
|
+
let buffer = "";
|
|
2247
|
+
const textDecoder = typeof TextDecoder !== "undefined" ? new TextDecoder() : null;
|
|
2248
|
+
for await (const chunk of toAsyncIterable(source)) {
|
|
2249
|
+
if (chunk instanceof Uint8Array && textDecoder) {
|
|
2250
|
+
buffer += textDecoder.decode(chunk, { stream: true });
|
|
2251
|
+
if (buffer.includes("\n")) {
|
|
2252
|
+
const lines = buffer.split("\n");
|
|
2253
|
+
buffer = lines.pop() ?? "";
|
|
2254
|
+
for (const line of lines) {
|
|
2255
|
+
const trimmed = line.trim();
|
|
2256
|
+
if (trimmed) {
|
|
2257
|
+
yield parseItem(trimmed, parseJson);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
} else if (typeof chunk === "string") {
|
|
2262
|
+
if (parseJson === false) {
|
|
2263
|
+
yield chunk;
|
|
2264
|
+
} else {
|
|
2265
|
+
buffer += chunk;
|
|
2266
|
+
if (buffer.includes("\n")) {
|
|
2267
|
+
const lines = buffer.split("\n");
|
|
2268
|
+
buffer = lines.pop() ?? "";
|
|
2269
|
+
for (const line of lines) {
|
|
2270
|
+
const trimmed = line.trim();
|
|
2271
|
+
if (trimmed) {
|
|
2272
|
+
yield parseItem(trimmed, parseJson);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
} else if (flatten && Array.isArray(chunk)) {
|
|
2278
|
+
if (buffer.trim()) {
|
|
2279
|
+
yield parseItem(buffer.trim(), parseJson);
|
|
2280
|
+
buffer = "";
|
|
2281
|
+
}
|
|
2282
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
2283
|
+
yield chunk[i];
|
|
2284
|
+
}
|
|
2285
|
+
} else {
|
|
2286
|
+
if (buffer.trim()) {
|
|
2287
|
+
yield parseItem(buffer.trim(), parseJson);
|
|
2288
|
+
buffer = "";
|
|
2289
|
+
}
|
|
2290
|
+
yield chunk;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
if (textDecoder && buffer) {
|
|
2294
|
+
buffer += textDecoder.decode();
|
|
2295
|
+
}
|
|
2296
|
+
if (buffer.trim()) {
|
|
2297
|
+
yield parseItem(buffer.trim(), parseJson);
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
function isStreamableNode(node) {
|
|
2301
|
+
switch (node.type) {
|
|
2302
|
+
case "Projection":
|
|
2303
|
+
if (node.left.type === "Identity" || node.left.type === "Current") {
|
|
2304
|
+
return true;
|
|
2305
|
+
}
|
|
2306
|
+
if (node.left.type === "IndexExpression" && node.left.right.type === "Slice") {
|
|
2307
|
+
const slice = node.left.right;
|
|
2308
|
+
return (slice.start === null || slice.start >= 0) && (slice.stop === null || slice.stop >= 0) && (slice.step === null || slice.step > 0);
|
|
2309
|
+
}
|
|
2310
|
+
return false;
|
|
2311
|
+
case "FilterProjection":
|
|
2312
|
+
return node.left.type === "Identity" || node.left.type === "Current";
|
|
2313
|
+
case "IndexExpression":
|
|
2314
|
+
if (node.right.type === "Slice" && (node.left.type === "Identity" || node.left.type === "Current")) {
|
|
2315
|
+
const slice = node.right;
|
|
2316
|
+
return (slice.start === null || slice.start >= 0) && (slice.stop === null || slice.stop >= 0) && (slice.step === null || slice.step > 0);
|
|
2317
|
+
}
|
|
2318
|
+
return true;
|
|
2319
|
+
case "Field":
|
|
2320
|
+
case "Identity":
|
|
2321
|
+
case "Current":
|
|
2322
|
+
case "Subexpression":
|
|
2323
|
+
case "MultiSelectHash":
|
|
2324
|
+
case "MultiSelectList":
|
|
2325
|
+
case "Ternary":
|
|
2326
|
+
case "Comparator":
|
|
2327
|
+
case "Arithmetic":
|
|
2328
|
+
case "NotExpression":
|
|
2329
|
+
return true;
|
|
2330
|
+
case "Pipe":
|
|
2331
|
+
return isStreamableNode(node.left) && isStreamableNode(node.right);
|
|
2332
|
+
default:
|
|
2333
|
+
return false;
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
async function* evaluateStreamNode(source, node, interpreter, options) {
|
|
2337
|
+
const deadline = options?.timeoutMs !== void 0 ? Date.now() + options.timeoutMs : 0;
|
|
2338
|
+
function checkDeadline() {
|
|
2339
|
+
if (deadline > 0 && Date.now() >= deadline) {
|
|
2340
|
+
throw new Error(`Query execution timed out after ${options?.timeoutMs}ms`);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
switch (node.type) {
|
|
2344
|
+
case "Projection": {
|
|
2345
|
+
const { left, right } = node;
|
|
2346
|
+
let streamSource = source;
|
|
2347
|
+
if (left.type === "IndexExpression" && left.right.type === "Slice") {
|
|
2348
|
+
streamSource = evaluateStreamNode(source, left, interpreter, options);
|
|
2349
|
+
}
|
|
2350
|
+
if (right.type === "Identity" || right.type === "Current") {
|
|
2351
|
+
for await (const item of streamSource) {
|
|
2352
|
+
checkDeadline();
|
|
2353
|
+
if (item !== null && item !== void 0) {
|
|
2354
|
+
yield item;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
if (right.type === "Field") {
|
|
2360
|
+
const key = right.name;
|
|
2361
|
+
for await (const item of streamSource) {
|
|
2362
|
+
checkDeadline();
|
|
2363
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
2364
|
+
const val = item[key];
|
|
2365
|
+
if (val !== void 0 && val !== null) {
|
|
2366
|
+
yield val;
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2372
|
+
for await (const item of streamSource) {
|
|
2373
|
+
checkDeadline();
|
|
2374
|
+
const res = interpreter.visit(right, item);
|
|
2375
|
+
if (res !== null && res !== void 0) {
|
|
2376
|
+
yield res;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
case "IndexExpression": {
|
|
2382
|
+
if (node.right.type === "Slice" && (node.left.type === "Identity" || node.left.type === "Current")) {
|
|
2383
|
+
const slice = node.right;
|
|
2384
|
+
const start = slice.start ?? 0;
|
|
2385
|
+
const stop = slice.stop ?? Infinity;
|
|
2386
|
+
const step = slice.step ?? 1;
|
|
2387
|
+
if (start >= 0 && stop >= 0 && step > 0) {
|
|
2388
|
+
let index = 0;
|
|
2389
|
+
for await (const item of source) {
|
|
2390
|
+
checkDeadline();
|
|
2391
|
+
if (index >= stop) {
|
|
2392
|
+
break;
|
|
2393
|
+
}
|
|
2394
|
+
if (index >= start && (index - start) % step === 0) {
|
|
2395
|
+
yield item;
|
|
2396
|
+
}
|
|
2397
|
+
index++;
|
|
2398
|
+
if (index >= stop) {
|
|
2399
|
+
break;
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
const collected = [];
|
|
2405
|
+
for await (const item of source) {
|
|
2406
|
+
checkDeadline();
|
|
2407
|
+
collected.push(item);
|
|
2408
|
+
if (options?.maxOutputSize !== void 0 && collected.length > options.maxOutputSize) {
|
|
2409
|
+
throw new Error(`Output size exceeds maximum allowed size of ${options.maxOutputSize}`);
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
const result = interpreter.search(node, collected, options);
|
|
2413
|
+
if (Array.isArray(result)) {
|
|
2414
|
+
for (const item of result) {
|
|
2415
|
+
yield item;
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
return;
|
|
2419
|
+
}
|
|
2420
|
+
for await (const item of source) {
|
|
2421
|
+
checkDeadline();
|
|
2422
|
+
const res = interpreter.visit(node, item);
|
|
2423
|
+
if (res !== null && res !== void 0) {
|
|
2424
|
+
yield res;
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
return;
|
|
2428
|
+
}
|
|
2429
|
+
case "FilterProjection": {
|
|
2430
|
+
const { condition, right } = node;
|
|
2431
|
+
if (right.type === "Identity" || right.type === "Current") {
|
|
2432
|
+
for await (const item of source) {
|
|
2433
|
+
checkDeadline();
|
|
2434
|
+
if (!isFalse(interpreter.visit(condition, item))) {
|
|
2435
|
+
yield item;
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
if (right.type === "Field") {
|
|
2441
|
+
const key = right.name;
|
|
2442
|
+
for await (const item of source) {
|
|
2443
|
+
checkDeadline();
|
|
2444
|
+
if (!isFalse(interpreter.visit(condition, item))) {
|
|
2445
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
2446
|
+
const val = item[key];
|
|
2447
|
+
if (val !== void 0 && val !== null) {
|
|
2448
|
+
yield val;
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
return;
|
|
2454
|
+
}
|
|
2455
|
+
for await (const item of source) {
|
|
2456
|
+
checkDeadline();
|
|
2457
|
+
if (!isFalse(interpreter.visit(condition, item))) {
|
|
2458
|
+
const res = interpreter.visit(right, item);
|
|
2459
|
+
if (res !== null && res !== void 0) {
|
|
2460
|
+
yield res;
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
return;
|
|
2465
|
+
}
|
|
2466
|
+
case "Pipe": {
|
|
2467
|
+
const leftStream = evaluateStreamNode(source, node.left, interpreter, options);
|
|
2468
|
+
if (isStreamableNode(node.right)) {
|
|
2469
|
+
for await (const res of evaluateStreamNode(leftStream, node.right, interpreter, options)) {
|
|
2470
|
+
yield res;
|
|
2471
|
+
}
|
|
2472
|
+
} else {
|
|
2473
|
+
const collected = [];
|
|
2474
|
+
for await (const item of leftStream) {
|
|
2475
|
+
checkDeadline();
|
|
2476
|
+
collected.push(item);
|
|
2477
|
+
if (options?.maxOutputSize !== void 0 && collected.length > options.maxOutputSize) {
|
|
2478
|
+
throw new Error(`Output size exceeds maximum allowed size of ${options.maxOutputSize}`);
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
const result = interpreter.search(node.right, collected, options);
|
|
2482
|
+
if (result !== null && result !== void 0) {
|
|
2483
|
+
yield result;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
return;
|
|
2487
|
+
}
|
|
2488
|
+
case "Identity":
|
|
2489
|
+
case "Current": {
|
|
2490
|
+
for await (const item of source) {
|
|
2491
|
+
checkDeadline();
|
|
2492
|
+
yield item;
|
|
2493
|
+
}
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
case "Field": {
|
|
2497
|
+
const key = node.name;
|
|
2498
|
+
for await (const item of source) {
|
|
2499
|
+
checkDeadline();
|
|
2500
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
2501
|
+
const val = item[key];
|
|
2502
|
+
if (val !== void 0 && val !== null) {
|
|
2503
|
+
yield val;
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
return;
|
|
2508
|
+
}
|
|
2509
|
+
default: {
|
|
2510
|
+
if (isStreamableNode(node)) {
|
|
2511
|
+
for await (const item of source) {
|
|
2512
|
+
checkDeadline();
|
|
2513
|
+
const res = interpreter.visit(node, item);
|
|
2514
|
+
if (res !== null && res !== void 0) {
|
|
2515
|
+
yield res;
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
const collected = [];
|
|
2521
|
+
for await (const item of source) {
|
|
2522
|
+
checkDeadline();
|
|
2523
|
+
collected.push(item);
|
|
2524
|
+
if (options?.maxOutputSize !== void 0 && collected.length > options.maxOutputSize) {
|
|
2525
|
+
throw new Error(`Output size exceeds maximum allowed size of ${options.maxOutputSize}`);
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
const result = interpreter.search(node, collected, options);
|
|
2529
|
+
if (result !== null && result !== void 0) {
|
|
2530
|
+
yield result;
|
|
2531
|
+
}
|
|
2532
|
+
return;
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
function isExpressionNode(val) {
|
|
2537
|
+
return typeof val === "object" && val !== null && "type" in val && typeof val.type === "string" && !(Symbol.iterator in val) && !(Symbol.asyncIterator in val);
|
|
2538
|
+
}
|
|
2539
|
+
async function* searchStream(sourceOrExpression, expressionOrSource, options) {
|
|
2540
|
+
let expression2;
|
|
2541
|
+
let source;
|
|
2542
|
+
if (typeof sourceOrExpression === "string" || isExpressionNode(sourceOrExpression)) {
|
|
2543
|
+
expression2 = sourceOrExpression;
|
|
2544
|
+
source = expressionOrSource;
|
|
2545
|
+
} else {
|
|
2546
|
+
source = sourceOrExpression;
|
|
2547
|
+
expression2 = expressionOrSource;
|
|
2548
|
+
}
|
|
2549
|
+
if (typeof expression2 !== "string" && !isExpressionNode(expression2)) {
|
|
2550
|
+
throw new TypeError("Expression must be a string or AST ExpressionNode");
|
|
2551
|
+
}
|
|
2552
|
+
const ast = typeof expression2 === "string" ? Parser_default.parse(expression2, options) : expression2;
|
|
2553
|
+
if (options) {
|
|
2554
|
+
const fnError = findDisallowedFunction(ast, options);
|
|
2555
|
+
if (fnError) {
|
|
2556
|
+
throw new Error(fnError);
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
const interpreter = new TreeInterpreter(options);
|
|
2560
|
+
interpreter.runtime._functionTable = TreeInterpreterInstance.runtime._functionTable;
|
|
2561
|
+
const items = normalizeSource(source, options);
|
|
2562
|
+
const results = evaluateStreamNode(items, ast, interpreter, options);
|
|
2563
|
+
const limit = options?.limit;
|
|
2564
|
+
const maxOutputSize = options?.maxOutputSize;
|
|
2565
|
+
let count = 0;
|
|
2566
|
+
for await (const result of results) {
|
|
2567
|
+
yield result;
|
|
2568
|
+
count++;
|
|
2569
|
+
if (limit !== void 0 && count >= limit) {
|
|
2570
|
+
break;
|
|
2571
|
+
}
|
|
2572
|
+
if (maxOutputSize !== void 0 && count > maxOutputSize) {
|
|
2573
|
+
throw new Error(`Output size exceeds maximum allowed size of ${maxOutputSize}`);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2023
2578
|
// src/index.ts
|
|
2024
2579
|
var TYPE_ANY = 1 /* TYPE_ANY */;
|
|
2025
2580
|
var TYPE_ARRAY = 3 /* TYPE_ARRAY */;
|
|
2581
|
+
var TYPE_ARRAY_ARRAY = 11 /* TYPE_ARRAY_ARRAY */;
|
|
2026
2582
|
var TYPE_ARRAY_NUMBER = 8 /* TYPE_ARRAY_NUMBER */;
|
|
2583
|
+
var TYPE_ARRAY_OBJECT = 10 /* TYPE_ARRAY_OBJECT */;
|
|
2027
2584
|
var TYPE_ARRAY_STRING = 9 /* TYPE_ARRAY_STRING */;
|
|
2028
2585
|
var TYPE_BOOLEAN = 5 /* TYPE_BOOLEAN */;
|
|
2029
2586
|
var TYPE_EXPREF = 6 /* TYPE_EXPREF */;
|
|
@@ -2032,8 +2589,37 @@ var TYPE_NUMBER = 0 /* TYPE_NUMBER */;
|
|
|
2032
2589
|
var TYPE_OBJECT = 4 /* TYPE_OBJECT */;
|
|
2033
2590
|
var TYPE_STRING = 2 /* TYPE_STRING */;
|
|
2034
2591
|
function compile(expression2, options) {
|
|
2592
|
+
return Parser_default.parse(expression2, options);
|
|
2593
|
+
}
|
|
2594
|
+
function compileQuery(expression2, options) {
|
|
2035
2595
|
const nodeTree = Parser_default.parse(expression2, options);
|
|
2036
|
-
|
|
2596
|
+
const fn = function(data) {
|
|
2597
|
+
return TreeInterpreter_default.search(nodeTree, data, options);
|
|
2598
|
+
};
|
|
2599
|
+
fn.search = (data) => TreeInterpreter_default.search(nodeTree, data, options);
|
|
2600
|
+
fn.searchStream = (source, streamOptions) => searchStream(source, nodeTree, { ...options, ...streamOptions });
|
|
2601
|
+
fn.ast = nodeTree;
|
|
2602
|
+
return fn;
|
|
2603
|
+
}
|
|
2604
|
+
function validate(expression2, options) {
|
|
2605
|
+
if (typeof expression2 !== "string") {
|
|
2606
|
+
return { valid: false, error: "Expression must be a string" };
|
|
2607
|
+
}
|
|
2608
|
+
try {
|
|
2609
|
+
const ast = Parser_default.parse(expression2, options);
|
|
2610
|
+
if (options) {
|
|
2611
|
+
const fnError = findDisallowedFunction(ast, options);
|
|
2612
|
+
if (fnError) {
|
|
2613
|
+
return { valid: false, error: fnError };
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
return { valid: true, ast };
|
|
2617
|
+
} catch (err) {
|
|
2618
|
+
return {
|
|
2619
|
+
valid: false,
|
|
2620
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2621
|
+
};
|
|
2622
|
+
}
|
|
2037
2623
|
}
|
|
2038
2624
|
function tokenize(expression2, options) {
|
|
2039
2625
|
return Lexer_default.tokenize(expression2, options);
|
|
@@ -2059,13 +2645,36 @@ var getCustomFunctions = () => {
|
|
|
2059
2645
|
var clearCustomFunctions = () => {
|
|
2060
2646
|
TreeInterpreter_default.runtime.clearCustomFunctions();
|
|
2061
2647
|
};
|
|
2648
|
+
var MAX_CACHE_SIZE = 1e3;
|
|
2649
|
+
var astCache = /* @__PURE__ */ new Map();
|
|
2062
2650
|
function search(data, expression2, options) {
|
|
2063
|
-
|
|
2064
|
-
|
|
2651
|
+
let nodeTree;
|
|
2652
|
+
if (!options) {
|
|
2653
|
+
nodeTree = astCache.get(expression2);
|
|
2654
|
+
if (!nodeTree) {
|
|
2655
|
+
nodeTree = Parser_default.parse(expression2);
|
|
2656
|
+
if (astCache.size >= MAX_CACHE_SIZE) {
|
|
2657
|
+
const firstKey = astCache.keys().next().value;
|
|
2658
|
+
if (firstKey !== void 0) {
|
|
2659
|
+
astCache.delete(firstKey);
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
astCache.set(expression2, nodeTree);
|
|
2663
|
+
}
|
|
2664
|
+
} else {
|
|
2665
|
+
nodeTree = Parser_default.parse(expression2, options);
|
|
2666
|
+
}
|
|
2667
|
+
return TreeInterpreter_default.search(nodeTree, data, options);
|
|
2668
|
+
}
|
|
2669
|
+
function Scope() {
|
|
2670
|
+
return new ScopeChain();
|
|
2065
2671
|
}
|
|
2066
2672
|
var TreeInterpreter2 = TreeInterpreter_default;
|
|
2067
2673
|
var jmespath = {
|
|
2068
2674
|
compile,
|
|
2675
|
+
compileQuery,
|
|
2676
|
+
searchStream,
|
|
2677
|
+
validate,
|
|
2069
2678
|
registerFunction,
|
|
2070
2679
|
register,
|
|
2071
2680
|
unregisterFunction,
|
|
@@ -2085,8 +2694,12 @@ var jmespath = {
|
|
|
2085
2694
|
TYPE_NULL,
|
|
2086
2695
|
TYPE_NUMBER,
|
|
2087
2696
|
TYPE_OBJECT,
|
|
2088
|
-
TYPE_STRING
|
|
2697
|
+
TYPE_STRING,
|
|
2698
|
+
TYPE_ARRAY_ARRAY,
|
|
2699
|
+
TYPE_ARRAY_OBJECT,
|
|
2700
|
+
Scope
|
|
2089
2701
|
};
|
|
2702
|
+
var index_default = jmespath;
|
|
2090
2703
|
|
|
2091
2704
|
// src/cli.ts
|
|
2092
2705
|
var args = getArgs();
|
|
@@ -2172,7 +2785,7 @@ function printResult(inputJSON2, expression2, compact = false) {
|
|
|
2172
2785
|
throw e;
|
|
2173
2786
|
}
|
|
2174
2787
|
try {
|
|
2175
|
-
console.log(JSON.stringify(
|
|
2788
|
+
console.log(JSON.stringify(index_default.search(parsedInput, expression2, void 0), null, compact ? 0 : 2));
|
|
2176
2789
|
} catch (e) {
|
|
2177
2790
|
throw e;
|
|
2178
2791
|
}
|