1extern crate proc_macro;
2
3mod child;
4mod children;
5mod css;
6mod element;
7mod element_attribute;
8mod element_attributes;
9mod function_component;
10mod tags;
11
12use element::Element;
13use proc_macro::TokenStream;
14use proc_macro_error::proc_macro_error;
15use quote::quote;
16use syn::parse_macro_input;
17
18#[proc_macro]
22#[proc_macro_error]
23pub fn html(input: TokenStream) -> TokenStream {
24 let mut el = parse_macro_input!(input as Element);
25 inject_tailwind(&mut el);
26 let result = quote! { ::workers_rsx::Render::render(#el) };
27 TokenStream::from(result)
28}
29
30#[proc_macro]
32#[proc_macro_error]
33pub fn rsx(input: TokenStream) -> TokenStream {
34 let el = parse_macro_input!(input as Element);
35 let result = quote! { #el };
36 TokenStream::from(result)
37}
38
39#[proc_macro]
43#[proc_macro_error]
44pub fn view(input: TokenStream) -> TokenStream {
45 let mut el = parse_macro_input!(input as Element);
46 inject_tailwind(&mut el);
47 let result = quote! {
48 ::worker::Response::from_html(::workers_rsx::Render::render(#el))
49 };
50 TokenStream::from(result)
51}
52
53#[proc_macro]
68#[proc_macro_error]
69pub fn css(input: TokenStream) -> TokenStream {
70 let input2 = proc_macro2::TokenStream::from(input);
71 let css_string = css::tokens_to_css(input2);
72 let result = quote! { #css_string };
73 TokenStream::from(result)
74}
75
76#[proc_macro_attribute]
78#[proc_macro_error]
79pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
80 let f = parse_macro_input!(item as syn::ItemFn);
81 function_component::create_function_component(f, None)
82}
83
84#[proc_macro_attribute]
97#[proc_macro_error]
98pub fn page(attr: TokenStream, item: TokenStream) -> TokenStream {
99 let state_ident = parse_macro_input!(attr as syn::Ident);
100 let f = parse_macro_input!(item as syn::ItemFn);
101 function_component::create_function_component(f, Some(state_ident))
102}
103
104fn collect_unique_classes(el: &Element) -> Vec<String> {
106 let all = el.collect_class_names();
107 let mut seen = std::collections::HashSet::new();
108 all.into_iter()
109 .filter(|c| seen.insert(c.clone()))
110 .collect()
111}
112
113fn inject_tailwind(el: &mut Element) {
116 let class_names = collect_unique_classes(el);
117 if class_names.is_empty() {
118 return;
119 }
120 if !el.inject_tailwind_style(class_names.clone()) {
121 el.prepend_child(child::Child::TailwindStyle(class_names));
123 }
124}
125
126#[proc_macro_derive(ActionJson)]
144pub fn derive_action(input: TokenStream) -> TokenStream {
145 let input = parse_macro_input!(input as syn::DeriveInput);
146 let name = &input.ident;
147
148 let variants = match &input.data {
149 syn::Data::Enum(data) => &data.variants,
150 _ => {
151 return syn::Error::new_spanned(&input, "ActionJson can only be derived for enums")
152 .to_compile_error()
153 .into();
154 }
155 };
156
157 let arms: Vec<_> = variants
158 .iter()
159 .map(|v| {
160 let ident = &v.ident;
161 let tag = ident.to_string();
162 match &v.fields {
163 syn::Fields::Unit => quote! { #name::#ident => #tag },
164 _ => quote! { #name::#ident { .. } => #tag },
165 }
166 })
167 .collect();
168
169 let expanded = quote! {
170 impl #name {
171 fn type_tag(&self) -> &'static str {
172 match self {
173 #(#arms),*
174 }
175 }
176
177 fn json(&self) -> String {
178 ::workers_rsx::serde_json::to_string(self).unwrap()
179 }
180 }
181
182 impl ::std::fmt::Display for #name {
183 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
184 f.write_str(&::workers_rsx::serde_json::to_string(self).unwrap())
185 }
186 }
187
188 impl<'a> ::std::convert::From<#name> for ::std::borrow::Cow<'a, str> {
189 fn from(action: #name) -> Self {
190 ::std::borrow::Cow::Owned(action.to_string())
191 }
192 }
193 };
194
195 TokenStream::from(expanded)
196}