From e9884913b117b92e4fb85a4f7f36eff4a290a4d2 Mon Sep 17 00:00:00 2001 From: zoomdong <1344492820@qq.com> Date: Thu, 28 Mar 2024 19:57:33 +0800 Subject: [PATCH] feat(transformer): implement @babel/plugin-transform-react-jsx-self --- crates/oxc_transformer/examples/test.tsx | 5 +++ .../oxc_transformer/examples/transformer.rs | 1 + crates/oxc_transformer/src/lib.rs | 8 ++++- crates/oxc_transformer/src/options.rs | 2 ++ .../oxc_transformer/src/react_jsx/jsx_self.rs | 35 +++++++++++++++++++ crates/oxc_transformer/src/react_jsx/mod.rs | 2 ++ .../oxc_transformer/src/react_jsx/options.rs | 5 +++ tasks/transform_conformance/src/test_case.rs | 3 ++ 8 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 crates/oxc_transformer/examples/test.tsx create mode 100644 crates/oxc_transformer/src/react_jsx/jsx_self.rs diff --git a/crates/oxc_transformer/examples/test.tsx b/crates/oxc_transformer/examples/test.tsx new file mode 100644 index 0000000000000..6c06d5d174b6e --- /dev/null +++ b/crates/oxc_transformer/examples/test.tsx @@ -0,0 +1,5 @@ +function App() { + return ( + + ) +} \ No newline at end of file diff --git a/crates/oxc_transformer/examples/transformer.rs b/crates/oxc_transformer/examples/transformer.rs index d3531898e646d..13f01074e9632 100644 --- a/crates/oxc_transformer/examples/transformer.rs +++ b/crates/oxc_transformer/examples/transformer.rs @@ -49,6 +49,7 @@ fn main() { target: TransformTarget::ES5, react_jsx: Some(ReactJsxOptions { runtime: Some(ReactJsxRuntimeOption::Valid(ReactJsxRuntime::Classic)), + development: Some(true), ..ReactJsxOptions::default() }), ..TransformOptions::default() diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 37123a934de02..496f4595e34db 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -52,7 +52,7 @@ use crate::{ es2021::{LogicalAssignmentOperators, NumericSeparator}, es2022::ClassStaticBlock, es3::PropertyLiteral, - react_jsx::ReactJsx, + react_jsx::{JsxSelf, ReactJsx}, regexp::RegexpFlags, typescript::TypeScript, utils::CreateVars, @@ -72,6 +72,7 @@ pub struct Transformer<'a> { decorators: Option>, #[allow(unused)] typescript: Option>, + jsx_self: Option>, react_jsx: Option>, regexp_flags: Option>, // es2022 @@ -140,6 +141,7 @@ impl<'a> Transformer<'a> { es2015_new_target: NewTarget::new(ctx.clone()), // other es3_property_literal: PropertyLiteral::new(ctx.clone()), + jsx_self: JsxSelf::new(ctx.clone()), react_jsx: ReactJsx::new(ctx.clone()), // original context ctx, @@ -202,6 +204,10 @@ impl<'a> VisitMut<'a> for Transformer<'a> { self.decorators.as_mut().map(|t| t.transform_declaration(decl)); } + fn visit_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) { + self.jsx_self.as_mut().map(|t| t.transform_jsx_opening_element(elem)); + } + fn visit_expression(&mut self, expr: &mut Expression<'a>) { // self.typescript.as_mut().map(|t| t.transform_expression(expr)); self.react_jsx.as_mut().map(|t| t.transform_expression(expr)); diff --git a/crates/oxc_transformer/src/options.rs b/crates/oxc_transformer/src/options.rs index 1ce80b3625cf1..1d742f2713a17 100644 --- a/crates/oxc_transformer/src/options.rs +++ b/crates/oxc_transformer/src/options.rs @@ -10,6 +10,8 @@ pub struct TransformOptions { pub target: TransformTarget, pub assumptions: CompilerAssumptions, + pub jsx_self: Option, + pub react_jsx: Option, pub typescript: Option, diff --git a/crates/oxc_transformer/src/react_jsx/jsx_self.rs b/crates/oxc_transformer/src/react_jsx/jsx_self.rs new file mode 100644 index 0000000000000..d89e40a10c159 --- /dev/null +++ b/crates/oxc_transformer/src/react_jsx/jsx_self.rs @@ -0,0 +1,35 @@ +use crate::{context::TransformerCtx, ReactJsxOptions}; +use oxc_ast::ast::*; +use oxc_span::SPAN; + +/// @babel/plugin-transform-react-jsx-self +/// +/// References: +/// * +/// * +/// +pub struct JsxSelf<'a> { + ctx: TransformerCtx<'a>, + options: ReactJsxOptions, +} + +impl<'a> JsxSelf<'a> { + pub fn new(ctx: TransformerCtx<'a>) -> Option { + let jsx_options = ctx.options.react_jsx.clone()?; + Some(Self { ctx, options: jsx_options }) + } + pub fn transform_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) { + if self.options.development != Some(true) { + return; + } + + elem.attributes.push(JSXAttributeItem::Attribute(self.ctx.ast.jsx_attribute( + SPAN, + JSXAttributeName::Identifier(self.ctx.ast.jsx_identifier(SPAN, "__self".into())), + Some(JSXAttributeValue::ExpressionContainer(self.ctx.ast.jsx_expression_container( + SPAN, + JSXExpression::Expression(self.ctx.ast.this_expression(SPAN)), + ))), + ))); + } +} diff --git a/crates/oxc_transformer/src/react_jsx/mod.rs b/crates/oxc_transformer/src/react_jsx/mod.rs index a1bbac5b36900..674c0f40cc79b 100644 --- a/crates/oxc_transformer/src/react_jsx/mod.rs +++ b/crates/oxc_transformer/src/react_jsx/mod.rs @@ -1,3 +1,4 @@ +mod jsx_self; mod options; use oxc_allocator::Vec; @@ -12,6 +13,7 @@ use oxc_syntax::{ xml_entities::XML_ENTITIES, }; +pub use self::jsx_self::JsxSelf; pub use self::options::{ReactJsxOptions, ReactJsxRuntime, ReactJsxRuntimeOption}; use crate::context::TransformerCtx; diff --git a/crates/oxc_transformer/src/react_jsx/options.rs b/crates/oxc_transformer/src/react_jsx/options.rs index 9ac934efe8b9c..ecee78c280775 100644 --- a/crates/oxc_transformer/src/react_jsx/options.rs +++ b/crates/oxc_transformer/src/react_jsx/options.rs @@ -34,6 +34,10 @@ pub struct ReactJsxOptions { /// Use `Some` instead of `bool` because we want to know if user set this field explicitly, /// which used for creating warning, pub use_spread: Option, + + /// enable development transform for jsx transform + #[serde(default)] + pub development: Option, } fn default_throw_if_namespace() -> bool { @@ -62,6 +66,7 @@ impl Default for ReactJsxOptions { pragma_frag: default_pragma_frag(), use_built_ins: None, use_spread: None, + development: None, } } } diff --git a/tasks/transform_conformance/src/test_case.rs b/tasks/transform_conformance/src/test_case.rs index 23772a5446466..5e246d95fa893 100644 --- a/tasks/transform_conformance/src/test_case.rs +++ b/tasks/transform_conformance/src/test_case.rs @@ -92,6 +92,9 @@ pub trait TestCase { decorators: options .get_plugin("proposal-decorators") .map(get_options::), + jsx_self: options + .get_plugin("transform-react-jsx-self") + .map(get_options::), react_jsx: options .get_plugin("transform-react-jsx") .map(get_options::),