mik_sdk_macros/
lib.rs

1// =============================================================================
2// CRATE-LEVEL QUALITY LINTS (following Tokio/Serde standards)
3// =============================================================================
4#![forbid(unsafe_code)]
5#![deny(unused_must_use)]
6#![warn(missing_docs)]
7#![warn(missing_debug_implementations)]
8#![warn(rust_2018_idioms)]
9// Note: unreachable_pub is not applicable to proc-macro crates where internal
10// functions need pub visibility for module organization but aren't exported
11#![warn(rustdoc::missing_crate_level_docs)]
12#![warn(rustdoc::broken_intra_doc_links)]
13// =============================================================================
14// CLIPPY CONFIGURATION FOR PROC-MACRO CRATES
15// =============================================================================
16// These lints are relaxed for proc-macro crates where syn/quote patterns are used
17#![allow(clippy::doc_markdown)] // Code in docs - extensive changes needed
18#![allow(clippy::missing_errors_doc)] // # Errors sections - doc-heavy
19#![allow(clippy::missing_panics_doc)] // # Panics sections - doc-heavy
20#![allow(clippy::indexing_slicing)] // Checked by syn parsing structure
21#![allow(clippy::unwrap_used)] // Struct fields are known to exist in derives
22#![allow(elided_lifetimes_in_paths)] // Common pattern with ParseStream
23
24//! Proc-macros for `mik-sdk` - clean JSON syntax for WASI HTTP handlers.
25
26use proc_macro::TokenStream;
27
28mod derive;
29mod dx;
30mod http_client;
31mod ids;
32mod json;
33mod response;
34mod schema;
35
36// Re-export internal types needed by other modules
37
38// ============================================================================
39// JSON Macro
40// ============================================================================
41
42/// Create a JSON value with clean syntax.
43#[proc_macro]
44pub fn json(input: TokenStream) -> TokenStream {
45    json::json_impl(input)
46}
47
48// ============================================================================
49// Response Macros
50// ============================================================================
51
52/// Return 200 OK with JSON body.
53#[proc_macro]
54pub fn ok(input: TokenStream) -> TokenStream {
55    response::ok_impl(input)
56}
57
58/// Return RFC 7807 Problem Details error response.
59#[proc_macro]
60pub fn error(input: TokenStream) -> TokenStream {
61    response::error_impl(input)
62}
63
64/// Create a 201 Created response.
65#[proc_macro]
66pub fn created(input: TokenStream) -> TokenStream {
67    response::created_impl(input)
68}
69
70/// Create a 204 No Content response.
71#[proc_macro]
72pub fn no_content(input: TokenStream) -> TokenStream {
73    response::no_content_impl(input)
74}
75
76/// Create a redirect response.
77#[proc_macro]
78pub fn redirect(input: TokenStream) -> TokenStream {
79    response::redirect_impl(input)
80}
81
82/// Return 404 Not Found.
83#[proc_macro]
84pub fn not_found(input: TokenStream) -> TokenStream {
85    response::not_found_impl(input)
86}
87
88/// Return 409 Conflict.
89#[proc_macro]
90pub fn conflict(input: TokenStream) -> TokenStream {
91    response::conflict_impl(input)
92}
93
94/// Return 403 Forbidden.
95#[proc_macro]
96pub fn forbidden(input: TokenStream) -> TokenStream {
97    response::forbidden_impl(input)
98}
99
100/// Return 400 Bad Request.
101#[proc_macro]
102pub fn bad_request(input: TokenStream) -> TokenStream {
103    response::bad_request_impl(input)
104}
105
106/// Return 202 Accepted.
107#[proc_macro]
108pub fn accepted(input: TokenStream) -> TokenStream {
109    response::accepted_impl(input)
110}
111
112// ============================================================================
113// DX Macros
114// ============================================================================
115
116/// Early return validation guard.
117#[proc_macro]
118pub fn guard(input: TokenStream) -> TokenStream {
119    dx::guard_impl(input)
120}
121
122/// Unwrap Option/Result or return error.
123#[proc_macro]
124pub fn ensure(input: TokenStream) -> TokenStream {
125    dx::ensure_impl(input)
126}
127
128// ============================================================================
129// HTTP Client Macro
130// ============================================================================
131
132/// Build an HTTP client request.
133#[proc_macro]
134pub fn fetch(input: TokenStream) -> TokenStream {
135    http_client::fetch_impl(input)
136}
137
138// ============================================================================
139// Utility Macros
140// ============================================================================
141
142/// Collect field values from a list.
143#[proc_macro]
144pub fn ids(input: TokenStream) -> TokenStream {
145    ids::ids_impl(input)
146}
147
148/// Define routes with typed inputs and OpenAPI generation.
149///
150/// ```ignore
151/// routes! {
152///     GET "/users" => list_users(query: ListQuery) -> Vec<User>,
153///     POST "/users" => create_user(body: CreateUserInput) -> User,
154///     GET "/users/{id}" => get_user(path: Id) -> User,
155///     PUT "/users/{id}" => update_user(path: Id, body: UpdateUser) -> User,
156///     DELETE "/users/{id}" => delete_user(path: Id),
157/// }
158/// ```
159#[proc_macro]
160pub fn routes(input: TokenStream) -> TokenStream {
161    schema::routes_impl(input)
162}
163
164// ============================================================================
165// Derive Macros
166// ============================================================================
167
168/// Derive macro for JSON body types.
169///
170/// Generates `FromJson`, `Validate`, and `OpenApiSchema` implementations.
171///
172/// ```ignore
173/// #[derive(Type)]
174/// pub struct CreateUser {
175///     #[field(min = 1, max = 100)]
176///     pub name: String,
177///
178///     #[field(format = "email")]
179///     pub email: String,
180///
181///     pub age: Option<i32>,
182/// }
183/// ```
184#[proc_macro_derive(Type, attributes(field))]
185pub fn derive_type(input: TokenStream) -> TokenStream {
186    derive::derive_type_impl(input)
187}
188
189/// Derive macro for query parameter types.
190///
191/// Generates `FromQuery` implementation.
192///
193/// ```ignore
194/// #[derive(Query)]
195/// pub struct ListQuery {
196///     #[field(default = 1)]
197///     pub page: u32,
198///
199///     #[field(default = 20, max = 100)]
200///     pub limit: u32,
201///
202///     pub search: Option<String>,
203/// }
204/// ```
205#[proc_macro_derive(Query, attributes(field))]
206pub fn derive_query(input: TokenStream) -> TokenStream {
207    derive::derive_query_impl(input)
208}
209
210/// Derive macro for path parameter types.
211///
212/// Generates `FromPath` implementation.
213///
214/// ```ignore
215/// #[derive(Path)]
216/// pub struct OrgUserPath {
217///     pub org_id: String,
218///     pub id: String,
219/// }
220/// ```
221#[proc_macro_derive(Path, attributes(field))]
222pub fn derive_path(input: TokenStream) -> TokenStream {
223    derive::derive_path_impl(input)
224}