astronomical 2.0.0 → 2.1.1-rc.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/lib/cjs/index.js +223 -74
- package/lib/cjs/parseQuery.js +109 -65
- package/lib/cjs/types/index.d.ts.map +1 -1
- package/lib/cjs/types/parseQuery.d.ts +36 -7
- package/lib/cjs/types/parseQuery.d.ts.map +1 -1
- package/lib/esm/{index.mjs → index.js} +223 -74
- package/lib/esm/parseQuery.js +109 -65
- package/lib/esm/types/index.d.ts.map +1 -1
- package/lib/esm/types/parseQuery.d.ts +36 -7
- package/lib/esm/types/parseQuery.d.ts.map +1 -1
- package/package.json +2 -2
package/lib/cjs/index.js
CHANGED
|
@@ -34,9 +34,16 @@ exports.functions = {
|
|
|
34
34
|
},
|
|
35
35
|
"concat": {
|
|
36
36
|
fn: (result) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
// Optimize: combine empty check with manual flattening
|
|
38
|
+
const flattened = [];
|
|
39
|
+
for (let i = 0; i < result.length; i++) {
|
|
40
|
+
if (result[i].length === 0)
|
|
41
|
+
return [];
|
|
42
|
+
for (let j = 0; j < result[i].length; j++) {
|
|
43
|
+
flattened.push(result[i][j]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return [flattened.join("")];
|
|
40
47
|
}
|
|
41
48
|
},
|
|
42
49
|
"first": {
|
|
@@ -45,7 +52,7 @@ exports.functions = {
|
|
|
45
52
|
throw new Error("Invalid number of arugments for first");
|
|
46
53
|
if (result[0].length == 0)
|
|
47
54
|
return [];
|
|
48
|
-
return [result
|
|
55
|
+
return [result[0][0]];
|
|
49
56
|
}
|
|
50
57
|
},
|
|
51
58
|
"nthchild": {
|
|
@@ -79,14 +86,14 @@ function createQuerier() {
|
|
|
79
86
|
const traverser = createTraverser();
|
|
80
87
|
const { getChildren, getPrimitiveChildren, getPrimitiveChildrenOrNodePaths, getBinding, createNodePath, traverse } = traverser;
|
|
81
88
|
function createFilter(filter, filterResult) {
|
|
82
|
-
if (filter.type ==
|
|
89
|
+
if (filter.type == parseQuery_1.NodeType.AND || filter.type == parseQuery_1.NodeType.OR || filter.type == parseQuery_1.NodeType.EQUALS) {
|
|
83
90
|
return {
|
|
84
91
|
type: filter.type,
|
|
85
92
|
left: createFilter(filter.left, []),
|
|
86
93
|
right: createFilter(filter.right, [])
|
|
87
94
|
};
|
|
88
95
|
}
|
|
89
|
-
else if (filter.type ==
|
|
96
|
+
else if (filter.type == parseQuery_1.NodeType.LITERAL) {
|
|
90
97
|
const r = [filter.value];
|
|
91
98
|
return {
|
|
92
99
|
node: filter,
|
|
@@ -102,16 +109,16 @@ function createQuerier() {
|
|
|
102
109
|
};
|
|
103
110
|
}
|
|
104
111
|
function addFilterChildrenToState(filter, state) {
|
|
105
|
-
if ("type" in filter && (filter.type ==
|
|
112
|
+
if ("type" in filter && (filter.type == parseQuery_1.NodeType.AND || filter.type == parseQuery_1.NodeType.OR || filter.type == parseQuery_1.NodeType.EQUALS)) {
|
|
106
113
|
addFilterChildrenToState(filter.left, state);
|
|
107
114
|
addFilterChildrenToState(filter.right, state);
|
|
108
115
|
}
|
|
109
116
|
else if ("node" in filter) {
|
|
110
|
-
if (filter.node.type ==
|
|
117
|
+
if (filter.node.type == parseQuery_1.NodeType.CHILD) {
|
|
111
118
|
log?.debug("ADDING FILTER CHILD", filter.node);
|
|
112
119
|
state.child[state.depth + 1].push(filter);
|
|
113
120
|
}
|
|
114
|
-
if (filter.node.type ==
|
|
121
|
+
if (filter.node.type == parseQuery_1.NodeType.DESCENDANT) {
|
|
115
122
|
log?.debug("ADDING FILTER DESCENDANT", filter.node);
|
|
116
123
|
state.descendant[state.depth + 1].push(filter);
|
|
117
124
|
}
|
|
@@ -120,10 +127,10 @@ function createQuerier() {
|
|
|
120
127
|
function createFNodeAndAddToState(token, result, state) {
|
|
121
128
|
log?.debug("ADDING FNODE", token);
|
|
122
129
|
const fnode = createFNode(token, result);
|
|
123
|
-
if (token.type ==
|
|
130
|
+
if (token.type == parseQuery_1.NodeType.CHILD) {
|
|
124
131
|
state.child[state.depth + 1].push(fnode);
|
|
125
132
|
}
|
|
126
|
-
else if (token.type ==
|
|
133
|
+
else if (token.type == parseQuery_1.NodeType.DESCENDANT) {
|
|
127
134
|
state.descendant[state.depth + 1].push(fnode);
|
|
128
135
|
}
|
|
129
136
|
return fnode;
|
|
@@ -161,7 +168,7 @@ function createQuerier() {
|
|
|
161
168
|
addFilterChildrenToState(filter, state);
|
|
162
169
|
const child = fnode.node.child;
|
|
163
170
|
if (child) {
|
|
164
|
-
if (child.type ==
|
|
171
|
+
if (child.type == parseQuery_1.NodeType.FUNCTION) {
|
|
165
172
|
const fr = addFunction(fnode, child, path, state);
|
|
166
173
|
state.functionCalls[state.depth].push(fr);
|
|
167
174
|
}
|
|
@@ -172,7 +179,7 @@ function createQuerier() {
|
|
|
172
179
|
}
|
|
173
180
|
else {
|
|
174
181
|
const child = fnode.node.child;
|
|
175
|
-
if (child?.type ==
|
|
182
|
+
if (child?.type == parseQuery_1.NodeType.FUNCTION) {
|
|
176
183
|
const fr = addFunction(fnode, child, path, state);
|
|
177
184
|
state.functionCalls[state.depth].push(fr);
|
|
178
185
|
}
|
|
@@ -184,11 +191,11 @@ function createQuerier() {
|
|
|
184
191
|
function addFunction(rootNode, functionCall, path, state) {
|
|
185
192
|
const functionNode = { node: rootNode.node, functionCall: functionCall, parameters: [], result: [] };
|
|
186
193
|
for (const param of functionCall.parameters) {
|
|
187
|
-
if (param.type ==
|
|
194
|
+
if (param.type == parseQuery_1.NodeType.LITERAL) {
|
|
188
195
|
functionNode.parameters.push({ node: param, result: [param.value] });
|
|
189
196
|
}
|
|
190
197
|
else {
|
|
191
|
-
if (param.type ==
|
|
198
|
+
if (param.type == parseQuery_1.NodeType.FUNCTION) {
|
|
192
199
|
functionNode.parameters.push(addFunction(functionNode, param, path, state));
|
|
193
200
|
}
|
|
194
201
|
else {
|
|
@@ -214,7 +221,7 @@ function createQuerier() {
|
|
|
214
221
|
function evaluateFilter(filter, path) {
|
|
215
222
|
log?.debug("EVALUATING FILTER", filter, breadCrumb(path));
|
|
216
223
|
if ("type" in filter) {
|
|
217
|
-
if (filter.type ==
|
|
224
|
+
if (filter.type == parseQuery_1.NodeType.AND) {
|
|
218
225
|
const left = evaluateFilter(filter.left, path);
|
|
219
226
|
if (left.length == 0) {
|
|
220
227
|
return [];
|
|
@@ -222,7 +229,7 @@ function createQuerier() {
|
|
|
222
229
|
const r = evaluateFilter(filter.right, path);
|
|
223
230
|
return r;
|
|
224
231
|
}
|
|
225
|
-
if (filter.type ==
|
|
232
|
+
if (filter.type == parseQuery_1.NodeType.OR) {
|
|
226
233
|
const left = evaluateFilter(filter.left, path);
|
|
227
234
|
if (left.length > 0) {
|
|
228
235
|
return left;
|
|
@@ -230,15 +237,30 @@ function createQuerier() {
|
|
|
230
237
|
const r = evaluateFilter(filter.right, path);
|
|
231
238
|
return r;
|
|
232
239
|
}
|
|
233
|
-
if (filter.type ==
|
|
240
|
+
if (filter.type == parseQuery_1.NodeType.EQUALS) {
|
|
234
241
|
const left = evaluateFilter(filter.left, path);
|
|
235
242
|
const right = evaluateFilter(filter.right, path);
|
|
236
|
-
|
|
243
|
+
// Optimize: use Set for O(1) lookups instead of O(n) includes
|
|
244
|
+
if (right.length > 3) {
|
|
245
|
+
const rightSet = new Set(right);
|
|
246
|
+
const r = [];
|
|
247
|
+
for (let i = 0; i < left.length; i++) {
|
|
248
|
+
if (rightSet.has(left[i]))
|
|
249
|
+
r.push(left[i]);
|
|
250
|
+
}
|
|
251
|
+
return r;
|
|
252
|
+
}
|
|
253
|
+
// For small arrays, includes is faster than Set creation
|
|
254
|
+
const r = [];
|
|
255
|
+
for (let i = 0; i < left.length; i++) {
|
|
256
|
+
if (right.includes(left[i]))
|
|
257
|
+
r.push(left[i]);
|
|
258
|
+
}
|
|
237
259
|
return r;
|
|
238
260
|
}
|
|
239
261
|
throw new Error("Unknown filter type: " + filter.type);
|
|
240
262
|
}
|
|
241
|
-
if (filter.node.type ==
|
|
263
|
+
if (filter.node.type == parseQuery_1.NodeType.PARENT) {
|
|
242
264
|
const r = resolveFilterWithParent(filter.node, path);
|
|
243
265
|
return r;
|
|
244
266
|
}
|
|
@@ -261,7 +283,7 @@ function createQuerier() {
|
|
|
261
283
|
function resolveFilterWithParent(node, path) {
|
|
262
284
|
let startNode = node;
|
|
263
285
|
let startPath = path;
|
|
264
|
-
while (startNode.type ==
|
|
286
|
+
while (startNode.type == parseQuery_1.NodeType.PARENT) {
|
|
265
287
|
if (!startNode.child)
|
|
266
288
|
throw new Error("Parent filter must have child");
|
|
267
289
|
if (!startPath.parentPath)
|
|
@@ -272,40 +294,80 @@ function createQuerier() {
|
|
|
272
294
|
}
|
|
273
295
|
return resolveDirectly(startNode, startPath);
|
|
274
296
|
}
|
|
275
|
-
function isDefined(value) {
|
|
276
|
-
return value != undefined && value != null;
|
|
277
|
-
}
|
|
278
297
|
let subQueryCounter = 0;
|
|
279
298
|
const memo = new Map();
|
|
280
299
|
function resolveDirectly(node, path) {
|
|
281
300
|
let startNode = node;
|
|
282
301
|
const startPath = path;
|
|
283
302
|
let paths = [startPath];
|
|
284
|
-
while (startNode.attribute && startNode.type ==
|
|
303
|
+
while (startNode.attribute && startNode.type == parseQuery_1.NodeType.CHILD) {
|
|
285
304
|
const lookup = startNode.value;
|
|
286
305
|
if (!lookup)
|
|
287
306
|
throw new Error("Selector must have a value");
|
|
288
307
|
//log?.debug("STEP IN ", lookup, paths.map(p => breadCrumb(p)));
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
308
|
+
// Optimize: avoid filter().map().flat() chain - use single loop
|
|
309
|
+
const nodes = [];
|
|
310
|
+
for (let i = 0; i < paths.length; i++) {
|
|
311
|
+
const p = paths[i];
|
|
312
|
+
if (!(0, nodeutils_1.isNodePath)(p))
|
|
313
|
+
continue;
|
|
314
|
+
const arr = getPrimitiveChildrenOrNodePaths(lookup, p);
|
|
315
|
+
for (let j = 0; j < arr.length; j++) {
|
|
316
|
+
nodes.push(arr[j]);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
292
319
|
if (nodes.length == 0)
|
|
293
320
|
return [];
|
|
294
321
|
paths = nodes;
|
|
295
322
|
if (startNode.resolve) {
|
|
296
|
-
const resolved =
|
|
323
|
+
const resolved = [];
|
|
324
|
+
for (let i = 0; i < paths.length; i++) {
|
|
325
|
+
const p = paths[i];
|
|
326
|
+
if (!(0, nodeutils_1.isNodePath)(p))
|
|
327
|
+
continue;
|
|
328
|
+
const binding = resolveBinding(p);
|
|
329
|
+
if (!binding)
|
|
330
|
+
continue;
|
|
331
|
+
const children = getChildren("init", binding);
|
|
332
|
+
for (let j = 0; j < children.length; j++) {
|
|
333
|
+
resolved.push(children[j]);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
297
336
|
if (resolved.length > 0)
|
|
298
337
|
paths = resolved;
|
|
299
338
|
}
|
|
300
339
|
else if (startNode.binding) {
|
|
301
|
-
|
|
340
|
+
const bindings = [];
|
|
341
|
+
for (let i = 0; i < paths.length; i++) {
|
|
342
|
+
const p = paths[i];
|
|
343
|
+
if (!(0, nodeutils_1.isNodePath)(p))
|
|
344
|
+
continue;
|
|
345
|
+
const binding = resolveBinding(p);
|
|
346
|
+
if (binding)
|
|
347
|
+
bindings.push(binding);
|
|
348
|
+
}
|
|
349
|
+
paths = bindings;
|
|
302
350
|
}
|
|
303
351
|
const filter = startNode.filter;
|
|
304
352
|
if (filter) {
|
|
305
|
-
|
|
353
|
+
const filtered = [];
|
|
354
|
+
for (let i = 0; i < paths.length; i++) {
|
|
355
|
+
const p = paths[i];
|
|
356
|
+
if (!(0, nodeutils_1.isNodePath)(p))
|
|
357
|
+
continue;
|
|
358
|
+
if (travHandle({ subquery: filter }, p).subquery.length > 0) {
|
|
359
|
+
filtered.push(p);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
paths = filtered;
|
|
306
363
|
}
|
|
307
364
|
if (!startNode.child) {
|
|
308
|
-
|
|
365
|
+
const results = new Array(paths.length);
|
|
366
|
+
for (let i = 0; i < paths.length; i++) {
|
|
367
|
+
const p = paths[i];
|
|
368
|
+
results[i] = (0, nodeutils_1.isPrimitive)(p) ? p : p.node;
|
|
369
|
+
}
|
|
370
|
+
return results;
|
|
309
371
|
}
|
|
310
372
|
startNode = startNode.child;
|
|
311
373
|
}
|
|
@@ -315,7 +377,10 @@ function createQuerier() {
|
|
|
315
377
|
for (const path of paths) {
|
|
316
378
|
if ((0, nodeutils_1.isNodePath)(path)) {
|
|
317
379
|
if (memo.has(startNode) && memo.get(startNode).has(path)) {
|
|
318
|
-
|
|
380
|
+
const cached = memo.get(startNode).get(path);
|
|
381
|
+
for (let i = 0; i < cached.length; i++) {
|
|
382
|
+
result.push(cached[i]);
|
|
383
|
+
}
|
|
319
384
|
}
|
|
320
385
|
else {
|
|
321
386
|
const subQueryKey = "subquery-" + subQueryCounter++;
|
|
@@ -323,7 +388,9 @@ function createQuerier() {
|
|
|
323
388
|
if (!memo.has(startNode))
|
|
324
389
|
memo.set(startNode, new Map());
|
|
325
390
|
memo.get(startNode)?.set(path, subQueryResult);
|
|
326
|
-
|
|
391
|
+
for (let i = 0; i < subQueryResult.length; i++) {
|
|
392
|
+
result.push(subQueryResult[i]);
|
|
393
|
+
}
|
|
327
394
|
}
|
|
328
395
|
}
|
|
329
396
|
}
|
|
@@ -336,14 +403,16 @@ function createQuerier() {
|
|
|
336
403
|
const filters = [];
|
|
337
404
|
const nodeFilters = state.filtersMap[state.depth].get(fnode.node);
|
|
338
405
|
if (nodeFilters) {
|
|
339
|
-
for (
|
|
406
|
+
for (let i = 0; i < nodeFilters.length; i++) {
|
|
407
|
+
const f = nodeFilters[i];
|
|
340
408
|
if (f.qNode !== fnode.node)
|
|
341
409
|
continue;
|
|
342
410
|
if (f.node !== path.node)
|
|
343
411
|
continue;
|
|
344
412
|
filters.push(f);
|
|
345
413
|
}
|
|
346
|
-
for (
|
|
414
|
+
for (let i = 0; i < filters.length; i++) {
|
|
415
|
+
const f = filters[i];
|
|
347
416
|
if (evaluateFilter(f.filter, path).length > 0) {
|
|
348
417
|
matchingFilters.push(f);
|
|
349
418
|
}
|
|
@@ -356,7 +425,9 @@ function createQuerier() {
|
|
|
356
425
|
const resolved = binding ? getChildren("init", binding)[0] : undefined;
|
|
357
426
|
if (fnode.node.child) {
|
|
358
427
|
const result = resolveDirectly(fnode.node.child, resolved ?? path);
|
|
359
|
-
|
|
428
|
+
for (let i = 0; i < result.length; i++) {
|
|
429
|
+
fnode.result.push(result[i]);
|
|
430
|
+
}
|
|
360
431
|
}
|
|
361
432
|
else {
|
|
362
433
|
fnode.result.push(path.node);
|
|
@@ -367,7 +438,9 @@ function createQuerier() {
|
|
|
367
438
|
if (binding) {
|
|
368
439
|
if (fnode.node.child) {
|
|
369
440
|
const result = resolveDirectly(fnode.node.child, binding);
|
|
370
|
-
|
|
441
|
+
for (let i = 0; i < result.length; i++) {
|
|
442
|
+
fnode.result.push(result[i]);
|
|
443
|
+
}
|
|
371
444
|
}
|
|
372
445
|
else {
|
|
373
446
|
fnode.result.push(binding.node);
|
|
@@ -377,7 +450,7 @@ function createQuerier() {
|
|
|
377
450
|
else if (!fnode.node.child) {
|
|
378
451
|
fnode.result.push(path.node);
|
|
379
452
|
}
|
|
380
|
-
else if (fnode.node.child.type ==
|
|
453
|
+
else if (fnode.node.child.type == parseQuery_1.NodeType.FUNCTION) {
|
|
381
454
|
const functionCallResult = state.functionCalls[state.depth].find(f => f.node == fnode.node);
|
|
382
455
|
if (!functionCallResult)
|
|
383
456
|
throw new Error("Did not find expected function call for " + fnode.node.child.function);
|
|
@@ -385,12 +458,18 @@ function createQuerier() {
|
|
|
385
458
|
}
|
|
386
459
|
else if (matchingFilters.length > 0) {
|
|
387
460
|
log?.debug("HAS MATCHING FILTER", fnode.result.length, matchingFilters.length, breadCrumb(path));
|
|
388
|
-
|
|
461
|
+
for (let i = 0; i < matchingFilters.length; i++) {
|
|
462
|
+
const filterResult = matchingFilters[i].result;
|
|
463
|
+
for (let j = 0; j < filterResult.length; j++) {
|
|
464
|
+
fnode.result.push(filterResult[j]);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
389
467
|
}
|
|
390
468
|
}
|
|
391
469
|
function resolveFunctionCalls(fnode, functionCallResult, path, state) {
|
|
392
470
|
const parameterResults = [];
|
|
393
|
-
for (
|
|
471
|
+
for (let i = 0; i < functionCallResult.parameters.length; i++) {
|
|
472
|
+
const p = functionCallResult.parameters[i];
|
|
394
473
|
if ("parameters" in p) {
|
|
395
474
|
resolveFunctionCalls(p, p, path, state);
|
|
396
475
|
parameterResults.push(p.result);
|
|
@@ -401,10 +480,17 @@ function createQuerier() {
|
|
|
401
480
|
}
|
|
402
481
|
const functionResult = exports.functions[functionCallResult.functionCall.function].fn(parameterResults);
|
|
403
482
|
log?.debug("PARAMETER RESULTS", functionCallResult.functionCall.function, parameterResults, functionResult);
|
|
404
|
-
|
|
483
|
+
for (let i = 0; i < functionResult.length; i++) {
|
|
484
|
+
fnode.result.push(functionResult[i]);
|
|
485
|
+
}
|
|
405
486
|
}
|
|
406
487
|
function travHandle(queries, root) {
|
|
407
|
-
|
|
488
|
+
// Optimize: create results object directly instead of Object.fromEntries + map
|
|
489
|
+
const results = {};
|
|
490
|
+
const queryKeys = Object.keys(queries);
|
|
491
|
+
for (let i = 0; i < queryKeys.length; i++) {
|
|
492
|
+
results[queryKeys[i]] = [];
|
|
493
|
+
}
|
|
408
494
|
const state = {
|
|
409
495
|
depth: 0,
|
|
410
496
|
child: [[], []],
|
|
@@ -417,8 +503,18 @@ function createQuerier() {
|
|
|
417
503
|
for (const [name, node] of Object.entries(queries)) {
|
|
418
504
|
createFNodeAndAddToState(node, results[name], state);
|
|
419
505
|
}
|
|
420
|
-
|
|
421
|
-
state.
|
|
506
|
+
// Optimize: replace forEach with for loop
|
|
507
|
+
const childAtDepth = state.child[state.depth + 1];
|
|
508
|
+
for (let i = 0; i < childAtDepth.length; i++) {
|
|
509
|
+
addPrimitiveAttributeIfMatch(childAtDepth[i], root);
|
|
510
|
+
}
|
|
511
|
+
const descendantSlice = state.descendant.slice(0, state.depth + 1);
|
|
512
|
+
for (let i = 0; i < descendantSlice.length; i++) {
|
|
513
|
+
const fnodes = descendantSlice[i];
|
|
514
|
+
for (let j = 0; j < fnodes.length; j++) {
|
|
515
|
+
addPrimitiveAttributeIfMatch(fnodes[j], root);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
422
518
|
traverse(root.node, {
|
|
423
519
|
enter(path, state) {
|
|
424
520
|
//log?.debug("ENTER", breadCrumb(path));
|
|
@@ -441,14 +537,20 @@ function createQuerier() {
|
|
|
441
537
|
exit(path, state) {
|
|
442
538
|
log?.debug("EXIT", breadCrumb(path));
|
|
443
539
|
// Check for attributes as not all attributes are visited
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
540
|
+
// Optimize: replace forEach with for loop
|
|
541
|
+
const childAtDepthPlusOne = state.child[state.depth + 1];
|
|
542
|
+
for (let i = 0; i < childAtDepthPlusOne.length; i++) {
|
|
543
|
+
addPrimitiveAttributeIfMatch(childAtDepthPlusOne[i], path);
|
|
544
|
+
}
|
|
545
|
+
for (let i = 0; i < state.descendant.length; i++) {
|
|
546
|
+
const fnodes = state.descendant[i];
|
|
547
|
+
for (let j = 0; j < fnodes.length; j++) {
|
|
548
|
+
addPrimitiveAttributeIfMatch(fnodes[j], path);
|
|
448
549
|
}
|
|
449
550
|
}
|
|
450
|
-
|
|
451
|
-
|
|
551
|
+
const matchesAtDepth = state.matches[state.depth];
|
|
552
|
+
for (let i = 0; i < matchesAtDepth.length; i++) {
|
|
553
|
+
addResultIfTokenMatch(matchesAtDepth[i][0], matchesAtDepth[i][1], state);
|
|
452
554
|
}
|
|
453
555
|
state.depth--;
|
|
454
556
|
state.child.pop();
|
|
@@ -464,6 +566,7 @@ function createQuerier() {
|
|
|
464
566
|
function beginHandle(queries, path) {
|
|
465
567
|
const rootPath = createNodePath(path, undefined, undefined, undefined, undefined);
|
|
466
568
|
const r = travHandle(queries, rootPath);
|
|
569
|
+
memo.clear();
|
|
467
570
|
return r;
|
|
468
571
|
}
|
|
469
572
|
return {
|
|
@@ -485,7 +588,13 @@ function multiQuery(code, namedQueries, returnAST) {
|
|
|
485
588
|
const ast = typeof code == "string" ? parseSource(code) : code;
|
|
486
589
|
if (ast == null)
|
|
487
590
|
throw new Error("Could not pase code");
|
|
488
|
-
|
|
591
|
+
// Optimize: parse queries directly instead of Object.fromEntries + map
|
|
592
|
+
const queries = {};
|
|
593
|
+
const entries = Object.entries(namedQueries);
|
|
594
|
+
for (let i = 0; i < entries.length; i++) {
|
|
595
|
+
const [name, queryStr] = entries[i];
|
|
596
|
+
queries[name] = (0, parseQuery_1.parse)(queryStr);
|
|
597
|
+
}
|
|
489
598
|
const querier = createQuerier();
|
|
490
599
|
const result = querier.beginHandle(queries, ast);
|
|
491
600
|
log?.debug("Query time: ", Date.now() - start);
|
|
@@ -503,9 +612,9 @@ function parseSource(source, optimize = true) {
|
|
|
503
612
|
return (0, meriyah_1.parseScript)(source, { module: false, next: true, ...parsingOptions, webcompat: true });
|
|
504
613
|
}
|
|
505
614
|
}
|
|
506
|
-
const scopes = new Map();
|
|
507
615
|
function createTraverser() {
|
|
508
616
|
let scopeIdCounter = 0;
|
|
617
|
+
const scopes = new Map();
|
|
509
618
|
let removedScopes = 0;
|
|
510
619
|
const nodePathsCreated = {};
|
|
511
620
|
function createScope(parentScopeId) {
|
|
@@ -553,7 +662,12 @@ function createTraverser() {
|
|
|
553
662
|
if (key in path.node) {
|
|
554
663
|
const r = path.node[key];
|
|
555
664
|
if (Array.isArray(r)) {
|
|
556
|
-
|
|
665
|
+
const len = r.length;
|
|
666
|
+
const result = new Array(len);
|
|
667
|
+
for (let i = 0; i < len; i++) {
|
|
668
|
+
result[i] = createNodePath(r[i], i, key, path.scopeId, path.functionScopeId, path);
|
|
669
|
+
}
|
|
670
|
+
return result;
|
|
557
671
|
}
|
|
558
672
|
else if (r != undefined) {
|
|
559
673
|
return [createNodePath(r, key, key, path.scopeId, path.functionScopeId, path)];
|
|
@@ -564,7 +678,16 @@ function createTraverser() {
|
|
|
564
678
|
function getPrimitiveChildren(key, path) {
|
|
565
679
|
if (key in path.node) {
|
|
566
680
|
const r = path.node[key];
|
|
567
|
-
|
|
681
|
+
const arr = (0, utils_1.toArray)(r);
|
|
682
|
+
// Optimize: single loop instead of chained filter()
|
|
683
|
+
const result = [];
|
|
684
|
+
for (let i = 0; i < arr.length; i++) {
|
|
685
|
+
const item = arr[i];
|
|
686
|
+
if ((0, utils_1.isDefined)(item) && (0, nodeutils_1.isPrimitive)(item)) {
|
|
687
|
+
result.push(item);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return result;
|
|
568
691
|
}
|
|
569
692
|
return [];
|
|
570
693
|
}
|
|
@@ -572,23 +695,29 @@ function createTraverser() {
|
|
|
572
695
|
if (key in path.node) {
|
|
573
696
|
const r = path.node[key];
|
|
574
697
|
if (Array.isArray(r)) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
698
|
+
const len = r.length;
|
|
699
|
+
const result = new Array(len);
|
|
700
|
+
for (let i = 0; i < len; i++) {
|
|
701
|
+
const n = r[i];
|
|
702
|
+
result[i] = (0, nodeutils_1.isPrimitive)(n) ? n : createNodePath(n, i, key, path.scopeId, path.functionScopeId, path);
|
|
703
|
+
}
|
|
704
|
+
return result;
|
|
578
705
|
}
|
|
579
706
|
else if (r != undefined) {
|
|
580
707
|
return [
|
|
581
708
|
(0, nodeutils_1.isPrimitive)(r) ? r :
|
|
582
|
-
// isLiteral(r) ? r.value as PrimitiveValue :
|
|
583
709
|
createNodePath(r, key, key, path.scopeId, path.functionScopeId, path)
|
|
584
710
|
];
|
|
585
711
|
}
|
|
586
712
|
}
|
|
587
713
|
return [];
|
|
588
714
|
}
|
|
715
|
+
const nodePathMap = new WeakMap();
|
|
589
716
|
function createNodePath(node, key, parentKey, scopeId, functionScopeId, nodePath) {
|
|
590
|
-
if (node
|
|
591
|
-
|
|
717
|
+
if (nodePathMap.has(node)) {
|
|
718
|
+
//if (node.extra?.nodePath) {
|
|
719
|
+
//const path = node.extra.nodePath;
|
|
720
|
+
const path = nodePathMap.get(node);
|
|
592
721
|
if (nodePath && (0, nodeutils_1.isExportSpecifier)(nodePath.node) && key == "exported" && path.key == "local") {
|
|
593
722
|
//Special handling for "export { someName }" as id is both local and exported
|
|
594
723
|
path.key = "exported";
|
|
@@ -614,9 +743,10 @@ function createTraverser() {
|
|
|
614
743
|
parentKey
|
|
615
744
|
};
|
|
616
745
|
if ((0, nodeutils_1.isNode)(node)) {
|
|
617
|
-
node.extra = node.extra ?? {};
|
|
618
|
-
node.extra.nodePath = path;
|
|
619
|
-
Object.defineProperty(node.extra, "nodePath", { enumerable: false });
|
|
746
|
+
//node.extra = node.extra ?? {};
|
|
747
|
+
//node.extra.nodePath = path;
|
|
748
|
+
//Object.defineProperty(node.extra, "nodePath", { enumerable: false });
|
|
749
|
+
nodePathMap.set(node, path);
|
|
620
750
|
}
|
|
621
751
|
nodePathsCreated[node.type] = (nodePathsCreated[node.type] ?? 0) + 1;
|
|
622
752
|
pathsCreated++;
|
|
@@ -670,11 +800,13 @@ function createTraverser() {
|
|
|
670
800
|
if ((0, nodeutils_1.isScopable)(node)) {
|
|
671
801
|
childScopeId = createScope(scopeId);
|
|
672
802
|
}
|
|
673
|
-
for (
|
|
803
|
+
for (let keyIdx = 0; keyIdx < keys.length; keyIdx++) {
|
|
804
|
+
const key = keys[keyIdx];
|
|
674
805
|
const childNodes = node[key];
|
|
675
|
-
const children = (0, utils_1.toArray)(childNodes)
|
|
676
|
-
for (
|
|
677
|
-
|
|
806
|
+
const children = (0, utils_1.toArray)(childNodes);
|
|
807
|
+
for (let i = 0; i < children.length; i++) {
|
|
808
|
+
const child = children[i];
|
|
809
|
+
if (!(0, utils_1.isDefined)(child) || !(0, nodeutils_1.isNode)(child))
|
|
678
810
|
continue;
|
|
679
811
|
const f = key === "body" && ((0, nodeutils_1.isFunctionDeclaration)(node) || (0, nodeutils_1.isFunctionExpression)(node)) ? childScopeId : functionScopeId;
|
|
680
812
|
stack.push(child);
|
|
@@ -695,20 +827,37 @@ function createTraverser() {
|
|
|
695
827
|
}
|
|
696
828
|
function traverseInner(node, visitor, scopeId, functionScopeId, state, path) {
|
|
697
829
|
const nodePath = path ?? createNodePath(node, undefined, undefined, scopeId, functionScopeId);
|
|
698
|
-
const keys = nodeutils_1.VISITOR_KEYS[node.type]
|
|
699
|
-
if (nodePath.parentPath)
|
|
700
|
-
|
|
701
|
-
|
|
830
|
+
const keys = nodeutils_1.VISITOR_KEYS[node.type];
|
|
831
|
+
if (nodePath.parentPath) {
|
|
832
|
+
const stack = [];
|
|
833
|
+
if (nodePath.parentPath.parentPath?.node)
|
|
834
|
+
stack.push(nodePath.parentPath.parentPath.node);
|
|
835
|
+
stack.push(nodePath.parentPath.node, nodePath.node);
|
|
836
|
+
registerBindings(stack, nodePath.scopeId, nodePath.functionScopeId);
|
|
837
|
+
}
|
|
838
|
+
// Optimization: Check if we need to traverse children at all
|
|
839
|
+
// If there are no descendant queries and no child queries at next depth, skip traversal
|
|
840
|
+
const stateTyped = state;
|
|
841
|
+
const hasDescendantQueries = stateTyped.descendant && stateTyped.descendant.some(arr => arr.length > 0);
|
|
842
|
+
const hasChildQueriesAtNextDepth = stateTyped.child && stateTyped.child[stateTyped.depth + 1] && stateTyped.child[stateTyped.depth + 1].length > 0;
|
|
843
|
+
// If no queries would match in this subtree, skip traversal entirely
|
|
844
|
+
if (!hasDescendantQueries && !hasChildQueriesAtNextDepth) {
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
for (let keyIdx = 0; keyIdx < keys.length; keyIdx++) {
|
|
848
|
+
const key = keys[keyIdx];
|
|
702
849
|
const childNodes = node[key];
|
|
703
850
|
const children = Array.isArray(childNodes) ? childNodes : childNodes ? [childNodes] : [];
|
|
704
851
|
const nodePaths = [];
|
|
705
|
-
for (
|
|
852
|
+
for (let i = 0; i < children.length; i++) {
|
|
853
|
+
const child = children[i];
|
|
706
854
|
if ((0, nodeutils_1.isNode)(child)) {
|
|
707
855
|
const childPath = createNodePath(child, Array.isArray(childNodes) ? i : key, key, nodePath.scopeId, nodePath.functionScopeId, nodePath);
|
|
708
856
|
nodePaths.push(childPath);
|
|
709
857
|
}
|
|
710
858
|
}
|
|
711
|
-
for (
|
|
859
|
+
for (let i = 0; i < nodePaths.length; i++) {
|
|
860
|
+
const childPath = nodePaths[i];
|
|
712
861
|
visitor.enter(childPath, state);
|
|
713
862
|
traverseInner(childPath.node, visitor, nodePath.scopeId, nodePath.functionScopeId, state, childPath);
|
|
714
863
|
visitor.exit(childPath, state);
|