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