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 constants;
29mod debug;
30mod derive;
31mod dx;
32mod errors;
33mod http_client;
34mod ids;
35mod json;
36mod openapi;
37mod response;
38mod schema;
39mod trace;
40mod type_registry;
41
42// Re-export internal types needed by other modules
43
44// ============================================================================
45// JSON Macro
46// ============================================================================
47
48/// Create a JSON value with clean syntax.
49#[proc_macro]
50pub fn json(input: TokenStream) -> TokenStream {
51    json::json_impl(input)
52}
53
54// ============================================================================
55// Response Macros
56// ============================================================================
57
58/// Return 200 OK with JSON body.
59#[proc_macro]
60pub fn ok(input: TokenStream) -> TokenStream {
61    response::ok_impl(input)
62}
63
64/// Return RFC 7807 Problem Details error response.
65#[proc_macro]
66pub fn error(input: TokenStream) -> TokenStream {
67    response::error_impl(input)
68}
69
70/// Create a 201 Created response.
71#[proc_macro]
72pub fn created(input: TokenStream) -> TokenStream {
73    response::created_impl(input)
74}
75
76/// Create a 204 No Content response.
77#[proc_macro]
78pub fn no_content(input: TokenStream) -> TokenStream {
79    response::no_content_impl(input)
80}
81
82/// Create a redirect response.
83#[proc_macro]
84pub fn redirect(input: TokenStream) -> TokenStream {
85    response::redirect_impl(input)
86}
87
88/// Return 404 Not Found.
89#[proc_macro]
90pub fn not_found(input: TokenStream) -> TokenStream {
91    response::not_found_impl(input)
92}
93
94/// Return 409 Conflict.
95#[proc_macro]
96pub fn conflict(input: TokenStream) -> TokenStream {
97    response::conflict_impl(input)
98}
99
100/// Return 403 Forbidden.
101#[proc_macro]
102pub fn forbidden(input: TokenStream) -> TokenStream {
103    response::forbidden_impl(input)
104}
105
106/// Return 400 Bad Request.
107#[proc_macro]
108pub fn bad_request(input: TokenStream) -> TokenStream {
109    response::bad_request_impl(input)
110}
111
112/// Return 202 Accepted.
113#[proc_macro]
114pub fn accepted(input: TokenStream) -> TokenStream {
115    response::accepted_impl(input)
116}
117
118// ============================================================================
119// DX Macros
120// ============================================================================
121
122/// Early return validation guard.
123#[proc_macro]
124pub fn guard(input: TokenStream) -> TokenStream {
125    dx::guard_impl(input)
126}
127
128/// Unwrap Option/Result or return error.
129#[proc_macro]
130pub fn ensure(input: TokenStream) -> TokenStream {
131    dx::ensure_impl(input)
132}
133
134// ============================================================================
135// HTTP Client Macro
136// ============================================================================
137
138/// Build an HTTP client request.
139#[proc_macro]
140pub fn fetch(input: TokenStream) -> TokenStream {
141    http_client::fetch_impl(input)
142}
143
144// ============================================================================
145// Utility Macros
146// ============================================================================
147
148/// Collect field values from a list.
149#[proc_macro]
150pub fn ids(input: TokenStream) -> TokenStream {
151    ids::ids_impl(input)
152}
153
154/// Define routes with typed inputs and OpenAPI generation.
155///
156/// ```ignore
157/// routes! {
158///     GET "/users" => list_users(query: ListQuery) -> Vec<User>,
159///     POST "/users" => create_user(body: CreateUserInput) -> User,
160///     GET "/users/{id}" => get_user(path: Id) -> User,
161///     PUT "/users/{id}" => update_user(path: Id, body: UpdateUser) -> User,
162///     DELETE "/users/{id}" => delete_user(path: Id),
163/// }
164/// ```
165#[proc_macro]
166pub fn routes(input: TokenStream) -> TokenStream {
167    schema::routes_impl(input)
168}
169
170// ============================================================================
171// Derive Macros
172// ============================================================================
173
174/// Derive macro for JSON body types.
175///
176/// Generates `FromJson`, `Validate`, and `OpenApiSchema` implementations.
177///
178/// ```ignore
179/// #[derive(Type)]
180/// pub struct CreateUser {
181///     #[field(min = 1, max = 100)]
182///     pub name: String,
183///
184///     #[field(format = "email")]
185///     pub email: String,
186///
187///     pub age: Option<i32>,
188/// }
189/// ```
190#[proc_macro_derive(Type, attributes(field))]
191pub fn derive_type(input: TokenStream) -> TokenStream {
192    derive::derive_type_impl(input)
193}
194
195/// Derive macro for query parameter types.
196///
197/// Generates `FromQuery` implementation.
198///
199/// ```ignore
200/// #[derive(Query)]
201/// pub struct ListQuery {
202///     #[field(default = 1)]
203///     pub page: u32,
204///
205///     #[field(default = 20, max = 100)]
206///     pub limit: u32,
207///
208///     pub search: Option<String>,
209/// }
210/// ```
211#[proc_macro_derive(Query, attributes(field))]
212pub fn derive_query(input: TokenStream) -> TokenStream {
213    derive::derive_query_impl(input)
214}
215
216/// Derive macro for path parameter types.
217///
218/// Generates `FromPath` implementation.
219///
220/// ```ignore
221/// #[derive(Path)]
222/// pub struct OrgUserPath {
223///     pub org_id: String,
224///     pub id: String,
225/// }
226/// ```
227#[proc_macro_derive(Path, attributes(field))]
228pub fn derive_path(input: TokenStream) -> TokenStream {
229    derive::derive_path_impl(input)
230}