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 +5 -1
- package/engine.js +2 -9
- package/index.d.ts +1 -1
- package/module.js +7 -55
- package/package.json +33 -33
- package/walk.js +3 -21
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,
|
|
94
|
+
_walk(root, visitors, state, new WalkContext());
|
|
95
95
|
return root;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
|
|
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
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
|
-
|
|
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
|
|
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
|
|
417
|
-
|
|
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.
|
|
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-
|
|
43
|
-
"@yuku-analyzer/binding-
|
|
44
|
-
"@yuku-analyzer/binding-
|
|
45
|
-
"@yuku-analyzer/binding-linux-
|
|
46
|
-
"@yuku-analyzer/binding-linux-
|
|
47
|
-
"@yuku-analyzer/binding-linux-
|
|
48
|
-
"@yuku-analyzer/binding-
|
|
49
|
-
"@yuku-analyzer/binding-
|
|
50
|
-
"@yuku-analyzer/binding-
|
|
51
|
-
"@yuku-analyzer/binding-win32-arm64": "0.5.
|
|
52
|
-
"@yuku-analyzer/binding-
|
|
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
|
-
|
|
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.#
|
|
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
|
-
|
|
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
|
}
|