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/esm/index.mjs 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.parseSource = exports.multiQuery = exports.query = exports.isAvailableFunction = exports.functions = void 0;
7
- const traverse_1 = __importDefault(require("./traverse"));
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
- if (debugLogEnabled)
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.includes(name);
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 = (0, traverse_1.default)();
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.debug("ADDING FILTER CHILD", filter.node);
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.debug("ADDING FILTER DESCENDANT", filter.node);
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.debug("ADDING FNODE", token);
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.debug("ATTR MATCH", fnode.node.value, breadCrumb(path));
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.debug("NODE MATCH", fnode.node.value, breadCrumb(path));
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
- state.filters[state.depth].push({ filter: filter, qNode: fnode.node, node: path.node, result: filteredResult });
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.debug("PRIMITIVE", fnode.node.value, nodes);
211
+ log?.debug("PRIMITIVE", fnode.node.value, nodes);
203
212
  fnode.result.push(...nodes);
204
213
  }
205
214
  function evaluateFilter(filter, path) {
206
- log.debug("EVALUATING FILTER", filter, breadCrumb(path));
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
- return evaluateFilter(filter.right, path);
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
- return evaluateFilter(filter.right, path);
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
- return left.filter(x => right.includes(x));
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
- return resolveFilterWithParent(filter.node, path);
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.debug("RESOLVING BINDING FOR ", path.node);
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.debug("THIS IS THE BINDING", binding);
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.debug("STEP OUT", startNode, breadCrumb(startPath));
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.debug("STEP IN ", lookup, paths.map(p => breadCrumb(p)));
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.debug("LOOKUP", lookup, path.node.type, nodes.map(n => n.node));
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.debug("DIRECT TRAV RESOLVE", startNode, paths.map(p => breadCrumb(p)));
297
- const result = paths.filter(nodeutils_1.isNodePath).flatMap(path => {
298
- const subQueryKey = "subquery-" + subQueryCounter++;
299
- return travHandle({ [subQueryKey]: startNode }, path)[subQueryKey];
300
- });
301
- log.debug("DIRECT TRAV RESOLVE RESULT", result);
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 filters = state.filters[state.depth].filter(f => f.node == path.node && f.qNode == fnode.node);
306
- const matchingFilters = filters.filter(f => evaluateFilter(f.filter, path).length > 0);
307
- log.debug("RESULT MATCH", fnode.node.value, breadCrumb(path), filters.length, matchingFilters.length);
308
- if (filters.length > 0 && matchingFilters.length == 0)
309
- return;
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.debug("HAS MATCHING FILTER", fnode.result.length, matchingFilters.length, breadCrumb(path));
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.debug("PARAMETER RESULTS", functionCallResult.functionCall.function, parameterResults, functionResult);
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
- Object.entries(queries).forEach(([name, node]) => {
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.debug("ENTER", breadCrumb(path));
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].forEach(fnode => addIfTokenMatch(fnode, path, state));
387
- state.descendant.slice(0, state.depth + 1).forEach(fnodes => fnodes.forEach(fnode => addIfTokenMatch(fnode, path, state)));
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.debug("EXIT", breadCrumb(path));
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
- state.descendant.forEach(fnodes => fnodes.forEach(fnode => addPrimitiveAttributeIfMatch(fnode, path)));
394
- state.matches[state.depth].forEach(([fNode, path]) => addResultIfTokenMatch(fNode, path, state));
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
- return travHandle(queries, rootPath);
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.debug("Query time: ", Date.now() - start);
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
- exports.multiQuery = multiQuery;
439
- function parseSource(source) {
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, specDeviation: 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, specDeviation: true });
503
+ return (0, meriyah_1.parseScript)(source, { module: false, next: true, ...parsingOptions, webcompat: true });
445
504
  }
446
505
  }
447
- exports.parseSource = parseSource;
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
+ }