@cerios/openapi-to-zod 1.3.2 → 1.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/LICENSE +8 -0
- package/README.md +546 -395
- package/dist/cli.js +831 -1321
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +864 -1371
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +472 -59
- package/dist/index.d.ts +472 -59
- package/dist/index.js +669 -909
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +675 -884
- package/dist/index.mjs.map +1 -1
- package/package.json +89 -104
- package/dist/internal.d.mts +0 -363
- package/dist/internal.d.ts +0 -363
- package/dist/internal.js +0 -759
- package/dist/internal.js.map +0 -1
- package/dist/internal.mjs +0 -706
- package/dist/internal.mjs.map +0 -1
- package/dist/types-DZ4Bw-D5.d.mts +0 -505
- package/dist/types-DZ4Bw-D5.d.ts +0 -505
package/README.md
CHANGED
|
@@ -44,6 +44,7 @@ npx @cerios/openapi-to-zod init
|
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
This interactive command will:
|
|
47
|
+
|
|
47
48
|
- Prompt for your OpenAPI spec path
|
|
48
49
|
- Prompt for output file path
|
|
49
50
|
- Ask if you want to include commonly-used defaults
|
|
@@ -59,66 +60,73 @@ The tool will auto-discover your config file and generate schemas.
|
|
|
59
60
|
|
|
60
61
|
### Configuration
|
|
61
62
|
|
|
63
|
+
> `outputTypes` is the preferred config key.
|
|
64
|
+
> Deprecated alias: `output` is still supported for backward compatibility.
|
|
65
|
+
> You must provide one of `outputTypes` or `output` per spec.
|
|
66
|
+
> If both are provided, they must have the same value.
|
|
67
|
+
|
|
62
68
|
#### TypeScript Config (Recommended)
|
|
63
69
|
|
|
64
70
|
**Minimal:**
|
|
71
|
+
|
|
65
72
|
```typescript
|
|
66
|
-
import { defineConfig } from
|
|
73
|
+
import { defineConfig } from "@cerios/openapi-to-zod";
|
|
67
74
|
|
|
68
75
|
export default defineConfig({
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
specs: [
|
|
77
|
+
{
|
|
78
|
+
input: "openapi.yaml",
|
|
79
|
+
outputTypes: "src/schemas.ts",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
75
82
|
});
|
|
76
83
|
```
|
|
77
84
|
|
|
78
85
|
**With Commonly-Used Defaults:**
|
|
86
|
+
|
|
79
87
|
```typescript
|
|
80
|
-
import { defineConfig } from
|
|
88
|
+
import { defineConfig } from "@cerios/openapi-to-zod";
|
|
81
89
|
|
|
82
90
|
export default defineConfig({
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
defaults: {
|
|
92
|
+
mode: "strict", // Strictest validation
|
|
93
|
+
includeDescriptions: true, // Useful JSDoc comments
|
|
94
|
+
showStats: false, // Cleaner output
|
|
95
|
+
},
|
|
96
|
+
specs: [
|
|
97
|
+
{
|
|
98
|
+
input: "openapi.yaml",
|
|
99
|
+
outputTypes: "src/schemas.ts",
|
|
100
|
+
},
|
|
101
|
+
],
|
|
94
102
|
});
|
|
95
103
|
```
|
|
96
104
|
|
|
97
105
|
**Multi-Spec with Custom Options:**
|
|
98
106
|
|
|
99
107
|
```typescript
|
|
100
|
-
import { defineConfig } from
|
|
108
|
+
import { defineConfig } from "@cerios/openapi-to-zod";
|
|
101
109
|
|
|
102
110
|
export default defineConfig({
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
111
|
+
defaults: {
|
|
112
|
+
mode: "strict",
|
|
113
|
+
includeDescriptions: true,
|
|
114
|
+
},
|
|
115
|
+
specs: [
|
|
116
|
+
{
|
|
117
|
+
name: "api-v1",
|
|
118
|
+
input: "specs/api-v1.yaml",
|
|
119
|
+
outputTypes: "src/schemas/v1.ts",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "api-v2",
|
|
123
|
+
input: "specs/api-v2.yaml",
|
|
124
|
+
outputTypes: "src/schemas/v2.ts",
|
|
125
|
+
mode: "normal", // Override default
|
|
126
|
+
prefix: "v2",
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
executionMode: "parallel", // Process specs in parallel (default)
|
|
122
130
|
});
|
|
123
131
|
```
|
|
124
132
|
|
|
@@ -128,16 +136,16 @@ export default defineConfig({
|
|
|
128
136
|
|
|
129
137
|
```json
|
|
130
138
|
{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
"defaults": {
|
|
140
|
+
"mode": "strict",
|
|
141
|
+
"includeDescriptions": true
|
|
142
|
+
},
|
|
143
|
+
"specs": [
|
|
144
|
+
{
|
|
145
|
+
"input": "openapi.yaml",
|
|
146
|
+
"outputTypes": "src/schemas.ts"
|
|
147
|
+
}
|
|
148
|
+
]
|
|
141
149
|
}
|
|
142
150
|
```
|
|
143
151
|
|
|
@@ -167,86 +175,96 @@ Examples:
|
|
|
167
175
|
|
|
168
176
|
### Configuration Options
|
|
169
177
|
|
|
170
|
-
|
|
171
|
-
|
|
|
172
|
-
|
|
173
|
-
| `
|
|
174
|
-
| `
|
|
175
|
-
| `executionMode` | `"parallel"` \| `"sequential"` | How to process specs (default: `"parallel"`) |
|
|
178
|
+
| Option | Type | Description |
|
|
179
|
+
| --------------- | ------------------------------ | ---------------------------------------------------------------- |
|
|
180
|
+
| `defaults` | `object` | Global options applied to all specs (can be overridden per-spec) |
|
|
181
|
+
| `specs` | `array` | Array of spec configurations (required, minimum 1) |
|
|
182
|
+
| `executionMode` | `"parallel"` \| `"sequential"` | How to process specs (default: `"parallel"`) |
|
|
176
183
|
|
|
177
184
|
**Per-Spec Options:**
|
|
178
185
|
|
|
179
|
-
| Spec Option
|
|
180
|
-
|
|
181
|
-
| `name`
|
|
182
|
-
| `input`
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
196
|
-
| `
|
|
186
|
+
| Spec Option | Type | Description |
|
|
187
|
+
| --------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
188
|
+
| `name` | `string` | Optional identifier for logging |
|
|
189
|
+
| `input` | `string` | Input OpenAPI YAML file path (required) |
|
|
190
|
+
| `outputTypes` | `string` | Preferred output TypeScript file path (required unless deprecated `output` is set) |
|
|
191
|
+
| `output` | `string` | Deprecated alias for `outputTypes`; allowed for backward compatibility |
|
|
192
|
+
| `mode` | `"strict"` \| `"normal"` \| `"loose"` | Validation mode for top-level schemas (default: `"normal"`) |
|
|
193
|
+
| `emptyObjectBehavior` | `"strict"` \| `"loose"` \| `"record"` | How to handle empty objects (default: `"loose"`) |
|
|
194
|
+
| `includeDescriptions` | `boolean` | Include JSDoc comments |
|
|
195
|
+
| `useDescribe` | `boolean` | Add `.describe()` calls |
|
|
196
|
+
| `defaultNullable` | `boolean` | Treat properties as nullable by default when not explicitly specified (default: `false`) |
|
|
197
|
+
| `schemaType` | `"all"` \| `"request"` \| `"response"` | Schema filtering |
|
|
198
|
+
| `prefix` | `string` | Prefix for schema names |
|
|
199
|
+
| `suffix` | `string` | Suffix for schema names |
|
|
200
|
+
| `stripSchemaPrefix` | `string` | Strip prefix from schema names before generating using glob patterns (e.g., `"Company.Models."` or `"*.Models."`) |
|
|
201
|
+
| `useOperationId` | `boolean` | Use operationId for operation-derived query/header schema names when available (default: `true`) |
|
|
202
|
+
| `showStats` | `boolean` | Include generation statistics |
|
|
203
|
+
| `request` | `object` | Request-specific options (mode, includeDescriptions, useDescribe) |
|
|
204
|
+
| `response` | `object` | Response-specific options (mode, includeDescriptions, useDescribe) |
|
|
205
|
+
| `operationFilters` | `object` | Filter operations by tags, paths, methods, etc. (see below) |
|
|
206
|
+
|
|
207
|
+
If `outputTypes` and `output` are both set with different values, configuration validation fails.
|
|
197
208
|
|
|
198
209
|
#### Operation Filters
|
|
199
210
|
|
|
200
211
|
Filter which operations to include/exclude during schema generation. Useful for generating separate schemas for different API subsets.
|
|
201
212
|
|
|
202
|
-
| Filter
|
|
203
|
-
|
|
204
|
-
| `includeTags`
|
|
205
|
-
| `excludeTags`
|
|
206
|
-
| `includePaths`
|
|
207
|
-
| `excludePaths`
|
|
208
|
-
| `includeMethods`
|
|
209
|
-
| `excludeMethods`
|
|
210
|
-
| `includeOperationIds` | `string[]` | Include only these operationIds (supports glob patterns)
|
|
211
|
-
| `excludeOperationIds` | `string[]` | Exclude these operationIds (supports glob patterns)
|
|
212
|
-
| `excludeDeprecated`
|
|
213
|
+
| Filter | Type | Description |
|
|
214
|
+
| --------------------- | ---------- | ------------------------------------------------------------------ |
|
|
215
|
+
| `includeTags` | `string[]` | Include only operations with these tags |
|
|
216
|
+
| `excludeTags` | `string[]` | Exclude operations with these tags |
|
|
217
|
+
| `includePaths` | `string[]` | Include only these paths (supports glob patterns like `/users/**`) |
|
|
218
|
+
| `excludePaths` | `string[]` | Exclude these paths (supports glob patterns) |
|
|
219
|
+
| `includeMethods` | `string[]` | Include only these HTTP methods (`get`, `post`, etc.) |
|
|
220
|
+
| `excludeMethods` | `string[]` | Exclude these HTTP methods |
|
|
221
|
+
| `includeOperationIds` | `string[]` | Include only these operationIds (supports glob patterns) |
|
|
222
|
+
| `excludeOperationIds` | `string[]` | Exclude these operationIds (supports glob patterns) |
|
|
223
|
+
| `excludeDeprecated` | `boolean` | Exclude deprecated operations |
|
|
213
224
|
|
|
214
225
|
**Example:**
|
|
226
|
+
|
|
215
227
|
```typescript
|
|
216
228
|
export default defineConfig({
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
229
|
+
specs: [
|
|
230
|
+
{
|
|
231
|
+
input: "openapi.yaml",
|
|
232
|
+
outputTypes: "schemas.ts",
|
|
233
|
+
operationFilters: {
|
|
234
|
+
includeTags: ["public"], // Only public endpoints
|
|
235
|
+
excludeDeprecated: true, // Skip deprecated operations
|
|
236
|
+
excludePaths: ["/internal/**"], // Exclude internal paths
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
],
|
|
226
240
|
});
|
|
227
241
|
```
|
|
228
242
|
|
|
229
243
|
### Batch Execution
|
|
230
244
|
|
|
231
245
|
**Parallel Mode** (default):
|
|
246
|
+
|
|
232
247
|
- Processes all specs concurrently
|
|
233
248
|
- Faster for multiple specs
|
|
234
249
|
- Recommended for most use cases
|
|
235
250
|
- Live progress shows all specs processing simultaneously
|
|
236
251
|
|
|
237
252
|
**Sequential Mode**:
|
|
253
|
+
|
|
238
254
|
- Processes specs one at a time
|
|
239
255
|
- Useful for resource-constrained environments
|
|
240
256
|
- Easier to debug issues
|
|
241
257
|
- Live progress shows specs processing in order
|
|
242
258
|
|
|
243
259
|
Both modes:
|
|
260
|
+
|
|
244
261
|
- Continue processing even if some specs fail
|
|
245
262
|
- Collect all errors and report at the end
|
|
246
263
|
- Exit with code 1 if any spec fails
|
|
247
264
|
- Show live progress updates to stderr
|
|
248
265
|
|
|
249
266
|
Example output:
|
|
267
|
+
|
|
250
268
|
```
|
|
251
269
|
Executing 3 spec(s) in parallel...
|
|
252
270
|
|
|
@@ -273,45 +291,54 @@ Failed specs:
|
|
|
273
291
|
## Programmatic Usage
|
|
274
292
|
|
|
275
293
|
```typescript
|
|
276
|
-
import {
|
|
294
|
+
import { OpenApiGenerator } from "@cerios/openapi-to-zod";
|
|
277
295
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
296
|
+
const generator = new OpenApiGenerator({
|
|
297
|
+
input: "path/to/openapi.yaml",
|
|
298
|
+
outputTypes: "path/to/schemas.ts",
|
|
299
|
+
mode: "normal", // 'strict' | 'normal' | 'loose'
|
|
300
|
+
includeDescriptions: true,
|
|
283
301
|
});
|
|
302
|
+
|
|
303
|
+
// Generate and write to file
|
|
304
|
+
generator.generate();
|
|
305
|
+
|
|
306
|
+
// Or generate as string
|
|
307
|
+
const code = generator.generateString();
|
|
284
308
|
```
|
|
285
309
|
|
|
286
310
|
## Validation Modes
|
|
287
311
|
|
|
288
312
|
### Normal Mode (default)
|
|
313
|
+
|
|
289
314
|
Uses `z.object()` which allows additional properties:
|
|
290
315
|
|
|
291
316
|
```typescript
|
|
292
317
|
const userSchema = z.object({
|
|
293
|
-
|
|
294
|
-
|
|
318
|
+
id: z.uuid(),
|
|
319
|
+
name: z.string(),
|
|
295
320
|
});
|
|
296
321
|
```
|
|
297
322
|
|
|
298
323
|
### Strict Mode
|
|
324
|
+
|
|
299
325
|
Uses `z.strictObject()` which rejects additional properties:
|
|
300
326
|
|
|
301
327
|
```typescript
|
|
302
328
|
const userSchema = z.strictObject({
|
|
303
|
-
|
|
304
|
-
|
|
329
|
+
id: z.uuid(),
|
|
330
|
+
name: z.string(),
|
|
305
331
|
});
|
|
306
332
|
```
|
|
307
333
|
|
|
308
334
|
### Loose Mode
|
|
335
|
+
|
|
309
336
|
Uses `z.looseObject()` which explicitly allows additional properties:
|
|
310
337
|
|
|
311
338
|
```typescript
|
|
312
339
|
const userSchema = z.looseObject({
|
|
313
|
-
|
|
314
|
-
|
|
340
|
+
id: z.uuid(),
|
|
341
|
+
name: z.string(),
|
|
315
342
|
});
|
|
316
343
|
```
|
|
317
344
|
|
|
@@ -320,6 +347,7 @@ const userSchema = z.looseObject({
|
|
|
320
347
|
When OpenAPI schemas define an object without any properties (e.g., `type: object` with no `properties`), the generator needs to decide how to represent it. The `emptyObjectBehavior` option controls this:
|
|
321
348
|
|
|
322
349
|
### Loose (default)
|
|
350
|
+
|
|
323
351
|
Uses `z.looseObject({})` which allows any additional properties:
|
|
324
352
|
|
|
325
353
|
```typescript
|
|
@@ -330,6 +358,7 @@ const metadataSchema = z.looseObject({});
|
|
|
330
358
|
```
|
|
331
359
|
|
|
332
360
|
### Strict
|
|
361
|
+
|
|
333
362
|
Uses `z.strictObject({})` which rejects any properties:
|
|
334
363
|
|
|
335
364
|
```typescript
|
|
@@ -341,6 +370,7 @@ const emptySchema = z.strictObject({});
|
|
|
341
370
|
```
|
|
342
371
|
|
|
343
372
|
### Record
|
|
373
|
+
|
|
344
374
|
Uses `z.record(z.string(), z.unknown())` which treats it as an arbitrary key-value map:
|
|
345
375
|
|
|
346
376
|
```typescript
|
|
@@ -390,7 +420,7 @@ components:
|
|
|
390
420
|
minimum: 0
|
|
391
421
|
maximum: 150
|
|
392
422
|
status:
|
|
393
|
-
$ref:
|
|
423
|
+
$ref: "#/components/schemas/UserStatusEnumOptions"
|
|
394
424
|
```
|
|
395
425
|
|
|
396
426
|
### Generated Output
|
|
@@ -403,20 +433,20 @@ import { z } from "zod";
|
|
|
403
433
|
|
|
404
434
|
// Enums
|
|
405
435
|
export enum UserStatusEnum {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
436
|
+
Active = "active",
|
|
437
|
+
Inactive = "inactive",
|
|
438
|
+
Pending = "pending",
|
|
409
439
|
}
|
|
410
440
|
|
|
411
441
|
// Schemas
|
|
412
442
|
export const userStatusEnumOptionsSchema = z.enum(UserStatusEnum);
|
|
413
443
|
|
|
414
444
|
export const userSchema = z.object({
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
445
|
+
id: z.uuid().min(36).max(36),
|
|
446
|
+
email: z.email().max(255),
|
|
447
|
+
name: z.string().min(1).max(100).optional(),
|
|
448
|
+
age: z.number().int().gte(0).lte(150).optional(),
|
|
449
|
+
status: userStatusEnumOptionsSchema.optional(),
|
|
420
450
|
});
|
|
421
451
|
|
|
422
452
|
// Types
|
|
@@ -428,26 +458,26 @@ export type User = z.infer<typeof userSchema>;
|
|
|
428
458
|
|
|
429
459
|
The generator supports all OpenAPI string formats with Zod v4:
|
|
430
460
|
|
|
431
|
-
| OpenAPI Format | Zod v4 Function
|
|
432
|
-
|
|
433
|
-
| `uuid`
|
|
434
|
-
| `email`
|
|
435
|
-
| `url`, `uri`
|
|
436
|
-
| `date`
|
|
437
|
-
| `date-time`
|
|
438
|
-
| `time`
|
|
439
|
-
| `duration`
|
|
440
|
-
| `ipv4`
|
|
441
|
-
| `ipv6`
|
|
442
|
-
| `emoji`
|
|
443
|
-
| `base64`
|
|
444
|
-
| `base64url`
|
|
445
|
-
| `nanoid`
|
|
446
|
-
| `cuid`
|
|
447
|
-
| `cuid2`
|
|
448
|
-
| `ulid`
|
|
449
|
-
| `cidrv4`
|
|
450
|
-
| `cidrv6`
|
|
461
|
+
| OpenAPI Format | Zod v4 Function |
|
|
462
|
+
| -------------- | ------------------ |
|
|
463
|
+
| `uuid` | `z.uuid()` |
|
|
464
|
+
| `email` | `z.email()` |
|
|
465
|
+
| `url`, `uri` | `z.url()` |
|
|
466
|
+
| `date` | `z.iso.date()` |
|
|
467
|
+
| `date-time` | `z.iso.datetime()` |
|
|
468
|
+
| `time` | `z.iso.time()` |
|
|
469
|
+
| `duration` | `z.iso.duration()` |
|
|
470
|
+
| `ipv4` | `z.ipv4()` |
|
|
471
|
+
| `ipv6` | `z.ipv6()` |
|
|
472
|
+
| `emoji` | `z.emoji()` |
|
|
473
|
+
| `base64` | `z.base64()` |
|
|
474
|
+
| `base64url` | `z.base64url()` |
|
|
475
|
+
| `nanoid` | `z.nanoid()` |
|
|
476
|
+
| `cuid` | `z.cuid()` |
|
|
477
|
+
| `cuid2` | `z.cuid2()` |
|
|
478
|
+
| `ulid` | `z.ulid()` |
|
|
479
|
+
| `cidrv4` | `z.cidrv4()` |
|
|
480
|
+
| `cidrv6` | `z.cidrv6()` |
|
|
451
481
|
|
|
452
482
|
### Custom Date-Time Format
|
|
453
483
|
|
|
@@ -456,19 +486,19 @@ By default, the generator uses `z.iso.datetime()` for `date-time` format fields,
|
|
|
456
486
|
If your API returns date-times **without the `Z` suffix** (e.g., `2026-01-07T14:30:00`), you can override this with a custom regex pattern:
|
|
457
487
|
|
|
458
488
|
```typescript
|
|
459
|
-
import { defineConfig } from
|
|
489
|
+
import { defineConfig } from "@cerios/openapi-to-zod";
|
|
460
490
|
|
|
461
491
|
export default defineConfig({
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
492
|
+
defaults: {
|
|
493
|
+
// For date-times without Z suffix
|
|
494
|
+
customDateTimeFormatRegex: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
|
495
|
+
},
|
|
496
|
+
specs: [
|
|
497
|
+
{
|
|
498
|
+
input: "openapi.yaml",
|
|
499
|
+
outputTypes: "src/schemas.ts",
|
|
500
|
+
},
|
|
501
|
+
],
|
|
472
502
|
});
|
|
473
503
|
```
|
|
474
504
|
|
|
@@ -478,27 +508,27 @@ In TypeScript config files, you can also use RegExp literals (which don't requir
|
|
|
478
508
|
|
|
479
509
|
```typescript
|
|
480
510
|
export default defineConfig({
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
511
|
+
defaults: {
|
|
512
|
+
// Use RegExp literal (single escaping)
|
|
513
|
+
customDateTimeFormatRegex: /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/,
|
|
514
|
+
},
|
|
515
|
+
specs: [
|
|
516
|
+
{
|
|
517
|
+
input: "openapi.yaml",
|
|
518
|
+
outputTypes: "src/schemas.ts",
|
|
519
|
+
},
|
|
520
|
+
],
|
|
491
521
|
});
|
|
492
522
|
```
|
|
493
523
|
|
|
494
524
|
**Common Custom Formats:**
|
|
495
525
|
|
|
496
|
-
| Use Case
|
|
497
|
-
|
|
498
|
-
| No timezone suffix<br>`2026-01-07T14:30:00`
|
|
499
|
-
| With milliseconds, no Z<br>`2026-01-07T14:30:00.123`
|
|
500
|
-
| Optional Z suffix<br>`2026-01-07T14:30:00` or<br>`2026-01-07T14:30:00Z` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z?$'`
|
|
501
|
-
| With milliseconds + optional Z<br>`2026-01-07T14:30:00.123Z`
|
|
526
|
+
| Use Case | String Pattern (JSON/YAML) | RegExp Literal (TypeScript) |
|
|
527
|
+
| ----------------------------------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------- |
|
|
528
|
+
| No timezone suffix<br>`2026-01-07T14:30:00` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$'` | `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/` |
|
|
529
|
+
| With milliseconds, no Z<br>`2026-01-07T14:30:00.123` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}$'` | `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}$/` |
|
|
530
|
+
| Optional Z suffix<br>`2026-01-07T14:30:00` or<br>`2026-01-07T14:30:00Z` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z?$'` | `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z?$/` |
|
|
531
|
+
| With milliseconds + optional Z<br>`2026-01-07T14:30:00.123Z` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z?$'` | `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z?$/` |
|
|
502
532
|
|
|
503
533
|
**Generated Output:**
|
|
504
534
|
|
|
@@ -518,46 +548,56 @@ When using a custom regex, the generator will produce:
|
|
|
518
548
|
Filter which operations are included in schema generation. This is useful when you want to generate schemas for only a subset of your API.
|
|
519
549
|
|
|
520
550
|
**Example 1: Filter by tags**
|
|
551
|
+
|
|
521
552
|
```typescript
|
|
522
553
|
export default defineConfig({
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
554
|
+
specs: [
|
|
555
|
+
{
|
|
556
|
+
input: "openapi.yaml",
|
|
557
|
+
outputTypes: "public-schemas.ts",
|
|
558
|
+
operationFilters: {
|
|
559
|
+
includeTags: ["public", "users"], // Only include operations tagged with 'public' or 'users'
|
|
560
|
+
},
|
|
561
|
+
},
|
|
562
|
+
],
|
|
530
563
|
});
|
|
531
564
|
```
|
|
532
565
|
|
|
533
566
|
**Example 2: Filter by paths**
|
|
567
|
+
|
|
534
568
|
```typescript
|
|
535
569
|
export default defineConfig({
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
570
|
+
specs: [
|
|
571
|
+
{
|
|
572
|
+
input: "openapi.yaml",
|
|
573
|
+
outputTypes: "v1-schemas.ts",
|
|
574
|
+
operationFilters: {
|
|
575
|
+
includePaths: ["/api/v1/**"], // Only v1 endpoints
|
|
576
|
+
excludePaths: ["/api/v1/admin/**"], // But exclude admin endpoints
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
],
|
|
544
580
|
});
|
|
545
581
|
```
|
|
546
582
|
|
|
547
583
|
**Example 3: Exclude deprecated operations**
|
|
584
|
+
|
|
548
585
|
```typescript
|
|
549
586
|
export default defineConfig({
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
587
|
+
specs: [
|
|
588
|
+
{
|
|
589
|
+
input: "openapi.yaml",
|
|
590
|
+
outputTypes: "current-schemas.ts",
|
|
591
|
+
operationFilters: {
|
|
592
|
+
excludeDeprecated: true, // Skip all deprecated operations
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
],
|
|
557
596
|
});
|
|
558
597
|
```
|
|
559
598
|
|
|
560
599
|
**Filtering Logic:**
|
|
600
|
+
|
|
561
601
|
1. If no filters specified, all operations are included
|
|
562
602
|
2. Empty arrays are treated as "no constraint"
|
|
563
603
|
3. Include filters are applied first (allowlist)
|
|
@@ -571,80 +611,92 @@ export default defineConfig({
|
|
|
571
611
|
Generate separate schemas for requests and responses by filtering `readOnly` and `writeOnly` properties.
|
|
572
612
|
|
|
573
613
|
**Example: Request schemas (exclude readOnly)**
|
|
614
|
+
|
|
574
615
|
```typescript
|
|
575
616
|
export default defineConfig({
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
617
|
+
specs: [
|
|
618
|
+
{
|
|
619
|
+
input: "openapi.yaml",
|
|
620
|
+
outputTypes: "request-schemas.ts",
|
|
621
|
+
schemaType: "request", // Excludes readOnly properties like 'id', 'createdAt'
|
|
622
|
+
},
|
|
623
|
+
],
|
|
581
624
|
});
|
|
582
625
|
```
|
|
583
626
|
|
|
584
627
|
**Example: Response schemas (exclude writeOnly)**
|
|
628
|
+
|
|
585
629
|
```typescript
|
|
586
630
|
export default defineConfig({
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
631
|
+
specs: [
|
|
632
|
+
{
|
|
633
|
+
input: "openapi.yaml",
|
|
634
|
+
outputTypes: "response-schemas.ts",
|
|
635
|
+
schemaType: "response", // Excludes writeOnly properties like 'password'
|
|
636
|
+
},
|
|
637
|
+
],
|
|
592
638
|
});
|
|
593
639
|
```
|
|
594
640
|
|
|
595
641
|
**Example: Context-specific validation**
|
|
642
|
+
|
|
596
643
|
```typescript
|
|
597
644
|
export default defineConfig({
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
645
|
+
specs: [
|
|
646
|
+
{
|
|
647
|
+
input: "openapi.yaml",
|
|
648
|
+
outputTypes: "schemas.ts",
|
|
649
|
+
request: {
|
|
650
|
+
mode: "strict", // Strict validation for incoming data
|
|
651
|
+
includeDescriptions: false,
|
|
652
|
+
},
|
|
653
|
+
response: {
|
|
654
|
+
mode: "loose", // Flexible validation for API responses
|
|
655
|
+
includeDescriptions: true,
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
],
|
|
610
659
|
});
|
|
611
660
|
```
|
|
612
661
|
|
|
613
662
|
**OpenAPI Spec:**
|
|
663
|
+
|
|
614
664
|
```yaml
|
|
615
665
|
User:
|
|
616
666
|
type: object
|
|
617
667
|
properties:
|
|
618
668
|
id:
|
|
619
669
|
type: string
|
|
620
|
-
readOnly: true
|
|
670
|
+
readOnly: true # Excluded in 'request' mode
|
|
621
671
|
email:
|
|
622
672
|
type: string
|
|
623
673
|
password:
|
|
624
674
|
type: string
|
|
625
|
-
writeOnly: true
|
|
675
|
+
writeOnly: true # Excluded in 'response' mode
|
|
626
676
|
createdAt:
|
|
627
677
|
type: string
|
|
628
678
|
format: date-time
|
|
629
|
-
readOnly: true
|
|
679
|
+
readOnly: true # Excluded in 'request' mode
|
|
630
680
|
```
|
|
631
681
|
|
|
632
682
|
**Generated Request Schema** (`schemaType: 'request'`):
|
|
683
|
+
|
|
633
684
|
```typescript
|
|
634
685
|
export const userSchema = z.object({
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
686
|
+
email: z.string(),
|
|
687
|
+
password: z.string(), // writeOnly included
|
|
688
|
+
// id and createdAt excluded (readOnly)
|
|
638
689
|
});
|
|
639
690
|
```
|
|
640
691
|
|
|
641
692
|
**Generated Response Schema** (`schemaType: 'response'`):
|
|
693
|
+
|
|
642
694
|
```typescript
|
|
643
695
|
export const userSchema = z.object({
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
696
|
+
id: z.string(), // readOnly included
|
|
697
|
+
email: z.string(),
|
|
698
|
+
createdAt: z.string().datetime(), // readOnly included
|
|
699
|
+
// password excluded (writeOnly)
|
|
648
700
|
});
|
|
649
701
|
```
|
|
650
702
|
|
|
@@ -672,11 +724,13 @@ However, many teams follow the industry de facto standard for OpenAPI 3.0.x wher
|
|
|
672
724
|
|
|
673
725
|
```typescript
|
|
674
726
|
export default defineConfig({
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
727
|
+
specs: [
|
|
728
|
+
{
|
|
729
|
+
input: "openapi.yaml",
|
|
730
|
+
outputTypes: "schemas.ts",
|
|
731
|
+
defaultNullable: true, // Treat unspecified properties as nullable
|
|
732
|
+
},
|
|
733
|
+
],
|
|
680
734
|
});
|
|
681
735
|
```
|
|
682
736
|
|
|
@@ -689,14 +743,14 @@ export default defineConfig({
|
|
|
689
743
|
|
|
690
744
|
**Behavior comparison:**
|
|
691
745
|
|
|
692
|
-
| Schema Property
|
|
693
|
-
|
|
694
|
-
| `nullable: true`
|
|
695
|
-
| `nullable: false`
|
|
696
|
-
| No annotation (primitive) | No `.nullable()`
|
|
697
|
-
| No annotation (`$ref`)
|
|
698
|
-
| No annotation (enum)
|
|
699
|
-
| No annotation (const)
|
|
746
|
+
| Schema Property | `defaultNullable: false` (default) | `defaultNullable: true` |
|
|
747
|
+
| ------------------------- | ---------------------------------- | ----------------------- |
|
|
748
|
+
| `nullable: true` | `.nullable()` | `.nullable()` |
|
|
749
|
+
| `nullable: false` | No `.nullable()` | No `.nullable()` |
|
|
750
|
+
| No annotation (primitive) | No `.nullable()` | `.nullable()` |
|
|
751
|
+
| No annotation (`$ref`) | No `.nullable()` | No `.nullable()` |
|
|
752
|
+
| No annotation (enum) | No `.nullable()` | No `.nullable()` |
|
|
753
|
+
| No annotation (const) | No `.nullable()` | No `.nullable()` |
|
|
700
754
|
|
|
701
755
|
**Example:**
|
|
702
756
|
|
|
@@ -714,34 +768,36 @@ components:
|
|
|
714
768
|
name:
|
|
715
769
|
type: string
|
|
716
770
|
status:
|
|
717
|
-
$ref:
|
|
771
|
+
$ref: "#/components/schemas/Status"
|
|
718
772
|
nullableStatus:
|
|
719
773
|
allOf:
|
|
720
|
-
- $ref:
|
|
774
|
+
- $ref: "#/components/schemas/Status"
|
|
721
775
|
nullable: true
|
|
722
776
|
```
|
|
723
777
|
|
|
724
778
|
**With `defaultNullable: false` (default):**
|
|
779
|
+
|
|
725
780
|
```typescript
|
|
726
781
|
export const statusSchema = z.enum(["active", "inactive"]);
|
|
727
782
|
|
|
728
783
|
export const userSchema = z.object({
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
784
|
+
id: z.number().int(),
|
|
785
|
+
name: z.string(), // Not nullable (no annotation)
|
|
786
|
+
status: statusSchema, // Not nullable ($ref)
|
|
787
|
+
nullableStatus: statusSchema.nullable(), // Explicitly nullable
|
|
733
788
|
});
|
|
734
789
|
```
|
|
735
790
|
|
|
736
791
|
**With `defaultNullable: true`:**
|
|
792
|
+
|
|
737
793
|
```typescript
|
|
738
794
|
export const statusSchema = z.enum(["active", "inactive"]);
|
|
739
795
|
|
|
740
796
|
export const userSchema = z.object({
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
797
|
+
id: z.number().int().nullable(), // Nullable (primitive)
|
|
798
|
+
name: z.string().nullable(), // Nullable (primitive)
|
|
799
|
+
status: statusSchema, // NOT nullable ($ref - must be explicit)
|
|
800
|
+
nullableStatus: statusSchema.nullable(), // Explicitly nullable
|
|
745
801
|
});
|
|
746
802
|
```
|
|
747
803
|
|
|
@@ -801,18 +857,19 @@ Customize schema names with prefixes and suffixes:
|
|
|
801
857
|
```typescript
|
|
802
858
|
// In your config file
|
|
803
859
|
export default defineConfig({
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
860
|
+
specs: [
|
|
861
|
+
{
|
|
862
|
+
input: "openapi.yaml",
|
|
863
|
+
outputTypes: "schemas.ts",
|
|
864
|
+
prefix: "api", // Output: apiUserSchema, apiProductSchema
|
|
865
|
+
suffix: "dto", // Output: userDtoSchema, productDtoSchema
|
|
866
|
+
},
|
|
867
|
+
],
|
|
812
868
|
});
|
|
813
869
|
```
|
|
814
870
|
|
|
815
871
|
This is useful when:
|
|
872
|
+
|
|
816
873
|
- Working with multiple API specs in the same project
|
|
817
874
|
- Following specific naming conventions (DTO, Model, Entity)
|
|
818
875
|
- Avoiding naming conflicts with existing code
|
|
@@ -822,6 +879,7 @@ This is useful when:
|
|
|
822
879
|
The `stripSchemaPrefix` option removes common prefixes from schema names in your OpenAPI spec before generating Zod schemas. This is particularly useful when your OpenAPI spec uses namespaced schema names (like .NET-generated specs with "Company.Models.User").
|
|
823
880
|
|
|
824
881
|
**OpenAPI Spec with Namespaced Schemas:**
|
|
882
|
+
|
|
825
883
|
```yaml
|
|
826
884
|
components:
|
|
827
885
|
schemas:
|
|
@@ -833,7 +891,7 @@ components:
|
|
|
833
891
|
name:
|
|
834
892
|
type: string
|
|
835
893
|
role:
|
|
836
|
-
$ref:
|
|
894
|
+
$ref: "#/components/schemas/Company.Models.UserRole"
|
|
837
895
|
Company.Models.UserRole:
|
|
838
896
|
type: string
|
|
839
897
|
enum: [admin, user, guest]
|
|
@@ -845,23 +903,24 @@ components:
|
|
|
845
903
|
title:
|
|
846
904
|
type: string
|
|
847
905
|
author:
|
|
848
|
-
$ref:
|
|
906
|
+
$ref: "#/components/schemas/Company.Models.User"
|
|
849
907
|
```
|
|
850
908
|
|
|
851
909
|
**Without `stripSchemaPrefix`:**
|
|
910
|
+
|
|
852
911
|
```typescript
|
|
853
912
|
export const companyModelsUserRoleSchema = z.enum(["admin", "user", "guest"]);
|
|
854
913
|
|
|
855
914
|
export const companyModelsUserSchema = z.object({
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
915
|
+
id: z.string(),
|
|
916
|
+
name: z.string(),
|
|
917
|
+
role: companyModelsUserRoleSchema, // Long reference name
|
|
859
918
|
});
|
|
860
919
|
|
|
861
920
|
export const companyModelsPostSchema = z.object({
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
921
|
+
id: z.string(),
|
|
922
|
+
title: z.string(),
|
|
923
|
+
author: companyModelsUserSchema, // Long reference name
|
|
865
924
|
});
|
|
866
925
|
|
|
867
926
|
export type CompanyModelsUserRole = z.infer<typeof companyModelsUserRoleSchema>;
|
|
@@ -870,19 +929,20 @@ export type CompanyModelsPost = z.infer<typeof companyModelsPostSchema>;
|
|
|
870
929
|
```
|
|
871
930
|
|
|
872
931
|
**With `stripSchemaPrefix: "Company.Models."`:**
|
|
932
|
+
|
|
873
933
|
```typescript
|
|
874
934
|
export const userRoleSchema = z.enum(["admin", "user", "guest"]);
|
|
875
935
|
|
|
876
936
|
export const userSchema = z.object({
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
937
|
+
id: z.string(),
|
|
938
|
+
name: z.string(),
|
|
939
|
+
role: userRoleSchema, // Clean reference
|
|
880
940
|
});
|
|
881
941
|
|
|
882
942
|
export const postSchema = z.object({
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
943
|
+
id: z.string(),
|
|
944
|
+
title: z.string(),
|
|
945
|
+
author: userSchema, // Clean reference
|
|
886
946
|
});
|
|
887
947
|
|
|
888
948
|
export type UserRole = z.infer<typeof userRoleSchema>;
|
|
@@ -894,11 +954,13 @@ export type Post = z.infer<typeof postSchema>;
|
|
|
894
954
|
|
|
895
955
|
```typescript
|
|
896
956
|
export default defineConfig({
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
957
|
+
specs: [
|
|
958
|
+
{
|
|
959
|
+
input: "openapi.yaml",
|
|
960
|
+
outputTypes: "schemas.ts",
|
|
961
|
+
stripSchemaPrefix: "Company.Models.", // Strip this exact prefix
|
|
962
|
+
},
|
|
963
|
+
],
|
|
902
964
|
});
|
|
903
965
|
```
|
|
904
966
|
|
|
@@ -908,18 +970,21 @@ Use glob patterns to strip dynamic prefixes:
|
|
|
908
970
|
|
|
909
971
|
```typescript
|
|
910
972
|
export default defineConfig({
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
973
|
+
specs: [
|
|
974
|
+
{
|
|
975
|
+
input: "openapi.yaml",
|
|
976
|
+
outputTypes: "schemas.ts",
|
|
977
|
+
// Strip any namespace prefix with wildcard
|
|
978
|
+
stripSchemaPrefix: "*.Models.",
|
|
979
|
+
},
|
|
980
|
+
],
|
|
917
981
|
});
|
|
918
982
|
```
|
|
919
983
|
|
|
920
984
|
**Glob Pattern Syntax:**
|
|
921
985
|
|
|
922
986
|
Glob patterns support powerful matching using [minimatch](https://github.com/isaacs/minimatch):
|
|
987
|
+
|
|
923
988
|
- `*` matches any characters within a single segment (stops at `.`)
|
|
924
989
|
- `**` matches any characters across multiple segments (crosses `.` boundaries)
|
|
925
990
|
- `?` matches a single character
|
|
@@ -929,29 +994,31 @@ Glob patterns support powerful matching using [minimatch](https://github.com/isa
|
|
|
929
994
|
|
|
930
995
|
```typescript
|
|
931
996
|
// Examples of glob patterns:
|
|
932
|
-
stripSchemaPrefix:
|
|
933
|
-
stripSchemaPrefix:
|
|
934
|
-
stripSchemaPrefix:
|
|
935
|
-
stripSchemaPrefix:
|
|
936
|
-
stripSchemaPrefix:
|
|
937
|
-
stripSchemaPrefix:
|
|
997
|
+
stripSchemaPrefix: "*.Models."; // Matches Company.Models., App.Models.
|
|
998
|
+
stripSchemaPrefix: "**.Models."; // Matches any depth: Company.Api.Models., App.V2.Models.
|
|
999
|
+
stripSchemaPrefix: "Company.{Models,Services}."; // Matches Company.Models. or Company.Services.
|
|
1000
|
+
stripSchemaPrefix: "api_v[0-9]_"; // Matches api_v1_, api_v2_, etc.
|
|
1001
|
+
stripSchemaPrefix: "v*.*."; // Matches v1.0., v2.1., etc.
|
|
1002
|
+
stripSchemaPrefix: "!(Internal)*."; // Matches any prefix except those starting with Internal
|
|
938
1003
|
```
|
|
939
1004
|
|
|
940
1005
|
#### Common Patterns
|
|
941
1006
|
|
|
942
1007
|
**Pattern 1: .NET Namespaces**
|
|
1008
|
+
|
|
943
1009
|
```typescript
|
|
944
1010
|
{
|
|
945
|
-
|
|
1011
|
+
stripSchemaPrefix: "Company.Models.";
|
|
946
1012
|
}
|
|
947
1013
|
// Company.Models.User → User
|
|
948
1014
|
// Company.Models.Post → Post
|
|
949
1015
|
```
|
|
950
1016
|
|
|
951
1017
|
**Pattern 2: Multiple Namespaces with Wildcard**
|
|
1018
|
+
|
|
952
1019
|
```typescript
|
|
953
1020
|
{
|
|
954
|
-
|
|
1021
|
+
stripSchemaPrefix: "*.Models.";
|
|
955
1022
|
}
|
|
956
1023
|
// MyApp.Models.User → User
|
|
957
1024
|
// OtherApp.Models.User → User
|
|
@@ -959,27 +1026,30 @@ stripSchemaPrefix: '!(Internal)*.' // Matches any prefix except
|
|
|
959
1026
|
```
|
|
960
1027
|
|
|
961
1028
|
**Pattern 3: Multiple Namespace Types**
|
|
1029
|
+
|
|
962
1030
|
```typescript
|
|
963
1031
|
{
|
|
964
|
-
|
|
1032
|
+
stripSchemaPrefix: "*.{Models,Services}.";
|
|
965
1033
|
}
|
|
966
1034
|
// App.Models.User → User
|
|
967
1035
|
// App.Services.UserService → UserService
|
|
968
1036
|
```
|
|
969
1037
|
|
|
970
1038
|
**Pattern 4: Version Prefixes with Character Class**
|
|
1039
|
+
|
|
971
1040
|
```typescript
|
|
972
1041
|
{
|
|
973
|
-
|
|
1042
|
+
stripSchemaPrefix: "v[0-9].";
|
|
974
1043
|
}
|
|
975
1044
|
// v1.User → User
|
|
976
1045
|
// v2.Product → Product
|
|
977
1046
|
```
|
|
978
1047
|
|
|
979
1048
|
**Pattern 5: Versioned Prefixes with Wildcards**
|
|
1049
|
+
|
|
980
1050
|
```typescript
|
|
981
1051
|
{
|
|
982
|
-
|
|
1052
|
+
stripSchemaPrefix: "api_v*_";
|
|
983
1053
|
}
|
|
984
1054
|
// api_v1_User → User
|
|
985
1055
|
// api_v2_Product → Product
|
|
@@ -992,17 +1062,20 @@ stripSchemaPrefix: '!(Internal)*.' // Matches any prefix except
|
|
|
992
1062
|
|
|
993
1063
|
```typescript
|
|
994
1064
|
export default defineConfig({
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1065
|
+
specs: [
|
|
1066
|
+
{
|
|
1067
|
+
input: "openapi.yaml",
|
|
1068
|
+
outputTypes: "schemas.ts",
|
|
1069
|
+
stripSchemaPrefix: "Company.Models.", // Applied first
|
|
1070
|
+
prefix: "api", // Applied second
|
|
1071
|
+
suffix: "dto", // Applied third
|
|
1072
|
+
},
|
|
1073
|
+
],
|
|
1002
1074
|
});
|
|
1003
1075
|
```
|
|
1004
1076
|
|
|
1005
1077
|
**Result:**
|
|
1078
|
+
|
|
1006
1079
|
- `Company.Models.User` → `User` → `apiUserDtoSchema`
|
|
1007
1080
|
- `Company.Models.Post` → `Post` → `apiPostDtoSchema`
|
|
1008
1081
|
|
|
@@ -1028,6 +1101,7 @@ Statistics are **included by default** in generated files. Use `showStats: false
|
|
|
1028
1101
|
```
|
|
1029
1102
|
|
|
1030
1103
|
Helpful for:
|
|
1104
|
+
|
|
1031
1105
|
- Understanding your API complexity
|
|
1032
1106
|
- Tracking changes over time
|
|
1033
1107
|
- Debugging generation issues
|
|
@@ -1037,12 +1111,14 @@ Helpful for:
|
|
|
1037
1111
|
### Basic Types
|
|
1038
1112
|
|
|
1039
1113
|
#### String Constraints
|
|
1114
|
+
|
|
1040
1115
|
- `minLength` → `.min(n)`
|
|
1041
1116
|
- `maxLength` → `.max(n)`
|
|
1042
1117
|
- `pattern` → `.regex(/pattern/)`
|
|
1043
1118
|
- `format` → Specific Zod validators (see Format Support section)
|
|
1044
1119
|
|
|
1045
1120
|
#### Number Constraints
|
|
1121
|
+
|
|
1046
1122
|
- `minimum` → `.gte(n)` (inclusive)
|
|
1047
1123
|
- `maximum` → `.lte(n)` (inclusive)
|
|
1048
1124
|
- `exclusiveMinimum` → `.gt(n)` (OpenAPI 3.0 boolean or 3.1 number)
|
|
@@ -1051,15 +1127,17 @@ Helpful for:
|
|
|
1051
1127
|
- `integer` type → `.int()`
|
|
1052
1128
|
|
|
1053
1129
|
**Example:**
|
|
1130
|
+
|
|
1054
1131
|
```yaml
|
|
1055
1132
|
Price:
|
|
1056
1133
|
type: number
|
|
1057
1134
|
minimum: 0
|
|
1058
1135
|
maximum: 10000
|
|
1059
|
-
multipleOf: 0.01
|
|
1136
|
+
multipleOf: 0.01 # Enforces 2 decimal places
|
|
1060
1137
|
```
|
|
1061
1138
|
|
|
1062
1139
|
**Generated:**
|
|
1140
|
+
|
|
1063
1141
|
```typescript
|
|
1064
1142
|
export const priceSchema = z.number().gte(0).lte(10000).multipleOf(0.01);
|
|
1065
1143
|
```
|
|
@@ -1067,6 +1145,7 @@ export const priceSchema = z.number().gte(0).lte(10000).multipleOf(0.01);
|
|
|
1067
1145
|
#### Exclusive Bounds (OpenAPI 3.0 & 3.1)
|
|
1068
1146
|
|
|
1069
1147
|
**OpenAPI 3.0 Style (boolean):**
|
|
1148
|
+
|
|
1070
1149
|
```yaml
|
|
1071
1150
|
Percentage:
|
|
1072
1151
|
type: number
|
|
@@ -1077,6 +1156,7 @@ Percentage:
|
|
|
1077
1156
|
```
|
|
1078
1157
|
|
|
1079
1158
|
**OpenAPI 3.1 Style (number):**
|
|
1159
|
+
|
|
1080
1160
|
```yaml
|
|
1081
1161
|
Score:
|
|
1082
1162
|
type: number
|
|
@@ -1085,6 +1165,7 @@ Score:
|
|
|
1085
1165
|
```
|
|
1086
1166
|
|
|
1087
1167
|
**Both generate:**
|
|
1168
|
+
|
|
1088
1169
|
```typescript
|
|
1089
1170
|
export const percentageSchema = z.number().gt(0).lt(100);
|
|
1090
1171
|
```
|
|
@@ -1092,11 +1173,13 @@ export const percentageSchema = z.number().gt(0).lt(100);
|
|
|
1092
1173
|
### Array Features
|
|
1093
1174
|
|
|
1094
1175
|
#### Basic Array Constraints
|
|
1176
|
+
|
|
1095
1177
|
- `minItems` → `.min(n)`
|
|
1096
1178
|
- `maxItems` → `.max(n)`
|
|
1097
1179
|
- `uniqueItems: true` → `.refine()` with Set-based validation
|
|
1098
1180
|
|
|
1099
1181
|
**Example:**
|
|
1182
|
+
|
|
1100
1183
|
```yaml
|
|
1101
1184
|
UniqueTags:
|
|
1102
1185
|
type: array
|
|
@@ -1108,14 +1191,15 @@ UniqueTags:
|
|
|
1108
1191
|
```
|
|
1109
1192
|
|
|
1110
1193
|
**Generated:**
|
|
1194
|
+
|
|
1111
1195
|
```typescript
|
|
1112
1196
|
export const uniqueTagsSchema = z
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1197
|
+
.array(z.string())
|
|
1198
|
+
.min(1)
|
|
1199
|
+
.max(10)
|
|
1200
|
+
.refine(items => new Set(items).size === items.length, {
|
|
1201
|
+
message: "Array items must be unique",
|
|
1202
|
+
});
|
|
1119
1203
|
```
|
|
1120
1204
|
|
|
1121
1205
|
#### Tuple Validation (OpenAPI 3.1)
|
|
@@ -1140,34 +1224,33 @@ Coordinates:
|
|
|
1140
1224
|
```
|
|
1141
1225
|
|
|
1142
1226
|
**Generated:**
|
|
1227
|
+
|
|
1143
1228
|
```typescript
|
|
1144
|
-
export const coordinatesSchema = z.tuple([
|
|
1145
|
-
z.number().gte(-90).lte(90),
|
|
1146
|
-
z.number().gte(-180).lte(180)
|
|
1147
|
-
]);
|
|
1229
|
+
export const coordinatesSchema = z.tuple([z.number().gte(-90).lte(90), z.number().gte(-180).lte(180)]);
|
|
1148
1230
|
```
|
|
1149
1231
|
|
|
1150
1232
|
**With Rest Items:**
|
|
1233
|
+
|
|
1151
1234
|
```yaml
|
|
1152
1235
|
CommandArgs:
|
|
1153
1236
|
type: array
|
|
1154
1237
|
prefixItems:
|
|
1155
|
-
- type: string
|
|
1156
|
-
- type: string
|
|
1238
|
+
- type: string # Command name
|
|
1239
|
+
- type: string # Action
|
|
1157
1240
|
items:
|
|
1158
|
-
type: string
|
|
1241
|
+
type: string # Additional arguments
|
|
1159
1242
|
```
|
|
1160
1243
|
|
|
1161
1244
|
**Generated:**
|
|
1245
|
+
|
|
1162
1246
|
```typescript
|
|
1163
|
-
export const commandArgsSchema = z
|
|
1164
|
-
.tuple([z.string(), z.string()])
|
|
1165
|
-
.rest(z.string());
|
|
1247
|
+
export const commandArgsSchema = z.tuple([z.string(), z.string()]).rest(z.string());
|
|
1166
1248
|
```
|
|
1167
1249
|
|
|
1168
1250
|
### Object Features
|
|
1169
1251
|
|
|
1170
1252
|
#### Property Constraints
|
|
1253
|
+
|
|
1171
1254
|
- `required` array → Properties without `.optional()`
|
|
1172
1255
|
- `additionalProperties: false` → `.strict()` (or implicit in strict mode)
|
|
1173
1256
|
- `additionalProperties: true` → `.catchall(z.unknown())`
|
|
@@ -1176,6 +1259,7 @@ export const commandArgsSchema = z
|
|
|
1176
1259
|
- `maxProperties` → `.refine()` with property count validation
|
|
1177
1260
|
|
|
1178
1261
|
**Example:**
|
|
1262
|
+
|
|
1179
1263
|
```yaml
|
|
1180
1264
|
FlexibleMetadata:
|
|
1181
1265
|
type: object
|
|
@@ -1186,13 +1270,14 @@ FlexibleMetadata:
|
|
|
1186
1270
|
```
|
|
1187
1271
|
|
|
1188
1272
|
**Generated:**
|
|
1273
|
+
|
|
1189
1274
|
```typescript
|
|
1190
1275
|
export const flexibleMetadataSchema = z
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1276
|
+
.object({})
|
|
1277
|
+
.catchall(z.string())
|
|
1278
|
+
.refine(obj => Object.keys(obj).length >= 1 && Object.keys(obj).length <= 10, {
|
|
1279
|
+
message: "Object must have between 1 and 10 properties",
|
|
1280
|
+
});
|
|
1196
1281
|
```
|
|
1197
1282
|
|
|
1198
1283
|
### Schema Composition
|
|
@@ -1202,6 +1287,7 @@ export const flexibleMetadataSchema = z
|
|
|
1202
1287
|
Uses `.extend()` for objects (Zod v4 compliant - `.merge()` is deprecated), `.and()` for primitives:
|
|
1203
1288
|
|
|
1204
1289
|
**Object Extending:**
|
|
1290
|
+
|
|
1205
1291
|
```yaml
|
|
1206
1292
|
User:
|
|
1207
1293
|
allOf:
|
|
@@ -1216,12 +1302,13 @@ User:
|
|
|
1216
1302
|
```
|
|
1217
1303
|
|
|
1218
1304
|
**Generated:**
|
|
1305
|
+
|
|
1219
1306
|
```typescript
|
|
1220
|
-
export const userSchema = baseEntitySchema
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1307
|
+
export const userSchema = baseEntitySchema.extend(timestampedSchema.shape).extend(
|
|
1308
|
+
z.object({
|
|
1309
|
+
username: z.string(),
|
|
1310
|
+
}).shape
|
|
1311
|
+
);
|
|
1225
1312
|
```
|
|
1226
1313
|
|
|
1227
1314
|
#### OneOf / AnyOf
|
|
@@ -1232,6 +1319,7 @@ export const userSchema = baseEntitySchema
|
|
|
1232
1319
|
### Nullable Types
|
|
1233
1320
|
|
|
1234
1321
|
**OpenAPI 3.0 Style:**
|
|
1322
|
+
|
|
1235
1323
|
```yaml
|
|
1236
1324
|
NullableString:
|
|
1237
1325
|
type: string
|
|
@@ -1239,12 +1327,14 @@ NullableString:
|
|
|
1239
1327
|
```
|
|
1240
1328
|
|
|
1241
1329
|
**OpenAPI 3.1 Style:**
|
|
1330
|
+
|
|
1242
1331
|
```yaml
|
|
1243
1332
|
NullableString:
|
|
1244
1333
|
type: ["string", "null"]
|
|
1245
1334
|
```
|
|
1246
1335
|
|
|
1247
1336
|
**Both generate:**
|
|
1337
|
+
|
|
1248
1338
|
```typescript
|
|
1249
1339
|
export const nullableStringSchema = z.string().nullable();
|
|
1250
1340
|
```
|
|
@@ -1260,6 +1350,7 @@ Environment:
|
|
|
1260
1350
|
```
|
|
1261
1351
|
|
|
1262
1352
|
**Generated:**
|
|
1353
|
+
|
|
1263
1354
|
```typescript
|
|
1264
1355
|
export const environmentSchema = z.literal("production");
|
|
1265
1356
|
```
|
|
@@ -1281,11 +1372,12 @@ OldUser:
|
|
|
1281
1372
|
```
|
|
1282
1373
|
|
|
1283
1374
|
**Generated:**
|
|
1375
|
+
|
|
1284
1376
|
```typescript
|
|
1285
1377
|
/** Legacy user schema @deprecated */
|
|
1286
1378
|
export const oldUserSchema = z.object({
|
|
1287
|
-
|
|
1288
|
-
|
|
1379
|
+
/** Old ID format, use uuid instead @deprecated */
|
|
1380
|
+
legacyId: z.number().int().optional(),
|
|
1289
1381
|
});
|
|
1290
1382
|
```
|
|
1291
1383
|
|
|
@@ -1301,9 +1393,12 @@ UserAccount:
|
|
|
1301
1393
|
```
|
|
1302
1394
|
|
|
1303
1395
|
**Generated:**
|
|
1396
|
+
|
|
1304
1397
|
```typescript
|
|
1305
1398
|
/** User Account Represents a user account in the system */
|
|
1306
|
-
export const userAccountSchema = z.object({
|
|
1399
|
+
export const userAccountSchema = z.object({
|
|
1400
|
+
/* ... */
|
|
1401
|
+
});
|
|
1307
1402
|
```
|
|
1308
1403
|
|
|
1309
1404
|
#### Examples
|
|
@@ -1320,6 +1415,7 @@ StatusCode:
|
|
|
1320
1415
|
```
|
|
1321
1416
|
|
|
1322
1417
|
**Generated:**
|
|
1418
|
+
|
|
1323
1419
|
```typescript
|
|
1324
1420
|
/** HTTP Status Code @example "200", "404", "500" */
|
|
1325
1421
|
export const statusCodeSchema = z.enum(["200", "201", "400", "404", "500"]);
|
|
@@ -1327,49 +1423,52 @@ export const statusCodeSchema = z.enum(["200", "201", "400", "404", "500"]);
|
|
|
1327
1423
|
|
|
1328
1424
|
### Feature Matrix
|
|
1329
1425
|
|
|
1330
|
-
| Feature
|
|
1331
|
-
|
|
1332
|
-
| Basic types
|
|
1333
|
-
| String constraints
|
|
1334
|
-
| Number constraints
|
|
1335
|
-
| Exclusive bounds (boolean)
|
|
1336
|
-
| Exclusive bounds (number)
|
|
1337
|
-
| multipleOf
|
|
1338
|
-
| Array constraints
|
|
1339
|
-
| uniqueItems
|
|
1340
|
-
| prefixItems (tuples)
|
|
1341
|
-
| additionalProperties
|
|
1342
|
-
| minProperties/maxProperties | ✅
|
|
1343
|
-
| const
|
|
1344
|
-
| nullable (property)
|
|
1345
|
-
| nullable (type array)
|
|
1346
|
-
| allOf (objects)
|
|
1347
|
-
| allOf (primitives)
|
|
1348
|
-
| oneOf/anyOf
|
|
1349
|
-
| discriminators
|
|
1350
|
-
| deprecated
|
|
1351
|
-
| title
|
|
1352
|
-
| examples
|
|
1353
|
-
| format
|
|
1354
|
-
| readOnly/writeOnly
|
|
1426
|
+
| Feature | OpenAPI 3.0 | OpenAPI 3.1 | Zod Method |
|
|
1427
|
+
| --------------------------- | ----------- | ----------- | -------------------------------- |
|
|
1428
|
+
| Basic types | ✅ | ✅ | `z.string()`, `z.number()`, etc. |
|
|
1429
|
+
| String constraints | ✅ | ✅ | `.min()`, `.max()`, `.regex()` |
|
|
1430
|
+
| Number constraints | ✅ | ✅ | `.gte()`, `.lte()`, `.int()` |
|
|
1431
|
+
| Exclusive bounds (boolean) | ✅ | ✅ | `.gt()`, `.lt()` |
|
|
1432
|
+
| Exclusive bounds (number) | ❌ | ✅ | `.gt()`, `.lt()` |
|
|
1433
|
+
| multipleOf | ✅ | ✅ | `.multipleOf()` |
|
|
1434
|
+
| Array constraints | ✅ | ✅ | `.min()`, `.max()` |
|
|
1435
|
+
| uniqueItems | ✅ | ✅ | `.refine()` with Set |
|
|
1436
|
+
| prefixItems (tuples) | ❌ | ✅ | `z.tuple()` |
|
|
1437
|
+
| additionalProperties | ✅ | ✅ | `.strict()`, `.catchall()` |
|
|
1438
|
+
| minProperties/maxProperties | ✅ | ✅ | `.refine()` |
|
|
1439
|
+
| const | ✅ | ✅ | `z.literal()` |
|
|
1440
|
+
| nullable (property) | ✅ | ✅ | `.nullable()` |
|
|
1441
|
+
| nullable (type array) | ❌ | ✅ | `.nullable()` |
|
|
1442
|
+
| allOf (objects) | ✅ | ✅ | `.extend()` |
|
|
1443
|
+
| allOf (primitives) | ✅ | ✅ | `.and()` |
|
|
1444
|
+
| oneOf/anyOf | ✅ | ✅ | `z.union()` |
|
|
1445
|
+
| discriminators | ✅ | ✅ | `z.discriminatedUnion()` |
|
|
1446
|
+
| deprecated | ✅ | ✅ | JSDoc `@deprecated` |
|
|
1447
|
+
| title | ✅ | ✅ | JSDoc comment |
|
|
1448
|
+
| examples | ✅ | ✅ | JSDoc `@example` |
|
|
1449
|
+
| format | ✅ | ✅ | Specific Zod validators |
|
|
1450
|
+
| readOnly/writeOnly | ✅ | ✅ | Schema filtering |
|
|
1355
1451
|
|
|
1356
1452
|
## Error Messages
|
|
1357
1453
|
|
|
1358
1454
|
The generator provides clear, actionable error messages:
|
|
1359
1455
|
|
|
1360
1456
|
### Invalid References
|
|
1457
|
+
|
|
1361
1458
|
```
|
|
1362
1459
|
Error: Invalid schema 'User': Invalid reference at 'profile':
|
|
1363
1460
|
'#/components/schemas/NonExistentProfile' points to non-existent schema 'NonExistentProfile'
|
|
1364
1461
|
```
|
|
1365
1462
|
|
|
1366
1463
|
### YAML Syntax Errors
|
|
1464
|
+
|
|
1367
1465
|
```
|
|
1368
1466
|
Error: Failed to parse OpenAPI YAML file at openapi.yaml:
|
|
1369
1467
|
Implicit keys need to be on a single line at line 12, column 9
|
|
1370
1468
|
```
|
|
1371
1469
|
|
|
1372
1470
|
All errors include:
|
|
1471
|
+
|
|
1373
1472
|
- File path
|
|
1374
1473
|
- Line and column numbers (when available)
|
|
1375
1474
|
- Clear description of the problem
|
|
@@ -1384,11 +1483,11 @@ Starting from **v0.7.0**, this package exports several utilities that can be use
|
|
|
1384
1483
|
A Least Recently Used (LRU) cache implementation for efficient caching.
|
|
1385
1484
|
|
|
1386
1485
|
```typescript
|
|
1387
|
-
import { LRUCache } from
|
|
1486
|
+
import { LRUCache } from "@cerios/openapi-to-zod";
|
|
1388
1487
|
|
|
1389
1488
|
const cache = new LRUCache<string, ParsedSpec>(50);
|
|
1390
|
-
cache.set(
|
|
1391
|
-
const spec = cache.get(
|
|
1489
|
+
cache.set("spec-key", parsedSpec);
|
|
1490
|
+
const spec = cache.get("spec-key");
|
|
1392
1491
|
```
|
|
1393
1492
|
|
|
1394
1493
|
### `toPascalCase(str: string | number): string`
|
|
@@ -1396,10 +1495,10 @@ const spec = cache.get('spec-key');
|
|
|
1396
1495
|
Converts strings to PascalCase, handling kebab-case, snake_case, and special characters.
|
|
1397
1496
|
|
|
1398
1497
|
```typescript
|
|
1399
|
-
import { toPascalCase } from
|
|
1498
|
+
import { toPascalCase } from "@cerios/openapi-to-zod";
|
|
1400
1499
|
|
|
1401
|
-
toPascalCase(
|
|
1402
|
-
toPascalCase(
|
|
1500
|
+
toPascalCase("my-api-client"); // => 'MyApiClient'
|
|
1501
|
+
toPascalCase("user_name"); // => 'UserName'
|
|
1403
1502
|
```
|
|
1404
1503
|
|
|
1405
1504
|
### `escapeJSDoc(str: string): string`
|
|
@@ -1407,9 +1506,9 @@ toPascalCase('user_name'); // => 'UserName'
|
|
|
1407
1506
|
Escapes JSDoc comment terminators to prevent injection.
|
|
1408
1507
|
|
|
1409
1508
|
```typescript
|
|
1410
|
-
import { escapeJSDoc } from
|
|
1509
|
+
import { escapeJSDoc } from "@cerios/openapi-to-zod";
|
|
1411
1510
|
|
|
1412
|
-
escapeJSDoc(
|
|
1511
|
+
escapeJSDoc("Comment with */ terminator"); // => 'Comment with *\\/ terminator'
|
|
1413
1512
|
```
|
|
1414
1513
|
|
|
1415
1514
|
### `executeBatch<T>()` and `Generator` Interface
|
|
@@ -1417,18 +1516,18 @@ escapeJSDoc('Comment with */ terminator'); // => 'Comment with *\\/ terminator'
|
|
|
1417
1516
|
Execute batch processing with custom generators.
|
|
1418
1517
|
|
|
1419
1518
|
```typescript
|
|
1420
|
-
import { executeBatch, type Generator } from
|
|
1519
|
+
import { executeBatch, type Generator } from "@cerios/openapi-to-zod";
|
|
1421
1520
|
|
|
1422
1521
|
class MyGenerator implements Generator {
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1522
|
+
generate(): void {
|
|
1523
|
+
// Your generation logic
|
|
1524
|
+
}
|
|
1426
1525
|
}
|
|
1427
1526
|
|
|
1428
1527
|
await executeBatch(
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1528
|
+
specs,
|
|
1529
|
+
"sequential", // or 'parallel'
|
|
1530
|
+
spec => new MyGenerator(spec)
|
|
1432
1531
|
);
|
|
1433
1532
|
```
|
|
1434
1533
|
|
|
@@ -1438,61 +1537,113 @@ Shared utilities for configuration file validation:
|
|
|
1438
1537
|
|
|
1439
1538
|
```typescript
|
|
1440
1539
|
import {
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
} from
|
|
1540
|
+
createTypeScriptLoader,
|
|
1541
|
+
formatConfigValidationError,
|
|
1542
|
+
type RequestResponseOptions,
|
|
1543
|
+
type BaseOperationFilters,
|
|
1544
|
+
} from "@cerios/openapi-to-zod";
|
|
1446
1545
|
|
|
1447
1546
|
// Create TypeScript config loader for cosmiconfig
|
|
1448
1547
|
const loader = createTypeScriptLoader();
|
|
1449
1548
|
|
|
1450
1549
|
// Format Zod validation errors
|
|
1451
|
-
const errorMessage = formatConfigValidationError(
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
['Additional note 1', 'Additional note 2']
|
|
1456
|
-
);
|
|
1550
|
+
const errorMessage = formatConfigValidationError(zodError, filePath, configPath, [
|
|
1551
|
+
"Additional note 1",
|
|
1552
|
+
"Additional note 2",
|
|
1553
|
+
]);
|
|
1457
1554
|
```
|
|
1458
1555
|
|
|
1459
1556
|
These utilities are marked with `@shared` tags in the source code and are covered by comprehensive tests.
|
|
1460
1557
|
|
|
1461
1558
|
## API Reference
|
|
1462
1559
|
|
|
1463
|
-
### `
|
|
1560
|
+
### `OpenApiGenerator`
|
|
1561
|
+
|
|
1562
|
+
Main class for generating Zod schemas from OpenAPI specifications.
|
|
1563
|
+
|
|
1564
|
+
```typescript
|
|
1565
|
+
import { OpenApiGenerator } from "@cerios/openapi-to-zod";
|
|
1566
|
+
|
|
1567
|
+
const generator = new OpenApiGenerator(options);
|
|
1568
|
+
|
|
1569
|
+
// Generate and write to file
|
|
1570
|
+
generator.generate();
|
|
1464
1571
|
|
|
1465
|
-
|
|
1572
|
+
// Or generate as string
|
|
1573
|
+
const code = generator.generateString();
|
|
1574
|
+
```
|
|
1466
1575
|
|
|
1467
1576
|
#### Options
|
|
1468
1577
|
|
|
1469
1578
|
```typescript
|
|
1470
1579
|
interface OpenApiGeneratorOptions {
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1580
|
+
/**
|
|
1581
|
+
* Input OpenAPI YAML/JSON file path
|
|
1582
|
+
*/
|
|
1583
|
+
input: string;
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* Output TypeScript file path
|
|
1587
|
+
*/
|
|
1588
|
+
outputTypes: string;
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* Object validation mode
|
|
1592
|
+
* - 'strict': Uses z.strictObject() - no additional properties allowed
|
|
1593
|
+
* - 'normal': Uses z.object() - additional properties allowed
|
|
1594
|
+
* - 'loose': Uses z.looseObject() - explicitly allows additional properties
|
|
1595
|
+
*/
|
|
1596
|
+
mode?: "strict" | "normal" | "loose";
|
|
1597
|
+
|
|
1598
|
+
/**
|
|
1599
|
+
* Whether to include descriptions as JSDoc comments
|
|
1600
|
+
*/
|
|
1601
|
+
includeDescriptions?: boolean;
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Add custom prefix to schema names
|
|
1605
|
+
*/
|
|
1606
|
+
prefix?: string;
|
|
1607
|
+
|
|
1608
|
+
/**
|
|
1609
|
+
* Add custom suffix to schema names
|
|
1610
|
+
*/
|
|
1611
|
+
suffix?: string;
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* Strip prefix from schema names using glob patterns
|
|
1615
|
+
*/
|
|
1616
|
+
stripSchemaPrefix?: string | string[];
|
|
1617
|
+
|
|
1618
|
+
/**
|
|
1619
|
+
* Show generation statistics in output
|
|
1620
|
+
*/
|
|
1621
|
+
showStats?: boolean;
|
|
1622
|
+
|
|
1623
|
+
/**
|
|
1624
|
+
* Schema filtering mode
|
|
1625
|
+
*/
|
|
1626
|
+
schemaType?: "all" | "request" | "response";
|
|
1627
|
+
|
|
1628
|
+
/**
|
|
1629
|
+
* Operation filters for including/excluding operations
|
|
1630
|
+
*/
|
|
1631
|
+
operationFilters?: OperationFilters;
|
|
1493
1632
|
}
|
|
1494
1633
|
```
|
|
1495
1634
|
|
|
1635
|
+
### `defineConfig`
|
|
1636
|
+
|
|
1637
|
+
Type-safe helper for creating configuration files.
|
|
1638
|
+
|
|
1639
|
+
```typescript
|
|
1640
|
+
import { defineConfig } from "@cerios/openapi-to-zod";
|
|
1641
|
+
|
|
1642
|
+
export default defineConfig({
|
|
1643
|
+
specs: [{ input: "api.yaml", outputTypes: "schemas.ts" }],
|
|
1644
|
+
});
|
|
1645
|
+
```
|
|
1646
|
+
|
|
1496
1647
|
## Requirements
|
|
1497
1648
|
|
|
1498
1649
|
- Node.js >= 16
|
|
@@ -1527,4 +1678,4 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
1527
1678
|
|
|
1528
1679
|
## Support
|
|
1529
1680
|
|
|
1530
|
-
For issues and questions, please use the [GitHub issues](https://github.com/CeriosTesting/openapi-
|
|
1681
|
+
For issues and questions, please use the [GitHub issues](https://github.com/CeriosTesting/openapi-codegen/issues) page.
|