Skip to content

Commit 2fed560

Browse files
committed
feat(napi/parser): add option to add parent prop to AST nodes with raw transfer
1 parent f4119a6 commit 2fed560

File tree

26 files changed

+38686
-7483
lines changed

26 files changed

+38686
-7483
lines changed

.github/generated/ast_changes_watch_list.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,14 @@ src:
6868
- 'crates/oxc_traverse/src/generated/scopes_collector.rs'
6969
- 'napi/parser/generated/constants.js'
7070
- 'napi/parser/generated/deserialize/js.js'
71+
- 'napi/parser/generated/deserialize/js_parent.js'
7172
- 'napi/parser/generated/deserialize/js_range.js'
73+
- 'napi/parser/generated/deserialize/js_range_parent.js'
7274
- 'napi/parser/generated/deserialize/ts.js'
75+
- 'napi/parser/generated/deserialize/ts_parent.js'
7376
- 'napi/parser/generated/deserialize/ts_range.js'
7477
- 'napi/parser/generated/deserialize/ts_range_no_parens.js'
78+
- 'napi/parser/generated/deserialize/ts_range_parent.js'
7579
- 'napi/parser/generated/lazy/constructors.js'
7680
- 'napi/parser/generated/lazy/types.js'
7781
- 'napi/parser/generated/lazy/walk.js'

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ jobs:
196196
- if: steps.filter.outputs.src == 'true'
197197
name: Run tests in workspace
198198
env:
199-
RUN_RAW_TESTS: "true"
199+
RUN_RAW_RANGE_TESTS: "true"
200200
run: |
201201
rustup target add wasm32-wasip1-threads
202202
pnpm run build-test

crates/oxc_ast/src/serialize/js.rs

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ use super::{EmptyArray, Null};
2020
#[estree(raw_deser = "
2121
const pattern = DESER[BindingPatternKind](POS_OFFSET.kind);
2222
if (IS_TS) {
23+
const previousParent = parent;
24+
parent = pattern;
2325
pattern.optional = DESER[bool](POS_OFFSET.optional);
2426
pattern.typeAnnotation = DESER[Option<Box<TSTypeAnnotation>>](POS_OFFSET.type_annotation);
27+
if (PARENT) parent = previousParent;
2528
}
2629
pattern
2730
")]
@@ -119,22 +122,31 @@ impl ESTree for CatchParameterConverter<'_, '_> {
119122
const params = DESER[Vec<FormalParameter>](POS_OFFSET.items);
120123
if (uint32[(POS_OFFSET.rest) >> 2] !== 0 && uint32[(POS_OFFSET.rest + 4) >> 2] !== 0) {
121124
pos = uint32[(POS_OFFSET.rest) >> 2];
125+
122126
let start, end;
123-
params.push({
127+
const previousParent = parent;
128+
const rest = parent = {
124129
type: 'RestElement',
125130
...(IS_TS && { decorators: [] }),
126-
argument: DESER[BindingPatternKind]( POS_OFFSET<BindingRestElement>.argument.kind ),
131+
argument: null,
127132
...(IS_TS && {
128133
optional: DESER[bool]( POS_OFFSET<BindingRestElement>.argument.optional ),
129-
typeAnnotation: DESER[Option<Box<TSTypeAnnotation>>](
130-
POS_OFFSET<BindingRestElement>.argument.type_annotation
131-
),
134+
typeAnnotation: null,
132135
value: null,
133136
}),
134137
start: start = DESER[u32]( POS_OFFSET<BindingRestElement>.span.start ),
135138
end: end = DESER[u32]( POS_OFFSET<BindingRestElement>.span.end ),
136139
...(RANGE && { range: [start, end] }),
137-
});
140+
...(PARENT && { parent }),
141+
};
142+
rest.argument = DESER[BindingPatternKind]( POS_OFFSET<BindingRestElement>.argument.kind );
143+
if (IS_TS) {
144+
rest.typeAnnotation = DESER[Option<Box<TSTypeAnnotation>>](
145+
POS_OFFSET<BindingRestElement>.argument.type_annotation
146+
);
147+
}
148+
params.push(rest);
149+
if (PARENT) parent = previousParent;
138150
}
139151
params
140152
"
@@ -187,27 +199,32 @@ impl ESTree for FormalParametersRest<'_, '_> {
187199
if (IS_TS) {
188200
const accessibility = DESER[Option<TSAccessibility>](POS_OFFSET.accessibility),
189201
readonly = DESER[bool](POS_OFFSET.readonly),
190-
override = DESER[bool](POS_OFFSET.override);
202+
override = DESER[bool](POS_OFFSET.override),
203+
previousParent = parent;
191204
if (accessibility === null && !readonly && !override) {
192-
param = DESER[BindingPatternKind](POS_OFFSET.pattern.kind);
205+
param = parent = DESER[BindingPatternKind](POS_OFFSET.pattern.kind);
193206
param.decorators = DESER[Vec<Decorator>](POS_OFFSET.decorators);
194207
param.optional = DESER[bool](POS_OFFSET.pattern.optional);
195208
param.typeAnnotation = DESER[Option<Box<TSTypeAnnotation>>](POS_OFFSET.pattern.type_annotation);
196209
} else {
197210
let start, end;
198-
param = {
211+
param = parent = {
199212
type: 'TSParameterProperty',
200213
accessibility,
201-
decorators: DESER[Vec<Decorator>](POS_OFFSET.decorators),
214+
decorators: null,
202215
override,
203-
parameter: DESER[BindingPattern](POS_OFFSET.pattern),
216+
parameter: null,
204217
readonly,
205218
static: false,
206219
start: start = DESER[u32]( POS_OFFSET<BindingRestElement>.span.start ),
207220
end: end = DESER[u32]( POS_OFFSET<BindingRestElement>.span.end ),
208221
...(RANGE && { range: [start, end] }),
222+
...(PARENT && { parent }),
209223
};
224+
param.decorators = DESER[Vec<Decorator>](POS_OFFSET.decorators);
225+
param.parameter = DESER[BindingPattern](POS_OFFSET.pattern);
210226
}
227+
if (PARENT) parent = previousParent;
211228
} else {
212229
param = DESER[BindingPatternKind](POS_OFFSET.pattern.kind);
213230
}
@@ -384,7 +401,11 @@ impl ESTree for ExportAllDeclarationWithClause<'_, '_> {
384401
ts_type = "FunctionBody | Expression",
385402
raw_deser = "
386403
let body = DESER[Box<FunctionBody>](POS_OFFSET.body);
387-
THIS.expression ? body.body[0].expression : body
404+
if (THIS.expression === true) {
405+
body = body.body[0].expression;
406+
if (PARENT) body.parent = parent;
407+
}
408+
body
388409
"
389410
)]
390411
pub struct ArrowFunctionExpressionBody<'a>(pub &'a ArrowFunctionExpression<'a>);
@@ -405,23 +426,31 @@ impl ESTree for ArrowFunctionExpressionBody<'_> {
405426
#[estree(
406427
ts_type = "IdentifierReference | AssignmentTargetWithDefault",
407428
raw_deser = "
408-
const init = DESER[Option<Expression>](POS_OFFSET.init),
409-
keyCopy = { ...THIS.key },
410-
value = init === null
411-
? keyCopy
412-
: {
413-
type: 'AssignmentPattern',
414-
...(IS_TS && { decorators: [] }),
415-
left: keyCopy,
416-
right: init,
417-
...(IS_TS && {
418-
optional: false,
419-
typeAnnotation: null,
420-
}),
421-
start: THIS.start,
422-
end: THIS.end,
423-
...(RANGE && { range: [THIS.start, THIS.end] }),
424-
};
429+
const init = DESER[Option<Expression>](POS_OFFSET.init);
430+
let value = { ...THIS.key };
431+
if (init !== null) {
432+
const left = value;
433+
const previousParent = parent;
434+
value = parent = {
435+
type: 'AssignmentPattern',
436+
...(IS_TS && { decorators: [] }),
437+
left,
438+
right: init,
439+
...(IS_TS && {
440+
optional: false,
441+
typeAnnotation: null,
442+
}),
443+
start: THIS.start,
444+
end: THIS.end,
445+
...(RANGE && { range: [THIS.start, THIS.end] }),
446+
...(PARENT && { parent }),
447+
};
448+
if (PARENT) {
449+
left.parent = value;
450+
init.parent = value;
451+
parent = previousParent;
452+
}
453+
}
425454
value
426455
"
427456
)]
@@ -458,16 +487,22 @@ impl ESTree for AssignmentTargetPropertyIdentifierInit<'_> {
458487
/// ESTree implementation is unchanged from the auto-generated version.
459488
#[ast_meta]
460489
#[estree(raw_deser = "
461-
let node = DESER[Expression](POS_OFFSET.expression);
490+
let node;
462491
if (PRESERVE_PARENS) {
463492
let start, end;
464-
node = {
493+
const previousParent = parent;
494+
node = parent = {
465495
type: 'ParenthesizedExpression',
466-
expression: node,
496+
expression: null,
467497
start: start = DESER[u32]( POS_OFFSET.span.start ),
468498
end: end = DESER[u32]( POS_OFFSET.span.end ),
469499
...(RANGE && { range: [start, end] }),
500+
...(PARENT && { parent }),
470501
};
502+
node.expression = DESER[Expression](POS_OFFSET.expression);
503+
if (PARENT) parent = previousParent;
504+
} else {
505+
node = DESER[Expression](POS_OFFSET.expression);
471506
}
472507
node
473508
")]

crates/oxc_ast/src/serialize/jsx.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl ESTree for JSXOpeningElementSelfClosing<'_, '_> {
5656
ts_type = "JSXIdentifier",
5757
raw_deser = "
5858
const ident = DESER[Box<IdentifierReference>](POS);
59-
{ type: 'JSXIdentifier', name: ident.name, start: ident.start, end: ident.end, ...(RANGE && { range: ident.range }) }
59+
{ type: 'JSXIdentifier', name: ident.name, start: ident.start, end: ident.end, ...(RANGE && { range: ident.range }), ...(PARENT && { parent }) }
6060
"
6161
)]
6262
pub struct JSXElementIdentifierReference<'a, 'b>(pub &'b IdentifierReference<'a>);
@@ -75,7 +75,7 @@ impl ESTree for JSXElementIdentifierReference<'_, '_> {
7575
ts_type = "JSXIdentifier",
7676
raw_deser = "
7777
const thisExpr = DESER[Box<ThisExpression>](POS);
78-
{ type: 'JSXIdentifier', name: 'this', start: thisExpr.start, end: thisExpr.end, ...(RANGE && { range: thisExpr.range }) }
78+
{ type: 'JSXIdentifier', name: 'this', start: thisExpr.start, end: thisExpr.end, ...(RANGE && { range: thisExpr.range }), ...(PARENT && { parent }) }
7979
"
8080
)]
8181
pub struct JSXElementThisExpression<'b>(pub &'b ThisExpression);

crates/oxc_ast/src/serialize/literal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl ESTree for RegExpFlagsConverter<'_> {
202202
value.cooked = value.cooked
203203
.replace(/\uFFFD(.{4})/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16)));
204204
}
205-
{ type: 'TemplateElement', value, tail, start, end, ...(RANGE && { range: [start, end] }) }
205+
{ type: 'TemplateElement', value, tail, start, end, ...(RANGE && { range: [start, end] }), ...(PARENT && { parent }) }
206206
"#)]
207207
pub struct TemplateElementConverter<'a, 'b>(pub &'b TemplateElement<'a>);
208208

crates/oxc_ast/src/serialize/mod.rs

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,27 @@ impl Program<'_> {
121121
/// `Program` span start is 0 (not 5).
122122
#[ast_meta]
123123
#[estree(raw_deser = "
124-
const body = DESER[Vec<Directive>](POS_OFFSET.directives);
125-
body.push(...DESER[Vec<Statement>](POS_OFFSET.body));
124+
const start = IS_TS ? 0 : DESER[u32](POS_OFFSET.span.start),
125+
end = DESER[u32](POS_OFFSET.span.end);
126+
127+
const program = parent = {
128+
type: 'Program',
129+
body: null,
130+
sourceType: DESER[ModuleKind](POS_OFFSET.source_type.module_kind),
131+
hashbang: null,
132+
start,
133+
end,
134+
...(RANGE && { range: [start, end] }),
135+
...(PARENT && { parent: null }),
136+
};
126137
127-
const end = DESER[u32](POS_OFFSET.span.end);
138+
program.hashbang = DESER[Option<Hashbang>](POS_OFFSET.hashbang);
139+
140+
const body = program.body = DESER[Vec<Directive>](POS_OFFSET.directives);
141+
body.push(...DESER[Vec<Statement>](POS_OFFSET.body));
128142
129-
let start;
130143
if (IS_TS) {
144+
let start;
131145
if (body.length > 0) {
132146
const first = body[0];
133147
start = first.start;
@@ -144,19 +158,16 @@ impl Program<'_> {
144158
} else {
145159
start = end;
146160
}
147-
} else {
148-
start = DESER[u32](POS_OFFSET.span.start);
161+
162+
if (RANGE) {
163+
program.start = program.range[0] = start;
164+
} else {
165+
program.start = start;
166+
}
149167
}
150168
151-
const program = {
152-
type: 'Program',
153-
body,
154-
sourceType: DESER[ModuleKind](POS_OFFSET.source_type.module_kind),
155-
hashbang: DESER[Option<Hashbang>](POS_OFFSET.hashbang),
156-
start,
157-
end,
158-
...(RANGE && { range: [start, end] }),
159-
};
169+
if (PARENT) parent = null;
170+
160171
program
161172
")]
162173
pub struct ProgramConverter<'a, 'b>(pub &'b Program<'a>);

0 commit comments

Comments
 (0)