1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
use proc_macro::TokenStream;
use quote::ToTokens;
use syn::parse_macro_input;

pub(crate) mod ifmt;
pub(crate) mod inlineprops;
pub(crate) mod props;
pub(crate) mod router;
pub(crate) mod rsx;

#[proc_macro]
pub fn format_args_f(input: TokenStream) -> TokenStream {
    use ifmt::*;
    let item = parse_macro_input!(input as IfmtInput);
    format_args_f_impl(item)
        .unwrap_or_else(|err| err.to_compile_error())
        .into()
}

#[proc_macro_derive(Props, attributes(props))]
pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as syn::DeriveInput);
    match props::impl_my_derive(&input) {
        Ok(output) => output.into(),
        Err(error) => error.to_compile_error().into(),
    }
}

/// The rsx! macro makes it easy for developers to write jsx-style markup in their components.
///
/// ## Complete Reference Guide:
/// ```
/// const Example: Component = |cx| {
///     let formatting = "formatting!";
///     let formatting_tuple = ("a", "b");
///     let lazy_fmt = format_args!("lazily formatted text");
///     cx.render(rsx! {
///         div {
///             // Elements
///             div {}
///             h1 {"Some text"}
///             h1 {"Some text with {formatting}"}
///             h1 {"Formatting basic expressions {formatting_tuple.0} and {formatting_tuple.1}"}
///             h2 {
///                 "Multiple"
///                 "Text"
///                 "Blocks"
///                 "Use comments as separators in html"
///             }
///             div {
///                 h1 {"multiple"}
///                 h2 {"nested"}
///                 h3 {"elements"}
///             }
///             div {
///                 class: "my special div"
///                 h1 {"Headers and attributes!"}
///             }
///             div {
///                 // pass simple rust expressions in
///                 class: lazy_fmt,
///                 id: format_args!("attributes can be passed lazily with std::fmt::Arguments"),
///                 div {
///                     class: {
///                         const WORD: &str = "expressions";
///                         format_args!("Arguments can be passed in through curly braces for complex {}", WORD)
///                     }
///                 }
///             }
///
///             // Expressions can be used in element position too:
///             {rsx!(p { "More templating!" })}
///             {html!(<p>"Even HTML templating!!"</p>)}
///
///             // Iterators
///             {(0..10).map(|i| rsx!(li { "{i}" }))}
///             {{
///                 let data = std::collections::HashMap::<&'static str, &'static str>::new();
///                 // Iterators *should* have keys when you can provide them.
///                 // Keys make your app run faster. Make sure your keys are stable, unique, and predictable.
///                 // Using an "ID" associated with your data is a good idea.
///                 data.into_iter().map(|(k, v)| rsx!(li { key: "{k}" "{v}" }))
///             }}
///            
///             // Matching
///             {match true {
///                 true => rsx!(h1 {"Top text"}),
///                 false => rsx!(h1 {"Bottom text"})
///             }}
///
///             // Conditional rendering
///             // Dioxus conditional rendering is based around None/Some. We have no special syntax for conditionals.
///             // You can convert a bool condition to rsx! with .then and .or
///             {true.then(|| rsx!(div {}))}
///
///             // True conditions
///             {if true {
///                 rsx!(h1 {"Top text"})
///             } else {
///                 rsx!(h1 {"Bottom text"})
///             }}
///
///             // returning "None" is a bit noisy... but rare in practice
///             {None as Option<()>}
///
///             // Use the Dioxus type-alias for less noise
///             {NONE_ELEMENT}
///
///             // can also just use empty fragments
///             Fragment {}
///
///             // Fragments let you insert groups of nodes without a parent.
///             // This lets you make components that insert elements as siblings without a container.
///             div {"A"}
///             Fragment {
///                 div {"B"}
///                 div {"C"}
///                 Fragment {
///                     "D"
///                     Fragment {
///                         "heavily nested fragments is an antipattern"
///                         "they cause Dioxus to do unnecessary work"
///                         "don't use them carelessly if you can help it"
///                     }
///                 }
///             }
///
///             // Components
///             // Can accept any paths
///             // Notice how you still get syntax highlighting and IDE support :)
///             Baller {}
///             baller::Baller { }
///             crate::baller::Baller {}
///
///             // Can take properties
///             Taller { a: "asd" }
///
///             // Can take optional properties
///             Taller { a: "asd" }
///
///             // Can pass in props directly as an expression
///             {{
///                 let props = TallerProps {a: "hello"};
///                 rsx!(Taller { ..props })
///             }}
///
///             // Spreading can also be overridden manually
///             Taller {
///                 ..TallerProps { a: "ballin!" }
///                 a: "not ballin!"
///             }
///
///             // Can take children too!
///             Taller { a: "asd", div {"hello world!"} }
///         }
///     })
/// };
///
/// mod baller {
///     use super::*;
///     pub struct BallerProps {}
///
///     /// This component totally balls
///     pub fn Baller(cx: Scope) -> DomTree {
///         todo!()
///     }
/// }
///
/// #[derive(Debug, PartialEq, Props)]
/// pub struct TallerProps {
///     a: &'static str,
/// }
///
/// /// This component is taller than most :)
/// pub fn Taller(cx: Scope<TallerProps>) -> DomTree {
///     let b = true;
///     todo!()
/// }
/// ```
#[proc_macro_error::proc_macro_error]
#[proc_macro]
pub fn rsx(s: TokenStream) -> TokenStream {
    match syn::parse::<rsx::CallBody>(s) {
        Err(err) => err.to_compile_error().into(),
        Ok(stream) => stream.to_token_stream().into(),
    }
}

/// Derive macro used to mark an enum as Routable.
///
/// This macro can only be used on enums. Every varient of the macro needs to be marked
/// with the `at` attribute to specify the URL of the route. It generates an implementation of
///  `yew_router::Routable` trait and `const`s for the routes passed which are used with `Route`
/// component.
///
/// # Example
///
/// ```
/// # use yew_router::Routable;
/// #[derive(Debug, Clone, Copy, PartialEq, Routable)]
/// enum Routes {
///     #[at("/")]
///     Home,
///     #[at("/secure")]
///     Secure,
///     #[at("/profile/{id}")]
///     Profile(u32),
///     #[at("/404")]
///     NotFound,
/// }
/// ```
#[proc_macro_derive(Routable, attributes(at, not_found))]
pub fn routable_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    use router::{routable_derive_impl, Routable};
    let input = parse_macro_input!(input as Routable);
    routable_derive_impl(input).into()
}

/// Derive props for a component within the component definition.
///
/// This macro provides a simple transformation from `Scope<{}>` to `Scope<P>`,
/// removing some boilerplate when defining props.
///
/// You don't *need* to use this macro at all, but it can be helpful in cases where
/// you would be repeating a lot of the usual Rust boilerplate.
///
/// # Example
/// ```
/// #[inline_props]
/// fn app(cx: Scope, bob: String) -> Element {
///     cx.render(rsx!("hello, {bob}"))
/// }  
///
/// // is equivalent to
///
/// #[derive(PartialEq, Props)]
/// struct AppProps {
///     bob: String,
/// }  
///
/// fn app(cx: Scope<AppProps>) -> Element {
///     cx.render(rsx!("hello, {bob}"))
/// }  
/// ```
#[proc_macro_attribute]
pub fn inline_props(_args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
    match syn::parse::<inlineprops::InlinePropsBody>(s) {
        Err(e) => e.to_compile_error().into(),
        Ok(s) => s.to_token_stream().into(),
    }
}