From 36e698b4112f2d8ee3b97dd8feb90a2a1149a46f Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Fri, 13 Sep 2024 17:58:41 +0000 Subject: [PATCH] perf(transformer): call `transform_jsx` in `exit_expression` rather than `enter_expression` (#5751) ### Difference In `enter_expression`: Recursive transform JSX In `exit_expression`: Deep first transform After the change, `transform_jsx` still has a lot of room for improvement. --- .../src/es2015/arrow_functions.rs | 44 ++++++++++++++++--- crates/oxc_transformer/src/es2015/mod.rs | 16 +++++++ crates/oxc_transformer/src/lib.rs | 12 +++++ crates/oxc_transformer/src/react/jsx.rs | 2 +- crates/oxc_transformer/src/react/mod.rs | 21 +++++---- tasks/coverage/semantic_typescript.snap | 12 ++--- tasks/transform_conformance/oxc.snap.md | 8 +--- 7 files changed, 84 insertions(+), 31 deletions(-) diff --git a/crates/oxc_transformer/src/es2015/arrow_functions.rs b/crates/oxc_transformer/src/es2015/arrow_functions.rs index 5117ae293f59e..ed9f9636b0fad 100644 --- a/crates/oxc_transformer/src/es2015/arrow_functions.rs +++ b/crates/oxc_transformer/src/es2015/arrow_functions.rs @@ -131,17 +131,37 @@ impl<'a> Traverse<'a> for ArrowFunctions<'a> { self.insert_this_var_statement_at_the_top_of_statements(&mut body.statements); } - fn enter_expression(&mut self, expr: &mut Expression<'a>, _ctx: &mut TraverseCtx<'a>) { - match expr { - Expression::ArrowFunctionExpression(_) => { - self.stacks.push(true); + fn enter_jsx_element_name( + &mut self, + element_name: &mut JSXElementName<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + if let JSXElementName::ThisExpression(this) = element_name { + if !self.is_inside_arrow_function() { + return; } - Expression::FunctionExpression(_) => self.stacks.push(false), - _ => {} + + let ident = self.get_this_name(ctx).create_spanned_read_reference(this.span, ctx); + *element_name = self.ctx.ast.jsx_element_name_from_identifier_reference(ident); + }; + } + + fn enter_jsx_member_expression_object( + &mut self, + object: &mut JSXMemberExpressionObject<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + if let JSXMemberExpressionObject::ThisExpression(this) = object { + if !self.is_inside_arrow_function() { + return; + } + + let ident = self.get_this_name(ctx).create_spanned_read_reference(this.span, ctx); + *object = self.ctx.ast.jsx_member_expression_object_from_identifier_reference(ident); } } - fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { + fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { match expr { Expression::ThisExpression(this_expr) => { if !self.is_inside_arrow_function() { @@ -152,6 +172,16 @@ impl<'a> Traverse<'a> for ArrowFunctions<'a> { self.get_this_name(ctx).create_spanned_read_reference(this_expr.span, ctx); *expr = self.ctx.ast.expression_from_identifier_reference(ident); } + Expression::ArrowFunctionExpression(_) => { + self.stacks.push(true); + } + Expression::FunctionExpression(_) => self.stacks.push(false), + _ => {} + } + } + + fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { + match expr { Expression::ArrowFunctionExpression(arrow_function_expr) => { *expr = self.transform_arrow_function_expression(arrow_function_expr, ctx); self.stacks.pop(); diff --git a/crates/oxc_transformer/src/es2015/mod.rs b/crates/oxc_transformer/src/es2015/mod.rs index c094901bc6888..f6643c0d10bce 100644 --- a/crates/oxc_transformer/src/es2015/mod.rs +++ b/crates/oxc_transformer/src/es2015/mod.rs @@ -96,4 +96,20 @@ impl<'a> Traverse<'a> for ES2015<'a> { self.arrow_functions.enter_variable_declarator(node, ctx); } } + + fn enter_jsx_element_name(&mut self, node: &mut JSXElementName<'a>, ctx: &mut TraverseCtx<'a>) { + if self.options.arrow_function.is_some() { + self.arrow_functions.enter_jsx_element_name(node, ctx); + } + } + + fn enter_jsx_member_expression_object( + &mut self, + node: &mut JSXMemberExpressionObject<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + if self.options.arrow_function.is_some() { + self.arrow_functions.enter_jsx_member_expression_object(node, ctx); + } + } } diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 4d968ecc24d01..2d5b6eabcd22c 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -228,6 +228,18 @@ impl<'a> Traverse<'a> for Transformer<'a> { self.x0_typescript.enter_jsx_element(node, ctx); } + fn enter_jsx_element_name(&mut self, node: &mut JSXElementName<'a>, ctx: &mut TraverseCtx<'a>) { + self.x3_es2015.enter_jsx_element_name(node, ctx); + } + + fn enter_jsx_member_expression_object( + &mut self, + node: &mut JSXMemberExpressionObject<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.x3_es2015.enter_jsx_member_expression_object(node, ctx); + } + fn enter_jsx_fragment(&mut self, node: &mut JSXFragment<'a>, ctx: &mut TraverseCtx<'a>) { self.x0_typescript.enter_jsx_fragment(node, ctx); } diff --git a/crates/oxc_transformer/src/react/jsx.rs b/crates/oxc_transformer/src/react/jsx.rs index 4b64dcf900da4..91fcc1d93e61c 100644 --- a/crates/oxc_transformer/src/react/jsx.rs +++ b/crates/oxc_transformer/src/react/jsx.rs @@ -370,7 +370,7 @@ impl<'a> Traverse<'a> for ReactJsx<'a> { self.add_runtime_imports(program, ctx); } - fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { + fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { *expr = match expr { Expression::JSXElement(e) => self.transform_jsx(&JSXElementOrFragment::Element(e), ctx), Expression::JSXFragment(e) => { diff --git a/crates/oxc_transformer/src/react/mod.rs b/crates/oxc_transformer/src/react/mod.rs index 46926f2354ec8..2ecfc9712b7bf 100644 --- a/crates/oxc_transformer/src/react/mod.rs +++ b/crates/oxc_transformer/src/react/mod.rs @@ -96,12 +96,6 @@ impl<'a> Traverse<'a> for React<'a> { } } - fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { - if self.jsx_plugin { - self.jsx.enter_expression(expr, ctx); - } - } - fn enter_call_expression( &mut self, call_expr: &mut CallExpression<'a>, @@ -121,15 +115,20 @@ impl<'a> Traverse<'a> for React<'a> { elem: &mut JSXOpeningElement<'a>, ctx: &mut TraverseCtx<'a>, ) { - if self.jsx_self_plugin && self.jsx.jsx_self.can_add_self_attribute(ctx) { - self.jsx.jsx_self.enter_jsx_opening_element(elem, ctx); - } - if self.jsx_source_plugin { - self.jsx.jsx_source.enter_jsx_opening_element(elem, ctx); + if !self.jsx_plugin { + if self.jsx_self_plugin && self.jsx.jsx_self.can_add_self_attribute(ctx) { + self.jsx.jsx_self.enter_jsx_opening_element(elem, ctx); + } + if self.jsx_source_plugin { + self.jsx.jsx_source.enter_jsx_opening_element(elem, ctx); + } } } fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { + if self.jsx_plugin { + self.jsx.exit_expression(expr, ctx); + } if self.refresh_plugin { self.refresh.exit_expression(expr, ctx); } diff --git a/tasks/coverage/semantic_typescript.snap b/tasks/coverage/semantic_typescript.snap index 4655e7ad4994e..64a0ac1dd6d17 100644 --- a/tasks/coverage/semantic_typescript.snap +++ b/tasks/coverage/semantic_typescript.snap @@ -5487,7 +5487,7 @@ Scope children mismatch: after transform: ScopeId(0): [ScopeId(1), ScopeId(8), ScopeId(9)] rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)] Symbol reference IDs mismatch: -after transform: SymbolId(0): [ReferenceId(6), ReferenceId(14), ReferenceId(17), ReferenceId(18), ReferenceId(20), ReferenceId(23), ReferenceId(24)] +after transform: SymbolId(0): [ReferenceId(6), ReferenceId(15), ReferenceId(16), ReferenceId(18), ReferenceId(21), ReferenceId(22), ReferenceId(24)] rebuilt : SymbolId(1): [ReferenceId(0), ReferenceId(3), ReferenceId(5), ReferenceId(8), ReferenceId(10), ReferenceId(12)] Reference symbol mismatch: after transform: ReferenceId(8): Some("DropdownMenu") @@ -21130,10 +21130,13 @@ rebuilt : ["undefined"] tasks/coverage/typescript/tests/cases/compiler/jsxEmptyExpressionNotCountedAsChild.tsx semantic error: Bindings mismatch: after transform: ScopeId(0): ["Props", "React", "Wrapper", "_jsx", "_jsxFileName", "element"] -rebuilt : ScopeId(0): ["Wrapper", "_jsx", "_jsxFileName", "element"] +rebuilt : ScopeId(0): ["React", "Wrapper", "_jsx", "_jsxFileName", "element"] Scope children mismatch: after transform: ScopeId(0): [ScopeId(1), ScopeId(2)] rebuilt : ScopeId(0): [ScopeId(1)] +Symbol reference IDs mismatch: +after transform: SymbolId(0): [ReferenceId(0)] +rebuilt : SymbolId(0): [] tasks/coverage/typescript/tests/cases/compiler/jsxFactoryAndJsxFragmentFactory.tsx semantic error: Bindings mismatch: @@ -21371,10 +21374,7 @@ after transform: ["Function"] rebuilt : [] tasks/coverage/typescript/tests/cases/compiler/jsxPartialSpread.tsx -semantic error: Bindings mismatch: -after transform: ScopeId(0): ["React", "Repro", "Select", "_jsx", "_jsxFileName"] -rebuilt : ScopeId(0): ["Repro", "Select", "_jsx", "_jsxFileName"] -Symbol reference IDs mismatch: +semantic error: Symbol reference IDs mismatch: after transform: SymbolId(0): [ReferenceId(2), ReferenceId(3)] rebuilt : SymbolId(0): [ReferenceId(3)] Unresolved references mismatch: diff --git a/tasks/transform_conformance/oxc.snap.md b/tasks/transform_conformance/oxc.snap.md index 5bb8cb0d9be3c..c1c31d7dbd9f4 100644 --- a/tasks/transform_conformance/oxc.snap.md +++ b/tasks/transform_conformance/oxc.snap.md @@ -1,19 +1,15 @@ commit: 3bcfee23 -Passed: 42/53 +Passed: 43/53 # All Passed: * babel-plugin-transform-nullish-coalescing-operator * babel-plugin-transform-optional-catch-binding +* babel-plugin-transform-arrow-functions * babel-preset-typescript * regexp -# babel-plugin-transform-arrow-functions (1/2) -* with-this-member-expression/input.jsx -x Output mismatch - - # babel-plugin-transform-typescript (1/8) * class-property-definition/input.ts Unresolved references mismatch: