resuma_macros/lib.rs
1//! Resuma procedural macros.
2//!
3//! Re-exported by the [`resuma`](https://docs.rs/resuma) crate. Typical surface:
4//!
5//! | Macro | Role |
6//! |-------|------|
7//! | [`view!`] | JSX-like templates → [`View`](https://docs.rs/resuma/latest/resuma/enum.View.html) |
8//! | [`#[component]`](component) | Resumable component + props builder (lazy handler boundary) |
9//! | [`#[server]`](server) | Async RPC at `POST /_resuma/action/:name` |
10//! | [`#[data]`](data) | Concise typed DTO/model helper |
11//! | [`computed!`](computed) | Client-replayable derived signal (rs2js) |
12//! | [`effect!`](effect) | Client-replayable side effect (rs2js) |
13//! | [`debounce!`](debounce) | Debounced client reaction |
14//! | [`#[island]`](island) | Optional heavy lazy boundary (`load = "visible"`) |
15//! | [`#[worker]`](worker) | Execution-layer async worker |
16//! | [`#[upload]`](upload) | Named multipart at `POST /_resuma/upload/:name` |
17//! | [`js!`](js) | Raw JavaScript handler escape hatch |
18
19mod component_macro;
20mod computed_macro;
21mod data_macro;
22mod debounce_macro;
23mod effect_macro;
24mod extract_codegen;
25mod island_macro;
26mod js_macro;
27mod layout_macro;
28mod load_macro;
29mod middleware_macro;
30mod rs2js;
31mod server_macro;
32mod store_macro;
33mod submit_macro;
34mod upload_macro;
35mod view_macro;
36mod worker_macro;
37
38use proc_macro::TokenStream;
39
40/// `view!` — JSX-like template macro.
41#[proc_macro]
42pub fn view(input: TokenStream) -> TokenStream {
43 view_macro::expand(input.into()).into()
44}
45
46/// `#[component]` — resumable component with generated props builder.
47///
48/// Wraps output in a lazy handler boundary; event handlers register under
49/// `/_resuma/handler/{ComponentName}.js`. For heavy optional lazy bundles, see [`island`].
50#[proc_macro_attribute]
51pub fn component(args: TokenStream, input: TokenStream) -> TokenStream {
52 component_macro::expand(args.into(), input.into()).into()
53}
54
55/// `#[server]` — exposes an async fn as a server action.
56#[proc_macro_attribute]
57pub fn server(args: TokenStream, input: TokenStream) -> TokenStream {
58 server_macro::expand(args.into(), input.into()).into()
59}
60
61/// `#[data]` — concise DTO/model helper for Resuma data structs and enums.
62#[proc_macro_attribute]
63pub fn data(args: TokenStream, input: TokenStream) -> TokenStream {
64 data_macro::expand(args.into(), input.into()).into()
65}
66
67/// `#[island]` — optional interactive boundary for heavy or visibility-gated JS.
68///
69/// Most UI only needs [`component`]. Use islands for large client bundles,
70/// `#[island(load = "visible")]`, or dev HMR refresh via `GET /_resuma/island/:instance`.
71#[proc_macro_attribute]
72pub fn island(args: TokenStream, input: TokenStream) -> TokenStream {
73 island_macro::expand(args.into(), input.into()).into()
74}
75
76/// `#[load]` — Resuma Flow server data loader.
77#[proc_macro_attribute]
78pub fn load(args: TokenStream, input: TokenStream) -> TokenStream {
79 load_macro::expand(args.into(), input.into()).into()
80}
81
82/// `#[submit]` — Resuma Flow form submission handler.
83#[proc_macro_attribute]
84pub fn submit(args: TokenStream, input: TokenStream) -> TokenStream {
85 submit_macro::expand(args.into(), input.into()).into()
86}
87
88/// `#[layout]` — Resuma Flow layout wrapper.
89#[proc_macro_attribute]
90pub fn layout(args: TokenStream, input: TokenStream) -> TokenStream {
91 layout_macro::expand(args.into(), input.into()).into()
92}
93
94/// `#[middleware]` — Resuma Flow request middleware.
95#[proc_macro_attribute]
96pub fn middleware(args: TokenStream, input: TokenStream) -> TokenStream {
97 middleware_macro::expand(args.into(), input.into()).into()
98}
99
100/// `#[worker]` — registers an async fn as a Resuma execution worker.
101///
102/// ```ignore
103/// #[worker(intent = "analyze leads")]
104/// async fn lead_agent(input: Value, ctx: WorkerContext) -> Result<Value> { ... }
105/// ```
106#[proc_macro_attribute]
107pub fn worker(args: TokenStream, input: TokenStream) -> TokenStream {
108 worker_macro::expand(args.into(), input.into()).into()
109}
110
111/// `#[upload]` — registers an async multipart handler at `POST /_resuma/upload/{fn_name}`.
112///
113/// ```ignore
114/// #[upload(max_bytes = 4_000_000, mime = "image/png,image/jpeg")]
115/// async fn heightmap(file: UploadedFile) -> Result<UploadReceipt> {
116/// Ok(store_upload(file.bytes, &file.content_type)?)
117/// }
118/// ```
119#[proc_macro_attribute]
120pub fn upload(args: TokenStream, input: TokenStream) -> TokenStream {
121 upload_macro::expand(args.into(), input.into()).into()
122}
123
124/// `js!` — raw JavaScript escape hatch for event handlers.
125#[proc_macro]
126pub fn js(input: TokenStream) -> TokenStream {
127 js_macro::expand(input.into()).into()
128}
129
130/// `computed!([deps…], move || …)` — derived signal with client replay (rs2js-translated).
131///
132/// Runs during SSR and replays in the browser when dependencies change.
133/// For SSR-only derived state, use [`use_computed`](https://docs.rs/resuma/latest/resuma/fn.use_computed.html) instead.
134#[proc_macro]
135pub fn computed(input: TokenStream) -> TokenStream {
136 computed_macro::expand(input.into()).into()
137}
138
139/// `effect!([signals…], move || { … })` — client-replayable side effect (rs2js).
140#[proc_macro]
141pub fn effect(input: TokenStream) -> TokenStream {
142 effect_macro::expand(input.into()).into()
143}
144
145#[proc_macro_derive(Store)]
146pub fn derive_store(input: TokenStream) -> TokenStream {
147 store_macro::derive(input)
148}
149
150/// `debounce!([deps…], ms, move || …)` — debounced client reaction (rs2js-translated).
151///
152/// ```ignore
153/// debounce!([search], 300, move || { /* runs after search settles */ });
154/// ```
155#[proc_macro]
156pub fn debounce(input: TokenStream) -> TokenStream {
157 debounce_macro::expand(input.into()).into()
158}