extern crate proc_macro;
mod child;
mod children;
mod css;
mod element;
mod element_attribute;
mod element_attributes;
mod function_component;
mod tags;
use element::Element;
use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use quote::quote;
use syn::parse_macro_input;
#[proc_macro]
#[proc_macro_error]
pub fn html(input: TokenStream) -> TokenStream {
let mut el = parse_macro_input!(input as Element);
inject_tailwind(&mut el);
let result = quote! { ::workers_rsx::Render::render(#el) };
TokenStream::from(result)
}
#[proc_macro]
#[proc_macro_error]
pub fn rsx(input: TokenStream) -> TokenStream {
let el = parse_macro_input!(input as Element);
let result = quote! { #el };
TokenStream::from(result)
}
#[proc_macro]
#[proc_macro_error]
pub fn view(input: TokenStream) -> TokenStream {
let mut el = parse_macro_input!(input as Element);
inject_tailwind(&mut el);
let result = quote! {
::worker::Response::from_html(::workers_rsx::Render::render(#el))
};
TokenStream::from(result)
}
#[proc_macro]
#[proc_macro_error]
pub fn css(input: TokenStream) -> TokenStream {
let input2 = proc_macro2::TokenStream::from(input);
let css_string = css::tokens_to_css(input2);
let result = quote! { #css_string };
TokenStream::from(result)
}
#[proc_macro_attribute]
#[proc_macro_error]
pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
let f = parse_macro_input!(item as syn::ItemFn);
function_component::create_function_component(f, None)
}
#[proc_macro_attribute]
#[proc_macro_error]
pub fn page(attr: TokenStream, item: TokenStream) -> TokenStream {
let state_ident = parse_macro_input!(attr as syn::Ident);
let f = parse_macro_input!(item as syn::ItemFn);
function_component::create_function_component(f, Some(state_ident))
}
fn collect_unique_classes(el: &Element) -> Vec<String> {
let all = el.collect_class_names();
let mut seen = std::collections::HashSet::new();
all.into_iter()
.filter(|c| seen.insert(c.clone()))
.collect()
}
fn inject_tailwind(el: &mut Element) {
let class_names = collect_unique_classes(el);
if class_names.is_empty() {
return;
}
if !el.inject_tailwind_style(class_names.clone()) {
el.prepend_child(child::Child::TailwindStyle(class_names));
}
}
#[proc_macro_derive(ActionJson)]
pub fn derive_action(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as syn::DeriveInput);
let name = &input.ident;
let variants = match &input.data {
syn::Data::Enum(data) => &data.variants,
_ => {
return syn::Error::new_spanned(&input, "ActionJson can only be derived for enums")
.to_compile_error()
.into();
}
};
let arms: Vec<_> = variants
.iter()
.map(|v| {
let ident = &v.ident;
let tag = ident.to_string();
match &v.fields {
syn::Fields::Unit => quote! { #name::#ident => #tag },
_ => quote! { #name::#ident { .. } => #tag },
}
})
.collect();
let expanded = quote! {
impl #name {
fn type_tag(&self) -> &'static str {
match self {
#(#arms),*
}
}
fn json(&self) -> String {
::workers_rsx::serde_json::to_string(self).unwrap()
}
}
impl ::std::fmt::Display for #name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
f.write_str(&::workers_rsx::serde_json::to_string(self).unwrap())
}
}
impl<'a> ::std::convert::From<#name> for ::std::borrow::Cow<'a, str> {
fn from(action: #name) -> Self {
::std::borrow::Cow::Owned(action.to_string())
}
}
};
TokenStream::from(expanded)
}