@alt-stack/zod-openapi 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -231,6 +231,9 @@ function isStringRegistration(reg) {
231
231
  function isStringsRegistration(reg) {
232
232
  return reg.type === "string" && "formats" in reg;
233
233
  }
234
+ function isSupportedStringFormat(format) {
235
+ return Object.prototype.hasOwnProperty.call(SUPPORTED_STRING_FORMATS_MAP, format);
236
+ }
234
237
  function getTypeFormatPairs(reg) {
235
238
  if (isStringRegistration(reg)) {
236
239
  return [{ type: "string", format: reg.format }];
@@ -281,6 +284,7 @@ var ZodSchemaRegistry = class {
281
284
  * Reverse-lookup helper: given a string format, return the registered schema's exported variable name
282
285
  */
283
286
  getSchemaExportedVariableNameForStringFormat(format) {
287
+ if (!isSupportedStringFormat(format)) return void 0;
284
288
  for (const registration of this.map.values()) {
285
289
  if (registration.type !== "string") continue;
286
290
  if (isStringRegistration(registration) && registration.format === format) {
@@ -292,6 +296,17 @@ var ZodSchemaRegistry = class {
292
296
  }
293
297
  return void 0;
294
298
  }
299
+ /**
300
+ * Reverse-lookup helper: given a primitive type, return the registered schema's exported variable name
301
+ */
302
+ getSchemaExportedVariableNameForPrimitiveType(type) {
303
+ for (const registration of this.map.values()) {
304
+ if (registration.type === type) {
305
+ return registration.schemaExportedVariableName;
306
+ }
307
+ }
308
+ return void 0;
309
+ }
295
310
  };
296
311
  var schemaRegistry = new ZodSchemaRegistry();
297
312
  function registerZodSchemaToOpenApiSchema(schema, openApiSchema) {
@@ -300,6 +315,9 @@ function registerZodSchemaToOpenApiSchema(schema, openApiSchema) {
300
315
  function getSchemaExportedVariableNameForStringFormat(format) {
301
316
  return schemaRegistry.getSchemaExportedVariableNameForStringFormat(format);
302
317
  }
318
+ function getSchemaExportedVariableNameForPrimitiveType(type) {
319
+ return schemaRegistry.getSchemaExportedVariableNameForPrimitiveType(type);
320
+ }
303
321
  function clearZodSchemaToOpenApiSchemaRegistry() {
304
322
  schemaRegistry.clear();
305
323
  }
@@ -674,7 +692,37 @@ var validIdentifierRegex2 = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
674
692
  function quotePropertyName2(name) {
675
693
  return validIdentifierRegex2.test(name) ? name : `'${name}'`;
676
694
  }
677
- function schemaToTypeString(schema) {
695
+ function toPascalCase2(name) {
696
+ return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[^a-zA-Z0-9]/g, " ").split(" ").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
697
+ }
698
+ function schemaExportNameToOutputAlias(name) {
699
+ return `${toPascalCase2(name)}Output`;
700
+ }
701
+ function registerOutputSchemaName(schemaName, options) {
702
+ options?.outputSchemaNames?.add(schemaName);
703
+ return schemaExportNameToOutputAlias(schemaName);
704
+ }
705
+ function getRegisteredOutputAlias(schema, options) {
706
+ if (!schema || typeof schema !== "object") return void 0;
707
+ if (schema["type"] === "string" && typeof schema["format"] === "string") {
708
+ const customSchemaName = getSchemaExportedVariableNameForStringFormat(
709
+ schema["format"]
710
+ );
711
+ if (customSchemaName) {
712
+ return registerOutputSchemaName(customSchemaName, options);
713
+ }
714
+ }
715
+ if (schema["type"] === "number" || schema["type"] === "integer" || schema["type"] === "boolean") {
716
+ const customSchemaName = getSchemaExportedVariableNameForPrimitiveType(
717
+ schema["type"]
718
+ );
719
+ if (customSchemaName) {
720
+ return registerOutputSchemaName(customSchemaName, options);
721
+ }
722
+ }
723
+ return void 0;
724
+ }
725
+ function schemaToTypeString(schema, options) {
678
726
  if (!schema || typeof schema !== "object") return "unknown";
679
727
  if (schema["$ref"] && typeof schema["$ref"] === "string") {
680
728
  const match = schema["$ref"].match(
@@ -692,56 +740,64 @@ function schemaToTypeString(schema) {
692
740
  let result = "unknown";
693
741
  if ("oneOf" in schema && Array.isArray(schema["oneOf"])) {
694
742
  const unionMembers = schema["oneOf"].map(
695
- (s) => schemaToTypeString(s)
743
+ (s) => schemaToTypeString(s, options)
696
744
  );
697
745
  result = unionMembers.length > 1 ? `(${unionMembers.join(" | ")})` : unionMembers[0] ?? "unknown";
698
746
  } else if ("allOf" in schema && Array.isArray(schema["allOf"])) {
699
747
  const intersectionMembers = schema["allOf"].map(
700
- (s) => schemaToTypeString(s)
748
+ (s) => schemaToTypeString(s, options)
701
749
  );
702
750
  result = intersectionMembers.length > 1 ? `(${intersectionMembers.join(" & ")})` : intersectionMembers[0] ?? "unknown";
703
751
  } else if ("anyOf" in schema && Array.isArray(schema["anyOf"])) {
704
752
  const unionMembers = schema["anyOf"].map(
705
- (s) => schemaToTypeString(s)
753
+ (s) => schemaToTypeString(s, options)
706
754
  );
707
755
  result = unionMembers.length > 1 ? `(${unionMembers.join(" | ")})` : unionMembers[0] ?? "unknown";
708
756
  } else {
709
757
  switch (schema["type"]) {
710
- case "string":
711
- if (schema["enum"] && Array.isArray(schema["enum"])) {
758
+ case "string": {
759
+ const registeredAlias = getRegisteredOutputAlias(schema, options);
760
+ if (registeredAlias) {
761
+ result = registeredAlias;
762
+ } else if (schema["enum"] && Array.isArray(schema["enum"])) {
712
763
  result = schema["enum"].map((v) => JSON.stringify(v)).join(" | ");
713
764
  } else {
714
765
  result = "string";
715
766
  }
716
767
  break;
768
+ }
717
769
  case "number":
718
- case "integer":
719
- if (schema["enum"] && Array.isArray(schema["enum"])) {
770
+ case "integer": {
771
+ const registeredAlias = getRegisteredOutputAlias(schema, options);
772
+ if (registeredAlias) {
773
+ result = registeredAlias;
774
+ } else if (schema["enum"] && Array.isArray(schema["enum"])) {
720
775
  result = schema["enum"].map((v) => String(v)).join(" | ");
721
776
  } else {
722
777
  result = "number";
723
778
  }
724
779
  break;
780
+ }
725
781
  case "boolean":
726
- result = "boolean";
782
+ result = getRegisteredOutputAlias(schema, options) ?? "boolean";
727
783
  break;
728
784
  case "null":
729
785
  result = "null";
730
786
  break;
731
787
  case "array":
732
788
  if (schema["items"]) {
733
- const itemType = schemaToTypeString(schema["items"]);
789
+ const itemType = schemaToTypeString(schema["items"], options);
734
790
  result = `Array<${itemType}>`;
735
791
  } else {
736
792
  result = "unknown[]";
737
793
  }
738
794
  break;
739
795
  case "object":
740
- result = objectSchemaToTypeString(schema);
796
+ result = objectSchemaToTypeString(schema, options);
741
797
  break;
742
798
  default:
743
799
  if (schema["properties"]) {
744
- result = objectSchemaToTypeString(schema);
800
+ result = objectSchemaToTypeString(schema, options);
745
801
  } else if (schema["enum"] && Array.isArray(schema["enum"])) {
746
802
  result = schema["enum"].map((v) => JSON.stringify(v)).join(" | ");
747
803
  } else {
@@ -755,7 +811,7 @@ function schemaToTypeString(schema) {
755
811
  }
756
812
  return result;
757
813
  }
758
- function objectSchemaToTypeString(schema) {
814
+ function objectSchemaToTypeString(schema, options) {
759
815
  const properties = schema["properties"];
760
816
  const required = new Set(schema["required"] ?? []);
761
817
  const additionalProperties = schema["additionalProperties"];
@@ -766,7 +822,7 @@ function objectSchemaToTypeString(schema) {
766
822
  if (properties) {
767
823
  for (const [propName, propSchema] of Object.entries(properties)) {
768
824
  const isRequired = required.has(propName);
769
- const propType = schemaToTypeString(propSchema);
825
+ const propType = schemaToTypeString(propSchema, options);
770
826
  const quotedName = quotePropertyName2(propName);
771
827
  propertyStrings.push(
772
828
  `${quotedName}${isRequired ? "" : "?"}: ${propType}`
@@ -776,23 +832,23 @@ function objectSchemaToTypeString(schema) {
776
832
  if (additionalProperties === true) {
777
833
  propertyStrings.push("[key: string]: unknown");
778
834
  } else if (typeof additionalProperties === "object" && additionalProperties !== null) {
779
- const additionalType = schemaToTypeString(additionalProperties);
835
+ const additionalType = schemaToTypeString(additionalProperties, options);
780
836
  propertyStrings.push(`[key: string]: ${additionalType}`);
781
837
  }
782
838
  return `{ ${propertyStrings.join("; ")} }`;
783
839
  }
784
- function generateInterface(name, schema) {
840
+ function generateInterface(name, schema, options) {
785
841
  const properties = schema["properties"];
786
842
  const required = new Set(schema["required"] ?? []);
787
843
  if (schema["type"] !== "object" && !properties) {
788
- return `export type ${name} = ${schemaToTypeString(schema)};`;
844
+ return `export type ${name} = ${schemaToTypeString(schema, options)};`;
789
845
  }
790
846
  const lines = [];
791
847
  lines.push(`export interface ${name} {`);
792
848
  if (properties) {
793
849
  for (const [propName, propSchema] of Object.entries(properties)) {
794
850
  const isRequired = required.has(propName);
795
- const propType = schemaToTypeString(propSchema);
851
+ const propType = schemaToTypeString(propSchema, options);
796
852
  const quotedName = quotePropertyName2(propName);
797
853
  lines.push(` ${quotedName}${isRequired ? "" : "?"}: ${propType};`);
798
854
  }
@@ -801,7 +857,7 @@ function generateInterface(name, schema) {
801
857
  if (additionalProperties === true) {
802
858
  lines.push(" [key: string]: unknown;");
803
859
  } else if (typeof additionalProperties === "object" && additionalProperties !== null) {
804
- const additionalType = schemaToTypeString(additionalProperties);
860
+ const additionalType = schemaToTypeString(additionalProperties, options);
805
861
  lines.push(` [key: string]: ${additionalType};`);
806
862
  }
807
863
  lines.push("}");
@@ -1127,20 +1183,31 @@ var openApiToZodTsCode = (openapi, customImportLines, options) => {
1127
1183
  const registry = createSchemaRegistry();
1128
1184
  const sortedSchemaNames = topologicalSortSchemas(schemas);
1129
1185
  const typeAssertions = [];
1186
+ const outputSchemaNames = /* @__PURE__ */ new Set();
1187
+ const schemaBlocks = [];
1130
1188
  for (const name of sortedSchemaNames) {
1131
1189
  const schema = schemas[name];
1132
1190
  if (schema) {
1133
1191
  const zodExpr = convertSchemaToZodString(schema);
1134
1192
  const schemaName = `${name}Schema`;
1135
1193
  const typeName = name;
1136
- lines.push(generateInterface(typeName, schema));
1137
- lines.push(`export const ${schemaName}: z.ZodType<${typeName}> = ${zodExpr};`);
1138
- lines.push("");
1194
+ schemaBlocks.push(generateInterface(typeName, schema, { outputSchemaNames }));
1195
+ schemaBlocks.push(`export const ${schemaName} = ${zodExpr};`);
1196
+ schemaBlocks.push("");
1139
1197
  typeAssertions.push(`type _Assert${typeName} = _AssertEqual<${typeName}, z.infer<typeof ${schemaName}>>;`);
1140
1198
  const fingerprint = getSchemaFingerprint(schema);
1141
1199
  preRegisterSchema(registry, schemaName, fingerprint);
1142
1200
  }
1143
1201
  }
1202
+ if (outputSchemaNames.size > 0) {
1203
+ lines.push("// Zod output aliases for registered schemas");
1204
+ for (const schemaName of outputSchemaNames) {
1205
+ const aliasName = schemaExportNameToOutputAlias(schemaName);
1206
+ lines.push(`type ${aliasName} = z.output<typeof ${schemaName}>;`);
1207
+ }
1208
+ lines.push("");
1209
+ }
1210
+ lines.push(...schemaBlocks);
1144
1211
  if (typeAssertions.length > 0) {
1145
1212
  lines.push("// Compile-time type assertions - ensure interfaces match schemas");
1146
1213
  lines.push(typeAssertions.join("\n"));