typespec-rust-emitter 0.6.0 → 0.8.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/QWEN.md DELETED
@@ -1,292 +0,0 @@
1
- # QWEN.md - Project Context
2
-
3
- ## Project Overview
4
-
5
- **TypeSpec Rust Emitter** - A TypeScript-based code generator that converts TypeSpec specifications into idiomatic Rust code.
6
-
7
- - **Type**: TypeScript/Node.js project (TypeSpec emitter)
8
- - **Output**: Generates Rust structs, enums, server traits with serde, thiserror, axum support
9
- - **Main Entry**: `src/emitter.ts` - core codegen logic
10
- - **Package**: `typespec-rust-emitter` v0.3.0
11
-
12
- ## Directory Structure
13
-
14
- ```
15
- typespec-emitter/
16
- ├── src/
17
- │ ├── emitter.ts # MAIN: TypeSpec→Rust code generation
18
- │ ├── index.ts # Exports ($onEmit, $rustDerive, $rustDerives, $rustAttr, $rustAttrs)
19
- │ ├── lib.ts # TypeSpec library definition
20
- │ ├── lib.tsp # Decorator declarations
21
- │ └── testing/ # Test utilities
22
- ├── test/
23
- │ ├── hello.test.ts # Unit tests
24
- │ └── test-host.ts # Test infrastructure (emit() helper)
25
- ├── example/
26
- │ ├── main.tsp # Demo TypeSpec entry
27
- │ ├── lib/learning/ # Demo models & operations
28
- │ ├── tspconfig.yaml # Emitter configuration
29
- │ └── output-rust/ # Generated Rust crate
30
- ├── oas3-gen/ # Reference template repo
31
- ├── dist/ # Compiled TypeScript output
32
- ├── package.json # Dependencies & scripts
33
- ├── tsconfig.json # TypeScript config (strict mode)
34
- └── justfile # Build automation
35
- ```
36
-
37
- ## Build & Run Commands
38
-
39
- ### Primary Workflow (Run After Every Change)
40
-
41
- ```bash
42
- just build # Compile TypeScript (npm run build)
43
- just test # Run unit tests (npm test)
44
- just compile # Generate Rust code from example
45
- just check-rust # Verify Rust compiles (cargo check)
46
- ```
47
-
48
- ### Individual Commands
49
-
50
- ```bash
51
- # Development
52
- npm run build # tsc compile
53
- npm run watch # Watch mode
54
- npm run lint # ESLint check
55
- npm run lint:fix # Auto-fix lint
56
- npm run format # Prettier format
57
- npm run format:check
58
-
59
- # Full pipeline
60
- just install # npm install (root + example)
61
- just publish # build + npm publish
62
- ```
63
-
64
- ## Type Mappings (TypeSpec → Rust)
65
-
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>` |
77
-
78
- ### Format Mappings
79
-
80
- | `@format()` | Rust Type |
81
- | ------------- | ----------------------- |
82
- | `"uuid"` | `uuid::Uuid` |
83
- | `"date"` | `chrono::NaiveDate` |
84
- | `"time"` | `chrono::NaiveTime` |
85
- | `"date-time"` | `chrono::DateTime<Utc>` |
86
-
87
- ## Decorators
88
-
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 |
100
-
101
- ## Output Files
102
-
103
- ### types.rs
104
-
105
- - All models → `pub struct` with serde derives
106
- - Enums → `pub enum` with serde rename
107
- - Unions → `Option<T>` for nullable, or sum types
108
- - Scalars → `pub type` or `pub struct` (if pattern validation)
109
-
110
- ### server.rs
111
-
112
- - `Server` trait with `type Claims` associated type
113
- - Request structs per operation
114
- - Response enums with status code variants
115
- - `create_router<S, M>(service: S, middleware: M)` function with axum routes
116
-
117
- ## Key Implementation Details
118
-
119
- ### emitter.ts Architecture
120
-
121
- 1. `navigateProgram()` - Walks TypeSpec AST
122
- 2. Collects: models, enums, unions, scalars, operations
123
- 3. Processes decorators (`@error`, `@pattern`, `@rustDerive`)
124
- 4. Generates Rust via string templates
125
- 5. Emits files to configured output directory
126
-
127
- ### Server Trait Generation
128
-
129
- - Generates `Server` trait with `type Claims: Send + Sync + 'static` associated type
130
- - Handler functions accept individual parameters (path params, body) directly
131
- - Path params extracted with `Path<T>`
132
- - Body extracted with `Json<T>`
133
- - Protected routes (`@useAuth`) receive `claims: Self::Claims` via `Extension<Self::Claims>`
134
- - Extractor order: `State` → `Extension` → `Path` → `Json`
135
- - `create_router<S, M>(service: S, middleware: M)` accepts middleware function
136
- - Middleware wraps protected routes: `middleware(protected)`
137
- - Router merges public/protected, applies `.with_state(service)` once at end
138
-
139
- ### Test Pattern
140
-
141
- ```typescript
142
- import { emit } from "./test-host.js";
143
- const results = await emit(`model User { name: string; }`);
144
- const output = results["types.rs"];
145
- strictEqual(output.includes("pub struct User"), true);
146
- ```
147
-
148
- ## Dependencies
149
-
150
- ### Peer (Required)
151
-
152
- - `@typespec/compiler` >=1.0.0
153
- - `@typespec/emitter-framework` ^0.17.0
154
-
155
- ### Dev
156
-
157
- - `typescript` ^5.3.3
158
- - `eslint` ^9.15.0
159
- - `prettier` ^3.3.3
160
-
161
- ### Generated Rust (example/output-rust/Cargo.toml)
162
-
163
- ```toml
164
- serde = { version = "1.0", features = ["derive"] }
165
- thiserror = "2.0"
166
- uuid = { version = "1.23", features = ["serde"] }
167
- chrono = { version = "0.4", features = ["serde"] }
168
- regex = "1.12"
169
- sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "derive"] }
170
- axum = "0.8"
171
- eyre = "0.6"
172
- async-trait = "0.1"
173
- tokio = { version = "1.50", features = ["full"] }
174
- ```
175
-
176
- ## Configuration Files
177
-
178
- ### tspconfig.yaml
179
-
180
- ```yaml
181
- emit:
182
- - "@typespec/openapi3"
183
- - "typespec-rust-emitter"
184
- options:
185
- "typespec-rust-emitter":
186
- emitter-output-dir: "{output-dir}/../output-rust/src/generated"
187
- ```
188
-
189
- ### tsconfig.json
190
-
191
- - Target: ES2022
192
- - Module: NodeNext
193
- - Strict: true
194
- - Root/Out: `.` → `dist`
195
-
196
- ## Development Conventions
197
-
198
- 1. **TypeScript**: Strict mode, ES2022, NodeNext modules
199
- 2. **Testing**: Node.js built-in test runner (`node:test`)
200
- 3. **Formatting**: Prettier (yaml config)
201
- 4. **Linting**: ESLint + typescript-eslint
202
- 5. **Code Style**: Match existing patterns in `src/emitter.ts`
203
-
204
- ## Rules
205
-
206
- 1. Always run full cycle after changes: `build → test → compile → check-rust`
207
- 2. Add tests for new features in `test/hello.test.ts`
208
- 3. Generated Rust must compile (verify with `just check-rust`)
209
- 4. Reference `oas3-gen/` for advanced codegen patterns
210
- 5. No implicit any (strict TypeScript)
211
-
212
- ## Recent Changes
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
-
249
- ### 2026-03-27: v0.3.0 - Custom Attributes & Enum Derives
250
-
251
- **New Features**:
252
-
253
- - `@rustAttr` / `@rustAttrs` decorators for custom Rust attributes (models & enums)
254
- - `@rustDerive` / `@rustDerives` now work on enums (previously models only)
255
- - Attributes render after `#[derive(...)]` for proper Rust syntax
256
-
257
- **Example**:
258
-
259
- ```typespec
260
- @rustDerive("sqlx::Type")
261
- @rustAttr("sqlx(type_name = \"study_status\")")
262
- enum StudyStatus { Starting, Paused }
263
- ```
264
-
265
- ```rust
266
- #[derive(..., sqlx::Type)]
267
- #[sqlx(type_name = "study_status")]
268
- pub enum StudyStatus { ... }
269
- ```
270
-
271
- ### 2026-03-27: v0.2.0 - Server Trait Refactoring
272
-
273
- **Changes**:
274
-
275
- - `pub trait Server<Claims>` → `pub trait Server` with `type Claims` associated type
276
- - Removed generated `Claims` struct from `types.rs` (users define their own)
277
- - `create_router<S, M>(service: S, middleware: M)` now accepts middleware function
278
- - Middleware wraps protected routes: `middleware(protected)`
279
- - Single `.with_state(service)` call at end of router creation
280
-
281
- **Benefits**:
282
-
283
- - Cleaner API - Claims type defined by user, not generated
284
- - Flexible middleware - any function `FnOnce(Router<S>) -> Router<S>`
285
- - No duplicate `.with_state(service.clone())` calls
286
-
287
- ## TODO
288
-
289
- - [ ] More server trait test coverage
290
- - [ ] Integration tests with Rust compilation
291
- - [ ] Expand scalar format mappings (more chrono types)
292
- - [ ] Support additional HTTP decorators