This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew_macro/
lib.rs

1//! This crate provides Yew's procedural macro `html!` which allows using JSX-like syntax
2//! for generating html and the `Properties` derive macro for deriving the `Properties` trait
3//! for components.
4//!
5//! ```
6//! use yew::prelude::*;
7//!
8//! struct Component;
9//!
10//! #[derive(Properties, PartialEq)]
11//! struct Props {
12//!     prop: String,
13//! }
14//!
15//! # enum Msg { Submit }
16//! #
17//! # impl yew::Component for Component {
18//! #     type Message = Msg;
19//! #     type Properties = Props;
20//! #     fn create(_ctx: &Context<Self>) -> Self {
21//! #         unimplemented!()
22//! #     }
23//! #
24//! #
25//! #     fn view(&self, ctx: &Context<Self>) -> Html {
26//! #
27//! // ...
28//!
29//! html! {
30//!   <div>
31//!     <button onclick={ctx.link().callback(|_| Msg::Submit)}>
32//!       { "Submit" }
33//!     </button>
34//!     <>
35//!       <Component prop="first" />
36//!       <Component prop="second" />
37//!     </>
38//!   </div>
39//! }
40//! #
41//! #     }
42//! # }
43//! #
44//! # fn main() {}
45//! ```
46//!
47//! Please refer to [https://github.com/yewstack/yew](https://github.com/yewstack/yew) for how to set this up.
48
49mod 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
88/// Combine multiple `syn` errors into a single one.
89/// Returns `Result::Ok` if the given iterator is empty
90fn 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}