zod 4.1.0-canary.20250729T053738 → 4.1.0-canary.20250730T051934
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/package.json +8 -7
- package/src/v4/classic/tests/optional.test.ts +13 -0
- package/src/v4/classic/tests/to-json-schema.test.ts +26 -0
- package/src/v4/core/json-schema.ts +6 -3
- package/src/v4/core/schemas.ts +10 -1
- package/src/v4/core/to-json-schema.ts +37 -11
- package/src/v4/core/versions.ts +1 -1
- package/v4/core/json-schema.d.cts +3 -3
- package/v4/core/json-schema.d.ts +3 -3
- package/v4/core/schemas.cjs +10 -1
- package/v4/core/schemas.js +10 -1
- package/v4/core/to-json-schema.cjs +37 -10
- package/v4/core/to-json-schema.d.cts +4 -3
- package/v4/core/to-json-schema.d.ts +4 -3
- package/v4/core/to-json-schema.js +37 -10
- package/v4/core/versions.cjs +1 -1
- package/v4/core/versions.js +1 -1
package/package.json
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod",
|
|
3
|
-
"version": "4.1.0-canary.
|
|
3
|
+
"version": "4.1.0-canary.20250730T051934",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"author": "Colin McDonnell <zod@colinhacks.com>",
|
|
6
7
|
"description": "TypeScript-first schema declaration and validation library with static type inference",
|
|
8
|
+
"homepage": "https://zod.dev",
|
|
9
|
+
"llms": "https://zod.dev/llms.txt",
|
|
10
|
+
"llmsFull": "https://zod.dev/llms-full.txt",
|
|
11
|
+
"mcpServer": "https://mcp.inkeep.com/zod/mcp",
|
|
12
|
+
"funding": "https://github.com/sponsors/colinhacks",
|
|
13
|
+
"sideEffects": false,
|
|
7
14
|
"files": [
|
|
8
15
|
"src",
|
|
9
16
|
"**/*.js",
|
|
@@ -13,10 +20,6 @@
|
|
|
13
20
|
"**/*.d.mts",
|
|
14
21
|
"**/*.d.cts"
|
|
15
22
|
],
|
|
16
|
-
"funding": "https://github.com/sponsors/colinhacks",
|
|
17
|
-
"homepage": "https://zod.dev",
|
|
18
|
-
"llms": "https://zod.dev/llms.txt",
|
|
19
|
-
"mcp": "https://mcp.inkeep.com/zod/mcp",
|
|
20
23
|
"keywords": [
|
|
21
24
|
"typescript",
|
|
22
25
|
"schema",
|
|
@@ -24,8 +27,6 @@
|
|
|
24
27
|
"type",
|
|
25
28
|
"inference"
|
|
26
29
|
],
|
|
27
|
-
"license": "MIT",
|
|
28
|
-
"sideEffects": false,
|
|
29
30
|
"main": "./index.cjs",
|
|
30
31
|
"types": "./index.d.cts",
|
|
31
32
|
"module": "./index.js",
|
|
@@ -121,3 +121,16 @@ test("pipe optionality inside objects", () => {
|
|
|
121
121
|
e: string;
|
|
122
122
|
}>();
|
|
123
123
|
});
|
|
124
|
+
|
|
125
|
+
test("optional prop with pipe", () => {
|
|
126
|
+
const schema = z.object({
|
|
127
|
+
id: z
|
|
128
|
+
.union([z.number(), z.string().nullish()])
|
|
129
|
+
.transform((val) => (val === null || val === undefined ? val : Number(val)))
|
|
130
|
+
.pipe(z.number())
|
|
131
|
+
.optional(),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
schema.parse({});
|
|
135
|
+
schema.parse({}, { jitless: true });
|
|
136
|
+
});
|
|
@@ -539,6 +539,19 @@ describe("toJSONSchema", () => {
|
|
|
539
539
|
`);
|
|
540
540
|
});
|
|
541
541
|
|
|
542
|
+
test("number constraints draft-4", () => {
|
|
543
|
+
expect(z.toJSONSchema(z.number().gt(5).lt(10), { target: "draft-4" })).toMatchInlineSnapshot(`
|
|
544
|
+
{
|
|
545
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
546
|
+
"exclusiveMaximum": true,
|
|
547
|
+
"exclusiveMinimum": true,
|
|
548
|
+
"maximum": 10,
|
|
549
|
+
"minimum": 5,
|
|
550
|
+
"type": "number",
|
|
551
|
+
}
|
|
552
|
+
`);
|
|
553
|
+
});
|
|
554
|
+
|
|
542
555
|
test("arrays", () => {
|
|
543
556
|
expect(z.toJSONSchema(z.array(z.string()))).toMatchInlineSnapshot(`
|
|
544
557
|
{
|
|
@@ -745,6 +758,19 @@ describe("toJSONSchema", () => {
|
|
|
745
758
|
`);
|
|
746
759
|
});
|
|
747
760
|
|
|
761
|
+
test("literal draft-4", () => {
|
|
762
|
+
const a = z.literal("hello");
|
|
763
|
+
expect(z.toJSONSchema(a, { target: "draft-4" })).toMatchInlineSnapshot(`
|
|
764
|
+
{
|
|
765
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
766
|
+
"enum": [
|
|
767
|
+
"hello",
|
|
768
|
+
],
|
|
769
|
+
"type": "string",
|
|
770
|
+
}
|
|
771
|
+
`);
|
|
772
|
+
});
|
|
773
|
+
|
|
748
774
|
// pipe
|
|
749
775
|
test("pipe", () => {
|
|
750
776
|
const schema = z
|
|
@@ -45,7 +45,10 @@ export type Schema =
|
|
|
45
45
|
export type _JSONSchema = boolean | JSONSchema;
|
|
46
46
|
export type JSONSchema = {
|
|
47
47
|
[k: string]: unknown;
|
|
48
|
-
$schema?:
|
|
48
|
+
$schema?:
|
|
49
|
+
| "https://json-schema.org/draft/2020-12/schema"
|
|
50
|
+
| "http://json-schema.org/draft-07/schema#"
|
|
51
|
+
| "http://json-schema.org/draft-04/schema#";
|
|
49
52
|
$id?: string;
|
|
50
53
|
$anchor?: string;
|
|
51
54
|
$ref?: string;
|
|
@@ -75,9 +78,9 @@ export type JSONSchema = {
|
|
|
75
78
|
not?: _JSONSchema;
|
|
76
79
|
multipleOf?: number;
|
|
77
80
|
maximum?: number;
|
|
78
|
-
exclusiveMaximum?: number;
|
|
81
|
+
exclusiveMaximum?: number | boolean;
|
|
79
82
|
minimum?: number;
|
|
80
|
-
exclusiveMinimum?: number;
|
|
83
|
+
exclusiveMinimum?: number | boolean;
|
|
81
84
|
maxLength?: number;
|
|
82
85
|
minLength?: number;
|
|
83
86
|
pattern?: string;
|
package/src/v4/core/schemas.ts
CHANGED
|
@@ -3007,6 +3007,13 @@ export interface $ZodOptional<T extends SomeType = $ZodType> extends $ZodType {
|
|
|
3007
3007
|
_zod: $ZodOptionalInternals<T>;
|
|
3008
3008
|
}
|
|
3009
3009
|
|
|
3010
|
+
function handleOptionalResult(result: ParsePayload, input: unknown) {
|
|
3011
|
+
if (result.issues.length && input === undefined) {
|
|
3012
|
+
return { issues: [], value: undefined };
|
|
3013
|
+
}
|
|
3014
|
+
return result;
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3010
3017
|
export const $ZodOptional: core.$constructor<$ZodOptional> = /*@__PURE__*/ core.$constructor(
|
|
3011
3018
|
"$ZodOptional",
|
|
3012
3019
|
(inst, def) => {
|
|
@@ -3024,7 +3031,9 @@ export const $ZodOptional: core.$constructor<$ZodOptional> = /*@__PURE__*/ core.
|
|
|
3024
3031
|
|
|
3025
3032
|
inst._zod.parse = (payload, ctx) => {
|
|
3026
3033
|
if (def.innerType._zod.optin === "optional") {
|
|
3027
|
-
|
|
3034
|
+
const result = def.innerType._zod.run(payload, ctx);
|
|
3035
|
+
if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, payload.value));
|
|
3036
|
+
return handleOptionalResult(result, payload.value);
|
|
3028
3037
|
}
|
|
3029
3038
|
if (payload.value === undefined) {
|
|
3030
3039
|
return payload;
|
|
@@ -10,8 +10,9 @@ interface JSONSchemaGeneratorParams {
|
|
|
10
10
|
metadata?: $ZodRegistry<Record<string, any>>;
|
|
11
11
|
/** The JSON Schema version to target.
|
|
12
12
|
* - `"draft-2020-12"` — Default. JSON Schema Draft 2020-12
|
|
13
|
-
* - `"draft-7"` — JSON Schema Draft 7
|
|
14
|
-
|
|
13
|
+
* - `"draft-7"` — JSON Schema Draft 7
|
|
14
|
+
* - `"draft-4"` — JSON Schema Draft 4 */
|
|
15
|
+
target?: "draft-4" | "draft-7" | "draft-2020-12";
|
|
15
16
|
/** How to handle unrepresentable types.
|
|
16
17
|
* - `"throw"` — Default. Unrepresentable types throw an error
|
|
17
18
|
* - `"any"` — Unrepresentable types become `{}` */
|
|
@@ -71,7 +72,7 @@ interface Seen {
|
|
|
71
72
|
|
|
72
73
|
export class JSONSchemaGenerator {
|
|
73
74
|
metadataRegistry: $ZodRegistry<Record<string, any>>;
|
|
74
|
-
target: "draft-7" | "draft-2020-12";
|
|
75
|
+
target: "draft-4" | "draft-7" | "draft-2020-12";
|
|
75
76
|
unrepresentable: "throw" | "any";
|
|
76
77
|
override: (ctx: {
|
|
77
78
|
zodSchema: schemas.$ZodTypes;
|
|
@@ -163,7 +164,7 @@ export class JSONSchemaGenerator {
|
|
|
163
164
|
else if (regexes.length > 1) {
|
|
164
165
|
result.schema.allOf = [
|
|
165
166
|
...regexes.map((regex) => ({
|
|
166
|
-
...(this.target === "draft-7" ? ({ type: "string" } as const) : {}),
|
|
167
|
+
...(this.target === "draft-7" || this.target === "draft-4" ? ({ type: "string" } as const) : {}),
|
|
167
168
|
pattern: regex.source,
|
|
168
169
|
})),
|
|
169
170
|
];
|
|
@@ -178,19 +179,33 @@ export class JSONSchemaGenerator {
|
|
|
178
179
|
if (typeof format === "string" && format.includes("int")) json.type = "integer";
|
|
179
180
|
else json.type = "number";
|
|
180
181
|
|
|
181
|
-
if (typeof exclusiveMinimum === "number")
|
|
182
|
+
if (typeof exclusiveMinimum === "number") {
|
|
183
|
+
if (this.target === "draft-4") {
|
|
184
|
+
json.minimum = exclusiveMinimum;
|
|
185
|
+
json.exclusiveMinimum = true;
|
|
186
|
+
} else {
|
|
187
|
+
json.exclusiveMinimum = exclusiveMinimum;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
182
190
|
if (typeof minimum === "number") {
|
|
183
191
|
json.minimum = minimum;
|
|
184
|
-
if (typeof exclusiveMinimum === "number") {
|
|
192
|
+
if (typeof exclusiveMinimum === "number" && this.target !== "draft-4") {
|
|
185
193
|
if (exclusiveMinimum >= minimum) delete json.minimum;
|
|
186
194
|
else delete json.exclusiveMinimum;
|
|
187
195
|
}
|
|
188
196
|
}
|
|
189
197
|
|
|
190
|
-
if (typeof exclusiveMaximum === "number")
|
|
198
|
+
if (typeof exclusiveMaximum === "number") {
|
|
199
|
+
if (this.target === "draft-4") {
|
|
200
|
+
json.maximum = exclusiveMaximum;
|
|
201
|
+
json.exclusiveMaximum = true;
|
|
202
|
+
} else {
|
|
203
|
+
json.exclusiveMaximum = exclusiveMaximum;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
191
206
|
if (typeof maximum === "number") {
|
|
192
207
|
json.maximum = maximum;
|
|
193
|
-
if (typeof exclusiveMaximum === "number") {
|
|
208
|
+
if (typeof exclusiveMaximum === "number" && this.target !== "draft-4") {
|
|
194
209
|
if (exclusiveMaximum <= maximum) delete json.maximum;
|
|
195
210
|
else delete json.exclusiveMaximum;
|
|
196
211
|
}
|
|
@@ -379,7 +394,12 @@ export class JSONSchemaGenerator {
|
|
|
379
394
|
case "record": {
|
|
380
395
|
const json: JSONSchema.ObjectSchema = _json as any;
|
|
381
396
|
json.type = "object";
|
|
382
|
-
|
|
397
|
+
if (this.target !== "draft-4") {
|
|
398
|
+
json.propertyNames = this.process(def.keyType, {
|
|
399
|
+
...params,
|
|
400
|
+
path: [...params.path, "propertyNames"],
|
|
401
|
+
});
|
|
402
|
+
}
|
|
383
403
|
json.additionalProperties = this.process(def.valueType, {
|
|
384
404
|
...params,
|
|
385
405
|
path: [...params.path, "additionalProperties"],
|
|
@@ -432,7 +452,11 @@ export class JSONSchemaGenerator {
|
|
|
432
452
|
} else if (vals.length === 1) {
|
|
433
453
|
const val = vals[0]!;
|
|
434
454
|
json.type = val === null ? ("null" as const) : (typeof val as any);
|
|
435
|
-
|
|
455
|
+
if (this.target === "draft-4") {
|
|
456
|
+
json.enum = [val];
|
|
457
|
+
} else {
|
|
458
|
+
json.const = val;
|
|
459
|
+
}
|
|
436
460
|
} else {
|
|
437
461
|
if (vals.every((v) => typeof v === "number")) json.type = "number";
|
|
438
462
|
if (vals.every((v) => typeof v === "string")) json.type = "string";
|
|
@@ -749,7 +773,7 @@ export class JSONSchemaGenerator {
|
|
|
749
773
|
|
|
750
774
|
// merge referenced schema into current
|
|
751
775
|
const refSchema = this.seen.get(ref)!.schema;
|
|
752
|
-
if (refSchema.$ref && params.target === "draft-7") {
|
|
776
|
+
if (refSchema.$ref && (params.target === "draft-7" || params.target === "draft-4")) {
|
|
753
777
|
schema.allOf = schema.allOf ?? [];
|
|
754
778
|
schema.allOf.push(refSchema);
|
|
755
779
|
} else {
|
|
@@ -776,6 +800,8 @@ export class JSONSchemaGenerator {
|
|
|
776
800
|
result.$schema = "https://json-schema.org/draft/2020-12/schema";
|
|
777
801
|
} else if (this.target === "draft-7") {
|
|
778
802
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
803
|
+
} else if (this.target === "draft-4") {
|
|
804
|
+
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
779
805
|
} else {
|
|
780
806
|
// @ts-ignore
|
|
781
807
|
console.warn(`Invalid target: ${this.target}`);
|
package/src/v4/core/versions.ts
CHANGED
|
@@ -2,7 +2,7 @@ export type Schema = ObjectSchema | ArraySchema | StringSchema | NumberSchema |
|
|
|
2
2
|
export type _JSONSchema = boolean | JSONSchema;
|
|
3
3
|
export type JSONSchema = {
|
|
4
4
|
[k: string]: unknown;
|
|
5
|
-
$schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#";
|
|
5
|
+
$schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#" | "http://json-schema.org/draft-04/schema#";
|
|
6
6
|
$id?: string;
|
|
7
7
|
$anchor?: string;
|
|
8
8
|
$ref?: string;
|
|
@@ -32,9 +32,9 @@ export type JSONSchema = {
|
|
|
32
32
|
not?: _JSONSchema;
|
|
33
33
|
multipleOf?: number;
|
|
34
34
|
maximum?: number;
|
|
35
|
-
exclusiveMaximum?: number;
|
|
35
|
+
exclusiveMaximum?: number | boolean;
|
|
36
36
|
minimum?: number;
|
|
37
|
-
exclusiveMinimum?: number;
|
|
37
|
+
exclusiveMinimum?: number | boolean;
|
|
38
38
|
maxLength?: number;
|
|
39
39
|
minLength?: number;
|
|
40
40
|
pattern?: string;
|
package/v4/core/json-schema.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export type Schema = ObjectSchema | ArraySchema | StringSchema | NumberSchema |
|
|
|
2
2
|
export type _JSONSchema = boolean | JSONSchema;
|
|
3
3
|
export type JSONSchema = {
|
|
4
4
|
[k: string]: unknown;
|
|
5
|
-
$schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#";
|
|
5
|
+
$schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#" | "http://json-schema.org/draft-04/schema#";
|
|
6
6
|
$id?: string;
|
|
7
7
|
$anchor?: string;
|
|
8
8
|
$ref?: string;
|
|
@@ -32,9 +32,9 @@ export type JSONSchema = {
|
|
|
32
32
|
not?: _JSONSchema;
|
|
33
33
|
multipleOf?: number;
|
|
34
34
|
maximum?: number;
|
|
35
|
-
exclusiveMaximum?: number;
|
|
35
|
+
exclusiveMaximum?: number | boolean;
|
|
36
36
|
minimum?: number;
|
|
37
|
-
exclusiveMinimum?: number;
|
|
37
|
+
exclusiveMinimum?: number | boolean;
|
|
38
38
|
maxLength?: number;
|
|
39
39
|
minLength?: number;
|
|
40
40
|
pattern?: string;
|
package/v4/core/schemas.cjs
CHANGED
|
@@ -1415,6 +1415,12 @@ exports.$ZodTransform = core.$constructor("$ZodTransform", (inst, def) => {
|
|
|
1415
1415
|
return payload;
|
|
1416
1416
|
};
|
|
1417
1417
|
});
|
|
1418
|
+
function handleOptionalResult(result, input) {
|
|
1419
|
+
if (result.issues.length && input === undefined) {
|
|
1420
|
+
return { issues: [], value: undefined };
|
|
1421
|
+
}
|
|
1422
|
+
return result;
|
|
1423
|
+
}
|
|
1418
1424
|
exports.$ZodOptional = core.$constructor("$ZodOptional", (inst, def) => {
|
|
1419
1425
|
exports.$ZodType.init(inst, def);
|
|
1420
1426
|
inst._zod.optin = "optional";
|
|
@@ -1428,7 +1434,10 @@ exports.$ZodOptional = core.$constructor("$ZodOptional", (inst, def) => {
|
|
|
1428
1434
|
});
|
|
1429
1435
|
inst._zod.parse = (payload, ctx) => {
|
|
1430
1436
|
if (def.innerType._zod.optin === "optional") {
|
|
1431
|
-
|
|
1437
|
+
const result = def.innerType._zod.run(payload, ctx);
|
|
1438
|
+
if (result instanceof Promise)
|
|
1439
|
+
return result.then((r) => handleOptionalResult(r, payload.value));
|
|
1440
|
+
return handleOptionalResult(result, payload.value);
|
|
1432
1441
|
}
|
|
1433
1442
|
if (payload.value === undefined) {
|
|
1434
1443
|
return payload;
|
package/v4/core/schemas.js
CHANGED
|
@@ -1384,6 +1384,12 @@ export const $ZodTransform = /*@__PURE__*/ core.$constructor("$ZodTransform", (i
|
|
|
1384
1384
|
return payload;
|
|
1385
1385
|
};
|
|
1386
1386
|
});
|
|
1387
|
+
function handleOptionalResult(result, input) {
|
|
1388
|
+
if (result.issues.length && input === undefined) {
|
|
1389
|
+
return { issues: [], value: undefined };
|
|
1390
|
+
}
|
|
1391
|
+
return result;
|
|
1392
|
+
}
|
|
1387
1393
|
export const $ZodOptional = /*@__PURE__*/ core.$constructor("$ZodOptional", (inst, def) => {
|
|
1388
1394
|
$ZodType.init(inst, def);
|
|
1389
1395
|
inst._zod.optin = "optional";
|
|
@@ -1397,7 +1403,10 @@ export const $ZodOptional = /*@__PURE__*/ core.$constructor("$ZodOptional", (ins
|
|
|
1397
1403
|
});
|
|
1398
1404
|
inst._zod.parse = (payload, ctx) => {
|
|
1399
1405
|
if (def.innerType._zod.optin === "optional") {
|
|
1400
|
-
|
|
1406
|
+
const result = def.innerType._zod.run(payload, ctx);
|
|
1407
|
+
if (result instanceof Promise)
|
|
1408
|
+
return result.then((r) => handleOptionalResult(r, payload.value));
|
|
1409
|
+
return handleOptionalResult(result, payload.value);
|
|
1401
1410
|
}
|
|
1402
1411
|
if (payload.value === undefined) {
|
|
1403
1412
|
return payload;
|
|
@@ -83,7 +83,7 @@ class JSONSchemaGenerator {
|
|
|
83
83
|
else if (regexes.length > 1) {
|
|
84
84
|
result.schema.allOf = [
|
|
85
85
|
...regexes.map((regex) => ({
|
|
86
|
-
...(this.target === "draft-7" ? { type: "string" } : {}),
|
|
86
|
+
...(this.target === "draft-7" || this.target === "draft-4" ? { type: "string" } : {}),
|
|
87
87
|
pattern: regex.source,
|
|
88
88
|
})),
|
|
89
89
|
];
|
|
@@ -98,22 +98,36 @@ class JSONSchemaGenerator {
|
|
|
98
98
|
json.type = "integer";
|
|
99
99
|
else
|
|
100
100
|
json.type = "number";
|
|
101
|
-
if (typeof exclusiveMinimum === "number")
|
|
102
|
-
|
|
101
|
+
if (typeof exclusiveMinimum === "number") {
|
|
102
|
+
if (this.target === "draft-4") {
|
|
103
|
+
json.minimum = exclusiveMinimum;
|
|
104
|
+
json.exclusiveMinimum = true;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
json.exclusiveMinimum = exclusiveMinimum;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
103
110
|
if (typeof minimum === "number") {
|
|
104
111
|
json.minimum = minimum;
|
|
105
|
-
if (typeof exclusiveMinimum === "number") {
|
|
112
|
+
if (typeof exclusiveMinimum === "number" && this.target !== "draft-4") {
|
|
106
113
|
if (exclusiveMinimum >= minimum)
|
|
107
114
|
delete json.minimum;
|
|
108
115
|
else
|
|
109
116
|
delete json.exclusiveMinimum;
|
|
110
117
|
}
|
|
111
118
|
}
|
|
112
|
-
if (typeof exclusiveMaximum === "number")
|
|
113
|
-
|
|
119
|
+
if (typeof exclusiveMaximum === "number") {
|
|
120
|
+
if (this.target === "draft-4") {
|
|
121
|
+
json.maximum = exclusiveMaximum;
|
|
122
|
+
json.exclusiveMaximum = true;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
json.exclusiveMaximum = exclusiveMaximum;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
114
128
|
if (typeof maximum === "number") {
|
|
115
129
|
json.maximum = maximum;
|
|
116
|
-
if (typeof exclusiveMaximum === "number") {
|
|
130
|
+
if (typeof exclusiveMaximum === "number" && this.target !== "draft-4") {
|
|
117
131
|
if (exclusiveMaximum <= maximum)
|
|
118
132
|
delete json.maximum;
|
|
119
133
|
else
|
|
@@ -294,7 +308,12 @@ class JSONSchemaGenerator {
|
|
|
294
308
|
case "record": {
|
|
295
309
|
const json = _json;
|
|
296
310
|
json.type = "object";
|
|
297
|
-
|
|
311
|
+
if (this.target !== "draft-4") {
|
|
312
|
+
json.propertyNames = this.process(def.keyType, {
|
|
313
|
+
...params,
|
|
314
|
+
path: [...params.path, "propertyNames"],
|
|
315
|
+
});
|
|
316
|
+
}
|
|
298
317
|
json.additionalProperties = this.process(def.valueType, {
|
|
299
318
|
...params,
|
|
300
319
|
path: [...params.path, "additionalProperties"],
|
|
@@ -354,7 +373,12 @@ class JSONSchemaGenerator {
|
|
|
354
373
|
else if (vals.length === 1) {
|
|
355
374
|
const val = vals[0];
|
|
356
375
|
json.type = val === null ? "null" : typeof val;
|
|
357
|
-
|
|
376
|
+
if (this.target === "draft-4") {
|
|
377
|
+
json.enum = [val];
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
json.const = val;
|
|
381
|
+
}
|
|
358
382
|
}
|
|
359
383
|
else {
|
|
360
384
|
if (vals.every((v) => typeof v === "number"))
|
|
@@ -650,7 +674,7 @@ class JSONSchemaGenerator {
|
|
|
650
674
|
flattenRef(ref, params);
|
|
651
675
|
// merge referenced schema into current
|
|
652
676
|
const refSchema = this.seen.get(ref).schema;
|
|
653
|
-
if (refSchema.$ref && params.target === "draft-7") {
|
|
677
|
+
if (refSchema.$ref && (params.target === "draft-7" || params.target === "draft-4")) {
|
|
654
678
|
schema.allOf = schema.allOf ?? [];
|
|
655
679
|
schema.allOf.push(refSchema);
|
|
656
680
|
}
|
|
@@ -677,6 +701,9 @@ class JSONSchemaGenerator {
|
|
|
677
701
|
else if (this.target === "draft-7") {
|
|
678
702
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
679
703
|
}
|
|
704
|
+
else if (this.target === "draft-4") {
|
|
705
|
+
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
706
|
+
}
|
|
680
707
|
else {
|
|
681
708
|
// @ts-ignore
|
|
682
709
|
console.warn(`Invalid target: ${this.target}`);
|
|
@@ -7,8 +7,9 @@ interface JSONSchemaGeneratorParams {
|
|
|
7
7
|
metadata?: $ZodRegistry<Record<string, any>>;
|
|
8
8
|
/** The JSON Schema version to target.
|
|
9
9
|
* - `"draft-2020-12"` — Default. JSON Schema Draft 2020-12
|
|
10
|
-
* - `"draft-7"` — JSON Schema Draft 7
|
|
11
|
-
|
|
10
|
+
* - `"draft-7"` — JSON Schema Draft 7
|
|
11
|
+
* - `"draft-4"` — JSON Schema Draft 4 */
|
|
12
|
+
target?: "draft-4" | "draft-7" | "draft-2020-12";
|
|
12
13
|
/** How to handle unrepresentable types.
|
|
13
14
|
* - `"throw"` — Default. Unrepresentable types throw an error
|
|
14
15
|
* - `"any"` — Unrepresentable types become `{}` */
|
|
@@ -60,7 +61,7 @@ interface Seen {
|
|
|
60
61
|
}
|
|
61
62
|
export declare class JSONSchemaGenerator {
|
|
62
63
|
metadataRegistry: $ZodRegistry<Record<string, any>>;
|
|
63
|
-
target: "draft-7" | "draft-2020-12";
|
|
64
|
+
target: "draft-4" | "draft-7" | "draft-2020-12";
|
|
64
65
|
unrepresentable: "throw" | "any";
|
|
65
66
|
override: (ctx: {
|
|
66
67
|
zodSchema: schemas.$ZodTypes;
|
|
@@ -7,8 +7,9 @@ interface JSONSchemaGeneratorParams {
|
|
|
7
7
|
metadata?: $ZodRegistry<Record<string, any>>;
|
|
8
8
|
/** The JSON Schema version to target.
|
|
9
9
|
* - `"draft-2020-12"` — Default. JSON Schema Draft 2020-12
|
|
10
|
-
* - `"draft-7"` — JSON Schema Draft 7
|
|
11
|
-
|
|
10
|
+
* - `"draft-7"` — JSON Schema Draft 7
|
|
11
|
+
* - `"draft-4"` — JSON Schema Draft 4 */
|
|
12
|
+
target?: "draft-4" | "draft-7" | "draft-2020-12";
|
|
12
13
|
/** How to handle unrepresentable types.
|
|
13
14
|
* - `"throw"` — Default. Unrepresentable types throw an error
|
|
14
15
|
* - `"any"` — Unrepresentable types become `{}` */
|
|
@@ -60,7 +61,7 @@ interface Seen {
|
|
|
60
61
|
}
|
|
61
62
|
export declare class JSONSchemaGenerator {
|
|
62
63
|
metadataRegistry: $ZodRegistry<Record<string, any>>;
|
|
63
|
-
target: "draft-7" | "draft-2020-12";
|
|
64
|
+
target: "draft-4" | "draft-7" | "draft-2020-12";
|
|
64
65
|
unrepresentable: "throw" | "any";
|
|
65
66
|
override: (ctx: {
|
|
66
67
|
zodSchema: schemas.$ZodTypes;
|
|
@@ -79,7 +79,7 @@ export class JSONSchemaGenerator {
|
|
|
79
79
|
else if (regexes.length > 1) {
|
|
80
80
|
result.schema.allOf = [
|
|
81
81
|
...regexes.map((regex) => ({
|
|
82
|
-
...(this.target === "draft-7" ? { type: "string" } : {}),
|
|
82
|
+
...(this.target === "draft-7" || this.target === "draft-4" ? { type: "string" } : {}),
|
|
83
83
|
pattern: regex.source,
|
|
84
84
|
})),
|
|
85
85
|
];
|
|
@@ -94,22 +94,36 @@ export class JSONSchemaGenerator {
|
|
|
94
94
|
json.type = "integer";
|
|
95
95
|
else
|
|
96
96
|
json.type = "number";
|
|
97
|
-
if (typeof exclusiveMinimum === "number")
|
|
98
|
-
|
|
97
|
+
if (typeof exclusiveMinimum === "number") {
|
|
98
|
+
if (this.target === "draft-4") {
|
|
99
|
+
json.minimum = exclusiveMinimum;
|
|
100
|
+
json.exclusiveMinimum = true;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
json.exclusiveMinimum = exclusiveMinimum;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
99
106
|
if (typeof minimum === "number") {
|
|
100
107
|
json.minimum = minimum;
|
|
101
|
-
if (typeof exclusiveMinimum === "number") {
|
|
108
|
+
if (typeof exclusiveMinimum === "number" && this.target !== "draft-4") {
|
|
102
109
|
if (exclusiveMinimum >= minimum)
|
|
103
110
|
delete json.minimum;
|
|
104
111
|
else
|
|
105
112
|
delete json.exclusiveMinimum;
|
|
106
113
|
}
|
|
107
114
|
}
|
|
108
|
-
if (typeof exclusiveMaximum === "number")
|
|
109
|
-
|
|
115
|
+
if (typeof exclusiveMaximum === "number") {
|
|
116
|
+
if (this.target === "draft-4") {
|
|
117
|
+
json.maximum = exclusiveMaximum;
|
|
118
|
+
json.exclusiveMaximum = true;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
json.exclusiveMaximum = exclusiveMaximum;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
110
124
|
if (typeof maximum === "number") {
|
|
111
125
|
json.maximum = maximum;
|
|
112
|
-
if (typeof exclusiveMaximum === "number") {
|
|
126
|
+
if (typeof exclusiveMaximum === "number" && this.target !== "draft-4") {
|
|
113
127
|
if (exclusiveMaximum <= maximum)
|
|
114
128
|
delete json.maximum;
|
|
115
129
|
else
|
|
@@ -290,7 +304,12 @@ export class JSONSchemaGenerator {
|
|
|
290
304
|
case "record": {
|
|
291
305
|
const json = _json;
|
|
292
306
|
json.type = "object";
|
|
293
|
-
|
|
307
|
+
if (this.target !== "draft-4") {
|
|
308
|
+
json.propertyNames = this.process(def.keyType, {
|
|
309
|
+
...params,
|
|
310
|
+
path: [...params.path, "propertyNames"],
|
|
311
|
+
});
|
|
312
|
+
}
|
|
294
313
|
json.additionalProperties = this.process(def.valueType, {
|
|
295
314
|
...params,
|
|
296
315
|
path: [...params.path, "additionalProperties"],
|
|
@@ -350,7 +369,12 @@ export class JSONSchemaGenerator {
|
|
|
350
369
|
else if (vals.length === 1) {
|
|
351
370
|
const val = vals[0];
|
|
352
371
|
json.type = val === null ? "null" : typeof val;
|
|
353
|
-
|
|
372
|
+
if (this.target === "draft-4") {
|
|
373
|
+
json.enum = [val];
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
json.const = val;
|
|
377
|
+
}
|
|
354
378
|
}
|
|
355
379
|
else {
|
|
356
380
|
if (vals.every((v) => typeof v === "number"))
|
|
@@ -646,7 +670,7 @@ export class JSONSchemaGenerator {
|
|
|
646
670
|
flattenRef(ref, params);
|
|
647
671
|
// merge referenced schema into current
|
|
648
672
|
const refSchema = this.seen.get(ref).schema;
|
|
649
|
-
if (refSchema.$ref && params.target === "draft-7") {
|
|
673
|
+
if (refSchema.$ref && (params.target === "draft-7" || params.target === "draft-4")) {
|
|
650
674
|
schema.allOf = schema.allOf ?? [];
|
|
651
675
|
schema.allOf.push(refSchema);
|
|
652
676
|
}
|
|
@@ -673,6 +697,9 @@ export class JSONSchemaGenerator {
|
|
|
673
697
|
else if (this.target === "draft-7") {
|
|
674
698
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
675
699
|
}
|
|
700
|
+
else if (this.target === "draft-4") {
|
|
701
|
+
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
702
|
+
}
|
|
676
703
|
else {
|
|
677
704
|
// @ts-ignore
|
|
678
705
|
console.warn(`Invalid target: ${this.target}`);
|
package/v4/core/versions.cjs
CHANGED
package/v4/core/versions.js
CHANGED