@alt-stack/zod-openapi 1.0.1

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/dist/index.js ADDED
@@ -0,0 +1,860 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ SUPPORTED_STRING_FORMATS: () => SUPPORTED_STRING_FORMATS,
24
+ clearZodSchemaToOpenApiSchemaRegistry: () => clearZodSchemaToOpenApiSchemaRegistry,
25
+ convertSchemaToZodString: () => convertSchemaToZodString,
26
+ generateRouteSchemaNames: () => generateRouteSchemaNames,
27
+ getSchemaExportedVariableNameForStringFormat: () => getSchemaExportedVariableNameForStringFormat,
28
+ openApiToZodTsCode: () => openApiToZodTsCode,
29
+ parseOpenApiPaths: () => parseOpenApiPaths,
30
+ registerZodSchemaToOpenApiSchema: () => registerZodSchemaToOpenApiSchema,
31
+ schemaRegistry: () => schemaRegistry
32
+ });
33
+ module.exports = __toCommonJS(index_exports);
34
+
35
+ // src/dependencies.ts
36
+ function extractSchemaDependencies(schema) {
37
+ const dependencies = /* @__PURE__ */ new Set();
38
+ const visited = /* @__PURE__ */ new WeakSet();
39
+ function traverse(obj) {
40
+ if (!obj || typeof obj !== "object") return;
41
+ if (visited.has(obj)) return;
42
+ visited.add(obj);
43
+ if (obj["$ref"] && typeof obj["$ref"] === "string") {
44
+ const match = obj["$ref"].match(
45
+ /#\/components\/schemas\/(.+)/
46
+ );
47
+ if (match && match[1]) {
48
+ dependencies.add(decodeURIComponent(match[1]));
49
+ }
50
+ return;
51
+ }
52
+ if (Array.isArray(obj)) {
53
+ obj.forEach(traverse);
54
+ return;
55
+ }
56
+ if (obj.properties && typeof obj.properties === "object") {
57
+ for (const propValue of Object.values(obj.properties)) {
58
+ traverse(propValue);
59
+ }
60
+ }
61
+ const schemaKeys = [
62
+ "items",
63
+ "oneOf",
64
+ "allOf",
65
+ "anyOf",
66
+ "not",
67
+ "if",
68
+ "then",
69
+ "else",
70
+ "prefixItems",
71
+ "contains",
72
+ "propertyNames",
73
+ "dependentSchemas"
74
+ ];
75
+ for (const key of schemaKeys) {
76
+ if (obj[key]) {
77
+ traverse(obj[key]);
78
+ }
79
+ }
80
+ if (obj.additionalProperties && typeof obj.additionalProperties === "object") {
81
+ traverse(obj.additionalProperties);
82
+ }
83
+ if (obj.discriminator?.mapping) {
84
+ Object.values(obj.discriminator.mapping).forEach(traverse);
85
+ }
86
+ }
87
+ traverse(schema);
88
+ return Array.from(dependencies);
89
+ }
90
+ function topologicalSortSchemas(schemas) {
91
+ const schemaNames = Object.keys(schemas);
92
+ const dependencies = /* @__PURE__ */ new Map();
93
+ const inDegree = /* @__PURE__ */ new Map();
94
+ const sorted = [];
95
+ const queue = [];
96
+ const dependents = /* @__PURE__ */ new Map();
97
+ for (const name of schemaNames) {
98
+ dependencies.set(name, []);
99
+ dependents.set(name, []);
100
+ inDegree.set(name, 0);
101
+ }
102
+ for (const name of schemaNames) {
103
+ const schemaValue = schemas[name];
104
+ if (schemaValue) {
105
+ const deps = extractSchemaDependencies(schemaValue);
106
+ const validDeps = deps.filter((dep) => schemaNames.includes(dep));
107
+ dependencies.set(name, validDeps);
108
+ for (const dep of validDeps) {
109
+ const currentDependents = dependents.get(dep) || [];
110
+ currentDependents.push(name);
111
+ dependents.set(dep, currentDependents);
112
+ }
113
+ }
114
+ }
115
+ for (const [name, deps] of dependencies.entries()) {
116
+ inDegree.set(name, deps.length);
117
+ }
118
+ for (const [name, degree] of inDegree.entries()) {
119
+ if (degree === 0) {
120
+ queue.push(name);
121
+ }
122
+ }
123
+ while (queue.length > 0) {
124
+ const current = queue.shift();
125
+ sorted.push(current);
126
+ const currentDependents = dependents.get(current) || [];
127
+ for (const dependent of currentDependents) {
128
+ const newDegree = (inDegree.get(dependent) || 0) - 1;
129
+ inDegree.set(dependent, newDegree);
130
+ if (newDegree === 0) {
131
+ queue.push(dependent);
132
+ }
133
+ }
134
+ }
135
+ if (sorted.length !== schemaNames.length) {
136
+ for (const name of schemaNames) {
137
+ if (!sorted.includes(name)) {
138
+ sorted.push(name);
139
+ }
140
+ }
141
+ }
142
+ return sorted;
143
+ }
144
+
145
+ // src/types/boolean.ts
146
+ function convertOpenAPIBooleanToZod(_) {
147
+ return "z.boolean()";
148
+ }
149
+
150
+ // src/types/number.ts
151
+ function convertOpenAPINumberToZod(schema) {
152
+ let result = "z.number()";
153
+ if (schema.type === "integer") {
154
+ result += ".int()";
155
+ }
156
+ if (typeof schema.minimum === "number") {
157
+ result += `.min(${schema.minimum})`;
158
+ }
159
+ if (typeof schema.maximum === "number") {
160
+ result += `.max(${schema.maximum})`;
161
+ }
162
+ return result;
163
+ }
164
+
165
+ // src/registry.ts
166
+ var SUPPORTED_STRING_FORMATS_MAP = {
167
+ "color-hex": 1,
168
+ date: 1,
169
+ "date-time": 1,
170
+ email: 1,
171
+ "iso-date": 1,
172
+ "iso-date-time": 1,
173
+ objectid: 1,
174
+ uri: 1,
175
+ url: 1,
176
+ uuid: 1
177
+ };
178
+ var SUPPORTED_STRING_FORMATS = Object.keys(
179
+ SUPPORTED_STRING_FORMATS_MAP
180
+ );
181
+ function isStringRegistration(reg) {
182
+ return reg.type === "string" && "format" in reg;
183
+ }
184
+ function isStringsRegistration(reg) {
185
+ return reg.type === "string" && "formats" in reg;
186
+ }
187
+ function getTypeFormatPairs(reg) {
188
+ if (isStringRegistration(reg)) {
189
+ return [{ type: "string", format: reg.format }];
190
+ }
191
+ if (isStringsRegistration(reg)) {
192
+ return reg.formats.map((f) => ({ type: "string", format: f }));
193
+ }
194
+ return [];
195
+ }
196
+ var ZodSchemaRegistry = class {
197
+ map = /* @__PURE__ */ new Map();
198
+ register(schema, registration) {
199
+ const newPairs = getTypeFormatPairs(registration);
200
+ if (newPairs.length > 0) {
201
+ for (const [existingSchema, existingRegistration] of this.map.entries()) {
202
+ if (existingSchema === schema) continue;
203
+ const existingPairs = getTypeFormatPairs(existingRegistration);
204
+ for (const { type, format } of newPairs) {
205
+ if (existingPairs.some((p) => p.type === type && p.format === format)) {
206
+ throw new Error(
207
+ `duplicate Zod OpenAPI registration for (type, format)=('${type}', '${format}')`
208
+ );
209
+ }
210
+ }
211
+ }
212
+ }
213
+ this.map.set(schema, registration);
214
+ }
215
+ /**
216
+ * Get the OpenAPI schema for a given Zod schema
217
+ */
218
+ getOpenApiSchema(schema) {
219
+ return this.map.get(schema);
220
+ }
221
+ /**
222
+ * Check if a Zod schema is registered
223
+ */
224
+ isRegistered(schema) {
225
+ return this.map.has(schema);
226
+ }
227
+ /**
228
+ * Clear all registered schemas
229
+ */
230
+ clear() {
231
+ this.map.clear();
232
+ }
233
+ /**
234
+ * Reverse-lookup helper: given a string format, return the registered schema's exported variable name
235
+ */
236
+ getSchemaExportedVariableNameForStringFormat(format) {
237
+ for (const registration of this.map.values()) {
238
+ if (registration.type !== "string") continue;
239
+ if (isStringRegistration(registration) && registration.format === format) {
240
+ return registration.schemaExportedVariableName;
241
+ }
242
+ if (isStringsRegistration(registration) && registration.formats.includes(format)) {
243
+ return registration.schemaExportedVariableName;
244
+ }
245
+ }
246
+ return void 0;
247
+ }
248
+ };
249
+ var schemaRegistry = new ZodSchemaRegistry();
250
+ function registerZodSchemaToOpenApiSchema(schema, openApiSchema) {
251
+ schemaRegistry.register(schema, openApiSchema);
252
+ }
253
+ function getSchemaExportedVariableNameForStringFormat(format) {
254
+ return schemaRegistry.getSchemaExportedVariableNameForStringFormat(format);
255
+ }
256
+ function clearZodSchemaToOpenApiSchemaRegistry() {
257
+ schemaRegistry.clear();
258
+ }
259
+
260
+ // src/types/string.ts
261
+ function convertOpenAPIStringToZod(schema) {
262
+ if (schema.enum) {
263
+ return `z.enum([${schema.enum.map((value) => `'${value}'`).join(", ")}])`;
264
+ }
265
+ if (schema.format && SUPPORTED_STRING_FORMATS.includes(schema.format)) {
266
+ const customSchemaName = getSchemaExportedVariableNameForStringFormat(
267
+ schema.format
268
+ );
269
+ if (customSchemaName) {
270
+ return customSchemaName;
271
+ }
272
+ }
273
+ let zodSchema = "z.string()";
274
+ if (schema.format) {
275
+ zodSchema += getFormatModifier(schema.format);
276
+ }
277
+ if (typeof schema.minLength === "number") {
278
+ zodSchema += `.min(${schema.minLength})`;
279
+ }
280
+ if (typeof schema.maxLength === "number") {
281
+ zodSchema += `.max(${schema.maxLength})`;
282
+ }
283
+ if (typeof schema.pattern === "string") {
284
+ zodSchema += `.regex(/${schema.pattern}/)`;
285
+ }
286
+ return zodSchema;
287
+ }
288
+ function getFormatModifier(format) {
289
+ switch (format) {
290
+ case "email":
291
+ return ".email()";
292
+ case "url":
293
+ case "uri":
294
+ return ".url()";
295
+ case "uuid":
296
+ return ".uuid()";
297
+ case "color-hex":
298
+ return ".regex(/^[a-fA-F0-9]{6}$/)";
299
+ default:
300
+ return "";
301
+ }
302
+ }
303
+
304
+ // src/types/array.ts
305
+ function convertOpenAPIArrayToZod(schema, convertSchema) {
306
+ const item = schema.items;
307
+ let itemZodString = "z.unknown()";
308
+ if (item && typeof item === "object") {
309
+ itemZodString = convertSchema(item);
310
+ }
311
+ let result = `z.array(${itemZodString})`;
312
+ if (typeof schema.minItems === "number") {
313
+ result += `.min(${schema.minItems})`;
314
+ }
315
+ if (typeof schema.maxItems === "number") {
316
+ result += `.max(${schema.maxItems})`;
317
+ }
318
+ return result;
319
+ }
320
+
321
+ // src/types/object.ts
322
+ function convertOpenAPIObjectToZod(schema, convertSchema) {
323
+ const properties = schema.properties || {};
324
+ const propertyNames = Object.keys(properties);
325
+ if (propertyNames.length === 0) {
326
+ if (schema.additionalProperties === false) {
327
+ return "z.object({}).strict()";
328
+ }
329
+ return "z.record(z.string(), z.unknown())";
330
+ }
331
+ const requiredSet = new Set(schema.required || []);
332
+ const entries = [];
333
+ for (const [propName, propSchema] of Object.entries(properties)) {
334
+ let zodProp = "z.unknown()";
335
+ if (propSchema && typeof propSchema === "object") {
336
+ zodProp = convertSchema(propSchema);
337
+ }
338
+ if (!requiredSet.has(propName)) {
339
+ zodProp += ".optional()";
340
+ }
341
+ entries.push(`${propName}: ${zodProp}`);
342
+ }
343
+ let result = `z.object({ ${entries.join(", ")} })`;
344
+ if (schema.additionalProperties === false) {
345
+ result += ".strict()";
346
+ }
347
+ return result;
348
+ }
349
+
350
+ // src/types/union.ts
351
+ function convertOpenAPIUnionToZod(schema, convertSchema) {
352
+ const items = schema.oneOf.map((item) => convertSchema(item));
353
+ return `z.union([${items.join(", ")}])`;
354
+ }
355
+
356
+ // src/types/intersection.ts
357
+ function convertOpenAPIIntersectionToZod(schema, convertSchema) {
358
+ const items = schema.allOf.map((item) => convertSchema(item));
359
+ if (schema.allOf.length === 0) return "z.unknown()";
360
+ if (schema.allOf.length === 1) return convertSchema(schema.allOf[0]);
361
+ return `z.intersection(${items.join(", ")})`;
362
+ }
363
+
364
+ // src/to-zod.ts
365
+ function convertSchemaToZodString(schema) {
366
+ if (!schema || typeof schema !== "object") return "z.unknown()";
367
+ if (schema["$ref"] && typeof schema["$ref"] === "string") {
368
+ const match = schema["$ref"].match(
369
+ /#\/components\/schemas\/(.+)/
370
+ );
371
+ let result2 = "z.unknown()";
372
+ if (match && match[1]) {
373
+ result2 = `${match[1]}Schema`;
374
+ }
375
+ if (schema["nullable"] === true) {
376
+ result2 = `z.union([${result2}, z.null()])`;
377
+ }
378
+ return result2;
379
+ }
380
+ let result = "z.unknown()";
381
+ if ("oneOf" in schema && Array.isArray(schema["oneOf"])) {
382
+ result = convertOpenAPIUnionToZod(
383
+ schema,
384
+ convertSchemaToZodString
385
+ );
386
+ } else if ("allOf" in schema && Array.isArray(schema["allOf"])) {
387
+ result = convertOpenAPIIntersectionToZod(
388
+ schema,
389
+ convertSchemaToZodString
390
+ );
391
+ } else {
392
+ switch (schema["type"]) {
393
+ case "string":
394
+ result = convertOpenAPIStringToZod({
395
+ enum: schema["enum"],
396
+ format: schema["format"],
397
+ maxLength: schema["maxLength"],
398
+ minLength: schema["minLength"],
399
+ pattern: schema["pattern"],
400
+ type: "string"
401
+ });
402
+ break;
403
+ case "number":
404
+ result = convertOpenAPINumberToZod({
405
+ maximum: schema["maximum"],
406
+ minimum: schema["minimum"],
407
+ type: "number"
408
+ });
409
+ break;
410
+ case "integer":
411
+ result = convertOpenAPINumberToZod({
412
+ maximum: schema["maximum"],
413
+ minimum: schema["minimum"],
414
+ type: "integer"
415
+ });
416
+ break;
417
+ case "boolean":
418
+ result = convertOpenAPIBooleanToZod({ type: "boolean" });
419
+ break;
420
+ case "array":
421
+ result = convertOpenAPIArrayToZod(
422
+ {
423
+ items: schema["items"],
424
+ maxItems: schema["maxItems"],
425
+ minItems: schema["minItems"],
426
+ type: "array"
427
+ },
428
+ convertSchemaToZodString
429
+ );
430
+ break;
431
+ case "object":
432
+ result = convertOpenAPIObjectToZod(
433
+ {
434
+ additionalProperties: schema["additionalProperties"],
435
+ properties: schema["properties"],
436
+ required: schema["required"],
437
+ type: "object"
438
+ },
439
+ convertSchemaToZodString
440
+ );
441
+ break;
442
+ default:
443
+ if (schema["properties"]) {
444
+ result = convertOpenAPIObjectToZod(
445
+ {
446
+ additionalProperties: schema["additionalProperties"],
447
+ properties: schema["properties"],
448
+ required: schema["required"],
449
+ type: "object"
450
+ },
451
+ convertSchemaToZodString
452
+ );
453
+ } else {
454
+ result = "z.unknown()";
455
+ }
456
+ break;
457
+ }
458
+ }
459
+ if (schema["nullable"] === true) {
460
+ result = `z.union([${result}, z.null()])`;
461
+ }
462
+ return result;
463
+ }
464
+
465
+ // src/routes.ts
466
+ function toUpperCaseMethod(method) {
467
+ const upper = method.toUpperCase();
468
+ if (upper === "GET" || upper === "POST" || upper === "PUT" || upper === "PATCH" || upper === "DELETE" || upper === "HEAD" || upper === "OPTIONS") {
469
+ return upper;
470
+ }
471
+ return "GET";
472
+ }
473
+ function toPascalCase(str) {
474
+ return str.replace(/[^a-zA-Z0-9]/g, " ").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
475
+ }
476
+ function generateRouteSchemaName(path, method, suffix) {
477
+ const pathParts = path.split("/").filter((p) => p).map((p) => {
478
+ if (p.startsWith("{") && p.endsWith("}")) {
479
+ return p.slice(1, -1);
480
+ }
481
+ return p;
482
+ }).map(toPascalCase);
483
+ const methodPrefix = method.charAt(0) + method.slice(1).toLowerCase();
484
+ const parts = [methodPrefix, ...pathParts, suffix];
485
+ return parts.join("");
486
+ }
487
+ function parseOpenApiPaths(openapi) {
488
+ const paths = openapi["paths"];
489
+ if (!paths) {
490
+ return [];
491
+ }
492
+ const routes = [];
493
+ for (const [path, pathItem] of Object.entries(paths)) {
494
+ if (!pathItem || typeof pathItem !== "object") continue;
495
+ const methods = [
496
+ "get",
497
+ "post",
498
+ "put",
499
+ "patch",
500
+ "delete",
501
+ "head",
502
+ "options"
503
+ ];
504
+ for (const method of methods) {
505
+ const operation = pathItem[method];
506
+ if (!operation) continue;
507
+ const parameters = [];
508
+ const responses = {};
509
+ if (Array.isArray(pathItem["parameters"])) {
510
+ for (const param of pathItem["parameters"]) {
511
+ if (param && typeof param === "object") {
512
+ parameters.push({
513
+ name: String(param["name"] || ""),
514
+ in: param["in"] || "query",
515
+ required: Boolean(param["required"]),
516
+ schema: param["schema"] || {}
517
+ });
518
+ }
519
+ }
520
+ }
521
+ if (Array.isArray(operation["parameters"])) {
522
+ for (const param of operation["parameters"]) {
523
+ if (param && typeof param === "object") {
524
+ parameters.push({
525
+ name: String(param["name"] || ""),
526
+ in: param["in"] || "query",
527
+ required: Boolean(param["required"]),
528
+ schema: param["schema"] || {}
529
+ });
530
+ }
531
+ }
532
+ }
533
+ let requestBody;
534
+ if (operation["requestBody"]) {
535
+ const rb = operation["requestBody"];
536
+ if (rb && typeof rb === "object") {
537
+ const content = rb["content"];
538
+ if (content && typeof content === "object") {
539
+ const jsonContent = content["application/json"];
540
+ if (jsonContent && typeof jsonContent === "object") {
541
+ requestBody = jsonContent["schema"] || {};
542
+ }
543
+ }
544
+ }
545
+ }
546
+ if (operation["responses"] && typeof operation["responses"] === "object") {
547
+ for (const [statusCode, response] of Object.entries(
548
+ operation["responses"]
549
+ )) {
550
+ if (response && typeof response === "object") {
551
+ const responseSchema = response;
552
+ const content = responseSchema["content"];
553
+ if (content && typeof content === "object") {
554
+ const jsonContent = content["application/json"];
555
+ if (jsonContent && typeof jsonContent === "object") {
556
+ const schema = jsonContent["schema"];
557
+ if (schema) {
558
+ responses[statusCode] = schema;
559
+ }
560
+ }
561
+ }
562
+ }
563
+ }
564
+ }
565
+ routes.push({
566
+ path,
567
+ method: toUpperCaseMethod(method),
568
+ parameters,
569
+ requestBody,
570
+ responses
571
+ });
572
+ }
573
+ }
574
+ return routes;
575
+ }
576
+ function generateRouteSchemaNames(route) {
577
+ const pathParams = route.parameters.filter((p) => p.in === "path");
578
+ const queryParams = route.parameters.filter((p) => p.in === "query");
579
+ const headerParams = route.parameters.filter((p) => p.in === "header");
580
+ const successStatuses = Object.keys(route.responses).filter(
581
+ (s) => s.startsWith("2")
582
+ );
583
+ const result = {
584
+ responseSchemaName: successStatuses.length > 0 ? generateRouteSchemaName(
585
+ route.path,
586
+ route.method,
587
+ "Response"
588
+ ) : void 0
589
+ };
590
+ if (pathParams.length > 0) {
591
+ result.paramsSchemaName = generateRouteSchemaName(
592
+ route.path,
593
+ route.method,
594
+ "Params"
595
+ );
596
+ }
597
+ if (queryParams.length > 0) {
598
+ result.querySchemaName = generateRouteSchemaName(
599
+ route.path,
600
+ route.method,
601
+ "Query"
602
+ );
603
+ }
604
+ if (headerParams.length > 0) {
605
+ result.headersSchemaName = generateRouteSchemaName(
606
+ route.path,
607
+ route.method,
608
+ "Headers"
609
+ );
610
+ }
611
+ if (route.requestBody) {
612
+ result.bodySchemaName = generateRouteSchemaName(
613
+ route.path,
614
+ route.method,
615
+ "Body"
616
+ );
617
+ }
618
+ return result;
619
+ }
620
+
621
+ // src/to-typescript.ts
622
+ function generateRouteSchemaName2(path, method, suffix) {
623
+ const pathParts = path.split("/").filter((p) => p).map((p) => {
624
+ if (p.startsWith("{") && p.endsWith("}")) {
625
+ return p.slice(1, -1);
626
+ }
627
+ return p;
628
+ }).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
629
+ const methodPrefix = method.charAt(0) + method.slice(1).toLowerCase();
630
+ const parts = [methodPrefix, ...pathParts, suffix];
631
+ return parts.join("");
632
+ }
633
+ function generateRouteSchemas(routes, convertSchema) {
634
+ const lines = [];
635
+ const schemaNames = /* @__PURE__ */ new Set();
636
+ for (const route of routes) {
637
+ const names = generateRouteSchemaNames(route);
638
+ const pathParams = route.parameters.filter((p) => p.in === "path");
639
+ const queryParams = route.parameters.filter((p) => p.in === "query");
640
+ const headerParams = route.parameters.filter((p) => p.in === "header");
641
+ if (names.paramsSchemaName && pathParams.length > 0) {
642
+ if (!schemaNames.has(names.paramsSchemaName)) {
643
+ schemaNames.add(names.paramsSchemaName);
644
+ const properties = [];
645
+ const required = [];
646
+ for (const param of pathParams) {
647
+ const zodExpr = convertSchema(param.schema);
648
+ properties.push(`${param.name}: ${zodExpr}`);
649
+ if (param.required) {
650
+ required.push(param.name);
651
+ }
652
+ }
653
+ lines.push(
654
+ `export const ${names.paramsSchemaName} = z.object({ ${properties.join(", ")} });`
655
+ );
656
+ }
657
+ }
658
+ if (names.querySchemaName && queryParams.length > 0) {
659
+ if (!schemaNames.has(names.querySchemaName)) {
660
+ schemaNames.add(names.querySchemaName);
661
+ const properties = [];
662
+ for (const param of queryParams) {
663
+ let zodExpr = convertSchema(param.schema);
664
+ if (!param.required) {
665
+ zodExpr += ".optional()";
666
+ }
667
+ properties.push(`${param.name}: ${zodExpr}`);
668
+ }
669
+ lines.push(
670
+ `export const ${names.querySchemaName} = z.object({ ${properties.join(", ")} });`
671
+ );
672
+ }
673
+ }
674
+ if (names.headersSchemaName && headerParams.length > 0) {
675
+ if (!schemaNames.has(names.headersSchemaName)) {
676
+ schemaNames.add(names.headersSchemaName);
677
+ const properties = [];
678
+ for (const param of headerParams) {
679
+ let zodExpr = convertSchema(param.schema);
680
+ if (!param.required) {
681
+ zodExpr += ".optional()";
682
+ }
683
+ properties.push(`${param.name}: ${zodExpr}`);
684
+ }
685
+ lines.push(
686
+ `export const ${names.headersSchemaName} = z.object({ ${properties.join(", ")} });`
687
+ );
688
+ }
689
+ }
690
+ if (names.bodySchemaName && route.requestBody) {
691
+ if (!schemaNames.has(names.bodySchemaName)) {
692
+ schemaNames.add(names.bodySchemaName);
693
+ const zodExpr = convertSchema(route.requestBody);
694
+ lines.push(`export const ${names.bodySchemaName} = ${zodExpr};`);
695
+ }
696
+ }
697
+ for (const [statusCode, responseSchema] of Object.entries(
698
+ route.responses
699
+ )) {
700
+ if (!responseSchema) continue;
701
+ const isSuccess = statusCode.startsWith("2");
702
+ const suffix = isSuccess ? `${statusCode}Response` : `${statusCode}ErrorResponse`;
703
+ const responseSchemaName = generateRouteSchemaName2(
704
+ route.path,
705
+ route.method,
706
+ suffix
707
+ );
708
+ if (!schemaNames.has(responseSchemaName)) {
709
+ schemaNames.add(responseSchemaName);
710
+ const zodExpr = convertSchema(responseSchema);
711
+ lines.push(`export const ${responseSchemaName} = ${zodExpr};`);
712
+ }
713
+ }
714
+ }
715
+ return lines;
716
+ }
717
+ function generateRequestResponseObjects(routes) {
718
+ const lines = [];
719
+ const requestPaths = {};
720
+ const responsePaths = {};
721
+ for (const route of routes) {
722
+ const names = generateRouteSchemaNames(route);
723
+ const pathParams = route.parameters.filter((p) => p.in === "path");
724
+ const queryParams = route.parameters.filter((p) => p.in === "query");
725
+ const headerParams = route.parameters.filter((p) => p.in === "header");
726
+ if (!requestPaths[route.path]) {
727
+ requestPaths[route.path] = {};
728
+ }
729
+ const requestMethodObj = requestPaths[route.path];
730
+ if (!requestMethodObj[route.method]) {
731
+ requestMethodObj[route.method] = [];
732
+ }
733
+ const requestParts = [];
734
+ if (names.paramsSchemaName && pathParams.length > 0) {
735
+ requestParts.push(`params: ${names.paramsSchemaName}`);
736
+ }
737
+ if (names.querySchemaName && queryParams.length > 0) {
738
+ requestParts.push(`query: ${names.querySchemaName}`);
739
+ }
740
+ if (names.headersSchemaName && headerParams.length > 0) {
741
+ requestParts.push(`headers: ${names.headersSchemaName}`);
742
+ }
743
+ if (names.bodySchemaName && route.requestBody) {
744
+ requestParts.push(`body: ${names.bodySchemaName}`);
745
+ }
746
+ if (requestParts.length > 0) {
747
+ requestMethodObj[route.method] = requestParts;
748
+ }
749
+ if (!responsePaths[route.path]) {
750
+ responsePaths[route.path] = {};
751
+ }
752
+ const responseMethodObj = responsePaths[route.path];
753
+ if (!responseMethodObj[route.method]) {
754
+ responseMethodObj[route.method] = {};
755
+ }
756
+ for (const [statusCode, responseSchema] of Object.entries(
757
+ route.responses
758
+ )) {
759
+ if (!responseSchema) continue;
760
+ const isSuccess = statusCode.startsWith("2");
761
+ const suffix = isSuccess ? `${statusCode}Response` : `${statusCode}ErrorResponse`;
762
+ const responseSchemaName = generateRouteSchemaName2(
763
+ route.path,
764
+ route.method,
765
+ suffix
766
+ );
767
+ responseMethodObj[route.method][statusCode] = responseSchemaName;
768
+ }
769
+ }
770
+ lines.push("export const Request = {");
771
+ for (const [path, methods] of Object.entries(requestPaths)) {
772
+ const methodEntries = Object.entries(methods).filter(
773
+ ([, parts]) => parts.length > 0
774
+ );
775
+ if (methodEntries.length > 0) {
776
+ lines.push(` '${path}': {`);
777
+ for (const [method, parts] of methodEntries) {
778
+ lines.push(` ${method}: {`);
779
+ for (const part of parts) {
780
+ lines.push(` ${part},`);
781
+ }
782
+ lines.push(` },`);
783
+ }
784
+ lines.push(` },`);
785
+ }
786
+ }
787
+ lines.push("} as const;");
788
+ lines.push("");
789
+ lines.push("export const Response = {");
790
+ for (const [path, methods] of Object.entries(responsePaths)) {
791
+ const methodEntries = Object.entries(methods);
792
+ if (methodEntries.length > 0) {
793
+ lines.push(` '${path}': {`);
794
+ for (const [method, statusCodes] of methodEntries) {
795
+ lines.push(` ${method}: {`);
796
+ for (const [statusCode, schemaName] of Object.entries(statusCodes)) {
797
+ lines.push(` '${statusCode}': ${schemaName},`);
798
+ }
799
+ lines.push(` },`);
800
+ }
801
+ lines.push(` },`);
802
+ }
803
+ }
804
+ lines.push("} as const;");
805
+ return lines;
806
+ }
807
+ var openApiToZodTsCode = (openapi, customImportLines, options) => {
808
+ const components = openapi["components"];
809
+ const schemas = components?.["schemas"] ?? {};
810
+ const lines = [];
811
+ lines.push("/**");
812
+ lines.push(" * This file was automatically generated from OpenAPI schema");
813
+ lines.push(" * Do not manually edit this file");
814
+ lines.push(" */");
815
+ lines.push("");
816
+ lines.push("import { z } from 'zod';");
817
+ lines.push(...customImportLines ?? []);
818
+ lines.push("");
819
+ const sortedSchemaNames = topologicalSortSchemas(schemas);
820
+ for (const name of sortedSchemaNames) {
821
+ const schema = schemas[name];
822
+ if (schema) {
823
+ const zodExpr = convertSchemaToZodString(schema);
824
+ const schemaName = `${name}Schema`;
825
+ const typeName = name;
826
+ lines.push(`export const ${schemaName} = ${zodExpr};`);
827
+ lines.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);
828
+ lines.push("");
829
+ }
830
+ }
831
+ if (options?.includeRoutes) {
832
+ const routes = parseOpenApiPaths(openapi);
833
+ if (routes.length > 0) {
834
+ const routeSchemas = generateRouteSchemas(
835
+ routes,
836
+ convertSchemaToZodString
837
+ );
838
+ if (routeSchemas.length > 0) {
839
+ lines.push(...routeSchemas);
840
+ lines.push("");
841
+ const requestResponseObjs = generateRequestResponseObjects(routes);
842
+ lines.push(...requestResponseObjs);
843
+ }
844
+ }
845
+ }
846
+ return lines.join("\n");
847
+ };
848
+ // Annotate the CommonJS export names for ESM import in node:
849
+ 0 && (module.exports = {
850
+ SUPPORTED_STRING_FORMATS,
851
+ clearZodSchemaToOpenApiSchemaRegistry,
852
+ convertSchemaToZodString,
853
+ generateRouteSchemaNames,
854
+ getSchemaExportedVariableNameForStringFormat,
855
+ openApiToZodTsCode,
856
+ parseOpenApiPaths,
857
+ registerZodSchemaToOpenApiSchema,
858
+ schemaRegistry
859
+ });
860
+ //# sourceMappingURL=index.js.map