astronomical 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/index.js +351 -61
- package/lib/cjs/nodeutils.js +34 -33
- package/lib/cjs/parseQuery.js +10 -12
- package/lib/cjs/types/index.d.ts +37 -2
- package/lib/cjs/types/index.d.ts.map +1 -1
- package/lib/cjs/types/nodeutils.d.ts +14 -14
- package/lib/cjs/types/nodeutils.d.ts.map +1 -1
- package/lib/cjs/utils.js +2 -3
- package/lib/esm/index.mjs +351 -61
- package/lib/esm/nodeutils.js +34 -33
- package/lib/esm/parseQuery.js +10 -12
- package/lib/esm/types/index.d.ts +37 -2
- package/lib/esm/types/index.d.ts.map +1 -1
- package/lib/esm/types/nodeutils.d.ts +14 -14
- package/lib/esm/types/nodeutils.d.ts.map +1 -1
- package/lib/esm/utils.js +2 -3
- package/package.json +3 -2
- package/lib/cjs/traverse.js +0 -239
- package/lib/cjs/types/traverse.d.ts +0 -39
- package/lib/cjs/types/traverse.d.ts.map +0 -1
- package/lib/esm/traverse.js +0 -239
- package/lib/esm/types/traverse.d.ts +0 -39
- package/lib/esm/types/traverse.d.ts.map +0 -1
package/lib/cjs/index.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
|
|
3
|
+
exports.functions = void 0;
|
|
4
|
+
exports.isAvailableFunction = isAvailableFunction;
|
|
5
|
+
exports.query = query;
|
|
6
|
+
exports.multiQuery = multiQuery;
|
|
7
|
+
exports.parseSource = parseSource;
|
|
8
|
+
exports.default = createTraverser;
|
|
8
9
|
const parseQuery_1 = require("./parseQuery");
|
|
9
10
|
const meriyah_1 = require("meriyah");
|
|
10
11
|
const nodeutils_1 = require("./nodeutils");
|
|
12
|
+
const utils_1 = require("./utils");
|
|
11
13
|
const debugLogEnabled = false;
|
|
12
|
-
const log = {
|
|
14
|
+
const log = debugLogEnabled ? {
|
|
13
15
|
debug: (...args) => {
|
|
14
|
-
|
|
15
|
-
console.debug(...args.map(x => typeof (x) == "object" && x != null && "valueOf" in x ? x.valueOf() : x));
|
|
16
|
+
console.debug(...args);
|
|
16
17
|
}
|
|
17
|
-
};
|
|
18
|
+
} : undefined;
|
|
18
19
|
exports.functions = {
|
|
19
20
|
"join": {
|
|
20
21
|
fn: (result) => {
|
|
@@ -59,12 +60,13 @@ exports.functions = {
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
};
|
|
62
|
-
const functionNames = Object.keys(exports.functions);
|
|
63
|
+
const functionNames = new Set(Object.keys(exports.functions));
|
|
63
64
|
function isAvailableFunction(name) {
|
|
64
|
-
return functionNames.
|
|
65
|
+
return functionNames.has(name);
|
|
65
66
|
}
|
|
66
|
-
exports.isAvailableFunction = isAvailableFunction;
|
|
67
67
|
function breadCrumb(path) {
|
|
68
|
+
if (!debugLogEnabled)
|
|
69
|
+
return "";
|
|
68
70
|
return {
|
|
69
71
|
valueOf() {
|
|
70
72
|
if (path.parentPath == undefined)
|
|
@@ -74,7 +76,7 @@ function breadCrumb(path) {
|
|
|
74
76
|
};
|
|
75
77
|
}
|
|
76
78
|
function createQuerier() {
|
|
77
|
-
const traverser = (
|
|
79
|
+
const traverser = createTraverser();
|
|
78
80
|
const { getChildren, getPrimitiveChildren, getPrimitiveChildrenOrNodePaths, getBinding, createNodePath, traverse } = traverser;
|
|
79
81
|
function createFilter(filter, filterResult) {
|
|
80
82
|
if (filter.type == "and" || filter.type == "or" || filter.type == "equals") {
|
|
@@ -106,17 +108,17 @@ function createQuerier() {
|
|
|
106
108
|
}
|
|
107
109
|
else if ("node" in filter) {
|
|
108
110
|
if (filter.node.type == "child") {
|
|
109
|
-
log
|
|
111
|
+
log?.debug("ADDING FILTER CHILD", filter.node);
|
|
110
112
|
state.child[state.depth + 1].push(filter);
|
|
111
113
|
}
|
|
112
114
|
if (filter.node.type == "descendant") {
|
|
113
|
-
log
|
|
115
|
+
log?.debug("ADDING FILTER DESCENDANT", filter.node);
|
|
114
116
|
state.descendant[state.depth + 1].push(filter);
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
119
|
}
|
|
118
120
|
function createFNodeAndAddToState(token, result, state) {
|
|
119
|
-
log
|
|
121
|
+
log?.debug("ADDING FNODE", token);
|
|
120
122
|
const fnode = createFNode(token, result);
|
|
121
123
|
if (token.type == "child") {
|
|
122
124
|
state.child[state.depth + 1].push(fnode);
|
|
@@ -130,7 +132,7 @@ function createQuerier() {
|
|
|
130
132
|
if (fnode.node.attribute) {
|
|
131
133
|
const m = fnode.node.value == path.parentKey || fnode.node.value == path.key;
|
|
132
134
|
if (m)
|
|
133
|
-
log
|
|
135
|
+
log?.debug("ATTR MATCH", fnode.node.value, breadCrumb(path));
|
|
134
136
|
return m;
|
|
135
137
|
}
|
|
136
138
|
if (fnode.node.value == "*") {
|
|
@@ -138,7 +140,7 @@ function createQuerier() {
|
|
|
138
140
|
}
|
|
139
141
|
const m = fnode.node.value == path.node.type;
|
|
140
142
|
if (m)
|
|
141
|
-
log
|
|
143
|
+
log?.debug("NODE MATCH", fnode.node.value, breadCrumb(path));
|
|
142
144
|
return m;
|
|
143
145
|
}
|
|
144
146
|
function addIfTokenMatch(fnode, path, state) {
|
|
@@ -148,7 +150,14 @@ function createQuerier() {
|
|
|
148
150
|
if (fnode.node.filter) {
|
|
149
151
|
const filter = createFilter(fnode.node.filter, []);
|
|
150
152
|
const filteredResult = [];
|
|
151
|
-
|
|
153
|
+
const f = { filter: filter, qNode: fnode.node, node: path.node, result: filteredResult };
|
|
154
|
+
state.filters[state.depth].push(f);
|
|
155
|
+
let fmap = state.filtersMap[state.depth].get(fnode.node);
|
|
156
|
+
if (!fmap) {
|
|
157
|
+
fmap = [];
|
|
158
|
+
state.filtersMap[state.depth].set(fnode.node, fmap);
|
|
159
|
+
}
|
|
160
|
+
fmap.push(f);
|
|
152
161
|
addFilterChildrenToState(filter, state);
|
|
153
162
|
const child = fnode.node.child;
|
|
154
163
|
if (child) {
|
|
@@ -199,40 +208,46 @@ function createQuerier() {
|
|
|
199
208
|
const nodes = getPrimitiveChildren(fnode.node.value, path);
|
|
200
209
|
if (nodes.length == 0)
|
|
201
210
|
return;
|
|
202
|
-
log
|
|
211
|
+
log?.debug("PRIMITIVE", fnode.node.value, nodes);
|
|
203
212
|
fnode.result.push(...nodes);
|
|
204
213
|
}
|
|
205
214
|
function evaluateFilter(filter, path) {
|
|
206
|
-
log
|
|
215
|
+
log?.debug("EVALUATING FILTER", filter, breadCrumb(path));
|
|
207
216
|
if ("type" in filter) {
|
|
208
217
|
if (filter.type == "and") {
|
|
209
218
|
const left = evaluateFilter(filter.left, path);
|
|
210
|
-
if (left.length == 0)
|
|
219
|
+
if (left.length == 0) {
|
|
211
220
|
return [];
|
|
212
|
-
|
|
221
|
+
}
|
|
222
|
+
const r = evaluateFilter(filter.right, path);
|
|
223
|
+
return r;
|
|
213
224
|
}
|
|
214
225
|
if (filter.type == "or") {
|
|
215
226
|
const left = evaluateFilter(filter.left, path);
|
|
216
|
-
if (left.length > 0)
|
|
227
|
+
if (left.length > 0) {
|
|
217
228
|
return left;
|
|
218
|
-
|
|
229
|
+
}
|
|
230
|
+
const r = evaluateFilter(filter.right, path);
|
|
231
|
+
return r;
|
|
219
232
|
}
|
|
220
233
|
if (filter.type == "equals") {
|
|
221
234
|
const left = evaluateFilter(filter.left, path);
|
|
222
235
|
const right = evaluateFilter(filter.right, path);
|
|
223
|
-
|
|
236
|
+
const r = left.filter(x => right.includes(x));
|
|
237
|
+
return r;
|
|
224
238
|
}
|
|
225
239
|
throw new Error("Unknown filter type: " + filter.type);
|
|
226
240
|
}
|
|
227
241
|
if (filter.node.type == "parent") {
|
|
228
|
-
|
|
242
|
+
const r = resolveFilterWithParent(filter.node, path);
|
|
243
|
+
return r;
|
|
229
244
|
}
|
|
230
245
|
return filter.result;
|
|
231
246
|
}
|
|
232
247
|
function resolveBinding(path) {
|
|
233
248
|
if (!(0, nodeutils_1.isIdentifier)(path.node))
|
|
234
249
|
return undefined;
|
|
235
|
-
log
|
|
250
|
+
log?.debug("RESOLVING BINDING FOR ", path.node);
|
|
236
251
|
const name = path.node.name;
|
|
237
252
|
if (name == undefined || typeof name != "string")
|
|
238
253
|
return undefined;
|
|
@@ -240,7 +255,7 @@ function createQuerier() {
|
|
|
240
255
|
const binding = getBinding(path.scopeId, name);
|
|
241
256
|
if (!binding)
|
|
242
257
|
return undefined;
|
|
243
|
-
log
|
|
258
|
+
log?.debug("THIS IS THE BINDING", binding);
|
|
244
259
|
return binding.path;
|
|
245
260
|
}
|
|
246
261
|
function resolveFilterWithParent(node, path) {
|
|
@@ -251,7 +266,7 @@ function createQuerier() {
|
|
|
251
266
|
throw new Error("Parent filter must have child");
|
|
252
267
|
if (!startPath.parentPath)
|
|
253
268
|
return [];
|
|
254
|
-
log
|
|
269
|
+
log?.debug("STEP OUT", startNode, breadCrumb(startPath));
|
|
255
270
|
startNode = startNode.child;
|
|
256
271
|
startPath = startPath.parentPath;
|
|
257
272
|
}
|
|
@@ -261,6 +276,7 @@ function createQuerier() {
|
|
|
261
276
|
return value != undefined && value != null;
|
|
262
277
|
}
|
|
263
278
|
let subQueryCounter = 0;
|
|
279
|
+
const memo = new Map();
|
|
264
280
|
function resolveDirectly(node, path) {
|
|
265
281
|
let startNode = node;
|
|
266
282
|
const startPath = path;
|
|
@@ -269,9 +285,9 @@ function createQuerier() {
|
|
|
269
285
|
const lookup = startNode.value;
|
|
270
286
|
if (!lookup)
|
|
271
287
|
throw new Error("Selector must have a value");
|
|
272
|
-
//log
|
|
288
|
+
//log?.debug("STEP IN ", lookup, paths.map(p => breadCrumb(p)));
|
|
273
289
|
const nodes = paths.filter(nodeutils_1.isNodePath).map(n => getPrimitiveChildrenOrNodePaths(lookup, n)).flat();
|
|
274
|
-
//log
|
|
290
|
+
//log?.debug("LOOKUP", lookup, path.node.type, nodes.map(n => n.node));
|
|
275
291
|
//console.log(nodes);
|
|
276
292
|
if (nodes.length == 0)
|
|
277
293
|
return [];
|
|
@@ -293,20 +309,48 @@ function createQuerier() {
|
|
|
293
309
|
}
|
|
294
310
|
startNode = startNode.child;
|
|
295
311
|
}
|
|
296
|
-
//log
|
|
297
|
-
const result =
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
312
|
+
//log?.debug("DIRECT TRAV RESOLVE", startNode, paths.map(p => breadCrumb(p)));
|
|
313
|
+
const result = [];
|
|
314
|
+
//console.log(paths.length, subQueryCounter);
|
|
315
|
+
for (const path of paths) {
|
|
316
|
+
if ((0, nodeutils_1.isNodePath)(path)) {
|
|
317
|
+
if (memo.has(startNode) && memo.get(startNode).has(path)) {
|
|
318
|
+
result.push(...memo.get(startNode).get(path));
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
const subQueryKey = "subquery-" + subQueryCounter++;
|
|
322
|
+
const subQueryResult = travHandle({ [subQueryKey]: startNode }, path)[subQueryKey];
|
|
323
|
+
if (!memo.has(startNode))
|
|
324
|
+
memo.set(startNode, new Map());
|
|
325
|
+
memo.get(startNode)?.set(path, subQueryResult);
|
|
326
|
+
result.push(...subQueryResult);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
log?.debug("DIRECT TRAV RESOLVE RESULT", result);
|
|
302
331
|
return result;
|
|
303
332
|
}
|
|
304
333
|
function addResultIfTokenMatch(fnode, path, state) {
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
334
|
+
const matchingFilters = [];
|
|
335
|
+
//console.log("FILTERS", state.filters[state.depth].length, state.filtersMap[state.depth].get(fnode.node)?.length);
|
|
336
|
+
const filters = [];
|
|
337
|
+
const nodeFilters = state.filtersMap[state.depth].get(fnode.node);
|
|
338
|
+
if (nodeFilters) {
|
|
339
|
+
for (const f of nodeFilters) {
|
|
340
|
+
if (f.qNode !== fnode.node)
|
|
341
|
+
continue;
|
|
342
|
+
if (f.node !== path.node)
|
|
343
|
+
continue;
|
|
344
|
+
filters.push(f);
|
|
345
|
+
}
|
|
346
|
+
for (const f of filters) {
|
|
347
|
+
if (evaluateFilter(f.filter, path).length > 0) {
|
|
348
|
+
matchingFilters.push(f);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (filters.length > 0 && matchingFilters.length == 0)
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
310
354
|
if (fnode.node.resolve) {
|
|
311
355
|
const binding = resolveBinding(path);
|
|
312
356
|
const resolved = binding ? getChildren("init", binding)[0] : undefined;
|
|
@@ -340,7 +384,7 @@ function createQuerier() {
|
|
|
340
384
|
resolveFunctionCalls(fnode, functionCallResult, path, state);
|
|
341
385
|
}
|
|
342
386
|
else if (matchingFilters.length > 0) {
|
|
343
|
-
log
|
|
387
|
+
log?.debug("HAS MATCHING FILTER", fnode.result.length, matchingFilters.length, breadCrumb(path));
|
|
344
388
|
fnode.result.push(...matchingFilters.flatMap(f => f.result));
|
|
345
389
|
}
|
|
346
390
|
}
|
|
@@ -356,7 +400,7 @@ function createQuerier() {
|
|
|
356
400
|
}
|
|
357
401
|
}
|
|
358
402
|
const functionResult = exports.functions[functionCallResult.functionCall.function].fn(parameterResults);
|
|
359
|
-
log
|
|
403
|
+
log?.debug("PARAMETER RESULTS", functionCallResult.functionCall.function, parameterResults, functionResult);
|
|
360
404
|
fnode.result.push(...functionResult);
|
|
361
405
|
}
|
|
362
406
|
function travHandle(queries, root) {
|
|
@@ -366,36 +410,51 @@ function createQuerier() {
|
|
|
366
410
|
child: [[], []],
|
|
367
411
|
descendant: [[], []],
|
|
368
412
|
filters: [[], []],
|
|
413
|
+
filtersMap: [new Map(), new Map()],
|
|
369
414
|
matches: [[]],
|
|
370
415
|
functionCalls: [[]]
|
|
371
416
|
};
|
|
372
|
-
|
|
417
|
+
for (const [name, node] of Object.entries(queries)) {
|
|
373
418
|
createFNodeAndAddToState(node, results[name], state);
|
|
374
|
-
}
|
|
419
|
+
}
|
|
375
420
|
state.child[state.depth + 1].forEach(fnode => addPrimitiveAttributeIfMatch(fnode, root));
|
|
376
421
|
state.descendant.slice(0, state.depth + 1).forEach(fnodes => fnodes.forEach(fnode => addPrimitiveAttributeIfMatch(fnode, root)));
|
|
377
422
|
traverse(root.node, {
|
|
378
423
|
enter(path, state) {
|
|
379
|
-
log
|
|
424
|
+
//log?.debug("ENTER", breadCrumb(path));
|
|
380
425
|
state.depth++;
|
|
381
426
|
state.child.push([]);
|
|
382
427
|
state.descendant.push([]);
|
|
383
428
|
state.filters.push([]);
|
|
429
|
+
state.filtersMap.push(new Map());
|
|
384
430
|
state.matches.push([]);
|
|
385
431
|
state.functionCalls.push([]);
|
|
386
|
-
state.child[state.depth]
|
|
387
|
-
|
|
432
|
+
for (const fnode of state.child[state.depth]) {
|
|
433
|
+
addIfTokenMatch(fnode, path, state);
|
|
434
|
+
}
|
|
435
|
+
for (const fnodes of state.descendant.slice(0, state.depth + 1)) {
|
|
436
|
+
for (const fnode of fnodes) {
|
|
437
|
+
addIfTokenMatch(fnode, path, state);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
388
440
|
},
|
|
389
441
|
exit(path, state) {
|
|
390
|
-
log
|
|
442
|
+
log?.debug("EXIT", breadCrumb(path));
|
|
391
443
|
// Check for attributes as not all attributes are visited
|
|
392
444
|
state.child[state.depth + 1].forEach(fnode => addPrimitiveAttributeIfMatch(fnode, path));
|
|
393
|
-
|
|
394
|
-
|
|
445
|
+
for (const fnodes of state.descendant) {
|
|
446
|
+
for (const fnode of fnodes) {
|
|
447
|
+
addPrimitiveAttributeIfMatch(fnode, path);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
for (const [fNode, path] of state.matches[state.depth]) {
|
|
451
|
+
addResultIfTokenMatch(fNode, path, state);
|
|
452
|
+
}
|
|
395
453
|
state.depth--;
|
|
396
454
|
state.child.pop();
|
|
397
455
|
state.descendant.pop();
|
|
398
456
|
state.filters.pop();
|
|
457
|
+
state.filtersMap.pop();
|
|
399
458
|
state.matches.pop();
|
|
400
459
|
state.functionCalls.pop();
|
|
401
460
|
}
|
|
@@ -404,7 +463,8 @@ function createQuerier() {
|
|
|
404
463
|
}
|
|
405
464
|
function beginHandle(queries, path) {
|
|
406
465
|
const rootPath = createNodePath(path, undefined, undefined, undefined, undefined);
|
|
407
|
-
|
|
466
|
+
const r = travHandle(queries, rootPath);
|
|
467
|
+
return r;
|
|
408
468
|
}
|
|
409
469
|
return {
|
|
410
470
|
beginHandle
|
|
@@ -420,7 +480,6 @@ function query(code, query, returnAST) {
|
|
|
420
480
|
}
|
|
421
481
|
return result[defaultKey];
|
|
422
482
|
}
|
|
423
|
-
exports.query = query;
|
|
424
483
|
function multiQuery(code, namedQueries, returnAST) {
|
|
425
484
|
const start = Date.now();
|
|
426
485
|
const ast = typeof code == "string" ? parseSource(code) : code;
|
|
@@ -429,19 +488,250 @@ function multiQuery(code, namedQueries, returnAST) {
|
|
|
429
488
|
const queries = Object.fromEntries(Object.entries(namedQueries).map(([name, query]) => [name, (0, parseQuery_1.parse)(query)]));
|
|
430
489
|
const querier = createQuerier();
|
|
431
490
|
const result = querier.beginHandle(queries, ast);
|
|
432
|
-
log
|
|
491
|
+
log?.debug("Query time: ", Date.now() - start);
|
|
433
492
|
if (returnAST) {
|
|
434
493
|
return { ...result, __AST: ast };
|
|
435
494
|
}
|
|
436
495
|
return result;
|
|
437
496
|
}
|
|
438
|
-
|
|
439
|
-
|
|
497
|
+
function parseSource(source, optimize = true) {
|
|
498
|
+
const parsingOptions = optimize ? { loc: false, ranges: false } : { loc: true, ranges: true };
|
|
440
499
|
try {
|
|
441
|
-
return (0, meriyah_1.parseScript)(source, { module: true, next: true,
|
|
500
|
+
return (0, meriyah_1.parseScript)(source, { module: true, next: true, ...parsingOptions });
|
|
442
501
|
}
|
|
443
502
|
catch (e) {
|
|
444
|
-
return (0, meriyah_1.parseScript)(source, { module: false, next: true,
|
|
503
|
+
return (0, meriyah_1.parseScript)(source, { module: false, next: true, ...parsingOptions, webcompat: true });
|
|
445
504
|
}
|
|
446
505
|
}
|
|
447
|
-
|
|
506
|
+
const scopes = new Map();
|
|
507
|
+
function createTraverser() {
|
|
508
|
+
let scopeIdCounter = 0;
|
|
509
|
+
let removedScopes = 0;
|
|
510
|
+
const nodePathsCreated = {};
|
|
511
|
+
function createScope(parentScopeId) {
|
|
512
|
+
const id = scopeIdCounter++;
|
|
513
|
+
if (parentScopeId != undefined) {
|
|
514
|
+
scopes.set(id, parentScopeId ?? -1);
|
|
515
|
+
}
|
|
516
|
+
return id;
|
|
517
|
+
}
|
|
518
|
+
function getBinding(scopeId, name) {
|
|
519
|
+
let currentScope = scopes.get(scopeId);
|
|
520
|
+
while (currentScope !== undefined) {
|
|
521
|
+
if (typeof currentScope !== "number") {
|
|
522
|
+
// Full scope: Check for binding
|
|
523
|
+
if (currentScope.bindings[name]) {
|
|
524
|
+
return currentScope.bindings[name];
|
|
525
|
+
}
|
|
526
|
+
// Move to parent scope
|
|
527
|
+
if (currentScope.parentScopeId === -1)
|
|
528
|
+
break; // No parent scope
|
|
529
|
+
currentScope = scopes.get(currentScope.parentScopeId);
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
// Lightweight scope: Retrieve parent scope
|
|
533
|
+
if (currentScope === -1 || currentScope == undefined)
|
|
534
|
+
break; // No parent scope
|
|
535
|
+
currentScope = scopes.get(currentScope);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return undefined; // Binding not found
|
|
539
|
+
}
|
|
540
|
+
function setBinding(scopeId, name, binding) {
|
|
541
|
+
let scope = scopes.get(scopeId);
|
|
542
|
+
if (typeof scope === "number" || scope === undefined) {
|
|
543
|
+
// Upgrade the lightweight scope to a full scope
|
|
544
|
+
scope = { bindings: {}, id: scopeId, parentScopeId: scope };
|
|
545
|
+
scopes.set(scopeId, scope);
|
|
546
|
+
}
|
|
547
|
+
if (scope && typeof scope !== "number") {
|
|
548
|
+
scope.bindings[name] = binding;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
let pathsCreated = 0;
|
|
552
|
+
function getChildren(key, path) {
|
|
553
|
+
if (key in path.node) {
|
|
554
|
+
const r = path.node[key];
|
|
555
|
+
if (Array.isArray(r)) {
|
|
556
|
+
return r.map((n, i) => createNodePath(n, i, key, path.scopeId, path.functionScopeId, path));
|
|
557
|
+
}
|
|
558
|
+
else if (r != undefined) {
|
|
559
|
+
return [createNodePath(r, key, key, path.scopeId, path.functionScopeId, path)];
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return [];
|
|
563
|
+
}
|
|
564
|
+
function getPrimitiveChildren(key, path) {
|
|
565
|
+
if (key in path.node) {
|
|
566
|
+
const r = path.node[key];
|
|
567
|
+
return (0, utils_1.toArray)(r).filter(utils_1.isDefined).filter(nodeutils_1.isPrimitive);
|
|
568
|
+
}
|
|
569
|
+
return [];
|
|
570
|
+
}
|
|
571
|
+
function getPrimitiveChildrenOrNodePaths(key, path) {
|
|
572
|
+
if (key in path.node) {
|
|
573
|
+
const r = path.node[key];
|
|
574
|
+
if (Array.isArray(r)) {
|
|
575
|
+
return r.map((n, i) => (0, nodeutils_1.isPrimitive)(n) ? n :
|
|
576
|
+
// isLiteral(n) ? n.value as PrimitiveValue :
|
|
577
|
+
createNodePath(n, i, key, path.scopeId, path.functionScopeId, path));
|
|
578
|
+
}
|
|
579
|
+
else if (r != undefined) {
|
|
580
|
+
return [
|
|
581
|
+
(0, nodeutils_1.isPrimitive)(r) ? r :
|
|
582
|
+
// isLiteral(r) ? r.value as PrimitiveValue :
|
|
583
|
+
createNodePath(r, key, key, path.scopeId, path.functionScopeId, path)
|
|
584
|
+
];
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return [];
|
|
588
|
+
}
|
|
589
|
+
function createNodePath(node, key, parentKey, scopeId, functionScopeId, nodePath) {
|
|
590
|
+
if (node.extra?.nodePath) {
|
|
591
|
+
const path = node.extra.nodePath;
|
|
592
|
+
if (nodePath && (0, nodeutils_1.isExportSpecifier)(nodePath.node) && key == "exported" && path.key == "local") {
|
|
593
|
+
//Special handling for "export { someName }" as id is both local and exported
|
|
594
|
+
path.key = "exported";
|
|
595
|
+
path.parentPath = nodePath;
|
|
596
|
+
return path;
|
|
597
|
+
}
|
|
598
|
+
if (key != undefined)
|
|
599
|
+
path.key = typeof (key) == "number" ? key.toString() : key;
|
|
600
|
+
if (parentKey != undefined)
|
|
601
|
+
path.parentKey = parentKey;
|
|
602
|
+
if (nodePath != undefined)
|
|
603
|
+
path.parentPath = nodePath;
|
|
604
|
+
return path;
|
|
605
|
+
}
|
|
606
|
+
const finalScope = ((node.extra && node.extra.scopeId != undefined) ? node.extra.scopeId : scopeId) ?? createScope();
|
|
607
|
+
const finalFScope = ((node.extra && node.extra.functionScopeId != undefined) ? node.extra.functionScopeId : functionScopeId) ?? finalScope;
|
|
608
|
+
const path = {
|
|
609
|
+
node,
|
|
610
|
+
scopeId: finalScope,
|
|
611
|
+
functionScopeId: finalFScope,
|
|
612
|
+
parentPath: nodePath,
|
|
613
|
+
key: typeof (key) == "number" ? key.toString() : key,
|
|
614
|
+
parentKey
|
|
615
|
+
};
|
|
616
|
+
if ((0, nodeutils_1.isNode)(node)) {
|
|
617
|
+
node.extra = node.extra ?? {};
|
|
618
|
+
node.extra.nodePath = path;
|
|
619
|
+
Object.defineProperty(node.extra, "nodePath", { enumerable: false });
|
|
620
|
+
}
|
|
621
|
+
nodePathsCreated[node.type] = (nodePathsCreated[node.type] ?? 0) + 1;
|
|
622
|
+
pathsCreated++;
|
|
623
|
+
return path;
|
|
624
|
+
}
|
|
625
|
+
function registerBinding(stack, scopeId, functionScopeId, key, parentKey) {
|
|
626
|
+
//console.log("x registerBinding?", isIdentifier(node) ? node.name : node.type, parentNode.type, grandParentNode?.type, scopeId, isBinding(node, parentNode, grandParentNode));
|
|
627
|
+
const node = stack[stack.length - 1];
|
|
628
|
+
if (!(0, nodeutils_1.isIdentifier)(node))
|
|
629
|
+
return;
|
|
630
|
+
const parentNode = stack[stack.length - 2];
|
|
631
|
+
if ((0, nodeutils_1.isAssignmentExpression)(parentNode) || (0, nodeutils_1.isMemberExpression)(parentNode) || (0, nodeutils_1.isUpdateExpression)(parentNode) || (0, nodeutils_1.isExportSpecifier)(parentNode))
|
|
632
|
+
return;
|
|
633
|
+
const grandParentNode = stack[stack.length - 3];
|
|
634
|
+
if (!(0, nodeutils_1.isBinding)(node, parentNode, grandParentNode))
|
|
635
|
+
return;
|
|
636
|
+
if (key == "id" && !(0, nodeutils_1.isVariableDeclarator)(parentNode)) {
|
|
637
|
+
setBinding(functionScopeId, node.name, { path: createNodePath(node, undefined, undefined, scopeId, functionScopeId) });
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if ((0, nodeutils_1.isVariableDeclarator)(parentNode) && (0, nodeutils_1.isVariableDeclaration)(grandParentNode)) {
|
|
641
|
+
if (grandParentNode.kind == "var") {
|
|
642
|
+
setBinding(functionScopeId, node.name, { path: createNodePath(parentNode, undefined, undefined, scopeId, functionScopeId) });
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
else {
|
|
646
|
+
setBinding(scopeId, node.name, { path: createNodePath(parentNode, undefined, undefined, scopeId, functionScopeId) });
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if ((0, nodeutils_1.isScope)(node, parentNode)) {
|
|
651
|
+
setBinding(scopeId, node.name, { path: createNodePath(node, key, parentKey, scopeId, functionScopeId) });
|
|
652
|
+
} /*else {
|
|
653
|
+
console.log(node.type, parentNode.type, grandParentNode?.type);
|
|
654
|
+
}*/
|
|
655
|
+
}
|
|
656
|
+
let bindingNodesVisited = 0;
|
|
657
|
+
function registerBindings(stack, scopeId, functionScopeId) {
|
|
658
|
+
const node = stack[stack.length - 1];
|
|
659
|
+
if (!(0, nodeutils_1.isNode)(node))
|
|
660
|
+
return;
|
|
661
|
+
if (node.extra?.scopeId != undefined)
|
|
662
|
+
return;
|
|
663
|
+
node.extra = node.extra ?? {};
|
|
664
|
+
node.extra.scopeId = scopeId;
|
|
665
|
+
bindingNodesVisited++;
|
|
666
|
+
const keys = nodeutils_1.VISITOR_KEYS[node.type];
|
|
667
|
+
if (keys.length == 0)
|
|
668
|
+
return;
|
|
669
|
+
let childScopeId = scopeId;
|
|
670
|
+
if ((0, nodeutils_1.isScopable)(node)) {
|
|
671
|
+
childScopeId = createScope(scopeId);
|
|
672
|
+
}
|
|
673
|
+
for (const key of keys) {
|
|
674
|
+
const childNodes = node[key];
|
|
675
|
+
const children = (0, utils_1.toArray)(childNodes).filter(utils_1.isDefined);
|
|
676
|
+
for (const [i, child] of children.entries()) {
|
|
677
|
+
if (!(0, nodeutils_1.isNode)(child))
|
|
678
|
+
continue;
|
|
679
|
+
const f = key === "body" && ((0, nodeutils_1.isFunctionDeclaration)(node) || (0, nodeutils_1.isFunctionExpression)(node)) ? childScopeId : functionScopeId;
|
|
680
|
+
stack.push(child);
|
|
681
|
+
if ((0, nodeutils_1.isIdentifier)(child)) {
|
|
682
|
+
const k = Array.isArray(childNodes) ? i : key;
|
|
683
|
+
registerBinding(stack, childScopeId, f, k, key);
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
registerBindings(stack, childScopeId, f);
|
|
687
|
+
}
|
|
688
|
+
stack.pop();
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
if (childScopeId != scopeId && typeof scopes.get(childScopeId) == "number") { // Scope has not been populated
|
|
692
|
+
scopes.set(childScopeId, scopes.get(scopeId));
|
|
693
|
+
removedScopes++;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
function traverseInner(node, visitor, scopeId, functionScopeId, state, path) {
|
|
697
|
+
const nodePath = path ?? createNodePath(node, undefined, undefined, scopeId, functionScopeId);
|
|
698
|
+
const keys = nodeutils_1.VISITOR_KEYS[node.type] ?? [];
|
|
699
|
+
if (nodePath.parentPath)
|
|
700
|
+
registerBindings([nodePath.parentPath.parentPath?.node, nodePath.parentPath.node, nodePath.node].filter(utils_1.isDefined), nodePath.scopeId, nodePath.functionScopeId);
|
|
701
|
+
for (const key of keys) {
|
|
702
|
+
const childNodes = node[key];
|
|
703
|
+
const children = Array.isArray(childNodes) ? childNodes : childNodes ? [childNodes] : [];
|
|
704
|
+
const nodePaths = [];
|
|
705
|
+
for (const [i, child] of children.entries()) {
|
|
706
|
+
if ((0, nodeutils_1.isNode)(child)) {
|
|
707
|
+
const childPath = createNodePath(child, Array.isArray(childNodes) ? i : key, key, nodePath.scopeId, nodePath.functionScopeId, nodePath);
|
|
708
|
+
nodePaths.push(childPath);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
for (const childPath of nodePaths) {
|
|
712
|
+
visitor.enter(childPath, state);
|
|
713
|
+
traverseInner(childPath.node, visitor, nodePath.scopeId, nodePath.functionScopeId, state, childPath);
|
|
714
|
+
visitor.exit(childPath, state);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
const sOut = [];
|
|
719
|
+
function traverse(node, visitor, scopeId, state, path) {
|
|
720
|
+
const fscope = path?.functionScopeId ?? node.extra?.functionScopeId ?? scopeId;
|
|
721
|
+
traverseInner(node, visitor, scopeId, fscope, state, path);
|
|
722
|
+
if (!sOut.includes(scopeIdCounter)) {
|
|
723
|
+
log?.debug("Scopes created", scopeIdCounter, " Scopes removed", removedScopes, "Paths created", pathsCreated, bindingNodesVisited);
|
|
724
|
+
sOut.push(scopeIdCounter);
|
|
725
|
+
const k = Object.fromEntries(Object.entries(nodePathsCreated).sort((a, b) => a[1] - b[1]));
|
|
726
|
+
log?.debug("Node paths created", k);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
traverse,
|
|
731
|
+
createNodePath,
|
|
732
|
+
getChildren,
|
|
733
|
+
getPrimitiveChildren,
|
|
734
|
+
getPrimitiveChildrenOrNodePaths,
|
|
735
|
+
getBinding
|
|
736
|
+
};
|
|
737
|
+
}
|