Skip to main content

yew_askama/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro2::Ident;
3use quote::{quote, ToTokens, TokenStreamExt};
4use syn::{ItemStruct, parse_macro_input};
5use crate::derive_attr::create_derive_attr;
6
7mod derive_attr;
8
9/// Creates a Yew component from an Askama template.
10///
11/// # Examples
12///
13/// ```rs
14/// #[template_component]
15/// #[template(path = "card.html")
16/// pub struct Card {
17///     title: &'static str,
18///     content: &'static str,
19/// }
20/// ```
21///
22/// # Requirements
23///
24/// - The attribute may only be applied to structs.
25/// - The structure must have [Askama's template attribute](https://djc.github.io/askama/creating_templates.html#the-template-attribute).
26/// - THe structure may not have lifetime parameters.
27///
28/// # Step-by-step
29///
30/// This attribute takes in no arguments, and creates a Yew component which renders an Askama
31/// template. It does so by appending "Template" to the target structure, deriving
32/// "askama::Template" and "yew::Properties", and then defining a new function with the attribute
33/// [yew::function_component], named after the original structure.
34#[proc_macro_attribute]
35pub fn template_component(_attr: TokenStream, input: TokenStream) -> TokenStream {
36    let mut output = parse_macro_input!(input as ItemStruct);
37
38    let mut attrs = vec![create_derive_attr()];
39    attrs.append(&mut output.attrs);
40
41    output.attrs = attrs;
42
43    let template_ident_string = format!("{}Template", output.ident.to_string());
44    let template_ident_span = output.ident.span();
45
46    let name = output.ident.clone();
47
48    let template_ident = Ident::new(template_ident_string.as_str(), template_ident_span);
49    let template_ident_token_stream = template_ident.to_token_stream();
50
51    output.ident = template_ident;
52
53    let mut output_token_stream = output.to_token_stream();
54
55    output_token_stream.append_all(quote! {
56        #[yew::function_component]
57        pub fn #name(template: &#template_ident_token_stream) -> yew::Html {
58            use askama::Template;
59            use std::str::FromStr;
60
61            let template_string = template.render().unwrap();
62            let attr_value = yew::AttrValue::from_str(template_string.as_str()).unwrap();
63
64            yew::Html::from_html_unchecked(attr_value)
65        }
66    });
67
68    output_token_stream.into()
69}