Skip to content

Commit d2dc731

Browse files
authored
#65 Support untagged enums (#68)
1 parent 08e14c0 commit d2dc731

File tree

6 files changed

+121
-1
lines changed

6 files changed

+121
-1
lines changed

src/to_typescript/enums.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ impl super::ToTypescript for syn::ItemEnum {
2020
let is_single = !self.variants.iter().any(|x| !x.fields.is_empty());
2121
state.write_comments(&comments, 0);
2222

23+
// Handle untagged enum if serde has the tag untagged
24+
if utils::get_attribute_arg("serde", "untagged", &self.attrs).is_some() {
25+
add_untagged_tagged_enum(self, state, casing, config.uses_type_interface);
26+
}
2327
// always use output the internally_tagged representation if the tag is present
24-
if let Some(tag_name) = utils::get_attribute_arg("serde", "tag", &self.attrs) {
28+
else if let Some(tag_name) = utils::get_attribute_arg("serde", "tag", &self.attrs) {
2529
let content_name = utils::get_attribute_arg("serde", "content", &self.attrs);
2630
add_internally_tagged_enum(
2731
tag_name,
@@ -398,3 +402,58 @@ fn add_externally_tagged_enum(
398402
}
399403
state.types.push_str(";\n");
400404
}
405+
406+
fn add_untagged_tagged_enum(
407+
exported_struct: syn::ItemEnum,
408+
state: &mut BuildState,
409+
casing: Option<Case>,
410+
uses_type_interface: bool,
411+
) {
412+
let export = if uses_type_interface { "" } else { "export " };
413+
let generics = utils::extract_struct_generics(exported_struct.generics.clone());
414+
415+
// Write type name and generics
416+
state.types.push_str(&format!(
417+
"{export}type {interface_name}{generics} =",
418+
interface_name = exported_struct.ident,
419+
generics = utils::format_generics(&generics)
420+
));
421+
422+
// Loop over each variant of the enum
423+
for variant in exported_struct.variants {
424+
state.types.push('\n');
425+
// Copy comments from rust
426+
let comments = utils::get_comments(variant.attrs);
427+
state.write_comments(&comments, 2);
428+
429+
// Unnamed fields:
430+
// ```rs
431+
// enum Data {
432+
// Value1(i32)
433+
// }
434+
// ```
435+
if let syn::Fields::Unnamed(fields) = &variant.fields {
436+
// add discriminant
437+
state.types.push_str(&format!(" | "));
438+
super::structs::process_tuple_fields(fields.clone(), state);
439+
state.types.push_str("");
440+
}
441+
// Named fields:
442+
// ```rs
443+
// enum Data {
444+
// Value1 { v: i32 }
445+
// }
446+
// ```
447+
else {
448+
// add discriminant
449+
state.types.push_str(&format!(" | {{\n"));
450+
451+
super::structs::process_fields(variant.fields, state, 6, casing, true);
452+
453+
state
454+
.types
455+
.push_str(&format!("{}}}", utils::build_indentation(4)));
456+
}
457+
}
458+
state.types.push_str(";\n");
459+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// test/rust.rs
2+
use tsync::tsync;
3+
4+
#[derive(Serialize, Deserialize)]
5+
#[tsync]
6+
#[serde(untagged)]
7+
enum Message {
8+
ValueOne(i32, i32),
9+
Value2(i32),
10+
}
11+
12+
#[derive(Serialize, Deserialize)]
13+
#[tsync]
14+
#[serde(untagged)]
15+
enum Message2<V, G> {
16+
ValueOne { a: V, b: G },
17+
Value2 { c: V },
18+
Value3(G),
19+
Value3(Vec<G>),
20+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/bash
2+
3+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
4+
5+
cd $SCRIPT_DIR
6+
7+
cargo run -- -i rust.rs -o typescript.d.ts
8+
cargo run -- -i rust.rs -o typescript.ts
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* This file is generated and managed by tsync */
2+
3+
type Message =
4+
| [ number, number ]
5+
| number;
6+
7+
type Message2<V, G> =
8+
| {
9+
a: V;
10+
b: G;
11+
}
12+
| {
13+
c: V;
14+
}
15+
| G
16+
| Array<G>;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* This file is generated and managed by tsync */
2+
3+
export type Message =
4+
| [ number, number ]
5+
| number;
6+
7+
export type Message2<V, G> =
8+
| {
9+
a: V;
10+
b: G;
11+
}
12+
| {
13+
c: V;
14+
}
15+
| G
16+
| Array<G>;

test/test_all.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ cd $SCRIPT_DIR
1717
./issue-43/tsync.sh
1818
./issue-55/tsync.sh
1919
./issue-58/tsync.sh
20+
./issue-65-untagged-enums/tsync.sh
2021
./raw_identifiers/tsync.sh

0 commit comments

Comments
 (0)