Skip to content

Commit

Permalink
Merge pull request #180 from timephy/main
Browse files Browse the repository at this point in the history
Added `serde(skip)` functionality inside Enum Variants
  • Loading branch information
NyxCode authored Dec 12, 2023
2 parents 0fb6094 + 5fbc845 commit 067c3f5
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 15 deletions.
50 changes: 36 additions & 14 deletions macros/src/types/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,33 @@ fn format_variant(
Tagged::Untagged => quote!(#inline_type),
Tagged::Externally => match &variant.fields {
Fields::Unit => quote!(format!("\"{}\"", #name)),
Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
let FieldAttr { skip, .. } = FieldAttr::from_attrs(&unnamed.unnamed[0].attrs)?;
if skip {
quote!(format!("\"{}\"", #name))
} else {
quote!(format!("{{ \"{}\": {} }}", #name, #inline_type))
}
}
_ => quote!(format!("{{ \"{}\": {} }}", #name, #inline_type)),
},
Tagged::Adjacently { tag, content } => match &variant.fields {
Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
let FieldAttr { type_override, .. } =
FieldAttr::from_attrs(&unnamed.unnamed[0].attrs)?;
let ty = if let Some(type_override) = type_override {
quote! { #type_override }
let FieldAttr {
type_override,
skip,
..
} = FieldAttr::from_attrs(&unnamed.unnamed[0].attrs)?;
if skip {
quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #name))
} else {
format_type(&unnamed.unnamed[0].ty, dependencies, generics)
};
quote!(format!("{{ \"{}\": \"{}\", \"{}\": {} }}", #tag, #name, #content, #ty))
let ty = if let Some(type_override) = type_override {
quote! { #type_override }
} else {
format_type(&unnamed.unnamed[0].ty, dependencies, generics)
};
quote!(format!("{{ \"{}\": \"{}\", \"{}\": {} }}", #tag, #name, #content, #ty))
}
}
Fields::Unit => quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #name)),
_ => quote!(
Expand All @@ -120,14 +135,21 @@ fn format_variant(
},
None => match &variant.fields {
Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
let FieldAttr { type_override, .. } =
FieldAttr::from_attrs(&unnamed.unnamed[0].attrs)?;
let ty = if let Some(type_override) = type_override {
quote! { #type_override }
let FieldAttr {
type_override,
skip,
..
} = FieldAttr::from_attrs(&unnamed.unnamed[0].attrs)?;
if skip {
quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #name))
} else {
format_type(&unnamed.unnamed[0].ty, dependencies, generics)
};
quote!(format!("{{ \"{}\": \"{}\" }} & {}", #tag, #name, #ty))
let ty = if let Some(type_override) = type_override {
quote! { #type_override }
} else {
format_type(&unnamed.unnamed[0].ty, dependencies, generics)
};
quote!(format!("{{ \"{}\": \"{}\" }} & {}", #tag, #name, #ty))
}
}
Fields::Unit => quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #name)),
_ => {
Expand Down
2 changes: 1 addition & 1 deletion macros/src/types/newtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub(crate) fn newtype(

match (&rename_inner, skip, optional, flatten) {
(Some(_), ..) => syn_err!("`rename` is not applicable to newtype fields"),
(_, true, ..) => syn_err!("`skip` is not applicable to newtype fields"),
(_, true, ..) => return super::unit::null(attr, name),
(_, _, true, ..) => syn_err!("`optional` is not applicable to newtype fields"),
(_, _, _, true) => syn_err!("`flatten` is not applicable to newtype fields"),
_ => {}
Expand Down
71 changes: 71 additions & 0 deletions ts-rs/tests/union_named_serde_skip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#![allow(dead_code)]

use serde::Deserialize;
use ts_rs::TS;

#[derive(TS, Deserialize)]
#[serde(untagged)]
enum TestUntagged {
A, // serde_json -> `null`
B(), // serde_json -> `[]`
C {
#[serde(skip)]
val: i32,
}, // serde_json -> `{}`
}

#[derive(TS, Deserialize)]
enum TestExternally {
A, // serde_json -> `"A"`
B(), // serde_json -> `{"B":[]}`
C {
#[serde(skip)]
val: i32,
}, // serde_json -> `{"C":{}}`
}

#[derive(TS, Deserialize)]
#[serde(tag = "type", content = "content")]
enum TestAdjacently {
A, // serde_json -> `{"type":"A"}`
B(), // serde_json -> `{"type":"B","content":[]}`
C {
#[serde(skip)]
val: i32,
}, // serde_json -> `{"type":"C","content":{}}`
}

#[derive(TS, Deserialize)]
#[serde(tag = "type")]
enum TestInternally {
A, // serde_json -> `{"type":"A"}`
B, // serde_json -> `{"type":"B"}`
C {
#[serde(skip)]
val: i32,
}, // serde_json -> `{"type":"C"}`
}

#[cfg(feature = "serde-compat")]
#[test]
fn test() {
assert_eq!(
TestUntagged::decl(),
r#"type TestUntagged = null | never[] | { };"#
);

assert_eq!(
TestExternally::decl(),
r#"type TestExternally = "A" | { "B": never[] } | { "C": { } };"#
);

assert_eq!(
TestAdjacently::decl(),
r#"type TestAdjacently = { "type": "A" } | { "type": "B", "content": never[] } | { "type": "C", "content": { } };"#
);

assert_eq!(
TestInternally::decl(),
r#"type TestInternally = { "type": "A" } | { "type": "B" } | { "type": "C", };"#
);
}
59 changes: 59 additions & 0 deletions ts-rs/tests/union_unnamed_serde_skip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#![allow(dead_code)]

use serde::Deserialize;
use ts_rs::TS;

#[derive(TS, Deserialize)]
#[serde(untagged)]
enum TestUntagged {
A, // serde_json -> `null`
B(), // serde_json -> `[]`
C(#[serde(skip)] i32), // serde_json -> `null`
}

#[derive(TS, Deserialize)]
enum TestExternally {
A, // serde_json -> `"A"`
B(), // serde_json -> `{"B":[]}`
C(#[serde(skip)] i32), // serde_json -> `"C"`
}

#[derive(TS, Deserialize)]
#[serde(tag = "type", content = "content")]
enum TestAdjacently {
A, // serde_json -> `{"type":"A"}`
B(), // serde_json -> `{"type":"B","content":[]}`
C(#[serde(skip)] i32), // serde_json -> `{"type":"C"}`
}

#[derive(TS, Deserialize)]
#[serde(tag = "type")]
enum TestInternally {
A, // serde_json -> `{"type":"A"}`
B, // serde_json -> `{"type":"B"}`
C(#[serde(skip)] i32), // serde_json -> `{"type":"C"}`
}

#[cfg(feature = "serde-compat")]
#[test]
fn test() {
assert_eq!(
TestUntagged::decl(),
r#"type TestUntagged = null | never[] | null;"#
);

assert_eq!(
TestExternally::decl(),
r#"type TestExternally = "A" | { "B": never[] } | "C";"#
);

assert_eq!(
TestAdjacently::decl(),
r#"type TestAdjacently = { "type": "A" } | { "type": "B", "content": never[] } | { "type": "C" };"#
);

assert_eq!(
TestInternally::decl(),
r#"type TestInternally = { "type": "A" } | { "type": "B" } | { "type": "C" };"#
);
}

0 comments on commit 067c3f5

Please sign in to comment.