yuku-parser 0.5.31 → 0.5.32
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/README.md +43 -17
- package/decode.js +807 -184
- package/index.d.ts +69 -1941
- package/index.js +2 -0
- package/package.json +17 -13
- package/walk.js +198 -0
package/README.md
CHANGED
|
@@ -71,23 +71,12 @@ const { line, column } = result.locOf(result.program.body[0].start);
|
|
|
71
71
|
|
|
72
72
|
Lines are 1-based and columns are 0-based, matching ESTree's `loc` convention. The lookup is an O(log n) binary search: tens of nanoseconds per call, safe to invoke per node during a walk.
|
|
73
73
|
|
|
74
|
-
When resolving many offsets in roughly source order, `locNear` is faster: it scans from a hint line instead of binary searching. Pass the previously returned `line` as the next `hintLine` so each lookup starts near the answer.
|
|
75
|
-
|
|
76
|
-
```ts
|
|
77
|
-
let hintLine = 1;
|
|
78
|
-
for (const node of nodesInSourceOrder) {
|
|
79
|
-
const { line, column } = result.locNear(node.start, hintLine);
|
|
80
|
-
hintLine = line;
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
74
|
## Walking the AST
|
|
85
75
|
|
|
86
|
-
|
|
76
|
+
A typed, mutating walker is built in. Handlers are keyed by node type and receive the exact node type, as a bare enter function or an enter/leave pair:
|
|
87
77
|
|
|
88
78
|
```ts
|
|
89
|
-
import { parse } from "yuku-parser";
|
|
90
|
-
import { walk } from "yuku-ast";
|
|
79
|
+
import { parse, walk } from "yuku-parser";
|
|
91
80
|
|
|
92
81
|
const { program } = parse(`
|
|
93
82
|
const message = "hello";
|
|
@@ -98,13 +87,51 @@ walk(program, {
|
|
|
98
87
|
Identifier(node) {
|
|
99
88
|
console.log(node.name);
|
|
100
89
|
},
|
|
101
|
-
|
|
102
|
-
|
|
90
|
+
CallExpression: {
|
|
91
|
+
enter(node, ctx) { /* before children */ },
|
|
92
|
+
leave(node, ctx) { /* after children */ },
|
|
93
|
+
},
|
|
94
|
+
enter(node) { /* every node */ },
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The context exposes the position (`ctx.parent`, `ctx.key`, `ctx.index`, `ctx.ancestors()`), flow control (`ctx.skip()`, `ctx.stop()`), and in-place mutation:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
walk(program, {
|
|
102
|
+
DebuggerStatement(node, ctx) {
|
|
103
|
+
ctx.remove();
|
|
104
|
+
},
|
|
105
|
+
Literal(node, ctx) {
|
|
106
|
+
if (node.value === 1) ctx.replace({ type: "Identifier", start: 0, end: 0, name: "ONE" });
|
|
103
107
|
},
|
|
104
108
|
});
|
|
105
109
|
```
|
|
106
110
|
|
|
107
|
-
|
|
111
|
+
`ctx.replace(node)` continues the walk into the replacement, `ctx.remove()` skips the removed subtree, `ctx.insertBefore(node)` inserts a sibling without visiting it, and `ctx.insertAfter(node)` inserts one the walk will visit. A replacement created with `start: 0, end: 0` inherits the original span, which keeps source maps meaningful through [`yuku-codegen`](https://www.npmjs.com/package/yuku-codegen). An optional third argument threads state to every handler as `ctx.state`.
|
|
112
|
+
|
|
113
|
+
The AST is also standard ESTree, so any ESTree-compatible walker works as well.
|
|
114
|
+
|
|
115
|
+
## Scanning without building the AST
|
|
116
|
+
|
|
117
|
+
`result.scan` visits the parsed node records directly in the binary buffer, before any AST objects exist. It is readonly and built for find-style passes:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const result = parse(source);
|
|
121
|
+
|
|
122
|
+
result.scan({
|
|
123
|
+
CallExpression(cursor) {
|
|
124
|
+
console.log(cursor.start, cursor.end); // spans, straight off the buffer
|
|
125
|
+
const node = cursor.node(); // materialize this one node on demand
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The cursor exposes `type`, `start`, `end`, `index`, `node()`, `skip()`, and `stop()`. Because it never builds the AST, scanning is two to three times faster than walking for find-style passes, and allocates nothing. The rule of thumb: scan to find, walk to change.
|
|
131
|
+
|
|
132
|
+
## Semantic analysis
|
|
133
|
+
|
|
134
|
+
[`yuku-analyzer`](https://www.npmjs.com/package/yuku-analyzer) builds on this parser and adds full semantics: scopes, symbols, resolved references, closure analysis, and cross-file module linking, computed natively in the same pass. Its walk and scan carry the semantic model in context (`ctx.scope`, `ctx.symbol`, `ctx.reference`). See the [analyzer documentation](https://yuku.fyi/analyzer).
|
|
108
135
|
|
|
109
136
|
## Options
|
|
110
137
|
|
|
@@ -141,7 +168,6 @@ interface ParseResult {
|
|
|
141
168
|
diagnostics: Diagnostic[];
|
|
142
169
|
lineStarts: number[];
|
|
143
170
|
locOf(offset: number): { line: number; column: number };
|
|
144
|
-
locNear(offset: number, hintLine: number): { line: number; column: number };
|
|
145
171
|
}
|
|
146
172
|
```
|
|
147
173
|
|