yuku-parser 0.5.14 → 0.5.16
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 +76 -25
- package/decode.js +390 -71
- package/index.d.ts +67 -52
- package/index.js +0 -10
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -15,8 +15,7 @@ import { parse } from "yuku-parser";
|
|
|
15
15
|
|
|
16
16
|
const result = parse("const x = 1 + 2;");
|
|
17
17
|
|
|
18
|
-
console.log(result.program);
|
|
19
|
-
console.log(result.comments); // all comments
|
|
18
|
+
console.log(result.program); // ESTree / TypeScript-ESTree Program node
|
|
20
19
|
console.log(result.diagnostics); // errors and warnings
|
|
21
20
|
```
|
|
22
21
|
|
|
@@ -26,10 +25,15 @@ For JavaScript and JSX, the AST is fully conformant with the [ESTree](https://gi
|
|
|
26
25
|
|
|
27
26
|
For TypeScript, the AST conforms to the [TypeScript-ESTree](https://www.npmjs.com/package/@typescript-eslint/typescript-estree) format used by `@typescript-eslint`.
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
Yuku also matches [Oxc](https://oxc.rs) for both JS and TS, with two intentional deviations from the base specs:
|
|
30
29
|
|
|
31
|
-
-
|
|
32
|
-
-
|
|
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.
|
|
32
|
+
|
|
33
|
+
On top of the base specs, the AST also carries:
|
|
34
|
+
|
|
35
|
+
- Stage 3 [decorators](https://github.com/tc39/proposal-decorators).
|
|
36
|
+
- Stage 3 [import defer](https://github.com/tc39/proposal-defer-import-eval) and [import source](https://github.com/tc39/proposal-source-phase-imports). Dynamic forms (`import.defer(...)`, `import.source(...)`) are represented as an `ImportExpression` with a `phase` field set to `"defer"` or `"source"`, following the ESTree convention.
|
|
33
37
|
- A non-standard `hashbang` field on `Program` for `#!/usr/bin/env node` lines.
|
|
34
38
|
|
|
35
39
|
Any other deviation from Acorn's ESTree or `@typescript-eslint`'s TypeScript-ESTree would be considered a bug.
|
|
@@ -51,24 +55,26 @@ Two small helpers are exported for resolving the `lang` and `sourceType` options
|
|
|
51
55
|
```ts
|
|
52
56
|
import { langFromPath, sourceTypeFromPath } from "yuku-parser";
|
|
53
57
|
|
|
54
|
-
langFromPath("foo.tsx");
|
|
55
|
-
langFromPath("types.d.ts");
|
|
56
|
-
sourceTypeFromPath("foo.cjs");
|
|
57
|
-
sourceTypeFromPath("foo.mjs");
|
|
58
|
+
langFromPath("foo.tsx"); // "tsx"
|
|
59
|
+
langFromPath("types.d.ts"); // "dts"
|
|
60
|
+
sourceTypeFromPath("foo.cjs"); // "script"
|
|
61
|
+
sourceTypeFromPath("foo.mjs"); // "module"
|
|
58
62
|
```
|
|
59
63
|
|
|
60
64
|
## Resolving offsets to `(line, column)`
|
|
61
65
|
|
|
62
|
-
Nodes
|
|
66
|
+
Nodes and diagnostics carry `start`/`end` offsets (UTF-16 code units). To turn an offset into a `{ line, column }` pair, call `locOf` on the parse result:
|
|
63
67
|
|
|
64
68
|
```ts
|
|
65
|
-
import { parse
|
|
69
|
+
import { parse } from "yuku-parser";
|
|
66
70
|
|
|
67
|
-
const
|
|
68
|
-
const { line, column } = locOf(
|
|
71
|
+
const result = parse(source);
|
|
72
|
+
const { line, column } = result.locOf(result.program.body[0].start);
|
|
69
73
|
```
|
|
70
74
|
|
|
71
|
-
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,
|
|
75
|
+
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
|
+
|
|
77
|
+
For bulk work — building your own line/column index, integrating with another source-map or diagnostics library, or skipping the per-call binary search — read `result.lineStarts` directly. It's a sorted array of UTF-16 offsets where each line begins: `lineStarts[i]` is the start of line `i + 1`. Decoded lazily on first access and cached.
|
|
72
78
|
|
|
73
79
|
## Walking the AST
|
|
74
80
|
|
|
@@ -104,6 +110,7 @@ const result = parse(source, {
|
|
|
104
110
|
preserveParens: true,
|
|
105
111
|
allowReturnOutsideFunction: false,
|
|
106
112
|
semanticErrors: false,
|
|
113
|
+
attachComments: false,
|
|
107
114
|
});
|
|
108
115
|
```
|
|
109
116
|
|
|
@@ -114,6 +121,7 @@ const result = parse(source, {
|
|
|
114
121
|
| `preserveParens` | `true`, `false` | `true` | Keep `ParenthesizedExpression` nodes in the AST. When false, parentheses are stripped and only the inner expression is kept. |
|
|
115
122
|
| `allowReturnOutsideFunction` | `true`, `false` | `false` | Allow `return` statements outside of functions, at the top level. |
|
|
116
123
|
| `semanticErrors` | `true`, `false` | `false` | Run semantic analysis and report semantic errors alongside syntax errors. |
|
|
124
|
+
| `attachComments` | `true`, `false` | `false` | Collect comments and attach them to host AST nodes. See [Comments](#comments). |
|
|
117
125
|
|
|
118
126
|
## Result
|
|
119
127
|
|
|
@@ -122,13 +130,13 @@ const result = parse(source, {
|
|
|
122
130
|
```ts
|
|
123
131
|
interface ParseResult {
|
|
124
132
|
program: Program;
|
|
125
|
-
comments: Comment[];
|
|
126
|
-
lineStarts: number[];
|
|
127
133
|
diagnostics: Diagnostic[];
|
|
134
|
+
lineStarts: number[];
|
|
135
|
+
locOf(offset: number): { line: number; column: number };
|
|
128
136
|
}
|
|
129
137
|
```
|
|
130
138
|
|
|
131
|
-
The parser is error-tolerant
|
|
139
|
+
The parser is error-tolerant: an AST is always produced even when diagnostics are present.
|
|
132
140
|
|
|
133
141
|
### Diagnostics
|
|
134
142
|
|
|
@@ -153,22 +161,65 @@ const result = parse(`let x = 1; let x = 2;`, { semanticErrors: true });
|
|
|
153
161
|
|
|
154
162
|
This incurs a very small performance overhead. If your build pipeline already handles semantic validation (e.g. through a linter or type checker), you can leave this off for faster parsing.
|
|
155
163
|
|
|
156
|
-
|
|
164
|
+
## Comments
|
|
157
165
|
|
|
158
|
-
|
|
166
|
+
Comments are attached to the AST node they sit next to. Enable collection with `attachComments`, then read them off any node:
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
const { program } = parse(
|
|
170
|
+
`// header\nfunction foo() {} // trailing`,
|
|
171
|
+
{ attachComments: true },
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const fn = program.body[0];
|
|
175
|
+
for (const c of fn.comments ?? []) {
|
|
176
|
+
console.log(c.position, c.type, c.value);
|
|
177
|
+
}
|
|
178
|
+
// before Line " header"
|
|
179
|
+
// after Line " trailing"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Each comment is:
|
|
159
183
|
|
|
160
184
|
```ts
|
|
161
185
|
interface Comment {
|
|
162
186
|
type: "Line" | "Block";
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
value: string; //
|
|
166
|
-
start: number; // byte offset
|
|
167
|
-
end: number; // byte offset
|
|
187
|
+
position: "before" | "after" | "inside";
|
|
188
|
+
sameLine: boolean;
|
|
189
|
+
value: string; // body without delimiters
|
|
168
190
|
}
|
|
169
191
|
```
|
|
170
192
|
|
|
171
|
-
`
|
|
193
|
+
`position` tells you where the comment sits relative to its host:
|
|
194
|
+
|
|
195
|
+
- `"before"`: leading the host node.
|
|
196
|
+
- `"after"`: trailing the host node.
|
|
197
|
+
- `"inside"`: interior to an otherwise empty host, like `function f() { /* hi */ }`.
|
|
198
|
+
|
|
199
|
+
`sameLine` is `true` when the comment shares a source line with the host's adjacent edge (host's start for `before`, host's end for `after`). For `inside` it is always `false`.
|
|
200
|
+
|
|
201
|
+
When `attachComments` is disabled (the default), comments are skipped like whitespace and no `comments` field appears on any node.
|
|
202
|
+
|
|
203
|
+
### Why comments are attached to nodes
|
|
204
|
+
|
|
205
|
+
Comments are part of the source. Any tool that reads or rewrites code needs to know which comments belong with which node, and that link has to survive AST transforms. Yuku puts a single `comments` array on each node, with a `position` field on each comment (`"before"`, `"after"`, `"inside"`). It is the simplest shape that holds up under transforms and stays cheap to decode. Every other approach trades away one of those properties.
|
|
206
|
+
|
|
207
|
+
**Flat offset-indexed array (ESTree default, Oxc).** A separate `comments: [...]` array on the parse result, sibling to the program, each entry pointing at a source range. Fine for read-only analysis. It falls apart the moment you transform the tree.
|
|
208
|
+
|
|
209
|
+
- *Transforms desync the array.* Insert, delete, or move a node and every offset downstream of the edit is wrong. The comment that used to sit between `a` and `b` may now sit inside something unrelated, or hang in empty space between two nodes. Re-syncing means walking the entire array and rewriting offsets on every edit, and even then the meaning of "the comment between these two things" cannot really be preserved by offsets alone.
|
|
210
|
+
- *Codegen cannot trust the offsets.* A printer takes whatever AST it is handed. With offset-based comments, a transformed AST will either print comments in the wrong places or drop them entirely. With attached comments, when you move a node its comments come with it. The printer reads them off `node.comments` and emits them next to the node, no reconciliation needed.
|
|
211
|
+
- *Lookup is awkward.* "Give me the comments belonging to this node" with a flat array is a binary search at best and a linear scan at worst. `node.comments` is O(1) and always exact.
|
|
212
|
+
|
|
213
|
+
**Parser returns a flat list, you attach on the JS side (Acorn).** Acorn's `onComment` option pushes every comment into an array you provide, and that is all it does. To get them onto AST nodes you have to run a separate JS pass like `escodegen.attachComments`, which walks the tree, scans the comment list alongside it, and tags each comment as leading or trailing on the nearest node. That work is unavoidable if you want to transform the tree, and doing it in JavaScript is slow. Yuku does the same attachment in Zig as part of the parse. On the 7.8 MB `typescript.js` (30k+ comments), turning `attachComments` on adds only around 4ms.
|
|
214
|
+
|
|
215
|
+
**Three separate fields per node (Babel).** `leadingComments`, `trailingComments`, and `innerComments`. Same idea as Yuku, but split across three arrays. Two costs come with the split.
|
|
216
|
+
|
|
217
|
+
- *Decode work.* Three fields per node means three slots to check, three potential array allocations, and roughly 3x the work on the JS side for the same information.
|
|
218
|
+
- *Duplication.* A comment that sits between two nodes is the `trailingComments` of one and the `leadingComments` of the other. Transforms have to track both copies and keep them in sync.
|
|
219
|
+
|
|
220
|
+
A single `comments` array with a `position` field carries the same meaning, with one entry per comment and one place to look.
|
|
221
|
+
|
|
222
|
+
Even with `attachComments` enabled, Yuku still parses the same file roughly 4x faster than Babel does without comments attached at all. When the flag is off (the default), comments are skipped like whitespace and there is no attachment work at all.
|
|
172
223
|
|
|
173
224
|
## License
|
|
174
225
|
|
package/decode.js
CHANGED
|
@@ -13,7 +13,6 @@ const PROPERTY_KINDS = ["init", "get", "set"];
|
|
|
13
13
|
const METHOD_KINDS = ["constructor", "method", "get", "set"];
|
|
14
14
|
const FUNCTION_TYPES = ["FunctionDeclaration", "FunctionExpression", "TSDeclareFunction", "TSEmptyBodyFunctionExpression"];
|
|
15
15
|
const CLASS_TYPES = ["ClassDeclaration", "ClassExpression"];
|
|
16
|
-
const COMMENT_TYPES = ["Line", "Block"];
|
|
17
16
|
const SEVERITY = ["error", "warning", "hint", "info"];
|
|
18
17
|
const IMPORT_EXPORT_KINDS = ["value", "type"];
|
|
19
18
|
const ACCESSIBILITY = [null, "public", "private", "protected"];
|
|
@@ -34,7 +33,9 @@ function buildPosMap(src, byteLen, startByte) {
|
|
|
34
33
|
while (i < len) {
|
|
35
34
|
if (i + 16 <= len) {
|
|
36
35
|
let allAscii = true;
|
|
37
|
-
for (let k = 0; k < 16; k++)
|
|
36
|
+
for (let k = 0; k < 16; k++) {
|
|
37
|
+
if (src.charCodeAt(i + k) >= 0x80) { allAscii = false; break; }
|
|
38
|
+
}
|
|
38
39
|
if (allAscii) {
|
|
39
40
|
for (let k = 0; k < 16; k++) m[bp + k] = u16p + k;
|
|
40
41
|
bp += 16; u16p += 16; i += 16;
|
|
@@ -45,8 +46,14 @@ function buildPosMap(src, byteLen, startByte) {
|
|
|
45
46
|
m[bp] = u16p;
|
|
46
47
|
if (cu < 0x80) { bp++; u16p++; i++; }
|
|
47
48
|
else if (cu < 0x800) { m[bp + 1] = u16p + 1; bp += 2; u16p++; i++; }
|
|
48
|
-
else if (cu < 0xD800 || cu >= 0xE000) {
|
|
49
|
-
|
|
49
|
+
else if (cu < 0xD800 || cu >= 0xE000) {
|
|
50
|
+
m[bp + 1] = u16p + 1; m[bp + 2] = u16p + 1;
|
|
51
|
+
bp += 3; u16p++; i++;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
m[bp + 1] = u16p + 1; m[bp + 2] = u16p + 2; m[bp + 3] = u16p + 2;
|
|
55
|
+
bp += 4; u16p += 2; i += 2;
|
|
56
|
+
}
|
|
50
57
|
}
|
|
51
58
|
m[byteLen - startByte] = u16p;
|
|
52
59
|
return m;
|
|
@@ -57,14 +64,26 @@ function decode(buffer, source) {
|
|
|
57
64
|
const _u32 = new Int32Array(buffer, 0, aLen >> 2);
|
|
58
65
|
const _src = source;
|
|
59
66
|
const _srcLen = _u32[3];
|
|
60
|
-
const nodeCount = _u32[0],
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
const nodeCount = _u32[0],
|
|
68
|
+
extraCount = _u32[1],
|
|
69
|
+
spLen = _u32[2];
|
|
70
|
+
const commentCount = _u32[4],
|
|
71
|
+
lineStartsCount = _u32[5],
|
|
72
|
+
diagCount = _u32[6],
|
|
73
|
+
progIdx = _u32[7];
|
|
74
|
+
const _flags = _u32[8];
|
|
75
|
+
const _isTs = !!(_flags & 1);
|
|
76
|
+
const _attachComments = !!(_flags & 2);
|
|
63
77
|
const _firstNa = _u32[9];
|
|
64
78
|
const _nodesOff = 40;
|
|
65
79
|
const eOff = _nodesOff + nodeCount * 48;
|
|
66
80
|
const _extraBase = eOff >> 2;
|
|
67
81
|
const _spOff = eOff + extraCount * 4;
|
|
82
|
+
// sections after the variable-length string pool may be at any
|
|
83
|
+
// byte alignment, so reads against them use `dv`, not `_u32`.
|
|
84
|
+
const dv = new DataView(buffer);
|
|
85
|
+
const _coOff = _spOff + spLen;
|
|
86
|
+
const _cOff = _attachComments ? _coOff + (nodeCount + 1) * 4 : _coOff;
|
|
68
87
|
function _poolDecode(s, e) {
|
|
69
88
|
const a = _spOff + s - _srcLen, b = _spOff + e - _srcLen;
|
|
70
89
|
let hasEd = false;
|
|
@@ -74,9 +93,23 @@ function decode(buffer, source) {
|
|
|
74
93
|
for (let i = a; i < b; ) {
|
|
75
94
|
const c = _u8[i];
|
|
76
95
|
if (c < 0x80) { r += String.fromCharCode(c); i++; }
|
|
77
|
-
else if (c < 0xE0) {
|
|
78
|
-
|
|
79
|
-
|
|
96
|
+
else if (c < 0xE0) {
|
|
97
|
+
r += String.fromCharCode(((c & 0x1F) << 6) | (_u8[i+1] & 0x3F));
|
|
98
|
+
i += 2;
|
|
99
|
+
}
|
|
100
|
+
else if (c < 0xF0) {
|
|
101
|
+
r += String.fromCharCode(
|
|
102
|
+
((c & 0x0F) << 12) | ((_u8[i+1] & 0x3F) << 6) | (_u8[i+2] & 0x3F)
|
|
103
|
+
);
|
|
104
|
+
i += 3;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
r += String.fromCodePoint(
|
|
108
|
+
((c & 0x07) << 18) | ((_u8[i+1] & 0x3F) << 12) |
|
|
109
|
+
((_u8[i+2] & 0x3F) << 6) | (_u8[i+3] & 0x3F)
|
|
110
|
+
);
|
|
111
|
+
i += 4;
|
|
112
|
+
}
|
|
80
113
|
}
|
|
81
114
|
return r;
|
|
82
115
|
}
|
|
@@ -106,7 +139,10 @@ function decode(buffer, source) {
|
|
|
106
139
|
}
|
|
107
140
|
function nodeArrHoles(s, len) {
|
|
108
141
|
const r = new Array(len);
|
|
109
|
-
for (let j = 0; j < len; j++) {
|
|
142
|
+
for (let j = 0; j < len; j++) {
|
|
143
|
+
const x = _u32[_extraBase + s + j];
|
|
144
|
+
r[j] = x !== NULL ? node(x) : null;
|
|
145
|
+
}
|
|
110
146
|
return r;
|
|
111
147
|
}
|
|
112
148
|
function fnParams(idx) {
|
|
@@ -119,19 +155,77 @@ function decode(buffer, source) {
|
|
|
119
155
|
if (rest !== NULL) p.push(node(rest));
|
|
120
156
|
return p;
|
|
121
157
|
}
|
|
122
|
-
function
|
|
158
|
+
function _commentsOf(a, e) {
|
|
159
|
+
const out = new Array(e - a);
|
|
160
|
+
for (let j = a; j < e; j++) {
|
|
161
|
+
const o = _cOff + j * 12;
|
|
162
|
+
const cf = _u8[o + 0];
|
|
163
|
+
const vs = dv.getUint32(o + 4, true),
|
|
164
|
+
ve = dv.getUint32(o + 8, true);
|
|
165
|
+
out[j - a] = {
|
|
166
|
+
type: (cf & 1) ? "Block" : "Line",
|
|
167
|
+
position: ["before", "after", "inside"][(cf >> 1) & 3],
|
|
168
|
+
sameLine: (cf & 8) !== 0,
|
|
169
|
+
value: str(vs, ve),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
function nodeWithComments(i) {
|
|
175
|
+
const r = _decode(i);
|
|
176
|
+
// skip unwrap cases whose inner node already carries its own
|
|
177
|
+
// comments (e.g. formal_parameter returning its pattern)
|
|
178
|
+
if (r && r.type !== undefined && r.comments === undefined) {
|
|
179
|
+
const off = _coOff + i * 4;
|
|
180
|
+
const a = dv.getUint32(off, true), e = dv.getUint32(off + 4, true);
|
|
181
|
+
if (a !== e) r.comments = _commentsOf(a, e);
|
|
182
|
+
}
|
|
183
|
+
return r;
|
|
184
|
+
}
|
|
185
|
+
function _decode(i) {
|
|
123
186
|
const o = _nodesOff + i * 48;
|
|
124
187
|
const tag = _u8[o];
|
|
125
188
|
const flags = _u8[o + 2] | (_u8[o + 3] << 8);
|
|
126
189
|
const f0 = _u8[o + 4] | (_u8[o + 5] << 8);
|
|
127
190
|
const b = o >> 2;
|
|
128
|
-
const f1 = _u32[b + 2], f2 = _u32[b + 3],
|
|
191
|
+
const f1 = _u32[b + 2], f2 = _u32[b + 3],
|
|
192
|
+
f3 = _u32[b + 4], f4 = _u32[b + 5],
|
|
193
|
+
f5 = _u32[b + 6], f6 = _u32[b + 7],
|
|
194
|
+
f7 = _u32[b + 8], f8 = _u32[b + 9];
|
|
129
195
|
const start = _p(_u32[b + 10]), end = _p(_u32[b + 11]);
|
|
130
196
|
switch (tag) {
|
|
131
197
|
case 0: return { type: "SequenceExpression", start, end, expressions: nodeArr(f1, f0) };
|
|
132
198
|
case 1: return { type: "ParenthesizedExpression", start, end, expression: f1 !== NULL ? node(f1) : null };
|
|
133
|
-
case 2: {
|
|
134
|
-
|
|
199
|
+
case 2: {
|
|
200
|
+
const r = {
|
|
201
|
+
type: "ArrowFunctionExpression", start, end,
|
|
202
|
+
id: null, generator: false, async: !!(flags & 2),
|
|
203
|
+
params: f1 !== NULL ? fnParams(f1) : [],
|
|
204
|
+
body: node(f2), expression: !!(flags & 1),
|
|
205
|
+
};
|
|
206
|
+
if (_isTs) {
|
|
207
|
+
r.typeParameters = f3 !== NULL ? node(f3) : null;
|
|
208
|
+
r.returnType = f4 !== NULL ? node(f4) : null;
|
|
209
|
+
}
|
|
210
|
+
return r;
|
|
211
|
+
}
|
|
212
|
+
case 3: {
|
|
213
|
+
const ft = flags & 3;
|
|
214
|
+
const r = {
|
|
215
|
+
type: FUNCTION_TYPES[ft], start, end,
|
|
216
|
+
id: f1 !== NULL ? node(f1) : null,
|
|
217
|
+
generator: !!(flags & 4), async: !!(flags & 8),
|
|
218
|
+
params: f2 !== NULL ? fnParams(f2) : [],
|
|
219
|
+
body: f3 !== NULL ? node(f3) : null,
|
|
220
|
+
expression: false,
|
|
221
|
+
};
|
|
222
|
+
if (_isTs) {
|
|
223
|
+
r.typeParameters = f4 !== NULL ? node(f4) : null;
|
|
224
|
+
r.returnType = f5 !== NULL ? node(f5) : null;
|
|
225
|
+
r.declare = !!(flags & 16);
|
|
226
|
+
}
|
|
227
|
+
return r;
|
|
228
|
+
}
|
|
135
229
|
case 4: return { type: "BlockStatement", start, end, body: nodeArr(f1, f0) };
|
|
136
230
|
case 5: return { type: "BlockStatement", start, end, body: nodeArr(f1, f0) };
|
|
137
231
|
case 6: return { params: fnParams(i) };
|
|
@@ -139,7 +233,11 @@ function decode(buffer, source) {
|
|
|
139
233
|
case 8: return { type: "BinaryExpression", start, end, left: f1 !== NULL ? node(f1) : null, right: f2 !== NULL ? node(f2) : null, operator: BINARY_OPS[flags & 31] };
|
|
140
234
|
case 9: return { type: "LogicalExpression", start, end, left: f1 !== NULL ? node(f1) : null, right: f2 !== NULL ? node(f2) : null, operator: LOGICAL_OPS[flags & 3] };
|
|
141
235
|
case 10: return { type: "ConditionalExpression", start, end, test: f1 !== NULL ? node(f1) : null, consequent: f2 !== NULL ? node(f2) : null, alternate: f3 !== NULL ? node(f3) : null };
|
|
142
|
-
case 11: return {
|
|
236
|
+
case 11: return {
|
|
237
|
+
type: "UnaryExpression", start, end,
|
|
238
|
+
operator: UNARY_OPS[flags & 7], prefix: true,
|
|
239
|
+
argument: f1 !== NULL ? node(f1) : null,
|
|
240
|
+
};
|
|
143
241
|
case 12: return { type: "UpdateExpression", start, end, argument: f1 !== NULL ? node(f1) : null, operator: UPDATE_OPS[flags & 1], prefix: !!(flags & 2) };
|
|
144
242
|
case 13: return { type: "AssignmentExpression", start, end, left: f1 !== NULL ? node(f1) : null, right: f2 !== NULL ? node(f2) : null, operator: ASSIGNMENT_OPS[flags & 15] };
|
|
145
243
|
case 14: return { type: "ArrayExpression", start, end, elements: nodeArrHoles(f1, f0) };
|
|
@@ -155,26 +253,133 @@ function decode(buffer, source) {
|
|
|
155
253
|
case 24: return { type: "YieldExpression", start, end, argument: f1 !== NULL ? node(f1) : null, delegate: !!(flags & 1) };
|
|
156
254
|
case 25: return { type: "MetaProperty", start, end, meta: f1 !== NULL ? node(f1) : null, property: f2 !== NULL ? node(f2) : null };
|
|
157
255
|
case 26: return { type: "Decorator", start, end, expression: f1 !== NULL ? node(f1) : null };
|
|
158
|
-
case 27: {
|
|
256
|
+
case 27: {
|
|
257
|
+
const r = {
|
|
258
|
+
type: CLASS_TYPES[flags & 1], start, end,
|
|
259
|
+
decorators: nodeArr(f1, f0),
|
|
260
|
+
id: f2 !== NULL ? node(f2) : null,
|
|
261
|
+
superClass: f3 !== NULL ? node(f3) : null,
|
|
262
|
+
body: node(f4),
|
|
263
|
+
};
|
|
264
|
+
if (_isTs) {
|
|
265
|
+
r.typeParameters = f5 !== NULL ? node(f5) : null;
|
|
266
|
+
r.superTypeArguments = f6 !== NULL ? node(f6) : null;
|
|
267
|
+
r.implements = nodeArr(f7, f8);
|
|
268
|
+
r.abstract = !!(flags & 2);
|
|
269
|
+
r.declare = !!(flags & 4);
|
|
270
|
+
}
|
|
271
|
+
return r;
|
|
272
|
+
}
|
|
159
273
|
case 28: return { type: "ClassBody", start, end, body: nodeArr(f1, f0) };
|
|
160
|
-
case 29: {
|
|
161
|
-
|
|
274
|
+
case 29: {
|
|
275
|
+
const r = {
|
|
276
|
+
type: "MethodDefinition", start, end,
|
|
277
|
+
decorators: nodeArr(f1, f0),
|
|
278
|
+
key: node(f2), value: node(f3),
|
|
279
|
+
kind: METHOD_KINDS[flags & 3],
|
|
280
|
+
computed: !!(flags & 4), static: !!(flags & 8),
|
|
281
|
+
};
|
|
282
|
+
if (_isTs) {
|
|
283
|
+
r.override = !!(flags & 16);
|
|
284
|
+
r.optional = !!(flags & 32);
|
|
285
|
+
const _abs = !!(flags & 64);
|
|
286
|
+
r.accessibility = ACCESSIBILITY[(flags >> 7) & 3];
|
|
287
|
+
if (_abs) r.type = "TSAbstractMethodDefinition";
|
|
288
|
+
}
|
|
289
|
+
return r;
|
|
290
|
+
}
|
|
291
|
+
case 30: {
|
|
292
|
+
const _acc = !!(flags & 4);
|
|
293
|
+
const r = {
|
|
294
|
+
type: _acc ? "AccessorProperty" : "PropertyDefinition",
|
|
295
|
+
start, end,
|
|
296
|
+
decorators: nodeArr(f1, f0),
|
|
297
|
+
key: node(f2),
|
|
298
|
+
value: f3 !== NULL ? node(f3) : null,
|
|
299
|
+
computed: !!(flags & 1), static: !!(flags & 2),
|
|
300
|
+
};
|
|
301
|
+
if (_isTs) {
|
|
302
|
+
r.typeAnnotation = f4 !== NULL ? node(f4) : null;
|
|
303
|
+
r.declare = !!(flags & 8);
|
|
304
|
+
r.override = !!(flags & 16);
|
|
305
|
+
r.optional = !!(flags & 32);
|
|
306
|
+
r.definite = !!(flags & 64);
|
|
307
|
+
r.readonly = !!(flags & 128);
|
|
308
|
+
const _abs = !!(flags & 256);
|
|
309
|
+
r.accessibility = ACCESSIBILITY[(flags >> 9) & 3];
|
|
310
|
+
if (_abs)
|
|
311
|
+
r.type = _acc
|
|
312
|
+
? "TSAbstractAccessorProperty"
|
|
313
|
+
: "TSAbstractPropertyDefinition";
|
|
314
|
+
}
|
|
315
|
+
return r;
|
|
316
|
+
}
|
|
162
317
|
case 31: return { type: "StaticBlock", start, end, body: nodeArr(f1, f0) };
|
|
163
318
|
case 32: return { type: "Super", start, end };
|
|
164
|
-
case 33: return {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
319
|
+
case 33: return {
|
|
320
|
+
type: "Literal", start, end,
|
|
321
|
+
value: str(f1, f2), raw: _src.slice(start, end),
|
|
322
|
+
};
|
|
323
|
+
case 34: {
|
|
324
|
+
const r = _src.slice(start, end);
|
|
325
|
+
const s = r.indexOf("_") === -1 ? r : r.replace(/_/g, "");
|
|
326
|
+
const v = (flags & 3) === 2 && s[1] !== "o" && s[1] !== "O"
|
|
327
|
+
? parseInt(s.slice(1), 8)
|
|
328
|
+
: +s;
|
|
329
|
+
return {
|
|
330
|
+
type: "Literal", start, end,
|
|
331
|
+
value: v === v && isFinite(v) ? v : null,
|
|
332
|
+
raw: r,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
case 35: {
|
|
336
|
+
const r = _src.slice(start, end);
|
|
337
|
+
const d = str(f1, f2).replace(/_/g, "");
|
|
338
|
+
const v = BigInt(d);
|
|
339
|
+
return {
|
|
340
|
+
type: "Literal", start, end,
|
|
341
|
+
value: v, raw: r, bigint: v.toString(),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
case 36: {
|
|
345
|
+
const v = !!(flags & 1);
|
|
346
|
+
return {
|
|
347
|
+
type: "Literal", start, end,
|
|
348
|
+
value: v, raw: v ? "true" : "false",
|
|
349
|
+
};
|
|
350
|
+
}
|
|
168
351
|
case 37: return { type: "Literal", start, end, value: null, raw: "null" };
|
|
169
352
|
case 38: return { type: "ThisExpression", start, end };
|
|
170
|
-
case 39: {
|
|
353
|
+
case 39: {
|
|
354
|
+
const p = str(f1, f2), fl = str(f3, f4);
|
|
355
|
+
let v = null;
|
|
356
|
+
try { v = new RegExp(p, fl); } catch {}
|
|
357
|
+
return {
|
|
358
|
+
type: "Literal", start, end,
|
|
359
|
+
value: v, raw: "/" + p + "/" + fl,
|
|
360
|
+
regex: { pattern: p, flags: fl.split("").sort().join("") },
|
|
361
|
+
};
|
|
362
|
+
}
|
|
171
363
|
case 40: return { type: "TemplateLiteral", start, end, quasis: nodeArr(f1, f0), expressions: nodeArr(f2, f3) };
|
|
172
|
-
case 41: {
|
|
173
|
-
|
|
364
|
+
case 41: {
|
|
365
|
+
const raw = _src.slice(start, end).replace(/\r\n?/g, "\n");
|
|
366
|
+
const tl = !!(flags & 1);
|
|
367
|
+
const s = _isTs ? start - 1 : start;
|
|
368
|
+
const e = _isTs ? (tl ? end + 1 : end + 2) : end;
|
|
369
|
+
return {
|
|
370
|
+
type: "TemplateElement", start: s, end: e,
|
|
371
|
+
value: {
|
|
372
|
+
raw,
|
|
373
|
+
cooked: (flags & 2) ? null : str(f1, f2),
|
|
374
|
+
},
|
|
375
|
+
tail: tl,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
case 42: { const r = { type: "Identifier", start, end, name: str(f1, f2), kind: "reference" }; if (_isTs) { r.decorators = []; r.optional = false; r.typeAnnotation = null; } return r; }
|
|
174
379
|
case 43: return { type: "PrivateIdentifier", start, end, name: str(f1, f2) };
|
|
175
|
-
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; }
|
|
176
|
-
case 45: { const r = { type: "Identifier", start, end, name: str(f1, f2) }; if (_isTs) { r.decorators = []; r.optional = false; r.typeAnnotation = null; } return r; }
|
|
177
|
-
case 46: { const r = { type: "Identifier", start, end, name: str(f1, f2) }; if (_isTs) { r.decorators = []; r.optional = false; r.typeAnnotation = null; } return r; }
|
|
380
|
+
case 44: { const r = { type: "Identifier", start, end, name: str(f1, f2), kind: "binding" }; if (_isTs) { r.decorators = nodeArr(f3, f0); r.typeAnnotation = f4 !== NULL ? node(f4) : null; r.optional = !!(flags & 1); } return r; }
|
|
381
|
+
case 45: { const r = { type: "Identifier", start, end, name: str(f1, f2), kind: "name" }; if (_isTs) { r.decorators = []; r.optional = false; r.typeAnnotation = null; } return r; }
|
|
382
|
+
case 46: { const r = { type: "Identifier", start, end, name: str(f1, f2), kind: "label" }; if (_isTs) { r.decorators = []; r.optional = false; r.typeAnnotation = null; } return r; }
|
|
178
383
|
case 47: { const r = { type: "ExpressionStatement", start, end, expression: f1 !== NULL ? node(f1) : null }; if (_isTs) { r.directive = null; } return r; }
|
|
179
384
|
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 };
|
|
180
385
|
case 49: return { type: "SwitchStatement", start, end, discriminant: f1 !== NULL ? node(f1) : null, cases: nodeArr(f2, f0) };
|
|
@@ -196,13 +401,53 @@ function decode(buffer, source) {
|
|
|
196
401
|
case 65: return { type: "EmptyStatement", start, end };
|
|
197
402
|
case 66: { const r = { type: "VariableDeclaration", start, end, kind: VAR_KINDS[flags & 7], declarations: nodeArr(f1, f0) }; if (_isTs) { r.declare = !!(flags & 8); } return r; }
|
|
198
403
|
case 67: { const r = { type: "VariableDeclarator", start, end, id: f1 !== NULL ? node(f1) : null, init: f2 !== NULL ? node(f2) : null }; if (_isTs) { r.definite = !!(flags & 1); } return r; }
|
|
199
|
-
case 68: return {
|
|
404
|
+
case 68: return {
|
|
405
|
+
type: "ExpressionStatement", start, end,
|
|
406
|
+
expression: node(f1), directive: str(f2, f3),
|
|
407
|
+
};
|
|
200
408
|
case 69: { const r = { type: "AssignmentPattern", start, end, left: f1 !== NULL ? node(f1) : null, right: f2 !== NULL ? node(f2) : null }; if (_isTs) { r.decorators = nodeArr(f3, f0); r.typeAnnotation = f4 !== NULL ? node(f4) : null; r.optional = !!(flags & 1); } return r; }
|
|
201
409
|
case 70: { const r = { type: "RestElement", start, end, argument: f1 !== NULL ? node(f1) : null }; if (_isTs) { r.decorators = nodeArr(f2, f0); r.typeAnnotation = f3 !== NULL ? node(f3) : null; r.optional = !!(flags & 1); r.value = null; } return r; }
|
|
202
|
-
case 71: {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
410
|
+
case 71: {
|
|
411
|
+
const el = nodeArrHoles(f1, f0);
|
|
412
|
+
if (f2 !== NULL) el.push(node(f2));
|
|
413
|
+
const r = { type: "ArrayPattern", start, end, elements: el };
|
|
414
|
+
if (_isTs) {
|
|
415
|
+
r.decorators = nodeArr(f3, f4);
|
|
416
|
+
r.optional = !!(flags & 1);
|
|
417
|
+
r.typeAnnotation = f5 !== NULL ? node(f5) : null;
|
|
418
|
+
}
|
|
419
|
+
return r;
|
|
420
|
+
}
|
|
421
|
+
case 72: {
|
|
422
|
+
const pr = nodeArr(f1, f0);
|
|
423
|
+
if (f2 !== NULL) pr.push(node(f2));
|
|
424
|
+
const r = { type: "ObjectPattern", start, end, properties: pr };
|
|
425
|
+
if (_isTs) {
|
|
426
|
+
r.decorators = nodeArr(f3, f4);
|
|
427
|
+
r.optional = !!(flags & 1);
|
|
428
|
+
r.typeAnnotation = f5 !== NULL ? node(f5) : null;
|
|
429
|
+
}
|
|
430
|
+
return r;
|
|
431
|
+
}
|
|
432
|
+
case 73: {
|
|
433
|
+
const r = {
|
|
434
|
+
type: "Property", start, end,
|
|
435
|
+
kind: "init",
|
|
436
|
+
key: node(f1), value: node(f2),
|
|
437
|
+
method: false,
|
|
438
|
+
shorthand: !!(flags & 1),
|
|
439
|
+
computed: !!(flags & 2),
|
|
440
|
+
}; if (_isTs) { r.optional = false; } return r; }
|
|
441
|
+
case 74: return {
|
|
442
|
+
type: "Program", start, end,
|
|
443
|
+
sourceType: (flags & 1) ? "module" : "script",
|
|
444
|
+
hashbang: (flags & 2) ? {
|
|
445
|
+
type: "Hashbang",
|
|
446
|
+
start: _p(f2 - 2), end: _p(f3),
|
|
447
|
+
value: str(f2, f3),
|
|
448
|
+
} : null,
|
|
449
|
+
body: nodeArr(f1, f0),
|
|
450
|
+
};
|
|
206
451
|
case 75: return { type: "ImportExpression", start, end, source: f1 !== NULL ? node(f1) : null, options: f2 !== NULL ? node(f2) : null, phase: (flags & 1) ? ["source", "defer"][(flags >> 1) & 1] : null };
|
|
207
452
|
case 76: { const r = { type: "ImportDeclaration", start, end, specifiers: nodeArr(f1, f0), source: f2 !== NULL ? node(f2) : null, attributes: nodeArr(f3, f4), phase: (flags & 1) ? ["source", "defer"][(flags >> 1) & 1] : null }; if (_isTs) { r.importKind = IMPORT_EXPORT_KINDS[(flags >> 2) & 1]; } return r; }
|
|
208
453
|
case 77: { const r = { type: "ImportSpecifier", start, end, imported: f1 !== NULL ? node(f1) : null, local: f2 !== NULL ? node(f2) : null }; if (_isTs) { r.importKind = IMPORT_EXPORT_KINDS[flags & 1]; } return r; }
|
|
@@ -252,15 +497,54 @@ function decode(buffer, source) {
|
|
|
252
497
|
case 121: return { type: "TSInferType", start, end, typeParameter: f1 !== NULL ? node(f1) : null };
|
|
253
498
|
case 122: return { type: "TSTypeOperator", start, end, operator: TS_TYPE_OPERATORS[flags & 3], typeAnnotation: f1 !== NULL ? node(f1) : null };
|
|
254
499
|
case 123: return { type: "TSParenthesizedType", start, end, typeAnnotation: f1 !== NULL ? node(f1) : null };
|
|
255
|
-
case 124: return {
|
|
256
|
-
|
|
500
|
+
case 124: return {
|
|
501
|
+
type: "TSFunctionType", start, end,
|
|
502
|
+
typeParameters: f1 !== NULL ? node(f1) : null,
|
|
503
|
+
params: f2 !== NULL ? fnParams(f2) : [],
|
|
504
|
+
returnType: f3 !== NULL ? node(f3) : null,
|
|
505
|
+
};
|
|
506
|
+
case 125: return {
|
|
507
|
+
type: "TSConstructorType", start, end,
|
|
508
|
+
abstract: !!(flags & 1),
|
|
509
|
+
typeParameters: f1 !== NULL ? node(f1) : null,
|
|
510
|
+
params: f2 !== NULL ? fnParams(f2) : [],
|
|
511
|
+
returnType: f3 !== NULL ? node(f3) : null,
|
|
512
|
+
};
|
|
257
513
|
case 126: return { type: "TSTypePredicate", start, end, parameterName: f1 !== NULL ? node(f1) : null, typeAnnotation: f2 !== NULL ? node(f2) : null, asserts: !!(flags & 1) };
|
|
258
514
|
case 127: return { type: "TSTypeLiteral", start, end, members: nodeArr(f1, f0) };
|
|
259
|
-
case 128: return {
|
|
515
|
+
case 128: return {
|
|
516
|
+
type: "TSMappedType", start, end,
|
|
517
|
+
key: node(f1),
|
|
518
|
+
constraint: node(f2),
|
|
519
|
+
nameType: f3 !== NULL ? node(f3) : null,
|
|
520
|
+
typeAnnotation: f4 !== NULL ? node(f4) : null,
|
|
521
|
+
optional: TS_MAPPED_OPTIONAL[(flags >> 0) & 3],
|
|
522
|
+
readonly: TS_MAPPED_READONLY[(flags >> 2) & 3],
|
|
523
|
+
};
|
|
260
524
|
case 129: { const r = { type: "TSPropertySignature", start, end, key: f1 !== NULL ? node(f1) : null, typeAnnotation: f2 !== NULL ? node(f2) : null, computed: !!(flags & 1), optional: !!(flags & 2), readonly: !!(flags & 4) }; if (_isTs) { r.accessibility = null; r.static = false; } return r; }
|
|
261
|
-
case 130: return {
|
|
262
|
-
|
|
263
|
-
|
|
525
|
+
case 130: return {
|
|
526
|
+
type: "TSMethodSignature", start, end,
|
|
527
|
+
key: node(f1),
|
|
528
|
+
computed: !!(flags & 4),
|
|
529
|
+
optional: !!(flags & 8),
|
|
530
|
+
kind: TS_METHOD_SIGNATURE_KINDS[(flags >> 0) & 3],
|
|
531
|
+
typeParameters: f2 !== NULL ? node(f2) : null,
|
|
532
|
+
params: f3 !== NULL ? fnParams(f3) : [],
|
|
533
|
+
returnType: f4 !== NULL ? node(f4) : null,
|
|
534
|
+
accessibility: null, readonly: false, static: false,
|
|
535
|
+
};
|
|
536
|
+
case 131: return {
|
|
537
|
+
type: "TSCallSignatureDeclaration", start, end,
|
|
538
|
+
typeParameters: f1 !== NULL ? node(f1) : null,
|
|
539
|
+
params: f2 !== NULL ? fnParams(f2) : [],
|
|
540
|
+
returnType: f3 !== NULL ? node(f3) : null,
|
|
541
|
+
};
|
|
542
|
+
case 132: return {
|
|
543
|
+
type: "TSConstructSignatureDeclaration", start, end,
|
|
544
|
+
typeParameters: f1 !== NULL ? node(f1) : null,
|
|
545
|
+
params: f2 !== NULL ? fnParams(f2) : [],
|
|
546
|
+
returnType: f3 !== NULL ? node(f3) : null,
|
|
547
|
+
};
|
|
264
548
|
case 133: { const r = { type: "TSIndexSignature", start, end, parameters: nodeArr(f1, f0), typeAnnotation: f2 !== NULL ? node(f2) : null, readonly: !!(flags & 1) }; if (_isTs) { r.static = !!(flags & 2); r.accessibility = null; } return r; }
|
|
265
549
|
case 134: return { type: "TSTypeAliasDeclaration", start, end, id: f1 !== NULL ? node(f1) : null, typeParameters: f2 !== NULL ? node(f2) : null, typeAnnotation: f3 !== NULL ? node(f3) : null, declare: !!(flags & 1) };
|
|
266
550
|
case 135: return { type: "TSInterfaceDeclaration", start, end, id: f1 !== NULL ? node(f1) : null, typeParameters: f2 !== NULL ? node(f2) : null, extends: nodeArr(f3, f0), body: f4 !== NULL ? node(f4) : null, declare: !!(flags & 1) };
|
|
@@ -270,11 +554,32 @@ function decode(buffer, source) {
|
|
|
270
554
|
case 139: return { type: "TSEnumDeclaration", start, end, id: f1 !== NULL ? node(f1) : null, body: f2 !== NULL ? node(f2) : null, const: !!(flags & 1), declare: !!(flags & 2) };
|
|
271
555
|
case 140: return { type: "TSEnumBody", start, end, members: nodeArr(f1, f0) };
|
|
272
556
|
case 141: return { type: "TSEnumMember", start, end, id: f1 !== NULL ? node(f1) : null, initializer: f2 !== NULL ? node(f2) : null, computed: !!(flags & 1) };
|
|
273
|
-
case 142: {
|
|
557
|
+
case 142: {
|
|
558
|
+
const r = {
|
|
559
|
+
type: "TSModuleDeclaration", start, end,
|
|
560
|
+
id: node(f1),
|
|
561
|
+
kind: TS_MODULE_KINDS[(flags >> 0) & 1],
|
|
562
|
+
declare: !!(flags & 2),
|
|
563
|
+
global: false,
|
|
564
|
+
};
|
|
565
|
+
if (f2 !== NULL) r.body = node(f2);
|
|
566
|
+
return r;
|
|
567
|
+
}
|
|
274
568
|
case 143: return { type: "TSModuleBlock", start, end, body: nodeArr(f1, f0) };
|
|
275
|
-
case 144: return {
|
|
569
|
+
case 144: return {
|
|
570
|
+
type: "TSModuleDeclaration", start, end,
|
|
571
|
+
id: node(f1), body: node(f2),
|
|
572
|
+
kind: "global",
|
|
573
|
+
declare: !!(flags & 1),
|
|
574
|
+
global: true,
|
|
575
|
+
};
|
|
276
576
|
case 145: { const r = { type: "TSParameterProperty", start, end, decorators: nodeArr(f1, f0), parameter: f2 !== NULL ? node(f2) : null, override: !!(flags & 1), readonly: !!(flags & 2), accessibility: ACCESSIBILITY[(flags >> 2) & 3] }; if (_isTs) { r.static = false; } return r; }
|
|
277
|
-
case 146: return {
|
|
577
|
+
case 146: return {
|
|
578
|
+
type: "Identifier", start, end,
|
|
579
|
+
decorators: [],
|
|
580
|
+
name: "this", kind: "this", optional: false,
|
|
581
|
+
typeAnnotation: f1 !== NULL ? node(f1) : null,
|
|
582
|
+
};
|
|
278
583
|
case 147: return { type: "TSAsExpression", start, end, expression: f1 !== NULL ? node(f1) : null, typeAnnotation: f2 !== NULL ? node(f2) : null };
|
|
279
584
|
case 148: return { type: "TSSatisfiesExpression", start, end, expression: f1 !== NULL ? node(f1) : null, typeAnnotation: f2 !== NULL ? node(f2) : null };
|
|
280
585
|
case 149: return { type: "TSTypeAssertion", start, end, typeAnnotation: f1 !== NULL ? node(f1) : null, expression: f2 !== NULL ? node(f2) : null };
|
|
@@ -297,34 +602,22 @@ function decode(buffer, source) {
|
|
|
297
602
|
case 166: return { type: "JSXSpreadAttribute", start, end, argument: f1 !== NULL ? node(f1) : null };
|
|
298
603
|
case 167: return { type: "JSXExpressionContainer", start, end, expression: f1 !== NULL ? node(f1) : null };
|
|
299
604
|
case 168: return { type: "JSXEmptyExpression", start, end };
|
|
300
|
-
case 169: {
|
|
605
|
+
case 169: {
|
|
606
|
+
const t = str(f1, f2);
|
|
607
|
+
return { type: "JSXText", start, end, value: t, raw: t };
|
|
608
|
+
}
|
|
301
609
|
case 170: return { type: "JSXSpreadChild", start, end, expression: f1 !== NULL ? node(f1) : null };
|
|
302
610
|
}
|
|
303
611
|
}
|
|
304
|
-
const
|
|
305
|
-
const lsOff =
|
|
612
|
+
const node = _attachComments ? nodeWithComments : _decode;
|
|
613
|
+
const lsOff = _cOff + commentCount * 12;
|
|
306
614
|
const dOff = lsOff + lineStartsCount * 4;
|
|
307
|
-
const dv = new DataView(buffer);
|
|
308
|
-
function _decodeComments() {
|
|
309
|
-
const out = new Array(commentCount);
|
|
310
|
-
for (let j = 0; j < commentCount; j++) {
|
|
311
|
-
const o = cOff + j * 20;
|
|
312
|
-
const flags = _u8[o + 1];
|
|
313
|
-
out[j] = {
|
|
314
|
-
type: COMMENT_TYPES[_u8[o + 0]],
|
|
315
|
-
precededByNewline: (flags & 1) !== 0,
|
|
316
|
-
followedByNewline: (flags & 2) !== 0,
|
|
317
|
-
value: str(dv.getUint32(o + 12, true), dv.getUint32(o + 16, true)),
|
|
318
|
-
start: _p(dv.getUint32(o + 4, true)),
|
|
319
|
-
end: _p(dv.getUint32(o + 8, true)),
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
return out;
|
|
323
|
-
}
|
|
324
615
|
function _decodeLineStarts() {
|
|
325
616
|
const out = new Array(lineStartsCount);
|
|
326
617
|
if (_firstNa >= _srcLen) {
|
|
327
|
-
for (let j = 0; j < lineStartsCount; j++)
|
|
618
|
+
for (let j = 0; j < lineStartsCount; j++) {
|
|
619
|
+
out[j] = dv.getUint32(lsOff + j * 4, true);
|
|
620
|
+
}
|
|
328
621
|
return out;
|
|
329
622
|
}
|
|
330
623
|
if (pm === null) pm = buildPosMap(_src, _srcLen, _firstNa);
|
|
@@ -345,25 +638,51 @@ function decode(buffer, source) {
|
|
|
345
638
|
const msg = _td.decode(_u8.subarray(dp, dp + ml)); dp += ml;
|
|
346
639
|
const hh = _u8[dp]; dp++;
|
|
347
640
|
let help = null;
|
|
348
|
-
if (hh) {
|
|
641
|
+
if (hh) {
|
|
642
|
+
const hl = dv.getUint32(dp, true); dp += 4;
|
|
643
|
+
help = _td.decode(_u8.subarray(dp, dp + hl)); dp += hl;
|
|
644
|
+
}
|
|
349
645
|
const lc = dv.getUint32(dp, true); dp += 4;
|
|
350
646
|
const labels = new Array(lc);
|
|
351
647
|
for (let k = 0; k < lc; k++) {
|
|
352
648
|
const ls = _p(dv.getUint32(dp, true)); dp += 4;
|
|
353
649
|
const le = _p(dv.getUint32(dp, true)); dp += 4;
|
|
354
650
|
const lml = dv.getUint32(dp, true); dp += 4;
|
|
355
|
-
labels[k] = {
|
|
651
|
+
labels[k] = {
|
|
652
|
+
start: ls,
|
|
653
|
+
end: le,
|
|
654
|
+
message: _td.decode(_u8.subarray(dp, dp + lml)),
|
|
655
|
+
};
|
|
656
|
+
dp += lml;
|
|
356
657
|
}
|
|
357
658
|
out[j] = { severity: sev, message: msg, start: ds, end: de, help, labels };
|
|
358
659
|
}
|
|
359
660
|
return out;
|
|
360
661
|
}
|
|
361
|
-
let _program,
|
|
662
|
+
let _program, _lineStarts, _diagnostics;
|
|
663
|
+
function _getLineStarts() {
|
|
664
|
+
if (_lineStarts === undefined) _lineStarts = _decodeLineStarts();
|
|
665
|
+
return _lineStarts;
|
|
666
|
+
}
|
|
362
667
|
return {
|
|
363
|
-
get program() {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
get diagnostics() {
|
|
668
|
+
get program() {
|
|
669
|
+
return _program !== undefined ? _program : (_program = node(progIdx));
|
|
670
|
+
},
|
|
671
|
+
get diagnostics() {
|
|
672
|
+
return _diagnostics !== undefined
|
|
673
|
+
? _diagnostics
|
|
674
|
+
: (_diagnostics = _decodeDiagnostics());
|
|
675
|
+
},
|
|
676
|
+
get lineStarts() { return _getLineStarts(); },
|
|
677
|
+
locOf(offset) {
|
|
678
|
+
const ls = _getLineStarts();
|
|
679
|
+
let lo = 0, hi = ls.length;
|
|
680
|
+
while (lo < hi) {
|
|
681
|
+
const mid = (lo + hi) >>> 1;
|
|
682
|
+
if (ls[mid] <= offset) lo = mid + 1; else hi = mid;
|
|
683
|
+
}
|
|
684
|
+
return { line: lo, column: offset - ls[lo - 1] };
|
|
685
|
+
},
|
|
367
686
|
};
|
|
368
687
|
}
|
|
369
688
|
export { decode };
|
package/index.d.ts
CHANGED
|
@@ -40,24 +40,39 @@ interface ParseOptions {
|
|
|
40
40
|
* @default false
|
|
41
41
|
*/
|
|
42
42
|
semanticErrors?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Collect comments and attach them to host AST nodes via
|
|
45
|
+
* {@link BaseNode.comments}.
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
attachComments?: boolean;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
/** Whether a {@link Comment} came from a line or block source comment. */
|
|
46
52
|
type CommentType = "Line" | "Block";
|
|
47
53
|
|
|
48
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Position of a {@link Comment} relative to its host node.
|
|
56
|
+
*
|
|
57
|
+
* - `before`: leading the host.
|
|
58
|
+
* - `after`: trailing the host.
|
|
59
|
+
* - `inside`: interior to an otherwise empty host.
|
|
60
|
+
*/
|
|
61
|
+
type CommentPosition = "before" | "after" | "inside";
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A source code comment attached to a single host AST node.
|
|
65
|
+
*
|
|
66
|
+
* `sameLine` is true when the comment shares a source line with the
|
|
67
|
+
* host's adjacent edge (host's start for `before`, host's end for
|
|
68
|
+
* `after`). For `inside` it is always `false`.
|
|
69
|
+
*/
|
|
49
70
|
interface Comment {
|
|
50
71
|
type: CommentType;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
/** True when a line terminator immediately follows this comment. */
|
|
54
|
-
followedByNewline: boolean;
|
|
72
|
+
position: CommentPosition;
|
|
73
|
+
sameLine: boolean;
|
|
55
74
|
/** Comment text without the delimiters. */
|
|
56
75
|
value: string;
|
|
57
|
-
/** Byte offset. */
|
|
58
|
-
start: number;
|
|
59
|
-
/** Byte offset. */
|
|
60
|
-
end: number;
|
|
61
76
|
}
|
|
62
77
|
|
|
63
78
|
/** A labeled source span attached to a {@link Diagnostic}. */
|
|
@@ -104,12 +119,19 @@ interface SourceLocation {
|
|
|
104
119
|
interface ParseResult {
|
|
105
120
|
/** Root ESTree/TypeScript-ESTree AST node. */
|
|
106
121
|
program: Program;
|
|
107
|
-
/** All comments in source order. */
|
|
108
|
-
comments: Comment[];
|
|
109
|
-
/** Byte offset where each source line begins. Index 0 is always 0. */
|
|
110
|
-
lineStarts: number[];
|
|
111
122
|
/** Syntax diagnostics, and semantic diagnostics when {@link ParseOptions.semanticErrors} is enabled. */
|
|
112
123
|
diagnostics: Diagnostic[];
|
|
124
|
+
/**
|
|
125
|
+
* Sorted UTF-16 offsets where each line begins. Index `i` is the start of
|
|
126
|
+
* line `i + 1`. Used internally by {@link locOf}, and required by
|
|
127
|
+
* `yuku-codegen` for source maps.
|
|
128
|
+
*/
|
|
129
|
+
lineStarts: number[];
|
|
130
|
+
/**
|
|
131
|
+
* Resolves an offset to a `{ line, column }` pair. Lines are
|
|
132
|
+
* 1-based, columns are 0-based, matching ESTree's `loc` convention.
|
|
133
|
+
*/
|
|
134
|
+
locOf(offset: number): SourceLocation;
|
|
113
135
|
}
|
|
114
136
|
|
|
115
137
|
/**
|
|
@@ -136,25 +158,16 @@ export function langFromPath(path: string): SourceLang;
|
|
|
136
158
|
*/
|
|
137
159
|
export function sourceTypeFromPath(path: string): SourceType;
|
|
138
160
|
|
|
139
|
-
/**
|
|
140
|
-
* Resolves a `{ line, column }` {@link SourceLocation} for an offset, using
|
|
141
|
-
* {@link ParseResult.lineStarts}. Runs in O(log n).
|
|
142
|
-
*
|
|
143
|
-
* Lines are 1-based; columns are 0-based. The unit of `offset` (UTF-16 code
|
|
144
|
-
* units in JS) must match the unit of `lineStarts`. Both come from the same
|
|
145
|
-
* {@link ParseResult}, so this is automatic.
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* const { program, lineStarts } = parse(source);
|
|
149
|
-
* locOf(lineStarts, program.body[0].start); // => { line, column }
|
|
150
|
-
*/
|
|
151
|
-
export function locOf(lineStarts: number[], offset: number): SourceLocation;
|
|
152
|
-
|
|
153
161
|
// AST node types
|
|
154
162
|
|
|
155
163
|
interface BaseNode {
|
|
156
164
|
start: number;
|
|
157
165
|
end: number;
|
|
166
|
+
/**
|
|
167
|
+
* Comments attached to this node in source order. Present only when
|
|
168
|
+
* {@link ParseOptions.attachComments} is enabled.
|
|
169
|
+
*/
|
|
170
|
+
comments?: Comment[];
|
|
158
171
|
}
|
|
159
172
|
|
|
160
173
|
type Span = BaseNode;
|
|
@@ -241,39 +254,37 @@ type PropertyDefinitionType = "PropertyDefinition" | "TSAbstractPropertyDefiniti
|
|
|
241
254
|
|
|
242
255
|
type AccessorPropertyType = "AccessorProperty" | "TSAbstractAccessorProperty";
|
|
243
256
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
optional?: false;
|
|
257
|
-
typeAnnotation?: null;
|
|
258
|
-
}
|
|
257
|
+
/**
|
|
258
|
+
* Role of an `Identifier` within the AST. Yuku exposes the four ESTree-collapsed
|
|
259
|
+
* identifier flavors as a discriminator, plus `"this"` for a TS `this`-parameter
|
|
260
|
+
* (which TS-ESTree also encodes as an `Identifier` with `name: "this"`).
|
|
261
|
+
*
|
|
262
|
+
* - `"reference"`: identifier read as a value (`x` in `x + 1`, `console`).
|
|
263
|
+
* - `"binding"`: identifier being declared (parameters, `let x`, function/class names).
|
|
264
|
+
* - `"name"`: identifier in a non-binding name slot (property/method names like `log` in `console.log`).
|
|
265
|
+
* - `"label"`: loop label (`outer` in `outer: for (...) {}`).
|
|
266
|
+
* - `"this"`: the TS `this`-parameter (`function f(this: T)`).
|
|
267
|
+
*/
|
|
268
|
+
type IdentifierKind = "reference" | "binding" | "name" | "label" | "this";
|
|
259
269
|
|
|
260
|
-
interface
|
|
270
|
+
interface Identifier extends BaseNode {
|
|
261
271
|
type: "Identifier";
|
|
262
272
|
name: string;
|
|
273
|
+
/**
|
|
274
|
+
* ESTree collapses several distinct identifier
|
|
275
|
+
* roles onto one `Identifier` node, `kind` lets you tell them apart without
|
|
276
|
+
* walking the parent context. See {@link IdentifierKind}.
|
|
277
|
+
*/
|
|
278
|
+
kind: IdentifierKind;
|
|
263
279
|
decorators?: Decorator[];
|
|
264
280
|
optional?: boolean;
|
|
265
281
|
typeAnnotation?: TSTypeAnnotation | null;
|
|
266
282
|
}
|
|
267
283
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
optional?: false;
|
|
273
|
-
typeAnnotation?: null;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
type Identifier = IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier;
|
|
284
|
+
type IdentifierName = Identifier;
|
|
285
|
+
type IdentifierReference = Identifier;
|
|
286
|
+
type BindingIdentifier = Identifier;
|
|
287
|
+
type LabelIdentifier = Identifier;
|
|
277
288
|
|
|
278
289
|
interface PrivateIdentifier extends BaseNode {
|
|
279
290
|
type: "PrivateIdentifier";
|
|
@@ -1686,6 +1697,7 @@ type Node =
|
|
|
1686
1697
|
| Directive
|
|
1687
1698
|
| ObjectProperty
|
|
1688
1699
|
| BindingProperty
|
|
1700
|
+
| SpreadElement
|
|
1689
1701
|
| PrivateIdentifier
|
|
1690
1702
|
| TemplateElement
|
|
1691
1703
|
| VariableDeclarator
|
|
@@ -1704,6 +1716,7 @@ type Node =
|
|
|
1704
1716
|
| TSAbstractAccessorProperty
|
|
1705
1717
|
| StaticBlock
|
|
1706
1718
|
| Decorator
|
|
1719
|
+
| TSEmptyBodyFunctionExpression
|
|
1707
1720
|
| ImportSpecifier
|
|
1708
1721
|
| ImportDefaultSpecifier
|
|
1709
1722
|
| ImportNamespaceSpecifier
|
|
@@ -1749,6 +1762,7 @@ export type {
|
|
|
1749
1762
|
ParseResult,
|
|
1750
1763
|
Comment,
|
|
1751
1764
|
CommentType,
|
|
1765
|
+
CommentPosition,
|
|
1752
1766
|
Diagnostic,
|
|
1753
1767
|
DiagnosticLabel,
|
|
1754
1768
|
DiagnosticSeverity,
|
|
@@ -1780,6 +1794,7 @@ export type {
|
|
|
1780
1794
|
ModuleExportName,
|
|
1781
1795
|
PropertyKey,
|
|
1782
1796
|
Identifier,
|
|
1797
|
+
IdentifierKind,
|
|
1783
1798
|
IdentifierName,
|
|
1784
1799
|
IdentifierReference,
|
|
1785
1800
|
BindingIdentifier,
|
package/index.js
CHANGED
|
@@ -16,13 +16,3 @@ export function langFromPath(path) {
|
|
|
16
16
|
export function sourceTypeFromPath(path) {
|
|
17
17
|
return path.endsWith(".cjs") || path.endsWith(".cts") ? "script" : "module";
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
export function locOf(lineStarts, offset) {
|
|
21
|
-
let lo = 0, hi = lineStarts.length;
|
|
22
|
-
while (lo < hi) {
|
|
23
|
-
const mid = (lo + hi) >>> 1;
|
|
24
|
-
if (lineStarts[mid] <= offset) lo = mid + 1;
|
|
25
|
-
else hi = mid;
|
|
26
|
-
}
|
|
27
|
-
return { line: lo, column: offset - lineStarts[lo - 1] };
|
|
28
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yuku-parser",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.16",
|
|
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.16",
|
|
21
|
+
"@yuku-parser/binding-linux-arm64-gnu": "0.5.16",
|
|
22
|
+
"@yuku-parser/binding-linux-arm-gnu": "0.5.16",
|
|
23
|
+
"@yuku-parser/binding-linux-x64-musl": "0.5.16",
|
|
24
|
+
"@yuku-parser/binding-linux-arm64-musl": "0.5.16",
|
|
25
|
+
"@yuku-parser/binding-linux-arm-musl": "0.5.16",
|
|
26
|
+
"@yuku-parser/binding-darwin-x64": "0.5.16",
|
|
27
|
+
"@yuku-parser/binding-darwin-arm64": "0.5.16",
|
|
28
|
+
"@yuku-parser/binding-win32-x64": "0.5.16",
|
|
29
|
+
"@yuku-parser/binding-win32-arm64": "0.5.16",
|
|
30
|
+
"@yuku-parser/binding-freebsd-x64": "0.5.16"
|
|
31
31
|
},
|
|
32
32
|
"keywords": [
|
|
33
33
|
"acorn",
|