1
- use crate :: typescript:: convert_type;
2
1
use crate :: { utils, BuildState } ;
3
2
use convert_case:: { Case , Casing } ;
4
3
use syn:: __private:: ToTokens ;
@@ -9,26 +8,6 @@ use syn::__private::ToTokens;
9
8
/// `rename_all` attributes for the name of the tag will also be adhered to.
10
9
impl super :: ToTypescript for syn:: ItemEnum {
11
10
fn convert_to_ts ( self , state : & mut BuildState , config : & crate :: BuildSettings ) {
12
- // check we don't have any tuple structs that could mess things up.
13
- // if we do ignore this struct
14
- for variant in self . variants . iter ( ) {
15
- // allow single-field tuple structs to pass through as newtype structs
16
- let mut is_newtype = false ;
17
- for f in variant. fields . iter ( ) {
18
- if f. ident . is_none ( ) {
19
- // If we already marked this variant as a newtype, we have a multi-field tuple struct
20
- if is_newtype {
21
- if crate :: DEBUG . try_get ( ) . is_some_and ( |d| * d) {
22
- println ! ( "#[tsync] failed for enum {}" , self . ident) ;
23
- }
24
- return ;
25
- } else {
26
- is_newtype = true ;
27
- }
28
- }
29
- }
30
- }
31
-
32
11
state. types . push ( '\n' ) ;
33
12
34
13
let comments = utils:: get_comments ( self . clone ( ) . attrs ) ;
@@ -42,7 +21,15 @@ impl super::ToTypescript for syn::ItemEnum {
42
21
43
22
// always use output the internally_tagged representation if the tag is present
44
23
if let Some ( tag_name) = utils:: get_attribute_arg ( "serde" , "tag" , & self . attrs ) {
45
- add_internally_tagged_enum ( tag_name, self , state, casing, config. uses_type_interface )
24
+ let content_name = utils:: get_attribute_arg ( "serde" , "content" , & self . attrs ) ;
25
+ add_internally_tagged_enum (
26
+ tag_name,
27
+ content_name,
28
+ self ,
29
+ state,
30
+ casing,
31
+ config. uses_type_interface ,
32
+ )
46
33
} else if is_single {
47
34
if utils:: has_attribute_arg ( "derive" , "Serialize_repr" , & self . attrs ) {
48
35
add_numeric_enum ( self , state, casing, config)
@@ -208,6 +195,7 @@ fn add_numeric_enum(
208
195
/// ```
209
196
fn add_internally_tagged_enum (
210
197
tag_name : String ,
198
+ content_name : Option < String > ,
211
199
exported_struct : syn:: ItemEnum ,
212
200
state : & mut BuildState ,
213
201
casing : Option < Case > ,
@@ -222,7 +210,7 @@ fn add_internally_tagged_enum(
222
210
223
211
for variant in exported_struct. variants . iter ( ) {
224
212
// Assumes that non-newtype tuple variants have already been filtered out
225
- if variant. fields . iter ( ) . any ( |v| v. ident . is_none ( ) ) {
213
+ if variant. fields . iter ( ) . any ( |v| v. ident . is_none ( ) ) && content_name . is_none ( ) {
226
214
// TODO: Generate newtype structure
227
215
// This should contain the discriminant plus all fields of the inner structure as a flat structure
228
216
// TODO: Check for case where discriminant name matches an inner structure field name
@@ -240,31 +228,62 @@ fn add_internally_tagged_enum(
240
228
state. types . push_str ( ";\n " ) ;
241
229
242
230
for variant in exported_struct. variants {
243
- // Assumes that non-newtype tuple variants have already been filtered out
244
- if !variant. fields . iter ( ) . any ( |v| v. ident . is_none ( ) ) {
245
- state. types . push ( '\n' ) ;
246
- let comments = utils:: get_comments ( variant. attrs ) ;
247
- state. write_comments ( & comments, 0 ) ;
248
- state. types . push_str ( & format ! (
249
- "type {interface_name}__{variant_name} = " ,
250
- interface_name = exported_struct. ident,
251
- variant_name = variant. ident,
252
- ) ) ;
231
+ match ( & variant. fields , content_name. as_ref ( ) ) {
232
+ // adjacently tagged
233
+ ( syn:: Fields :: Unnamed ( fields) , Some ( content_name) ) => {
234
+ state. types . push ( '\n' ) ;
235
+ let comments = utils:: get_comments ( variant. attrs ) ;
236
+ state. write_comments ( & comments, 0 ) ;
237
+ state. types . push_str ( & format ! (
238
+ "type {interface_name}__{variant_name} = " ,
239
+ interface_name = exported_struct. ident,
240
+ variant_name = variant. ident,
241
+ ) ) ;
242
+ // add discriminant
243
+ state. types . push_str ( & format ! (
244
+ "{{\n {indent}\" {tag_name}\" : \" {}\" ;\n {indent}\" {content_name}\" : " ,
245
+ variant. ident,
246
+ indent = utils:: build_indentation( 2 ) ,
247
+ ) ) ;
248
+ super :: structs:: process_tuple_fields ( fields. clone ( ) , state) ;
249
+ state. types . push_str ( ";\n };" ) ;
250
+ }
251
+ // missing content name
252
+ ( syn:: Fields :: Unnamed ( _) , None ) => {
253
+ if crate :: DEBUG . try_get ( ) . is_some_and ( |d : & bool | * d) {
254
+ println ! (
255
+ "#[tsync] failed for {} variant of enum {}, missing content attribute, skipping" ,
256
+ variant. ident,
257
+ exported_struct. ident
258
+ ) ;
259
+ }
260
+ continue ;
261
+ }
262
+ _ => {
263
+ state. types . push ( '\n' ) ;
264
+ let comments = utils:: get_comments ( variant. attrs ) ;
265
+ state. write_comments ( & comments, 0 ) ;
266
+ state. types . push_str ( & format ! (
267
+ "type {interface_name}__{variant_name} = " ,
268
+ interface_name = exported_struct. ident,
269
+ variant_name = variant. ident,
270
+ ) ) ;
253
271
254
- let field_name = if let Some ( casing) = casing {
255
- variant. ident . to_string ( ) . to_case ( casing)
256
- } else {
257
- variant. ident . to_string ( )
258
- } ;
259
- // add discriminant
260
- state. types . push_str ( & format ! (
261
- "{{\n {}{}: \" {}\" ;\n " ,
262
- utils:: build_indentation( 2 ) ,
263
- tag_name,
264
- field_name,
265
- ) ) ;
266
- super :: structs:: process_fields ( variant. fields , state, 2 , casing) ;
267
- state. types . push_str ( "};" ) ;
272
+ let field_name = if let Some ( casing) = casing {
273
+ variant. ident . to_string ( ) . to_case ( casing)
274
+ } else {
275
+ variant. ident . to_string ( )
276
+ } ;
277
+ // add discriminant
278
+ state. types . push_str ( & format ! (
279
+ "{{\n {}{}: \" {}\" ;\n " ,
280
+ utils:: build_indentation( 2 ) ,
281
+ tag_name,
282
+ field_name,
283
+ ) ) ;
284
+ super :: structs:: process_fields ( variant. fields , state, 2 , casing) ;
285
+ state. types . push_str ( "};" ) ;
286
+ }
268
287
}
269
288
}
270
289
state. types . push ( '\n' ) ;
@@ -293,17 +312,13 @@ fn add_externally_tagged_enum(
293
312
} else {
294
313
variant. ident . to_string ( )
295
314
} ;
296
- // Assumes that non-newtype tuple variants have already been filtered out
297
- let is_newtype = variant. fields . iter ( ) . any ( |v| v. ident . is_none ( ) ) ;
298
315
299
- if is_newtype {
316
+ if let syn :: Fields :: Unnamed ( fields ) = & variant . fields {
300
317
// add discriminant
301
- state. types . push_str ( & format ! ( " | {{ \" {}\" :" , field_name) ) ;
302
- for field in variant. fields {
303
- state
304
- . types
305
- . push_str ( & format ! ( " {}" , convert_type( & field. ty) . ts_type, ) ) ;
306
- }
318
+ state
319
+ . types
320
+ . push_str ( & format ! ( " | {{ \" {}\" : " , field_name) ) ;
321
+ super :: structs:: process_tuple_fields ( fields. clone ( ) , state) ;
307
322
state. types . push_str ( " }" ) ;
308
323
} else {
309
324
// add discriminant
0 commit comments