kit_macros/
lib.rs

1//! Procedural macros for the Kit framework
2//!
3//! This crate provides compile-time validated macros for:
4//! - Inertia.js responses with component validation
5//! - Named route redirects with route validation
6
7use proc_macro::TokenStream;
8
9mod inertia;
10mod redirect;
11mod service;
12mod utils;
13
14/// Derive macro for generating `Serialize` implementation for Inertia props
15///
16/// # Example
17///
18/// ```rust,ignore
19/// #[derive(InertiaProps)]
20/// struct HomeProps {
21///     title: String,
22///     user: User,
23/// }
24/// ```
25#[proc_macro_derive(InertiaProps)]
26pub fn derive_inertia_props(input: TokenStream) -> TokenStream {
27    inertia::derive_inertia_props_impl(input)
28}
29
30/// Create an Inertia response with compile-time component validation
31///
32/// # Examples
33///
34/// ## With typed struct (recommended for type safety):
35/// ```rust,ignore
36/// #[derive(InertiaProps)]
37/// struct HomeProps {
38///     title: String,
39///     user: User,
40/// }
41///
42/// inertia_response!("Home", HomeProps { title: "Welcome".into(), user })
43/// ```
44///
45/// ## With JSON-like syntax (for quick prototyping):
46/// ```rust,ignore
47/// inertia_response!("Dashboard", { "user": { "name": "John" } })
48/// ```
49///
50/// This macro validates that the component file exists at compile time.
51/// If `frontend/src/pages/Dashboard.tsx` doesn't exist, you'll get a compile error.
52#[proc_macro]
53pub fn inertia_response(input: TokenStream) -> TokenStream {
54    inertia::inertia_response_impl(input)
55}
56
57/// Create a redirect to a named route with compile-time validation
58///
59/// # Examples
60///
61/// ```rust,ignore
62/// // Simple redirect
63/// redirect!("users.index").into()
64///
65/// // Redirect with route parameters
66/// redirect!("users.show").with("id", "42").into()
67///
68/// // Redirect with query parameters
69/// redirect!("users.index").query("page", "1").into()
70/// ```
71///
72/// This macro validates that the route name exists at compile time.
73/// If the route doesn't exist, you'll get a compile error with suggestions.
74#[proc_macro]
75pub fn redirect(input: TokenStream) -> TokenStream {
76    redirect::redirect_impl(input)
77}
78
79/// Mark a trait as a service for the App container
80///
81/// This attribute macro automatically adds `Send + Sync + 'static` bounds
82/// to your trait, making it suitable for use with the dependency injection
83/// container.
84///
85/// # Example
86///
87/// ```rust,ignore
88/// use kit::service;
89///
90/// #[service]
91/// pub trait HttpClient {
92///     async fn get(&self, url: &str) -> Result<String, Error>;
93/// }
94///
95/// // This expands to:
96/// pub trait HttpClient: Send + Sync + 'static {
97///     async fn get(&self, url: &str) -> Result<String, Error>;
98/// }
99/// ```
100///
101/// Then you can use it with the App container:
102///
103/// ```rust,ignore
104/// // Register
105/// App::bind::<dyn HttpClient>(Arc::new(RealHttpClient::new()));
106///
107/// // Resolve
108/// let client: Arc<dyn HttpClient> = App::make::<dyn HttpClient>().unwrap();
109/// ```
110#[proc_macro_attribute]
111pub fn service(attr: TokenStream, input: TokenStream) -> TokenStream {
112    service::service_impl(attr, input)
113}