@@ -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" ) ]
8081pub 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" ) ]
189146pub 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" ) ]
202228macro_rules! static_str {
203229 ( $s: expr) => { {
0 commit comments