mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer/react-jsx): when the source type is a script, use require to import the react (#1207)
This commit is contained in:
parent
3e15fa624b
commit
d9b450414b
3 changed files with 61 additions and 35 deletions
|
|
@ -7,7 +7,7 @@ use std::{
|
||||||
use oxc_ast::AstBuilder;
|
use oxc_ast::AstBuilder;
|
||||||
use oxc_diagnostics::Error;
|
use oxc_diagnostics::Error;
|
||||||
use oxc_semantic::{ScopeId, ScopeTree, Semantic, SymbolId, SymbolTable};
|
use oxc_semantic::{ScopeId, ScopeTree, Semantic, SymbolId, SymbolTable};
|
||||||
use oxc_span::Atom;
|
use oxc_span::{Atom, SourceType};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TransformerCtx<'a> {
|
pub struct TransformerCtx<'a> {
|
||||||
|
|
@ -42,6 +42,10 @@ impl<'a> TransformerCtx<'a> {
|
||||||
self.scopes_mut().add_binding(ScopeId::new(0), name, SymbolId::new(0));
|
self.scopes_mut().add_binding(ScopeId::new(0), name, SymbolId::new(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn source_type(&self) -> Ref<'_, SourceType> {
|
||||||
|
Ref::map(self.semantic.borrow(), |semantic| semantic.source_type())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn errors(&self) -> Vec<Error> {
|
pub fn errors(&self) -> Vec<Error> {
|
||||||
mem::take(&mut self.errors.borrow_mut())
|
mem::take(&mut self.errors.borrow_mut())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,12 +165,16 @@ impl<'a> ReactJsx<'a> {
|
||||||
fn add_require_jsx_runtime(&mut self) {
|
fn add_require_jsx_runtime(&mut self) {
|
||||||
if !self.require_jsx_runtime {
|
if !self.require_jsx_runtime {
|
||||||
self.require_jsx_runtime = true;
|
self.require_jsx_runtime = true;
|
||||||
self.require_jsx_runtime(Self::new_string_literal(self.jsx_runtime_importer.as_str()));
|
self.add_require_statement(
|
||||||
|
"_reactJsxRuntime",
|
||||||
|
Self::new_string_literal(self.jsx_runtime_importer.as_str()),
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_import_jsx(&mut self) {
|
fn add_import_jsx(&mut self) {
|
||||||
if self.ctx.semantic().source_type().is_script() {
|
if self.ctx.source_type().is_script() {
|
||||||
self.add_require_jsx_runtime();
|
self.add_require_jsx_runtime();
|
||||||
} else if !self.import_jsx {
|
} else if !self.import_jsx {
|
||||||
self.import_jsx = true;
|
self.import_jsx = true;
|
||||||
|
|
@ -183,7 +187,7 @@ impl<'a> ReactJsx<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_import_jsxs(&mut self) {
|
fn add_import_jsxs(&mut self) {
|
||||||
if self.ctx.semantic().source_type().is_script() {
|
if self.ctx.source_type().is_script() {
|
||||||
self.add_require_jsx_runtime();
|
self.add_require_jsx_runtime();
|
||||||
} else if !self.import_jsxs {
|
} else if !self.import_jsxs {
|
||||||
self.import_jsxs = true;
|
self.import_jsxs = true;
|
||||||
|
|
@ -193,7 +197,7 @@ impl<'a> ReactJsx<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_import_fragment(&mut self) {
|
fn add_import_fragment(&mut self) {
|
||||||
if self.ctx.semantic().source_type().is_script() {
|
if self.ctx.source_type().is_script() {
|
||||||
self.add_require_jsx_runtime();
|
self.add_require_jsx_runtime();
|
||||||
} else if !self.import_fragment {
|
} else if !self.import_fragment {
|
||||||
self.import_fragment = true;
|
self.import_fragment = true;
|
||||||
|
|
@ -206,8 +210,17 @@ impl<'a> ReactJsx<'a> {
|
||||||
fn add_import_create_element(&mut self) {
|
fn add_import_create_element(&mut self) {
|
||||||
if !self.import_create_element {
|
if !self.import_create_element {
|
||||||
self.import_create_element = true;
|
self.import_create_element = true;
|
||||||
let source = Self::new_string_literal(self.options.import_source.as_ref());
|
|
||||||
self.add_import_statement("createElement", "_createElement", source);
|
if self.ctx.source_type().is_script() {
|
||||||
|
self.add_require_statement(
|
||||||
|
"_react",
|
||||||
|
Self::new_string_literal(self.options.import_source.as_ref()),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let source = Self::new_string_literal(self.options.import_source.as_ref());
|
||||||
|
self.add_import_statement("createElement", "_createElement", source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,7 +244,7 @@ impl<'a> ReactJsx<'a> {
|
||||||
self.imports.push(decl);
|
self.imports.push(decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_jsx_runtime(&mut self, source: StringLiteral) {
|
fn add_require_statement(&mut self, variable_name: &str, source: StringLiteral, front: bool) {
|
||||||
let callee = self
|
let callee = self
|
||||||
.ast
|
.ast
|
||||||
.identifier_reference_expression(IdentifierReference::new(SPAN, "require".into()));
|
.identifier_reference_expression(IdentifierReference::new(SPAN, "require".into()));
|
||||||
|
|
@ -240,10 +253,7 @@ impl<'a> ReactJsx<'a> {
|
||||||
.new_vec_single(Argument::Expression(self.ast.literal_string_expression(source)));
|
.new_vec_single(Argument::Expression(self.ast.literal_string_expression(source)));
|
||||||
let init = self.ast.call_expression(SPAN, callee, arguments, false, None);
|
let init = self.ast.call_expression(SPAN, callee, arguments, false, None);
|
||||||
let id = self.ast.binding_pattern(
|
let id = self.ast.binding_pattern(
|
||||||
self.ast.binding_pattern_identifier(BindingIdentifier::new(
|
self.ast.binding_pattern_identifier(BindingIdentifier::new(SPAN, variable_name.into())),
|
||||||
SPAN,
|
|
||||||
"_reactJsxRuntime".into(),
|
|
||||||
)),
|
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
@ -263,7 +273,11 @@ impl<'a> ReactJsx<'a> {
|
||||||
);
|
);
|
||||||
let stmt = Statement::Declaration(Declaration::VariableDeclaration(variable_declaration));
|
let stmt = Statement::Declaration(Declaration::VariableDeclaration(variable_declaration));
|
||||||
|
|
||||||
self.imports.push(stmt);
|
if front {
|
||||||
|
self.imports.insert(0, stmt);
|
||||||
|
} else {
|
||||||
|
self.imports.push(stmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_jsx<'b>(&mut self, e: &JSXElementOrFragment<'a, 'b>) -> Expression<'a> {
|
fn transform_jsx<'b>(&mut self, e: &JSXElementOrFragment<'a, 'b>) -> Expression<'a> {
|
||||||
|
|
@ -389,6 +403,17 @@ impl<'a> ReactJsx<'a> {
|
||||||
self.ast.identifier_reference_expression(ident)
|
self.ast.identifier_reference_expression(ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_static_member_expression(
|
||||||
|
&self,
|
||||||
|
object_ident_name: &str,
|
||||||
|
property_name: &str,
|
||||||
|
) -> Expression<'a> {
|
||||||
|
let property = IdentifierName::new(SPAN, property_name.into());
|
||||||
|
let ident = IdentifierReference::new(SPAN, object_ident_name.into());
|
||||||
|
let object = self.ast.identifier_reference_expression(ident);
|
||||||
|
self.ast.static_member_expression(SPAN, object, property, false)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the callee from `pragma` and `pragmaFrag`
|
/// Get the callee from `pragma` and `pragmaFrag`
|
||||||
fn get_call_expression_callee(&self, literal_callee: &str) -> Expression<'a> {
|
fn get_call_expression_callee(&self, literal_callee: &str) -> Expression<'a> {
|
||||||
let mut callee = literal_callee.split('.');
|
let mut callee = literal_callee.split('.');
|
||||||
|
|
@ -399,12 +424,7 @@ impl<'a> ReactJsx<'a> {
|
||||||
let ident = IdentifierReference::new(SPAN, member.into());
|
let ident = IdentifierReference::new(SPAN, member.into());
|
||||||
self.ast.identifier_reference_expression(ident)
|
self.ast.identifier_reference_expression(ident)
|
||||||
},
|
},
|
||||||
|property_name| {
|
|property_name| self.get_static_member_expression(member, property_name),
|
||||||
let property = IdentifierName::new(SPAN, property_name.into());
|
|
||||||
let ident = IdentifierReference::new(SPAN, member.into());
|
|
||||||
let object = self.ast.identifier_reference_expression(ident);
|
|
||||||
self.ast.static_member_expression(SPAN, object, property, false)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,31 +444,30 @@ impl<'a> ReactJsx<'a> {
|
||||||
self.get_call_expression_callee(self.options.pragma.as_ref())
|
self.get_call_expression_callee(self.options.pragma.as_ref())
|
||||||
}
|
}
|
||||||
ReactJsxRuntime::Automatic => {
|
ReactJsxRuntime::Automatic => {
|
||||||
let name = if has_key_after_props_spread {
|
let is_script = self.ctx.source_type().is_script();
|
||||||
"_createElement"
|
let name = if is_script {
|
||||||
} else if self.require_jsx_runtime {
|
if has_key_after_props_spread {
|
||||||
if jsxs {
|
"createElement"
|
||||||
|
} else if jsxs {
|
||||||
"jsxs"
|
"jsxs"
|
||||||
} else {
|
} else {
|
||||||
"jsx"
|
"jsx"
|
||||||
}
|
}
|
||||||
|
} else if has_key_after_props_spread {
|
||||||
|
"_createElement"
|
||||||
} else if jsxs {
|
} else if jsxs {
|
||||||
"_jsxs"
|
"_jsxs"
|
||||||
} else {
|
} else {
|
||||||
"_jsx"
|
"_jsx"
|
||||||
};
|
};
|
||||||
|
|
||||||
if has_key_after_props_spread || !self.require_jsx_runtime {
|
if is_script {
|
||||||
|
let object_ident_name =
|
||||||
|
if has_key_after_props_spread { "_react" } else { "_reactJsxRuntime" };
|
||||||
|
self.get_static_member_expression(object_ident_name, name)
|
||||||
|
} else {
|
||||||
let ident = IdentifierReference::new(SPAN, name.into());
|
let ident = IdentifierReference::new(SPAN, name.into());
|
||||||
self.ast.identifier_reference_expression(ident)
|
self.ast.identifier_reference_expression(ident)
|
||||||
} else {
|
|
||||||
let ident = IdentifierReference::new(SPAN, "_reactJsxRuntime".into());
|
|
||||||
self.ast.static_member_expression(
|
|
||||||
SPAN,
|
|
||||||
self.ast.identifier_reference_expression(ident),
|
|
||||||
IdentifierName::new(SPAN, name.into()),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -466,8 +485,12 @@ impl<'a> ReactJsx<'a> {
|
||||||
self.get_call_expression_callee(self.options.pragma_frag.as_ref())
|
self.get_call_expression_callee(self.options.pragma_frag.as_ref())
|
||||||
}
|
}
|
||||||
ReactJsxRuntime::Automatic => {
|
ReactJsxRuntime::Automatic => {
|
||||||
let ident = IdentifierReference::new(SPAN, "_Fragment".into());
|
if self.ctx.source_type().is_script() {
|
||||||
self.ast.identifier_reference_expression(ident)
|
self.get_static_member_expression("_reactJsxRuntime", "Fragment")
|
||||||
|
} else {
|
||||||
|
let ident = IdentifierReference::new(SPAN, "_Fragment".into());
|
||||||
|
self.ast.identifier_reference_expression(ident)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -854,7 +854,6 @@ Passed: 264/1113
|
||||||
|
|
||||||
# babel-plugin-transform-react-jsx (129/170)
|
# babel-plugin-transform-react-jsx (129/170)
|
||||||
* autoImport/after-polyfills-compiled-to-cjs/input.mjs
|
* autoImport/after-polyfills-compiled-to-cjs/input.mjs
|
||||||
* autoImport/auto-import-react-source-type-script/input.js
|
|
||||||
* autoImport/complicated-scope-module/input.js
|
* autoImport/complicated-scope-module/input.js
|
||||||
* react/adds-appropriate-newlines-when-using-spread-attribute-babel-7/input.js
|
* react/adds-appropriate-newlines-when-using-spread-attribute-babel-7/input.js
|
||||||
* react/arrow-functions/input.js
|
* react/arrow-functions/input.js
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue