From f903a225a8fb182e85bed6349e07458b877fad81 Mon Sep 17 00:00:00 2001 From: Boshen Date: Fri, 12 Apr 2024 18:08:36 +0800 Subject: [PATCH] feat(transformer): implement react-jsx-self (#2946) --- crates/oxc_ast/src/ast/jsx.rs | 6 +++ crates/oxc_transformer/src/lib.rs | 5 +++ .../oxc_transformer/src/react/jsx_self/mod.rs | 40 ++++++++++++++++++- crates/oxc_transformer/src/react/mod.rs | 7 +++- tasks/transform_conformance/babel.snap.md | 6 ++- tasks/transform_conformance/src/lib.rs | 1 + 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/crates/oxc_ast/src/ast/jsx.rs b/crates/oxc_ast/src/ast/jsx.rs index 3d6711112..d41e78c23 100644 --- a/crates/oxc_ast/src/ast/jsx.rs +++ b/crates/oxc_ast/src/ast/jsx.rs @@ -227,6 +227,12 @@ pub struct JSXIdentifier<'a> { pub name: Atom<'a>, } +impl<'a> JSXIdentifier<'a> { + pub fn new(span: Span, name: Atom<'a>) -> Self { + Self { span, name } + } +} + // 1.4 JSX Children /// JSX Child diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 2029c6ec4..827f0afd1 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -122,4 +122,9 @@ impl<'a> VisitMut<'a> for Transformer<'a> { self.x1_react.transform_export_default_declaration(decl); walk_mut::walk_export_default_declaration_mut(self, decl); } + + fn visit_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) { + self.x1_react.transform_jsx_opening_element(elem); + walk_mut::walk_jsx_opening_element_mut(self, elem); + } } diff --git a/crates/oxc_transformer/src/react/jsx_self/mod.rs b/crates/oxc_transformer/src/react/jsx_self/mod.rs index d89121625..19b9d7a1d 100644 --- a/crates/oxc_transformer/src/react/jsx_self/mod.rs +++ b/crates/oxc_transformer/src/react/jsx_self/mod.rs @@ -1,5 +1,8 @@ use std::rc::Rc; +use oxc_ast::ast::*; +use oxc_span::SPAN; + use crate::context::Ctx; /// [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self) @@ -10,13 +13,46 @@ use crate::context::Ctx; /// /// In: `` /// Out: `` +/// +/// TODO: +/// *. Omit adding `this` in some conditions +/// #[allow(unused)] pub struct ReactJsxSelf<'a> { + development: bool, + ctx: Ctx<'a>, } impl<'a> ReactJsxSelf<'a> { - pub fn new(ctx: &Ctx<'a>) -> Self { - Self { ctx: Rc::clone(ctx) } + pub fn new(development: bool, ctx: &Ctx<'a>) -> Self { + Self { development, ctx: Rc::clone(ctx) } + } + + pub fn transform_jsx_opening_element(&self, elem: &mut JSXOpeningElement<'a>) { + if self.development { + self.add_self_this_attribute(elem); + } + } +} + +impl<'a> ReactJsxSelf<'a> { + /// `
` + /// ^^^^^^^^^^^^^ + fn add_self_this_attribute(&self, elem: &mut JSXOpeningElement<'a>) { + let name = { + let name = self.ctx.ast.new_atom("__self"); + JSXAttributeName::Identifier(JSXIdentifier::new(SPAN, name)) + }; + let value = { + let jsx_expr = JSXExpression::Expression(self.ctx.ast.this_expression(SPAN)); + let container = self.ctx.ast.jsx_expression_container(SPAN, jsx_expr); + JSXAttributeValue::ExpressionContainer(container) + }; + let attribute = { + let attribute = self.ctx.ast.jsx_attribute(SPAN, name, Some(value)); + JSXAttributeItem::Attribute(attribute) + }; + elem.attributes.push(attribute); } } diff --git a/crates/oxc_transformer/src/react/mod.rs b/crates/oxc_transformer/src/react/mod.rs index b176ba915..40a5a380e 100644 --- a/crates/oxc_transformer/src/react/mod.rs +++ b/crates/oxc_transformer/src/react/mod.rs @@ -35,10 +35,11 @@ pub struct React<'a> { // Constructors impl<'a> React<'a> { pub fn new(options: ReactOptions, ctx: &Ctx<'a>) -> Self { + let development = options.development; Self { ctx: Rc::clone(ctx), jsx: ReactJsx::new(options, ctx), - jsx_self: ReactJsxSelf::new(ctx), + jsx_self: ReactJsxSelf::new(development, ctx), jsx_source: ReactJsxSource::new(ctx), display_name: ReactDisplayName::new(ctx), } @@ -76,4 +77,8 @@ impl<'a> React<'a> { ) { self.display_name.transform_export_default_declaration(decl); } + + pub fn transform_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) { + self.jsx_self.transform_jsx_opening_element(elem); + } } diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index 4a2f73753..8e51e47b9 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,4 +1,4 @@ -Passed: 75/174 +Passed: 76/177 # All Passed: @@ -107,3 +107,7 @@ Passed: 75/174 # babel-plugin-transform-react-display-name (15/16) * display-name/nested/input.js +# babel-plugin-transform-react-jsx-self (1/3) +* react-source/arrow-function/input.js +* react-source/disable-with-super/input.js + diff --git a/tasks/transform_conformance/src/lib.rs b/tasks/transform_conformance/src/lib.rs index 8df21dfec..4a1f8c9a7 100644 --- a/tasks/transform_conformance/src/lib.rs +++ b/tasks/transform_conformance/src/lib.rs @@ -94,6 +94,7 @@ const CASES: &[&str] = &[ // React // "babel-plugin-transform-react-jsx", "babel-plugin-transform-react-display-name", + "babel-plugin-transform-react-jsx-self", // // Proposal // "babel-plugin-proposal-decorators", ];