Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions crates/oxc_transformer/src/jsx/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,3 @@ pub fn valueless_key(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Please provide an explicit key value. Using \"key\" as a shorthand for \"key={true}\" is not allowed.")
.with_label(span)
}

pub fn spread_children_are_not_supported(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Spread children are not supported in React.").with_label(span)
}
46 changes: 37 additions & 9 deletions crates/oxc_transformer/src/jsx/jsx_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ impl<'a> JsxImpl<'a, '_> {
// Append children to object properties in automatic mode
if is_automatic {
let mut children = ctx.ast.vec_from_iter(
children.iter().filter_map(|child| self.transform_jsx_child(child, ctx)),
children.iter().filter_map(|child| self.transform_jsx_child_automatic(child, ctx)),
);
children_len = children.len();
if children_len != 0 {
Expand Down Expand Up @@ -750,10 +750,7 @@ impl<'a> JsxImpl<'a, '_> {
// React.createElement(type, arguments, ...children)
// ^^^^^^^^^^^
arguments.extend(
children
.iter()
.filter_map(|child| self.transform_jsx_child(child, ctx))
.map(Argument::from),
children.iter().filter_map(|child| self.transform_jsx_child_classic(child, ctx)),
);
}

Expand Down Expand Up @@ -883,6 +880,40 @@ impl<'a> JsxImpl<'a, '_> {
}
}

fn transform_jsx_child_automatic(
&mut self,
child: &JSXChild<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<Expression<'a>> {
// Align spread child behavior with esbuild.
// Instead of Babel throwing `Spread children are not supported in React.`
// `<>{...foo}</>` -> `jsxs(Fragment, { children: [ ...foo ] })`
if let JSXChild::Spread(e) = child {
// SAFETY: `ast.copy` is unsound! We need to fix.
let argument = unsafe { ctx.ast.copy(&e.expression) };
let spread_element = ctx.ast.array_expression_element_spread_element(e.span, argument);
let elements = ctx.ast.vec1(spread_element);
return Some(ctx.ast.expression_array(e.span, elements, None));
}
self.transform_jsx_child(child, ctx)
}

fn transform_jsx_child_classic(
&mut self,
child: &JSXChild<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<Argument<'a>> {
// Align spread child behavior with esbuild.
// Instead of Babel throwing `Spread children are not supported in React.`
// `<>{...foo}</>` -> `React.createElement(React.Fragment, null, ...foo)`
if let JSXChild::Spread(e) = child {
// SAFETY: `ast.copy` is unsound! We need to fix.
let argument = unsafe { ctx.ast.copy(&e.expression) };
return Some(ctx.ast.argument_spread_element(e.span, argument));
}
self.transform_jsx_child(child, ctx).map(Argument::from)
}

fn transform_jsx_child(
&mut self,
child: &JSXChild<'a>,
Expand All @@ -903,10 +934,7 @@ impl<'a> JsxImpl<'a, '_> {
JSXChild::Fragment(e) => {
Some(self.transform_jsx(&JSXElementOrFragment::Fragment(e), ctx))
}
JSXChild::Spread(e) => {
self.ctx.error(diagnostics::spread_children_are_not_supported(e.span));
None
}
JSXChild::Spread(_) => unreachable!(),
}
}

Expand Down
15 changes: 12 additions & 3 deletions tasks/coverage/snapshots/semantic_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -39578,11 +39578,20 @@ after transform: ScopeId(0): [ScopeId(1), ScopeId(2)]
rebuilt : ScopeId(0): [ScopeId(1)]

tasks/coverage/typescript/tests/cases/conformance/jsx/tsxSpreadChildren.tsx
semantic error: Spread children are not supported in React.
semantic error: Bindings mismatch:
after transform: ScopeId(0): ["JSX", "React", "Todo", "TodoList", "_jsxFileName", "_objectSpread", "_reactJsxRuntime", "x"]
rebuilt : ScopeId(0): ["Todo", "TodoList", "_jsxFileName", "_objectSpread", "_reactJsxRuntime", "x"]
Scope children mismatch:
after transform: ScopeId(0): [ScopeId(1), ScopeId(4), ScopeId(5), ScopeId(6), ScopeId(7)]
rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)]

tasks/coverage/typescript/tests/cases/conformance/jsx/tsxSpreadChildrenInvalidType.tsx
semantic error: Spread children are not supported in React.
Spread children are not supported in React.
semantic error: Bindings mismatch:
after transform: ScopeId(0): ["JSX", "React", "Todo", "TodoList", "TodoListNoError", "_jsxFileName", "_objectSpread", "_reactJsxRuntime", "x"]
rebuilt : ScopeId(0): ["Todo", "TodoList", "TodoListNoError", "_jsxFileName", "_objectSpread", "_reactJsxRuntime", "x"]
Scope children mismatch:
after transform: ScopeId(0): [ScopeId(1), ScopeId(4), ScopeId(5), ScopeId(6), ScopeId(7), ScopeId(8)]
rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(3)]

tasks/coverage/typescript/tests/cases/conformance/jsx/tsxStatelessFunctionComponentOverload2.tsx
semantic error: Scope children mismatch:
Expand Down
4 changes: 2 additions & 2 deletions tasks/transform_conformance/snapshots/oxc.snap.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
commit: acbc09a8

Passed: 133/155
Passed: 135/157

# All Passed:
* babel-plugin-transform-class-static-block
Expand Down Expand Up @@ -308,7 +308,7 @@ rebuilt : SymbolId(2): []
x Output mismatch


# babel-plugin-transform-react-jsx (35/38)
# babel-plugin-transform-react-jsx (37/40)
* refresh/does-not-transform-it-because-it-is-not-used-in-the-AST/input.jsx
x Output mismatch

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<>{...foo}</>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"plugins": [
[
"transform-react-jsx",
{
"runtime": "automatic"
}
]
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var _reactJsxRuntime = require("react/jsx-runtime");
_reactJsxRuntime.jsx(_reactJsxRuntime.Fragment, { children: [...foo] });
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<>{...foo}</>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"plugins": [
[
"transform-react-jsx",
{
"runtime": "classic"
}
]
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
React.createElement(React.Fragment, null, ...foo);
Loading