zenko 0.1.10-beta.1 → 0.1.10-beta.2

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/cli.cjs CHANGED
@@ -26,7 +26,1557 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  // src/cli.ts
27
27
  var path2 = __toESM(require("path"), 1);
28
28
  var import_promises = require("fs/promises");
29
- var import_core = require("@zenko/core");
29
+
30
+ // ../zenko-core/src/utils/topological-sort.ts
31
+ function topologicalSort(schemas) {
32
+ const visited = /* @__PURE__ */ new Set();
33
+ const visiting = /* @__PURE__ */ new Set();
34
+ const result = [];
35
+ const visit = (name) => {
36
+ if (visited.has(name)) return;
37
+ if (visiting.has(name)) {
38
+ return;
39
+ }
40
+ visiting.add(name);
41
+ const schema = schemas[name];
42
+ const dependencies = extractDependencies(schema);
43
+ for (const dep of dependencies) {
44
+ if (schemas[dep]) {
45
+ visit(dep);
46
+ }
47
+ }
48
+ visiting.delete(name);
49
+ visited.add(name);
50
+ result.push(name);
51
+ };
52
+ for (const name of Object.keys(schemas)) {
53
+ visit(name);
54
+ }
55
+ return result;
56
+ }
57
+ function extractDependencies(schema) {
58
+ const dependencies = [];
59
+ const traverse = (obj) => {
60
+ if (typeof obj !== "object" || obj === null) return;
61
+ if (obj.$ref && typeof obj.$ref === "string") {
62
+ const refName = extractRefName(obj.$ref);
63
+ dependencies.push(refName);
64
+ return;
65
+ }
66
+ if (Array.isArray(obj)) {
67
+ obj.forEach(traverse);
68
+ } else {
69
+ Object.values(obj).forEach(traverse);
70
+ }
71
+ };
72
+ traverse(schema);
73
+ return [...new Set(dependencies)];
74
+ }
75
+ function extractRefName(ref) {
76
+ return ref.split("/").pop() || "Unknown";
77
+ }
78
+
79
+ // ../zenko-core/src/utils/property-name.ts
80
+ function isValidJSIdentifier(name) {
81
+ if (!name) return false;
82
+ const firstChar = name.at(0);
83
+ if (firstChar === void 0) return false;
84
+ if (!/[a-zA-Z_$]/.test(firstChar)) return false;
85
+ if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)) return false;
86
+ const reservedWords = /* @__PURE__ */ new Set([
87
+ "abstract",
88
+ "arguments",
89
+ "await",
90
+ "boolean",
91
+ "break",
92
+ "byte",
93
+ "case",
94
+ "catch",
95
+ "char",
96
+ "class",
97
+ "const",
98
+ "continue",
99
+ "debugger",
100
+ "default",
101
+ "delete",
102
+ "do",
103
+ "double",
104
+ "else",
105
+ "enum",
106
+ "eval",
107
+ "export",
108
+ "extends",
109
+ "false",
110
+ "final",
111
+ "finally",
112
+ "float",
113
+ "for",
114
+ "function",
115
+ "goto",
116
+ "if",
117
+ "implements",
118
+ "import",
119
+ "in",
120
+ "instanceof",
121
+ "int",
122
+ "interface",
123
+ "let",
124
+ "long",
125
+ "native",
126
+ "new",
127
+ "null",
128
+ "package",
129
+ "private",
130
+ "protected",
131
+ "public",
132
+ "return",
133
+ "short",
134
+ "static",
135
+ "super",
136
+ "switch",
137
+ "synchronized",
138
+ "this",
139
+ "throw",
140
+ "throws",
141
+ "transient",
142
+ "true",
143
+ "try",
144
+ "typeof",
145
+ "var",
146
+ "void",
147
+ "volatile",
148
+ "while",
149
+ "with",
150
+ "yield",
151
+ "async"
152
+ ]);
153
+ return !reservedWords.has(name);
154
+ }
155
+ function formatPropertyName(name) {
156
+ return isValidJSIdentifier(name) ? name : `"${name}"`;
157
+ }
158
+
159
+ // ../zenko-core/src/utils/string-utils.ts
160
+ function toCamelCase(str) {
161
+ return str.replace(/-([a-zA-Z])/g, (_, letter) => letter.toUpperCase()).replace(/-+$/, "");
162
+ }
163
+ function capitalize(str) {
164
+ return str.charAt(0).toUpperCase() + str.slice(1);
165
+ }
166
+
167
+ // ../zenko-core/src/utils/http-status.ts
168
+ var statusNameMap = {
169
+ "400": "badRequest",
170
+ "401": "unauthorized",
171
+ "402": "paymentRequired",
172
+ "403": "forbidden",
173
+ "404": "notFound",
174
+ "405": "methodNotAllowed",
175
+ "406": "notAcceptable",
176
+ "407": "proxyAuthenticationRequired",
177
+ "408": "requestTimeout",
178
+ "409": "conflict",
179
+ "410": "gone",
180
+ "411": "lengthRequired",
181
+ "412": "preconditionFailed",
182
+ "413": "payloadTooLarge",
183
+ "414": "uriTooLong",
184
+ "415": "unsupportedMediaType",
185
+ "416": "rangeNotSatisfiable",
186
+ "417": "expectationFailed",
187
+ "418": "imATeapot",
188
+ "421": "misdirectedRequest",
189
+ "422": "unprocessableEntity",
190
+ "423": "locked",
191
+ "424": "failedDependency",
192
+ "425": "tooEarly",
193
+ "426": "upgradeRequired",
194
+ "428": "preconditionRequired",
195
+ "429": "tooManyRequests",
196
+ "431": "requestHeaderFieldsTooLarge",
197
+ "451": "unavailableForLegalReasons",
198
+ "500": "internalServerError",
199
+ "501": "notImplemented",
200
+ "502": "badGateway",
201
+ "503": "serviceUnavailable",
202
+ "504": "gatewayTimeout",
203
+ "505": "httpVersionNotSupported",
204
+ "506": "variantAlsoNegotiates",
205
+ "507": "insufficientStorage",
206
+ "508": "loopDetected",
207
+ "510": "notExtended",
208
+ "511": "networkAuthenticationRequired"
209
+ };
210
+ function mapStatusToIdentifier(status) {
211
+ if (status === "default") return "defaultError";
212
+ const trimmed = status.trim();
213
+ const mapped = statusNameMap[trimmed];
214
+ if (mapped) return mapped;
215
+ if (/^\d{3}$/.test(trimmed)) {
216
+ return `status${trimmed}`;
217
+ }
218
+ const sanitized = trimmed.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
219
+ if (!sanitized) return "unknownError";
220
+ const parts = sanitized.split(/\s+/);
221
+ const [first, ...rest] = parts;
222
+ const candidate = first + rest.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("");
223
+ if (!candidate) return "unknownError";
224
+ return /^[a-zA-Z_$]/.test(candidate) ? candidate : `status${candidate.charAt(0).toUpperCase()}${candidate.slice(1)}`;
225
+ }
226
+ function isErrorStatus(status) {
227
+ if (status === "default") return true;
228
+ const code = Number(status);
229
+ if (!Number.isInteger(code)) return false;
230
+ return code >= 400;
231
+ }
232
+
233
+ // ../zenko-core/src/utils/tree-shaking.ts
234
+ function analyzeZenkoUsage(operations) {
235
+ const usage = {
236
+ usesHeaderFn: false,
237
+ usesOperationDefinition: false,
238
+ usesOperationErrors: false
239
+ };
240
+ if (operations.length > 0) {
241
+ usage.usesOperationDefinition = true;
242
+ }
243
+ for (const op of operations) {
244
+ if (op.errors && hasAnyErrors(op.errors)) {
245
+ usage.usesOperationErrors = true;
246
+ }
247
+ }
248
+ if (operations.length > 0 && !usage.usesOperationErrors) {
249
+ const hasDefaultErrors = operations.some(
250
+ (op) => !op.errors || !hasAnyErrors(op.errors)
251
+ );
252
+ if (hasDefaultErrors) {
253
+ usage.usesOperationErrors = true;
254
+ }
255
+ }
256
+ return usage;
257
+ }
258
+ function generateZenkoImport(usage, mode, helpersOutput) {
259
+ const types = [];
260
+ if (usage.usesHeaderFn) types.push("HeaderFn");
261
+ if (usage.usesOperationDefinition) types.push("OperationDefinition");
262
+ if (usage.usesOperationErrors) types.push("OperationErrors");
263
+ if (types.length === 0) {
264
+ return "";
265
+ }
266
+ const importSource = mode === "package" ? '"zenko"' : `"${helpersOutput}"`;
267
+ return `import type { ${types.join(", ")} } from ${importSource};`;
268
+ }
269
+ function hasAnyErrors(errors) {
270
+ return Boolean(errors && Object.keys(errors).length > 0);
271
+ }
272
+
273
+ // ../zenko-core/src/utils/collect-inline-types.ts
274
+ function collectInlineRequestTypes(operations, spec) {
275
+ const requestTypesToGenerate = /* @__PURE__ */ new Map();
276
+ const operationLookup = /* @__PURE__ */ new Map();
277
+ for (const [, pathItem] of Object.entries(spec.paths || {})) {
278
+ for (const [, operation] of Object.entries(pathItem)) {
279
+ const op = operation;
280
+ if (op.operationId) {
281
+ operationLookup.set(op.operationId, op);
282
+ }
283
+ }
284
+ }
285
+ for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
286
+ for (const [, operation] of Object.entries(pathItem)) {
287
+ const op = operation;
288
+ if (op.operationId) {
289
+ operationLookup.set(op.operationId, op);
290
+ }
291
+ }
292
+ }
293
+ for (const op of operations) {
294
+ const operation = operationLookup.get(op.operationId);
295
+ if (!operation) continue;
296
+ const requestBody = operation.requestBody;
297
+ if (requestBody && requestBody.content) {
298
+ const content = requestBody.content;
299
+ const jsonContent = content["application/json"];
300
+ if (jsonContent && jsonContent.schema) {
301
+ const schema = jsonContent.schema;
302
+ const typeName = `${capitalize(toCamelCase(op.operationId))}Request`;
303
+ if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
304
+ requestTypesToGenerate.set(typeName, schema);
305
+ }
306
+ }
307
+ }
308
+ }
309
+ return requestTypesToGenerate;
310
+ }
311
+ function collectInlineResponseTypes(operations, spec) {
312
+ const responseTypesToGenerate = /* @__PURE__ */ new Map();
313
+ const operationLookup = /* @__PURE__ */ new Map();
314
+ for (const [, pathItem] of Object.entries(spec.paths || {})) {
315
+ for (const [, operation] of Object.entries(pathItem)) {
316
+ const op = operation;
317
+ if (op.operationId) {
318
+ operationLookup.set(op.operationId, op);
319
+ }
320
+ }
321
+ }
322
+ for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
323
+ for (const [, operation] of Object.entries(pathItem)) {
324
+ const op = operation;
325
+ if (op.operationId) {
326
+ operationLookup.set(op.operationId, op);
327
+ }
328
+ }
329
+ }
330
+ for (const op of operations) {
331
+ const operation = operationLookup.get(op.operationId);
332
+ if (!operation) continue;
333
+ const responses = operation.responses || {};
334
+ for (const [statusCode, response] of Object.entries(responses)) {
335
+ if (/^2\d\d$/.test(statusCode) && response.content) {
336
+ const content = response.content;
337
+ const jsonContent = content["application/json"];
338
+ if (jsonContent && jsonContent.schema) {
339
+ const schema = jsonContent.schema;
340
+ const typeName = `${capitalize(toCamelCase(op.operationId))}Response`;
341
+ if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
342
+ responseTypesToGenerate.set(typeName, schema);
343
+ }
344
+ }
345
+ }
346
+ }
347
+ }
348
+ return responseTypesToGenerate;
349
+ }
350
+ function collectInlineErrorTypes(operations, spec) {
351
+ const errorTypesToGenerate = /* @__PURE__ */ new Map();
352
+ const operationLookup = /* @__PURE__ */ new Map();
353
+ for (const [, pathItem] of Object.entries(spec.paths || {})) {
354
+ for (const [, operation] of Object.entries(pathItem)) {
355
+ const op = operation;
356
+ if (op.operationId) {
357
+ operationLookup.set(op.operationId, op);
358
+ }
359
+ }
360
+ }
361
+ for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
362
+ for (const [, operation] of Object.entries(pathItem)) {
363
+ const op = operation;
364
+ if (op.operationId) {
365
+ operationLookup.set(op.operationId, op);
366
+ }
367
+ }
368
+ }
369
+ for (const op of operations) {
370
+ const operation = operationLookup.get(op.operationId);
371
+ if (!operation) continue;
372
+ const responses = operation.responses || {};
373
+ for (const [statusCode, response] of Object.entries(responses)) {
374
+ if (isErrorStatus(statusCode) && response.content) {
375
+ const content = response.content;
376
+ const jsonContent = content["application/json"];
377
+ if (jsonContent && jsonContent.schema) {
378
+ const schema = jsonContent.schema;
379
+ const identifier = mapStatusToIdentifier(statusCode);
380
+ const typeName = `${capitalize(toCamelCase(op.operationId))}${capitalize(identifier)}`;
381
+ if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
382
+ errorTypesToGenerate.set(typeName, schema);
383
+ }
384
+ }
385
+ }
386
+ }
387
+ }
388
+ return errorTypesToGenerate;
389
+ }
390
+
391
+ // ../zenko-core/src/utils/collect-referenced-schemas.ts
392
+ function findContentType(content) {
393
+ const contentTypes = Object.keys(content);
394
+ if (contentTypes.includes("application/json")) {
395
+ return "application/json";
396
+ }
397
+ const CONTENT_TYPE_MAP2 = {
398
+ "application/json": "unknown",
399
+ "text/csv": "string",
400
+ "text/plain": "string",
401
+ "application/octet-stream": "unknown",
402
+ "application/pdf": "unknown"
403
+ };
404
+ for (const contentType of contentTypes) {
405
+ if (contentType in CONTENT_TYPE_MAP2) {
406
+ return contentType;
407
+ }
408
+ }
409
+ return contentTypes[0] || "";
410
+ }
411
+ function resolveParameter(parameter, spec) {
412
+ if (!parameter) return void 0;
413
+ if (parameter.$ref) {
414
+ const refName = extractRefName(parameter.$ref);
415
+ const resolved = spec.components?.parameters?.[refName];
416
+ if (!resolved) return void 0;
417
+ const { $ref, ...overrides } = parameter;
418
+ return {
419
+ ...resolved,
420
+ ...overrides
421
+ };
422
+ }
423
+ return parameter;
424
+ }
425
+ function collectReferencedSchemas(operations, spec) {
426
+ const referenced = /* @__PURE__ */ new Set();
427
+ const operationLookup = /* @__PURE__ */ new Map();
428
+ for (const [, pathItem] of Object.entries(spec.paths || {})) {
429
+ for (const [, operation] of Object.entries(pathItem)) {
430
+ const op = operation;
431
+ if (op.operationId) {
432
+ operationLookup.set(op.operationId, op);
433
+ }
434
+ }
435
+ }
436
+ for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
437
+ for (const [, operation] of Object.entries(pathItem)) {
438
+ const op = operation;
439
+ if (op.operationId) {
440
+ operationLookup.set(op.operationId, op);
441
+ }
442
+ }
443
+ }
444
+ for (const op of operations) {
445
+ const rawOperation = operationLookup.get(op.operationId);
446
+ if (!rawOperation) continue;
447
+ const requestBody = rawOperation.requestBody?.content?.["application/json"]?.schema;
448
+ if (requestBody?.$ref) {
449
+ const refName = extractRefName(requestBody.$ref);
450
+ referenced.add(refName);
451
+ } else if (requestBody) {
452
+ const deps = extractDependencies(requestBody);
453
+ for (const dep of deps) {
454
+ if (spec.components?.schemas?.[dep]) {
455
+ referenced.add(dep);
456
+ }
457
+ }
458
+ }
459
+ const responses = rawOperation.responses || {};
460
+ for (const [, response] of Object.entries(responses)) {
461
+ const content = response?.content;
462
+ if (!content) continue;
463
+ const contentType = findContentType(content);
464
+ const responseSchema = content[contentType]?.schema;
465
+ if (responseSchema?.$ref) {
466
+ const refName = extractRefName(responseSchema.$ref);
467
+ referenced.add(refName);
468
+ } else if (responseSchema) {
469
+ const deps = extractDependencies(responseSchema);
470
+ for (const dep of deps) {
471
+ if (spec.components?.schemas?.[dep]) {
472
+ referenced.add(dep);
473
+ }
474
+ }
475
+ }
476
+ }
477
+ for (const param of op.queryParams) {
478
+ if (param.schema?.$ref) {
479
+ const refName = extractRefName(param.schema.$ref);
480
+ referenced.add(refName);
481
+ }
482
+ if (param.schema?.items?.$ref) {
483
+ const refName = extractRefName(param.schema.items.$ref);
484
+ referenced.add(refName);
485
+ }
486
+ }
487
+ for (const header of op.requestHeaders || []) {
488
+ if (header.schema?.$ref) {
489
+ const refName = extractRefName(header.schema.$ref);
490
+ referenced.add(refName);
491
+ }
492
+ if (header.schema?.items?.$ref) {
493
+ const refName = extractRefName(header.schema.items.$ref);
494
+ referenced.add(refName);
495
+ }
496
+ }
497
+ const parameters = rawOperation.parameters || [];
498
+ for (const param of parameters) {
499
+ const resolvedParam = resolveParameter(param, spec);
500
+ if (resolvedParam?.schema?.$ref) {
501
+ const refName = extractRefName(resolvedParam.schema.$ref);
502
+ referenced.add(refName);
503
+ }
504
+ if (resolvedParam?.schema?.items?.$ref) {
505
+ const refName = extractRefName(resolvedParam.schema.items.$ref);
506
+ referenced.add(refName);
507
+ }
508
+ }
509
+ }
510
+ const visited = /* @__PURE__ */ new Set();
511
+ const toVisit = Array.from(referenced);
512
+ while (toVisit.length > 0) {
513
+ const schemaName = toVisit.pop();
514
+ if (visited.has(schemaName)) continue;
515
+ visited.add(schemaName);
516
+ const schema = spec.components?.schemas?.[schemaName];
517
+ if (!schema) continue;
518
+ const dependencies = extractDependencies(schema);
519
+ for (const dep of dependencies) {
520
+ if (spec.components?.schemas?.[dep] && !visited.has(dep)) {
521
+ referenced.add(dep);
522
+ toVisit.push(dep);
523
+ }
524
+ }
525
+ }
526
+ return referenced;
527
+ }
528
+
529
+ // ../zenko-core/src/utils/generate-helper-file.ts
530
+ function generateHelperFile() {
531
+ const output = [];
532
+ output.push("// Generated helper types for Zenko");
533
+ output.push(
534
+ "// This file provides type definitions for operation objects and path functions"
535
+ );
536
+ output.push("");
537
+ output.push(
538
+ "export type PathFn<TArgs extends unknown[] = []> = (...args: TArgs) => string"
539
+ );
540
+ output.push("");
541
+ output.push(
542
+ 'export type RequestMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"'
543
+ );
544
+ output.push("");
545
+ output.push(
546
+ "export type HeaderFn<TArgs extends unknown[] = [], TResult = Record<string, unknown> | Record<string, never>> = (...args: TArgs) => TResult"
547
+ );
548
+ output.push("");
549
+ output.push(
550
+ "export type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown)"
551
+ );
552
+ output.push("");
553
+ output.push(
554
+ "export type OperationErrors<TError = unknown> = TError extends Record<string, unknown> ? TError : Record<string, TError>;"
555
+ );
556
+ output.push("");
557
+ output.push(
558
+ "export type OperationDefinition<TMethod extends RequestMethod, TPath extends (...args: any[]) => string, TRequest = undefined, TResponse = undefined, THeaders extends AnyHeaderFn | undefined = undefined, TErrors extends OperationErrors | undefined = undefined> = {"
559
+ );
560
+ output.push(" method: TMethod");
561
+ output.push(" path: TPath");
562
+ output.push(" request?: TRequest");
563
+ output.push(" response?: TResponse");
564
+ output.push(" headers?: THeaders");
565
+ output.push(" errors?: TErrors");
566
+ output.push("}");
567
+ output.push("");
568
+ return output.join("\n");
569
+ }
570
+
571
+ // ../zenko-core/src/zenko.ts
572
+ function generateWithMetadata(spec, options = {}) {
573
+ const output = [];
574
+ const generatedTypes = /* @__PURE__ */ new Set();
575
+ const { strictDates = false, strictNumeric = false, operationIds } = options;
576
+ const typesConfig = normalizeTypesConfig(options.types);
577
+ const schemaOptions = {
578
+ strictDates,
579
+ strictNumeric,
580
+ optionalType: typesConfig.optionalType
581
+ };
582
+ output.push('import { z } from "zod";');
583
+ const nameMap = /* @__PURE__ */ new Map();
584
+ if (spec.components?.schemas) {
585
+ for (const name of Object.keys(spec.components.schemas)) {
586
+ nameMap.set(name, toCamelCase(name));
587
+ }
588
+ }
589
+ let operations = parseOperations(spec, nameMap);
590
+ if (operationIds && operationIds.length > 0) {
591
+ const selectedIds = new Set(operationIds);
592
+ operations = operations.filter((op) => selectedIds.has(op.operationId));
593
+ }
594
+ appendHelperTypesImport(output, typesConfig, operations);
595
+ output.push("");
596
+ if (spec.components?.schemas) {
597
+ output.push("// Generated Zod Schemas");
598
+ output.push("");
599
+ let schemasToGenerate;
600
+ if (operationIds && operationIds.length > 0) {
601
+ const referencedSchemas = collectReferencedSchemas(operations, spec);
602
+ schemasToGenerate = Array.from(referencedSchemas);
603
+ } else {
604
+ schemasToGenerate = Object.keys(spec.components.schemas);
605
+ }
606
+ const sortedSchemas = topologicalSort(spec.components.schemas).filter(
607
+ (name) => schemasToGenerate.includes(name)
608
+ );
609
+ for (const name of sortedSchemas) {
610
+ const schema = spec.components.schemas[name];
611
+ const sanitizedName = nameMap.get(name);
612
+ output.push(
613
+ generateZodSchema(
614
+ sanitizedName,
615
+ schema,
616
+ generatedTypes,
617
+ schemaOptions,
618
+ nameMap
619
+ )
620
+ );
621
+ output.push("");
622
+ output.push(
623
+ `export type ${sanitizedName} = z.infer<typeof ${sanitizedName}>;`
624
+ );
625
+ output.push("");
626
+ }
627
+ }
628
+ output.push("// Path Functions");
629
+ output.push("export const paths = {");
630
+ for (const op of operations) {
631
+ const pathParamNames = op.pathParams.map((p) => p.name);
632
+ const hasPathParams = pathParamNames.length > 0;
633
+ const hasQueryParams = op.queryParams.length > 0;
634
+ const camelCaseOperationId = toCamelCase(op.operationId);
635
+ if (!hasPathParams && !hasQueryParams) {
636
+ output.push(
637
+ ` ${formatPropertyName(camelCaseOperationId)}: () => "${op.path}",`
638
+ );
639
+ continue;
640
+ }
641
+ const alias = (n) => {
642
+ if (isValidJSIdentifier(n)) return n;
643
+ let aliased = toCamelCase(n);
644
+ if (!isValidJSIdentifier(aliased)) {
645
+ aliased = `_${aliased}`;
646
+ }
647
+ return aliased;
648
+ };
649
+ const destructPieces = [];
650
+ const typePieces = [];
651
+ for (const param of op.pathParams) {
652
+ destructPieces.push(
653
+ isValidJSIdentifier(param.name) ? param.name : `${formatPropertyName(param.name)}: ${alias(param.name)}`
654
+ );
655
+ typePieces.push(`${formatPropertyName(param.name)}: string`);
656
+ }
657
+ for (const param of op.queryParams) {
658
+ destructPieces.push(
659
+ isValidJSIdentifier(param.name) ? param.name : `${formatPropertyName(param.name)}: ${alias(param.name)}`
660
+ );
661
+ typePieces.push(
662
+ `${formatPropertyName(param.name)}${param.required ? "" : "?"}: ${mapQueryType(param)}`
663
+ );
664
+ }
665
+ const needsDefaultObject = !hasPathParams && hasQueryParams && op.queryParams.every((param) => !param.required);
666
+ const signatureArgs = destructPieces.length ? `{ ${destructPieces.join(", ")} }` : "{}";
667
+ const signature = `${signatureArgs}: { ${typePieces.join(", ")} }${needsDefaultObject ? " = {}" : ""}`;
668
+ const pathWithParams = op.path.replace(
669
+ /{([^}]+)}/g,
670
+ (_m, n) => `\${${alias(n)}}`
671
+ );
672
+ if (!hasQueryParams) {
673
+ output.push(
674
+ ` ${formatPropertyName(camelCaseOperationId)}: (${signature}) => \`${pathWithParams}\`,`
675
+ );
676
+ continue;
677
+ }
678
+ output.push(
679
+ ` ${formatPropertyName(camelCaseOperationId)}: (${signature}) => {`
680
+ );
681
+ output.push(" const params = new URLSearchParams()");
682
+ for (const param of op.queryParams) {
683
+ const accessor = isValidJSIdentifier(param.name) ? param.name : alias(toCamelCase(param.name));
684
+ const schema = param.schema ?? {};
685
+ if (schema?.type === "array") {
686
+ const itemValueExpression = convertQueryParamValue(
687
+ schema.items ?? {},
688
+ "value"
689
+ );
690
+ if (param.required) {
691
+ output.push(` for (const value of ${accessor}) {`);
692
+ output.push(
693
+ ` params.append("${param.name}", ${itemValueExpression})`
694
+ );
695
+ output.push(" }");
696
+ } else {
697
+ output.push(` if (${accessor} !== undefined) {`);
698
+ output.push(` for (const value of ${accessor}) {`);
699
+ output.push(
700
+ ` params.append("${param.name}", ${itemValueExpression})`
701
+ );
702
+ output.push(" }");
703
+ output.push(" }");
704
+ }
705
+ continue;
706
+ }
707
+ const valueExpression = convertQueryParamValue(schema, accessor);
708
+ if (param.required) {
709
+ output.push(` params.set("${param.name}", ${valueExpression})`);
710
+ } else {
711
+ output.push(` if (${accessor} !== undefined) {`);
712
+ output.push(` params.set("${param.name}", ${valueExpression})`);
713
+ output.push(" }");
714
+ }
715
+ }
716
+ output.push(" const _searchParams = params.toString()");
717
+ output.push(
718
+ ` return \`${pathWithParams}\${_searchParams ? \`?\${_searchParams}\` : ""}\``
719
+ );
720
+ output.push(" },");
721
+ }
722
+ output.push("} as const;");
723
+ output.push("");
724
+ output.push("// Header Schemas");
725
+ output.push("export const headerSchemas = {");
726
+ for (const op of operations) {
727
+ const camelCaseOperationId = toCamelCase(op.operationId);
728
+ if (!op.requestHeaders || op.requestHeaders.length === 0) {
729
+ output.push(
730
+ ` ${formatPropertyName(camelCaseOperationId)}: z.object({}),`
731
+ );
732
+ continue;
733
+ }
734
+ const schemaFields = op.requestHeaders.map((header) => {
735
+ const zodType = mapHeaderToZodType(header);
736
+ const finalType = header.required ? zodType : applyOptionalModifier(zodType, schemaOptions.optionalType);
737
+ return ` ${formatPropertyName(header.name)}: ${finalType},`;
738
+ }).join("\n");
739
+ output.push(` ${formatPropertyName(camelCaseOperationId)}: z.object({`);
740
+ output.push(schemaFields);
741
+ output.push(" }),");
742
+ }
743
+ output.push("} as const;");
744
+ output.push("");
745
+ output.push("// Header Functions");
746
+ output.push("export const headers = {");
747
+ for (const op of operations) {
748
+ const camelCaseOperationId = toCamelCase(op.operationId);
749
+ if (!op.requestHeaders || op.requestHeaders.length === 0) {
750
+ output.push(
751
+ ` ${formatPropertyName(camelCaseOperationId)}: () => ${isValidJSIdentifier(camelCaseOperationId) ? `headerSchemas.${camelCaseOperationId}` : `headerSchemas[${formatPropertyName(camelCaseOperationId)}]`}.parse({}),`
752
+ );
753
+ continue;
754
+ }
755
+ output.push(
756
+ ` ${formatPropertyName(camelCaseOperationId)}: (params: z.input<${isValidJSIdentifier(camelCaseOperationId) ? `typeof headerSchemas.${camelCaseOperationId}` : `(typeof headerSchemas)[${formatPropertyName(camelCaseOperationId)}]`}>) => {`
757
+ );
758
+ output.push(
759
+ ` return ${isValidJSIdentifier(camelCaseOperationId) ? `headerSchemas.${camelCaseOperationId}` : `headerSchemas[${formatPropertyName(camelCaseOperationId)}]`}.parse(params)`
760
+ );
761
+ output.push(" },");
762
+ }
763
+ output.push("} as const;");
764
+ output.push("");
765
+ generateRequestTypes(output, operations, spec, nameMap, schemaOptions);
766
+ generateResponseTypes(output, operations, spec, nameMap, schemaOptions);
767
+ generateOperationTypes(output, operations, typesConfig);
768
+ output.push("// Operation Objects");
769
+ for (const op of operations) {
770
+ const camelCaseOperationId = toCamelCase(op.operationId);
771
+ const typeAnnotation = typesConfig.emit ? `: ${capitalize(camelCaseOperationId)}Operation` : "";
772
+ output.push(`export const ${camelCaseOperationId}${typeAnnotation} = {`);
773
+ output.push(` method: "${op.method}",`);
774
+ output.push(` path: paths.${camelCaseOperationId},`);
775
+ appendOperationField(output, "request", op.requestType);
776
+ appendOperationField(output, "response", op.responseType);
777
+ if (op.requestHeaders && op.requestHeaders.length > 0) {
778
+ output.push(` headers: headers.${camelCaseOperationId},`);
779
+ }
780
+ if (op.errors && hasAnyErrors2(op.errors)) {
781
+ appendErrorGroup(output, "errors", op.errors);
782
+ }
783
+ output.push("} as const;");
784
+ output.push("");
785
+ }
786
+ const result = {
787
+ output: output.join("\n")
788
+ };
789
+ if (typesConfig.emit && typesConfig.helpers === "file" && typesConfig.helpersOutput) {
790
+ result.helperFile = {
791
+ path: typesConfig.helpersOutput,
792
+ content: generateHelperFile()
793
+ };
794
+ }
795
+ return result;
796
+ }
797
+ function generateFromDocument(spec, options = {}) {
798
+ return generateWithMetadata(spec, options);
799
+ }
800
+ function generateRequestTypes(output, operations, spec, nameMap, schemaOptions) {
801
+ const requestTypesToGenerate = collectInlineRequestTypes(operations, spec);
802
+ if (requestTypesToGenerate.size > 0) {
803
+ output.push("// Generated Request Types");
804
+ output.push("");
805
+ for (const [typeName, schema] of requestTypesToGenerate) {
806
+ const generatedSchema = generateZodSchema(
807
+ typeName,
808
+ schema,
809
+ /* @__PURE__ */ new Set(),
810
+ schemaOptions,
811
+ nameMap
812
+ );
813
+ output.push(generatedSchema);
814
+ output.push("");
815
+ output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
816
+ output.push("");
817
+ }
818
+ }
819
+ }
820
+ function generateResponseTypes(output, operations, spec, nameMap, schemaOptions) {
821
+ const responseTypesToGenerate = collectInlineResponseTypes(operations, spec);
822
+ const errorTypesToGenerate = collectInlineErrorTypes(operations, spec);
823
+ if (responseTypesToGenerate.size > 0 || errorTypesToGenerate.size > 0) {
824
+ output.push("// Generated Response Types");
825
+ output.push("");
826
+ for (const [typeName, schema] of responseTypesToGenerate) {
827
+ const generatedSchema = generateZodSchema(
828
+ typeName,
829
+ schema,
830
+ /* @__PURE__ */ new Set(),
831
+ schemaOptions,
832
+ nameMap
833
+ );
834
+ output.push(generatedSchema);
835
+ output.push("");
836
+ output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
837
+ output.push("");
838
+ }
839
+ for (const [typeName, schema] of errorTypesToGenerate) {
840
+ const generatedSchema = generateZodSchema(
841
+ typeName,
842
+ schema,
843
+ /* @__PURE__ */ new Set(),
844
+ schemaOptions,
845
+ nameMap
846
+ );
847
+ output.push(generatedSchema);
848
+ output.push("");
849
+ output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
850
+ output.push("");
851
+ }
852
+ }
853
+ }
854
+ function appendOperationField(buffer, key, value) {
855
+ if (!value) return;
856
+ buffer.push(` ${key}: ${value},`);
857
+ }
858
+ function appendErrorGroup(buffer, label, errors) {
859
+ if (!errors || Object.keys(errors).length === 0) return;
860
+ buffer.push(` ${label}: {`);
861
+ for (const [name, typeName] of Object.entries(errors)) {
862
+ buffer.push(` ${formatPropertyName(name)}: ${typeName},`);
863
+ }
864
+ buffer.push(" },");
865
+ }
866
+ function hasAnyErrors2(group) {
867
+ return Boolean(group && Object.keys(group).length > 0);
868
+ }
869
+ function isRequestMethod(method) {
870
+ switch (method) {
871
+ case "get":
872
+ case "put":
873
+ case "post":
874
+ case "delete":
875
+ case "options":
876
+ case "head":
877
+ case "patch":
878
+ case "trace":
879
+ return true;
880
+ default:
881
+ return false;
882
+ }
883
+ }
884
+ var CONTENT_TYPE_MAP = {
885
+ "application/json": "unknown",
886
+ // Will use schema when available
887
+ "text/csv": "string",
888
+ "text/plain": "string",
889
+ // Binary/ambiguous types default to unknown for cross-platform compatibility
890
+ "application/octet-stream": "unknown",
891
+ "application/pdf": "unknown"
892
+ };
893
+ function findContentType2(content) {
894
+ const contentTypes = Object.keys(content);
895
+ if (contentTypes.includes("application/json")) {
896
+ return "application/json";
897
+ }
898
+ for (const contentType of contentTypes) {
899
+ if (contentType in CONTENT_TYPE_MAP) {
900
+ return contentType;
901
+ }
902
+ }
903
+ return contentTypes[0] || "";
904
+ }
905
+ function inferResponseType(contentType, statusCode) {
906
+ if (statusCode === "204" || /^3\d\d$/.test(statusCode)) {
907
+ return "undefined";
908
+ }
909
+ if (contentType in CONTENT_TYPE_MAP) {
910
+ return CONTENT_TYPE_MAP[contentType];
911
+ }
912
+ return "unknown";
913
+ }
914
+ function parseOperations(spec, nameMap) {
915
+ const operations = [];
916
+ if (spec.paths) {
917
+ for (const [path3, pathItem] of Object.entries(spec.paths)) {
918
+ for (const [method, operation] of Object.entries(pathItem)) {
919
+ const normalizedMethod = method.toLowerCase();
920
+ if (!isRequestMethod(normalizedMethod)) continue;
921
+ if (!operation.operationId) continue;
922
+ const pathParams = extractPathParams(path3);
923
+ const requestType = getRequestType(operation);
924
+ const { successResponse, errors } = getResponseTypes(
925
+ operation,
926
+ operation.operationId,
927
+ nameMap
928
+ );
929
+ const resolvedParameters = collectParameters(pathItem, operation, spec);
930
+ const requestHeaders = getRequestHeaders(resolvedParameters);
931
+ const queryParams = getQueryParams(resolvedParameters);
932
+ operations.push({
933
+ operationId: operation.operationId,
934
+ path: path3,
935
+ method: normalizedMethod,
936
+ pathParams,
937
+ queryParams,
938
+ requestType,
939
+ responseType: successResponse,
940
+ requestHeaders,
941
+ errors
942
+ });
943
+ }
944
+ }
945
+ }
946
+ if (spec.webhooks) {
947
+ for (const [webhookName, webhookItem] of Object.entries(spec.webhooks)) {
948
+ for (const [method, operation] of Object.entries(webhookItem)) {
949
+ const normalizedMethod = method.toLowerCase();
950
+ if (!isRequestMethod(normalizedMethod)) continue;
951
+ if (!operation.operationId) continue;
952
+ const path3 = webhookName;
953
+ const pathParams = extractPathParams(path3);
954
+ const requestType = getRequestType(operation);
955
+ const { successResponse, errors } = getResponseTypes(
956
+ operation,
957
+ operation.operationId
958
+ );
959
+ const resolvedParameters = collectParameters(
960
+ webhookItem,
961
+ operation,
962
+ spec
963
+ );
964
+ const requestHeaders = getRequestHeaders(resolvedParameters);
965
+ const queryParams = getQueryParams(resolvedParameters);
966
+ operations.push({
967
+ operationId: operation.operationId,
968
+ path: path3,
969
+ method: normalizedMethod,
970
+ pathParams,
971
+ queryParams,
972
+ requestType,
973
+ responseType: successResponse,
974
+ requestHeaders,
975
+ errors
976
+ });
977
+ }
978
+ }
979
+ }
980
+ return operations;
981
+ }
982
+ function normalizeTypesConfig(config) {
983
+ return {
984
+ emit: config?.emit ?? true,
985
+ helpers: config?.helpers ?? "package",
986
+ helpersOutput: config?.helpersOutput ?? "./zenko-types",
987
+ treeShake: config?.treeShake ?? true,
988
+ optionalType: config?.optionalType ?? "optional"
989
+ };
990
+ }
991
+ function appendHelperTypesImport(buffer, config, operations) {
992
+ if (!config.emit) return;
993
+ switch (config.helpers) {
994
+ case "package":
995
+ if (config.treeShake) {
996
+ const usage = analyzeZenkoUsage(operations);
997
+ const importStatement = generateZenkoImport(usage, "package");
998
+ if (importStatement) {
999
+ buffer.push(importStatement);
1000
+ }
1001
+ } else {
1002
+ buffer.push(
1003
+ 'import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "zenko";'
1004
+ );
1005
+ }
1006
+ return;
1007
+ case "file":
1008
+ if (config.treeShake) {
1009
+ const usage = analyzeZenkoUsage(operations);
1010
+ const importStatement = generateZenkoImport(
1011
+ usage,
1012
+ "file",
1013
+ config.helpersOutput
1014
+ );
1015
+ if (importStatement) {
1016
+ buffer.push(importStatement);
1017
+ }
1018
+ } else {
1019
+ buffer.push(
1020
+ `import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "${config.helpersOutput}";`
1021
+ );
1022
+ }
1023
+ return;
1024
+ case "inline":
1025
+ buffer.push(
1026
+ "type PathFn<TArgs extends unknown[] = []> = (...args: TArgs) => string;"
1027
+ );
1028
+ buffer.push(
1029
+ 'type RequestMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace";'
1030
+ );
1031
+ buffer.push(
1032
+ "type HeaderFn<TArgs extends unknown[] = [], TResult = Record<string, unknown> | Record<string, never>> = (...args: TArgs) => TResult;"
1033
+ );
1034
+ buffer.push(
1035
+ "type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown);"
1036
+ );
1037
+ buffer.push(
1038
+ "type OperationErrors<TError = unknown> = TError extends Record<string, unknown> ? TError : Record<string, TError>;"
1039
+ );
1040
+ buffer.push(
1041
+ "type OperationDefinition<TMethod extends RequestMethod, TPath extends (...args: any[]) => string, TRequest = undefined, TResponse = undefined, THeaders extends AnyHeaderFn | undefined = undefined, TErrors extends OperationErrors | undefined = undefined> = {"
1042
+ );
1043
+ buffer.push(" method: TMethod");
1044
+ buffer.push(" path: TPath");
1045
+ buffer.push(" request?: TRequest");
1046
+ buffer.push(" response?: TResponse");
1047
+ buffer.push(" headers?: THeaders");
1048
+ buffer.push(" errors?: TErrors");
1049
+ buffer.push("}");
1050
+ buffer.push("");
1051
+ }
1052
+ }
1053
+ function generateOperationTypes(buffer, operations, config) {
1054
+ if (!config.emit) return;
1055
+ buffer.push("// Operation Types");
1056
+ for (const op of operations) {
1057
+ const camelCaseOperationId = toCamelCase(op.operationId);
1058
+ const headerType = op.requestHeaders?.length ? isValidJSIdentifier(camelCaseOperationId) ? `typeof headers.${camelCaseOperationId}` : `(typeof headers)[${formatPropertyName(camelCaseOperationId)}]` : "undefined";
1059
+ const requestType = wrapTypeReference(op.requestType);
1060
+ const responseType = wrapTypeReference(op.responseType);
1061
+ const errorsType = buildOperationErrorsType(op.errors);
1062
+ buffer.push(
1063
+ `export type ${capitalize(camelCaseOperationId)}Operation = OperationDefinition<`
1064
+ );
1065
+ buffer.push(` "${op.method}",`);
1066
+ buffer.push(
1067
+ ` ${isValidJSIdentifier(camelCaseOperationId) ? `typeof paths.${camelCaseOperationId}` : `(typeof paths)[${formatPropertyName(camelCaseOperationId)}]`},`
1068
+ );
1069
+ buffer.push(` ${requestType},`);
1070
+ buffer.push(` ${responseType},`);
1071
+ buffer.push(` ${headerType},`);
1072
+ buffer.push(` ${errorsType}`);
1073
+ buffer.push(`>;`);
1074
+ buffer.push("");
1075
+ }
1076
+ }
1077
+ function buildOperationErrorsType(errors) {
1078
+ if (!errors || !hasAnyErrors2(errors)) {
1079
+ return "OperationErrors";
1080
+ }
1081
+ const errorBucket = buildErrorBucket(errors);
1082
+ return `OperationErrors<${errorBucket}>`;
1083
+ }
1084
+ function buildErrorBucket(bucket) {
1085
+ if (!bucket || Object.keys(bucket).length === 0) {
1086
+ return "unknown";
1087
+ }
1088
+ const entries = Object.entries(bucket);
1089
+ const accessibleEntries = entries.map(([name, type]) => {
1090
+ const propertyKey = formatPropertyName(name);
1091
+ const valueType = wrapErrorValueType(type);
1092
+ return `${propertyKey}: ${valueType}`;
1093
+ });
1094
+ return `{ ${accessibleEntries.join("; ")} }`;
1095
+ }
1096
+ var TYPE_KEYWORDS = /* @__PURE__ */ new Set([
1097
+ "any",
1098
+ "unknown",
1099
+ "never",
1100
+ "void",
1101
+ "null",
1102
+ "undefined",
1103
+ "string",
1104
+ "number",
1105
+ "boolean",
1106
+ "bigint",
1107
+ "symbol"
1108
+ ]);
1109
+ var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1110
+ function wrapTypeReference(typeName) {
1111
+ if (!typeName) return "undefined";
1112
+ const normalized = typeName.trim();
1113
+ if (normalized === "undefined") return "undefined";
1114
+ if (TYPE_KEYWORDS.has(normalized)) return normalized;
1115
+ if (normalized.startsWith("typeof ")) return normalized;
1116
+ const arrayMatch = normalized.match(/^z\.array\((.+)\)$/);
1117
+ if (arrayMatch) {
1118
+ return `z.ZodArray<${wrapTypeReference(arrayMatch[1])}>`;
1119
+ }
1120
+ if (IDENTIFIER_PATTERN.test(normalized)) {
1121
+ return `typeof ${normalized}`;
1122
+ }
1123
+ return normalized;
1124
+ }
1125
+ function wrapErrorValueType(typeName) {
1126
+ if (!typeName) return "unknown";
1127
+ const normalized = typeName.trim();
1128
+ if (TYPE_KEYWORDS.has(normalized)) return normalized;
1129
+ if (normalized.startsWith("typeof ")) return normalized;
1130
+ const arrayMatch = normalized.match(/^z\.array\((.+)\)$/);
1131
+ if (arrayMatch) {
1132
+ return `z.ZodArray<${wrapErrorValueType(arrayMatch[1])}>`;
1133
+ }
1134
+ if (IDENTIFIER_PATTERN.test(normalized)) {
1135
+ return `typeof ${normalized}`;
1136
+ }
1137
+ return normalized;
1138
+ }
1139
+ function collectParameters(pathItem, operation, spec) {
1140
+ const parametersMap = /* @__PURE__ */ new Map();
1141
+ const addParameters = (params) => {
1142
+ if (!Array.isArray(params)) return;
1143
+ for (const param of params) {
1144
+ const resolved = resolveParameter2(param, spec);
1145
+ if (!resolved) continue;
1146
+ const key = `${resolved.in}:${resolved.name}`;
1147
+ parametersMap.set(key, resolved);
1148
+ }
1149
+ };
1150
+ addParameters(pathItem.parameters);
1151
+ addParameters(operation.parameters);
1152
+ return Array.from(parametersMap.values());
1153
+ }
1154
+ function resolveParameter2(parameter, spec) {
1155
+ if (!parameter) return void 0;
1156
+ if (parameter.$ref) {
1157
+ const refName = extractRefName(parameter.$ref);
1158
+ const resolved = spec.components?.parameters?.[refName];
1159
+ if (!resolved) return void 0;
1160
+ const { $ref, ...overrides } = parameter;
1161
+ return {
1162
+ ...resolved,
1163
+ ...overrides
1164
+ };
1165
+ }
1166
+ return parameter;
1167
+ }
1168
+ function extractPathParams(path3) {
1169
+ const params = [];
1170
+ const matches = path3.match(/{([^}]+)}/g);
1171
+ if (matches) {
1172
+ for (const match of matches) {
1173
+ const paramName = match.slice(1, -1);
1174
+ params.push({
1175
+ name: paramName,
1176
+ type: "string"
1177
+ // OpenAPI path params are always strings
1178
+ });
1179
+ }
1180
+ }
1181
+ return params;
1182
+ }
1183
+ function getRequestType(operation) {
1184
+ const requestBody = operation.requestBody?.content?.["application/json"]?.schema;
1185
+ if (!requestBody) return void 0;
1186
+ if (requestBody.$ref) {
1187
+ return extractRefName(requestBody.$ref);
1188
+ }
1189
+ const typeName = `${capitalize(toCamelCase(operation.operationId))}Request`;
1190
+ return typeName;
1191
+ }
1192
+ function getResponseTypes(operation, operationId, nameMap) {
1193
+ const responses = operation.responses ?? {};
1194
+ const successCodes = /* @__PURE__ */ new Map();
1195
+ const errorEntries = [];
1196
+ for (const [statusCode, response] of Object.entries(responses)) {
1197
+ const content = response?.content;
1198
+ if (!content || Object.keys(content).length === 0) {
1199
+ if (statusCode === "204" || /^3\d\d$/.test(statusCode)) {
1200
+ successCodes.set(statusCode, "undefined");
1201
+ } else if (isErrorStatus(statusCode)) {
1202
+ errorEntries.push({
1203
+ code: statusCode,
1204
+ schema: "undefined"
1205
+ });
1206
+ }
1207
+ continue;
1208
+ }
1209
+ const contentType = findContentType2(content);
1210
+ const resolvedSchema = content[contentType]?.schema;
1211
+ if (!resolvedSchema) {
1212
+ const inferredType = inferResponseType(contentType, statusCode);
1213
+ if (inferredType) {
1214
+ if (isErrorStatus(statusCode)) {
1215
+ errorEntries.push({
1216
+ code: statusCode,
1217
+ schema: inferredType
1218
+ });
1219
+ } else if (/^2\d\d$/.test(statusCode)) {
1220
+ successCodes.set(statusCode, inferredType);
1221
+ }
1222
+ }
1223
+ continue;
1224
+ }
1225
+ if (isErrorStatus(statusCode)) {
1226
+ errorEntries.push({ code: statusCode, schema: resolvedSchema });
1227
+ continue;
1228
+ }
1229
+ if (/^2\d\d$/.test(statusCode)) {
1230
+ successCodes.set(statusCode, resolvedSchema);
1231
+ }
1232
+ }
1233
+ const successResponse = selectSuccessResponse(
1234
+ successCodes,
1235
+ operationId,
1236
+ nameMap
1237
+ );
1238
+ const errors = buildErrorGroups(errorEntries, operationId, nameMap);
1239
+ return { successResponse, errors };
1240
+ }
1241
+ function selectSuccessResponse(responses, operationId, nameMap) {
1242
+ if (responses.size === 0) return void 0;
1243
+ const preferredOrder = ["200", "201", "204"];
1244
+ for (const code of preferredOrder) {
1245
+ const schema = responses.get(code);
1246
+ if (schema) {
1247
+ if (typeof schema === "string") {
1248
+ return schema;
1249
+ }
1250
+ return resolveResponseType(
1251
+ schema,
1252
+ `${capitalize(toCamelCase(operationId))}Response`,
1253
+ nameMap
1254
+ );
1255
+ }
1256
+ }
1257
+ const [, firstSchema] = responses.entries().next().value ?? [];
1258
+ if (!firstSchema) return void 0;
1259
+ if (typeof firstSchema === "string") {
1260
+ return firstSchema;
1261
+ }
1262
+ return resolveResponseType(
1263
+ firstSchema,
1264
+ `${capitalize(toCamelCase(operationId))}Response`,
1265
+ nameMap
1266
+ );
1267
+ }
1268
+ function buildErrorGroups(errors = [], operationId, nameMap) {
1269
+ if (!errors.length) return void 0;
1270
+ const group = {};
1271
+ for (const { code, schema } of errors) {
1272
+ const identifier = mapStatusToIdentifier(code);
1273
+ const typeName = resolveResponseType(
1274
+ schema,
1275
+ `${capitalize(toCamelCase(operationId))}${capitalize(identifier)}`,
1276
+ nameMap
1277
+ );
1278
+ group[identifier] = typeName;
1279
+ }
1280
+ return group;
1281
+ }
1282
+ function resolveResponseType(schema, fallbackName, nameMap) {
1283
+ if (typeof schema === "string") {
1284
+ return schema;
1285
+ }
1286
+ if (schema.$ref) {
1287
+ const refName = extractRefName(schema.$ref);
1288
+ return nameMap?.get(refName) || refName;
1289
+ }
1290
+ if (schema.type === "array" && schema.items?.$ref) {
1291
+ const itemRef = extractRefName(schema.items.$ref);
1292
+ const sanitizedItemRef = nameMap?.get(itemRef) || itemRef;
1293
+ return `z.array(${sanitizedItemRef})`;
1294
+ }
1295
+ if (schema.allOf && Array.isArray(schema.allOf)) {
1296
+ return fallbackName;
1297
+ }
1298
+ return fallbackName;
1299
+ }
1300
+ function getRequestHeaders(parameters) {
1301
+ const headers = [];
1302
+ for (const param of parameters ?? []) {
1303
+ if (param.in === "header") {
1304
+ headers.push({
1305
+ name: param.name,
1306
+ description: param.description,
1307
+ schema: param.schema,
1308
+ required: param.required
1309
+ });
1310
+ }
1311
+ }
1312
+ return headers;
1313
+ }
1314
+ function getQueryParams(parameters) {
1315
+ const queryParams = [];
1316
+ for (const param of parameters ?? []) {
1317
+ if (param.in === "query") {
1318
+ queryParams.push({
1319
+ name: param.name,
1320
+ description: param.description,
1321
+ schema: param.schema,
1322
+ required: param.required
1323
+ });
1324
+ }
1325
+ }
1326
+ return queryParams;
1327
+ }
1328
+ function mapHeaderToZodType(header) {
1329
+ const schema = header.schema ?? {};
1330
+ const schemaType = schema.type;
1331
+ switch (schemaType) {
1332
+ case "integer":
1333
+ case "number":
1334
+ return "z.coerce.number()";
1335
+ case "boolean":
1336
+ return "z.coerce.boolean()";
1337
+ case "array": {
1338
+ const items = schema.items ?? { type: "string" };
1339
+ const itemType = items.type === "integer" || items.type === "number" ? "z.coerce.number()" : items.type === "boolean" ? "z.coerce.boolean()" : "z.string()";
1340
+ return `z.array(${itemType})`;
1341
+ }
1342
+ default:
1343
+ return "z.string()";
1344
+ }
1345
+ }
1346
+ function mapQueryType(param) {
1347
+ return mapQuerySchemaType(param.schema);
1348
+ }
1349
+ function mapQuerySchemaType(schema) {
1350
+ if (!schema) return "string";
1351
+ if (schema.type === "array") {
1352
+ const itemType = mapQuerySchemaType(schema.items);
1353
+ return `Array<${itemType}>`;
1354
+ }
1355
+ switch (schema.type) {
1356
+ case "integer":
1357
+ case "number":
1358
+ return "number";
1359
+ case "boolean":
1360
+ return "boolean";
1361
+ default:
1362
+ return "string";
1363
+ }
1364
+ }
1365
+ function convertQueryParamValue(schema, accessor) {
1366
+ if (!schema) {
1367
+ return `String(${accessor})`;
1368
+ }
1369
+ switch (schema.type) {
1370
+ case "integer":
1371
+ case "number":
1372
+ return `String(${accessor})`;
1373
+ case "boolean":
1374
+ return `${accessor} ? "true" : "false"`;
1375
+ default:
1376
+ return `String(${accessor})`;
1377
+ }
1378
+ }
1379
+ function applyOptionalModifier(zodType, optionalType) {
1380
+ switch (optionalType) {
1381
+ case "optional":
1382
+ return `${zodType}.optional()`;
1383
+ case "nullable":
1384
+ return `${zodType}.nullable()`;
1385
+ case "nullish":
1386
+ return `${zodType}.nullish()`;
1387
+ }
1388
+ }
1389
+ function generateZodSchema(name, schema, generatedTypes, options, nameMap) {
1390
+ if (generatedTypes.has(name)) return "";
1391
+ generatedTypes.add(name);
1392
+ if (schema.enum) {
1393
+ const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
1394
+ return `export const ${name} = z.enum([${enumValues}]);`;
1395
+ }
1396
+ if (schema.allOf && Array.isArray(schema.allOf)) {
1397
+ const allOfParts = schema.allOf.map(
1398
+ (part) => getZodTypeFromSchema(part, options, nameMap)
1399
+ );
1400
+ if (allOfParts.length === 0) return `export const ${name} = z.object({});`;
1401
+ if (allOfParts.length === 1)
1402
+ return `export const ${name} = ${allOfParts[0]};`;
1403
+ const first = allOfParts[0];
1404
+ const rest = allOfParts.slice(1).map((part) => `.and(${part})`).join("");
1405
+ return `export const ${name} = ${first}${rest};`;
1406
+ }
1407
+ if (schema.type === "object" || schema.properties) {
1408
+ return `export const ${name} = ${buildZodObject(schema, options, nameMap)};`;
1409
+ }
1410
+ if (schema.type === "array") {
1411
+ const itemSchema = schema.items ?? { type: "unknown" };
1412
+ const itemType = getZodTypeFromSchema(itemSchema, options, nameMap);
1413
+ const builder = applyStrictArrayBounds(
1414
+ schema,
1415
+ `z.array(${itemType})`,
1416
+ itemSchema,
1417
+ options.strictNumeric
1418
+ );
1419
+ return `export const ${name} = ${builder};`;
1420
+ }
1421
+ return `export const ${name} = ${getZodTypeFromSchema(schema, options, nameMap)};`;
1422
+ }
1423
+ function getZodTypeFromSchema(schema, options, nameMap) {
1424
+ if (schema.$ref) {
1425
+ const refName = extractRefName(schema.$ref);
1426
+ return nameMap?.get(refName) || refName;
1427
+ }
1428
+ if (schema.enum) {
1429
+ const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
1430
+ return `z.enum([${enumValues}])`;
1431
+ }
1432
+ if (schema.allOf && Array.isArray(schema.allOf)) {
1433
+ const allOfParts = schema.allOf.map(
1434
+ (part) => getZodTypeFromSchema(part, options, nameMap)
1435
+ );
1436
+ if (allOfParts.length === 0) return "z.object({})";
1437
+ if (allOfParts.length === 1) return allOfParts[0];
1438
+ const first = allOfParts[0];
1439
+ const rest = allOfParts.slice(1).map((part) => `.and(${part})`).join("");
1440
+ return `${first}${rest}`;
1441
+ }
1442
+ if (schema.type === "object" || schema.properties || schema.allOf || schema.oneOf || schema.anyOf) {
1443
+ return buildZodObject(schema, options, nameMap);
1444
+ }
1445
+ switch (schema.type) {
1446
+ case "string":
1447
+ return buildString(schema, options);
1448
+ case "boolean":
1449
+ return "z.boolean()";
1450
+ case "array":
1451
+ return `z.array(${getZodTypeFromSchema(
1452
+ schema.items ?? { type: "unknown" },
1453
+ options,
1454
+ nameMap
1455
+ )})`;
1456
+ case "null":
1457
+ return "z.null()";
1458
+ case "number":
1459
+ return buildNumber(schema, options);
1460
+ case "integer":
1461
+ return buildInteger(schema, options);
1462
+ default:
1463
+ return "z.unknown()";
1464
+ }
1465
+ }
1466
+ function buildZodObject(schema, options, nameMap) {
1467
+ const properties = [];
1468
+ for (const [propName, propSchema] of Object.entries(
1469
+ schema.properties || {}
1470
+ )) {
1471
+ const isRequired = schema.required?.includes(propName) ?? false;
1472
+ const zodType = getZodTypeFromSchema(propSchema, options, nameMap);
1473
+ const finalType = isRequired ? zodType : applyOptionalModifier(zodType, options.optionalType);
1474
+ properties.push(` ${formatPropertyName(propName)}: ${finalType},`);
1475
+ }
1476
+ if (properties.length === 0) {
1477
+ return "z.object({})";
1478
+ }
1479
+ return `z.object({
1480
+ ${properties.join("\n")}
1481
+ })`;
1482
+ }
1483
+ function buildString(schema, options) {
1484
+ if (options.strictDates) {
1485
+ switch (schema.format) {
1486
+ case "date-time":
1487
+ return "z.string().datetime()";
1488
+ case "date":
1489
+ return "z.string().date()";
1490
+ case "time":
1491
+ return "z.string().time()";
1492
+ case "duration":
1493
+ return "z.string().duration()";
1494
+ }
1495
+ }
1496
+ let builder = "z.string()";
1497
+ if (options.strictNumeric) {
1498
+ if (typeof schema.minLength === "number") {
1499
+ builder += `.min(${schema.minLength})`;
1500
+ }
1501
+ if (typeof schema.maxLength === "number") {
1502
+ builder += `.max(${schema.maxLength})`;
1503
+ }
1504
+ if (schema.pattern) {
1505
+ builder += `.regex(new RegExp(${JSON.stringify(schema.pattern)}))`;
1506
+ }
1507
+ }
1508
+ switch (schema.format) {
1509
+ case "uuid":
1510
+ return `${builder}.uuid()`;
1511
+ case "email":
1512
+ return `${builder}.email()`;
1513
+ case "uri":
1514
+ case "url":
1515
+ return `${builder}.url()`;
1516
+ case "ipv4":
1517
+ return `${builder}.ip({ version: "v4" })`;
1518
+ case "ipv6":
1519
+ return `${builder}.ip({ version: "v6" })`;
1520
+ default:
1521
+ return builder;
1522
+ }
1523
+ }
1524
+ function buildNumber(schema, options) {
1525
+ let builder = "z.number()";
1526
+ if (options.strictNumeric) {
1527
+ builder = applyNumericBounds(schema, builder);
1528
+ if (typeof schema.multipleOf === "number" && schema.multipleOf !== 0) {
1529
+ builder += `.refine((value) => Math.abs(value / ${schema.multipleOf} - Math.round(value / ${schema.multipleOf})) < Number.EPSILON, { message: "Must be a multiple of ${schema.multipleOf}" })`;
1530
+ }
1531
+ }
1532
+ return builder;
1533
+ }
1534
+ function buildInteger(schema, options) {
1535
+ let builder = buildNumber(schema, options);
1536
+ builder += ".int()";
1537
+ return builder;
1538
+ }
1539
+ function applyStrictArrayBounds(schema, builder, itemSchema, enforceBounds) {
1540
+ if (!enforceBounds) {
1541
+ return builder;
1542
+ }
1543
+ if (typeof schema.minItems === "number") {
1544
+ builder += `.min(${schema.minItems})`;
1545
+ }
1546
+ if (typeof schema.maxItems === "number") {
1547
+ builder += `.max(${schema.maxItems})`;
1548
+ }
1549
+ if (schema.uniqueItems && isPrimitiveLike(itemSchema)) {
1550
+ builder += '.refine((items) => new Set(items).size === items.length, { message: "Items must be unique" })';
1551
+ }
1552
+ return builder;
1553
+ }
1554
+ function isPrimitiveLike(schema) {
1555
+ if (schema?.$ref) return false;
1556
+ const primitiveTypes = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean"]);
1557
+ return primitiveTypes.has(schema?.type);
1558
+ }
1559
+ function applyNumericBounds(schema, builder) {
1560
+ if (typeof schema.minimum === "number") {
1561
+ if (schema.exclusiveMinimum === true) {
1562
+ builder += `.gt(${schema.minimum})`;
1563
+ } else {
1564
+ builder += `.min(${schema.minimum})`;
1565
+ }
1566
+ } else if (typeof schema.exclusiveMinimum === "number") {
1567
+ builder += `.gt(${schema.exclusiveMinimum})`;
1568
+ }
1569
+ if (typeof schema.maximum === "number") {
1570
+ if (schema.exclusiveMaximum === true) {
1571
+ builder += `.lt(${schema.maximum})`;
1572
+ } else {
1573
+ builder += `.max(${schema.maximum})`;
1574
+ }
1575
+ } else if (typeof schema.exclusiveMaximum === "number") {
1576
+ builder += `.lt(${schema.exclusiveMaximum})`;
1577
+ }
1578
+ return builder;
1579
+ }
30
1580
 
31
1581
  // src/loader.ts
32
1582
  var path = __toESM(require("path"), 1);
@@ -232,7 +1782,7 @@ async function generateSingle(options) {
232
1782
  operationIds
233
1783
  } = options;
234
1784
  const spec = await loadSpec(resolvedInput);
235
- const result = (0, import_core.generateFromDocument)(spec, {
1785
+ const result = generateFromDocument(spec, {
236
1786
  strictDates,
237
1787
  strictNumeric,
238
1788
  types,