yuku-parser 0.5.19 → 0.5.21
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 +12 -4
- package/decode.js +10 -30
- package/index.d.ts +0 -20
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -25,10 +25,7 @@ For JavaScript and JSX, the AST is fully conformant with the [ESTree](https://gi
|
|
|
25
25
|
|
|
26
26
|
For TypeScript, the AST conforms to the [TypeScript-ESTree](https://www.npmjs.com/package/@typescript-eslint/typescript-estree) format used by `@typescript-eslint`.
|
|
27
27
|
|
|
28
|
-
Yuku
|
|
29
|
-
|
|
30
|
-
- **Comments are attached to the AST nodes they belong to** rather than exposed as a separate offset-indexed array. See [Comments](#comments) for why.
|
|
31
|
-
- **`Identifier` carries a `kind` field** (`"reference" | "binding" | "name" | "label" | "this"`) naming its role in the tree. ESTree collapses these distinct roles onto one `Identifier` type, so consumers normally have to walk the parent context to tell them apart. The parser already knows which is which, so it surfaces the answer as a free field.
|
|
28
|
+
Yuku produces exactly the AST that [Oxc](https://oxc.rs) produces, for both JS and TS.
|
|
32
29
|
|
|
33
30
|
On top of the base specs, the AST also carries:
|
|
34
31
|
|
|
@@ -74,6 +71,16 @@ const { line, column } = result.locOf(result.program.body[0].start);
|
|
|
74
71
|
|
|
75
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.
|
|
76
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
|
+
|
|
77
84
|
## Walking the AST
|
|
78
85
|
|
|
79
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.
|
|
@@ -134,6 +141,7 @@ interface ParseResult {
|
|
|
134
141
|
diagnostics: Diagnostic[];
|
|
135
142
|
lineStarts: number[];
|
|
136
143
|
locOf(offset: number): { line: number; column: number };
|
|
144
|
+
locNear(offset: number, hintLine: number): { line: number; column: number };
|
|
137
145
|
}
|
|
138
146
|
```
|
|
139
147
|
|
package/decode.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
// generated by tools/gen_estree_decoder.zig, do not edit
|
|
2
|
-
// `_u32` is an Int32Array so NodeIndex NULL reads as -1 and fits in
|
|
3
|
-
// an SMI/int32, avoiding heap-number boxing on every field read in JSC.
|
|
4
2
|
const NULL = -1;
|
|
5
3
|
const _td = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
6
4
|
const BINARY_OPS = ["==", "!=", "===", "!==", "<", "<=", ">", ">=", "+", "-", "*", "/", "%", "**", "|", "^", "&", "<<", ">>", ">>>", "in", "instanceof"];
|
|
@@ -21,11 +19,6 @@ const TS_METHOD_SIGNATURE_KINDS = ["method", "get", "set"];
|
|
|
21
19
|
const TS_MODULE_KINDS = ["namespace", "module"];
|
|
22
20
|
const TS_MAPPED_OPTIONAL = [false, true, "+", "-"];
|
|
23
21
|
const TS_MAPPED_READONLY = [null, true, "+", "-"];
|
|
24
|
-
// builds a partial pos-map covering bytes [startByte, byteLen]. for any
|
|
25
|
-
// byte position v >= startByte, m[v - startByte] is the corresponding
|
|
26
|
-
// UTF-16 code-unit index into `src`. positions below startByte are an
|
|
27
|
-
// identity map (byte position == UTF-16 position because the prefix is
|
|
28
|
-
// pure ASCII), so the caller checks `v < startByte` and returns v directly.
|
|
29
22
|
function buildPosMap(src, byteLen, startByte) {
|
|
30
23
|
const m = new Uint32Array(byteLen - startByte + 1);
|
|
31
24
|
const len = src.length;
|
|
@@ -80,8 +73,6 @@ function decode(buffer, source) {
|
|
|
80
73
|
const eOff = _nodesOff + nodeCount * 48;
|
|
81
74
|
const _extraBase = eOff >> 2;
|
|
82
75
|
const _spOff = eOff + extraCount * 4;
|
|
83
|
-
// sections after the variable-length string pool may be at any
|
|
84
|
-
// byte alignment, so reads against them use `dv`, not `_u32`.
|
|
85
76
|
const dv = new DataView(buffer);
|
|
86
77
|
const _aoOff = _spOff + spLen;
|
|
87
78
|
const _acOff = _attached ? _aoOff + (nodeCount + 1) * 4 : _aoOff;
|
|
@@ -115,22 +106,12 @@ function decode(buffer, source) {
|
|
|
115
106
|
}
|
|
116
107
|
return r;
|
|
117
108
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// ASCII) the mapping is the identity, so we short-circuit and skip
|
|
121
|
-
// building a pos-map. when offsets cross into non-ASCII territory we
|
|
122
|
-
// lazily build a pos-map for `[_firstNa, _srcLen]` on first use.
|
|
123
|
-
let pm = null;
|
|
124
|
-
const _p = v => {
|
|
125
|
-
if (v < _firstNa) return v;
|
|
126
|
-
if (pm === null) pm = buildPosMap(_src, _srcLen, _firstNa);
|
|
127
|
-
return pm[v - _firstNa];
|
|
128
|
-
};
|
|
109
|
+
const pm = _firstNa < _srcLen ? buildPosMap(_src, _srcLen, _firstNa) : null;
|
|
110
|
+
const _p = v => v <= _firstNa ? v : pm[v - _firstNa];
|
|
129
111
|
const str = (s, e) => {
|
|
130
112
|
if (s === e) return "";
|
|
131
113
|
if (s >= _srcLen) return _poolDecode(s, e);
|
|
132
114
|
if (e <= _firstNa) return _src.slice(s, e);
|
|
133
|
-
if (pm === null) pm = buildPosMap(_src, _srcLen, _firstNa);
|
|
134
115
|
const ss = s < _firstNa ? s : pm[s - _firstNa];
|
|
135
116
|
return _src.slice(ss, pm[e - _firstNa]);
|
|
136
117
|
};
|
|
@@ -175,8 +156,6 @@ function decode(buffer, source) {
|
|
|
175
156
|
}
|
|
176
157
|
function nodeWithComments(i) {
|
|
177
158
|
const r = _decode(i);
|
|
178
|
-
// skip unwrap cases whose inner node already carries its own
|
|
179
|
-
// comments (e.g. formal_parameter returning its pattern)
|
|
180
159
|
if (r && r.type !== undefined && r.comments === undefined) {
|
|
181
160
|
const off = _aoOff + i * 4;
|
|
182
161
|
const a = dv.getUint32(off, true), e = dv.getUint32(off + 4, true);
|
|
@@ -194,7 +173,9 @@ function decode(buffer, source) {
|
|
|
194
173
|
f3 = _u32[b + 4], f4 = _u32[b + 5],
|
|
195
174
|
f5 = _u32[b + 6], f6 = _u32[b + 7],
|
|
196
175
|
f7 = _u32[b + 8], f8 = _u32[b + 9];
|
|
197
|
-
const
|
|
176
|
+
const _ss = _u32[b + 10], _se = _u32[b + 11];
|
|
177
|
+
const start = _ss <= _firstNa ? _ss : pm[_ss - _firstNa];
|
|
178
|
+
const end = _se <= _firstNa ? _se : pm[_se - _firstNa];
|
|
198
179
|
switch (tag) {
|
|
199
180
|
case 0: return { type: "SequenceExpression", start, end, expressions: nodeArr(f1, f0) };
|
|
200
181
|
case 1: return { type: "ParenthesizedExpression", start, end, expression: f1 !== NULL ? node(f1) : null };
|
|
@@ -377,11 +358,11 @@ function decode(buffer, source) {
|
|
|
377
358
|
tail: tl,
|
|
378
359
|
};
|
|
379
360
|
}
|
|
380
|
-
case 42: { const r = { type: "Identifier", start, end, name: str(f1, f2)
|
|
361
|
+
case 42: { const r = { type: "Identifier", start, end, name: str(f1, f2) }; if (_isTs) { r.decorators = []; r.optional = false; r.typeAnnotation = null; } return r; }
|
|
381
362
|
case 43: return { type: "PrivateIdentifier", start, end, name: str(f1, f2) };
|
|
382
|
-
case 44: { const r = { type: "Identifier", start, end, name: str(f1, f2)
|
|
383
|
-
case 45: { const r = { type: "Identifier", start, end, name: str(f1, f2)
|
|
384
|
-
case 46: { const r = { type: "Identifier", start, end, name: str(f1, f2)
|
|
363
|
+
case 44: { const r = { type: "Identifier", start, end, name: str(f1, f2) }; if (_isTs) { r.decorators = nodeArr(f3, f0); r.typeAnnotation = f4 !== NULL ? node(f4) : null; r.optional = !!(flags & 1); } return r; }
|
|
364
|
+
case 45: { const r = { type: "Identifier", start, end, name: str(f1, f2) }; if (_isTs) { r.decorators = []; r.optional = false; r.typeAnnotation = null; } return r; }
|
|
365
|
+
case 46: { const r = { type: "Identifier", start, end, name: str(f1, f2) }; if (_isTs) { r.decorators = []; r.optional = false; r.typeAnnotation = null; } return r; }
|
|
385
366
|
case 47: { const r = { type: "ExpressionStatement", start, end, expression: f1 !== NULL ? node(f1) : null }; if (_isTs) { r.directive = null; } return r; }
|
|
386
367
|
case 48: return { type: "IfStatement", start, end, test: f1 !== NULL ? node(f1) : null, consequent: f2 !== NULL ? node(f2) : null, alternate: f3 !== NULL ? node(f3) : null };
|
|
387
368
|
case 49: return { type: "SwitchStatement", start, end, discriminant: f1 !== NULL ? node(f1) : null, cases: nodeArr(f2, f0) };
|
|
@@ -579,7 +560,7 @@ function decode(buffer, source) {
|
|
|
579
560
|
case 146: return {
|
|
580
561
|
type: "Identifier", start, end,
|
|
581
562
|
decorators: [],
|
|
582
|
-
name: "this",
|
|
563
|
+
name: "this", optional: false,
|
|
583
564
|
typeAnnotation: f1 !== NULL ? node(f1) : null,
|
|
584
565
|
};
|
|
585
566
|
case 147: return { type: "TSAsExpression", start, end, expression: f1 !== NULL ? node(f1) : null, typeAnnotation: f2 !== NULL ? node(f2) : null };
|
|
@@ -640,7 +621,6 @@ function decode(buffer, source) {
|
|
|
640
621
|
}
|
|
641
622
|
return out;
|
|
642
623
|
}
|
|
643
|
-
if (pm === null) pm = buildPosMap(_src, _srcLen, _firstNa);
|
|
644
624
|
for (let j = 0; j < lineStartsCount; j++) {
|
|
645
625
|
const v = dv.getUint32(lsOff + j * 4, true);
|
|
646
626
|
out[j] = v < _firstNa ? v : (v >= _srcLen ? pm[pm.length - 1] : pm[v - _firstNa]);
|
package/index.d.ts
CHANGED
|
@@ -271,28 +271,9 @@ type PropertyDefinitionType = "PropertyDefinition" | "TSAbstractPropertyDefiniti
|
|
|
271
271
|
|
|
272
272
|
type AccessorPropertyType = "AccessorProperty" | "TSAbstractAccessorProperty";
|
|
273
273
|
|
|
274
|
-
/**
|
|
275
|
-
* Role of an `Identifier` within the AST. Yuku exposes the four ESTree-collapsed
|
|
276
|
-
* identifier flavors as a discriminator, plus `"this"` for a TS `this`-parameter
|
|
277
|
-
* (which TS-ESTree also encodes as an `Identifier` with `name: "this"`).
|
|
278
|
-
*
|
|
279
|
-
* - `"reference"`: identifier read as a value (`x` in `x + 1`, `console`).
|
|
280
|
-
* - `"binding"`: identifier being declared (parameters, `let x`, function/class names).
|
|
281
|
-
* - `"name"`: identifier in a non-binding name slot (property/method names like `log` in `console.log`).
|
|
282
|
-
* - `"label"`: loop label (`outer` in `outer: for (...) {}`).
|
|
283
|
-
* - `"this"`: the TS `this`-parameter (`function f(this: T)`).
|
|
284
|
-
*/
|
|
285
|
-
type IdentifierKind = "reference" | "binding" | "name" | "label" | "this";
|
|
286
|
-
|
|
287
274
|
interface Identifier extends BaseNode {
|
|
288
275
|
type: "Identifier";
|
|
289
276
|
name: string;
|
|
290
|
-
/**
|
|
291
|
-
* ESTree collapses several distinct identifier
|
|
292
|
-
* roles onto one `Identifier` node, `kind` lets you tell them apart without
|
|
293
|
-
* walking the parent context. See {@link IdentifierKind}.
|
|
294
|
-
*/
|
|
295
|
-
kind: IdentifierKind;
|
|
296
277
|
decorators?: Decorator[];
|
|
297
278
|
optional?: boolean;
|
|
298
279
|
typeAnnotation?: TSTypeAnnotation | null;
|
|
@@ -1821,7 +1802,6 @@ export type {
|
|
|
1821
1802
|
ModuleExportName,
|
|
1822
1803
|
PropertyKey,
|
|
1823
1804
|
Identifier,
|
|
1824
|
-
IdentifierKind,
|
|
1825
1805
|
IdentifierName,
|
|
1826
1806
|
IdentifierReference,
|
|
1827
1807
|
BindingIdentifier,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yuku-parser",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.21",
|
|
4
4
|
"description": "High-performance JavaScript/TypeScript parser",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -17,17 +17,17 @@
|
|
|
17
17
|
"decode.js"
|
|
18
18
|
],
|
|
19
19
|
"optionalDependencies": {
|
|
20
|
-
"@yuku-parser/binding-linux-x64-gnu": "0.5.
|
|
21
|
-
"@yuku-parser/binding-linux-arm64-gnu": "0.5.
|
|
22
|
-
"@yuku-parser/binding-linux-arm-gnu": "0.5.
|
|
23
|
-
"@yuku-parser/binding-linux-x64-musl": "0.5.
|
|
24
|
-
"@yuku-parser/binding-linux-arm64-musl": "0.5.
|
|
25
|
-
"@yuku-parser/binding-linux-arm-musl": "0.5.
|
|
26
|
-
"@yuku-parser/binding-darwin-x64": "0.5.
|
|
27
|
-
"@yuku-parser/binding-darwin-arm64": "0.5.
|
|
28
|
-
"@yuku-parser/binding-win32-x64": "0.5.
|
|
29
|
-
"@yuku-parser/binding-win32-arm64": "0.5.
|
|
30
|
-
"@yuku-parser/binding-freebsd-x64": "0.5.
|
|
20
|
+
"@yuku-parser/binding-linux-x64-gnu": "0.5.21",
|
|
21
|
+
"@yuku-parser/binding-linux-arm64-gnu": "0.5.21",
|
|
22
|
+
"@yuku-parser/binding-linux-arm-gnu": "0.5.21",
|
|
23
|
+
"@yuku-parser/binding-linux-x64-musl": "0.5.21",
|
|
24
|
+
"@yuku-parser/binding-linux-arm64-musl": "0.5.21",
|
|
25
|
+
"@yuku-parser/binding-linux-arm-musl": "0.5.21",
|
|
26
|
+
"@yuku-parser/binding-darwin-x64": "0.5.21",
|
|
27
|
+
"@yuku-parser/binding-darwin-arm64": "0.5.21",
|
|
28
|
+
"@yuku-parser/binding-win32-x64": "0.5.21",
|
|
29
|
+
"@yuku-parser/binding-win32-arm64": "0.5.21",
|
|
30
|
+
"@yuku-parser/binding-freebsd-x64": "0.5.21"
|
|
31
31
|
},
|
|
32
32
|
"keywords": [
|
|
33
33
|
"acorn",
|