Skip to content

Commit a0ceb6e

Browse files
magic-akarikdy1
authored andcommitted
fix(es/react): Run classic jsx transform before resolver pass (#10697)
**Related issue:** - #10553
1 parent 5467127 commit a0ceb6e

File tree

99 files changed

+682
-911
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+682
-911
lines changed

crates/swc/src/config/mod.rs

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -295,16 +295,42 @@ impl Options {
295295

296296
let mut transform = transform.into_inner().unwrap_or_default();
297297

298-
// Do a resolver pass before everything.
299-
//
300-
// We do this before creating custom passes, so custom passses can use the
301-
// variable management system based on the syntax contexts.
302298
if syntax.typescript() {
303299
assumptions.set_class_methods |= !transform.use_define_for_class_fields.into_bool();
304300
}
305301

306302
assumptions.set_public_class_fields |= !transform.use_define_for_class_fields.into_bool();
307303

304+
// Do a resolver pass before everything.
305+
//
306+
// We do this before creating custom passes, so custom passses can use the
307+
// variable management system based on the syntax contexts.
308+
//
309+
// Exception: Classic JSX transformation runs before the resolver
310+
// because it's a context-free syntactic transformation that doesn't require
311+
// scope information.
312+
// Running resolver first would mark identifiers (like JSX pragma functions)
313+
// with syntax contexts, making it harder for the JSX transform to
314+
// handle pragma references that should resolve to local scope declarations.
315+
316+
let jsx_pass = 'jsx_pass: {
317+
if !syntax.jsx() {
318+
break 'jsx_pass None;
319+
}
320+
321+
let (mut before_resolver, after_resolver) = react::react(
322+
cm.clone(),
323+
comments.cloned(),
324+
transform.react,
325+
top_level_mark,
326+
unresolved_mark,
327+
);
328+
329+
program.mutate(&mut before_resolver);
330+
331+
Some(after_resolver)
332+
};
333+
308334
program.visit_mut_with(&mut resolver(
309335
unresolved_mark,
310336
top_level_mark,
@@ -782,53 +808,17 @@ impl Options {
782808
..Default::default()
783809
};
784810

785-
(
786-
Optional::new(
787-
typescript::typescript(ts_config, unresolved_mark, top_level_mark),
788-
syntax.typescript() && !syntax.jsx(),
789-
),
790-
// [TODO]: Remove tsx
791-
Optional::new(
792-
{
793-
let (pragma, pragma_frag) = match transform.react.runtime {
794-
react::Runtime::Classic(ref config) => (
795-
Some(config.pragma.clone()),
796-
Some(config.pragma_frag.clone()),
797-
),
798-
_ => (None, None),
799-
};
800-
801-
typescript::tsx::<Option<&dyn Comments>>(
802-
cm.clone(),
803-
ts_config,
804-
typescript::TsxConfig {
805-
pragma,
806-
pragma_frag,
807-
},
808-
comments.map(|v| v as _),
809-
unresolved_mark,
810-
top_level_mark,
811-
)
812-
},
813-
syntax.typescript() && syntax.jsx(),
814-
),
811+
Optional::new(
812+
typescript::typescript(ts_config, unresolved_mark, top_level_mark),
813+
syntax.typescript(),
815814
)
816815
},
817816
),
818817
(
819818
plugin_transforms.take(),
820819
custom_before_pass(&program),
821820
// handle jsx
822-
Optional::new(
823-
react::react(
824-
cm.clone(),
825-
comments.cloned(),
826-
transform.react,
827-
top_level_mark,
828-
unresolved_mark,
829-
),
830-
syntax.jsx(),
831-
),
821+
jsx_pass,
832822
built_pass,
833823
Optional::new(jest::jest(), transform.hidden.jest.into_bool()),
834824
Optional::new(
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"jsc": {
3+
"parser": {
4+
"syntax": "ecmascript",
5+
"exportDefaultFrom": true,
6+
"jsx": true
7+
},
8+
"target": "es5",
9+
"loose": false,
10+
"minify": {
11+
"compress": false,
12+
"mangle": false
13+
},
14+
"transform": {
15+
"react": {
16+
"runtime": "classic"
17+
}
18+
}
19+
},
20+
"module": {
21+
"type": "es6"
22+
},
23+
"minify": false,
24+
"isModule": true
25+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function Home(React) {
2+
return <div>Hello World {count}</div>
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function Home(React) {
2+
return React.createElement("div", null, "Hello World ", count);
3+
}

crates/swc/tests/fixture/issues-2xxx/2214/input/.swcrc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
"parser": {
44
"syntax": "typescript",
55
"tsx": true
6+
},
7+
"transform": {
8+
"react": {
9+
"runtime": "classic"
10+
}
611
}
712
}
8-
}
13+
}
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
import { jsx as _jsx } from "react/jsx-runtime";
21
import React from "react";
32
(function(Test) {
4-
Test.content = /*#__PURE__*/ _jsx("div", {
5-
children: "Content"
6-
});
3+
Test.content = /*#__PURE__*/ React.createElement("div", null, "Content");
74
})(Test || (Test = {}));
85
export var Test;
Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
//// [file.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | import React = require('react');
6-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7-
//! 3 |
8-
//! 4 | interface Prop {
9-
//! 5 | a: number,
10-
//! `----
2+
function Comp(p) {
3+
return <div>{p.b}</div>;
4+
}
5+
// OK
6+
var k = <Comp a={10} b="hi" children="lol"/>;
7+
var k1 = <Comp a={10} b="hi">
8+
hi hi hi!
9+
</Comp>;
10+
var k2 = <Comp a={10} b="hi">
11+
<div>hi hi hi!</div>
12+
</Comp>;
Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
//// [file.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | import React = require('react');
6-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7-
//! 3 |
8-
//! 4 | interface Prop {
9-
//! 5 | a: number,
10-
//! `----
2+
function Comp(p) {
3+
return <div>{p.b}</div>;
4+
}
5+
<Comp a={10} b="hi" children="lol"/>, <Comp a={10} b="hi">
6+
hi hi hi!
7+
</Comp>, <Comp a={10} b="hi">
8+
<div>hi hi hi!</div>
9+
</Comp>;
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
//// [file.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | import React = require('react');
6-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7-
//! 3 |
8-
//! 4 | const Tag = (x: {}) => <div></div>;
9-
//! `----
2+
var Tag = function(x) {
3+
return <div></div>;
4+
};
5+
// OK
6+
var k1 = <Tag/>;
7+
var k2 = <Tag></Tag>;
8+
// Not OK (excess children)
9+
var k3 = <Tag children={<div></div>}/>;
10+
var k4 = <Tag key="1"><div></div></Tag>;
11+
var k5 = <Tag key="1"><div></div><div></div></Tag>;
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
//// [file.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | import React = require('react');
6-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7-
//! 3 |
8-
//! 4 | const Tag = (x: {}) => <div></div>;
9-
//! `----
2+
var Tag = function(x) {
3+
return <div></div>;
4+
};
5+
<Tag/>, <Tag></Tag>, <Tag children={<div></div>}/>, <Tag key="1"><div></div></Tag>, <Tag key="1"><div></div><div></div></Tag>;
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//// [checkJsxChildrenProperty16.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[6:1]
4-
//! 3 |
5-
//! 4 | // repro from #53493
6-
//! 5 |
7-
//! 6 | import React = require('react');
8-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9-
//! 7 |
10-
//! 8 | export type Props =
11-
//! 9 | | { renderNumber?: false; children: (arg: string) => void }
12-
//! `----
2+
/// <reference path="/.lib/react16.d.ts" />
3+
// repro from #53493
4+
export var Test = function() {
5+
return <>
6+
<Foo>{function(value) {}}</Foo>
7+
<Foo renderNumber>{function(value) {}}</Foo>
8+
9+
<Foo children={function(value) {}}/>
10+
<Foo renderNumber children={function(value) {}}/>
11+
</>;
12+
};
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
//// [checkJsxChildrenProperty16.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[6:1]
4-
//! 3 |
5-
//! 4 | // repro from #53493
6-
//! 5 |
7-
//! 6 | import React = require('react');
8-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9-
//! 7 |
10-
//! 8 | export type Props =
11-
//! 9 | | { renderNumber?: false; children: (arg: string) => void }
12-
//! `----
2+
export var Test = function() {
3+
return <>
4+
<Foo>{function(value) {}}</Foo>
5+
<Foo renderNumber>{function(value) {}}</Foo>
6+
7+
<Foo children={function(value) {}}/>
8+
<Foo renderNumber children={function(value) {}}/>
9+
</>;
10+
};
Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
11
//// [file.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | import React = require('react');
6-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7-
//! 3 |
8-
//! 4 | interface Prop {
9-
//! 5 | a: number,
10-
//! `----
2+
function Comp(p) {
3+
return <div>{p.b}</div>;
4+
}
5+
// Error: missing children
6+
var k = <Comp a={10} b="hi"/>;
7+
var k0 = <Comp a={10} b="hi" children="Random">
8+
hi hi hi!
9+
</Comp>;
10+
var o = {
11+
children: "Random"
12+
};
13+
var k1 = <Comp a={10} b="hi" {...o}>
14+
hi hi hi!
15+
</Comp>;
16+
// Error: incorrect type
17+
var k2 = <Comp a={10} b="hi">
18+
<div> My Div </div>
19+
{function(name) {
20+
return <div> My name {name} </div>;
21+
}}
22+
</Comp>;
23+
var k3 = <Comp a={10} b="hi">
24+
<div> My Div </div>
25+
{1000000}
26+
</Comp>;
27+
var k4 = <Comp a={10} b="hi">
28+
<div> My Div </div>
29+
hi hi hi!
30+
</Comp>;
31+
var k5 = <Comp a={10} b="hi">
32+
<div> My Div </div>
33+
<div> My Div </div>
34+
</Comp>;
Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
//// [file.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | import React = require('react');
6-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7-
//! 3 |
8-
//! 4 | interface Prop {
9-
//! 5 | a: number,
10-
//! `----
2+
function Comp(p) {
3+
return <div>{p.b}</div>;
4+
}
5+
<Comp a={10} b="hi"/>, <Comp a={10} b="hi" children="Random">
6+
hi hi hi!
7+
</Comp>, <Comp a={10} b="hi" {...{
8+
children: "Random"
9+
}}>
10+
hi hi hi!
11+
</Comp>, <Comp a={10} b="hi">
12+
<div> My Div </div>
13+
{function(name) {
14+
return <div> My name {name} </div>;
15+
}}
16+
</Comp>, <Comp a={10} b="hi">
17+
<div> My Div </div>
18+
{1000000}
19+
</Comp>, <Comp a={10} b="hi">
20+
<div> My Div </div>
21+
hi hi hi!
22+
</Comp>, <Comp a={10} b="hi">
23+
<div> My Div </div>
24+
<div> My Div </div>
25+
</Comp>;
Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
//// [file.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | import React = require('react');
6-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7-
//! 3 |
8-
//! 4 | // OK
9-
//! 5 | let k1 = <div> <h2> Hello </h2> <h1> world </h1></div>;
10-
//! `----
2+
// OK
3+
var k1 = <div> <h2> Hello </h2> <h1> world </h1></div>;
4+
var k2 = <div> <h2> Hello </h2> {function(user) {
5+
return <h2>{user.name}</h2>;
6+
}}</div>;
7+
var k3 = <div> {1} {"That is a number"} </div>;
Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
//// [file.tsx]
2-
//! x Import assignment cannot be used when targeting ECMAScript modules. Consider using `import * as ns from "mod"`, `import {a} from "mod"`, `import d from "mod"`, or another module format instead.
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | import React = require('react');
6-
//! : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7-
//! 3 |
8-
//! 4 | // OK
9-
//! 5 | let k1 = <div> <h2> Hello </h2> <h1> world </h1></div>;
10-
//! `----
2+
<div> <h2> Hello </h2> <h1> world </h1></div>, <div> <h2> Hello </h2> {function(user) {
3+
return <h2>{user.name}</h2>;
4+
}}</div>, <div> {1} {"That is a number"} </div>;

0 commit comments

Comments
 (0)