frender-macros 1.0.0-alpha.8

macros for frender
Documentation
use proc_macro2::TokenStream;
use quote::quote_spanned;

use super::data::*;
impl CustomElementDefinition {
    pub fn into_ts(self) -> TokenStream {
        let Self {
            errors,
            item_struct,
            options,
        } = self;
        let CustomElementItemStruct {
            attrs,
            vis,
            struct_token,
            ident,
            generics,
            mut fields,
            semi_token,
        } = item_struct;

        let CustomElementOptions {
            react,
            no_derive_clone,
            no_derive_debug,
            no_from_element,
        } = options;

        let span = ident.span();
        let (impl_generics, type_generics, where_clause) = generics.split_for_impl();

        let react = react.unwrap_or_else(|| default_react_mod_path(span));

        let derive = if no_derive_clone.is_none() && no_derive_debug.is_none() {
            None
        } else {
            let debug = no_derive_clone.map(|_| syn::Ident::new("Debug", span));
            let clone = no_derive_clone.map(|_| syn::Ident::new("Clone", span));
            Some(quote_spanned! {span=>
                #[derive( #debug #clone )]
            })
        };

        if fields.unnamed.len() == 0 {
            fields.unnamed.push(syn::Field {
                attrs: vec![],
                colon_token: None,
                ident: None,
                ty: syn::parse_quote_spanned!(span=> #react::Element),
                vis: syn::Visibility::Inherited,
            })
        }
        let fields = fields;

        let element_ty = &fields.unnamed.first().unwrap().ty;

        let fields_len = fields.unnamed.len();
        let impl_from_element = if no_from_element.is_none() {
            None
        } else {
            let ts = if fields_len > 1 {
                let default = quote_spanned!(span=> ::core::default::Default::default());
                let init_fields = (1..fields_len).map(|_| default.clone());
                quote_spanned! {span=>
                    impl #impl_generics #ident #type_generics #where_clause {
                        fn private_from_element(el: #element_ty) -> Self {
                            Self( el, #(#init_fields)* )
                        }
                    }
                }
            } else {
                quote_spanned!(span=> el)
            };

            Some(ts)
        };

        let error_ts = if errors.len() > 0 {
            Some(
                darling::Error::multiple(errors)
                    .with_span(&ident)
                    .write_errors(),
            )
        } else {
            None
        };

        quote_spanned! {span=>
            #(#attrs)*
            #derive
            #vis #struct_token #ident #generics #fields #semi_token

            #impl_from_element

            impl #impl_generics #react::IntoElement for #ident #type_generics #where_clause {
                #[inline]
                fn into_element(self) -> #react::Element {
                    #react::IntoElement::into_element(self.0)
                }
            }

            impl #impl_generics Into<#element_ty> for #ident #type_generics #where_clause {
                #[inline]
                fn into(self) -> #element_ty {
                    self.0
                }
            }

            impl #impl_generics AsRef<#element_ty> for #ident #type_generics #where_clause {
                #[inline]
                fn as_ref(&self) -> &#element_ty {
                    &self.0
                }
            }

            impl #impl_generics #react::Node for #ident #type_generics #where_clause {
                #[inline]
                fn to_node(&self) -> #react::AnyNode {
                    #react::Node::to_node(&self.0)
                }

                #[inline]
                fn to_children(&self) -> Option<#react::Children> {
                    #react::Node::to_children(&self.0)
                }

                #[inline]
                fn into_node(self) -> #react::AnyNode {
                    #react::Node::into_node(self.0)
                }

                #[inline]
                fn into_children(self) -> Option<#react::Children> {
                    #react::Node::into_children(self.0)
                }
            }

            impl #impl_generics ::core::ops::Deref for #ident #type_generics #where_clause {
                type Target = #element_ty;

                fn deref(&self) -> &Self::Target {
                    &self.0
                }
            }

            #error_ts
        }
    }
}