feat(transformer): apply jsx self and source plugin inside jsx transform (#2966)

This commit is contained in:
Boshen 2024-04-14 19:10:59 +08:00 committed by GitHub
parent 10814d5331
commit 3a6eae1abd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 59 additions and 23 deletions

View file

@ -10,7 +10,11 @@ use oxc_syntax::{
use crate::context::Ctx; use crate::context::Ctx;
pub use super::options::{ReactJsxRuntime, ReactOptions}; pub use super::{
jsx_self::ReactJsxSelf,
jsx_source::ReactJsxSource,
options::{ReactJsxRuntime, ReactOptions},
};
/// [plugin-transform-react-jsx](https://babeljs.io/docs/babel-plugin-transform-react-jsx) /// [plugin-transform-react-jsx](https://babeljs.io/docs/babel-plugin-transform-react-jsx)
/// ///
@ -27,6 +31,9 @@ pub struct ReactJsx<'a> {
ctx: Ctx<'a>, ctx: Ctx<'a>,
jsx_self: ReactJsxSelf<'a>,
jsx_source: ReactJsxSource<'a>,
// States // States
imports: std::vec::Vec<Statement<'a>>, imports: std::vec::Vec<Statement<'a>>,
require_jsx_runtime: bool, require_jsx_runtime: bool,
@ -53,6 +60,8 @@ impl<'a> ReactJsx<'a> {
Self { Self {
options: Rc::clone(options), options: Rc::clone(options),
ctx: Rc::clone(ctx), ctx: Rc::clone(ctx),
jsx_self: ReactJsxSelf::new(ctx),
jsx_source: ReactJsxSource::new(ctx),
imports: vec![], imports: vec![],
require_jsx_runtime: false, require_jsx_runtime: false,
jsx_runtime_importer, jsx_runtime_importer,
@ -374,6 +383,13 @@ impl<'a> ReactJsx<'a> {
} }
} }
if self.options.is_jsx_self_plugin_enabled() {
properties.push(self.jsx_self.get_object_property_kind_for_jsx_plugin());
}
if self.options.is_jsx_source_plugin_enabled() {
properties.push(self.jsx_source.get_object_property_kind_for_jsx_plugin());
}
self.add_import(e, has_key_after_props_spread, need_jsxs); self.add_import(e, has_key_after_props_spread, need_jsxs);
if !properties.is_empty() || is_automatic { if !properties.is_empty() || is_automatic {

View file

@ -5,6 +5,8 @@ use oxc_span::SPAN;
use crate::context::Ctx; use crate::context::Ctx;
const SELF: &str = "__self";
/// [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self) /// [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self)
/// ///
/// This plugin is included in `preset-react` and only enabled in development mode. /// This plugin is included in `preset-react` and only enabled in development mode.
@ -17,7 +19,6 @@ use crate::context::Ctx;
/// TODO: /// TODO:
/// *. Omit adding `this` in some conditions /// *. Omit adding `this` in some conditions
/// <https://github.com/babel/babel/blob/9cd048b5ad45eafd157c4f9968343e36170a66c1/packages/babel-plugin-transform-react-jsx-self/src/index.ts#L78> /// <https://github.com/babel/babel/blob/9cd048b5ad45eafd157c4f9968343e36170a66c1/packages/babel-plugin-transform-react-jsx-self/src/index.ts#L78>
#[allow(unused)]
pub struct ReactJsxSelf<'a> { pub struct ReactJsxSelf<'a> {
ctx: Ctx<'a>, ctx: Ctx<'a>,
} }
@ -30,13 +31,22 @@ impl<'a> ReactJsxSelf<'a> {
pub fn transform_jsx_opening_element(&self, elem: &mut JSXOpeningElement<'a>) { pub fn transform_jsx_opening_element(&self, elem: &mut JSXOpeningElement<'a>) {
self.add_self_this_attribute(elem); self.add_self_this_attribute(elem);
} }
pub fn get_object_property_kind_for_jsx_plugin(&self) -> ObjectPropertyKind<'a> {
let kind = PropertyKind::Init;
let ident = IdentifierName::new(SPAN, SELF.into());
let key = self.ctx.ast.property_key_identifier(ident);
let value = self.ctx.ast.this_expression(SPAN);
let obj = self.ctx.ast.object_property(SPAN, kind, key, value, None, false, false, false);
ObjectPropertyKind::ObjectProperty(obj)
}
} }
impl<'a> ReactJsxSelf<'a> { impl<'a> ReactJsxSelf<'a> {
/// `<div __self={this} />` /// `<div __self={this} />`
/// ^^^^^^^^^^^^^ /// ^^^^^^^^^^^^^
fn add_self_this_attribute(&self, elem: &mut JSXOpeningElement<'a>) { fn add_self_this_attribute(&self, elem: &mut JSXOpeningElement<'a>) {
let name = JSXAttributeName::Identifier(JSXIdentifier::new(SPAN, "__self".into())); let name = JSXAttributeName::Identifier(JSXIdentifier::new(SPAN, SELF.into()));
let value = { let value = {
let jsx_expr = JSXExpression::Expression(self.ctx.ast.this_expression(SPAN)); let jsx_expr = JSXExpression::Expression(self.ctx.ast.this_expression(SPAN));
let container = self.ctx.ast.jsx_expression_container(SPAN, jsx_expr); let container = self.ctx.ast.jsx_expression_container(SPAN, jsx_expr);

View file

@ -6,6 +6,8 @@ use oxc_syntax::NumberBase;
use crate::context::Ctx; use crate::context::Ctx;
const SOURCE: &str = "__source";
/// [plugin-transform-react-jsx-source](https://babeljs.io/docs/babel-plugin-transform-react-jsx-source) /// [plugin-transform-react-jsx-source](https://babeljs.io/docs/babel-plugin-transform-react-jsx-source)
/// ///
/// This plugin is included in `preset-react` and only enabled in development mode. /// This plugin is included in `preset-react` and only enabled in development mode.
@ -28,12 +30,30 @@ impl<'a> ReactJsxSource<'a> {
pub fn transform_jsx_opening_element(&self, elem: &mut JSXOpeningElement<'a>) { pub fn transform_jsx_opening_element(&self, elem: &mut JSXOpeningElement<'a>) {
self.add_source_attribute(elem); self.add_source_attribute(elem);
} }
pub fn get_object_property_kind_for_jsx_plugin(&self) -> ObjectPropertyKind<'a> {
let kind = PropertyKind::Init;
let ident = IdentifierName::new(SPAN, SOURCE.into());
let key = self.ctx.ast.property_key_identifier(ident);
let value = self.get_source_object();
let obj = self.ctx.ast.object_property(SPAN, kind, key, value, None, false, false, false);
ObjectPropertyKind::ObjectProperty(obj)
}
} }
impl<'a> ReactJsxSource<'a> { impl<'a> ReactJsxSource<'a> {
/// `<sometag __source={ { fileName: 'this/file.js', lineNumber: 10, columnNumber: 1 } } />` /// `<sometag __source={ { fileName: 'this/file.js', lineNumber: 10, columnNumber: 1 } } />`
/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
fn add_source_attribute(&self, elem: &mut JSXOpeningElement<'a>) { fn add_source_attribute(&self, elem: &mut JSXOpeningElement<'a>) {
let key = JSXAttributeName::Identifier(self.ctx.ast.jsx_identifier(SPAN, SOURCE.into()));
let object = self.get_source_object();
let expr = self.ctx.ast.jsx_expression_container(SPAN, JSXExpression::Expression(object));
let value = JSXAttributeValue::ExpressionContainer(expr);
let attribute_item = self.ctx.ast.jsx_attribute(SPAN, key, Some(value));
elem.attributes.push(JSXAttributeItem::Attribute(attribute_item));
}
fn get_source_object(&self) -> Expression<'a> {
let kind = PropertyKind::Init; let kind = PropertyKind::Init;
let filename = { let filename = {
@ -64,16 +84,6 @@ impl<'a> ReactJsxSource<'a> {
properties.push(ObjectPropertyKind::ObjectProperty(filename)); properties.push(ObjectPropertyKind::ObjectProperty(filename));
properties.push(ObjectPropertyKind::ObjectProperty(line_number)); properties.push(ObjectPropertyKind::ObjectProperty(line_number));
properties.push(ObjectPropertyKind::ObjectProperty(column_number)); properties.push(ObjectPropertyKind::ObjectProperty(column_number));
self.ctx.ast.object_expression(SPAN, properties, None)
let attribute_item = self.ctx.ast.jsx_attribute(
SPAN,
JSXAttributeName::Identifier(self.ctx.ast.jsx_identifier(SPAN, "__source".into())),
Some(JSXAttributeValue::ExpressionContainer(self.ctx.ast.jsx_expression_container(
SPAN,
JSXExpression::Expression(self.ctx.ast.object_expression(SPAN, properties, None)),
))),
);
elem.attributes.push(JSXAttributeItem::Attribute(attribute_item));
} }
} }

View file

@ -99,13 +99,11 @@ impl<'a> React<'a> {
} }
pub fn transform_jsx_opening_element(&self, elem: &mut JSXOpeningElement<'a>) { pub fn transform_jsx_opening_element(&self, elem: &mut JSXOpeningElement<'a>) {
if self.development { if self.options.is_jsx_self_plugin_enabled() {
if self.options.jsx_self_plugin { self.jsx_self.transform_jsx_opening_element(elem);
self.jsx_self.transform_jsx_opening_element(elem); }
} if self.options.is_jsx_source_plugin_enabled() {
if self.options.jsx_source_plugin { self.jsx_source.transform_jsx_opening_element(elem);
self.jsx_source.transform_jsx_opening_element(elem);
}
} }
} }
} }

View file

@ -1,4 +1,4 @@
Passed: 131/392 Passed: 129/392
# All Passed: # All Passed:
* babel-plugin-transform-react-jsx-source * babel-plugin-transform-react-jsx-source
@ -125,11 +125,13 @@ Passed: 131/392
* regression/15768/input.ts * regression/15768/input.ts
* variable-declaration/non-null-in-optional-chain/input.ts * variable-declaration/non-null-in-optional-chain/input.ts
# babel-preset-react (4/13) # babel-preset-react (2/13)
* preset-options/development/input.js * preset-options/development/input.js
* preset-options/development-runtime-automatic/input.js * preset-options/development-runtime-automatic/input.js
* preset-options/development-runtime-automatic-windows/input.js * preset-options/development-runtime-automatic-windows/input.js
* preset-options/development-windows/input.js * preset-options/development-windows/input.js
* preset-options/empty-options/input.js
* preset-options/runtime-automatic/input.js
* preset-options/runtime-classic/input.js * preset-options/runtime-classic/input.js
* preset-options/runtime-classic-pragma-no-frag/input.js * preset-options/runtime-classic-pragma-no-frag/input.js
* regression/11294/input.mjs * regression/11294/input.mjs