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