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}