yuku-parser 0.5.17 → 0.5.18
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 +39 -43
- package/decode.js +41 -16
- package/index.d.ts +38 -11
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -74,22 +74,20 @@ const { line, column } = result.locOf(result.program.body[0].start);
|
|
|
74
74
|
|
|
75
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
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.
|
|
78
|
-
|
|
79
77
|
## Walking the AST
|
|
80
78
|
|
|
81
|
-
|
|
79
|
+
[`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.
|
|
82
80
|
|
|
83
81
|
```ts
|
|
84
|
-
import { parse
|
|
85
|
-
import { walk } from "
|
|
82
|
+
import { parse } from "yuku-parser";
|
|
83
|
+
import { walk } from "yuku-ast";
|
|
86
84
|
|
|
87
85
|
const { program } = parse(`
|
|
88
86
|
const message = "hello";
|
|
89
87
|
console.log(message);
|
|
90
88
|
`);
|
|
91
89
|
|
|
92
|
-
walk(program
|
|
90
|
+
walk(program, {
|
|
93
91
|
Identifier(node) {
|
|
94
92
|
console.log(node.name);
|
|
95
93
|
},
|
|
@@ -99,6 +97,8 @@ walk(program as Node, null, {
|
|
|
99
97
|
});
|
|
100
98
|
```
|
|
101
99
|
|
|
100
|
+
The AST is also standard ESTree, so any ESTree-compatible walker (e.g. [zimmerframe](https://github.com/sveltejs/zimmerframe)) works just as well.
|
|
101
|
+
|
|
102
102
|
## Options
|
|
103
103
|
|
|
104
104
|
All options are optional.
|
|
@@ -121,7 +121,7 @@ const result = parse(source, {
|
|
|
121
121
|
| `preserveParens` | `true`, `false` | `true` | Keep `ParenthesizedExpression` nodes in the AST. When false, parentheses are stripped and only the inner expression is kept. |
|
|
122
122
|
| `allowReturnOutsideFunction` | `true`, `false` | `false` | Allow `return` statements outside of functions, at the top level. |
|
|
123
123
|
| `semanticErrors` | `true`, `false` | `false` | Run semantic analysis and report semantic errors alongside syntax errors. |
|
|
124
|
-
| `attachComments` | `true`, `false` | `false` |
|
|
124
|
+
| `attachComments` | `true`, `false` | `false` | Also attach each comment to its host AST node. The flat `result.comments` list is always present. See [Comments](#comments). |
|
|
125
125
|
|
|
126
126
|
## Result
|
|
127
127
|
|
|
@@ -130,6 +130,7 @@ const result = parse(source, {
|
|
|
130
130
|
```ts
|
|
131
131
|
interface ParseResult {
|
|
132
132
|
program: Program;
|
|
133
|
+
comments: Comment[]; // every comment in source order
|
|
133
134
|
diagnostics: Diagnostic[];
|
|
134
135
|
lineStarts: number[];
|
|
135
136
|
locOf(offset: number): { line: number; column: number };
|
|
@@ -163,63 +164,58 @@ This incurs a very small performance overhead. If your build pipeline already ha
|
|
|
163
164
|
|
|
164
165
|
## Comments
|
|
165
166
|
|
|
166
|
-
|
|
167
|
+
Every comment is always in `result.comments`, a flat list in source order with each comment's source span:
|
|
167
168
|
|
|
168
169
|
```js
|
|
169
|
-
const {
|
|
170
|
-
`// header\nfunction foo() {} // trailing`,
|
|
171
|
-
{ attachComments: true },
|
|
172
|
-
);
|
|
170
|
+
const { comments } = parse(`// a line comment\nconst x = 1; /* a block comment */`);
|
|
173
171
|
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
console.log(c.position, c.type, c.value);
|
|
172
|
+
for (const c of comments) {
|
|
173
|
+
console.log(c.type, JSON.stringify(c.value), c.start, c.end);
|
|
177
174
|
}
|
|
178
|
-
//
|
|
179
|
-
//
|
|
175
|
+
// Line " a line comment" 0 17
|
|
176
|
+
// Block " a block comment " 31 52
|
|
180
177
|
```
|
|
181
178
|
|
|
182
|
-
Each
|
|
179
|
+
Each entry is:
|
|
183
180
|
|
|
184
181
|
```ts
|
|
185
182
|
interface Comment {
|
|
186
183
|
type: "Line" | "Block";
|
|
187
|
-
position: "before" | "after" | "inside";
|
|
188
|
-
sameLine: boolean;
|
|
189
184
|
value: string; // body without delimiters
|
|
185
|
+
start: number; // byte offset, delimiter included
|
|
186
|
+
end: number; // byte offset, delimiter included
|
|
190
187
|
}
|
|
191
188
|
```
|
|
192
189
|
|
|
193
|
-
`
|
|
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.
|
|
190
|
+
The span (`start`/`end`) covers the whole comment, delimiters included, so `source.slice(c.start, c.end)` returns the raw text.
|
|
206
191
|
|
|
207
|
-
|
|
192
|
+
### Attaching comments to nodes
|
|
208
193
|
|
|
209
|
-
|
|
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.
|
|
194
|
+
Set `attachComments: true` to also hang each comment on the AST node it sits next to, read off `node.comments`. This is what a codegen pass needs, since attached comments move with their node through transforms.
|
|
212
195
|
|
|
213
|
-
|
|
196
|
+
```js
|
|
197
|
+
const { program } = parse(`// header\nfunction foo() {} // trailing`, { attachComments: true });
|
|
214
198
|
|
|
215
|
-
|
|
199
|
+
const fn = program.body[0];
|
|
200
|
+
for (const c of fn.comments ?? []) {
|
|
201
|
+
console.log(c.position, c.type, c.value);
|
|
202
|
+
}
|
|
203
|
+
// before Line " header"
|
|
204
|
+
// after Line " trailing"
|
|
205
|
+
```
|
|
216
206
|
|
|
217
|
-
|
|
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.
|
|
207
|
+
Each attached comment is:
|
|
219
208
|
|
|
220
|
-
|
|
209
|
+
```ts
|
|
210
|
+
interface AttachedComment {
|
|
211
|
+
type: "Line" | "Block";
|
|
212
|
+
position: "before" | "after" | "inside";
|
|
213
|
+
sameLine: boolean;
|
|
214
|
+
value: string; // body without delimiters
|
|
215
|
+
}
|
|
216
|
+
```
|
|
221
217
|
|
|
222
|
-
|
|
218
|
+
`position` is where the comment sits relative to its host: `"before"` (leading), `"after"` (trailing), or `"inside"` (interior to an otherwise empty host like `function f() { /* hi */ }`). `sameLine` is `true` when the comment shares a source line with the host's adjacent edge.
|
|
223
219
|
|
|
224
220
|
## License
|
|
225
221
|
|
package/decode.js
CHANGED
|
@@ -68,22 +68,24 @@ function decode(buffer, source) {
|
|
|
68
68
|
extraCount = _u32[1],
|
|
69
69
|
spLen = _u32[2];
|
|
70
70
|
const commentCount = _u32[4],
|
|
71
|
-
lineStartsCount = _u32[
|
|
72
|
-
diagCount = _u32[
|
|
73
|
-
progIdx = _u32[
|
|
74
|
-
const
|
|
71
|
+
lineStartsCount = _u32[6],
|
|
72
|
+
diagCount = _u32[7],
|
|
73
|
+
progIdx = _u32[8];
|
|
74
|
+
const attachedCommentCount = _u32[5];
|
|
75
|
+
const _flags = _u32[9];
|
|
75
76
|
const _isTs = !!(_flags & 1);
|
|
76
|
-
const
|
|
77
|
-
const _firstNa = _u32[
|
|
78
|
-
const _nodesOff =
|
|
77
|
+
const _attached = !!(_flags & 2);
|
|
78
|
+
const _firstNa = _u32[10];
|
|
79
|
+
const _nodesOff = 44;
|
|
79
80
|
const eOff = _nodesOff + nodeCount * 48;
|
|
80
81
|
const _extraBase = eOff >> 2;
|
|
81
82
|
const _spOff = eOff + extraCount * 4;
|
|
82
83
|
// sections after the variable-length string pool may be at any
|
|
83
84
|
// byte alignment, so reads against them use `dv`, not `_u32`.
|
|
84
85
|
const dv = new DataView(buffer);
|
|
85
|
-
const
|
|
86
|
-
const
|
|
86
|
+
const _aoOff = _spOff + spLen;
|
|
87
|
+
const _acOff = _attached ? _aoOff + (nodeCount + 1) * 4 : _aoOff;
|
|
88
|
+
const _cOff = _acOff + attachedCommentCount * 12;
|
|
87
89
|
function _poolDecode(s, e) {
|
|
88
90
|
const a = _spOff + s - _srcLen, b = _spOff + e - _srcLen;
|
|
89
91
|
let hasEd = false;
|
|
@@ -155,10 +157,10 @@ function decode(buffer, source) {
|
|
|
155
157
|
if (rest !== NULL) p.push(node(rest));
|
|
156
158
|
return p;
|
|
157
159
|
}
|
|
158
|
-
function
|
|
160
|
+
function _attachedCommentsOf(a, e) {
|
|
159
161
|
const out = new Array(e - a);
|
|
160
162
|
for (let j = a; j < e; j++) {
|
|
161
|
-
const o =
|
|
163
|
+
const o = _acOff + j * 12;
|
|
162
164
|
const cf = _u8[o + 0];
|
|
163
165
|
const vs = dv.getUint32(o + 4, true),
|
|
164
166
|
ve = dv.getUint32(o + 8, true);
|
|
@@ -176,9 +178,9 @@ function decode(buffer, source) {
|
|
|
176
178
|
// skip unwrap cases whose inner node already carries its own
|
|
177
179
|
// comments (e.g. formal_parameter returning its pattern)
|
|
178
180
|
if (r && r.type !== undefined && r.comments === undefined) {
|
|
179
|
-
const off =
|
|
181
|
+
const off = _aoOff + i * 4;
|
|
180
182
|
const a = dv.getUint32(off, true), e = dv.getUint32(off + 4, true);
|
|
181
|
-
if (a !== e) r.comments =
|
|
183
|
+
if (a !== e) r.comments = _attachedCommentsOf(a, e);
|
|
182
184
|
}
|
|
183
185
|
return r;
|
|
184
186
|
}
|
|
@@ -609,9 +611,27 @@ function decode(buffer, source) {
|
|
|
609
611
|
case 170: return { type: "JSXSpreadChild", start, end, expression: f1 !== NULL ? node(f1) : null };
|
|
610
612
|
}
|
|
611
613
|
}
|
|
612
|
-
const node =
|
|
613
|
-
const lsOff = _cOff + commentCount *
|
|
614
|
+
const node = _attached ? nodeWithComments : _decode;
|
|
615
|
+
const lsOff = _cOff + commentCount * 20;
|
|
614
616
|
const dOff = lsOff + lineStartsCount * 4;
|
|
617
|
+
function _decodeComments() {
|
|
618
|
+
const out = new Array(commentCount);
|
|
619
|
+
for (let j = 0; j < commentCount; j++) {
|
|
620
|
+
const o = _cOff + j * 20;
|
|
621
|
+
const cf = _u8[o + 0];
|
|
622
|
+
const vs = dv.getUint32(o + 4, true),
|
|
623
|
+
ve = dv.getUint32(o + 8, true);
|
|
624
|
+
const ss = dv.getUint32(o + 12, true),
|
|
625
|
+
se = dv.getUint32(o + 16, true);
|
|
626
|
+
out[j] = {
|
|
627
|
+
type: (cf & 1) ? "Block" : "Line",
|
|
628
|
+
value: str(vs, ve),
|
|
629
|
+
start: _p(ss),
|
|
630
|
+
end: _p(se),
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
return out;
|
|
634
|
+
}
|
|
615
635
|
function _decodeLineStarts() {
|
|
616
636
|
const out = new Array(lineStartsCount);
|
|
617
637
|
if (_firstNa >= _srcLen) {
|
|
@@ -659,7 +679,7 @@ function decode(buffer, source) {
|
|
|
659
679
|
}
|
|
660
680
|
return out;
|
|
661
681
|
}
|
|
662
|
-
let _program, _lineStarts, _diagnostics;
|
|
682
|
+
let _program, _lineStarts, _diagnostics, _comments;
|
|
663
683
|
function _getLineStarts() {
|
|
664
684
|
if (_lineStarts === undefined) _lineStarts = _decodeLineStarts();
|
|
665
685
|
return _lineStarts;
|
|
@@ -668,6 +688,11 @@ function decode(buffer, source) {
|
|
|
668
688
|
get program() {
|
|
669
689
|
return _program !== undefined ? _program : (_program = node(progIdx));
|
|
670
690
|
},
|
|
691
|
+
get comments() {
|
|
692
|
+
return _comments !== undefined
|
|
693
|
+
? _comments
|
|
694
|
+
: (_comments = _decodeComments());
|
|
695
|
+
},
|
|
671
696
|
get diagnostics() {
|
|
672
697
|
return _diagnostics !== undefined
|
|
673
698
|
? _diagnostics
|
package/index.d.ts
CHANGED
|
@@ -41,18 +41,33 @@ interface ParseOptions {
|
|
|
41
41
|
*/
|
|
42
42
|
semanticErrors?: boolean;
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
45
|
-
* {@link BaseNode.comments}.
|
|
44
|
+
* Also attach each comment to the AST node it sits next to, via
|
|
45
|
+
* {@link BaseNode.comments}. The flat {@link ParseResult.comments} list is
|
|
46
|
+
* always present regardless.
|
|
46
47
|
* @default false
|
|
47
48
|
*/
|
|
48
49
|
attachComments?: boolean;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
/** Whether a
|
|
52
|
+
/** Whether a comment came from a line or block source comment. */
|
|
52
53
|
type CommentType = "Line" | "Block";
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
|
-
*
|
|
56
|
+
* A source comment in the flat {@link ParseResult.comments} list, carrying its
|
|
57
|
+
* source span.
|
|
58
|
+
*/
|
|
59
|
+
interface Comment {
|
|
60
|
+
type: CommentType;
|
|
61
|
+
/** Comment text without the delimiters. */
|
|
62
|
+
value: string;
|
|
63
|
+
/** Byte offset of the comment start (delimiter included). */
|
|
64
|
+
start: number;
|
|
65
|
+
/** Byte offset of the comment end (delimiter included). */
|
|
66
|
+
end: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Position of an {@link AttachedComment} relative to its host node.
|
|
56
71
|
*
|
|
57
72
|
* - `before`: leading the host.
|
|
58
73
|
* - `after`: trailing the host.
|
|
@@ -61,13 +76,13 @@ type CommentType = "Line" | "Block";
|
|
|
61
76
|
type CommentPosition = "before" | "after" | "inside";
|
|
62
77
|
|
|
63
78
|
/**
|
|
64
|
-
* A
|
|
79
|
+
* A comment attached to a single host AST node, via {@link BaseNode.comments}.
|
|
65
80
|
*
|
|
66
81
|
* `sameLine` is true when the comment shares a source line with the
|
|
67
82
|
* host's adjacent edge (host's start for `before`, host's end for
|
|
68
83
|
* `after`). For `inside` it is always `false`.
|
|
69
84
|
*/
|
|
70
|
-
interface
|
|
85
|
+
interface AttachedComment {
|
|
71
86
|
type: CommentType;
|
|
72
87
|
position: CommentPosition;
|
|
73
88
|
sameLine: boolean;
|
|
@@ -119,6 +134,8 @@ interface SourceLocation {
|
|
|
119
134
|
interface ParseResult {
|
|
120
135
|
/** Root ESTree/TypeScript-ESTree AST node. */
|
|
121
136
|
program: Program;
|
|
137
|
+
/** Every comment in source order, each with its source span. */
|
|
138
|
+
comments: Comment[];
|
|
122
139
|
/** Syntax diagnostics, and semantic diagnostics when {@link ParseOptions.semanticErrors} is enabled. */
|
|
123
140
|
diagnostics: Diagnostic[];
|
|
124
141
|
/**
|
|
@@ -165,9 +182,9 @@ interface BaseNode {
|
|
|
165
182
|
end: number;
|
|
166
183
|
/**
|
|
167
184
|
* Comments attached to this node in source order. Present only when
|
|
168
|
-
* {@link ParseOptions.attachComments} is
|
|
185
|
+
* {@link ParseOptions.attachComments} is true.
|
|
169
186
|
*/
|
|
170
|
-
comments?:
|
|
187
|
+
comments?: AttachedComment[];
|
|
171
188
|
}
|
|
172
189
|
|
|
173
190
|
type Span = BaseNode;
|
|
@@ -605,7 +622,7 @@ interface Directive extends BaseNode {
|
|
|
605
622
|
|
|
606
623
|
interface BlockStatement extends BaseNode {
|
|
607
624
|
type: "BlockStatement";
|
|
608
|
-
body: Statement[];
|
|
625
|
+
body: (Statement | Directive)[];
|
|
609
626
|
}
|
|
610
627
|
|
|
611
628
|
interface IfStatement extends BaseNode {
|
|
@@ -1495,7 +1512,7 @@ interface TSModuleDeclaration extends BaseNode {
|
|
|
1495
1512
|
|
|
1496
1513
|
interface TSModuleBlock extends BaseNode {
|
|
1497
1514
|
type: "TSModuleBlock";
|
|
1498
|
-
body:
|
|
1515
|
+
body: ProgramStatement[];
|
|
1499
1516
|
}
|
|
1500
1517
|
|
|
1501
1518
|
interface TSParameterProperty extends BaseNode {
|
|
@@ -1609,9 +1626,17 @@ interface Program extends BaseNode {
|
|
|
1609
1626
|
type: "Program";
|
|
1610
1627
|
sourceType: ModuleKind;
|
|
1611
1628
|
hashbang: Hashbang | null;
|
|
1612
|
-
body:
|
|
1629
|
+
body: ProgramStatement[];
|
|
1613
1630
|
}
|
|
1614
1631
|
|
|
1632
|
+
/**
|
|
1633
|
+
* An element of `Program.body`. Unlike {@link Statement}, this also includes
|
|
1634
|
+
* {@link ModuleDeclaration} (`import`/`export`) and {@link Directive}, which
|
|
1635
|
+
* are only valid at the top level of a program, never in nested statement
|
|
1636
|
+
* positions such as a block, loop, or `if` body.
|
|
1637
|
+
*/
|
|
1638
|
+
type ProgramStatement = Statement | ModuleDeclaration | Directive;
|
|
1639
|
+
|
|
1615
1640
|
type Declaration =
|
|
1616
1641
|
| FunctionDeclaration
|
|
1617
1642
|
| ClassDeclaration
|
|
@@ -1761,6 +1786,7 @@ export type {
|
|
|
1761
1786
|
ParseOptions,
|
|
1762
1787
|
ParseResult,
|
|
1763
1788
|
Comment,
|
|
1789
|
+
AttachedComment,
|
|
1764
1790
|
CommentType,
|
|
1765
1791
|
CommentPosition,
|
|
1766
1792
|
Diagnostic,
|
|
@@ -1773,6 +1799,7 @@ export type {
|
|
|
1773
1799
|
BaseNode,
|
|
1774
1800
|
Span,
|
|
1775
1801
|
Program,
|
|
1802
|
+
ProgramStatement,
|
|
1776
1803
|
Statement,
|
|
1777
1804
|
Expression,
|
|
1778
1805
|
Declaration,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yuku-parser",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.18",
|
|
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.18",
|
|
21
|
+
"@yuku-parser/binding-linux-arm64-gnu": "0.5.18",
|
|
22
|
+
"@yuku-parser/binding-linux-arm-gnu": "0.5.18",
|
|
23
|
+
"@yuku-parser/binding-linux-x64-musl": "0.5.18",
|
|
24
|
+
"@yuku-parser/binding-linux-arm64-musl": "0.5.18",
|
|
25
|
+
"@yuku-parser/binding-linux-arm-musl": "0.5.18",
|
|
26
|
+
"@yuku-parser/binding-darwin-x64": "0.5.18",
|
|
27
|
+
"@yuku-parser/binding-darwin-arm64": "0.5.18",
|
|
28
|
+
"@yuku-parser/binding-win32-x64": "0.5.18",
|
|
29
|
+
"@yuku-parser/binding-win32-arm64": "0.5.18",
|
|
30
|
+
"@yuku-parser/binding-freebsd-x64": "0.5.18"
|
|
31
31
|
},
|
|
32
32
|
"keywords": [
|
|
33
33
|
"acorn",
|