Skip to content

Commit 0c55dd6

Browse files
hi-ogawaoverlookmotel
andauthoredFeb 5, 2025··
fix(ast): serialize Function.params like estree (#8772)
- part of #2854 This PR attempts to handle estree ast incompatibility of `Function.params: FormalParameters` as mentioned in the above issue: > `FormalParameters` is closer to ESTree now, but should be inlined directly into `<node>.params` in multiple nodes. Estree spec has `Function.params: Pattern[]` https://github.com/estree/estree/blob/master/es5.md#functions, but oxc already has `interface Pattern`, so I named it to `Function.params: ParamPattern[]` for now. Also I'm not sure about the testing (I suppose that's a part of #8630), so I snapshoted one example code. For comparison, here is acorn's output https://astexplorer.net/#/gist/25138c0605f82dcfc1a8fd363dc2a681/5ad30d36c9f276519063e6fd2e340c113d8c85b0 --------- Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
1 parent e930cae commit 0c55dd6

File tree

7 files changed

+157
-36
lines changed

7 files changed

+157
-36
lines changed
 

‎crates/oxc_ast/src/ast/js.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,9 @@ pub struct BindingRestElement<'a> {
15521552
)]
15531553
#[derive(Debug)]
15541554
#[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
1555+
// https://github.com/estree/estree/blob/master/es5.md#patterns
1556+
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/cd61c555bfc93e985b313263a42ed78074570d08/types/estree/index.d.ts#L411
1557+
#[estree(add_ts_def = "type ParamPattern = FormalParameter | FormalParameterRest")]
15551558
pub struct Function<'a> {
15561559
pub span: Span,
15571560
pub r#type: FunctionType,
@@ -1590,6 +1593,7 @@ pub struct Function<'a> {
15901593
/// Function parameters.
15911594
///
15921595
/// Does not include `this` parameters used by some TypeScript functions.
1596+
#[estree(ts_type = "ParamPattern[]")]
15931597
pub params: Box<'a, FormalParameters<'a>>,
15941598
/// The TypeScript return type annotation.
15951599
#[ts]
@@ -1651,10 +1655,15 @@ pub struct FormalParameters<'a> {
16511655
#[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
16521656
// Pluralize as `FormalParameterList` to avoid naming clash with `FormalParameters`.
16531657
#[plural(FormalParameterList)]
1658+
#[estree(no_type)]
16541659
pub struct FormalParameter<'a> {
16551660
pub span: Span,
16561661
#[ts]
16571662
pub decorators: Vec<'a, Decorator<'a>>,
1663+
#[estree(
1664+
flatten,
1665+
ts_type = "(BindingIdentifier | ObjectPattern | ArrayPattern | AssignmentPattern)"
1666+
)]
16581667
pub pattern: BindingPattern<'a>,
16591668
#[ts]
16601669
pub accessibility: Option<TSAccessibility>,
@@ -1704,6 +1713,7 @@ pub struct ArrowFunctionExpression<'a> {
17041713
pub r#async: bool,
17051714
#[ts]
17061715
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
1716+
#[estree(ts_type = "ParamPattern[]")]
17071717
pub params: Box<'a, FormalParameters<'a>>,
17081718
#[ts]
17091719
pub return_type: Option<Box<'a, TSTypeAnnotation<'a>>>,

‎crates/oxc_ast/src/ast/ts.rs

+5
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,7 @@ pub struct TSCallSignatureDeclaration<'a> {
973973
pub span: Span,
974974
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
975975
pub this_param: Option<TSThisParameter<'a>>,
976+
#[estree(ts_type = "ParamPattern[]")]
976977
pub params: Box<'a, FormalParameters<'a>>,
977978
pub return_type: Option<Box<'a, TSTypeAnnotation<'a>>>,
978979
}
@@ -1009,6 +1010,7 @@ pub struct TSMethodSignature<'a> {
10091010
pub kind: TSMethodSignatureKind,
10101011
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
10111012
pub this_param: Option<Box<'a, TSThisParameter<'a>>>,
1013+
#[estree(ts_type = "ParamPattern[]")]
10121014
pub params: Box<'a, FormalParameters<'a>>,
10131015
pub return_type: Option<Box<'a, TSTypeAnnotation<'a>>>,
10141016
pub scope_id: Cell<Option<ScopeId>>,
@@ -1022,6 +1024,7 @@ pub struct TSMethodSignature<'a> {
10221024
pub struct TSConstructSignatureDeclaration<'a> {
10231025
pub span: Span,
10241026
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
1027+
#[estree(ts_type = "ParamPattern[]")]
10251028
pub params: Box<'a, FormalParameters<'a>>,
10261029
pub return_type: Option<Box<'a, TSTypeAnnotation<'a>>>,
10271030
pub scope_id: Cell<Option<ScopeId>>,
@@ -1343,6 +1346,7 @@ pub struct TSFunctionType<'a> {
13431346
/// ```
13441347
pub this_param: Option<Box<'a, TSThisParameter<'a>>>,
13451348
/// Function parameters. Akin to [`Function::params`].
1349+
#[estree(ts_type = "ParamPattern[]")]
13461350
pub params: Box<'a, FormalParameters<'a>>,
13471351
/// Return type of the function.
13481352
/// ```ts
@@ -1359,6 +1363,7 @@ pub struct TSConstructorType<'a> {
13591363
pub span: Span,
13601364
pub r#abstract: bool,
13611365
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
1366+
#[estree(ts_type = "ParamPattern[]")]
13621367
pub params: Box<'a, FormalParameters<'a>>,
13631368
pub return_type: Box<'a, TSTypeAnnotation<'a>>,
13641369
}

‎crates/oxc_ast/src/generated/derive_estree.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1355,10 +1355,9 @@ impl Serialize for FunctionType {
13551355
impl Serialize for FormalParameter<'_> {
13561356
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
13571357
let mut map = serializer.serialize_map(None)?;
1358-
map.serialize_entry("type", "FormalParameter")?;
13591358
self.span.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
13601359
map.serialize_entry("decorators", &self.decorators)?;
1361-
map.serialize_entry("pattern", &self.pattern)?;
1360+
self.pattern.serialize(serde::__private::ser::FlatMapSerializer(&mut map))?;
13621361
map.serialize_entry("accessibility", &self.accessibility)?;
13631362
map.serialize_entry("readonly", &self.readonly)?;
13641363
map.serialize_entry("override", &self.r#override)?;

‎crates/oxc_ast/src/serialize.rs

+5-19
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ use oxc_span::{Atom, Span};
1111
use oxc_syntax::number::BigintBase;
1212

1313
use crate::ast::{
14-
BigIntLiteral, BindingPatternKind, BooleanLiteral, Directive, Elision, FormalParameter,
15-
FormalParameterKind, FormalParameters, JSXElementName, JSXIdentifier,
16-
JSXMemberExpressionObject, NullLiteral, NumericLiteral, Program, RegExpFlags, RegExpLiteral,
17-
RegExpPattern, Statement, StringLiteral, TSModuleBlock, TSTypeAnnotation,
14+
BigIntLiteral, BindingPatternKind, BooleanLiteral, Directive, Elision, FormalParameters,
15+
JSXElementName, JSXIdentifier, JSXMemberExpressionObject, NullLiteral, NumericLiteral, Program,
16+
RegExpFlags, RegExpLiteral, RegExpPattern, Statement, StringLiteral, TSModuleBlock,
17+
TSTypeAnnotation,
1818
};
1919

2020
#[derive(Serialize)]
@@ -187,24 +187,10 @@ impl Serialize for FormalParameters<'_> {
187187
type_annotation: &rest.argument.type_annotation,
188188
optional: rest.argument.optional,
189189
});
190-
let converted = SerFormalParameters {
191-
span: self.span,
192-
kind: self.kind,
193-
items: ElementsAndRest::new(&self.items, converted_rest.as_ref()),
194-
};
195-
converted.serialize(serializer)
190+
ElementsAndRest::new(&self.items, converted_rest.as_ref()).serialize(serializer)
196191
}
197192
}
198193

199-
#[derive(Serialize)]
200-
#[serde(tag = "type", rename = "FormalParameters")]
201-
struct SerFormalParameters<'a, 'b> {
202-
#[serde(flatten)]
203-
span: Span,
204-
kind: FormalParameterKind,
205-
items: ElementsAndRest<'b, FormalParameter<'a>, SerFormalParameterRest<'a, 'b>>,
206-
}
207-
208194
#[derive(Serialize)]
209195
#[serde(tag = "type", rename = "RestElement", rename_all = "camelCase")]
210196
struct SerFormalParameterRest<'a, 'b> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`parse > estree function params 1`] = `
4+
{
5+
"async": true,
6+
"body": {
7+
"directives": [],
8+
"end": 48,
9+
"start": 46,
10+
"statements": [],
11+
"type": "FunctionBody",
12+
},
13+
"declare": false,
14+
"end": 48,
15+
"generator": false,
16+
"id": {
17+
"end": 19,
18+
"name": "test",
19+
"start": 15,
20+
"type": "Identifier",
21+
},
22+
"params": [
23+
{
24+
"accessibility": null,
25+
"decorators": [],
26+
"end": 21,
27+
"name": "x",
28+
"optional": false,
29+
"override": false,
30+
"readonly": false,
31+
"start": 20,
32+
"type": "Identifier",
33+
"typeAnnotation": null,
34+
},
35+
{
36+
"accessibility": null,
37+
"decorators": [],
38+
"end": 28,
39+
"optional": false,
40+
"override": false,
41+
"properties": [
42+
{
43+
"computed": false,
44+
"end": 26,
45+
"key": {
46+
"end": 26,
47+
"name": "y",
48+
"start": 25,
49+
"type": "Identifier",
50+
},
51+
"shorthand": true,
52+
"start": 25,
53+
"type": "BindingProperty",
54+
"value": {
55+
"end": 26,
56+
"name": "y",
57+
"optional": false,
58+
"start": 25,
59+
"type": "Identifier",
60+
"typeAnnotation": null,
61+
},
62+
},
63+
],
64+
"readonly": false,
65+
"start": 23,
66+
"type": "ObjectPattern",
67+
"typeAnnotation": null,
68+
},
69+
{
70+
"accessibility": null,
71+
"decorators": [],
72+
"elements": [
73+
{
74+
"end": 33,
75+
"name": "z",
76+
"optional": false,
77+
"start": 32,
78+
"type": "Identifier",
79+
"typeAnnotation": null,
80+
},
81+
],
82+
"end": 35,
83+
"optional": false,
84+
"override": false,
85+
"readonly": false,
86+
"start": 30,
87+
"type": "ArrayPattern",
88+
"typeAnnotation": null,
89+
},
90+
{
91+
"argument": {
92+
"end": 44,
93+
"name": "rest",
94+
"start": 40,
95+
"type": "Identifier",
96+
},
97+
"end": 44,
98+
"optional": false,
99+
"start": 37,
100+
"type": "RestElement",
101+
"typeAnnotation": null,
102+
},
103+
],
104+
"returnType": null,
105+
"start": 0,
106+
"thisParam": null,
107+
"type": "FunctionDeclaration",
108+
"typeParameters": null,
109+
}
110+
`;

‎napi/parser/test/parse.test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ describe('parse', () => {
2626
});
2727
expect(code.substring(comment.start, comment.end)).toBe('/*' + comment.value + '*/');
2828
});
29+
30+
it('estree function params', async () => {
31+
const ret = await parseAsync(
32+
'test.js',
33+
`async function test(x, { y }, [ z ], ...rest) {}`,
34+
);
35+
expect(ret.program.body[0]).matchSnapshot();
36+
});
2937
});
3038

3139
describe('error', () => {

‎npm/oxc-types/types.d.ts

+18-15
Original file line numberDiff line numberDiff line change
@@ -718,11 +718,13 @@ export interface Function extends Span {
718718
declare: boolean;
719719
typeParameters: TSTypeParameterDeclaration | null;
720720
thisParam: TSThisParameter | null;
721-
params: FormalParameters;
721+
params: ParamPattern[];
722722
returnType: TSTypeAnnotation | null;
723723
body: FunctionBody | null;
724724
}
725725

726+
export type ParamPattern = FormalParameter | FormalParameterRest;
727+
726728
export type FunctionType =
727729
| 'FunctionDeclaration'
728730
| 'FunctionExpression'
@@ -742,14 +744,15 @@ export interface FormalParameterRest extends Span {
742744
optional: boolean;
743745
}
744746

745-
export interface FormalParameter extends Span {
746-
type: 'FormalParameter';
747-
decorators: Array<Decorator>;
748-
pattern: BindingPattern;
749-
accessibility: TSAccessibility | null;
750-
readonly: boolean;
751-
override: boolean;
752-
}
747+
export type FormalParameter =
748+
& ({
749+
decorators: Array<Decorator>;
750+
accessibility: TSAccessibility | null;
751+
readonly: boolean;
752+
override: boolean;
753+
})
754+
& Span
755+
& (BindingIdentifier | ObjectPattern | ArrayPattern | AssignmentPattern);
753756

754757
export type FormalParameterKind = 'FormalParameter' | 'UniqueFormalParameters' | 'ArrowFormalParameters' | 'Signature';
755758

@@ -764,7 +767,7 @@ export interface ArrowFunctionExpression extends Span {
764767
expression: boolean;
765768
async: boolean;
766769
typeParameters: TSTypeParameterDeclaration | null;
767-
params: FormalParameters;
770+
params: ParamPattern[];
768771
returnType: TSTypeAnnotation | null;
769772
body: FunctionBody;
770773
}
@@ -1532,7 +1535,7 @@ export interface TSCallSignatureDeclaration extends Span {
15321535
type: 'TSCallSignatureDeclaration';
15331536
typeParameters: TSTypeParameterDeclaration | null;
15341537
thisParam: TSThisParameter | null;
1535-
params: FormalParameters;
1538+
params: ParamPattern[];
15361539
returnType: TSTypeAnnotation | null;
15371540
}
15381541

@@ -1546,14 +1549,14 @@ export interface TSMethodSignature extends Span {
15461549
kind: TSMethodSignatureKind;
15471550
typeParameters: TSTypeParameterDeclaration | null;
15481551
thisParam: TSThisParameter | null;
1549-
params: FormalParameters;
1552+
params: ParamPattern[];
15501553
returnType: TSTypeAnnotation | null;
15511554
}
15521555

15531556
export interface TSConstructSignatureDeclaration extends Span {
15541557
type: 'TSConstructSignatureDeclaration';
15551558
typeParameters: TSTypeParameterDeclaration | null;
1556-
params: FormalParameters;
1559+
params: ParamPattern[];
15571560
returnType: TSTypeAnnotation | null;
15581561
}
15591562

@@ -1642,15 +1645,15 @@ export interface TSFunctionType extends Span {
16421645
type: 'TSFunctionType';
16431646
typeParameters: TSTypeParameterDeclaration | null;
16441647
thisParam: TSThisParameter | null;
1645-
params: FormalParameters;
1648+
params: ParamPattern[];
16461649
returnType: TSTypeAnnotation;
16471650
}
16481651

16491652
export interface TSConstructorType extends Span {
16501653
type: 'TSConstructorType';
16511654
abstract: boolean;
16521655
typeParameters: TSTypeParameterDeclaration | null;
1653-
params: FormalParameters;
1656+
params: ParamPattern[];
16541657
returnType: TSTypeAnnotation;
16551658
}
16561659

0 commit comments

Comments
 (0)
Please sign in to comment.