diff --git a/crates/oxc_transformer/examples/test.tsx b/crates/oxc_transformer/examples/test.tsx
new file mode 100644
index 00000000000000..6c06d5d174b6ea
--- /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 d3531898e646d4..13f01074e9632b 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 37123a934de024..496f4595e34dbb 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 1ce80b3625cf17..1d742f2713a17b 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 00000000000000..d89e40a10c159b
--- /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 a1bbac5b369000..674c0f40cc79b5 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 9ac934efe8b9c7..ecee78c280775b 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 23772a5446466e..5e246d95fa893f 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::),