typespec-rust-emitter 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -0
- package/QWEN.md +83 -29
- package/README.md +36 -24
- package/dist/src/emitter.js +102 -112
- package/dist/src/emitter.js.map +1 -1
- package/example/output-rust/src/generated/server.rs +58 -156
- package/example/output-rust/src/generated/types.rs +12 -12
- package/example/package-lock.json +1 -1
- package/package.json +1 -1
- package/src/emitter.ts +117 -144
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,95 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.5.0] - 2026-03-29
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Date/time scalars now generate proper chrono types instead of `String`:
|
|
13
|
+
- `utcDateTime` → `chrono::DateTime<chrono::Utc>`
|
|
14
|
+
- `offsetDateTime` → `chrono::DateTime<chrono::FixedOffset>`
|
|
15
|
+
- `plainDateTime` → `chrono::NaiveDateTime`
|
|
16
|
+
- `plainDate` → `chrono::NaiveDate`
|
|
17
|
+
- `plainTime` → `chrono::NaiveTime`
|
|
18
|
+
|
|
19
|
+
### Example
|
|
20
|
+
|
|
21
|
+
```typespec
|
|
22
|
+
model Event {
|
|
23
|
+
createdAt: utcDateTime;
|
|
24
|
+
startTime: plainDateTime;
|
|
25
|
+
eventDate: plainDate;
|
|
26
|
+
eventTime: plainTime;
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Generates:
|
|
31
|
+
|
|
32
|
+
```rust
|
|
33
|
+
pub struct Event {
|
|
34
|
+
pub created_at: chrono::DateTime<chrono::Utc>,
|
|
35
|
+
pub start_time: chrono::NaiveDateTime,
|
|
36
|
+
pub event_date: chrono::NaiveDate,
|
|
37
|
+
pub event_time: chrono::NaiveTime,
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## [0.4.0] - 2026-03-27
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **Breaking**: Server trait methods now accept individual parameters instead of request structs
|
|
46
|
+
- `async fn subjects_create(&self, claims: Self::Claims, request: SubjectsCreateRequest)` → `async fn subjects_create(&self, claims: Self::Claims, group_id: i64, body: CreateSubjectBody)`
|
|
47
|
+
- Path parameters extracted with `Path<T>` extractor
|
|
48
|
+
- Body extracted with `Json<T>` extractor
|
|
49
|
+
- Request structs (`SubjectsCreateRequest`, etc.) are no longer generated
|
|
50
|
+
- **Breaking**: Extractor order in handlers follows axum conventions
|
|
51
|
+
- Order: `State` → `Extension` → `Path` → `Json`
|
|
52
|
+
- Fixes axum 0.8 `Handler` trait inference issues
|
|
53
|
+
- Removed unused `Query` extractor import from generated code
|
|
54
|
+
- Fixed decorator detection to use `getDecoratorName()` instead of direct property access
|
|
55
|
+
|
|
56
|
+
### Benefits
|
|
57
|
+
|
|
58
|
+
- Cleaner server trait API - no boilerplate request structs
|
|
59
|
+
- Direct parameter access in handler implementations
|
|
60
|
+
- Follows axum best practices for extractor ordering
|
|
61
|
+
- Better IDE autocomplete for handler parameters
|
|
62
|
+
|
|
63
|
+
### Example
|
|
64
|
+
|
|
65
|
+
**TypeSpec:**
|
|
66
|
+
|
|
67
|
+
```typespec
|
|
68
|
+
@post
|
|
69
|
+
@route("/groups/{groupId}/subjects")
|
|
70
|
+
op create(@path groupId: int64, @body body: CreateSubjectBody): Subject;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Before (v0.3.0):**
|
|
74
|
+
|
|
75
|
+
```rust
|
|
76
|
+
// Server trait
|
|
77
|
+
async fn subjects_create(&self, claims: Self::Claims, request: SubjectsCreateRequest) -> Result<...>;
|
|
78
|
+
|
|
79
|
+
// Handler
|
|
80
|
+
axum::extract::Query(query): axum::extract::Query<SubjectsCreateRequest>
|
|
81
|
+
let result = service.subjects_create(claims, query).await;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**After (v0.4.0):**
|
|
85
|
+
|
|
86
|
+
```rust
|
|
87
|
+
// Server trait
|
|
88
|
+
async fn subjects_create(&self, claims: Self::Claims, group_id: i64, body: CreateSubjectBody) -> Result<...>;
|
|
89
|
+
|
|
90
|
+
// Handler
|
|
91
|
+
Extension(claims): Extension<S::Claims>,
|
|
92
|
+
Path(group_id): Path<i64>,
|
|
93
|
+
Json(payload): Json<CreateSubjectBody>
|
|
94
|
+
let result = service.subjects_create(claims, group_id, payload).await;
|
|
95
|
+
```
|
|
96
|
+
|
|
8
97
|
## [0.3.0] - 2026-03-27
|
|
9
98
|
|
|
10
99
|
### Added
|
package/QWEN.md
CHANGED
|
@@ -37,6 +37,7 @@ typespec-emitter/
|
|
|
37
37
|
## Build & Run Commands
|
|
38
38
|
|
|
39
39
|
### Primary Workflow (Run After Every Change)
|
|
40
|
+
|
|
40
41
|
```bash
|
|
41
42
|
just build # Compile TypeScript (npm run build)
|
|
42
43
|
just test # Run unit tests (npm test)
|
|
@@ -45,6 +46,7 @@ just check-rust # Verify Rust compiles (cargo check)
|
|
|
45
46
|
```
|
|
46
47
|
|
|
47
48
|
### Individual Commands
|
|
49
|
+
|
|
48
50
|
```bash
|
|
49
51
|
# Development
|
|
50
52
|
npm run build # tsc compile
|
|
@@ -61,49 +63,52 @@ just publish # build + npm publish
|
|
|
61
63
|
|
|
62
64
|
## Type Mappings (TypeSpec → Rust)
|
|
63
65
|
|
|
64
|
-
| TypeSpec
|
|
65
|
-
|
|
66
|
-
| `string`
|
|
67
|
-
| `int8/16/32/64`
|
|
68
|
-
| `uint8/16/32/64` | `u8/u16/u32/u64`
|
|
69
|
-
| `float32/64`
|
|
70
|
-
| `boolean`
|
|
71
|
-
| `bytes`
|
|
72
|
-
| `T[]`
|
|
73
|
-
| `Record<T>`
|
|
74
|
-
| `T \| null`
|
|
66
|
+
| TypeSpec | Rust |
|
|
67
|
+
| ---------------- | -------------------- |
|
|
68
|
+
| `string` | `String` |
|
|
69
|
+
| `int8/16/32/64` | `i8/i16/i32/i64` |
|
|
70
|
+
| `uint8/16/32/64` | `u8/u16/u32/u64` |
|
|
71
|
+
| `float32/64` | `f32/f64` |
|
|
72
|
+
| `boolean` | `bool` |
|
|
73
|
+
| `bytes` | `Vec<u8>` |
|
|
74
|
+
| `T[]` | `Vec<T>` |
|
|
75
|
+
| `Record<T>` | `HashMap<String, T>` |
|
|
76
|
+
| `T \| null` | `Option<T>` |
|
|
75
77
|
|
|
76
78
|
### Format Mappings
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
|
80
|
-
| `"
|
|
81
|
-
| `"
|
|
79
|
+
|
|
80
|
+
| `@format()` | Rust Type |
|
|
81
|
+
| ------------- | ----------------------- |
|
|
82
|
+
| `"uuid"` | `uuid::Uuid` |
|
|
83
|
+
| `"date"` | `chrono::NaiveDate` |
|
|
84
|
+
| `"time"` | `chrono::NaiveTime` |
|
|
82
85
|
| `"date-time"` | `chrono::DateTime<Utc>` |
|
|
83
86
|
|
|
84
87
|
## Decorators
|
|
85
88
|
|
|
86
|
-
| Decorator
|
|
87
|
-
|
|
88
|
-
| `@error`
|
|
89
|
-
| `@pattern("regex")`
|
|
90
|
-
| `@rustDerive("...")`
|
|
91
|
-
| `@rustDerives("...", "...")` | Adds multiple custom derives (models & enums)
|
|
92
|
-
| `@rustAttr("...")`
|
|
93
|
-
| `@rustAttrs("...", "...")`
|
|
94
|
-
| `@doc("...")`
|
|
95
|
-
| `@useAuth(BearerAuth)`
|
|
96
|
-
| `@maxLength(n)`
|
|
89
|
+
| Decorator | Effect |
|
|
90
|
+
| ---------------------------- | ---------------------------------------------------------------------------- |
|
|
91
|
+
| `@error` | Adds `thiserror::Error` derive + `#[error("{code}: {message}")]` |
|
|
92
|
+
| `@pattern("regex")` | Generates `TryFrom<String>` with regex validation |
|
|
93
|
+
| `@rustDerive("...")` | Adds custom derive (models & enums, e.g., `sqlx::FromRow`, `sqlx::Type`) |
|
|
94
|
+
| `@rustDerives("...", "...")` | Adds multiple custom derives (models & enums) |
|
|
95
|
+
| `@rustAttr("...")` | Adds custom Rust attribute (models & enums, e.g., `sqlx(type_name = "...")`) |
|
|
96
|
+
| `@rustAttrs("...", "...")` | Adds multiple custom attributes (models & enums) |
|
|
97
|
+
| `@doc("...")` | Generates `///` doc comments |
|
|
98
|
+
| `@useAuth(BearerAuth)` | Marks operation as protected (adds `Claims` param) |
|
|
99
|
+
| `@maxLength(n)` | Documentation only |
|
|
97
100
|
|
|
98
101
|
## Output Files
|
|
99
102
|
|
|
100
103
|
### types.rs
|
|
104
|
+
|
|
101
105
|
- All models → `pub struct` with serde derives
|
|
102
106
|
- Enums → `pub enum` with serde rename
|
|
103
107
|
- Unions → `Option<T>` for nullable, or sum types
|
|
104
108
|
- Scalars → `pub type` or `pub struct` (if pattern validation)
|
|
105
109
|
|
|
106
110
|
### server.rs
|
|
111
|
+
|
|
107
112
|
- `Server` trait with `type Claims` associated type
|
|
108
113
|
- Request structs per operation
|
|
109
114
|
- Response enums with status code variants
|
|
@@ -112,6 +117,7 @@ just publish # build + npm publish
|
|
|
112
117
|
## Key Implementation Details
|
|
113
118
|
|
|
114
119
|
### emitter.ts Architecture
|
|
120
|
+
|
|
115
121
|
1. `navigateProgram()` - Walks TypeSpec AST
|
|
116
122
|
2. Collects: models, enums, unions, scalars, operations
|
|
117
123
|
3. Processes decorators (`@error`, `@pattern`, `@rustDerive`)
|
|
@@ -119,15 +125,19 @@ just publish # build + npm publish
|
|
|
119
125
|
5. Emits files to configured output directory
|
|
120
126
|
|
|
121
127
|
### Server Trait Generation
|
|
128
|
+
|
|
122
129
|
- Generates `Server` trait with `type Claims: Send + Sync + 'static` associated type
|
|
123
|
-
- Handler functions
|
|
130
|
+
- Handler functions accept individual parameters (path params, body) directly
|
|
131
|
+
- Path params extracted with `Path<T>`
|
|
132
|
+
- Body extracted with `Json<T>`
|
|
124
133
|
- Protected routes (`@useAuth`) receive `claims: Self::Claims` via `Extension<Self::Claims>`
|
|
125
|
-
-
|
|
134
|
+
- Extractor order: `State` → `Extension` → `Path` → `Json`
|
|
126
135
|
- `create_router<S, M>(service: S, middleware: M)` accepts middleware function
|
|
127
136
|
- Middleware wraps protected routes: `middleware(protected)`
|
|
128
137
|
- Router merges public/protected, applies `.with_state(service)` once at end
|
|
129
138
|
|
|
130
139
|
### Test Pattern
|
|
140
|
+
|
|
131
141
|
```typescript
|
|
132
142
|
import { emit } from "./test-host.js";
|
|
133
143
|
const results = await emit(`model User { name: string; }`);
|
|
@@ -138,15 +148,18 @@ strictEqual(output.includes("pub struct User"), true);
|
|
|
138
148
|
## Dependencies
|
|
139
149
|
|
|
140
150
|
### Peer (Required)
|
|
151
|
+
|
|
141
152
|
- `@typespec/compiler` >=1.0.0
|
|
142
153
|
- `@typespec/emitter-framework` ^0.17.0
|
|
143
154
|
|
|
144
155
|
### Dev
|
|
156
|
+
|
|
145
157
|
- `typescript` ^5.3.3
|
|
146
158
|
- `eslint` ^9.15.0
|
|
147
159
|
- `prettier` ^3.3.3
|
|
148
160
|
|
|
149
161
|
### Generated Rust (example/output-rust/Cargo.toml)
|
|
162
|
+
|
|
150
163
|
```toml
|
|
151
164
|
serde = { version = "1.0", features = ["derive"] }
|
|
152
165
|
thiserror = "2.0"
|
|
@@ -163,6 +176,7 @@ tokio = { version = "1.50", features = ["full"] }
|
|
|
163
176
|
## Configuration Files
|
|
164
177
|
|
|
165
178
|
### tspconfig.yaml
|
|
179
|
+
|
|
166
180
|
```yaml
|
|
167
181
|
emit:
|
|
168
182
|
- "@typespec/openapi3"
|
|
@@ -173,6 +187,7 @@ options:
|
|
|
173
187
|
```
|
|
174
188
|
|
|
175
189
|
### tsconfig.json
|
|
190
|
+
|
|
176
191
|
- Target: ES2022
|
|
177
192
|
- Module: NodeNext
|
|
178
193
|
- Strict: true
|
|
@@ -196,14 +211,51 @@ options:
|
|
|
196
211
|
|
|
197
212
|
## Recent Changes
|
|
198
213
|
|
|
214
|
+
### 2026-03-27: v0.4.0 - Individual Parameters Instead of Request Structs
|
|
215
|
+
|
|
216
|
+
**Breaking Changes**:
|
|
217
|
+
|
|
218
|
+
- Server trait methods now accept individual parameters instead of request structs
|
|
219
|
+
- `async fn subjects_create(&self, claims: Self::Claims, request: SubjectsCreateRequest)` → `async fn subjects_create(&self, claims: Self::Claims, group_id: i64, body: CreateSubjectBody)`
|
|
220
|
+
- Request structs (`SubjectsCreateRequest`, etc.) are no longer generated
|
|
221
|
+
- Handler extractor order follows axum conventions: `State` → `Extension` → `Path` → `Json`
|
|
222
|
+
|
|
223
|
+
**Benefits**:
|
|
224
|
+
|
|
225
|
+
- Cleaner server trait API - no boilerplate request structs
|
|
226
|
+
- Direct parameter access in handler implementations
|
|
227
|
+
- Follows axum best practices for extractor ordering
|
|
228
|
+
- Better IDE autocomplete for handler parameters
|
|
229
|
+
|
|
230
|
+
**Example**:
|
|
231
|
+
|
|
232
|
+
```typespec
|
|
233
|
+
@post
|
|
234
|
+
@route("/groups/{groupId}/subjects")
|
|
235
|
+
op create(@path groupId: int64, @body body: CreateSubjectBody): Subject;
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
```rust
|
|
239
|
+
// Server trait
|
|
240
|
+
async fn subjects_create(&self, claims: Self::Claims, group_id: i64, body: CreateSubjectBody) -> Result<...>;
|
|
241
|
+
|
|
242
|
+
// Handler
|
|
243
|
+
Extension(claims): Extension<S::Claims>,
|
|
244
|
+
Path(group_id): Path<i64>,
|
|
245
|
+
Json(payload): Json<CreateSubjectBody>
|
|
246
|
+
let result = service.subjects_create(claims, group_id, payload).await;
|
|
247
|
+
```
|
|
248
|
+
|
|
199
249
|
### 2026-03-27: v0.3.0 - Custom Attributes & Enum Derives
|
|
200
250
|
|
|
201
251
|
**New Features**:
|
|
252
|
+
|
|
202
253
|
- `@rustAttr` / `@rustAttrs` decorators for custom Rust attributes (models & enums)
|
|
203
254
|
- `@rustDerive` / `@rustDerives` now work on enums (previously models only)
|
|
204
255
|
- Attributes render after `#[derive(...)]` for proper Rust syntax
|
|
205
256
|
|
|
206
257
|
**Example**:
|
|
258
|
+
|
|
207
259
|
```typespec
|
|
208
260
|
@rustDerive("sqlx::Type")
|
|
209
261
|
@rustAttr("sqlx(type_name = \"study_status\")")
|
|
@@ -219,6 +271,7 @@ pub enum StudyStatus { ... }
|
|
|
219
271
|
### 2026-03-27: v0.2.0 - Server Trait Refactoring
|
|
220
272
|
|
|
221
273
|
**Changes**:
|
|
274
|
+
|
|
222
275
|
- `pub trait Server<Claims>` → `pub trait Server` with `type Claims` associated type
|
|
223
276
|
- Removed generated `Claims` struct from `types.rs` (users define their own)
|
|
224
277
|
- `create_router<S, M>(service: S, middleware: M)` now accepts middleware function
|
|
@@ -226,6 +279,7 @@ pub enum StudyStatus { ... }
|
|
|
226
279
|
- Single `.with_state(service)` call at end of router creation
|
|
227
280
|
|
|
228
281
|
**Benefits**:
|
|
282
|
+
|
|
229
283
|
- Cleaner API - Claims type defined by user, not generated
|
|
230
284
|
- Flexible middleware - any function `FnOnce(Router<S>) -> Router<S>`
|
|
231
285
|
- No duplicate `.with_state(service.clone())` calls
|
package/README.md
CHANGED
|
@@ -248,9 +248,9 @@ namespace Groups {
|
|
|
248
248
|
pub trait Server: Send + Sync {
|
|
249
249
|
type Claims: Send + Sync + 'static;
|
|
250
250
|
|
|
251
|
-
async fn groups_list(&self
|
|
252
|
-
async fn groups_create(&self, claims: Self::Claims,
|
|
253
|
-
async fn groups_get_by_id(&self,
|
|
251
|
+
async fn groups_list(&self) -> Result<GroupsListResponse>;
|
|
252
|
+
async fn groups_create(&self, claims: Self::Claims, body: CreateGroupBody) -> Result<GroupsCreateResponse>;
|
|
253
|
+
async fn groups_get_by_id(&self, id: i64) -> Result<GroupsGetByIdResponse>;
|
|
254
254
|
}
|
|
255
255
|
```
|
|
256
256
|
|
|
@@ -270,10 +270,7 @@ pub struct MyServer {
|
|
|
270
270
|
impl Server for MyServer {
|
|
271
271
|
type Claims = Claims; // Your custom claims type
|
|
272
272
|
|
|
273
|
-
async fn groups_list(
|
|
274
|
-
&self,
|
|
275
|
-
_request: GroupsListRequest,
|
|
276
|
-
) -> eyre::Result<GroupsListResponse> {
|
|
273
|
+
async fn groups_list(&self) -> eyre::Result<GroupsListResponse> {
|
|
277
274
|
let groups = sqlx::query_as::<_, Group>("SELECT * FROM groups")
|
|
278
275
|
.fetch_all(&self.state.db)
|
|
279
276
|
.await?;
|
|
@@ -283,19 +280,29 @@ impl Server for MyServer {
|
|
|
283
280
|
async fn groups_create(
|
|
284
281
|
&self,
|
|
285
282
|
claims: Self::Claims,
|
|
286
|
-
|
|
283
|
+
body: CreateGroupBody,
|
|
287
284
|
) -> eyre::Result<GroupsCreateResponse> {
|
|
288
|
-
//
|
|
285
|
+
// Direct access to body fields
|
|
289
286
|
let group = sqlx::query_as::<_, Group>(
|
|
290
287
|
"INSERT INTO groups (name, owner_id) VALUES ($1, $2) RETURNING *"
|
|
291
288
|
)
|
|
292
|
-
.bind(&
|
|
289
|
+
.bind(&body.name)
|
|
293
290
|
.bind(&claims.sub)
|
|
294
291
|
.fetch_one(&self.state.db)
|
|
295
292
|
.await?;
|
|
296
293
|
Ok(GroupsCreateResponse::Created(Json(group)))
|
|
297
294
|
}
|
|
298
295
|
|
|
296
|
+
async fn groups_get_by_id(&self, id: i64) -> eyre::Result<GroupsGetByIdResponse> {
|
|
297
|
+
// Direct access to path parameter
|
|
298
|
+
let group = sqlx::query_as::<_, Group>("SELECT * FROM groups WHERE id = $1")
|
|
299
|
+
.bind(id)
|
|
300
|
+
.fetch_optional(&self.state.db)
|
|
301
|
+
.await?
|
|
302
|
+
.ok_or_else(|| GroupsGetByIdResponse::NotFound)?;
|
|
303
|
+
Ok(GroupsGetByIdResponse::Ok(Json(group)))
|
|
304
|
+
}
|
|
305
|
+
|
|
299
306
|
// ... implement other methods
|
|
300
307
|
}
|
|
301
308
|
```
|
|
@@ -352,14 +359,19 @@ Public routes do not receive claims and are not wrapped with auth middleware.
|
|
|
352
359
|
| TypeSpec Type | Rust Type |
|
|
353
360
|
| ---------------- | ------------------------------------------- |
|
|
354
361
|
| `string` | `String` |
|
|
355
|
-
| `
|
|
356
|
-
| `
|
|
357
|
-
| `float32`
|
|
358
|
-
| `float64` | `f64` |
|
|
362
|
+
| `int8/16/32/64` | `i8/i16/i32/i64` |
|
|
363
|
+
| `uint8/16/32/64` | `u8/u16/u32/u64` |
|
|
364
|
+
| `float32/64` | `f32/f64` |
|
|
359
365
|
| `boolean` | `bool` |
|
|
366
|
+
| `bytes` | `Vec<u8>` |
|
|
360
367
|
| `string[]` | `Vec<String>` |
|
|
361
368
|
| `Record<string>` | `std::collections::HashMap<String, String>` |
|
|
362
369
|
| `T \| null` | `Option<T>` |
|
|
370
|
+
| `utcDateTime` | `chrono::DateTime<chrono::Utc>` |
|
|
371
|
+
| `offsetDateTime` | `chrono::DateTime<chrono::FixedOffset>` |
|
|
372
|
+
| `plainDateTime` | `chrono::NaiveDateTime` |
|
|
373
|
+
| `plainDate` | `chrono::NaiveDate` |
|
|
374
|
+
| `plainTime` | `chrono::NaiveTime` |
|
|
363
375
|
|
|
364
376
|
### Format Mappings
|
|
365
377
|
|
|
@@ -372,16 +384,16 @@ Public routes do not receive claims and are not wrapped with auth middleware.
|
|
|
372
384
|
|
|
373
385
|
## Decorators
|
|
374
386
|
|
|
375
|
-
| Decorator | Description
|
|
376
|
-
| ---------------------------- |
|
|
377
|
-
| `@error` | Adds `thiserror::Error` derive with error message
|
|
378
|
-
| `@pattern("regex")` | Generates `TryFrom<String>` with regex validation
|
|
379
|
-
| `@rustDerive("...")` | Adds a custom derive macro (models & enums)
|
|
380
|
-
| `@rustDerives("...", "...")` | Adds multiple custom derive macros (models & enums)
|
|
381
|
-
| `@rustAttr("...")` | Adds a custom Rust attribute (models & enums)
|
|
382
|
-
| `@rustAttrs("...", "...")` | Adds multiple custom Rust attributes (models & enums)
|
|
383
|
-
| `@doc("...")` | Generates `///` doc comments
|
|
384
|
-
| `@useAuth(AuthType)` | Marks operation as protected, adds `Claims` parameter
|
|
387
|
+
| Decorator | Description |
|
|
388
|
+
| ---------------------------- | ----------------------------------------------------- |
|
|
389
|
+
| `@error` | Adds `thiserror::Error` derive with error message |
|
|
390
|
+
| `@pattern("regex")` | Generates `TryFrom<String>` with regex validation |
|
|
391
|
+
| `@rustDerive("...")` | Adds a custom derive macro (models & enums) |
|
|
392
|
+
| `@rustDerives("...", "...")` | Adds multiple custom derive macros (models & enums) |
|
|
393
|
+
| `@rustAttr("...")` | Adds a custom Rust attribute (models & enums) |
|
|
394
|
+
| `@rustAttrs("...", "...")` | Adds multiple custom Rust attributes (models & enums) |
|
|
395
|
+
| `@doc("...")` | Generates `///` doc comments |
|
|
396
|
+
| `@useAuth(AuthType)` | Marks operation as protected, adds `Claims` parameter |
|
|
385
397
|
|
|
386
398
|
## Building
|
|
387
399
|
|