Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions macros/src/attr/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,15 @@ impl Attr for EnumAttr {
item;
"content cannot be used without tag"
),
(false, Some(_), None) => {
for variant in item.variants.iter() {
if let Fields::Unnamed(ref unnamed) = variant.fields {
if unnamed.unnamed.len() > 1 {
syn_err_spanned!(variant; r#"`#[ts(tag = "...")]` cannot be used with tuple variants"#);
}
}
}
}
_ => (),
};

Expand Down
53 changes: 23 additions & 30 deletions macros/src/types/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ fn format_variant(
};

let formatted = match (untagged_variant, enum_attr.tagged()?) {
(true, _) | (_, Tagged::Untagged) => quote!(#parsed_ty),
(true, _) | (_, Tagged::Untagged) => parsed_ty,
(false, Tagged::Externally) => match &variant.fields {
Fields::Unit => quote!(format!("\"{}\"", #ts_name)),
Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
Expand Down Expand Up @@ -183,36 +183,29 @@ fn format_variant(
format!("{{ \"{}\": \"{}\", \"{}\": {} }}", #tag, #ts_name, #content, #parsed_ty)
),
},
(false, Tagged::Internally { tag }) => match variant_type.inline_flattened {
Some(_) => {
quote! { #parsed_ty }
}
None => match &variant.fields {
Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
let field = &unnamed.unnamed[0];
let field_attr = FieldAttr::from_attrs(&unnamed.unnamed[0].attrs)?;

field_attr.assert_validity(field)?;

if field_attr.skip {
quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #ts_name))
} else {
let ty = match field_attr.type_override {
Some(type_override) => quote! { #type_override },
None => {
let ty = field_attr.type_as(&field.ty);
quote!(<#ty as #crate_rename::TS>::name(cfg))
}
};

quote!(format!("{{ \"{}\": \"{}\" }} & {}", #tag, #ts_name, #ty))
}
}
Fields::Unit => quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #ts_name)),
_ => {
quote!(format!("{{ \"{}\": \"{}\" }} & {}", #tag, #ts_name, #parsed_ty))
(false, Tagged::Internally { tag }) => match &variant.fields {
Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
let field = &unnamed.unnamed[0];
let field_attr = FieldAttr::from_attrs(&unnamed.unnamed[0].attrs)?;

field_attr.assert_validity(field)?;

if field_attr.skip {
quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #ts_name))
} else {
let ty = match field_attr.type_override {
Some(type_override) => quote! { #type_override },
None => {
let ty = field_attr.type_as(&field.ty);
quote!(<#ty as #crate_rename::TS>::name(cfg))
}
};

quote!(format!("{{ \"{}\": \"{}\" }} & {}", #tag, #ts_name, #ty))
}
},
}
Fields::Unit => quote!(format!("{{ \"{}\": \"{}\" }}", #tag, #ts_name)),
_ => parsed_ty,
},
};

Expand Down
4 changes: 2 additions & 2 deletions macros/src/types/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub(crate) fn empty_object(attr: &StructAttr, ts_name: Expr) -> DerivedTS {
DerivedTS {
crate_rename: crate_rename.clone(),
inline: quote!("Record<symbol, never>".to_owned()),
inline_flattened: None,
inline_flattened: Some(quote!("{ }".to_owned())),
docs: attr.docs.clone(),
dependencies: Dependencies::new(crate_rename),
export: attr.export,
Expand Down Expand Up @@ -51,7 +51,7 @@ pub(crate) fn null(attr: &StructAttr, ts_name: Expr) -> DerivedTS {
DerivedTS {
crate_rename: crate_rename.clone(),
inline: quote!("null".to_owned()),
inline_flattened: None,
inline_flattened: Some(quote!("{ }".to_owned())),
docs: attr.docs.clone(),
dependencies: Dependencies::new(crate_rename),
export: attr.export,
Expand Down
14 changes: 14 additions & 0 deletions ts-rs/tests/integration/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,25 @@ struct C {
d: i32,
}

#[derive(TS)]
#[ts(export, export_to = "flatten/")]
pub struct Inner {}

// Create a parent struct that flattens the zero-field struct:
#[derive(TS)]
#[ts(export, export_to = "flatten/")]
pub struct Outer {
#[ts(flatten)]
pub inner: Inner,
pub other_field: String,
}

#[test]
fn test_def() {
let cfg = Config::from_env();
assert_eq!(
C::inline(&cfg),
"{ b: { c: number, a: number, b: number, } & ({ [key in string]: number }), d: number, }"
);
assert_eq!(Outer::inline(&cfg), "{ other_field: string, }");
}