1#![expect(missing_docs)]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3
4mod component;
5mod derive;
6mod html;
7
8use html::{AttributeValueNode, Nodes};
9use proc_macro::TokenStream;
10use syn::{DeriveInput, ItemFn, parse::Parse, parse_macro_input};
11
12use self::html::{Document, Maud, Rsx, Syntax};
13use crate::{component::ComponentArgs, html::generate::Context};
14
15#[proc_macro]
16pub fn maud(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
17 lazy::<Maud>(tokens, true)
18}
19
20#[proc_macro]
21pub fn maud_borrow(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
22 lazy::<Maud>(tokens, false)
23}
24
25#[proc_macro]
26pub fn rsx(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
27 lazy::<Rsx>(tokens, true)
28}
29
30#[proc_macro]
31pub fn rsx_borrow(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
32 lazy::<Rsx>(tokens, false)
33}
34
35#[proc_macro]
36pub fn maud_static(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
37 static_::<Maud>(tokens)
38}
39
40#[proc_macro]
41pub fn rsx_static(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
42 static_::<Rsx>(tokens)
43}
44
45fn lazy<S: Syntax>(tokens: proc_macro::TokenStream, move_: bool) -> proc_macro::TokenStream
46where
47 Document<S>: Parse,
48{
49 html::generate::lazy::<Document<S>>(tokens.into(), move_)
50 .unwrap_or_else(|err| err.to_compile_error())
51 .into()
52}
53
54fn static_<S: Syntax>(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream
55where
56 Document<S>: Parse,
57{
58 html::generate::literal::<Document<S>>(tokens.into())
59 .unwrap_or_else(|err| err.to_compile_error())
60 .into()
61}
62
63#[proc_macro]
64pub fn attribute(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
65 attribute_lazy(tokens, true)
66}
67
68#[proc_macro]
69pub fn attribute_borrow(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
70 attribute_lazy(tokens, false)
71}
72
73fn attribute_lazy(tokens: proc_macro::TokenStream, move_: bool) -> proc_macro::TokenStream {
74 html::generate::lazy::<Nodes<AttributeValueNode>>(tokens.into(), move_)
75 .unwrap_or_else(|err| err.to_compile_error())
76 .into()
77}
78
79#[proc_macro]
80pub fn attribute_static(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
81 html::generate::literal::<Nodes<AttributeValueNode>>(tokens.into())
82 .unwrap_or_else(|err| err.to_compile_error())
83 .into()
84}
85
86#[proc_macro_derive(Renderable, attributes(maud, rsx, attribute))]
87pub fn derive_renderable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
88 derive::renderable(parse_macro_input!(input as DeriveInput))
89 .unwrap_or_else(|err| err.to_compile_error())
90 .into()
91}
92
93#[proc_macro_attribute]
94pub fn component(attr: TokenStream, item: TokenStream) -> TokenStream {
95 let attr = parse_macro_input!(attr as ComponentArgs);
96 let item = parse_macro_input!(item as ItemFn);
97
98 component::generate(attr, &item)
99 .unwrap_or_else(|err| err.to_compile_error())
100 .into()
101}