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}