1mod classes;
50mod derive_props;
51mod function_component;
52mod hook;
53mod html_tree;
54mod props;
55mod stringify;
56mod use_prepared_state;
57mod use_transitive_state;
58
59use derive_props::DerivePropsInput;
60use function_component::{function_component_impl, FunctionComponent, FunctionComponentName};
61use hook::{hook_impl, HookFn};
62use html_tree::{HtmlRoot, HtmlRootVNode};
63use proc_macro::TokenStream;
64use quote::ToTokens;
65use syn::buffer::Cursor;
66use syn::parse_macro_input;
67use use_prepared_state::PreparedState;
68use use_transitive_state::TransitiveState;
69
70trait Peek<'a, T> {
71 fn peek(cursor: Cursor<'a>) -> Option<(T, Cursor<'a>)>;
72}
73
74trait PeekValue<T> {
75 fn peek(cursor: Cursor) -> Option<T>;
76}
77
78fn non_capitalized_ascii(string: &str) -> bool {
79 if !string.is_ascii() {
80 false
81 } else if let Some(c) = string.bytes().next() {
82 c.is_ascii_lowercase()
83 } else {
84 false
85 }
86}
87
88fn join_errors(mut it: impl Iterator<Item = syn::Error>) -> syn::Result<()> {
91 it.next().map_or(Ok(()), |mut err| {
92 for other in it {
93 err.combine(other);
94 }
95 Err(err)
96 })
97}
98
99fn is_ide_completion() -> bool {
100 match std::env::var_os("RUST_IDE_PROC_MACRO_COMPLETION_DUMMY_IDENTIFIER") {
101 None => false,
102 Some(dummy_identifier) => !dummy_identifier.is_empty(),
103 }
104}
105
106#[proc_macro_derive(Properties, attributes(prop_or, prop_or_else, prop_or_default))]
107pub fn derive_props(input: TokenStream) -> TokenStream {
108 let mut input = parse_macro_input!(input as DerivePropsInput);
109 input.normalise();
110 TokenStream::from(input.into_token_stream())
111}
112
113#[proc_macro_error::proc_macro_error]
114#[proc_macro]
115pub fn html_nested(input: TokenStream) -> TokenStream {
116 let root = parse_macro_input!(input as HtmlRoot);
117 TokenStream::from(root.into_token_stream())
118}
119
120#[proc_macro_error::proc_macro_error]
121#[proc_macro]
122pub fn html(input: TokenStream) -> TokenStream {
123 let root = parse_macro_input!(input as HtmlRootVNode);
124 TokenStream::from(root.into_token_stream())
125}
126
127#[proc_macro]
128pub fn props(input: TokenStream) -> TokenStream {
129 let props = parse_macro_input!(input as props::PropsMacroInput);
130 TokenStream::from(props.into_token_stream())
131}
132
133#[proc_macro]
134pub fn classes(input: TokenStream) -> TokenStream {
135 let classes = parse_macro_input!(input as classes::Classes);
136 TokenStream::from(classes.into_token_stream())
137}
138
139#[proc_macro_error::proc_macro_error]
140#[proc_macro_attribute]
141pub fn function_component(attr: TokenStream, item: TokenStream) -> TokenStream {
142 let item = parse_macro_input!(item as FunctionComponent);
143 let attr = parse_macro_input!(attr as FunctionComponentName);
144
145 function_component_impl(attr, item)
146 .unwrap_or_else(|err| err.to_compile_error())
147 .into()
148}
149
150#[proc_macro_error::proc_macro_error]
151#[proc_macro_attribute]
152pub fn hook(attr: TokenStream, item: TokenStream) -> TokenStream {
153 let item = parse_macro_input!(item as HookFn);
154
155 if let Some(m) = proc_macro2::TokenStream::from(attr).into_iter().next() {
156 return syn::Error::new_spanned(m, "hook attribute does not accept any arguments")
157 .into_compile_error()
158 .into();
159 }
160
161 hook_impl(item)
162 .unwrap_or_else(|err| err.to_compile_error())
163 .into()
164}
165
166#[proc_macro]
167pub fn use_prepared_state_with_closure(input: TokenStream) -> TokenStream {
168 let prepared_state = parse_macro_input!(input as PreparedState);
169 prepared_state.to_token_stream_with_closure().into()
170}
171
172#[proc_macro]
173pub fn use_prepared_state_without_closure(input: TokenStream) -> TokenStream {
174 let prepared_state = parse_macro_input!(input as PreparedState);
175 prepared_state.to_token_stream_without_closure().into()
176}
177
178#[proc_macro]
179pub fn use_transitive_state_with_closure(input: TokenStream) -> TokenStream {
180 let transitive_state = parse_macro_input!(input as TransitiveState);
181 transitive_state.to_token_stream_with_closure().into()
182}
183
184#[proc_macro]
185pub fn use_transitive_state_without_closure(input: TokenStream) -> TokenStream {
186 let transitive_state = parse_macro_input!(input as TransitiveState);
187 transitive_state.to_token_stream_without_closure().into()
188}