yuku-analyzer 0.5.32 → 0.5.35

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/decode.js CHANGED
@@ -1349,7 +1349,8 @@ function decode(buffer, source) {
1349
1349
  let o = ((dp + 3) & ~3) >> 2;
1350
1350
  const scopeCount = _u32[o], symbolCount = _u32[o + 1],
1351
1351
  referenceCount = _u32[o + 2], declNodeCount = _u32[o + 3],
1352
- importCount = _u32[o + 4], exportCount = _u32[o + 5];
1352
+ importCount = _u32[o + 4], exportCount = _u32[o + 5],
1353
+ nodeScopeCount = _u32[o + 6];
1353
1354
  o += 8;
1354
1355
  const scopes = _u32.subarray(o, o + scopeCount * 4);
1355
1356
  o += scopeCount * 4;
@@ -1363,6 +1364,8 @@ function decode(buffer, source) {
1363
1364
  o += importCount * 8;
1364
1365
  const exports = _u32.subarray(o, o + exportCount * 10);
1365
1366
  o += exportCount * 10;
1367
+ const nodeScopes = _u32.subarray(o, o + nodeScopeCount);
1368
+ o += nodeScopeCount;
1366
1369
  const _id = (v) => v === NULL ? null : v;
1367
1370
  return (_semView = {
1368
1371
  scope: {
@@ -1421,6 +1424,7 @@ function decode(buffer, source) {
1421
1424
  symbolId: (i) => _id(exports[i * 10 + 3]),
1422
1425
  node: (i) => node(exports[i * 10 + 8]),
1423
1426
  },
1427
+ nodeScope: (i) => nodeScopes[i],
1424
1428
  });
1425
1429
  }
1426
1430
  let _program, _lineStarts, _diagnostics, _comments;
package/engine.js CHANGED
@@ -91,15 +91,11 @@ function createDispatch(visitors) {
91
91
  * in place. Returns the root.
92
92
  */
93
93
  export function walk(root, visitors, state) {
94
- _walk(root, visitors, state, null, new WalkContext());
94
+ _walk(root, visitors, state, new WalkContext());
95
95
  return root;
96
96
  }
97
97
 
98
- // internal entry point. yuku-analyzer layers scope replay via `hooks`
99
- // (enter returns a token passed to exit, which runs after the node is
100
- // handled, removal included) and a WalkContext subclass. exits are
101
- // skipped once stopped.
102
- export function _walk(root, visitors, state, hooks, ctx) {
98
+ export function _walk(root, visitors, state, ctx) {
103
99
  const d = createDispatch(visitors);
104
100
  ctx.state = state;
105
101
  const ancestors = ctx._ancestors;
@@ -133,7 +129,6 @@ export function _walk(root, visitors, state, hooks, ctx) {
133
129
 
134
130
  (function visit(node, key, list, frame) {
135
131
  let typed = d.typed(node.type);
136
- const token = hooks === null ? undefined : hooks.enter(node);
137
132
  const parent = ctx.parent;
138
133
 
139
134
  position(node, key, list, frame);
@@ -147,7 +142,6 @@ export function _walk(root, visitors, state, hooks, ctx) {
147
142
  }
148
143
  if (ctx._removed) {
149
144
  applyRemove(parent, key, list, frame);
150
- if (hooks !== null) hooks.exit(token);
151
145
  return true;
152
146
  }
153
147
  if (ctx._replacement !== null) {
@@ -192,7 +186,6 @@ export function _walk(root, visitors, state, hooks, ctx) {
192
186
  if (ctx._removed) applyRemove(parent, key, list, frame);
193
187
  else if (ctx._replacement !== null) applyReplace(parent, key, list, frame);
194
188
 
195
- if (hooks !== null) hooks.exit(token);
196
189
  return true;
197
190
  })(root, null, null, null);
198
191
  }
package/index.d.ts CHANGED
@@ -17,7 +17,7 @@ import type {
17
17
  SourceLocation,
18
18
  SourceType,
19
19
  WalkContext as BaseWalkContext,
20
- } from "@yuku/types";
20
+ } from "@yuku-toolchain/types";
21
21
 
22
22
  /** A diagnostic produced by {@link Analyzer.link}. */
23
23
  interface LinkDiagnostic {
package/module.js CHANGED
@@ -1,7 +1,5 @@
1
1
  // One analyzed file, the AST plus the scope/symbol/reference/import/
2
2
  // export object graph, built lazily over the decoded analyzer buffer.
3
- // All wire reads go through the generated `semantic` accessors from
4
- // decode.js. Nothing in this file knows the buffer layout.
5
3
 
6
4
  import binding from "./binding.js";
7
5
  import { decode, SymbolFlags } from "./decode.js";
@@ -268,8 +266,6 @@ export class Module {
268
266
  #symbolReferences = null;
269
267
  #declToSymbol = null;
270
268
  #nodeToReference = null;
271
- #functionScopes = null;
272
- #scopeMap = null;
273
269
  #exportMap = null;
274
270
  #starExports = null;
275
271
  #importBySymbol = null;
@@ -355,22 +351,9 @@ export class Module {
355
351
 
356
352
  scopeOf(node) {
357
353
  const index = this.#r.indexOf(node);
354
+ // a node inserted after analysis has no recorded scope
358
355
  if (index === undefined) return this.rootScope;
359
- const start = this.#r.startOf(index);
360
- const end = this.#r.endOf(index);
361
- const { scope } = this.#sem;
362
- let best = this.scopes[0];
363
- let bestDepth = 0;
364
- for (let i = 1; i < scope.count; i++) {
365
- if (scope.start(i) > start || scope.end(i) < end) continue;
366
- let depth = 0;
367
- for (let p = i; p !== null; p = scope.parentId(p)) depth++;
368
- if (depth > bestDepth) {
369
- best = this.scopes[i];
370
- bestDepth = depth;
371
- }
372
- }
373
- return best;
356
+ return this.scopes[this.#sem.nodeScope(index)];
374
357
  }
375
358
 
376
359
  resolve(name, from = this.rootScope) {
@@ -403,9 +386,9 @@ export class Module {
403
386
  // the free variables of a function: every binding referenced inside
404
387
  // `fn` (nested functions included, value positions only) that is
405
388
  // declared outside its scope subtree, deduplicated by symbol with
406
- // `isWritten` OR-ed across the references. only bindings count:
389
+ // `isWritten` OR-ed across the references. only bindings count.
407
390
  // `this`, `arguments`, and unresolved/global names carry no symbol
408
- // and never appear; module-scope and import bindings count like any
391
+ // and never appear. module-scope and import bindings count like any
409
392
  // other outer binding. computed method keys evaluate in the enclosing
410
393
  // scope, outside the function node's span, so they are not captures.
411
394
  capturesOf(fn) {
@@ -413,13 +396,13 @@ export class Module {
413
396
  if (index === undefined) {
414
397
  throw new TypeError("capturesOf: node does not belong to this module's AST");
415
398
  }
416
- const fnScopeId = this.#functionScopeOf(index);
417
- if (fnScopeId === undefined) {
399
+ const { scope, symbol, reference } = this.#sem;
400
+ const fnScopeId = this.#sem.nodeScope(index);
401
+ if (scope.kind(fnScopeId) !== "function" || scope.nodeIndex(fnScopeId) !== index) {
418
402
  throw new TypeError("capturesOf: node does not create a function scope");
419
403
  }
420
404
  const start = this.#r.startOf(index);
421
405
  const end = this.#r.endOf(index);
422
- const { scope, symbol, reference } = this.#sem;
423
406
  const captures = new Map();
424
407
  for (let i = 0; i < reference.count; i++) {
425
408
  const symbolId = reference.symbolId(i);
@@ -511,22 +494,6 @@ export class Module {
511
494
  return this.#symbolReferences[symbolId];
512
495
  }
513
496
 
514
- // scope-creating node object -> innermost Scope (keep-last covers
515
- // shared nodes, global/module on program, expression_name/function).
516
- _scopeMap() {
517
- if (this.#scopeMap === null) {
518
- const byNode = new WeakMap();
519
- const types = new Set();
520
- for (const scope of this.scopes) {
521
- const node = this.#sem.scope.node(scope.id);
522
- byNode.set(node, scope);
523
- types.add(node.type);
524
- }
525
- this.#scopeMap = { byNode, types };
526
- }
527
- return this.#scopeMap;
528
- }
529
-
530
497
  // the spec's export-entry partition (ParseModule, 16.2.1.7.1): a
531
498
  // name-keyed map of the local + indirect entries and the star-entry
532
499
  // list (`export *` only). name-less records (`export *`, TS
@@ -591,21 +558,6 @@ export class Module {
591
558
  }
592
559
  return this.#nodeToReference;
593
560
  }
594
-
595
- // node index -> the function scope it creates. named function
596
- // expressions share the node with their expression_name scope. the
597
- // function scope has the higher id, so keep-last wins.
598
- #functionScopeOf(nodeIndex) {
599
- if (this.#functionScopes === null) {
600
- const map = new Map();
601
- const { scope } = this.#sem;
602
- for (let i = 0; i < scope.count; i++) {
603
- if (scope.kind(i) === "function") map.set(scope.nodeIndex(i), i);
604
- }
605
- this.#functionScopes = map;
606
- }
607
- return this.#functionScopes.get(nodeIndex);
608
- }
609
561
  }
610
562
 
611
563
  export { SymbolFlags };
package/package.json CHANGED
@@ -1,27 +1,15 @@
1
1
  {
2
2
  "name": "yuku-analyzer",
3
- "version": "0.5.32",
3
+ "version": "0.5.35",
4
4
  "description": "High-performance JavaScript/TypeScript semantic analyzer: per-file scopes, symbols, references, and cross-file module linking",
5
- "keywords": [
6
- "analyzer",
7
- "ast",
8
- "bindings",
9
- "compiler",
10
- "cross-file",
11
- "javascript",
12
- "linker",
13
- "module-graph",
14
- "references",
15
- "scope",
16
- "semantic",
17
- "symbols",
18
- "typescript"
19
- ],
20
5
  "license": "MIT",
21
6
  "repository": {
22
7
  "type": "git",
23
8
  "url": "https://github.com/yuku-toolchain/yuku"
24
9
  },
10
+ "type": "module",
11
+ "main": "index.js",
12
+ "types": "index.d.ts",
25
13
  "files": [
26
14
  "index.js",
27
15
  "index.d.ts",
@@ -32,23 +20,35 @@
32
20
  "binding.js",
33
21
  "decode.js"
34
22
  ],
35
- "type": "module",
36
- "main": "index.js",
37
- "types": "index.d.ts",
38
- "dependencies": {
39
- "@yuku/types": "workspace:*"
40
- },
41
23
  "optionalDependencies": {
42
- "@yuku-analyzer/binding-darwin-arm64": "0.5.32",
43
- "@yuku-analyzer/binding-darwin-x64": "0.5.32",
44
- "@yuku-analyzer/binding-freebsd-x64": "0.5.32",
45
- "@yuku-analyzer/binding-linux-arm-gnu": "0.5.32",
46
- "@yuku-analyzer/binding-linux-arm-musl": "0.5.32",
47
- "@yuku-analyzer/binding-linux-arm64-gnu": "0.5.32",
48
- "@yuku-analyzer/binding-linux-arm64-musl": "0.5.32",
49
- "@yuku-analyzer/binding-linux-x64-gnu": "0.5.32",
50
- "@yuku-analyzer/binding-linux-x64-musl": "0.5.32",
51
- "@yuku-analyzer/binding-win32-arm64": "0.5.32",
52
- "@yuku-analyzer/binding-win32-x64": "0.5.32"
24
+ "@yuku-analyzer/binding-linux-x64-gnu": "0.5.35",
25
+ "@yuku-analyzer/binding-linux-arm64-gnu": "0.5.35",
26
+ "@yuku-analyzer/binding-linux-arm-gnu": "0.5.35",
27
+ "@yuku-analyzer/binding-linux-x64-musl": "0.5.35",
28
+ "@yuku-analyzer/binding-linux-arm64-musl": "0.5.35",
29
+ "@yuku-analyzer/binding-linux-arm-musl": "0.5.35",
30
+ "@yuku-analyzer/binding-darwin-x64": "0.5.35",
31
+ "@yuku-analyzer/binding-darwin-arm64": "0.5.35",
32
+ "@yuku-analyzer/binding-win32-x64": "0.5.35",
33
+ "@yuku-analyzer/binding-win32-arm64": "0.5.35",
34
+ "@yuku-analyzer/binding-freebsd-x64": "0.5.35"
35
+ },
36
+ "keywords": [
37
+ "analyzer",
38
+ "ast",
39
+ "bindings",
40
+ "compiler",
41
+ "cross-file",
42
+ "javascript",
43
+ "linker",
44
+ "module-graph",
45
+ "references",
46
+ "scope",
47
+ "semantic",
48
+ "symbols",
49
+ "typescript"
50
+ ],
51
+ "dependencies": {
52
+ "@yuku-toolchain/types": "0.5.32"
53
53
  }
54
54
  }
package/walk.js CHANGED
@@ -2,17 +2,15 @@ import { WalkContext, _walk } from "./engine.js";
2
2
 
3
3
  class SemanticWalkContext extends WalkContext {
4
4
  #module;
5
- #scopes;
6
- constructor(module, scopes) {
5
+ constructor(module) {
7
6
  super();
8
7
  this.#module = module;
9
- this.#scopes = scopes;
10
8
  }
11
9
  get module() {
12
10
  return this.#module;
13
11
  }
14
12
  get scope() {
15
- return this.#scopes[this.#scopes.length - 1];
13
+ return this.#module.scopeOf(this._node);
16
14
  }
17
15
  get symbol() {
18
16
  return this.#module.symbolOf(this._node);
@@ -23,21 +21,5 @@ class SemanticWalkContext extends WalkContext {
23
21
  }
24
22
 
25
23
  export function walkModule(module, visitors, root) {
26
- const { byNode, types } = module._scopeMap();
27
- const start = root ?? module.ast;
28
- const scopes = [module.scopeOf(start)];
29
- const hooks = {
30
- // the scope was created for the original node. a replacement keeps
31
- // the same lexical position, so push/pop stays balanced on it
32
- enter(node) {
33
- const scope = types.has(node.type) ? byNode.get(node) : undefined;
34
- if (scope === undefined) return false;
35
- scopes.push(scope);
36
- return true;
37
- },
38
- exit(pushed) {
39
- if (pushed) scopes.pop();
40
- },
41
- };
42
- _walk(start, visitors, undefined, hooks, new SemanticWalkContext(module, scopes));
24
+ _walk(root ?? module.ast, visitors, undefined, new SemanticWalkContext(module));
43
25
  }