@@ -76,7 +76,8 @@ impl Default for ClassicConfig {
76
76
}
77
77
}
78
78
79
- #[ derive( Debug , Clone , Serialize ) ]
79
+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
80
+ #[ serde( try_from = "RuntimeRaw" ) ]
80
81
pub enum Runtime {
81
82
Classic ( ClassicConfig ) ,
82
83
Automatic ( AutomaticConfig ) ,
@@ -95,97 +96,53 @@ impl Merge for Runtime {
95
96
}
96
97
}
97
98
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
+ }
143
111
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
+ } ) )
180
135
}
181
- }
136
+ ( _, _, import_source) => Ok ( Runtime :: Automatic ( AutomaticConfig {
137
+ import_source : import_source. unwrap_or_else ( default_import_source) ,
138
+ } ) ) ,
139
+ } ,
182
140
}
183
-
184
- deserializer. deserialize_any ( RuntimeVisitor )
185
141
}
186
142
}
187
143
188
144
#[ derive( Debug , Clone , Serialize , Deserialize , Default , Merge ) ]
145
+ #[ serde( try_from = "OptionsRaw" ) ]
189
146
pub struct Options {
190
147
#[ serde( flatten) ]
191
148
pub runtime : Runtime ,
@@ -198,6 +155,75 @@ pub struct Options {
198
155
pub refresh : Option < RefreshOptions > ,
199
156
}
200
157
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
+
201
227
#[ cfg( feature = "concurrent" ) ]
202
228
macro_rules! static_str {
203
229
( $s: expr) => { {
0 commit comments