From 974871c4d8b2e3d13bd902a050bcdd157be6c5e2 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 11 Mar 2025 13:06:41 +0900 Subject: [PATCH 1/4] fix(ast/estree): fix TSImportType --- crates/oxc_ast/src/ast/ts.rs | 7 ++ crates/oxc_ast/src/generated/derive_estree.rs | 16 ++-- crates/oxc_ast/src/serialize.rs | 80 +++++++++++++++++++ napi/parser/deserialize-js.js | 43 +++++++--- napi/parser/deserialize-ts.js | 43 +++++++--- npm/oxc-types/types.d.ts | 16 ++-- 6 files changed, 169 insertions(+), 36 deletions(-) diff --git a/crates/oxc_ast/src/ast/ts.rs b/crates/oxc_ast/src/ast/ts.rs index 940f8de2902a6..b74731d775843 100644 --- a/crates/oxc_ast/src/ast/ts.rs +++ b/crates/oxc_ast/src/ast/ts.rs @@ -1289,6 +1289,7 @@ pub struct TSImportType<'a> { #[ast(visit)] #[derive(Debug)] #[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)] +#[estree(via = TSImportAttributesConverter)] pub struct TSImportAttributes<'a> { pub span: Span, pub attributes_keyword: IdentifierName<'a>, // `with` or `assert` @@ -1300,8 +1301,14 @@ pub struct TSImportAttributes<'a> { #[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)] // Pluralize as `TSImportAttributeList` to avoid naming clash with `TSImportAttributes`. #[plural(TSImportAttributeList)] +#[estree( + rename = "Property", + add_fields(method = False, shorthand = True, computed = False, kind = Init), + field_order(span, method, shorthand, computed, name, value, kind), +)] pub struct TSImportAttribute<'a> { pub span: Span, + #[estree(rename = "key")] pub name: TSImportAttributeName<'a>, pub value: Expression<'a>, } diff --git a/crates/oxc_ast/src/generated/derive_estree.rs b/crates/oxc_ast/src/generated/derive_estree.rs index 3393dc7f31dec..a3650e77b1b73 100644 --- a/crates/oxc_ast/src/generated/derive_estree.rs +++ b/crates/oxc_ast/src/generated/derive_estree.rs @@ -3102,24 +3102,22 @@ impl ESTree for TSImportType<'_> { impl ESTree for TSImportAttributes<'_> { fn serialize(&self, serializer: S) { - let mut state = serializer.serialize_struct(); - state.serialize_field("type", &JsonSafeString("TSImportAttributes")); - state.serialize_field("start", &self.span.start); - state.serialize_field("end", &self.span.end); - state.serialize_field("attributesKeyword", &self.attributes_keyword); - state.serialize_field("elements", &self.elements); - state.end(); + crate::serialize::TSImportAttributesConverter(self).serialize(serializer) } } impl ESTree for TSImportAttribute<'_> { fn serialize(&self, serializer: S) { let mut state = serializer.serialize_struct(); - state.serialize_field("type", &JsonSafeString("TSImportAttribute")); + state.serialize_field("type", &JsonSafeString("Property")); state.serialize_field("start", &self.span.start); state.serialize_field("end", &self.span.end); - state.serialize_field("name", &self.name); + state.serialize_field("method", &crate::serialize::False(self)); + state.serialize_field("shorthand", &crate::serialize::True(self)); + state.serialize_field("computed", &crate::serialize::False(self)); + state.serialize_field("key", &self.name); state.serialize_field("value", &self.value); + state.serialize_field("kind", &crate::serialize::Init(self)); state.end(); } } diff --git a/crates/oxc_ast/src/serialize.rs b/crates/oxc_ast/src/serialize.rs index 38aab4d1b42fe..f38cdf2b473d5 100644 --- a/crates/oxc_ast/src/serialize.rs +++ b/crates/oxc_ast/src/serialize.rs @@ -505,6 +505,86 @@ impl ESTree for ExportAllDeclarationWithClause<'_, '_> { } } +#[ast_meta] +#[estree( + ts_type = "ObjectExpression", + raw_deser = " + const start = DESER[u32](POS_OFFSET.span.start); + const end = DESER[u32](POS_OFFSET.span.end); + const attributesKeyword = DESER[IdentifierName](POS_OFFSET.attributes_keyword); + const properties = DESER[Vec](POS_OFFSET.elements); + const result = { + type: 'ObjectExpression', + start, + end, + properties: [ + { + type: 'Property', + start, + end, + method: false, + shorthand: false, + computed: false, + key: attributesKeyword, + value: { + type: 'ObjectExpression', + start, + end, + properties, + }, + kind: 'init', + }, + ], + }; + result + " +)] +pub struct TSImportAttributesConverter<'a, 'b>(pub &'b TSImportAttributes<'a>); + +impl ESTree for TSImportAttributesConverter<'_, '_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("type", &JsonSafeString("ObjectExpression")); + state.serialize_field("start", &self.0.span.start); + state.serialize_field("end", &self.0.span.end); + state.serialize_field("properties", &[TSImportAttributesWithClauseConverter(self.0)]); + state.end(); + } +} + +struct TSImportAttributesWithClauseConverter<'a, 'b>(&'b TSImportAttributes<'a>); + +impl ESTree for TSImportAttributesWithClauseConverter<'_, '_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("type", &JsonSafeString("Property")); + // TODO: span + state.serialize_field("start", &self.0.span.end); + state.serialize_field("end", &self.0.span.end); + state.serialize_field("method", &false); + state.serialize_field("shorthand", &false); + state.serialize_field("computed", &false); + state.serialize_field("key", &self.0.attributes_keyword); + state.serialize_field("value", &TSImportAttributesElementsConverter(self.0)); + state.serialize_field("kind", &"init"); + state.end(); + } +} + +struct TSImportAttributesElementsConverter<'a, 'b>(&'b TSImportAttributes<'a>); + +impl ESTree for TSImportAttributesElementsConverter<'_, '_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("type", &JsonSafeString("ObjectExpression")); + // TODO: span + state.serialize_field("start", &self.0.span.start); + state.serialize_field("end", &self.0.span.end); + state.serialize_field("properties", &self.0.elements); + state.end(); + } +} + // -------------------- // JSX // -------------------- diff --git a/napi/parser/deserialize-js.js b/napi/parser/deserialize-js.js index 069db022e954b..0c9be74b60a40 100644 --- a/napi/parser/deserialize-js.js +++ b/napi/parser/deserialize-js.js @@ -1780,22 +1780,47 @@ function deserializeTSImportType(pos) { } function deserializeTSImportAttributes(pos) { - return { - type: 'TSImportAttributes', - start: deserializeU32(pos), - end: deserializeU32(pos + 4), - attributesKeyword: deserializeIdentifierName(pos + 8), - elements: deserializeVecTSImportAttribute(pos + 32), - }; + const start = deserializeU32(pos); + const end = deserializeU32(pos + 4); + const attributesKeyword = deserializeIdentifierName(pos + 8); + const properties = deserializeVecTSImportAttribute(pos + 32); + const result = { + type: 'ObjectExpression', + start, + end, + properties: [ + { + type: 'Property', + start, + end, + method: false, + shorthand: false, + computed: false, + key: attributesKeyword, + value: { + type: 'ObjectExpression', + start, + end, + properties, + }, + kind: 'init', + }, + ], + }; + return result; } function deserializeTSImportAttribute(pos) { return { - type: 'TSImportAttribute', + type: 'Property', start: deserializeU32(pos), end: deserializeU32(pos + 4), - name: deserializeTSImportAttributeName(pos + 8), + method: false, + shorthand: true, + computed: false, + key: deserializeTSImportAttributeName(pos + 8), value: deserializeExpression(pos + 56), + kind: 'init', }; } diff --git a/napi/parser/deserialize-ts.js b/napi/parser/deserialize-ts.js index 18fbff6891e57..bfffdcf15a4f3 100644 --- a/napi/parser/deserialize-ts.js +++ b/napi/parser/deserialize-ts.js @@ -1833,22 +1833,47 @@ function deserializeTSImportType(pos) { } function deserializeTSImportAttributes(pos) { - return { - type: 'TSImportAttributes', - start: deserializeU32(pos), - end: deserializeU32(pos + 4), - attributesKeyword: deserializeIdentifierName(pos + 8), - elements: deserializeVecTSImportAttribute(pos + 32), - }; + const start = deserializeU32(pos); + const end = deserializeU32(pos + 4); + const attributesKeyword = deserializeIdentifierName(pos + 8); + const properties = deserializeVecTSImportAttribute(pos + 32); + const result = { + type: 'ObjectExpression', + start, + end, + properties: [ + { + type: 'Property', + start, + end, + method: false, + shorthand: false, + computed: false, + key: attributesKeyword, + value: { + type: 'ObjectExpression', + start, + end, + properties, + }, + kind: 'init', + }, + ], + }; + return result; } function deserializeTSImportAttribute(pos) { return { - type: 'TSImportAttribute', + type: 'Property', start: deserializeU32(pos), end: deserializeU32(pos + 4), - name: deserializeTSImportAttributeName(pos + 8), + method: false, + shorthand: true, + computed: false, + key: deserializeTSImportAttributeName(pos + 8), value: deserializeExpression(pos + 56), + kind: 'init', }; } diff --git a/npm/oxc-types/types.d.ts b/npm/oxc-types/types.d.ts index ca2db41313217..ac0125c66d0dc 100644 --- a/npm/oxc-types/types.d.ts +++ b/npm/oxc-types/types.d.ts @@ -1282,22 +1282,20 @@ export type TSTypeQueryExprName = TSImportType | TSTypeName; export interface TSImportType extends Span { type: 'TSImportType'; argument: TSType; - options: TSImportAttributes | null; + options: ObjectExpression | null; qualifier: TSTypeName | null; typeArguments: TSTypeParameterInstantiation | null; isTypeOf: boolean; } -export interface TSImportAttributes extends Span { - type: 'TSImportAttributes'; - attributesKeyword: IdentifierName; - elements: Array; -} - export interface TSImportAttribute extends Span { - type: 'TSImportAttribute'; - name: TSImportAttributeName; + type: 'Property'; + method: false; + shorthand: true; + computed: false; + key: TSImportAttributeName; value: Expression; + kind: 'init'; } export type TSImportAttributeName = IdentifierName | StringLiteral; From 7c420fa718c60216c5c77197b0fe9c4499c773b0 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 13 Mar 2025 11:50:48 +0900 Subject: [PATCH 2/4] chore: just ast --- npm/oxc-types/types.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/npm/oxc-types/types.d.ts b/npm/oxc-types/types.d.ts index ac0125c66d0dc..ba5bd820679ce 100644 --- a/npm/oxc-types/types.d.ts +++ b/npm/oxc-types/types.d.ts @@ -1787,7 +1787,6 @@ export type Node = | TSInferType | TSTypeQuery | TSImportType - | TSImportAttributes | TSImportAttribute | TSFunctionType | TSConstructorType From 583795a652e65158a0554ccc5165d61acbcee3e6 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 13 Mar 2025 11:53:03 +0900 Subject: [PATCH 3/4] wip: ts_no_def for TSImportAttributes and TSImportAttributeName --- crates/oxc_ast/src/ast/ts.rs | 2 ++ npm/oxc-types/types.d.ts | 13 ------------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/crates/oxc_ast/src/ast/ts.rs b/crates/oxc_ast/src/ast/ts.rs index b74731d775843..5fcde90f4c25b 100644 --- a/crates/oxc_ast/src/ast/ts.rs +++ b/crates/oxc_ast/src/ast/ts.rs @@ -1302,6 +1302,7 @@ pub struct TSImportAttributes<'a> { // Pluralize as `TSImportAttributeList` to avoid naming clash with `TSImportAttributes`. #[plural(TSImportAttributeList)] #[estree( + no_ts_def, rename = "Property", add_fields(method = False, shorthand = True, computed = False, kind = Init), field_order(span, method, shorthand, computed, name, value, kind), @@ -1316,6 +1317,7 @@ pub struct TSImportAttribute<'a> { #[ast(visit)] #[derive(Debug)] #[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)] +#[estree(no_ts_def)] pub enum TSImportAttributeName<'a> { Identifier(IdentifierName<'a>) = 0, StringLiteral(StringLiteral<'a>) = 1, diff --git a/npm/oxc-types/types.d.ts b/npm/oxc-types/types.d.ts index ba5bd820679ce..cade0c68637f0 100644 --- a/npm/oxc-types/types.d.ts +++ b/npm/oxc-types/types.d.ts @@ -1288,18 +1288,6 @@ export interface TSImportType extends Span { isTypeOf: boolean; } -export interface TSImportAttribute extends Span { - type: 'Property'; - method: false; - shorthand: true; - computed: false; - key: TSImportAttributeName; - value: Expression; - kind: 'init'; -} - -export type TSImportAttributeName = IdentifierName | StringLiteral; - export interface TSFunctionType extends Span { type: 'TSFunctionType'; typeParameters: TSTypeParameterDeclaration | null; @@ -1787,7 +1775,6 @@ export type Node = | TSInferType | TSTypeQuery | TSImportType - | TSImportAttribute | TSFunctionType | TSConstructorType | TSMappedType From 6d43aad2761ad3a3b185a363e53e5b445e9bf13f Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 13 Mar 2025 12:20:18 +0900 Subject: [PATCH 4/4] wip: move `via` from struct to field --- crates/oxc_ast/src/ast/ts.rs | 4 +- crates/oxc_ast/src/generated/derive_estree.rs | 7 ++- crates/oxc_ast/src/serialize.rs | 63 ++++++++----------- napi/parser/deserialize-js.js | 40 ++++++------ napi/parser/deserialize-ts.js | 40 ++++++------ 5 files changed, 75 insertions(+), 79 deletions(-) diff --git a/crates/oxc_ast/src/ast/ts.rs b/crates/oxc_ast/src/ast/ts.rs index 5fcde90f4c25b..657221d9b6d91 100644 --- a/crates/oxc_ast/src/ast/ts.rs +++ b/crates/oxc_ast/src/ast/ts.rs @@ -1289,10 +1289,12 @@ pub struct TSImportType<'a> { #[ast(visit)] #[derive(Debug)] #[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)] -#[estree(via = TSImportAttributesConverter)] +#[estree(ts_alias = "ObjectExpression")] pub struct TSImportAttributes<'a> { pub span: Span, + #[estree(skip)] pub attributes_keyword: IdentifierName<'a>, // `with` or `assert` + #[estree(rename = "properties", via = TSImportAttributesProperties)] pub elements: Vec<'a, TSImportAttribute<'a>>, } diff --git a/crates/oxc_ast/src/generated/derive_estree.rs b/crates/oxc_ast/src/generated/derive_estree.rs index a3650e77b1b73..03dc369246bcb 100644 --- a/crates/oxc_ast/src/generated/derive_estree.rs +++ b/crates/oxc_ast/src/generated/derive_estree.rs @@ -3102,7 +3102,12 @@ impl ESTree for TSImportType<'_> { impl ESTree for TSImportAttributes<'_> { fn serialize(&self, serializer: S) { - crate::serialize::TSImportAttributesConverter(self).serialize(serializer) + let mut state = serializer.serialize_struct(); + state.serialize_field("type", &JsonSafeString("TSImportAttributes")); + state.serialize_field("start", &self.span.start); + state.serialize_field("end", &self.span.end); + state.serialize_field("properties", &crate::serialize::TSImportAttributesProperties(self)); + state.end(); } } diff --git a/crates/oxc_ast/src/serialize.rs b/crates/oxc_ast/src/serialize.rs index f38cdf2b473d5..dcfa56427dc7a 100644 --- a/crates/oxc_ast/src/serialize.rs +++ b/crates/oxc_ast/src/serialize.rs @@ -506,55 +506,44 @@ impl ESTree for ExportAllDeclarationWithClause<'_, '_> { } #[ast_meta] -#[estree( - ts_type = "ObjectExpression", - raw_deser = " +#[estree(raw_deser = " const start = DESER[u32](POS_OFFSET.span.start); const end = DESER[u32](POS_OFFSET.span.end); const attributesKeyword = DESER[IdentifierName](POS_OFFSET.attributes_keyword); const properties = DESER[Vec](POS_OFFSET.elements); - const result = { - type: 'ObjectExpression', - start, - end, - properties: [ - { - type: 'Property', + const result = [ + { + type: 'Property', + start, + end, + method: false, + shorthand: false, + computed: false, + key: attributesKeyword, + value: { + type: 'ObjectExpression', start, end, - method: false, - shorthand: false, - computed: false, - key: attributesKeyword, - value: { - type: 'ObjectExpression', - start, - end, - properties, - }, - kind: 'init', + properties, }, - ], - }; + kind: 'init', + }, + ]; result - " -)] -pub struct TSImportAttributesConverter<'a, 'b>(pub &'b TSImportAttributes<'a>); + ")] +pub struct TSImportAttributesProperties<'a, 'b>(pub &'b TSImportAttributes<'a>); -impl ESTree for TSImportAttributesConverter<'_, '_> { +impl ESTree for TSImportAttributesProperties<'_, '_> { fn serialize(&self, serializer: S) { - let mut state = serializer.serialize_struct(); - state.serialize_field("type", &JsonSafeString("ObjectExpression")); - state.serialize_field("start", &self.0.span.start); - state.serialize_field("end", &self.0.span.end); - state.serialize_field("properties", &[TSImportAttributesWithClauseConverter(self.0)]); + let mut state = serializer.serialize_sequence(); + state.serialize_element(&TSImportAttributesPropertiesWithProperty(self.0)); state.end(); } } -struct TSImportAttributesWithClauseConverter<'a, 'b>(&'b TSImportAttributes<'a>); +pub struct TSImportAttributesPropertiesWithProperty<'a, 'b>(pub &'b TSImportAttributes<'a>); -impl ESTree for TSImportAttributesWithClauseConverter<'_, '_> { +impl ESTree for TSImportAttributesPropertiesWithProperty<'_, '_> { fn serialize(&self, serializer: S) { let mut state = serializer.serialize_struct(); state.serialize_field("type", &JsonSafeString("Property")); @@ -565,15 +554,15 @@ impl ESTree for TSImportAttributesWithClauseConverter<'_, '_> { state.serialize_field("shorthand", &false); state.serialize_field("computed", &false); state.serialize_field("key", &self.0.attributes_keyword); - state.serialize_field("value", &TSImportAttributesElementsConverter(self.0)); + state.serialize_field("value", &TSImportAttributesPropertiesWithPropertyValue(self.0)); state.serialize_field("kind", &"init"); state.end(); } } -struct TSImportAttributesElementsConverter<'a, 'b>(&'b TSImportAttributes<'a>); +struct TSImportAttributesPropertiesWithPropertyValue<'a, 'b>(&'b TSImportAttributes<'a>); -impl ESTree for TSImportAttributesElementsConverter<'_, '_> { +impl ESTree for TSImportAttributesPropertiesWithPropertyValue<'_, '_> { fn serialize(&self, serializer: S) { let mut state = serializer.serialize_struct(); state.serialize_field("type", &JsonSafeString("ObjectExpression")); diff --git a/napi/parser/deserialize-js.js b/napi/parser/deserialize-js.js index 0c9be74b60a40..467ef43b0fbbf 100644 --- a/napi/parser/deserialize-js.js +++ b/napi/parser/deserialize-js.js @@ -1784,30 +1784,30 @@ function deserializeTSImportAttributes(pos) { const end = deserializeU32(pos + 4); const attributesKeyword = deserializeIdentifierName(pos + 8); const properties = deserializeVecTSImportAttribute(pos + 32); - const result = { - type: 'ObjectExpression', - start, - end, - properties: [ - { - type: 'Property', + const result = [ + { + type: 'Property', + start, + end, + method: false, + shorthand: false, + computed: false, + key: attributesKeyword, + value: { + type: 'ObjectExpression', start, end, - method: false, - shorthand: false, - computed: false, - key: attributesKeyword, - value: { - type: 'ObjectExpression', - start, - end, - properties, - }, - kind: 'init', + properties, }, - ], + kind: 'init', + }, + ]; + return { + type: 'TSImportAttributes', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + properties: result, }; - return result; } function deserializeTSImportAttribute(pos) { diff --git a/napi/parser/deserialize-ts.js b/napi/parser/deserialize-ts.js index bfffdcf15a4f3..e323c51e5bd6d 100644 --- a/napi/parser/deserialize-ts.js +++ b/napi/parser/deserialize-ts.js @@ -1837,30 +1837,30 @@ function deserializeTSImportAttributes(pos) { const end = deserializeU32(pos + 4); const attributesKeyword = deserializeIdentifierName(pos + 8); const properties = deserializeVecTSImportAttribute(pos + 32); - const result = { - type: 'ObjectExpression', - start, - end, - properties: [ - { - type: 'Property', + const result = [ + { + type: 'Property', + start, + end, + method: false, + shorthand: false, + computed: false, + key: attributesKeyword, + value: { + type: 'ObjectExpression', start, end, - method: false, - shorthand: false, - computed: false, - key: attributesKeyword, - value: { - type: 'ObjectExpression', - start, - end, - properties, - }, - kind: 'init', + properties, }, - ], + kind: 'init', + }, + ]; + return { + type: 'TSImportAttributes', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + properties: result, }; - return result; } function deserializeTSImportAttribute(pos) {