@alt-stack/zod-openapi 1.2.0 → 1.3.0
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/.turbo/turbo-build.log +9 -9
- package/dist/index.cjs +89 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +89 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/interface-generator.spec.ts +74 -1
- package/src/interface-generator.ts +98 -19
- package/src/registry.ts +32 -2
- package/src/to-typescript.spec.ts +60 -0
- package/src/to-typescript.ts +17 -4
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @alt-stack/zod-openapi@1.
|
|
2
|
+
> @alt-stack/zod-openapi@1.3.0 build /home/runner/work/alt-stack/alt-stack/packages/zod-openapi
|
|
3
3
|
> tsup
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[32mESM[39m ⚡️ Build success in 32ms
|
|
16
|
-
[32mCJS[39m [1mdist/index.cjs [22m[32m39.98 KB[39m
|
|
17
|
-
[32mCJS[39m [1mdist/index.cjs.map [22m[32m85.09 KB[39m
|
|
13
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m42.75 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.cjs.map [22m[32m90.45 KB[39m
|
|
18
15
|
[32mCJS[39m ⚡️ Build success in 33ms
|
|
16
|
+
[32mESM[39m [1mdist/index.js [22m[32m41.13 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.js.map [22m[32m89.49 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 33ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.cts [22m[
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 1429ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m6.06 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.cts [22m[32m6.06 KB[39m
|
package/dist/index.cjs
CHANGED
|
@@ -267,6 +267,9 @@ function isStringRegistration(reg) {
|
|
|
267
267
|
function isStringsRegistration(reg) {
|
|
268
268
|
return reg.type === "string" && "formats" in reg;
|
|
269
269
|
}
|
|
270
|
+
function isSupportedStringFormat(format) {
|
|
271
|
+
return Object.prototype.hasOwnProperty.call(SUPPORTED_STRING_FORMATS_MAP, format);
|
|
272
|
+
}
|
|
270
273
|
function getTypeFormatPairs(reg) {
|
|
271
274
|
if (isStringRegistration(reg)) {
|
|
272
275
|
return [{ type: "string", format: reg.format }];
|
|
@@ -317,6 +320,7 @@ var ZodSchemaRegistry = class {
|
|
|
317
320
|
* Reverse-lookup helper: given a string format, return the registered schema's exported variable name
|
|
318
321
|
*/
|
|
319
322
|
getSchemaExportedVariableNameForStringFormat(format) {
|
|
323
|
+
if (!isSupportedStringFormat(format)) return void 0;
|
|
320
324
|
for (const registration of this.map.values()) {
|
|
321
325
|
if (registration.type !== "string") continue;
|
|
322
326
|
if (isStringRegistration(registration) && registration.format === format) {
|
|
@@ -328,6 +332,17 @@ var ZodSchemaRegistry = class {
|
|
|
328
332
|
}
|
|
329
333
|
return void 0;
|
|
330
334
|
}
|
|
335
|
+
/**
|
|
336
|
+
* Reverse-lookup helper: given a primitive type, return the registered schema's exported variable name
|
|
337
|
+
*/
|
|
338
|
+
getSchemaExportedVariableNameForPrimitiveType(type) {
|
|
339
|
+
for (const registration of this.map.values()) {
|
|
340
|
+
if (registration.type === type) {
|
|
341
|
+
return registration.schemaExportedVariableName;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return void 0;
|
|
345
|
+
}
|
|
331
346
|
};
|
|
332
347
|
var schemaRegistry = new ZodSchemaRegistry();
|
|
333
348
|
function registerZodSchemaToOpenApiSchema(schema, openApiSchema) {
|
|
@@ -336,6 +351,9 @@ function registerZodSchemaToOpenApiSchema(schema, openApiSchema) {
|
|
|
336
351
|
function getSchemaExportedVariableNameForStringFormat(format) {
|
|
337
352
|
return schemaRegistry.getSchemaExportedVariableNameForStringFormat(format);
|
|
338
353
|
}
|
|
354
|
+
function getSchemaExportedVariableNameForPrimitiveType(type) {
|
|
355
|
+
return schemaRegistry.getSchemaExportedVariableNameForPrimitiveType(type);
|
|
356
|
+
}
|
|
339
357
|
function clearZodSchemaToOpenApiSchemaRegistry() {
|
|
340
358
|
schemaRegistry.clear();
|
|
341
359
|
}
|
|
@@ -710,7 +728,37 @@ var validIdentifierRegex2 = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
|
710
728
|
function quotePropertyName2(name) {
|
|
711
729
|
return validIdentifierRegex2.test(name) ? name : `'${name}'`;
|
|
712
730
|
}
|
|
713
|
-
function
|
|
731
|
+
function toPascalCase2(name) {
|
|
732
|
+
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("");
|
|
733
|
+
}
|
|
734
|
+
function schemaExportNameToOutputAlias(name) {
|
|
735
|
+
return `${toPascalCase2(name)}Output`;
|
|
736
|
+
}
|
|
737
|
+
function registerOutputSchemaName(schemaName, options) {
|
|
738
|
+
options?.outputSchemaNames?.add(schemaName);
|
|
739
|
+
return schemaExportNameToOutputAlias(schemaName);
|
|
740
|
+
}
|
|
741
|
+
function getRegisteredOutputAlias(schema, options) {
|
|
742
|
+
if (!schema || typeof schema !== "object") return void 0;
|
|
743
|
+
if (schema["type"] === "string" && typeof schema["format"] === "string") {
|
|
744
|
+
const customSchemaName = getSchemaExportedVariableNameForStringFormat(
|
|
745
|
+
schema["format"]
|
|
746
|
+
);
|
|
747
|
+
if (customSchemaName) {
|
|
748
|
+
return registerOutputSchemaName(customSchemaName, options);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (schema["type"] === "number" || schema["type"] === "integer" || schema["type"] === "boolean") {
|
|
752
|
+
const customSchemaName = getSchemaExportedVariableNameForPrimitiveType(
|
|
753
|
+
schema["type"]
|
|
754
|
+
);
|
|
755
|
+
if (customSchemaName) {
|
|
756
|
+
return registerOutputSchemaName(customSchemaName, options);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return void 0;
|
|
760
|
+
}
|
|
761
|
+
function schemaToTypeString(schema, options) {
|
|
714
762
|
if (!schema || typeof schema !== "object") return "unknown";
|
|
715
763
|
if (schema["$ref"] && typeof schema["$ref"] === "string") {
|
|
716
764
|
const match = schema["$ref"].match(
|
|
@@ -728,56 +776,64 @@ function schemaToTypeString(schema) {
|
|
|
728
776
|
let result = "unknown";
|
|
729
777
|
if ("oneOf" in schema && Array.isArray(schema["oneOf"])) {
|
|
730
778
|
const unionMembers = schema["oneOf"].map(
|
|
731
|
-
(s) => schemaToTypeString(s)
|
|
779
|
+
(s) => schemaToTypeString(s, options)
|
|
732
780
|
);
|
|
733
781
|
result = unionMembers.length > 1 ? `(${unionMembers.join(" | ")})` : unionMembers[0] ?? "unknown";
|
|
734
782
|
} else if ("allOf" in schema && Array.isArray(schema["allOf"])) {
|
|
735
783
|
const intersectionMembers = schema["allOf"].map(
|
|
736
|
-
(s) => schemaToTypeString(s)
|
|
784
|
+
(s) => schemaToTypeString(s, options)
|
|
737
785
|
);
|
|
738
786
|
result = intersectionMembers.length > 1 ? `(${intersectionMembers.join(" & ")})` : intersectionMembers[0] ?? "unknown";
|
|
739
787
|
} else if ("anyOf" in schema && Array.isArray(schema["anyOf"])) {
|
|
740
788
|
const unionMembers = schema["anyOf"].map(
|
|
741
|
-
(s) => schemaToTypeString(s)
|
|
789
|
+
(s) => schemaToTypeString(s, options)
|
|
742
790
|
);
|
|
743
791
|
result = unionMembers.length > 1 ? `(${unionMembers.join(" | ")})` : unionMembers[0] ?? "unknown";
|
|
744
792
|
} else {
|
|
745
793
|
switch (schema["type"]) {
|
|
746
|
-
case "string":
|
|
747
|
-
|
|
794
|
+
case "string": {
|
|
795
|
+
const registeredAlias = getRegisteredOutputAlias(schema, options);
|
|
796
|
+
if (registeredAlias) {
|
|
797
|
+
result = registeredAlias;
|
|
798
|
+
} else if (schema["enum"] && Array.isArray(schema["enum"])) {
|
|
748
799
|
result = schema["enum"].map((v) => JSON.stringify(v)).join(" | ");
|
|
749
800
|
} else {
|
|
750
801
|
result = "string";
|
|
751
802
|
}
|
|
752
803
|
break;
|
|
804
|
+
}
|
|
753
805
|
case "number":
|
|
754
|
-
case "integer":
|
|
755
|
-
|
|
806
|
+
case "integer": {
|
|
807
|
+
const registeredAlias = getRegisteredOutputAlias(schema, options);
|
|
808
|
+
if (registeredAlias) {
|
|
809
|
+
result = registeredAlias;
|
|
810
|
+
} else if (schema["enum"] && Array.isArray(schema["enum"])) {
|
|
756
811
|
result = schema["enum"].map((v) => String(v)).join(" | ");
|
|
757
812
|
} else {
|
|
758
813
|
result = "number";
|
|
759
814
|
}
|
|
760
815
|
break;
|
|
816
|
+
}
|
|
761
817
|
case "boolean":
|
|
762
|
-
result = "boolean";
|
|
818
|
+
result = getRegisteredOutputAlias(schema, options) ?? "boolean";
|
|
763
819
|
break;
|
|
764
820
|
case "null":
|
|
765
821
|
result = "null";
|
|
766
822
|
break;
|
|
767
823
|
case "array":
|
|
768
824
|
if (schema["items"]) {
|
|
769
|
-
const itemType = schemaToTypeString(schema["items"]);
|
|
825
|
+
const itemType = schemaToTypeString(schema["items"], options);
|
|
770
826
|
result = `Array<${itemType}>`;
|
|
771
827
|
} else {
|
|
772
828
|
result = "unknown[]";
|
|
773
829
|
}
|
|
774
830
|
break;
|
|
775
831
|
case "object":
|
|
776
|
-
result = objectSchemaToTypeString(schema);
|
|
832
|
+
result = objectSchemaToTypeString(schema, options);
|
|
777
833
|
break;
|
|
778
834
|
default:
|
|
779
835
|
if (schema["properties"]) {
|
|
780
|
-
result = objectSchemaToTypeString(schema);
|
|
836
|
+
result = objectSchemaToTypeString(schema, options);
|
|
781
837
|
} else if (schema["enum"] && Array.isArray(schema["enum"])) {
|
|
782
838
|
result = schema["enum"].map((v) => JSON.stringify(v)).join(" | ");
|
|
783
839
|
} else {
|
|
@@ -791,7 +847,7 @@ function schemaToTypeString(schema) {
|
|
|
791
847
|
}
|
|
792
848
|
return result;
|
|
793
849
|
}
|
|
794
|
-
function objectSchemaToTypeString(schema) {
|
|
850
|
+
function objectSchemaToTypeString(schema, options) {
|
|
795
851
|
const properties = schema["properties"];
|
|
796
852
|
const required = new Set(schema["required"] ?? []);
|
|
797
853
|
const additionalProperties = schema["additionalProperties"];
|
|
@@ -802,7 +858,7 @@ function objectSchemaToTypeString(schema) {
|
|
|
802
858
|
if (properties) {
|
|
803
859
|
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
804
860
|
const isRequired = required.has(propName);
|
|
805
|
-
const propType = schemaToTypeString(propSchema);
|
|
861
|
+
const propType = schemaToTypeString(propSchema, options);
|
|
806
862
|
const quotedName = quotePropertyName2(propName);
|
|
807
863
|
propertyStrings.push(
|
|
808
864
|
`${quotedName}${isRequired ? "" : "?"}: ${propType}`
|
|
@@ -812,23 +868,23 @@ function objectSchemaToTypeString(schema) {
|
|
|
812
868
|
if (additionalProperties === true) {
|
|
813
869
|
propertyStrings.push("[key: string]: unknown");
|
|
814
870
|
} else if (typeof additionalProperties === "object" && additionalProperties !== null) {
|
|
815
|
-
const additionalType = schemaToTypeString(additionalProperties);
|
|
871
|
+
const additionalType = schemaToTypeString(additionalProperties, options);
|
|
816
872
|
propertyStrings.push(`[key: string]: ${additionalType}`);
|
|
817
873
|
}
|
|
818
874
|
return `{ ${propertyStrings.join("; ")} }`;
|
|
819
875
|
}
|
|
820
|
-
function generateInterface(name, schema) {
|
|
876
|
+
function generateInterface(name, schema, options) {
|
|
821
877
|
const properties = schema["properties"];
|
|
822
878
|
const required = new Set(schema["required"] ?? []);
|
|
823
879
|
if (schema["type"] !== "object" && !properties) {
|
|
824
|
-
return `export type ${name} = ${schemaToTypeString(schema)};`;
|
|
880
|
+
return `export type ${name} = ${schemaToTypeString(schema, options)};`;
|
|
825
881
|
}
|
|
826
882
|
const lines = [];
|
|
827
883
|
lines.push(`export interface ${name} {`);
|
|
828
884
|
if (properties) {
|
|
829
885
|
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
830
886
|
const isRequired = required.has(propName);
|
|
831
|
-
const propType = schemaToTypeString(propSchema);
|
|
887
|
+
const propType = schemaToTypeString(propSchema, options);
|
|
832
888
|
const quotedName = quotePropertyName2(propName);
|
|
833
889
|
lines.push(` ${quotedName}${isRequired ? "" : "?"}: ${propType};`);
|
|
834
890
|
}
|
|
@@ -837,7 +893,7 @@ function generateInterface(name, schema) {
|
|
|
837
893
|
if (additionalProperties === true) {
|
|
838
894
|
lines.push(" [key: string]: unknown;");
|
|
839
895
|
} else if (typeof additionalProperties === "object" && additionalProperties !== null) {
|
|
840
|
-
const additionalType = schemaToTypeString(additionalProperties);
|
|
896
|
+
const additionalType = schemaToTypeString(additionalProperties, options);
|
|
841
897
|
lines.push(` [key: string]: ${additionalType};`);
|
|
842
898
|
}
|
|
843
899
|
lines.push("}");
|
|
@@ -1163,20 +1219,31 @@ var openApiToZodTsCode = (openapi, customImportLines, options) => {
|
|
|
1163
1219
|
const registry = createSchemaRegistry();
|
|
1164
1220
|
const sortedSchemaNames = topologicalSortSchemas(schemas);
|
|
1165
1221
|
const typeAssertions = [];
|
|
1222
|
+
const outputSchemaNames = /* @__PURE__ */ new Set();
|
|
1223
|
+
const schemaBlocks = [];
|
|
1166
1224
|
for (const name of sortedSchemaNames) {
|
|
1167
1225
|
const schema = schemas[name];
|
|
1168
1226
|
if (schema) {
|
|
1169
1227
|
const zodExpr = convertSchemaToZodString(schema);
|
|
1170
1228
|
const schemaName = `${name}Schema`;
|
|
1171
1229
|
const typeName = name;
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1230
|
+
schemaBlocks.push(generateInterface(typeName, schema, { outputSchemaNames }));
|
|
1231
|
+
schemaBlocks.push(`export const ${schemaName}: z.ZodType<${typeName}> = ${zodExpr};`);
|
|
1232
|
+
schemaBlocks.push("");
|
|
1175
1233
|
typeAssertions.push(`type _Assert${typeName} = _AssertEqual<${typeName}, z.infer<typeof ${schemaName}>>;`);
|
|
1176
1234
|
const fingerprint = getSchemaFingerprint(schema);
|
|
1177
1235
|
preRegisterSchema(registry, schemaName, fingerprint);
|
|
1178
1236
|
}
|
|
1179
1237
|
}
|
|
1238
|
+
if (outputSchemaNames.size > 0) {
|
|
1239
|
+
lines.push("// Zod output aliases for registered schemas");
|
|
1240
|
+
for (const schemaName of outputSchemaNames) {
|
|
1241
|
+
const aliasName = schemaExportNameToOutputAlias(schemaName);
|
|
1242
|
+
lines.push(`type ${aliasName} = z.output<typeof ${schemaName}>;`);
|
|
1243
|
+
}
|
|
1244
|
+
lines.push("");
|
|
1245
|
+
}
|
|
1246
|
+
lines.push(...schemaBlocks);
|
|
1180
1247
|
if (typeAssertions.length > 0) {
|
|
1181
1248
|
lines.push("// Compile-time type assertions - ensure interfaces match schemas");
|
|
1182
1249
|
lines.push(typeAssertions.join("\n"));
|