Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for top level as #288

Merged
merged 3 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions macros/src/attr/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
#[derive(Default)]
pub struct EnumAttr {
crate_rename: Option<Path>,
pub type_as: Option<Type>,
pub type_override: Option<String>,
pub rename_all: Option<Inflection>,
pub rename_all_fields: Option<Inflection>,
Expand Down Expand Up @@ -72,6 +73,7 @@ impl EnumAttr {
&mut self,
EnumAttr {
crate_rename,
type_as,
type_override,
rename_all,
rename_all_fields,
Expand All @@ -87,6 +89,7 @@ impl EnumAttr {
}: EnumAttr,
) {
self.crate_rename = self.crate_rename.take().or(crate_rename);
self.type_as = self.type_as.take().or(type_as);
self.type_override = self.type_override.take().or(type_override);
self.rename = self.rename.take().or(rename);
self.rename_all = self.rename_all.take().or(rename_all);
Expand All @@ -113,6 +116,7 @@ impl EnumAttr {
impl_parse! {
EnumAttr(input, out) {
"crate" => out.crate_rename = Some(parse_assign_from_str(input)?),
"as" => out.type_as = Some(parse_assign_from_str(input)?),
"type" => out.type_override = Some(parse_assign_str(input)?),
"rename" => out.rename = Some(parse_assign_str(input)?),
"rename_all" => out.rename_all = Some(parse_assign_inflection(input)?),
Expand Down
4 changes: 4 additions & 0 deletions macros/src/attr/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
#[derive(Default, Clone)]
pub struct StructAttr {
crate_rename: Option<Path>,
pub type_as: Option<Type>,
pub type_override: Option<String>,
pub rename_all: Option<Inflection>,
pub rename: Option<String>,
Expand Down Expand Up @@ -59,6 +60,7 @@ impl StructAttr {
&mut self,
StructAttr {
crate_rename,
type_as,
type_override,
rename_all,
rename,
Expand All @@ -71,6 +73,7 @@ impl StructAttr {
}: StructAttr,
) {
self.crate_rename = self.crate_rename.take().or(crate_rename);
self.type_as = self.type_as.take().or(type_as);
self.type_override = self.type_override.take().or(type_override);
self.rename = self.rename.take().or(rename);
self.rename_all = self.rename_all.take().or(rename_all);
Expand All @@ -94,6 +97,7 @@ impl StructAttr {
impl_parse! {
StructAttr(input, out) {
"crate" => out.crate_rename = Some(parse_assign_from_str(input)?),
"as" => out.type_as = Some(parse_assign_from_str(input)?),
"type" => out.type_override = Some(parse_assign_str(input)?),
"rename" => out.rename = Some(parse_assign_str(input)?),
"rename_all" => out.rename_all = Some(parse_assign_str(input).and_then(Inflection::try_from)?),
Expand Down
5 changes: 4 additions & 1 deletion macros/src/types/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use syn::{Fields, ItemEnum, Variant};
use crate::{
attr::{EnumAttr, FieldAttr, StructAttr, Tagged, VariantAttr},
deps::Dependencies,
types::{self, type_override},
types::{self, type_as, type_override},
DerivedTS,
};

Expand All @@ -22,6 +22,9 @@ pub(crate) fn r#enum_def(s: &ItemEnum) -> syn::Result<DerivedTS> {
if let Some(attr_type_override) = &enum_attr.type_override {
return type_override::type_override_enum(&enum_attr, &name, attr_type_override);
}
if let Some(attr_type_as) = &enum_attr.type_as {
return type_as::type_as_enum(&enum_attr, &name, attr_type_as);
}

if s.variants.is_empty() {
return Ok(empty_enum(name, enum_attr));
Expand Down
4 changes: 4 additions & 0 deletions macros/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod r#enum;
mod named;
mod newtype;
mod tuple;
mod type_as;
mod type_override;
mod unit;

Expand All @@ -22,6 +23,9 @@ fn type_def(attr: &StructAttr, ident: &Ident, fields: &Fields) -> Result<Derived
if let Some(attr_type_override) = &attr.type_override {
return type_override::type_override_struct(attr, &name, attr_type_override);
}
if let Some(attr_type_as) = &attr.type_as {
return type_as::type_as_struct(attr, &name, attr_type_as);
}

match fields {
Fields::Named(named) => match named.named.len() {
Expand Down
65 changes: 65 additions & 0 deletions macros/src/types/type_as.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use quote::quote;
use syn::{Result, Type};

use crate::{
attr::{EnumAttr, StructAttr},
deps::Dependencies,
DerivedTS,
};

pub(crate) fn type_as_struct(attr: &StructAttr, name: &str, type_as: &Type) -> Result<DerivedTS> {
if attr.rename_all.is_some() {
syn_err!("`rename_all` is not compatible with `as`");
}
if attr.tag.is_some() {
syn_err!("`tag` is not compatible with `as`");
}
dr-bonez marked this conversation as resolved.
Show resolved Hide resolved

let crate_rename = attr.crate_rename();

Ok(DerivedTS {
crate_rename: crate_rename.clone(),
inline: quote!(#type_as::inline()),
inline_flattened: None,
docs: attr.docs.clone(),
dependencies: Dependencies::new(crate_rename),
export: attr.export,
export_to: attr.export_to.clone(),
ts_name: name.to_owned(),
concrete: attr.concrete.clone(),
bound: attr.bound.clone(),
})
}

pub(crate) fn type_as_enum(attr: &EnumAttr, name: &str, type_as: &Type) -> Result<DerivedTS> {
if attr.rename_all.is_some() {
syn_err!("`rename_all` is not compatible with `as`");
}
if attr.rename_all_fields.is_some() {
syn_err!("`rename_all_fields` is not compatible with `as`");
}
if attr.tag.is_some() {
syn_err!("`tag` is not compatible with `as`");
}
if attr.content.is_some() {
syn_err!("`content` is not compatible with `as`");
}
if attr.untagged {
syn_err!("`untagged` is not compatible with `as`");
}

let crate_rename = attr.crate_rename();

Ok(DerivedTS {
crate_rename: crate_rename.clone(),
inline: quote!(#type_as::inline()),
inline_flattened: None,
docs: attr.docs.clone(),
dependencies: Dependencies::new(crate_rename),
export: attr.export,
export_to: attr.export_to.clone(),
ts_name: name.to_owned(),
concrete: attr.concrete.clone(),
bound: attr.bound.clone(),
})
}
5 changes: 5 additions & 0 deletions ts-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ pub mod typelist;
/// Note that you need to add the `export` attribute as well, in order to generate a test which exports the type.
/// <br/><br/>
///
/// - **`#[ts(as = "..")]`**
/// Overrides the type used in Typescript, using the provided Rust type instead.
/// This is useful when you have a custom serializer and deserializer and don't want to implement `TS` manually
/// <br/><br/>
///
/// - **`#[ts(type = "..")]`**
/// Overrides the type used in TypeScript.
/// This is useful when you have a custom serializer and deserializer and don't want to implement `TS` manually
Expand Down
22 changes: 22 additions & 0 deletions ts-rs/tests/top_level_type_as.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use ts_rs::TS;

#[derive(TS)]
#[ts(as = "T")]
pub enum UntaggedEnum<T: TS> {
Left(T),
Right(T),
}

#[test]
pub fn top_level_type_as_enum() {
assert_eq!(UntaggedEnum::<String>::inline(), r#"string"#)
}

#[derive(TS)]
#[ts(as = "T")]
pub struct Wrapper<T: TS>(T);

#[test]
pub fn top_level_type_as_struct() {
assert_eq!(Wrapper::<String>::inline(), r#"string"#)
}
Loading