Skip to content

Commit 7aabf91

Browse files
Copilotjakebailey
andcommitted
Fix regression: preserve previous inJsxChild state in nested transforms
The previous fix incorrectly cleared the inJsxChild flag when transforming nested JSX children. When transforming a nested child element, the defer statement would set inJsxChild back to false, causing the parent element to not receive the EFStartOnNewLine flag. Fixed by saving and restoring the previous value of inJsxChild instead of unconditionally setting it to false. This ensures that the flag state is properly maintained across nested transformations. Also fixed the logic for adding EFStartOnNewLine to children: the flag should only be added when there are multiple children AFTER filtering out null/whitespace children, not before. This matches TypeScript's behavior where a single child expression does not get a newline, but multiple children do. These fixes resolve the regression in commentsOnJSXExpressionsArePreserved tests, where a single JSX expression child was incorrectly getting a newline. Co-authored-by: jakebailey <[email protected]>
1 parent b45754a commit 7aabf91

File tree

31 files changed

+59
-246
lines changed

31 files changed

+59
-246
lines changed

internal/transformers/jsxtransforms/jsx.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,9 @@ func (tx *JSXTransformer) convertJsxChildrenToChildrenPropObject(children []*ast
319319
}
320320

321321
func (tx *JSXTransformer) transformJsxChildToExpression(node *ast.Node) *ast.Node {
322+
prev := tx.inJsxChild
322323
tx.setInChild(true)
323-
defer tx.setInChild(false)
324+
defer tx.setInChild(prev)
324325
return tx.Visitor().Visit(node)
325326
}
326327

@@ -688,14 +689,18 @@ func (tx *JSXTransformer) visitJsxOpeningLikeElementCreateElement(element *ast.N
688689
for _, c := range children.Nodes {
689690
res := tx.transformJsxChildToExpression(c)
690691
if res != nil {
691-
if len(children.Nodes) > 1 {
692-
tx.EmitContext().AddEmitFlags(res, printer.EFStartOnNewLine)
693-
}
694692
newChildren = append(newChildren, res)
695693
}
696694
}
697695
}
698696

697+
// Add StartOnNewLine flag only if there are multiple actual children (after filtering)
698+
if len(newChildren) > 1 {
699+
for _, child := range newChildren {
700+
tx.EmitContext().AddEmitFlags(child, printer.EFStartOnNewLine)
701+
}
702+
}
703+
699704
args := make([]*ast.Expression, 0, len(newChildren)+2)
700705
args = append(args, tagName)
701706
args = append(args, objectProperties)
@@ -725,14 +730,18 @@ func (tx *JSXTransformer) visitJsxOpeningFragmentCreateElement(fragment *ast.Jsx
725730
for _, c := range children.Nodes {
726731
res := tx.transformJsxChildToExpression(c)
727732
if res != nil {
728-
if len(children.Nodes) > 1 {
729-
tx.EmitContext().AddEmitFlags(res, printer.EFStartOnNewLine)
730-
}
731733
newChildren = append(newChildren, res)
732734
}
733735
}
734736
}
735737

738+
// Add StartOnNewLine flag only if there are multiple actual children (after filtering)
739+
if len(newChildren) > 1 {
740+
for _, child := range newChildren {
741+
tx.EmitContext().AddEmitFlags(child, printer.EFStartOnNewLine)
742+
}
743+
}
744+
736745
args := make([]*ast.Expression, 0, len(newChildren)+2)
737746
args = append(args, tagName)
738747
args = append(args, tx.Factory().NewKeywordExpression(ast.KindNullKeyword))

testdata/baselines/reference/compiler/jsxUnicodeEscapeSequence.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ export const InlineUnicodeChar = () => {
3434
};
3535
export const StandaloneUnicodeChar = () => {
3636
// This should reproduce the issue - unicode character on its own line
37-
return (_jsxs("div", { children: [_jsx("span", { children: "\u26A0" }), "\u26A0"] }));
37+
return (_jsxs("div", { children: [
38+
_jsx("span", { children: "\u26A0" }),
39+
"\u26A0"] }));
3840
};
3941
export const MultipleUnicodeChars = () => {
4042
// Test multiple unicode characters

testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=auto).js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class Component {
2525
//// [commentsOnJSXExpressionsArePreserved.js]
2626
class Component {
2727
render() {
28-
return React.createElement("div", null,
29-
null /* preserved */);
28+
return React.createElement("div", null, null /* preserved */);
3029
}
3130
}

testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=auto).js.diff

Lines changed: 0 additions & 11 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=force).js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ class Component {
2727
Object.defineProperty(exports, "__esModule", { value: true });
2828
class Component {
2929
render() {
30-
return React.createElement("div", null,
31-
null /* preserved */);
30+
return React.createElement("div", null, null /* preserved */);
3231
}
3332
}

testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=force).js.diff

Lines changed: 0 additions & 11 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=legacy).js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class Component {
2525
//// [commentsOnJSXExpressionsArePreserved.js]
2626
class Component {
2727
render() {
28-
return React.createElement("div", null,
29-
null /* preserved */);
28+
return React.createElement("div", null, null /* preserved */);
3029
}
3130
}

testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=legacy).js.diff

Lines changed: 0 additions & 11 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/jsxChildrenIndividualErrorElaborations.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ function Blah(props) {
9090
return React.createElement(React.Fragment, null);
9191
}
9292
// Incompatible child.
93-
var a = React.createElement(Blah, null,
94-
x => x);
93+
var a = React.createElement(Blah, null, x => x);
9594
// Blah components don't accept text as child elements
9695
var a = React.createElement(Blah, null, "Hello unexpected text!");
9796
// Blah components don't accept multiple children.
@@ -102,8 +101,7 @@ function Blah2(props) {
102101
return React.createElement(React.Fragment, null);
103102
}
104103
// Incompatible child.
105-
var a = React.createElement(Blah2, null,
106-
x => x);
104+
var a = React.createElement(Blah2, null, x => x);
107105
// Blah2 components don't accept text as child elements
108106
var a = React.createElement(Blah2, null, "Hello unexpected text!");
109107
// Blah2 components don't accept multiple children of the wrong type.
@@ -114,8 +112,7 @@ function Blah3(props) {
114112
return React.createElement(React.Fragment, null);
115113
}
116114
// Incompatible child.
117-
var a = React.createElement(Blah3, null,
118-
x => x);
115+
var a = React.createElement(Blah3, null, x => x);
119116
// Blah3 components don't accept text as child elements
120117
var a = React.createElement(Blah3, null, "Hello unexpected text!");
121118
// Blah3 components don't accept multiple children of the wrong type.

testdata/baselines/reference/submodule/compiler/jsxChildrenIndividualErrorElaborations.js.diff

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,4 @@
88
+const React = require("react");
99
function Blah(props) {
1010
return React.createElement(React.Fragment, null);
11-
}
12-
// Incompatible child.
13-
-var a = React.createElement(Blah, null, x => x);
14-
+var a = React.createElement(Blah, null,
15-
+ x => x);
16-
// Blah components don't accept text as child elements
17-
var a = React.createElement(Blah, null, "Hello unexpected text!");
18-
// Blah components don't accept multiple children.
19-
@@= skipped -16, +17 lines =@@
20-
return React.createElement(React.Fragment, null);
21-
}
22-
// Incompatible child.
23-
-var a = React.createElement(Blah2, null, x => x);
24-
+var a = React.createElement(Blah2, null,
25-
+ x => x);
26-
// Blah2 components don't accept text as child elements
27-
var a = React.createElement(Blah2, null, "Hello unexpected text!");
28-
// Blah2 components don't accept multiple children of the wrong type.
29-
@@= skipped -11, +12 lines =@@
30-
return React.createElement(React.Fragment, null);
31-
}
32-
// Incompatible child.
33-
-var a = React.createElement(Blah3, null, x => x);
34-
+var a = React.createElement(Blah3, null,
35-
+ x => x);
36-
// Blah3 components don't accept text as child elements
37-
var a = React.createElement(Blah3, null, "Hello unexpected text!");
38-
// Blah3 components don't accept multiple children of the wrong type.
11+
}

0 commit comments

Comments
 (0)