dioxus_html_internal_macro/
lib.rs

1use proc_macro::TokenStream;
2
3use convert_case::{Case, Casing};
4use quote::{quote, ToTokens, TokenStreamExt};
5use syn::__private::TokenStream2;
6use syn::parse::{Parse, ParseStream};
7use syn::punctuated::Punctuated;
8use syn::{braced, parse_macro_input, Ident, Token};
9
10#[proc_macro]
11pub fn impl_extension_attributes(input: TokenStream) -> TokenStream {
12    let input = parse_macro_input!(input as ImplExtensionAttributes);
13    input.to_token_stream().into()
14}
15
16struct ImplExtensionAttributes {
17    name: Ident,
18    attrs: Punctuated<Ident, Token![,]>,
19}
20
21impl Parse for ImplExtensionAttributes {
22    fn parse(input: ParseStream) -> syn::Result<Self> {
23        let content;
24
25        let name = input.parse()?;
26        braced!(content in input);
27        let attrs = content.parse_terminated(Ident::parse, Token![,])?;
28
29        Ok(ImplExtensionAttributes { name, attrs })
30    }
31}
32
33impl ToTokens for ImplExtensionAttributes {
34    fn to_tokens(&self, tokens: &mut TokenStream2) {
35        let name = &self.name;
36        let name_string = name.to_string();
37        let camel_name = name_string
38            .strip_prefix("r#")
39            .unwrap_or(&name_string)
40            .to_case(Case::UpperCamel);
41        let extension_name = Ident::new(format!("{}Extension", &camel_name).as_str(), name.span());
42
43        let impls = self.attrs.iter().map(|ident| {
44            let d = quote! { #name::#ident };
45            quote! {
46                fn #ident(self, value: impl IntoAttributeValue) -> Self {
47                    let d = #d;
48                    self.push_attribute(d.0, d.1, value, d.2)
49                }
50            }
51        });
52        tokens.append_all(quote! {
53            pub trait #extension_name: HasAttributes + Sized {
54                #(#impls)*
55            }
56        });
57    }
58}