zod-codegen 1.0.3 → 1.1.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 +7 -0
- package/CONTRIBUTING.md +1 -1
- package/EXAMPLES.md +704 -0
- package/PERFORMANCE.md +59 -0
- package/README.md +270 -58
- package/dist/src/services/code-generator.service.js +211 -26
- package/dist/src/types/openapi.js +1 -1
- package/dist/tests/unit/code-generator.test.js +219 -0
- package/dist/tests/unit/file-reader.test.js +110 -0
- package/dist/tests/unit/generator.test.js +77 -7
- package/eslint.config.mjs +1 -0
- package/examples/.gitkeep +3 -0
- package/examples/README.md +74 -0
- package/examples/petstore/README.md +121 -0
- package/examples/petstore/authenticated-usage.ts +60 -0
- package/examples/petstore/basic-usage.ts +51 -0
- package/examples/petstore/server-variables-usage.ts +63 -0
- package/examples/petstore/type.ts +217 -0
- package/examples/pokeapi/README.md +105 -0
- package/examples/pokeapi/basic-usage.ts +57 -0
- package/examples/pokeapi/custom-client.ts +56 -0
- package/examples/pokeapi/type.ts +109 -0
- package/package.json +4 -2
- package/samples/pokeapi-openapi.json +212 -0
- package/samples/server-variables-example.yaml +49 -0
- package/src/services/code-generator.service.ts +641 -57
- package/src/types/openapi.ts +1 -1
- package/tests/unit/code-generator.test.ts +243 -0
- package/tests/unit/file-reader.test.ts +134 -0
- package/tests/unit/generator.test.ts +99 -7
- package/tsconfig.examples.json +17 -0
- package/tsconfig.json +1 -1
package/PERFORMANCE.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Build Performance
|
|
2
|
+
|
|
3
|
+
## Current Build Time
|
|
4
|
+
|
|
5
|
+
- **Standard TypeScript (`tsc`)**: ~1.2 seconds
|
|
6
|
+
- **Project size**: 19 TypeScript files, ~184KB
|
|
7
|
+
|
|
8
|
+
## TypeScript Native Preview (TSGO)
|
|
9
|
+
|
|
10
|
+
For even faster builds, you can optionally use the TypeScript Native Preview (TSGO), a Go-based compiler that can be up to 10x faster.
|
|
11
|
+
|
|
12
|
+
### Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -D @typescript/native-preview
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Usage
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Use native compiler for builds
|
|
22
|
+
npm run build:native
|
|
23
|
+
|
|
24
|
+
# Or use directly
|
|
25
|
+
npx tsgo --project tsconfig.json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Notes
|
|
29
|
+
|
|
30
|
+
- **Status**: Still in preview/experimental phase
|
|
31
|
+
- **Compatibility**: May not support all TypeScript features yet
|
|
32
|
+
- **Best for**: Large codebases where build time is a bottleneck
|
|
33
|
+
- **Current project**: Build is already fast (~1.2s), so the benefit is minimal
|
|
34
|
+
|
|
35
|
+
### When to Use TSGO
|
|
36
|
+
|
|
37
|
+
✅ **Use TSGO if:**
|
|
38
|
+
|
|
39
|
+
- You have a large codebase (>100 files)
|
|
40
|
+
- Build time is >5 seconds
|
|
41
|
+
- You're willing to test experimental features
|
|
42
|
+
|
|
43
|
+
❌ **Stick with `tsc` if:**
|
|
44
|
+
|
|
45
|
+
- Your build is already fast (<2 seconds)
|
|
46
|
+
- You need 100% feature compatibility
|
|
47
|
+
- You're in production
|
|
48
|
+
|
|
49
|
+
### Benchmarking
|
|
50
|
+
|
|
51
|
+
To compare performance:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Standard TypeScript
|
|
55
|
+
time npm run build
|
|
56
|
+
|
|
57
|
+
# Native TypeScript
|
|
58
|
+
time npm run build:native
|
|
59
|
+
```
|
package/README.md
CHANGED
|
@@ -10,13 +10,18 @@ A powerful TypeScript code generator that creates **Zod schemas** and **type-saf
|
|
|
10
10
|
|
|
11
11
|
## 🚀 Features
|
|
12
12
|
|
|
13
|
-
- **🔥 Zod Schema Generation**: Automatically generate Zod validation schemas from OpenAPI
|
|
14
|
-
- **🎯 Type-Safe**:
|
|
15
|
-
- **📡 Multiple Formats**: Support for OpenAPI 3.x
|
|
16
|
-
- **🌐 Remote Files**: Fetch OpenAPI specs from URLs
|
|
13
|
+
- **🔥 Zod Schema Generation**: Automatically generate Zod validation schemas from OpenAPI component schemas
|
|
14
|
+
- **🎯 Type-Safe Client**: Generate a fully type-safe API client class with methods for each endpoint
|
|
15
|
+
- **📡 Multiple Formats**: Support for OpenAPI 3.x specifications in JSON and YAML formats
|
|
16
|
+
- **🌐 Remote Files**: Fetch OpenAPI specs from URLs using native fetch API
|
|
17
17
|
- **⚡ Fast**: Optimized for performance with minimal dependencies
|
|
18
|
-
- **🔧
|
|
19
|
-
- **📦
|
|
18
|
+
- **🔧 Advanced Schema Support**: Handles logical operators (anyOf, oneOf, allOf, not), enums, discriminators, and complex nested schemas
|
|
19
|
+
- **📦 Single File Output**: Generates all schemas and client in one convenient TypeScript file
|
|
20
|
+
- **🛡️ Runtime Validation**: Built-in Zod validation for request/response data
|
|
21
|
+
- **🌍 Form Support**: Supports both JSON and form-urlencoded request bodies
|
|
22
|
+
- **🔐 Extensible**: Override `getBaseRequestOptions()` to add authentication, custom headers, CORS, and other fetch options
|
|
23
|
+
- **🌐 Server Configuration**: Full support for OpenAPI server variables and templating (e.g., `{environment}.example.com`)
|
|
24
|
+
- **⚙️ Flexible Client Options**: Options-based constructor supporting server selection, variable overrides, and custom base URLs
|
|
20
25
|
|
|
21
26
|
## 📦 Installation
|
|
22
27
|
|
|
@@ -61,35 +66,85 @@ zod-codegen -i ./swagger.yaml -o ./src/generated
|
|
|
61
66
|
```typescript
|
|
62
67
|
import {Generator} from 'zod-codegen';
|
|
63
68
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
// Create a simple reporter object
|
|
70
|
+
const reporter = {
|
|
71
|
+
log: (...args: unknown[]) => console.log(...args),
|
|
72
|
+
error: (...args: unknown[]) => console.error(...args),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Create generator instance
|
|
76
|
+
const generator = new Generator(
|
|
77
|
+
'my-app',
|
|
78
|
+
'1.0.0',
|
|
79
|
+
reporter,
|
|
80
|
+
'./openapi.json', // Input path or URL
|
|
81
|
+
'./generated', // Output directory
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// Run the generator
|
|
85
|
+
const exitCode = await generator.run();
|
|
77
86
|
```
|
|
78
87
|
|
|
79
88
|
## 📁 Generated Output
|
|
80
89
|
|
|
81
|
-
The generator creates
|
|
90
|
+
The generator creates a single TypeScript file (`type.ts`) containing:
|
|
91
|
+
|
|
92
|
+
- **Zod Schemas**: Exported Zod validation schemas for all component schemas defined in your OpenAPI spec
|
|
93
|
+
- **API Client Class**: A type-safe client class with methods for each endpoint operation
|
|
94
|
+
- **Server Configuration**: `serverConfigurations` array and `defaultBaseUrl` constant extracted from OpenAPI servers
|
|
95
|
+
- **Client Options Type**: `ClientOptions` type for flexible server selection and variable overrides
|
|
96
|
+
- **Protected Extension Point**: A `getBaseRequestOptions()` method that can be overridden for customization
|
|
97
|
+
|
|
98
|
+
### Generated Client Structure
|
|
99
|
+
|
|
100
|
+
The generated client class includes:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
export class YourAPI {
|
|
104
|
+
readonly #baseUrl: string;
|
|
105
|
+
|
|
106
|
+
// Options-based constructor (if servers are defined in OpenAPI spec)
|
|
107
|
+
constructor(options: ClientOptions);
|
|
108
|
+
|
|
109
|
+
// Or simple baseUrl constructor (if no servers defined)
|
|
110
|
+
constructor(baseUrl: string = '/', _?: unknown);
|
|
111
|
+
|
|
112
|
+
// Protected method - override to customize request options
|
|
113
|
+
protected getBaseRequestOptions(): Partial<Omit<RequestInit, 'method' | 'body'>>;
|
|
114
|
+
|
|
115
|
+
// Private method - handles all HTTP requests
|
|
116
|
+
async #makeRequest<T>(method: string, path: string, options: {...}): Promise<T>;
|
|
117
|
+
|
|
118
|
+
// Generated endpoint methods (one per operationId)
|
|
119
|
+
async yourEndpointMethod(...): Promise<ResponseType>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ClientOptions type (when servers are defined)
|
|
123
|
+
export type ClientOptions = {
|
|
124
|
+
baseUrl?: string; // Override base URL directly
|
|
125
|
+
serverIndex?: number; // Select server by index (0-based)
|
|
126
|
+
serverVariables?: Record<string, string>; // Override server template variables
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Server configuration (when servers are defined)
|
|
130
|
+
export const serverConfigurations: Array<{
|
|
131
|
+
url: string;
|
|
132
|
+
description?: string;
|
|
133
|
+
variables?: Record<string, {
|
|
134
|
+
default: string;
|
|
135
|
+
enum?: string[];
|
|
136
|
+
description?: string;
|
|
137
|
+
}>;
|
|
138
|
+
}>;
|
|
139
|
+
|
|
140
|
+
export const defaultBaseUrl: string; // First server with default variables
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### File Structure
|
|
82
144
|
|
|
83
145
|
```
|
|
84
146
|
generated/
|
|
85
|
-
|
|
86
|
-
│ ├── user.schema.ts
|
|
87
|
-
│ └── product.schema.ts
|
|
88
|
-
├── types/ # TypeScript type definitions
|
|
89
|
-
│ ├── user.types.ts
|
|
90
|
-
│ └── product.types.ts
|
|
91
|
-
└── client/ # Type-safe API client
|
|
92
|
-
└── api.client.ts
|
|
147
|
+
└── type.ts # All schemas and client in one file
|
|
93
148
|
```
|
|
94
149
|
|
|
95
150
|
## 🎯 Example
|
|
@@ -101,69 +156,226 @@ openapi: 3.0.0
|
|
|
101
156
|
info:
|
|
102
157
|
title: User API
|
|
103
158
|
version: 1.0.0
|
|
159
|
+
servers:
|
|
160
|
+
- url: https://api.example.com
|
|
104
161
|
paths:
|
|
105
|
-
/users:
|
|
162
|
+
/users/{id}:
|
|
106
163
|
get:
|
|
164
|
+
operationId: getUserById
|
|
165
|
+
parameters:
|
|
166
|
+
- name: id
|
|
167
|
+
in: path
|
|
168
|
+
required: true
|
|
169
|
+
schema:
|
|
170
|
+
type: integer
|
|
107
171
|
responses:
|
|
108
172
|
'200':
|
|
109
173
|
content:
|
|
110
174
|
application/json:
|
|
111
175
|
schema:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
176
|
+
$ref: '#/components/schemas/User'
|
|
177
|
+
components:
|
|
178
|
+
schemas:
|
|
179
|
+
User:
|
|
180
|
+
type: object
|
|
181
|
+
properties:
|
|
182
|
+
id:
|
|
183
|
+
type: integer
|
|
184
|
+
name:
|
|
185
|
+
type: string
|
|
186
|
+
email:
|
|
187
|
+
type: string
|
|
188
|
+
format: email
|
|
189
|
+
required: [id, name, email]
|
|
122
190
|
```
|
|
123
191
|
|
|
124
|
-
**Generated
|
|
192
|
+
**Generated Output** (`generated/type.ts`):
|
|
125
193
|
|
|
126
194
|
```typescript
|
|
127
195
|
import {z} from 'zod';
|
|
128
196
|
|
|
129
|
-
|
|
197
|
+
// Components schemas
|
|
198
|
+
export const User = z.object({
|
|
130
199
|
id: z.number().int(),
|
|
131
200
|
name: z.string(),
|
|
132
201
|
email: z.string().email(),
|
|
133
202
|
});
|
|
134
203
|
|
|
135
|
-
|
|
204
|
+
// Server configuration (when servers are defined in OpenAPI spec)
|
|
205
|
+
export const serverConfigurations = [
|
|
206
|
+
{
|
|
207
|
+
url: 'https://api.example.com',
|
|
208
|
+
},
|
|
209
|
+
];
|
|
210
|
+
export const defaultBaseUrl = 'https://api.example.com';
|
|
211
|
+
export type ClientOptions = {
|
|
212
|
+
baseUrl?: string;
|
|
213
|
+
serverIndex?: number;
|
|
214
|
+
serverVariables?: Record<string, string>;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// Client class
|
|
218
|
+
export class UserAPI {
|
|
219
|
+
readonly #baseUrl: string;
|
|
220
|
+
|
|
221
|
+
constructor(options: ClientOptions = {}) {
|
|
222
|
+
this.#baseUrl = options.baseUrl || defaultBaseUrl;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
protected getBaseRequestOptions(): Partial<Omit<RequestInit, 'method' | 'body'>> {
|
|
226
|
+
return {};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async getUserById(id: number): Promise<z.infer<typeof User>> {
|
|
230
|
+
return User.parse(await this.#makeRequest<z.infer<typeof User>>('GET', `/users/${id}`, {}));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ... private #makeRequest method
|
|
234
|
+
}
|
|
136
235
|
```
|
|
137
236
|
|
|
138
|
-
**
|
|
237
|
+
**Usage:**
|
|
139
238
|
|
|
140
239
|
```typescript
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
240
|
+
import {UserAPI, User} from './generated/type.js';
|
|
241
|
+
|
|
242
|
+
// Use default server from OpenAPI spec
|
|
243
|
+
const client = new UserAPI({});
|
|
244
|
+
const user = await client.getUserById(123);
|
|
245
|
+
// user is fully typed and validated!
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Extending the Client
|
|
249
|
+
|
|
250
|
+
The generated client includes a protected `getBaseRequestOptions()` method that you can override to customize request options. This method returns `Partial<Omit<RequestInit, 'method' | 'body'>>`, allowing you to configure:
|
|
251
|
+
|
|
252
|
+
- **Headers**: Authentication tokens, User-Agent, custom headers
|
|
253
|
+
- **CORS**: `mode`, `credentials` for cross-origin requests
|
|
254
|
+
- **Request Options**: `signal` (AbortController), `cache`, `redirect`, `referrer`, etc.
|
|
255
|
+
|
|
256
|
+
#### Basic Authentication Example
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import {UserAPI, ClientOptions} from './generated/type.js';
|
|
260
|
+
|
|
261
|
+
class AuthenticatedUserAPI extends UserAPI {
|
|
262
|
+
private accessToken: string | null = null;
|
|
263
|
+
|
|
264
|
+
constructor(options: ClientOptions = {}) {
|
|
265
|
+
super(options);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
protected getBaseRequestOptions(): Partial<Omit<RequestInit, 'method' | 'body'>> {
|
|
269
|
+
const options = super.getBaseRequestOptions();
|
|
270
|
+
return {
|
|
271
|
+
...options,
|
|
272
|
+
headers: {
|
|
273
|
+
...((options.headers as Record<string, string>) || {}),
|
|
274
|
+
...(this.accessToken ? {Authorization: `Bearer ${this.accessToken}`} : {}),
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
setAccessToken(token: string): void {
|
|
280
|
+
this.accessToken = token;
|
|
281
|
+
}
|
|
145
282
|
}
|
|
283
|
+
|
|
284
|
+
// Usage
|
|
285
|
+
const client = new AuthenticatedUserAPI({});
|
|
286
|
+
client.setAccessToken('your-token-here');
|
|
287
|
+
const user = await client.getUserById(123); // Includes Authorization header
|
|
146
288
|
```
|
|
147
289
|
|
|
148
|
-
|
|
290
|
+
#### Complete Configuration Example
|
|
149
291
|
|
|
150
292
|
```typescript
|
|
151
|
-
import {
|
|
293
|
+
import {UserAPI, ClientOptions} from './generated/type.js';
|
|
294
|
+
|
|
295
|
+
class FullyConfiguredAPI extends UserAPI {
|
|
296
|
+
private accessToken: string | null = null;
|
|
152
297
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
298
|
+
constructor(options: ClientOptions = {}) {
|
|
299
|
+
super(options);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
protected getBaseRequestOptions(): Partial<Omit<RequestInit, 'method' | 'body'>> {
|
|
303
|
+
const options = super.getBaseRequestOptions();
|
|
304
|
+
return {
|
|
305
|
+
...options,
|
|
306
|
+
headers: {
|
|
307
|
+
...((options.headers as Record<string, string>) || {}),
|
|
308
|
+
'User-Agent': 'MyApp/1.0.0',
|
|
309
|
+
...(this.accessToken ? {Authorization: `Bearer ${this.accessToken}`} : {}),
|
|
310
|
+
},
|
|
311
|
+
mode: 'cors',
|
|
312
|
+
credentials: 'include',
|
|
313
|
+
cache: 'no-cache',
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
setAccessToken(token: string): void {
|
|
318
|
+
this.accessToken = token;
|
|
158
319
|
}
|
|
159
320
|
}
|
|
321
|
+
|
|
322
|
+
// Usage
|
|
323
|
+
const client = new FullyConfiguredAPI({});
|
|
324
|
+
client.setAccessToken('your-token');
|
|
160
325
|
```
|
|
161
326
|
|
|
327
|
+
#### Available Request Options
|
|
328
|
+
|
|
329
|
+
You can set any `RequestInit` option except `method` and `body` (which are controlled by the generated code):
|
|
330
|
+
|
|
331
|
+
| Option | Type | Description |
|
|
332
|
+
| ---------------- | -------------------- | ------------------------------------------------------------------- |
|
|
333
|
+
| `headers` | `HeadersInit` | Request headers (authentication, User-Agent, etc.) |
|
|
334
|
+
| `signal` | `AbortSignal` | AbortController signal for request cancellation |
|
|
335
|
+
| `credentials` | `RequestCredentials` | CORS credentials mode (`'include'`, `'same-origin'`, `'omit'`) |
|
|
336
|
+
| `mode` | `RequestMode` | Request mode (`'cors'`, `'no-cors'`, `'same-origin'`, `'navigate'`) |
|
|
337
|
+
| `cache` | `RequestCache` | Cache mode (`'default'`, `'no-cache'`, `'reload'`, etc.) |
|
|
338
|
+
| `redirect` | `RequestRedirect` | Redirect handling (`'follow'`, `'error'`, `'manual'`) |
|
|
339
|
+
| `referrer` | `string` | Referrer URL |
|
|
340
|
+
| `referrerPolicy` | `ReferrerPolicy` | Referrer policy |
|
|
341
|
+
| `integrity` | `string` | Subresource integrity hash |
|
|
342
|
+
| `keepalive` | `boolean` | Keep connection alive |
|
|
343
|
+
|
|
344
|
+
See [EXAMPLES.md](EXAMPLES.md) for comprehensive examples including:
|
|
345
|
+
|
|
346
|
+
- Bearer token authentication
|
|
347
|
+
- Session management with token refresh
|
|
348
|
+
- Custom User-Agent headers
|
|
349
|
+
- CORS configuration
|
|
350
|
+
- Request cancellation with AbortController
|
|
351
|
+
- Environment-specific configurations
|
|
352
|
+
|
|
353
|
+
## 📖 Examples
|
|
354
|
+
|
|
355
|
+
Check out the [examples directory](./examples/) for complete, runnable examples:
|
|
356
|
+
|
|
357
|
+
- **[Petstore API](./examples/petstore/)** - Complete example with the Swagger Petstore API
|
|
358
|
+
- **[PokéAPI](./examples/pokeapi/)** - Example with a public REST API
|
|
359
|
+
|
|
360
|
+
Each example includes:
|
|
361
|
+
|
|
362
|
+
- Generated client code
|
|
363
|
+
- Basic usage examples
|
|
364
|
+
- Authentication examples
|
|
365
|
+
- README with instructions
|
|
366
|
+
|
|
367
|
+
## 📚 Documentation
|
|
368
|
+
|
|
369
|
+
- **[README.md](README.md)** - Project overview and quick start guide
|
|
370
|
+
- **[EXAMPLES.md](EXAMPLES.md)** - Comprehensive examples and patterns for extending the client
|
|
371
|
+
- **[CONTRIBUTING.md](CONTRIBUTING.md)** - Guidelines for contributing to the project
|
|
372
|
+
- **[CHANGELOG.md](CHANGELOG.md)** - Version history and changes
|
|
373
|
+
|
|
162
374
|
## 🛠️ Development
|
|
163
375
|
|
|
164
376
|
### Prerequisites
|
|
165
377
|
|
|
166
|
-
- Node.js ≥
|
|
378
|
+
- Node.js ≥ 24.11.1
|
|
167
379
|
- npm or yarn
|
|
168
380
|
|
|
169
381
|
### Setup
|
|
@@ -223,9 +435,9 @@ npm run test:ui
|
|
|
223
435
|
|
|
224
436
|
## 📋 Requirements
|
|
225
437
|
|
|
226
|
-
- **Node.js**: ≥
|
|
227
|
-
- **TypeScript**: ≥ 5.
|
|
228
|
-
- **Zod**: ≥
|
|
438
|
+
- **Node.js**: ≥ 24.11.1
|
|
439
|
+
- **TypeScript**: ≥ 5.9.3
|
|
440
|
+
- **Zod**: ≥ 4.1.12
|
|
229
441
|
|
|
230
442
|
## 🤝 Contributing
|
|
231
443
|
|