sycamore_macro/lib.rs
1//! Proc-macros used in [Sycamore](https://sycamore-rs.netlify.app).
2
3#![deny(missing_debug_implementations)]
4#![warn(missing_docs)]
5
6use proc_macro::TokenStream;
7use quote::quote;
8use syn::{parse_macro_input, DeriveInput};
9
10mod component;
11mod props;
12mod view;
13
14/// A macro for ergonomically creating complex UI complex layouts.
15///
16/// To learn more about the view syntax, see [the chapter on views](https://sycamore-rs.netlify.app/docs/basics/view)
17/// in the Sycamore Book.
18#[proc_macro]
19pub fn view(input: TokenStream) -> TokenStream {
20 let root = parse_macro_input!(input as sycamore_view_parser::ir::Root);
21
22 view::Codegen {}.root(&root).into()
23}
24
25/// A macro for creating components from functions.
26///
27/// Add this attribute to a `fn` to create a component from that function.
28///
29/// To learn more about components, see the chapter on
30/// [components](https://sycamore-rs.netlify.app/docs/basics/components) in the Sycamore Book.
31#[proc_macro_attribute]
32pub fn component(args: TokenStream, item: TokenStream) -> TokenStream {
33 let args = parse_macro_input!(args as component::ComponentArgs);
34
35 component::component_impl(args, item.clone().into())
36 .unwrap_or_else(|err| {
37 // If proc-macro errors, emit the original function for better IDE support.
38 let error_tokens = err.into_compile_error();
39 let body_input = proc_macro2::TokenStream::from(item);
40 quote! {
41 #body_input
42 #error_tokens
43 }
44 })
45 .into()
46}
47
48/// The derive macro for `Props`. The macro creates a builder-like API used in the [`view!`] macro.
49#[proc_macro_derive(Props, attributes(prop))]
50pub fn derive_props(input: TokenStream) -> TokenStream {
51 let input = parse_macro_input!(input as DeriveInput);
52
53 props::impl_derive_props(&input)
54 .unwrap_or_else(|err| err.to_compile_error())
55 .into()
56}
57
58/// A macro for feature gating code that should only be run on the server.
59///
60/// By default, the target is used to determine the rendering mode. However, `--cfg
61/// sycamore_force_ssr` can be used to override this behavior.
62///
63/// # Example
64///
65/// ```
66/// # use sycamore_macro::*;
67/// #[cfg_ssr]
68/// fn server_only() {}
69/// ```
70///
71/// See also [`macro@cfg_not_ssr`].
72#[proc_macro_attribute]
73pub fn cfg_ssr(_args: TokenStream, input: TokenStream) -> TokenStream {
74 let input: proc_macro2::TokenStream = input.into();
75 quote! {
76 #[cfg(any(not(target_arch = "wasm32"), sycamore_force_ssr))]
77 #input
78 }
79 .into()
80}
81
82/// A macro for feature gating code that should only be run on the web.
83///
84/// By default, the target is used to determine the rendering mode. However, `--cfg
85/// sycamore_force_ssr` can be used to override this behavior.
86///
87/// # Example
88///
89/// ```
90/// # use sycamore_macro::*;
91/// #[cfg_not_ssr]
92/// fn browser_only() {}
93/// ```
94///
95/// See also [`macro@cfg_ssr`].
96#[proc_macro_attribute]
97pub fn cfg_not_ssr(_args: TokenStream, input: TokenStream) -> TokenStream {
98 let input: proc_macro2::TokenStream = input.into();
99 quote! {
100 #[cfg(all(target_arch = "wasm32", not(sycamore_force_ssr)))]
101 #input
102 }
103 .into()
104}