From a26fd3430a89a4c87b4c9dfd9a8233192aaa8a54 Mon Sep 17 00:00:00 2001 From: overlookmotel <557937+overlookmotel@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:27:19 +0000 Subject: [PATCH] refactor(ast)!: remove `JSXOpeningElement::self_closing` field (#10275) Remove `self_closing` field from `JSXOpeningElement`. Whether the tag is self-closing can be determined by whether the `JSXElement` has a `closing_element` or not. This is advantageous for 2 reasons: 1. Reduce size of `JSXOpeningElement` by 8 bytes. 2. Make it impossible for `self_closing` and `closing_element` fields to get out of sync. Only one source of truth. --- crates/oxc_ast/src/ast/jsx.rs | 20 ++++---- .../oxc_ast/src/generated/assert_layouts.rs | 18 ++++---- crates/oxc_ast/src/generated/ast_builder.rs | 27 +++++------ .../oxc_ast/src/generated/derive_clone_in.rs | 2 - .../src/generated/derive_content_eq.rs | 3 +- crates/oxc_ast/src/generated/derive_dummy.rs | 3 +- crates/oxc_ast/src/generated/derive_estree.rs | 4 +- crates/oxc_ast/src/serialize.rs | 46 +++++++++++++++++++ crates/oxc_codegen/src/gen.rs | 35 ++++++-------- .../src/rules/react/self_closing_comp.rs | 2 +- crates/oxc_parser/src/jsx/mod.rs | 18 ++++---- crates/oxc_traverse/src/generated/ancestor.rs | 23 ---------- napi/parser/deserialize-js.js | 13 ++++-- napi/parser/deserialize-ts.js | 15 +++--- 14 files changed, 121 insertions(+), 108 deletions(-) diff --git a/crates/oxc_ast/src/ast/jsx.rs b/crates/oxc_ast/src/ast/jsx.rs index f3f8f278c7a53..77eca967043ba 100644 --- a/crates/oxc_ast/src/ast/jsx.rs +++ b/crates/oxc_ast/src/ast/jsx.rs @@ -37,10 +37,13 @@ pub struct JSXElement<'a> { /// Node location in source code pub span: Span, /// Opening tag of the element. + #[estree(via = JSXElementOpening)] pub opening_element: Box<'a, JSXOpeningElement<'a>>, - /// Closing tag of the element. Will be [`None`] for self-closing tags. + /// Closing tag of the element. + /// [`None`] for self-closing tags. pub closing_element: Option>>, - /// Children of the element. This can be text, other elements, or expressions. + /// Children of the element. + /// This can be text, other elements, or expressions. pub children: Vec<'a, JSXChild<'a>>, } @@ -62,18 +65,13 @@ pub struct JSXElement<'a> { #[ast(visit)] #[derive(Debug)] #[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree)] -#[estree(field_order(span, attributes, name, self_closing, type_arguments))] +#[estree( + add_fields(selfClosing = JSXOpeningElementSelfClosing), + field_order(span, attributes, name, selfClosing, type_arguments), +)] pub struct JSXOpeningElement<'a> { /// Node location in source code pub span: Span, - /// Is this tag self-closing? - /// - /// ## Examples - /// ```tsx - /// // <- self_closing = true - /// // <- self_closing = false - /// ``` - pub self_closing: bool, /// The possibly-namespaced tag name, e.g. `Foo` in ``. pub name: JSXElementName<'a>, /// List of JSX attributes. In React-like applications, these become props. diff --git a/crates/oxc_ast/src/generated/assert_layouts.rs b/crates/oxc_ast/src/generated/assert_layouts.rs index 7ba5e76b6ebeb..52bc4cd3d761c 100644 --- a/crates/oxc_ast/src/generated/assert_layouts.rs +++ b/crates/oxc_ast/src/generated/assert_layouts.rs @@ -809,13 +809,12 @@ const _: () = { assert!(offset_of!(JSXElement, closing_element) == 16); assert!(offset_of!(JSXElement, children) == 24); - assert!(size_of::() == 72); + assert!(size_of::() == 64); assert!(align_of::() == 8); assert!(offset_of!(JSXOpeningElement, span) == 0); - assert!(offset_of!(JSXOpeningElement, self_closing) == 8); - assert!(offset_of!(JSXOpeningElement, name) == 16); - assert!(offset_of!(JSXOpeningElement, attributes) == 32); - assert!(offset_of!(JSXOpeningElement, type_arguments) == 64); + assert!(offset_of!(JSXOpeningElement, name) == 8); + assert!(offset_of!(JSXOpeningElement, attributes) == 24); + assert!(offset_of!(JSXOpeningElement, type_arguments) == 56); assert!(size_of::() == 24); assert!(align_of::() == 8); @@ -2201,13 +2200,12 @@ const _: () = { assert!(offset_of!(JSXElement, closing_element) == 12); assert!(offset_of!(JSXElement, children) == 16); - assert!(size_of::() == 40); + assert!(size_of::() == 36); assert!(align_of::() == 4); assert!(offset_of!(JSXOpeningElement, span) == 0); - assert!(offset_of!(JSXOpeningElement, self_closing) == 8); - assert!(offset_of!(JSXOpeningElement, name) == 12); - assert!(offset_of!(JSXOpeningElement, attributes) == 20); - assert!(offset_of!(JSXOpeningElement, type_arguments) == 36); + assert!(offset_of!(JSXOpeningElement, name) == 8); + assert!(offset_of!(JSXOpeningElement, attributes) == 16); + assert!(offset_of!(JSXOpeningElement, type_arguments) == 32); assert!(size_of::() == 16); assert!(align_of::() == 4); diff --git a/crates/oxc_ast/src/generated/ast_builder.rs b/crates/oxc_ast/src/generated/ast_builder.rs index 311de4501bf62..fe0854cf7ada3 100644 --- a/crates/oxc_ast/src/generated/ast_builder.rs +++ b/crates/oxc_ast/src/generated/ast_builder.rs @@ -1057,8 +1057,8 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// * `span`: Node location in source code /// * `opening_element`: Opening tag of the element. - /// * `closing_element`: Closing tag of the element. Will be [`None`] for self-closing tags. - /// * `children`: Children of the element. This can be text, other elements, or expressions. + /// * `closing_element`: Closing tag of the element. + /// * `children`: Children of the element. #[inline] pub fn expression_jsx_element( self, @@ -8623,8 +8623,8 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// * `span`: Node location in source code /// * `opening_element`: Opening tag of the element. - /// * `closing_element`: Closing tag of the element. Will be [`None`] for self-closing tags. - /// * `children`: Children of the element. This can be text, other elements, or expressions. + /// * `closing_element`: Closing tag of the element. + /// * `children`: Children of the element. #[inline] pub fn jsx_element( self, @@ -8653,8 +8653,8 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// * `span`: Node location in source code /// * `opening_element`: Opening tag of the element. - /// * `closing_element`: Closing tag of the element. Will be [`None`] for self-closing tags. - /// * `children`: Children of the element. This can be text, other elements, or expressions. + /// * `closing_element`: Closing tag of the element. + /// * `children`: Children of the element. #[inline] pub fn alloc_jsx_element( self, @@ -8680,7 +8680,6 @@ impl<'a> AstBuilder<'a> { /// /// ## Parameters /// * `span`: Node location in source code - /// * `self_closing`: Is this tag self-closing? /// * `name`: The possibly-namespaced tag name, e.g. `Foo` in ``. /// * `attributes`: List of JSX attributes. In React-like applications, these become props. /// * `type_arguments`: Type parameters for generic JSX elements. @@ -8688,7 +8687,6 @@ impl<'a> AstBuilder<'a> { pub fn jsx_opening_element( self, span: Span, - self_closing: bool, name: JSXElementName<'a>, attributes: Vec<'a, JSXAttributeItem<'a>>, type_arguments: T1, @@ -8698,7 +8696,6 @@ impl<'a> AstBuilder<'a> { { JSXOpeningElement { span, - self_closing, name, attributes, type_arguments: type_arguments.into_in(self.allocator), @@ -8712,7 +8709,6 @@ impl<'a> AstBuilder<'a> { /// /// ## Parameters /// * `span`: Node location in source code - /// * `self_closing`: Is this tag self-closing? /// * `name`: The possibly-namespaced tag name, e.g. `Foo` in ``. /// * `attributes`: List of JSX attributes. In React-like applications, these become props. /// * `type_arguments`: Type parameters for generic JSX elements. @@ -8720,7 +8716,6 @@ impl<'a> AstBuilder<'a> { pub fn alloc_jsx_opening_element( self, span: Span, - self_closing: bool, name: JSXElementName<'a>, attributes: Vec<'a, JSXAttributeItem<'a>>, type_arguments: T1, @@ -8729,7 +8724,7 @@ impl<'a> AstBuilder<'a> { T1: IntoIn<'a, Option>>>, { Box::new_in( - self.jsx_opening_element(span, self_closing, name, attributes, type_arguments), + self.jsx_opening_element(span, name, attributes, type_arguments), self.allocator, ) } @@ -9350,8 +9345,8 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// * `span`: Node location in source code /// * `opening_element`: Opening tag of the element. - /// * `closing_element`: Closing tag of the element. Will be [`None`] for self-closing tags. - /// * `children`: Children of the element. This can be text, other elements, or expressions. + /// * `closing_element`: Closing tag of the element. + /// * `children`: Children of the element. #[inline] pub fn jsx_attribute_value_element( self, @@ -9452,8 +9447,8 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// * `span`: Node location in source code /// * `opening_element`: Opening tag of the element. - /// * `closing_element`: Closing tag of the element. Will be [`None`] for self-closing tags. - /// * `children`: Children of the element. This can be text, other elements, or expressions. + /// * `closing_element`: Closing tag of the element. + /// * `children`: Children of the element. #[inline] pub fn jsx_child_element( self, diff --git a/crates/oxc_ast/src/generated/derive_clone_in.rs b/crates/oxc_ast/src/generated/derive_clone_in.rs index 7cf0975696ed1..1346014499832 100644 --- a/crates/oxc_ast/src/generated/derive_clone_in.rs +++ b/crates/oxc_ast/src/generated/derive_clone_in.rs @@ -4969,7 +4969,6 @@ impl<'new_alloc> CloneIn<'new_alloc> for JSXOpeningElement<'_> { fn clone_in(&self, allocator: &'new_alloc Allocator) -> Self::Cloned { JSXOpeningElement { span: CloneIn::clone_in(&self.span, allocator), - self_closing: CloneIn::clone_in(&self.self_closing, allocator), name: CloneIn::clone_in(&self.name, allocator), attributes: CloneIn::clone_in(&self.attributes, allocator), type_arguments: CloneIn::clone_in(&self.type_arguments, allocator), @@ -4979,7 +4978,6 @@ impl<'new_alloc> CloneIn<'new_alloc> for JSXOpeningElement<'_> { fn clone_in_with_semantic_ids(&self, allocator: &'new_alloc Allocator) -> Self::Cloned { JSXOpeningElement { span: CloneIn::clone_in_with_semantic_ids(&self.span, allocator), - self_closing: CloneIn::clone_in_with_semantic_ids(&self.self_closing, allocator), name: CloneIn::clone_in_with_semantic_ids(&self.name, allocator), attributes: CloneIn::clone_in_with_semantic_ids(&self.attributes, allocator), type_arguments: CloneIn::clone_in_with_semantic_ids(&self.type_arguments, allocator), diff --git a/crates/oxc_ast/src/generated/derive_content_eq.rs b/crates/oxc_ast/src/generated/derive_content_eq.rs index fc452e485e1f6..74ac99c234534 100644 --- a/crates/oxc_ast/src/generated/derive_content_eq.rs +++ b/crates/oxc_ast/src/generated/derive_content_eq.rs @@ -1505,8 +1505,7 @@ impl ContentEq for JSXElement<'_> { impl ContentEq for JSXOpeningElement<'_> { fn content_eq(&self, other: &Self) -> bool { - ContentEq::content_eq(&self.self_closing, &other.self_closing) - && ContentEq::content_eq(&self.name, &other.name) + ContentEq::content_eq(&self.name, &other.name) && ContentEq::content_eq(&self.attributes, &other.attributes) && ContentEq::content_eq(&self.type_arguments, &other.type_arguments) } diff --git a/crates/oxc_ast/src/generated/derive_dummy.rs b/crates/oxc_ast/src/generated/derive_dummy.rs index 873546c5fa3e4..bdcc22c7786f8 100644 --- a/crates/oxc_ast/src/generated/derive_dummy.rs +++ b/crates/oxc_ast/src/generated/derive_dummy.rs @@ -1650,7 +1650,7 @@ impl<'a> Dummy<'a> for RegExpPattern<'a> { impl<'a> Dummy<'a> for JSXElement<'a> { /// Create a dummy [`JSXElement`]. /// - /// Has cost of making 2 allocations (80 bytes). + /// Has cost of making 2 allocations (72 bytes). fn dummy(allocator: &'a Allocator) -> Self { Self { span: Dummy::dummy(allocator), @@ -1668,7 +1668,6 @@ impl<'a> Dummy<'a> for JSXOpeningElement<'a> { fn dummy(allocator: &'a Allocator) -> Self { Self { span: Dummy::dummy(allocator), - self_closing: Dummy::dummy(allocator), name: Dummy::dummy(allocator), attributes: Dummy::dummy(allocator), type_arguments: Dummy::dummy(allocator), diff --git a/crates/oxc_ast/src/generated/derive_estree.rs b/crates/oxc_ast/src/generated/derive_estree.rs index d464a90573322..e4c3853c75981 100644 --- a/crates/oxc_ast/src/generated/derive_estree.rs +++ b/crates/oxc_ast/src/generated/derive_estree.rs @@ -1982,7 +1982,7 @@ impl ESTree for JSXElement<'_> { state.serialize_field("type", &JsonSafeString("JSXElement")); state.serialize_field("start", &self.span.start); state.serialize_field("end", &self.span.end); - state.serialize_field("openingElement", &self.opening_element); + state.serialize_field("openingElement", &crate::serialize::JSXElementOpening(self)); state.serialize_field("closingElement", &self.closing_element); state.serialize_field("children", &self.children); state.end(); @@ -1997,7 +1997,7 @@ impl ESTree for JSXOpeningElement<'_> { state.serialize_field("end", &self.span.end); state.serialize_field("attributes", &self.attributes); state.serialize_field("name", &self.name); - state.serialize_field("selfClosing", &self.self_closing); + state.serialize_field("selfClosing", &crate::serialize::JSXOpeningElementSelfClosing(self)); state.serialize_ts_field("typeArguments", &self.type_arguments); state.end(); } diff --git a/crates/oxc_ast/src/serialize.rs b/crates/oxc_ast/src/serialize.rs index 50e448017dc37..b43ee72979b13 100644 --- a/crates/oxc_ast/src/serialize.rs +++ b/crates/oxc_ast/src/serialize.rs @@ -783,6 +783,52 @@ impl ESTree for ExportAllDeclarationWithClause<'_, '_> { // JSX // -------------------- +/// Serializer for `opening_element` field of `JSXElement`. +/// +/// `selfClosing` field of `JSXOpeningElement` depends on whether `JSXElement` has a `closing_element`. +#[ast_meta] +#[estree( + ts_type = "JSXOpeningElement", + raw_deser = " + const openingElement = DESER[Box](POS_OFFSET.opening_element); + if (THIS.closingElement === null) openingElement.selfClosing = true; + openingElement + " +)] +pub struct JSXElementOpening<'a, 'b>(pub &'b JSXElement<'a>); + +impl ESTree for JSXElementOpening<'_, '_> { + fn serialize(&self, serializer: S) { + let element = self.0; + let opening_element = element.opening_element.as_ref(); + + let mut state = serializer.serialize_struct(); + state.serialize_field("type", &JsonSafeString("JSXOpeningElement")); + state.serialize_field("start", &opening_element.span.start); + state.serialize_field("end", &opening_element.span.end); + state.serialize_field("attributes", &opening_element.attributes); + state.serialize_field("name", &opening_element.name); + state.serialize_field("selfClosing", &element.closing_element.is_none()); + state.serialize_ts_field("typeArguments", &opening_element.type_arguments); + state.end(); + } +} + +/// Converter for `selfClosing` field of `JSXOpeningElement`. +/// +/// This converter is not used for serialization - `JSXElementOpening` above handles serialization. +/// This type is only required to add `selfClosing: boolean` to TS type def, +/// and provide default value of `false` for raw transfer deserializer. +#[ast_meta] +#[estree(ts_type = "boolean", raw_deser = "false")] +pub struct JSXOpeningElementSelfClosing<'a, 'b>(#[expect(dead_code)] pub &'b JSXOpeningElement<'a>); + +impl ESTree for JSXOpeningElementSelfClosing<'_, '_> { + fn serialize(&self, _serializer: S) { + unreachable!() + } +} + /// Serializer for `IdentifierReference` variant of `JSXElementName` and `JSXMemberExpressionObject`. /// /// Convert to `JSXIdentifier`. diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index fab7f1d392cb7..291e449530b73 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -2508,12 +2508,15 @@ impl Gen for JSXAttributeItem<'_> { } } -impl Gen for JSXOpeningElement<'_> { +impl Gen for JSXElement<'_> { fn r#gen(&self, p: &mut Codegen, ctx: Context) { - p.add_source_mapping(self.span); + // Opening element. + // Cannot `impl Gen for JSXOpeningElement` because it needs to know value of `self.closing_element` + // to determine whether to print a trailing `/`. + p.add_source_mapping(self.opening_element.span); p.print_ascii_byte(b'<'); - self.name.print(p, ctx); - for attr in &self.attributes { + self.opening_element.name.print(p, ctx); + for attr in &self.opening_element.attributes { match attr { JSXAttributeItem::Attribute(_) => { p.print_hard_space(); @@ -2524,31 +2527,23 @@ impl Gen for JSXOpeningElement<'_> { } attr.print(p, ctx); } - if self.self_closing { + if self.closing_element.is_none() { p.print_soft_space(); p.print_str("/"); } p.print_ascii_byte(b'>'); - } -} -impl Gen for JSXClosingElement<'_> { - fn r#gen(&self, p: &mut Codegen, ctx: Context) { - p.add_source_mapping(self.span); - p.print_str("'); - } -} - -impl Gen for JSXElement<'_> { - fn r#gen(&self, p: &mut Codegen, ctx: Context) { - self.opening_element.print(p, ctx); + // Children for child in &self.children { child.print(p, ctx); } + + // Closing element if let Some(closing_element) = &self.closing_element { - closing_element.print(p, ctx); + p.add_source_mapping(closing_element.span); + p.print_str("'); } } } diff --git a/crates/oxc_linter/src/rules/react/self_closing_comp.rs b/crates/oxc_linter/src/rules/react/self_closing_comp.rs index de76079f814b2..1c9dc9a97aea2 100644 --- a/crates/oxc_linter/src/rules/react/self_closing_comp.rs +++ b/crates/oxc_linter/src/rules/react/self_closing_comp.rs @@ -84,7 +84,7 @@ impl Rule for SelfClosingComp { return; }; - if jsx_el.opening_element.self_closing { + if jsx_el.closing_element.is_none() { return; } diff --git a/crates/oxc_parser/src/jsx/mod.rs b/crates/oxc_parser/src/jsx/mod.rs index a2d7afd3949ab..45b331a00a242 100644 --- a/crates/oxc_parser/src/jsx/mod.rs +++ b/crates/oxc_parser/src/jsx/mod.rs @@ -59,10 +59,9 @@ impl<'a> ParserImpl<'a> { /// true when inside jsx element, false when at top level expression fn parse_jsx_element(&mut self, in_jsx_child: bool) -> Result>> { let span = self.start_span(); - let opening_element = self.parse_jsx_opening_element(span, in_jsx_child)?; - let children = - if opening_element.self_closing { self.ast.vec() } else { self.parse_jsx_children()? }; - let closing_element = if opening_element.self_closing { + let (opening_element, self_closing) = self.parse_jsx_opening_element(span, in_jsx_child)?; + let children = if self_closing { self.ast.vec() } else { self.parse_jsx_children()? }; + let closing_element = if self_closing { None } else { let closing_element = self.parse_jsx_closing_element(in_jsx_child)?; @@ -89,7 +88,10 @@ impl<'a> ParserImpl<'a> { &mut self, span: Span, in_jsx_child: bool, - ) -> Result>> { + ) -> Result<( + Box<'a, JSXOpeningElement<'a>>, + bool, // `true` if self-closing + )> { self.expect(Kind::LAngle)?; let name = self.parse_jsx_element_name()?; // for tsx @@ -101,13 +103,13 @@ impl<'a> ParserImpl<'a> { } else { self.expect(Kind::RAngle)?; } - Ok(self.ast.alloc_jsx_opening_element( + let elem = self.ast.alloc_jsx_opening_element( self.end_span(span), - self_closing, name, attributes, type_parameters, - )) + ); + Ok((elem, self_closing)) } fn parse_jsx_closing_element( diff --git a/crates/oxc_traverse/src/generated/ancestor.rs b/crates/oxc_traverse/src/generated/ancestor.rs index 0966b56a3fa5b..d71635475f458 100644 --- a/crates/oxc_traverse/src/generated/ancestor.rs +++ b/crates/oxc_traverse/src/generated/ancestor.rs @@ -10559,8 +10559,6 @@ impl<'a, 't> GetAddress for JSXElementWithoutChildren<'a, 't> { } pub(crate) const OFFSET_JSX_OPENING_ELEMENT_SPAN: usize = offset_of!(JSXOpeningElement, span); -pub(crate) const OFFSET_JSX_OPENING_ELEMENT_SELF_CLOSING: usize = - offset_of!(JSXOpeningElement, self_closing); pub(crate) const OFFSET_JSX_OPENING_ELEMENT_NAME: usize = offset_of!(JSXOpeningElement, name); pub(crate) const OFFSET_JSX_OPENING_ELEMENT_ATTRIBUTES: usize = offset_of!(JSXOpeningElement, attributes); @@ -10580,13 +10578,6 @@ impl<'a, 't> JSXOpeningElementWithoutName<'a, 't> { unsafe { &*((self.0 as *const u8).add(OFFSET_JSX_OPENING_ELEMENT_SPAN) as *const Span) } } - #[inline] - pub fn self_closing(self) -> &'t bool { - unsafe { - &*((self.0 as *const u8).add(OFFSET_JSX_OPENING_ELEMENT_SELF_CLOSING) as *const bool) - } - } - #[inline] pub fn attributes(self) -> &'t Vec<'a, JSXAttributeItem<'a>> { unsafe { @@ -10624,13 +10615,6 @@ impl<'a, 't> JSXOpeningElementWithoutAttributes<'a, 't> { unsafe { &*((self.0 as *const u8).add(OFFSET_JSX_OPENING_ELEMENT_SPAN) as *const Span) } } - #[inline] - pub fn self_closing(self) -> &'t bool { - unsafe { - &*((self.0 as *const u8).add(OFFSET_JSX_OPENING_ELEMENT_SELF_CLOSING) as *const bool) - } - } - #[inline] pub fn name(self) -> &'t JSXElementName<'a> { unsafe { @@ -10668,13 +10652,6 @@ impl<'a, 't> JSXOpeningElementWithoutTypeArguments<'a, 't> { unsafe { &*((self.0 as *const u8).add(OFFSET_JSX_OPENING_ELEMENT_SPAN) as *const Span) } } - #[inline] - pub fn self_closing(self) -> &'t bool { - unsafe { - &*((self.0 as *const u8).add(OFFSET_JSX_OPENING_ELEMENT_SELF_CLOSING) as *const bool) - } - } - #[inline] pub fn name(self) -> &'t JSXElementName<'a> { unsafe { diff --git a/napi/parser/deserialize-js.js b/napi/parser/deserialize-js.js index b5126a530a99b..3aedf81bd3294 100644 --- a/napi/parser/deserialize-js.js +++ b/napi/parser/deserialize-js.js @@ -1133,12 +1133,15 @@ function deserializeRegExpFlags(pos) { } function deserializeJSXElement(pos) { + const closingElement = deserializeOptionBoxJSXClosingElement(pos + 16); + const openingElement = deserializeBoxJSXOpeningElement(pos + 8); + if (closingElement === null) openingElement.selfClosing = true; return { type: 'JSXElement', start: deserializeU32(pos), end: deserializeU32(pos + 4), - openingElement: deserializeBoxJSXOpeningElement(pos + 8), - closingElement: deserializeOptionBoxJSXClosingElement(pos + 16), + openingElement, + closingElement, children: deserializeVecJSXChild(pos + 24), }; } @@ -1148,9 +1151,9 @@ function deserializeJSXOpeningElement(pos) { type: 'JSXOpeningElement', start: deserializeU32(pos), end: deserializeU32(pos + 4), - attributes: deserializeVecJSXAttributeItem(pos + 32), - name: deserializeJSXElementName(pos + 16), - selfClosing: deserializeBool(pos + 8), + attributes: deserializeVecJSXAttributeItem(pos + 24), + name: deserializeJSXElementName(pos + 8), + selfClosing: false, }; } diff --git a/napi/parser/deserialize-ts.js b/napi/parser/deserialize-ts.js index 801167e953e7a..4aa29e2e587d6 100644 --- a/napi/parser/deserialize-ts.js +++ b/napi/parser/deserialize-ts.js @@ -1207,12 +1207,15 @@ function deserializeRegExpFlags(pos) { } function deserializeJSXElement(pos) { + const closingElement = deserializeOptionBoxJSXClosingElement(pos + 16); + const openingElement = deserializeBoxJSXOpeningElement(pos + 8); + if (closingElement === null) openingElement.selfClosing = true; return { type: 'JSXElement', start: deserializeU32(pos), end: deserializeU32(pos + 4), - openingElement: deserializeBoxJSXOpeningElement(pos + 8), - closingElement: deserializeOptionBoxJSXClosingElement(pos + 16), + openingElement, + closingElement, children: deserializeVecJSXChild(pos + 24), }; } @@ -1222,10 +1225,10 @@ function deserializeJSXOpeningElement(pos) { type: 'JSXOpeningElement', start: deserializeU32(pos), end: deserializeU32(pos + 4), - attributes: deserializeVecJSXAttributeItem(pos + 32), - name: deserializeJSXElementName(pos + 16), - selfClosing: deserializeBool(pos + 8), - typeArguments: deserializeOptionBoxTSTypeParameterInstantiation(pos + 64), + attributes: deserializeVecJSXAttributeItem(pos + 24), + name: deserializeJSXElementName(pos + 8), + selfClosing: false, + typeArguments: deserializeOptionBoxTSTypeParameterInstantiation(pos + 56), }; }