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 90f9ec434df64..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) => { @@ -541,6 +541,28 @@ impl<'a> ReactJsx<'a> { } } + // React.createElement's second argument + if !is_fragment && is_classic { + if self.options.jsx_self_plugin && self.jsx_self.can_add_self_attribute(ctx) { + if let Some(span) = self_attr_span { + self.jsx_self.report_error(span); + } else { + properties.push(self.jsx_self.get_object_property_kind_for_jsx_plugin()); + } + } + + if self.options.jsx_source_plugin { + if let Some(span) = source_attr_span { + self.jsx_source.report_error(span); + } else { + let (line, column) = self.jsx_source.get_line_column(e.span().start); + properties.push( + self.jsx_source.get_object_property_kind_for_jsx_plugin(line, column, ctx), + ); + } + } + } + // It would be better to push to `arguments` earlier, rather than use `insert`. // But we have to do it here to replicate the same import order as Babel, in order to pass // Babel's conformance tests. diff --git a/crates/oxc_transformer/src/react/jsx_self.rs b/crates/oxc_transformer/src/react/jsx_self.rs index c102cb0b2dc1e..60979bd7f5b10 100644 --- a/crates/oxc_transformer/src/react/jsx_self.rs +++ b/crates/oxc_transformer/src/react/jsx_self.rs @@ -62,6 +62,15 @@ impl<'a> ReactJsxSelf<'a> { true } + pub fn get_object_property_kind_for_jsx_plugin(&self) -> ObjectPropertyKind<'a> { + let kind = PropertyKind::Init; + let key = self.ctx.ast.property_key_identifier_name(SPAN, SELF); + let value = self.ctx.ast.expression_this(SPAN); + self.ctx + .ast + .object_property_kind_object_property(SPAN, kind, key, value, None, false, false, false) + } + pub fn can_add_self_attribute(&self, ctx: &TraverseCtx<'a>) -> bool { !self.is_inside_constructor(ctx) || Self::has_no_super_class(ctx) } diff --git a/crates/oxc_transformer/src/react/jsx_source.rs b/crates/oxc_transformer/src/react/jsx_source.rs index d863b70ea1c1f..8809114ed8a80 100644 --- a/crates/oxc_transformer/src/react/jsx_source.rs +++ b/crates/oxc_transformer/src/react/jsx_source.rs @@ -49,6 +49,20 @@ impl<'a> ReactJsxSource<'a> { get_line_column(self.source_rope.as_ref().unwrap(), offset, self.ctx.source_text) } + pub fn get_object_property_kind_for_jsx_plugin( + &mut self, + line: usize, + column: usize, + ctx: &mut TraverseCtx<'a>, + ) -> ObjectPropertyKind<'a> { + let kind = PropertyKind::Init; + let key = self.ctx.ast.property_key_identifier_name(SPAN, SOURCE); + let value = self.get_source_object(line, column, ctx); + self.ctx + .ast + .object_property_kind_object_property(SPAN, kind, key, value, None, false, false, false) + } + pub fn report_error(&self, span: Span) { let error = OxcDiagnostic::warn("Duplicate __source prop found.").with_label(span); self.ctx.error(error); diff --git a/crates/oxc_transformer/src/react/mod.rs b/crates/oxc_transformer/src/react/mod.rs index 7d444b0e18381..2ecfc9712b7bf 100644 --- a/crates/oxc_transformer/src/react/mod.rs +++ b/crates/oxc_transformer/src/react/mod.rs @@ -30,7 +30,6 @@ use crate::context::Ctx; /// * [plugin-transform-react-jsx-source](https://babel.dev/docs/babel-plugin-transform-react-jsx-source) /// * [plugin-transform-react-display-name](https://babeljs.io/docs/babel-plugin-transform-react-display-name) pub struct React<'a> { - runtime: ReactJsxRuntime, jsx: ReactJsx<'a>, display_name: ReactDisplayName<'a>, refresh: ReactRefresh<'a>, @@ -53,12 +52,10 @@ impl<'a> React<'a> { display_name_plugin, jsx_self_plugin, jsx_source_plugin, - runtime, .. } = options; let refresh = options.refresh.clone(); Self { - runtime, jsx: ReactJsx::new(options, Rc::clone(&ctx)), display_name: ReactDisplayName::new(Rc::clone(&ctx)), jsx_plugin, @@ -118,7 +115,7 @@ impl<'a> Traverse<'a> for React<'a> { elem: &mut JSXOpeningElement<'a>, ctx: &mut TraverseCtx<'a>, ) { - if self.runtime.is_classic() { + 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); } @@ -130,7 +127,7 @@ impl<'a> Traverse<'a> for React<'a> { fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { if self.jsx_plugin { - self.jsx.enter_expression(expr, ctx); + self.jsx.exit_expression(expr, ctx); } if self.refresh_plugin { self.refresh.exit_expression(expr, ctx); diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index 0b03e09377d6e..64b54a6beac84 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,11 +1,12 @@ commit: 3bcfee23 -Passed: 324/1022 +Passed: 330/1022 # All Passed: * babel-plugin-transform-optional-catch-binding * babel-preset-react * babel-plugin-transform-react-display-name +* babel-plugin-transform-react-jsx-self * babel-plugin-transform-react-jsx-source @@ -3465,7 +3466,7 @@ after transform: ["T", "f"] rebuilt : ["f"] -# babel-plugin-transform-react-jsx (122/144) +# babel-plugin-transform-react-jsx (124/144) * pure/false-pragma-comment-automatic-runtime/input.js pragma and pragmaFrag cannot be set when runtime is automatic. @@ -3484,9 +3485,6 @@ pragma and pragmaFrag cannot be set when runtime is automatic. * pure/unset-pragma-option-automatic-runtime/input.js pragma and pragmaFrag cannot be set when runtime is automatic. -* react/arrow-functions/input.js -x Output mismatch - * react/should-disallow-spread-children/input.js Spread children are not supported in React. @@ -3526,9 +3524,6 @@ importSource cannot be set when runtime is classic. * react/should-warn-when-importSource-pragma-is-set/input.js importSource cannot be set when runtime is classic. -* react-automatic/arrow-functions/input.js -x Output mismatch - * react-automatic/does-not-add-source-self-automatic/input.mjs transform-react-jsx: unknown field `autoImport`, expected one of `runtime`, `development`, `throwIfNamespace`, `pure`, `importSource`, `pragma`, `pragmaFrag`, `useBuiltIns`, `useSpread`, `refresh` @@ -3575,21 +3570,7 @@ x Output mismatch x Output mismatch -# babel-plugin-transform-react-jsx-self (0/3) -* react-source/arrow-function/input.js -x Output mismatch - -* react-source/basic-sample/input.js -x Output mismatch - -* react-source/disable-with-super/input.js -x Output mismatch - - -# babel-plugin-transform-react-jsx-development (7/11) -* cross-platform/auto-import-dev/input.js -x Output mismatch - +# babel-plugin-transform-react-jsx-development (8/11) * cross-platform/disallow-__self-as-jsx-attribute/input.js ! Duplicate __self prop found. ,-[tasks/coverage/babel/packages/babel-plugin-transform-react-jsx-development/test/fixtures/cross-platform/disallow-__self-as-jsx-attribute/input.js:1:14] 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: