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.
Files changed (6) hide show
  1. package/README.md +43 -17
  2. package/decode.js +807 -184
  3. package/index.d.ts +69 -1941
  4. package/index.js +2 -0
  5. package/package.json +17 -13
  6. 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
- [`yuku-ast`](https://www.npmjs.com/package/yuku-ast) is the companion toolkit built for this AST: a typed walker, node builders (`b`), type guards (`is`), and identifier validators.
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
- VariableDeclaration(node) {
102
- console.log(node.kind);
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
- The AST is also standard ESTree, so any ESTree-compatible walker (e.g. [zimmerframe](https://github.com/sveltejs/zimmerframe)) works just as well.
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