@alt-stack/zod-openapi 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +331 -0
- package/bin/zod-openapi.js +28 -0
- package/dist/index.d.mts +120 -0
- package/dist/index.d.ts +120 -0
- package/dist/index.js +860 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +825 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +35 -0
- package/src/cli.ts +105 -0
- package/src/dependencies.spec.ts +440 -0
- package/src/dependencies.ts +176 -0
- package/src/index.ts +27 -0
- package/src/registry.spec.ts +308 -0
- package/src/registry.ts +227 -0
- package/src/routes.ts +231 -0
- package/src/to-typescript.spec.ts +474 -0
- package/src/to-typescript.ts +289 -0
- package/src/to-zod.spec.ts +480 -0
- package/src/to-zod.ts +112 -0
- package/src/types/array.spec.ts +222 -0
- package/src/types/array.ts +29 -0
- package/src/types/boolean.spec.ts +18 -0
- package/src/types/boolean.ts +6 -0
- package/src/types/intersection.spec.ts +108 -0
- package/src/types/intersection.ts +14 -0
- package/src/types/number.spec.ts +127 -0
- package/src/types/number.ts +20 -0
- package/src/types/object.spec.ts +302 -0
- package/src/types/object.ts +41 -0
- package/src/types/string.spec.ts +431 -0
- package/src/types/string.ts +75 -0
- package/src/types/types.ts +10 -0
- package/src/types/union.spec.ts +135 -0
- package/src/types/union.ts +10 -0
- package/tsconfig.json +12 -0
- package/tsup.config.ts +11 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { convertOpenAPIArrayToZod } from "./array";
|
|
3
|
+
import type { AnySchema } from "./types";
|
|
4
|
+
|
|
5
|
+
describe("convertOpenAPIArrayToZod", () => {
|
|
6
|
+
const mockConvertSchema = (schema: AnySchema): string => {
|
|
7
|
+
if (schema.type === "string") return "z.string()";
|
|
8
|
+
if (schema.type === "number") return "z.number()";
|
|
9
|
+
if (schema.type === "boolean") return "z.boolean()";
|
|
10
|
+
return "z.unknown()";
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
describe("array without items", () => {
|
|
14
|
+
it("should convert array schema without items definition", () => {
|
|
15
|
+
const result = convertOpenAPIArrayToZod(
|
|
16
|
+
{ type: "array" },
|
|
17
|
+
mockConvertSchema,
|
|
18
|
+
);
|
|
19
|
+
expect(result).toBe("z.array(z.unknown())");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should convert array without items but with constraints", () => {
|
|
23
|
+
const result = convertOpenAPIArrayToZod(
|
|
24
|
+
{
|
|
25
|
+
type: "array",
|
|
26
|
+
minItems: 1,
|
|
27
|
+
maxItems: 10,
|
|
28
|
+
},
|
|
29
|
+
mockConvertSchema,
|
|
30
|
+
);
|
|
31
|
+
expect(result).toBe("z.array(z.unknown()).min(1).max(10)");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("array with items", () => {
|
|
36
|
+
it("should convert array with string items", () => {
|
|
37
|
+
const result = convertOpenAPIArrayToZod(
|
|
38
|
+
{
|
|
39
|
+
type: "array",
|
|
40
|
+
items: { type: "string" },
|
|
41
|
+
},
|
|
42
|
+
mockConvertSchema,
|
|
43
|
+
);
|
|
44
|
+
expect(result).toBe("z.array(z.string())");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should convert array with number items", () => {
|
|
48
|
+
const result = convertOpenAPIArrayToZod(
|
|
49
|
+
{
|
|
50
|
+
type: "array",
|
|
51
|
+
items: { type: "number" },
|
|
52
|
+
},
|
|
53
|
+
mockConvertSchema,
|
|
54
|
+
);
|
|
55
|
+
expect(result).toBe("z.array(z.number())");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should convert array with boolean items", () => {
|
|
59
|
+
const result = convertOpenAPIArrayToZod(
|
|
60
|
+
{
|
|
61
|
+
type: "array",
|
|
62
|
+
items: { type: "boolean" },
|
|
63
|
+
},
|
|
64
|
+
mockConvertSchema,
|
|
65
|
+
);
|
|
66
|
+
expect(result).toBe("z.array(z.boolean())");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should convert array with unknown items when items type is unrecognized", () => {
|
|
70
|
+
const result = convertOpenAPIArrayToZod(
|
|
71
|
+
{
|
|
72
|
+
type: "array",
|
|
73
|
+
items: { type: "unknown-type" },
|
|
74
|
+
},
|
|
75
|
+
mockConvertSchema,
|
|
76
|
+
);
|
|
77
|
+
expect(result).toBe("z.array(z.unknown())");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("array with minItems constraint", () => {
|
|
82
|
+
it("should apply minItems constraint", () => {
|
|
83
|
+
const result = convertOpenAPIArrayToZod(
|
|
84
|
+
{
|
|
85
|
+
type: "array",
|
|
86
|
+
items: { type: "string" },
|
|
87
|
+
minItems: 1,
|
|
88
|
+
},
|
|
89
|
+
mockConvertSchema,
|
|
90
|
+
);
|
|
91
|
+
expect(result).toBe("z.array(z.string()).min(1)");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should handle minItems of 0", () => {
|
|
95
|
+
const result = convertOpenAPIArrayToZod(
|
|
96
|
+
{
|
|
97
|
+
type: "array",
|
|
98
|
+
items: { type: "string" },
|
|
99
|
+
minItems: 0,
|
|
100
|
+
},
|
|
101
|
+
mockConvertSchema,
|
|
102
|
+
);
|
|
103
|
+
expect(result).toBe("z.array(z.string()).min(0)");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should handle large minItems value", () => {
|
|
107
|
+
const result = convertOpenAPIArrayToZod(
|
|
108
|
+
{
|
|
109
|
+
type: "array",
|
|
110
|
+
items: { type: "number" },
|
|
111
|
+
minItems: 100,
|
|
112
|
+
},
|
|
113
|
+
mockConvertSchema,
|
|
114
|
+
);
|
|
115
|
+
expect(result).toBe("z.array(z.number()).min(100)");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("array with maxItems constraint", () => {
|
|
120
|
+
it("should apply maxItems constraint", () => {
|
|
121
|
+
const result = convertOpenAPIArrayToZod(
|
|
122
|
+
{
|
|
123
|
+
type: "array",
|
|
124
|
+
items: { type: "string" },
|
|
125
|
+
maxItems: 10,
|
|
126
|
+
},
|
|
127
|
+
mockConvertSchema,
|
|
128
|
+
);
|
|
129
|
+
expect(result).toBe("z.array(z.string()).max(10)");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("should handle maxItems of 0", () => {
|
|
133
|
+
const result = convertOpenAPIArrayToZod(
|
|
134
|
+
{
|
|
135
|
+
type: "array",
|
|
136
|
+
items: { type: "string" },
|
|
137
|
+
maxItems: 0,
|
|
138
|
+
},
|
|
139
|
+
mockConvertSchema,
|
|
140
|
+
);
|
|
141
|
+
expect(result).toBe("z.array(z.string()).max(0)");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("should handle large maxItems value", () => {
|
|
145
|
+
const result = convertOpenAPIArrayToZod(
|
|
146
|
+
{
|
|
147
|
+
type: "array",
|
|
148
|
+
items: { type: "number" },
|
|
149
|
+
maxItems: 1000,
|
|
150
|
+
},
|
|
151
|
+
mockConvertSchema,
|
|
152
|
+
);
|
|
153
|
+
expect(result).toBe("z.array(z.number()).max(1000)");
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("array with both minItems and maxItems", () => {
|
|
158
|
+
it("should apply both minItems and maxItems constraints", () => {
|
|
159
|
+
const result = convertOpenAPIArrayToZod(
|
|
160
|
+
{
|
|
161
|
+
type: "array",
|
|
162
|
+
items: { type: "string" },
|
|
163
|
+
minItems: 1,
|
|
164
|
+
maxItems: 10,
|
|
165
|
+
},
|
|
166
|
+
mockConvertSchema,
|
|
167
|
+
);
|
|
168
|
+
expect(result).toBe("z.array(z.string()).min(1).max(10)");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("should maintain order: array, min, max", () => {
|
|
172
|
+
const result = convertOpenAPIArrayToZod(
|
|
173
|
+
{
|
|
174
|
+
type: "array",
|
|
175
|
+
items: { type: "number" },
|
|
176
|
+
maxItems: 100,
|
|
177
|
+
minItems: 5,
|
|
178
|
+
},
|
|
179
|
+
mockConvertSchema,
|
|
180
|
+
);
|
|
181
|
+
expect(result).toBe("z.array(z.number()).min(5).max(100)");
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe("edge cases", () => {
|
|
186
|
+
it("should handle items as null", () => {
|
|
187
|
+
const result = convertOpenAPIArrayToZod(
|
|
188
|
+
{
|
|
189
|
+
type: "array",
|
|
190
|
+
items: null,
|
|
191
|
+
},
|
|
192
|
+
mockConvertSchema,
|
|
193
|
+
);
|
|
194
|
+
expect(result).toBe("z.array(z.unknown())");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("should handle items as primitive value", () => {
|
|
198
|
+
const result = convertOpenAPIArrayToZod(
|
|
199
|
+
{
|
|
200
|
+
type: "array",
|
|
201
|
+
items: "invalid",
|
|
202
|
+
},
|
|
203
|
+
mockConvertSchema,
|
|
204
|
+
);
|
|
205
|
+
expect(result).toBe("z.array(z.unknown())");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("should not apply constraints when undefined", () => {
|
|
209
|
+
const result = convertOpenAPIArrayToZod(
|
|
210
|
+
{
|
|
211
|
+
type: "array",
|
|
212
|
+
items: { type: "string" },
|
|
213
|
+
minItems: undefined,
|
|
214
|
+
maxItems: undefined,
|
|
215
|
+
},
|
|
216
|
+
mockConvertSchema,
|
|
217
|
+
);
|
|
218
|
+
expect(result).toBe("z.array(z.string())");
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AnySchema } from "./types";
|
|
2
|
+
|
|
3
|
+
export function convertOpenAPIArrayToZod(
|
|
4
|
+
schema: {
|
|
5
|
+
type: "array";
|
|
6
|
+
items?: any;
|
|
7
|
+
minItems?: number;
|
|
8
|
+
maxItems?: number;
|
|
9
|
+
},
|
|
10
|
+
convertSchema: (schema: AnySchema) => string,
|
|
11
|
+
): string {
|
|
12
|
+
const item = schema.items;
|
|
13
|
+
|
|
14
|
+
let itemZodString = "z.unknown()";
|
|
15
|
+
if (item && typeof item === "object") {
|
|
16
|
+
itemZodString = convertSchema(item);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let result = `z.array(${itemZodString})`;
|
|
20
|
+
|
|
21
|
+
if (typeof schema.minItems === "number") {
|
|
22
|
+
result += `.min(${schema.minItems})`;
|
|
23
|
+
}
|
|
24
|
+
if (typeof schema.maxItems === "number") {
|
|
25
|
+
result += `.max(${schema.maxItems})`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { convertOpenAPIBooleanToZod } from "./boolean";
|
|
3
|
+
|
|
4
|
+
describe("convertOpenAPIBooleanToZod", () => {
|
|
5
|
+
it("should convert a boolean schema", () => {
|
|
6
|
+
const result = convertOpenAPIBooleanToZod({ type: "boolean" });
|
|
7
|
+
expect(result).toBe("z.boolean()");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should always return the same result regardless of input", () => {
|
|
11
|
+
const result1 = convertOpenAPIBooleanToZod({ type: "boolean" });
|
|
12
|
+
const result2 = convertOpenAPIBooleanToZod({ type: "boolean" });
|
|
13
|
+
expect(result1).toBe("z.boolean()");
|
|
14
|
+
expect(result2).toBe("z.boolean()");
|
|
15
|
+
expect(result1).toBe(result2);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { convertOpenAPIIntersectionToZod } from "./intersection";
|
|
3
|
+
import type { AnySchema } from "./types";
|
|
4
|
+
|
|
5
|
+
describe("convertOpenAPIIntersectionToZod", () => {
|
|
6
|
+
const mockConvertSchema = (schema: AnySchema): string => {
|
|
7
|
+
if (schema.type === "string") return "z.string()";
|
|
8
|
+
if (schema.type === "number") return "z.number()";
|
|
9
|
+
if (schema.type === "boolean") return "z.boolean()";
|
|
10
|
+
return "z.unknown()";
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
describe("intersection with two types", () => {
|
|
14
|
+
it("should convert intersection of string and number", () => {
|
|
15
|
+
const result = convertOpenAPIIntersectionToZod(
|
|
16
|
+
{
|
|
17
|
+
allOf: [{ type: "string" }, { type: "number" }],
|
|
18
|
+
},
|
|
19
|
+
mockConvertSchema,
|
|
20
|
+
);
|
|
21
|
+
expect(result).toBe("z.intersection(z.string(), z.number())");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should convert intersection of string and boolean", () => {
|
|
25
|
+
const result = convertOpenAPIIntersectionToZod(
|
|
26
|
+
{
|
|
27
|
+
allOf: [{ type: "string" }, { type: "boolean" }],
|
|
28
|
+
},
|
|
29
|
+
mockConvertSchema,
|
|
30
|
+
);
|
|
31
|
+
expect(result).toBe("z.intersection(z.string(), z.boolean())");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("intersection with multiple types", () => {
|
|
36
|
+
it("should convert intersection of three types", () => {
|
|
37
|
+
const result = convertOpenAPIIntersectionToZod(
|
|
38
|
+
{
|
|
39
|
+
allOf: [{ type: "string" }, { type: "number" }, { type: "boolean" }],
|
|
40
|
+
},
|
|
41
|
+
mockConvertSchema,
|
|
42
|
+
);
|
|
43
|
+
expect(result).toBe(
|
|
44
|
+
"z.intersection(z.string(), z.number(), z.boolean())",
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should convert intersection of multiple same types", () => {
|
|
49
|
+
const result = convertOpenAPIIntersectionToZod(
|
|
50
|
+
{
|
|
51
|
+
allOf: [{ type: "string" }, { type: "string" }],
|
|
52
|
+
},
|
|
53
|
+
mockConvertSchema,
|
|
54
|
+
);
|
|
55
|
+
expect(result).toBe("z.intersection(z.string(), z.string())");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("intersection with single type", () => {
|
|
60
|
+
it("should return single schema without intersection wrapper", () => {
|
|
61
|
+
const result = convertOpenAPIIntersectionToZod(
|
|
62
|
+
{
|
|
63
|
+
allOf: [{ type: "string" }],
|
|
64
|
+
},
|
|
65
|
+
mockConvertSchema,
|
|
66
|
+
);
|
|
67
|
+
expect(result).toBe("z.string()");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe("empty intersection", () => {
|
|
72
|
+
it("should return z.unknown() for empty allOf array", () => {
|
|
73
|
+
const result = convertOpenAPIIntersectionToZod(
|
|
74
|
+
{
|
|
75
|
+
allOf: [],
|
|
76
|
+
},
|
|
77
|
+
mockConvertSchema,
|
|
78
|
+
);
|
|
79
|
+
expect(result).toBe("z.unknown()");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("intersection with unknown types", () => {
|
|
84
|
+
it("should convert intersection containing unknown types", () => {
|
|
85
|
+
const result = convertOpenAPIIntersectionToZod(
|
|
86
|
+
{
|
|
87
|
+
allOf: [{ type: "string" }, { type: "unknown-type" }],
|
|
88
|
+
},
|
|
89
|
+
mockConvertSchema,
|
|
90
|
+
);
|
|
91
|
+
expect(result).toBe("z.intersection(z.string(), z.unknown())");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("edge cases", () => {
|
|
96
|
+
it("should preserve order of intersection members", () => {
|
|
97
|
+
const result = convertOpenAPIIntersectionToZod(
|
|
98
|
+
{
|
|
99
|
+
allOf: [{ type: "boolean" }, { type: "number" }, { type: "string" }],
|
|
100
|
+
},
|
|
101
|
+
mockConvertSchema,
|
|
102
|
+
);
|
|
103
|
+
expect(result).toBe(
|
|
104
|
+
"z.intersection(z.boolean(), z.number(), z.string())",
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AnySchema } from "./types";
|
|
2
|
+
|
|
3
|
+
export function convertOpenAPIIntersectionToZod(
|
|
4
|
+
schema: { allOf: AnySchema[] },
|
|
5
|
+
convertSchema: (schema: AnySchema) => string,
|
|
6
|
+
): string {
|
|
7
|
+
const items = schema.allOf.map((item) => convertSchema(item));
|
|
8
|
+
|
|
9
|
+
if (schema.allOf.length === 0) return "z.unknown()";
|
|
10
|
+
if (schema.allOf.length === 1) return convertSchema(schema.allOf[0]!);
|
|
11
|
+
|
|
12
|
+
return `z.intersection(${items.join(", ")})`;
|
|
13
|
+
}
|
|
14
|
+
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { convertOpenAPINumberToZod } from "./number";
|
|
3
|
+
|
|
4
|
+
describe("convertOpenAPINumberToZod", () => {
|
|
5
|
+
describe("number type", () => {
|
|
6
|
+
it("should convert a basic number schema", () => {
|
|
7
|
+
const result = convertOpenAPINumberToZod({ type: "number" });
|
|
8
|
+
expect(result).toBe("z.number()");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("should convert number with minimum constraint", () => {
|
|
12
|
+
const result = convertOpenAPINumberToZod({
|
|
13
|
+
type: "number",
|
|
14
|
+
minimum: 0,
|
|
15
|
+
});
|
|
16
|
+
expect(result).toBe("z.number().min(0)");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should convert number with maximum constraint", () => {
|
|
20
|
+
const result = convertOpenAPINumberToZod({
|
|
21
|
+
type: "number",
|
|
22
|
+
maximum: 100,
|
|
23
|
+
});
|
|
24
|
+
expect(result).toBe("z.number().max(100)");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should convert number with both minimum and maximum constraints", () => {
|
|
28
|
+
const result = convertOpenAPINumberToZod({
|
|
29
|
+
type: "number",
|
|
30
|
+
minimum: 0,
|
|
31
|
+
maximum: 100,
|
|
32
|
+
});
|
|
33
|
+
expect(result).toBe("z.number().min(0).max(100)");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should handle negative minimum", () => {
|
|
37
|
+
const result = convertOpenAPINumberToZod({
|
|
38
|
+
type: "number",
|
|
39
|
+
minimum: -10,
|
|
40
|
+
});
|
|
41
|
+
expect(result).toBe("z.number().min(-10)");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should handle negative maximum", () => {
|
|
45
|
+
const result = convertOpenAPINumberToZod({
|
|
46
|
+
type: "number",
|
|
47
|
+
maximum: -5,
|
|
48
|
+
});
|
|
49
|
+
expect(result).toBe("z.number().max(-5)");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should handle decimal minimum and maximum", () => {
|
|
53
|
+
const result = convertOpenAPINumberToZod({
|
|
54
|
+
type: "number",
|
|
55
|
+
minimum: 0.5,
|
|
56
|
+
maximum: 99.99,
|
|
57
|
+
});
|
|
58
|
+
expect(result).toBe("z.number().min(0.5).max(99.99)");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should not apply constraints when undefined", () => {
|
|
62
|
+
const result = convertOpenAPINumberToZod({
|
|
63
|
+
type: "number",
|
|
64
|
+
minimum: undefined,
|
|
65
|
+
maximum: undefined,
|
|
66
|
+
});
|
|
67
|
+
expect(result).toBe("z.number()");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe("integer type", () => {
|
|
72
|
+
it("should convert a basic integer schema", () => {
|
|
73
|
+
const result = convertOpenAPINumberToZod({ type: "integer" });
|
|
74
|
+
expect(result).toBe("z.number().int()");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should convert integer with minimum constraint", () => {
|
|
78
|
+
const result = convertOpenAPINumberToZod({
|
|
79
|
+
type: "integer",
|
|
80
|
+
minimum: 1,
|
|
81
|
+
});
|
|
82
|
+
expect(result).toBe("z.number().int().min(1)");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should convert integer with maximum constraint", () => {
|
|
86
|
+
const result = convertOpenAPINumberToZod({
|
|
87
|
+
type: "integer",
|
|
88
|
+
maximum: 10,
|
|
89
|
+
});
|
|
90
|
+
expect(result).toBe("z.number().int().max(10)");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should convert integer with both minimum and maximum constraints", () => {
|
|
94
|
+
const result = convertOpenAPINumberToZod({
|
|
95
|
+
type: "integer",
|
|
96
|
+
minimum: 1,
|
|
97
|
+
maximum: 10,
|
|
98
|
+
});
|
|
99
|
+
expect(result).toBe("z.number().int().min(1).max(10)");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should handle zero as minimum", () => {
|
|
103
|
+
const result = convertOpenAPINumberToZod({
|
|
104
|
+
type: "integer",
|
|
105
|
+
minimum: 0,
|
|
106
|
+
});
|
|
107
|
+
expect(result).toBe("z.number().int().min(0)");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should handle zero as maximum", () => {
|
|
111
|
+
const result = convertOpenAPINumberToZod({
|
|
112
|
+
type: "integer",
|
|
113
|
+
maximum: 0,
|
|
114
|
+
});
|
|
115
|
+
expect(result).toBe("z.number().int().max(0)");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("should maintain order: int(), min(), max()", () => {
|
|
119
|
+
const result = convertOpenAPINumberToZod({
|
|
120
|
+
type: "integer",
|
|
121
|
+
maximum: 100,
|
|
122
|
+
minimum: 0,
|
|
123
|
+
});
|
|
124
|
+
expect(result).toBe("z.number().int().min(0).max(100)");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert an OpenAPI v3 number/integer schema to a Zod schema string
|
|
3
|
+
*/
|
|
4
|
+
export function convertOpenAPINumberToZod(schema: {
|
|
5
|
+
type: "number" | "integer";
|
|
6
|
+
minimum?: number;
|
|
7
|
+
maximum?: number;
|
|
8
|
+
}): string {
|
|
9
|
+
let result = "z.number()";
|
|
10
|
+
if (schema.type === "integer") {
|
|
11
|
+
result += ".int()";
|
|
12
|
+
}
|
|
13
|
+
if (typeof schema.minimum === "number") {
|
|
14
|
+
result += `.min(${schema.minimum})`;
|
|
15
|
+
}
|
|
16
|
+
if (typeof schema.maximum === "number") {
|
|
17
|
+
result += `.max(${schema.maximum})`;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|