zenko 0.1.6 → 0.1.7-beta.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.cjs CHANGED
@@ -153,6 +153,14 @@ function formatPropertyName(name) {
153
153
  return isValidJSIdentifier(name) ? name : `"${name}"`;
154
154
  }
155
155
 
156
+ // src/utils/string-utils.ts
157
+ function toCamelCase(str) {
158
+ return str.replace(/-([a-zA-Z])/g, (_, letter) => letter.toUpperCase()).replace(/-+$/, "");
159
+ }
160
+ function capitalize(str) {
161
+ return str.charAt(0).toUpperCase() + str.slice(1);
162
+ }
163
+
156
164
  // src/utils/http-status.ts
157
165
  var statusNameMap = {
158
166
  "400": "badRequest",
@@ -212,14 +220,6 @@ function mapStatusToIdentifier(status) {
212
220
  if (!candidate) return "unknownError";
213
221
  return /^[a-zA-Z_$]/.test(candidate) ? candidate : `status${candidate.charAt(0).toUpperCase()}${candidate.slice(1)}`;
214
222
  }
215
- function getStatusCategory(status) {
216
- if (status === "default") return "default";
217
- const code = Number(status);
218
- if (!Number.isInteger(code)) return "unknown";
219
- if (code >= 400 && code <= 499) return "client";
220
- if (code >= 500 && code <= 599) return "server";
221
- return "unknown";
222
- }
223
223
  function isErrorStatus(status) {
224
224
  if (status === "default") return true;
225
225
  const code = Number(status);
@@ -227,6 +227,169 @@ function isErrorStatus(status) {
227
227
  return code >= 400;
228
228
  }
229
229
 
230
+ // src/utils/tree-shaking.ts
231
+ function analyzeZenkoUsage(operations) {
232
+ const usage = {
233
+ usesHeaderFn: false,
234
+ usesOperationDefinition: false,
235
+ usesOperationErrors: false
236
+ };
237
+ if (operations.length > 0) {
238
+ usage.usesOperationDefinition = true;
239
+ }
240
+ for (const op of operations) {
241
+ if (op.requestHeaders && op.requestHeaders.length > 0) {
242
+ usage.usesHeaderFn = true;
243
+ }
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
+ // 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
+
351
+ // src/utils/generate-helper-file.ts
352
+ function generateHelperFile() {
353
+ const output = [];
354
+ output.push("// Generated helper types for Zenko");
355
+ output.push(
356
+ "// This file provides type definitions for operation objects and path functions"
357
+ );
358
+ output.push("");
359
+ output.push(
360
+ "export type PathFn<TArgs extends unknown[] = []> = (...args: TArgs) => string"
361
+ );
362
+ output.push("");
363
+ output.push(
364
+ 'export type RequestMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"'
365
+ );
366
+ output.push("");
367
+ output.push(
368
+ "export type HeaderFn<TArgs extends unknown[] = [], TResult = Record<string, unknown> | Record<string, never>> = (...args: TArgs) => TResult"
369
+ );
370
+ output.push("");
371
+ output.push(
372
+ "export type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown)"
373
+ );
374
+ output.push("");
375
+ output.push(
376
+ "export type OperationErrors<TError = unknown> = TError extends Record<string, unknown> ? TError : Record<string, TError>;"
377
+ );
378
+ output.push("");
379
+ output.push(
380
+ "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> = {"
381
+ );
382
+ output.push(" method: TMethod");
383
+ output.push(" path: TPath");
384
+ output.push(" request?: TRequest");
385
+ output.push(" response?: TResponse");
386
+ output.push(" headers?: THeaders");
387
+ output.push(" errors?: TErrors");
388
+ output.push("}");
389
+ output.push("");
390
+ return output.join("\n");
391
+ }
392
+
230
393
  // src/zenko.ts
231
394
  function generateWithMetadata(spec, options = {}) {
232
395
  const output = [];
@@ -238,7 +401,14 @@ function generateWithMetadata(spec, options = {}) {
238
401
  strictNumeric
239
402
  };
240
403
  output.push('import { z } from "zod";');
241
- appendHelperTypesImport(output, typesConfig);
404
+ const nameMap = /* @__PURE__ */ new Map();
405
+ if (spec.components?.schemas) {
406
+ for (const name of Object.keys(spec.components.schemas)) {
407
+ nameMap.set(name, toCamelCase(name));
408
+ }
409
+ }
410
+ const operations = parseOperations(spec, nameMap);
411
+ appendHelperTypesImport(output, typesConfig, operations);
242
412
  output.push("");
243
413
  if (spec.components?.schemas) {
244
414
  output.push("// Generated Zod Schemas");
@@ -246,15 +416,23 @@ function generateWithMetadata(spec, options = {}) {
246
416
  const sortedSchemas = topologicalSort(spec.components.schemas);
247
417
  for (const name of sortedSchemas) {
248
418
  const schema = spec.components.schemas[name];
419
+ const sanitizedName = nameMap.get(name);
249
420
  output.push(
250
- generateZodSchema(name, schema, generatedTypes, schemaOptions)
421
+ generateZodSchema(
422
+ sanitizedName,
423
+ schema,
424
+ generatedTypes,
425
+ schemaOptions,
426
+ nameMap
427
+ )
251
428
  );
252
429
  output.push("");
253
- output.push(`export type ${name} = z.infer<typeof ${name}>;`);
430
+ output.push(
431
+ `export type ${sanitizedName} = z.infer<typeof ${sanitizedName}>;`
432
+ );
254
433
  output.push("");
255
434
  }
256
435
  }
257
- const operations = parseOperations(spec);
258
436
  output.push("// Path Functions");
259
437
  output.push("export const paths = {");
260
438
  for (const op of operations) {
@@ -268,24 +446,37 @@ function generateWithMetadata(spec, options = {}) {
268
446
  );
269
447
  continue;
270
448
  }
271
- const allParamNames = [
272
- ...pathParamNames,
273
- ...op.queryParams.map((p) => p.name)
274
- ];
275
- const signaturePieces = [];
449
+ const alias = (n) => {
450
+ if (isValidJSIdentifier(n)) return n;
451
+ let aliased = toCamelCase(n);
452
+ if (!isValidJSIdentifier(aliased)) {
453
+ aliased = `_${aliased}`;
454
+ }
455
+ return aliased;
456
+ };
457
+ const destructPieces = [];
458
+ const typePieces = [];
276
459
  for (const param of op.pathParams) {
277
- signaturePieces.push(`${param.name}: string`);
460
+ destructPieces.push(
461
+ isValidJSIdentifier(param.name) ? param.name : `${formatPropertyName(param.name)}: ${alias(param.name)}`
462
+ );
463
+ typePieces.push(`${formatPropertyName(param.name)}: string`);
278
464
  }
279
465
  for (const param of op.queryParams) {
280
- signaturePieces.push(
281
- `${param.name}${param.required ? "" : "?"}: ${mapQueryType(param)}`
466
+ destructPieces.push(
467
+ isValidJSIdentifier(param.name) ? param.name : `${formatPropertyName(param.name)}: ${alias(param.name)}`
468
+ );
469
+ typePieces.push(
470
+ `${formatPropertyName(param.name)}${param.required ? "" : "?"}: ${mapQueryType(param)}`
282
471
  );
283
472
  }
284
- const signatureParams = signaturePieces.join(", ");
285
473
  const needsDefaultObject = !hasPathParams && hasQueryParams && op.queryParams.every((param) => !param.required);
286
- const signatureArgs = allParamNames.length ? `{ ${allParamNames.join(", ")} }` : "{}";
287
- const signature = `${signatureArgs}: { ${signatureParams} }${needsDefaultObject ? " = {}" : ""}`;
288
- const pathWithParams = op.path.replace(/{([^}]+)}/g, "${$1}");
474
+ const signatureArgs = destructPieces.length ? `{ ${destructPieces.join(", ")} }` : "{}";
475
+ const signature = `${signatureArgs}: { ${typePieces.join(", ")} }${needsDefaultObject ? " = {}" : ""}`;
476
+ const pathWithParams = op.path.replace(
477
+ /{([^}]+)}/g,
478
+ (_m, n) => `\${${alias(n)}}`
479
+ );
289
480
  if (!hasQueryParams) {
290
481
  output.push(
291
482
  ` ${formatPropertyName(camelCaseOperationId)}: (${signature}) => \`${pathWithParams}\`,`
@@ -297,8 +488,7 @@ function generateWithMetadata(spec, options = {}) {
297
488
  );
298
489
  output.push(" const params = new URLSearchParams()");
299
490
  for (const param of op.queryParams) {
300
- const propertyKey = formatPropertyName(param.name);
301
- const accessor = isValidJSIdentifier(param.name) ? param.name : propertyKey;
491
+ const accessor = isValidJSIdentifier(param.name) ? param.name : alias(toCamelCase(param.name));
302
492
  const schema = param.schema ?? {};
303
493
  if (schema?.type === "array") {
304
494
  const itemValueExpression = convertQueryParamValue(
@@ -380,6 +570,8 @@ function generateWithMetadata(spec, options = {}) {
380
570
  }
381
571
  output.push("} as const;");
382
572
  output.push("");
573
+ generateRequestTypes(output, operations, spec, nameMap, schemaOptions);
574
+ generateResponseTypes(output, operations, spec, nameMap, schemaOptions);
383
575
  generateOperationTypes(output, operations, typesConfig);
384
576
  output.push("// Operation Objects");
385
577
  for (const op of operations) {
@@ -393,13 +585,8 @@ function generateWithMetadata(spec, options = {}) {
393
585
  if (op.requestHeaders && op.requestHeaders.length > 0) {
394
586
  output.push(` headers: headers.${camelCaseOperationId},`);
395
587
  }
396
- if (op.errors && hasAnyErrors(op.errors)) {
397
- output.push(" errors: {");
398
- appendErrorGroup(output, "clientErrors", op.errors.clientErrors);
399
- appendErrorGroup(output, "serverErrors", op.errors.serverErrors);
400
- appendErrorGroup(output, "defaultErrors", op.errors.defaultErrors);
401
- appendErrorGroup(output, "otherErrors", op.errors.otherErrors);
402
- output.push(" },");
588
+ if (op.errors && hasAnyErrors2(op.errors)) {
589
+ appendErrorGroup(output, "errors", op.errors);
403
590
  }
404
591
  output.push("} as const;");
405
592
  output.push("");
@@ -415,6 +602,46 @@ function generateWithMetadata(spec, options = {}) {
415
602
  }
416
603
  return result;
417
604
  }
605
+ function generateRequestTypes(output, operations, spec, nameMap, schemaOptions) {
606
+ const requestTypesToGenerate = collectInlineRequestTypes(operations, spec);
607
+ if (requestTypesToGenerate.size > 0) {
608
+ output.push("// Generated Request Types");
609
+ output.push("");
610
+ for (const [typeName, schema] of requestTypesToGenerate) {
611
+ const generatedSchema = generateZodSchema(
612
+ typeName,
613
+ schema,
614
+ /* @__PURE__ */ new Set(),
615
+ schemaOptions,
616
+ nameMap
617
+ );
618
+ output.push(generatedSchema);
619
+ output.push("");
620
+ output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
621
+ output.push("");
622
+ }
623
+ }
624
+ }
625
+ function generateResponseTypes(output, operations, spec, nameMap, schemaOptions) {
626
+ const responseTypesToGenerate = collectInlineResponseTypes(operations, spec);
627
+ if (responseTypesToGenerate.size > 0) {
628
+ output.push("// Generated Response Types");
629
+ output.push("");
630
+ for (const [typeName, schema] of responseTypesToGenerate) {
631
+ const generatedSchema = generateZodSchema(
632
+ typeName,
633
+ schema,
634
+ /* @__PURE__ */ new Set(),
635
+ schemaOptions,
636
+ nameMap
637
+ );
638
+ output.push(generatedSchema);
639
+ output.push("");
640
+ output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
641
+ output.push("");
642
+ }
643
+ }
644
+ }
418
645
  function generate(spec, options = {}) {
419
646
  return generateWithMetadata(spec, options).output;
420
647
  }
@@ -430,13 +657,8 @@ function appendErrorGroup(buffer, label, errors) {
430
657
  }
431
658
  buffer.push(" },");
432
659
  }
433
- function hasAnyErrors(group) {
434
- return [
435
- group.clientErrors,
436
- group.serverErrors,
437
- group.defaultErrors,
438
- group.otherErrors
439
- ].some((bucket) => bucket && Object.keys(bucket).length > 0);
660
+ function hasAnyErrors2(group) {
661
+ return Boolean(group && Object.keys(group).length > 0);
440
662
  }
441
663
  function isRequestMethod(method) {
442
664
  switch (method) {
@@ -483,33 +705,70 @@ function inferResponseType(contentType, statusCode) {
483
705
  }
484
706
  return "unknown";
485
707
  }
486
- function parseOperations(spec) {
708
+ function parseOperations(spec, nameMap) {
487
709
  const operations = [];
488
- for (const [path, pathItem] of Object.entries(spec.paths)) {
489
- for (const [method, operation] of Object.entries(pathItem)) {
490
- const normalizedMethod = method.toLowerCase();
491
- if (!isRequestMethod(normalizedMethod)) continue;
492
- if (!operation.operationId) continue;
493
- const pathParams = extractPathParams(path);
494
- const requestType = getRequestType(operation);
495
- const { successResponse, errors } = getResponseTypes(
496
- operation,
497
- operation.operationId
498
- );
499
- const resolvedParameters = collectParameters(pathItem, operation, spec);
500
- const requestHeaders = getRequestHeaders(resolvedParameters);
501
- const queryParams = getQueryParams(resolvedParameters);
502
- operations.push({
503
- operationId: operation.operationId,
504
- path,
505
- method: normalizedMethod,
506
- pathParams,
507
- queryParams,
508
- requestType,
509
- responseType: successResponse,
510
- requestHeaders,
511
- errors
512
- });
710
+ if (spec.paths) {
711
+ for (const [path, pathItem] of Object.entries(spec.paths)) {
712
+ for (const [method, operation] of Object.entries(pathItem)) {
713
+ const normalizedMethod = method.toLowerCase();
714
+ if (!isRequestMethod(normalizedMethod)) continue;
715
+ if (!operation.operationId) continue;
716
+ const pathParams = extractPathParams(path);
717
+ const requestType = getRequestType(operation);
718
+ const { successResponse, errors } = getResponseTypes(
719
+ operation,
720
+ operation.operationId,
721
+ nameMap
722
+ );
723
+ const resolvedParameters = collectParameters(pathItem, operation, spec);
724
+ const requestHeaders = getRequestHeaders(resolvedParameters);
725
+ const queryParams = getQueryParams(resolvedParameters);
726
+ operations.push({
727
+ operationId: operation.operationId,
728
+ path,
729
+ method: normalizedMethod,
730
+ pathParams,
731
+ queryParams,
732
+ requestType,
733
+ responseType: successResponse,
734
+ requestHeaders,
735
+ errors
736
+ });
737
+ }
738
+ }
739
+ }
740
+ if (spec.webhooks) {
741
+ for (const [webhookName, webhookItem] of Object.entries(spec.webhooks)) {
742
+ for (const [method, operation] of Object.entries(webhookItem)) {
743
+ const normalizedMethod = method.toLowerCase();
744
+ if (!isRequestMethod(normalizedMethod)) continue;
745
+ if (!operation.operationId) continue;
746
+ const path = webhookName;
747
+ const pathParams = extractPathParams(path);
748
+ const requestType = getRequestType(operation);
749
+ const { successResponse, errors } = getResponseTypes(
750
+ operation,
751
+ operation.operationId
752
+ );
753
+ const resolvedParameters = collectParameters(
754
+ webhookItem,
755
+ operation,
756
+ spec
757
+ );
758
+ const requestHeaders = getRequestHeaders(resolvedParameters);
759
+ const queryParams = getQueryParams(resolvedParameters);
760
+ operations.push({
761
+ operationId: operation.operationId,
762
+ path,
763
+ method: normalizedMethod,
764
+ pathParams,
765
+ queryParams,
766
+ requestType,
767
+ responseType: successResponse,
768
+ requestHeaders,
769
+ errors
770
+ });
771
+ }
513
772
  }
514
773
  }
515
774
  return operations;
@@ -518,21 +777,42 @@ function normalizeTypesConfig(config) {
518
777
  return {
519
778
  emit: config?.emit ?? true,
520
779
  helpers: config?.helpers ?? "package",
521
- helpersOutput: config?.helpersOutput ?? "./zenko-types"
780
+ helpersOutput: config?.helpersOutput ?? "./zenko-types",
781
+ treeShake: config?.treeShake ?? true
522
782
  };
523
783
  }
524
- function appendHelperTypesImport(buffer, config) {
784
+ function appendHelperTypesImport(buffer, config, operations) {
525
785
  if (!config.emit) return;
526
786
  switch (config.helpers) {
527
787
  case "package":
528
- buffer.push(
529
- 'import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "zenko";'
530
- );
788
+ if (config.treeShake) {
789
+ const usage = analyzeZenkoUsage(operations);
790
+ const importStatement = generateZenkoImport(usage, "package");
791
+ if (importStatement) {
792
+ buffer.push(importStatement);
793
+ }
794
+ } else {
795
+ buffer.push(
796
+ 'import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "zenko";'
797
+ );
798
+ }
531
799
  return;
532
800
  case "file":
533
- buffer.push(
534
- `import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "${config.helpersOutput}";`
535
- );
801
+ if (config.treeShake) {
802
+ const usage = analyzeZenkoUsage(operations);
803
+ const importStatement = generateZenkoImport(
804
+ usage,
805
+ "file",
806
+ config.helpersOutput
807
+ );
808
+ if (importStatement) {
809
+ buffer.push(importStatement);
810
+ }
811
+ } else {
812
+ buffer.push(
813
+ `import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "${config.helpersOutput}";`
814
+ );
815
+ }
536
816
  return;
537
817
  case "inline":
538
818
  buffer.push(
@@ -548,24 +828,19 @@ function appendHelperTypesImport(buffer, config) {
548
828
  "type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown);"
549
829
  );
550
830
  buffer.push(
551
- "type OperationErrors<TClient = unknown, TServer = unknown, TDefault = unknown, TOther = unknown> = {"
831
+ "type OperationErrors<TError = unknown> = TError extends Record<string, unknown> ? TError : Record<string, TError>;"
552
832
  );
553
- buffer.push(" clientErrors?: TClient;");
554
- buffer.push(" serverErrors?: TServer;");
555
- buffer.push(" defaultErrors?: TDefault;");
556
- buffer.push(" otherErrors?: TOther;");
557
- buffer.push("};");
558
833
  buffer.push(
559
834
  "type OperationDefinition<TMethod extends RequestMethod, TPath extends (...args: any[]) => string, TRequest = undefined, TResponse = undefined, THeaders extends AnyHeaderFn | undefined = undefined, TErrors extends OperationErrors | undefined = undefined> = {"
560
835
  );
561
- buffer.push(" method: TMethod;");
562
- buffer.push(" path: TPath;");
563
- buffer.push(" request?: TRequest;");
564
- buffer.push(" response?: TResponse;");
565
- buffer.push(" headers?: THeaders;");
566
- buffer.push(" errors?: TErrors;");
567
- buffer.push("};");
568
- return;
836
+ buffer.push(" method: TMethod");
837
+ buffer.push(" path: TPath");
838
+ buffer.push(" request?: TRequest");
839
+ buffer.push(" response?: TResponse");
840
+ buffer.push(" headers?: THeaders");
841
+ buffer.push(" errors?: TErrors");
842
+ buffer.push("}");
843
+ buffer.push("");
569
844
  }
570
845
  }
571
846
  function generateOperationTypes(buffer, operations, config) {
@@ -593,14 +868,11 @@ function generateOperationTypes(buffer, operations, config) {
593
868
  }
594
869
  }
595
870
  function buildOperationErrorsType(errors) {
596
- if (!errors || !hasAnyErrors(errors)) {
871
+ if (!errors || !hasAnyErrors2(errors)) {
597
872
  return "OperationErrors";
598
873
  }
599
- const client = buildErrorBucket(errors.clientErrors);
600
- const server = buildErrorBucket(errors.serverErrors);
601
- const fallback = buildErrorBucket(errors.defaultErrors);
602
- const other = buildErrorBucket(errors.otherErrors);
603
- return `OperationErrors<${client}, ${server}, ${fallback}, ${other}>`;
874
+ const errorBucket = buildErrorBucket(errors);
875
+ return `OperationErrors<${errorBucket}>`;
604
876
  }
605
877
  function buildErrorBucket(bucket) {
606
878
  if (!bucket || Object.keys(bucket).length === 0) {
@@ -707,10 +979,10 @@ function getRequestType(operation) {
707
979
  if (requestBody.$ref) {
708
980
  return extractRefName(requestBody.$ref);
709
981
  }
710
- const typeName = `${capitalize(operation.operationId)}Request`;
982
+ const typeName = `${capitalize(toCamelCase(operation.operationId))}Request`;
711
983
  return typeName;
712
984
  }
713
- function getResponseTypes(operation, operationId) {
985
+ function getResponseTypes(operation, operationId, nameMap) {
714
986
  const responses = operation.responses ?? {};
715
987
  const successCodes = /* @__PURE__ */ new Map();
716
988
  const errorEntries = [];
@@ -751,11 +1023,15 @@ function getResponseTypes(operation, operationId) {
751
1023
  successCodes.set(statusCode, resolvedSchema);
752
1024
  }
753
1025
  }
754
- const successResponse = selectSuccessResponse(successCodes, operationId);
755
- const errors = buildErrorGroups(errorEntries, operationId);
1026
+ const successResponse = selectSuccessResponse(
1027
+ successCodes,
1028
+ operationId,
1029
+ nameMap
1030
+ );
1031
+ const errors = buildErrorGroups(errorEntries, operationId, nameMap);
756
1032
  return { successResponse, errors };
757
1033
  }
758
- function selectSuccessResponse(responses, operationId) {
1034
+ function selectSuccessResponse(responses, operationId, nameMap) {
759
1035
  if (responses.size === 0) return void 0;
760
1036
  const preferredOrder = ["200", "201", "204"];
761
1037
  for (const code of preferredOrder) {
@@ -766,61 +1042,51 @@ function selectSuccessResponse(responses, operationId) {
766
1042
  }
767
1043
  return resolveResponseType(
768
1044
  schema,
769
- `${capitalize(operationId)}Response${code}`
1045
+ `${capitalize(toCamelCase(operationId))}Response`,
1046
+ nameMap
770
1047
  );
771
1048
  }
772
1049
  }
773
- const [firstCode, firstSchema] = responses.entries().next().value ?? [];
1050
+ const [, firstSchema] = responses.entries().next().value ?? [];
774
1051
  if (!firstSchema) return void 0;
775
1052
  if (typeof firstSchema === "string") {
776
1053
  return firstSchema;
777
1054
  }
778
1055
  return resolveResponseType(
779
1056
  firstSchema,
780
- `${capitalize(operationId)}Response${firstCode ?? "Default"}`
1057
+ `${capitalize(toCamelCase(operationId))}Response`,
1058
+ nameMap
781
1059
  );
782
1060
  }
783
- function buildErrorGroups(errors = [], operationId) {
1061
+ function buildErrorGroups(errors = [], operationId, nameMap) {
784
1062
  if (!errors.length) return void 0;
785
1063
  const group = {};
786
1064
  for (const { code, schema } of errors) {
787
- const category = getStatusCategory(code);
788
1065
  const identifier = mapStatusToIdentifier(code);
789
1066
  const typeName = resolveResponseType(
790
1067
  schema,
791
- `${capitalize(operationId)}${capitalize(identifier)}`
1068
+ `${capitalize(toCamelCase(operationId))}${capitalize(identifier)}`,
1069
+ nameMap
792
1070
  );
793
- switch (category) {
794
- case "client":
795
- group.clientErrors ??= {};
796
- group.clientErrors[identifier] = typeName;
797
- break;
798
- case "server":
799
- group.serverErrors ??= {};
800
- group.serverErrors[identifier] = typeName;
801
- break;
802
- case "default":
803
- group.defaultErrors ??= {};
804
- group.defaultErrors[identifier] = typeName;
805
- break;
806
- default:
807
- group.otherErrors ??= {};
808
- group.otherErrors[identifier] = typeName;
809
- break;
810
- }
1071
+ group[identifier] = typeName;
811
1072
  }
812
1073
  return group;
813
1074
  }
814
- function resolveResponseType(schema, fallbackName) {
1075
+ function resolveResponseType(schema, fallbackName, nameMap) {
815
1076
  if (typeof schema === "string") {
816
1077
  return schema;
817
1078
  }
818
1079
  if (schema.$ref) {
819
- return extractRefName(schema.$ref);
1080
+ const refName = extractRefName(schema.$ref);
1081
+ return nameMap?.get(refName) || refName;
820
1082
  }
821
1083
  if (schema.type === "array" && schema.items?.$ref) {
822
1084
  const itemRef = extractRefName(schema.items.$ref);
823
- return `z.array(${itemRef})`;
1085
+ const sanitizedItemRef = nameMap?.get(itemRef) || itemRef;
1086
+ return `z.array(${sanitizedItemRef})`;
1087
+ }
1088
+ if (schema.allOf && Array.isArray(schema.allOf)) {
1089
+ return fallbackName;
824
1090
  }
825
1091
  return fallbackName;
826
1092
  }
@@ -903,19 +1169,30 @@ function convertQueryParamValue(schema, accessor) {
903
1169
  return `String(${accessor})`;
904
1170
  }
905
1171
  }
906
- function generateZodSchema(name, schema, generatedTypes, options) {
1172
+ function generateZodSchema(name, schema, generatedTypes, options, nameMap) {
907
1173
  if (generatedTypes.has(name)) return "";
908
1174
  generatedTypes.add(name);
909
1175
  if (schema.enum) {
910
1176
  const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
911
1177
  return `export const ${name} = z.enum([${enumValues}]);`;
912
1178
  }
1179
+ if (schema.allOf && Array.isArray(schema.allOf)) {
1180
+ const allOfParts = schema.allOf.map(
1181
+ (part) => getZodTypeFromSchema(part, options, nameMap)
1182
+ );
1183
+ if (allOfParts.length === 0) return `export const ${name} = z.object({});`;
1184
+ if (allOfParts.length === 1)
1185
+ return `export const ${name} = ${allOfParts[0]};`;
1186
+ const first = allOfParts[0];
1187
+ const rest = allOfParts.slice(1).map((part) => `.and(${part})`).join("");
1188
+ return `export const ${name} = ${first}${rest};`;
1189
+ }
913
1190
  if (schema.type === "object" || schema.properties) {
914
- return `export const ${name} = ${buildZodObject(schema, options)};`;
1191
+ return `export const ${name} = ${buildZodObject(schema, options, nameMap)};`;
915
1192
  }
916
1193
  if (schema.type === "array") {
917
1194
  const itemSchema = schema.items ?? { type: "unknown" };
918
- const itemType = getZodTypeFromSchema(itemSchema, options);
1195
+ const itemType = getZodTypeFromSchema(itemSchema, options, nameMap);
919
1196
  const builder = applyStrictArrayBounds(
920
1197
  schema,
921
1198
  `z.array(${itemType})`,
@@ -924,18 +1201,29 @@ function generateZodSchema(name, schema, generatedTypes, options) {
924
1201
  );
925
1202
  return `export const ${name} = ${builder};`;
926
1203
  }
927
- return `export const ${name} = ${getZodTypeFromSchema(schema, options)};`;
1204
+ return `export const ${name} = ${getZodTypeFromSchema(schema, options, nameMap)};`;
928
1205
  }
929
- function getZodTypeFromSchema(schema, options) {
1206
+ function getZodTypeFromSchema(schema, options, nameMap) {
930
1207
  if (schema.$ref) {
931
- return extractRefName(schema.$ref);
1208
+ const refName = extractRefName(schema.$ref);
1209
+ return nameMap?.get(refName) || refName;
932
1210
  }
933
1211
  if (schema.enum) {
934
1212
  const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
935
1213
  return `z.enum([${enumValues}])`;
936
1214
  }
937
- if (schema.type === "object" || schema.properties) {
938
- return buildZodObject(schema, options);
1215
+ if (schema.allOf && Array.isArray(schema.allOf)) {
1216
+ const allOfParts = schema.allOf.map(
1217
+ (part) => getZodTypeFromSchema(part, options, nameMap)
1218
+ );
1219
+ if (allOfParts.length === 0) return "z.object({})";
1220
+ if (allOfParts.length === 1) return allOfParts[0];
1221
+ const first = allOfParts[0];
1222
+ const rest = allOfParts.slice(1).map((part) => `.and(${part})`).join("");
1223
+ return `${first}${rest}`;
1224
+ }
1225
+ if (schema.type === "object" || schema.properties || schema.allOf || schema.oneOf || schema.anyOf) {
1226
+ return buildZodObject(schema, options, nameMap);
939
1227
  }
940
1228
  switch (schema.type) {
941
1229
  case "string":
@@ -945,7 +1233,8 @@ function getZodTypeFromSchema(schema, options) {
945
1233
  case "array":
946
1234
  return `z.array(${getZodTypeFromSchema(
947
1235
  schema.items ?? { type: "unknown" },
948
- options
1236
+ options,
1237
+ nameMap
949
1238
  )})`;
950
1239
  case "null":
951
1240
  return "z.null()";
@@ -957,13 +1246,13 @@ function getZodTypeFromSchema(schema, options) {
957
1246
  return "z.unknown()";
958
1247
  }
959
1248
  }
960
- function buildZodObject(schema, options) {
1249
+ function buildZodObject(schema, options, nameMap) {
961
1250
  const properties = [];
962
1251
  for (const [propName, propSchema] of Object.entries(
963
1252
  schema.properties || {}
964
1253
  )) {
965
1254
  const isRequired = schema.required?.includes(propName) ?? false;
966
- const zodType = getZodTypeFromSchema(propSchema, options);
1255
+ const zodType = getZodTypeFromSchema(propSchema, options, nameMap);
967
1256
  const finalType = isRequired ? zodType : `${zodType}.optional()`;
968
1257
  properties.push(` ${formatPropertyName(propName)}: ${finalType},`);
969
1258
  }
@@ -1071,57 +1360,6 @@ function applyNumericBounds(schema, builder) {
1071
1360
  }
1072
1361
  return builder;
1073
1362
  }
1074
- function generateHelperFile() {
1075
- const output = [];
1076
- output.push("// Generated helper types for Zenko");
1077
- output.push(
1078
- "// This file provides type definitions for operation objects and path functions"
1079
- );
1080
- output.push("");
1081
- output.push(
1082
- "export type PathFn<TArgs extends unknown[] = []> = (...args: TArgs) => string"
1083
- );
1084
- output.push("");
1085
- output.push(
1086
- 'export type RequestMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"'
1087
- );
1088
- output.push("");
1089
- output.push(
1090
- "export type HeaderFn<TArgs extends unknown[] = [], TResult = Record<string, unknown> | Record<string, never>> = (...args: TArgs) => TResult"
1091
- );
1092
- output.push("");
1093
- output.push(
1094
- "export type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown)"
1095
- );
1096
- output.push("");
1097
- output.push(
1098
- "export type OperationErrors<TClient = unknown, TServer = unknown, TDefault = unknown, TOther = unknown> = {"
1099
- );
1100
- output.push(" clientErrors?: TClient");
1101
- output.push(" serverErrors?: TServer");
1102
- output.push(" defaultErrors?: TDefault");
1103
- output.push(" otherErrors?: TOther");
1104
- output.push("}");
1105
- output.push("");
1106
- output.push(
1107
- "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> = {"
1108
- );
1109
- output.push(" method: TMethod");
1110
- output.push(" path: TPath");
1111
- output.push(" request?: TRequest");
1112
- output.push(" response?: TResponse");
1113
- output.push(" headers?: THeaders");
1114
- output.push(" errors?: TErrors");
1115
- output.push("}");
1116
- output.push("");
1117
- return output.join("\n");
1118
- }
1119
- function toCamelCase(str) {
1120
- return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
1121
- }
1122
- function capitalize(str) {
1123
- return str.charAt(0).toUpperCase() + str.slice(1);
1124
- }
1125
1363
  // Annotate the CommonJS export names for ESM import in node:
1126
1364
  0 && (module.exports = {
1127
1365
  generate