use super::data::Data;
use super::derive_field::DeriveField;
use super::derived_variant::DerivedVariant;
use super::fields::Fields;
use convert_case::{Case, Casing};
use syn::LitStr;
#[derive(Debug)]
pub(crate) struct DeriveInput {
pub(crate) ident: syn::Ident,
pub(crate) data: Data<DerivedVariant, DeriveField>,
pub(crate) id: Option<String>,
pub(crate) transparent: bool,
pub(crate) mark: bool,
}
impl DeriveInput {
pub(crate) fn from_derive_input(input: &syn::DeriveInput) -> syn::Result<Self> {
let ident = input.ident.clone();
let mut id: Option<String> = None;
let mut transparent = false;
let mut mark = false;
for attr in &input.attrs {
if !attr.path().is_ident("ts") {
continue;
}
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("id") {
let value = meta.value()?;
let lit: LitStr = value.parse()?;
id = Some(lit.value());
} else if meta.path.is_ident("name") {
let value = meta.value()?;
let _: LitStr = value.parse()?;
} else if meta.path.is_ident("text") {
if meta.input.peek(syn::Token![=]) {
let value = meta.value()?;
let _: syn::LitBool = value.parse()?;
}
} else if meta.path.is_ident("transparent") {
if meta.input.peek(syn::Token![=]) {
let value = meta.value()?;
let lit: syn::LitBool = value.parse()?;
transparent = lit.value();
} else {
transparent = true;
}
} else if meta.path.is_ident("mark") {
if meta.input.peek(syn::Token![=]) {
let value = meta.value()?;
let lit: syn::LitBool = value.parse()?;
mark = lit.value();
} else {
mark = true;
}
} else {
return Err(meta.error(format!(
"unknown ts attribute `{}`",
meta.path
.get_ident()
.map(|i| i.to_string())
.unwrap_or_default()
)));
}
Ok(())
})?;
}
let data = match &input.data {
syn::Data::Enum(data_enum) => {
let mut variants = Vec::new();
for variant in &data_enum.variants {
variants.push(DerivedVariant::from_variant(variant)?);
}
Data::Enum(variants)
}
syn::Data::Struct(data_struct) => {
let fields = Fields::from_syn_fields(&data_struct.fields)?;
Data::Struct(fields)
}
syn::Data::Union(_) => {
return Err(syn::Error::new_spanned(
&input.ident,
"union not supported for Parser derive",
));
}
};
Ok(Self {
ident,
data,
id,
transparent,
mark,
})
}
pub fn ts_node_name(&self) -> LitStr {
let name = self
.id
.clone()
.unwrap_or_else(|| self.ident.to_string().to_case(Case::Snake));
LitStr::new(&name, self.ident.span())
}
pub fn generate(&self) -> proc_macro2::TokenStream {
match &self.data {
Data::Enum(fields) => self.generate_variant(fields),
Data::Struct(fields) => self.generate_struct(fields),
}
}
}