diff --git a/macros/src/type/struct.rs b/macros/src/type/struct.rs index bebf5e3d..1efc6878 100644 --- a/macros/src/type/struct.rs +++ b/macros/src/type/struct.rs @@ -96,21 +96,56 @@ pub fn parse_struct( data.fields.span(), "specta: unit structs cannot be transparent", )); - } else if data.fields.len() != 1 { - return Err(syn::Error::new( - data.fields.span(), - "specta: transparent structs must have exactly one field", - )); } - let field = data - .fields - .iter() - .next() - .expect("unreachable: we just checked this!"); - let field_attrs = decode_field_attrs(field)?; + let (field_ty, field_attrs) = match data.fields { + Fields::Named(_) => { + let fields = data + .fields + .iter() + .map(|field| decode_field_attrs(field).map(|v| (field.ty.clone(), v))) + .collect::, _>>()? + .into_iter() + .filter(|(_, attrs)| !attrs.skip) + .collect::>(); - let field_ty = field_attrs.r#type.as_ref().unwrap_or(&field.ty); + if fields.len() != 1 { + return Err(syn::Error::new( + data.fields.span(), + "specta: transparent structs must have exactly one field", + )); + } + + fields.into_iter().next().expect("fields.len() != 1") + } + Fields::Unnamed(_) => { + let fields = data + .fields + .iter() + .map(|field| decode_field_attrs(field).map(|v| (field.ty.clone(), v))) + .collect::, _>>()? + .into_iter() + .filter(|(_, attrs)| !attrs.skip) + .collect::>(); + + if fields.len() != 1 { + return Err(syn::Error::new( + data.fields.span(), + "specta: transparent structs must have exactly one field", + )); + } + + fields.into_iter().next().expect("fields.len() != 1") + } + Fields::Unit => { + return Err(syn::Error::new( + data.fields.span(), + "specta: transparent structs must have exactly one field", + )); + } + }; + + let field_ty = field_attrs.r#type.as_ref().unwrap_or(&field_ty); let ty = construct_datatype( format_ident!("ty"), @@ -152,7 +187,6 @@ pub fn parse_struct( .then(|| quote!(true)) .unwrap_or(parent_inline.clone()); - let ty = field_attrs.skip.then(|| Ok(quote!(None))) .unwrap_or_else(|| { construct_datatype( diff --git a/tests/serde/skip.rs b/tests/serde/skip.rs index 2240c6f8..806f2456 100644 --- a/tests/serde/skip.rs +++ b/tests/serde/skip.rs @@ -80,6 +80,16 @@ pub enum SkipNamedFieldInVariant { }, } +// https://github.com/oscartbeaumont/specta/issues/170 +#[derive(Type)] +#[specta(transparent, export = false)] +pub struct TransparentWithSkip((), #[specta(skip)] String); + +// https://github.com/oscartbeaumont/specta/issues/170 +#[derive(Type)] +#[specta(transparent, export = false)] +pub struct TransparentWithSkip2(#[specta(skip)] (), String); + #[test] fn skip() { assert_ts!(SkipOnlyField, "Record"); @@ -94,4 +104,6 @@ fn skip() { SkipNamedFieldInVariant, "{ A: Record } | { B: { b: number } }" ); + assert_ts!(TransparentWithSkip, "null"); + assert_ts!(TransparentWithSkip2, "string"); }