Skip to content

Commit 4e1ec35

Browse files
magic-akarikdy1
authored andcommitted
refactor(es/react): Add preserve supports and ts config style preset (#10691)
- #9929
1 parent 425167c commit 4e1ec35

File tree

7 files changed

+129
-136
lines changed

7 files changed

+129
-136
lines changed

bindings/binding_core_wasm/src/types.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -793,14 +793,16 @@ export interface EsParserConfig {
793793
importAssertions?: boolean;
794794
}
795795
796+
type JSXPreset = "react" | "react-jsx" | "react-jsxdev" | "preserve" | "react-native";
797+
796798
/**
797799
* Options for transform.
798800
*/
799801
export interface TransformConfig {
800802
/**
801-
* Effective only if `syntax` supports ƒ.
803+
* Effective only if `syntax` supports.
802804
*/
803-
react?: ReactConfig;
805+
react?: JSXPreset | ReactConfig;
804806
805807
constModules?: ConstModulesConfig;
806808
@@ -889,7 +891,7 @@ export interface ReactConfig {
889891
/**
890892
* jsx runtime
891893
*/
892-
runtime?: 'automatic' | 'classic'
894+
runtime?: 'automatic' | 'classic' | 'preserve';
893895
894896
/**
895897
* Declares the module specifier to be used for importing the `jsx` and `jsxs` factory functions when using `runtime` 'automatic'

crates/swc/tests/fixture/issues-1xxx/1525/case1/input/.swcrc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
"tsx": true
1111
},
1212
"transform": {
13-
"react": {
14-
"runtime": "classic"
15-
}
13+
"react": "react"
1614
}
1715
},
1816
"module": {

crates/swc/tests/fixture/issues-1xxx/1687/.input/.swcrc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@
77
"dynamicImport": true
88
},
99
"transform": {
10-
"react": {
11-
"runtime": "automatic"
12-
}
10+
"react": "react-jsx"
1311
},
1412
"externalHelpers": true
1513
},
1614
"env": {
1715
"coreJs": "3",
1816
"mode": "usage"
1917
}
20-
}
18+
}

crates/swc/tests/fixture/issues-8xxx/8210/input/.swcrc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
"mangle": false
1212
},
1313
"transform": {
14-
"react": {
15-
"development": true,
16-
"runtime": "automatic"
17-
}
14+
"react": "react-jsxdev"
1815
}
1916
},
2017
"module": {

crates/swc/tests/tsc.rs

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -142,40 +142,10 @@ fn matrix(input: &Path) -> Vec<TestUnitData> {
142142
.collect();
143143

144144
for value in values {
145-
match value.as_str() {
146-
"react-jsx" => {
147-
let options = react::Options {
148-
runtime: react::Runtime::Automatic(Default::default()),
149-
..Default::default()
150-
};
151-
react.push(options);
152-
}
153-
"react-jsxdev" => {
154-
let options = react::Options {
155-
runtime: react::Runtime::Automatic(Default::default()),
156-
common: react::CommonConfig {
157-
development: true.into(),
158-
..Default::default()
159-
},
160-
..Default::default()
161-
};
162-
react.push(options);
163-
}
164-
"preserve" => {
165-
react.push(react::Options {
166-
runtime: react::Runtime::Preserve,
167-
..Default::default()
168-
});
169-
}
170-
"react" => {
171-
let options = react::Options {
172-
runtime: react::Runtime::Classic(Default::default()),
173-
..Default::default()
174-
};
175-
react.push(options);
176-
}
177-
_ => {}
178-
}
145+
let Ok(options) = react::Options::try_from(value.as_str()) else {
146+
continue;
147+
};
148+
react.push(options);
179149
}
180150
}
181151
"removecomments" => {}

crates/swc_ecma_transforms_react/src/jsx/mod.rs

Lines changed: 111 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ impl Default for ClassicConfig {
7676
}
7777
}
7878

79-
#[derive(Debug, Clone, Serialize)]
79+
#[derive(Debug, Clone, Serialize, Deserialize)]
80+
#[serde(try_from = "RuntimeRaw")]
8081
pub enum Runtime {
8182
Classic(ClassicConfig),
8283
Automatic(AutomaticConfig),
@@ -95,97 +96,53 @@ impl Merge for Runtime {
9596
}
9697
}
9798

98-
impl<'de> Deserialize<'de> for Runtime {
99-
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100-
where
101-
D: serde::Deserializer<'de>,
102-
{
103-
use std::fmt;
104-
105-
use serde::de::{Error, Visitor};
106-
107-
struct RuntimeVisitor;
108-
109-
impl<'de> Visitor<'de> for RuntimeVisitor {
110-
type Value = Runtime;
111-
112-
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
113-
formatter.write_str("a string or an object for runtime configuration")
114-
}
115-
116-
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
117-
where
118-
E: Error,
119-
{
120-
match value {
121-
"automatic" => Ok(Runtime::Automatic(AutomaticConfig::default())),
122-
"classic" => Ok(Runtime::Classic(ClassicConfig::default())),
123-
"preserve" => Ok(Runtime::Preserve),
124-
_ => Err(Error::unknown_variant(
125-
value,
126-
&["automatic", "classic", "preserve"],
127-
)),
128-
}
129-
}
130-
131-
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
132-
where
133-
A: serde::de::MapAccess<'de>,
134-
{
135-
#[derive(Deserialize)]
136-
#[serde(rename_all = "camelCase")]
137-
struct ConfigHelper {
138-
runtime: Option<String>,
139-
pragma: Option<BytesStr>,
140-
pragma_frag: Option<BytesStr>,
141-
import_source: Option<Atom>,
142-
}
99+
#[derive(Deserialize)]
100+
#[serde(rename_all = "camelCase")]
101+
struct RuntimeRaw {
102+
#[serde(default)]
103+
runtime: Option<String>,
104+
#[serde(default)]
105+
pragma: Option<BytesStr>,
106+
#[serde(default)]
107+
pragma_frag: Option<BytesStr>,
108+
#[serde(default)]
109+
import_source: Option<Atom>,
110+
}
143111

144-
let helper: ConfigHelper =
145-
Deserialize::deserialize(serde::de::value::MapAccessDeserializer::new(map))?;
146-
147-
match helper.runtime.as_deref() {
148-
Some("automatic") => {
149-
let config = AutomaticConfig {
150-
import_source: helper
151-
.import_source
152-
.unwrap_or_else(default_import_source),
153-
};
154-
Ok(Runtime::Automatic(config))
155-
}
156-
Some("classic") => {
157-
let config = ClassicConfig {
158-
pragma: helper.pragma.unwrap_or_else(default_pragma),
159-
pragma_frag: helper.pragma_frag.unwrap_or_else(default_pragma_frag),
160-
};
161-
Ok(Runtime::Classic(config))
162-
}
163-
Some("preserve") => Ok(Runtime::Preserve),
164-
Some(other) => Err(Error::unknown_variant(
165-
other,
166-
&["automatic", "classic", "preserve"],
167-
)),
168-
None => match (helper.pragma, helper.pragma_frag, helper.import_source) {
169-
(pragma @ Some(..), pragma_frag, None)
170-
| (pragma, pragma_frag @ Some(..), None) => {
171-
Ok(Runtime::Classic(ClassicConfig {
172-
pragma: pragma.unwrap_or_else(default_pragma),
173-
pragma_frag: pragma_frag.unwrap_or_else(default_pragma_frag),
174-
}))
175-
}
176-
(_, _, import_source) => Ok(Runtime::Automatic(AutomaticConfig {
177-
import_source: import_source.unwrap_or_else(default_import_source),
178-
})),
179-
},
112+
impl TryFrom<RuntimeRaw> for Runtime {
113+
type Error = String;
114+
115+
fn try_from(raw: RuntimeRaw) -> Result<Self, Self::Error> {
116+
match raw.runtime.as_deref() {
117+
Some("automatic") => Ok(Runtime::Automatic(AutomaticConfig {
118+
import_source: raw.import_source.unwrap_or_else(default_import_source),
119+
})),
120+
Some("classic") => Ok(Runtime::Classic(ClassicConfig {
121+
pragma: raw.pragma.unwrap_or_else(default_pragma),
122+
pragma_frag: raw.pragma_frag.unwrap_or_else(default_pragma_frag),
123+
})),
124+
Some("preserve") => Ok(Runtime::Preserve),
125+
Some(other) => Err(format!(
126+
"unknown runtime variant `{other}`, expected one of `automatic`, `classic`, \
127+
`preserve`"
128+
)),
129+
None => match (raw.pragma, raw.pragma_frag, raw.import_source) {
130+
(pragma @ Some(..), pragma_frag, None) | (pragma, pragma_frag @ Some(..), None) => {
131+
Ok(Runtime::Classic(ClassicConfig {
132+
pragma: pragma.unwrap_or_else(default_pragma),
133+
pragma_frag: pragma_frag.unwrap_or_else(default_pragma_frag),
134+
}))
180135
}
181-
}
136+
(_, _, import_source) => Ok(Runtime::Automatic(AutomaticConfig {
137+
import_source: import_source.unwrap_or_else(default_import_source),
138+
})),
139+
},
182140
}
183-
184-
deserializer.deserialize_any(RuntimeVisitor)
185141
}
186142
}
187143

188144
#[derive(Debug, Clone, Serialize, Deserialize, Default, Merge)]
145+
#[serde(try_from = "OptionsRaw")]
189146
pub struct Options {
190147
#[serde(flatten)]
191148
pub runtime: Runtime,
@@ -198,6 +155,75 @@ pub struct Options {
198155
pub refresh: Option<RefreshOptions>,
199156
}
200157

158+
impl TryFrom<&str> for Options {
159+
type Error = String;
160+
161+
fn try_from(s: &str) -> Result<Self, Self::Error> {
162+
match s {
163+
"react" => Ok(Options {
164+
runtime: Runtime::Classic(ClassicConfig::default()),
165+
common: CommonConfig::default(),
166+
refresh: None,
167+
}),
168+
"react-jsx" => Ok(Options {
169+
runtime: Runtime::Automatic(AutomaticConfig::default()),
170+
common: CommonConfig::default(),
171+
refresh: None,
172+
}),
173+
"react-jsxdev" => Ok(Options {
174+
runtime: Runtime::Automatic(AutomaticConfig::default()),
175+
common: CommonConfig {
176+
development: true.into(),
177+
..CommonConfig::default()
178+
},
179+
refresh: None,
180+
}),
181+
"preserve" | "react-native" => Ok(Options {
182+
runtime: Runtime::Preserve,
183+
common: CommonConfig::default(),
184+
refresh: None,
185+
}),
186+
other => Err(format!(
187+
"unknown preset `{other}`, expected one of `react`, `react-jsx`, `react-jsxdev`, \
188+
`preserve`, `react-native`"
189+
)),
190+
}
191+
}
192+
}
193+
194+
#[derive(Deserialize)]
195+
#[serde(untagged)]
196+
enum OptionsRaw {
197+
Preset(String),
198+
Object {
199+
#[serde(flatten)]
200+
runtime: Runtime,
201+
#[serde(flatten)]
202+
common: CommonConfig,
203+
#[serde(default, deserialize_with = "deserialize_refresh")]
204+
refresh: Option<RefreshOptions>,
205+
},
206+
}
207+
208+
impl TryFrom<OptionsRaw> for Options {
209+
type Error = String;
210+
211+
fn try_from(raw: OptionsRaw) -> Result<Self, Self::Error> {
212+
match raw {
213+
OptionsRaw::Preset(preset) => preset.as_str().try_into(),
214+
OptionsRaw::Object {
215+
runtime,
216+
common,
217+
refresh,
218+
} => Ok(Options {
219+
runtime,
220+
common,
221+
refresh,
222+
}),
223+
}
224+
}
225+
}
226+
201227
#[cfg(feature = "concurrent")]
202228
macro_rules! static_str {
203229
($s:expr) => {{

packages/types/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -836,14 +836,16 @@ export interface EsParserConfig {
836836
explicitResourceManagement?: boolean;
837837
}
838838

839+
type JSXPreset = "react" | "react-jsx" | "react-jsxdev" | "preserve" | "react-native";
840+
839841
/**
840842
* Options for transform.
841843
*/
842844
export interface TransformConfig {
843845
/**
844-
* Effective only if `syntax` supports ƒ.
846+
* Effective only if `syntax` supports.
845847
*/
846-
react?: ReactConfig;
848+
react?: JSXPreset | ReactConfig;
847849

848850
constModules?: ConstModulesConfig;
849851

@@ -946,7 +948,7 @@ export interface ReactConfig {
946948
/**
947949
* jsx runtime
948950
*/
949-
runtime?: "automatic" | "classic";
951+
runtime?: "automatic" | "classic" | "preserve";
950952

951953
/**
952954
* Declares the module specifier to be used for importing the `jsx` and `jsxs` factory functions when using `runtime` 'automatic'

0 commit comments

Comments
 (0)