@atom8n/json-schema-to-zod 1.6.9 → 1.7.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 +2 -8
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/json-schema-to-zod.js +12 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/parsers/parse-all-of.js +37 -0
- package/dist/cjs/parsers/parse-any-of.js +16 -0
- package/dist/cjs/parsers/parse-array.js +18 -0
- package/dist/cjs/parsers/parse-boolean.js +8 -0
- package/dist/cjs/parsers/parse-const.js +8 -0
- package/dist/cjs/parsers/parse-default.js +8 -0
- package/dist/cjs/parsers/parse-enum.js +18 -0
- package/dist/cjs/parsers/parse-if-then-else.js +23 -0
- package/dist/cjs/parsers/parse-multiple-type.js +9 -0
- package/dist/cjs/parsers/parse-not.js +12 -0
- package/dist/cjs/parsers/parse-null.js +8 -0
- package/dist/cjs/parsers/parse-nullable.js +12 -0
- package/dist/cjs/parsers/parse-number.js +49 -0
- package/dist/cjs/parsers/parse-object.js +206 -0
- package/dist/cjs/parsers/parse-one-of.js +32 -0
- package/dist/cjs/parsers/parse-schema.js +159 -0
- package/dist/cjs/parsers/parse-string.js +42 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/utils/extend-schema.js +11 -0
- package/dist/cjs/utils/half.js +7 -0
- package/dist/cjs/utils/its.js +23 -0
- package/dist/cjs/utils/omit.js +10 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/json-schema-to-zod.js +8 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/parsers/parse-all-of.js +34 -0
- package/dist/esm/parsers/parse-any-of.js +12 -0
- package/dist/esm/parsers/parse-array.js +14 -0
- package/dist/esm/parsers/parse-boolean.js +4 -0
- package/dist/esm/parsers/parse-const.js +4 -0
- package/dist/esm/parsers/parse-default.js +4 -0
- package/dist/esm/parsers/parse-enum.js +14 -0
- package/dist/esm/parsers/parse-if-then-else.js +19 -0
- package/dist/esm/parsers/parse-multiple-type.js +5 -0
- package/dist/esm/parsers/parse-not.js +8 -0
- package/dist/esm/parsers/parse-null.js +4 -0
- package/dist/esm/parsers/parse-nullable.js +8 -0
- package/dist/esm/parsers/parse-number.js +45 -0
- package/dist/esm/parsers/parse-object.js +170 -0
- package/dist/esm/parsers/parse-one-of.js +28 -0
- package/dist/esm/parsers/parse-schema.js +122 -0
- package/dist/esm/parsers/parse-string.js +38 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils/extend-schema.js +8 -0
- package/dist/esm/utils/half.js +3 -0
- package/dist/esm/utils/its.js +20 -0
- package/dist/esm/utils/omit.js +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/json-schema-to-zod.d.ts +3 -0
- package/dist/types/parsers/parse-all-of.d.ts +5 -0
- package/dist/types/parsers/parse-any-of.d.ts +5 -0
- package/dist/types/parsers/parse-array.d.ts +5 -0
- package/dist/types/parsers/parse-boolean.d.ts +5 -0
- package/dist/types/parsers/parse-const.d.ts +5 -0
- package/dist/types/parsers/parse-default.d.ts +3 -0
- package/dist/types/parsers/parse-enum.d.ts +5 -0
- package/dist/types/parsers/parse-if-then-else.d.ts +7 -0
- package/dist/types/parsers/parse-multiple-type.d.ts +5 -0
- package/dist/types/parsers/parse-not.d.ts +5 -0
- package/dist/types/parsers/parse-null.d.ts +5 -0
- package/dist/types/parsers/parse-nullable.d.ts +7 -0
- package/dist/types/parsers/parse-number.d.ts +5 -0
- package/dist/types/parsers/parse-object.d.ts +5 -0
- package/dist/types/parsers/parse-one-of.d.ts +5 -0
- package/dist/types/parsers/parse-schema.d.ts +3 -0
- package/dist/types/parsers/parse-string.d.ts +5 -0
- package/dist/types/types.d.ts +66 -0
- package/dist/types/utils/extend-schema.d.ts +3 -0
- package/dist/types/utils/half.d.ts +1 -0
- package/dist/types/utils/its.d.ts +45 -0
- package/dist/types/utils/omit.d.ts +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseSchema = void 0;
|
|
37
|
+
const z = __importStar(require("zod"));
|
|
38
|
+
const parse_all_of_1 = require("./parse-all-of");
|
|
39
|
+
const parse_any_of_1 = require("./parse-any-of");
|
|
40
|
+
const parse_array_1 = require("./parse-array");
|
|
41
|
+
const parse_boolean_1 = require("./parse-boolean");
|
|
42
|
+
const parse_const_1 = require("./parse-const");
|
|
43
|
+
const parse_default_1 = require("./parse-default");
|
|
44
|
+
const parse_enum_1 = require("./parse-enum");
|
|
45
|
+
const parse_if_then_else_1 = require("./parse-if-then-else");
|
|
46
|
+
const parse_multiple_type_1 = require("./parse-multiple-type");
|
|
47
|
+
const parse_not_1 = require("./parse-not");
|
|
48
|
+
const parse_null_1 = require("./parse-null");
|
|
49
|
+
const parse_nullable_1 = require("./parse-nullable");
|
|
50
|
+
const parse_number_1 = require("./parse-number");
|
|
51
|
+
const parse_object_1 = require("./parse-object");
|
|
52
|
+
const parse_one_of_1 = require("./parse-one-of");
|
|
53
|
+
const parse_string_1 = require("./parse-string");
|
|
54
|
+
const its_1 = require("../utils/its");
|
|
55
|
+
const addDescribes = (jsonSchema, zodSchema) => {
|
|
56
|
+
if (jsonSchema.description) {
|
|
57
|
+
zodSchema = zodSchema.describe(jsonSchema.description);
|
|
58
|
+
}
|
|
59
|
+
return zodSchema;
|
|
60
|
+
};
|
|
61
|
+
const addDefaults = (jsonSchema, zodSchema) => {
|
|
62
|
+
if (jsonSchema.default !== undefined) {
|
|
63
|
+
zodSchema = zodSchema.default(jsonSchema.default);
|
|
64
|
+
}
|
|
65
|
+
return zodSchema;
|
|
66
|
+
};
|
|
67
|
+
const addAnnotations = (jsonSchema, zodSchema) => {
|
|
68
|
+
if (jsonSchema.readOnly) {
|
|
69
|
+
zodSchema = zodSchema.readonly();
|
|
70
|
+
}
|
|
71
|
+
return zodSchema;
|
|
72
|
+
};
|
|
73
|
+
const selectParser = (schema, refs) => {
|
|
74
|
+
if (its_1.its.a.nullable(schema)) {
|
|
75
|
+
return (0, parse_nullable_1.parseNullable)(schema, refs);
|
|
76
|
+
}
|
|
77
|
+
else if (its_1.its.an.object(schema)) {
|
|
78
|
+
return (0, parse_object_1.parseObject)(schema, refs);
|
|
79
|
+
}
|
|
80
|
+
else if (its_1.its.an.array(schema)) {
|
|
81
|
+
return (0, parse_array_1.parseArray)(schema, refs);
|
|
82
|
+
}
|
|
83
|
+
else if (its_1.its.an.anyOf(schema)) {
|
|
84
|
+
return (0, parse_any_of_1.parseAnyOf)(schema, refs);
|
|
85
|
+
}
|
|
86
|
+
else if (its_1.its.an.allOf(schema)) {
|
|
87
|
+
return (0, parse_all_of_1.parseAllOf)(schema, refs);
|
|
88
|
+
}
|
|
89
|
+
else if (its_1.its.a.oneOf(schema)) {
|
|
90
|
+
return (0, parse_one_of_1.parseOneOf)(schema, refs);
|
|
91
|
+
}
|
|
92
|
+
else if (its_1.its.a.not(schema)) {
|
|
93
|
+
return (0, parse_not_1.parseNot)(schema, refs);
|
|
94
|
+
}
|
|
95
|
+
else if (its_1.its.an.enum(schema)) {
|
|
96
|
+
return (0, parse_enum_1.parseEnum)(schema); //<-- needs to come before primitives
|
|
97
|
+
}
|
|
98
|
+
else if (its_1.its.a.const(schema)) {
|
|
99
|
+
return (0, parse_const_1.parseConst)(schema);
|
|
100
|
+
}
|
|
101
|
+
else if (its_1.its.a.multipleType(schema)) {
|
|
102
|
+
return (0, parse_multiple_type_1.parseMultipleType)(schema, refs);
|
|
103
|
+
}
|
|
104
|
+
else if (its_1.its.a.primitive(schema, 'string')) {
|
|
105
|
+
return (0, parse_string_1.parseString)(schema);
|
|
106
|
+
}
|
|
107
|
+
else if (its_1.its.a.primitive(schema, 'number') || its_1.its.a.primitive(schema, 'integer')) {
|
|
108
|
+
return (0, parse_number_1.parseNumber)(schema);
|
|
109
|
+
}
|
|
110
|
+
else if (its_1.its.a.primitive(schema, 'boolean')) {
|
|
111
|
+
return (0, parse_boolean_1.parseBoolean)(schema);
|
|
112
|
+
}
|
|
113
|
+
else if (its_1.its.a.primitive(schema, 'null')) {
|
|
114
|
+
return (0, parse_null_1.parseNull)(schema);
|
|
115
|
+
}
|
|
116
|
+
else if (its_1.its.a.conditional(schema)) {
|
|
117
|
+
return (0, parse_if_then_else_1.parseIfThenElse)(schema, refs);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
return (0, parse_default_1.parseDefault)(schema);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const parseSchema = (jsonSchema, refs = { seen: new Map(), path: [] }, blockMeta) => {
|
|
124
|
+
if (typeof jsonSchema !== 'object')
|
|
125
|
+
return jsonSchema ? z.any() : z.never();
|
|
126
|
+
if (refs.parserOverride) {
|
|
127
|
+
const custom = refs.parserOverride(jsonSchema, refs);
|
|
128
|
+
if (custom instanceof z.ZodType) {
|
|
129
|
+
return custom;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
let seen = refs.seen.get(jsonSchema);
|
|
133
|
+
if (seen) {
|
|
134
|
+
if (seen.r !== undefined) {
|
|
135
|
+
return seen.r;
|
|
136
|
+
}
|
|
137
|
+
if (refs.depth === undefined || seen.n >= refs.depth) {
|
|
138
|
+
return z.any();
|
|
139
|
+
}
|
|
140
|
+
seen.n += 1;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
seen = { r: undefined, n: 0 };
|
|
144
|
+
refs.seen.set(jsonSchema, seen);
|
|
145
|
+
}
|
|
146
|
+
let parsedZodSchema = selectParser(jsonSchema, refs);
|
|
147
|
+
if (!blockMeta) {
|
|
148
|
+
if (!refs.withoutDescribes) {
|
|
149
|
+
parsedZodSchema = addDescribes(jsonSchema, parsedZodSchema);
|
|
150
|
+
}
|
|
151
|
+
if (!refs.withoutDefaults) {
|
|
152
|
+
parsedZodSchema = addDefaults(jsonSchema, parsedZodSchema);
|
|
153
|
+
}
|
|
154
|
+
parsedZodSchema = addAnnotations(jsonSchema, parsedZodSchema);
|
|
155
|
+
}
|
|
156
|
+
seen.r = parsedZodSchema;
|
|
157
|
+
return parsedZodSchema;
|
|
158
|
+
};
|
|
159
|
+
exports.parseSchema = parseSchema;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseString = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const extend_schema_1 = require("../utils/extend-schema");
|
|
6
|
+
const parseString = (jsonSchema) => {
|
|
7
|
+
let zodSchema = zod_1.z.string();
|
|
8
|
+
zodSchema = (0, extend_schema_1.extendSchemaWithMessage)(zodSchema, jsonSchema, 'format', (zs, format, errorMsg) => {
|
|
9
|
+
switch (format) {
|
|
10
|
+
case 'email':
|
|
11
|
+
return zs.email(errorMsg);
|
|
12
|
+
case 'ip':
|
|
13
|
+
return zs.ip(errorMsg);
|
|
14
|
+
case 'ipv4':
|
|
15
|
+
return zs.ip({ version: 'v4', message: errorMsg });
|
|
16
|
+
case 'ipv6':
|
|
17
|
+
return zs.ip({ version: 'v6', message: errorMsg });
|
|
18
|
+
case 'uri':
|
|
19
|
+
return zs.url(errorMsg);
|
|
20
|
+
case 'uuid':
|
|
21
|
+
return zs.uuid(errorMsg);
|
|
22
|
+
case 'date-time':
|
|
23
|
+
return zs.datetime({ offset: true, message: errorMsg });
|
|
24
|
+
case 'time':
|
|
25
|
+
return zs.time(errorMsg);
|
|
26
|
+
case 'date':
|
|
27
|
+
return zs.date(errorMsg);
|
|
28
|
+
case 'binary':
|
|
29
|
+
return zs.base64(errorMsg);
|
|
30
|
+
case 'duration':
|
|
31
|
+
return zs.duration(errorMsg);
|
|
32
|
+
default:
|
|
33
|
+
return zs;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
zodSchema = (0, extend_schema_1.extendSchemaWithMessage)(zodSchema, jsonSchema, 'contentEncoding', (zs, _, errorMsg) => zs.base64(errorMsg));
|
|
37
|
+
zodSchema = (0, extend_schema_1.extendSchemaWithMessage)(zodSchema, jsonSchema, 'pattern', (zs, pattern, errorMsg) => zs.regex(new RegExp(pattern), errorMsg));
|
|
38
|
+
zodSchema = (0, extend_schema_1.extendSchemaWithMessage)(zodSchema, jsonSchema, 'minLength', (zs, minLength, errorMsg) => zs.min(minLength, errorMsg));
|
|
39
|
+
zodSchema = (0, extend_schema_1.extendSchemaWithMessage)(zodSchema, jsonSchema, 'maxLength', (zs, maxLength, errorMsg) => zs.max(maxLength, errorMsg));
|
|
40
|
+
return zodSchema;
|
|
41
|
+
};
|
|
42
|
+
exports.parseString = parseString;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extendSchemaWithMessage = extendSchemaWithMessage;
|
|
4
|
+
function extendSchemaWithMessage(zodSchema, jsonSchema, key, extend) {
|
|
5
|
+
const value = jsonSchema[key];
|
|
6
|
+
if (value !== undefined) {
|
|
7
|
+
const errorMessage = jsonSchema.errorMessage?.[key];
|
|
8
|
+
return extend(zodSchema, value, errorMessage);
|
|
9
|
+
}
|
|
10
|
+
return zodSchema;
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.its = void 0;
|
|
4
|
+
exports.its = {
|
|
5
|
+
an: {
|
|
6
|
+
object: (x) => x.type === 'object',
|
|
7
|
+
array: (x) => x.type === 'array',
|
|
8
|
+
anyOf: (x) => x.anyOf !== undefined,
|
|
9
|
+
allOf: (x) => x.allOf !== undefined,
|
|
10
|
+
enum: (x) => x.enum !== undefined,
|
|
11
|
+
},
|
|
12
|
+
a: {
|
|
13
|
+
nullable: (x) =>
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
|
|
15
|
+
x.nullable === true,
|
|
16
|
+
multipleType: (x) => Array.isArray(x.type),
|
|
17
|
+
not: (x) => x.not !== undefined,
|
|
18
|
+
const: (x) => x.const !== undefined,
|
|
19
|
+
primitive: (x, p) => x.type === p,
|
|
20
|
+
conditional: (x) => Boolean('if' in x && x.if && 'then' in x && 'else' in x && x.then && x.else),
|
|
21
|
+
oneOf: (x) => x.oneOf !== undefined,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.omit = void 0;
|
|
4
|
+
const omit = (obj, ...keys) => Object.keys(obj).reduce((acc, key) => {
|
|
5
|
+
if (!keys.includes(key)) {
|
|
6
|
+
acc[key] = obj[key];
|
|
7
|
+
}
|
|
8
|
+
return acc;
|
|
9
|
+
}, {});
|
|
10
|
+
exports.omit = omit;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { jsonSchemaToZod } from './json-schema-to-zod';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { parseSchema } from './parse-schema';
|
|
3
|
+
import { half } from '../utils/half';
|
|
4
|
+
const originalIndex = Symbol('Original index');
|
|
5
|
+
const ensureOriginalIndex = (arr) => {
|
|
6
|
+
const newArr = [];
|
|
7
|
+
for (let i = 0; i < arr.length; i++) {
|
|
8
|
+
const item = arr[i];
|
|
9
|
+
if (typeof item === 'boolean') {
|
|
10
|
+
newArr.push(item ? { [originalIndex]: i } : { [originalIndex]: i, not: {} });
|
|
11
|
+
}
|
|
12
|
+
else if (originalIndex in item) {
|
|
13
|
+
return arr;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
newArr.push({ ...item, [originalIndex]: i });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return newArr;
|
|
20
|
+
};
|
|
21
|
+
export function parseAllOf(jsonSchema, refs) {
|
|
22
|
+
if (jsonSchema.allOf.length === 0) {
|
|
23
|
+
return z.never();
|
|
24
|
+
}
|
|
25
|
+
if (jsonSchema.allOf.length === 1) {
|
|
26
|
+
const item = jsonSchema.allOf[0];
|
|
27
|
+
return parseSchema(item, {
|
|
28
|
+
...refs,
|
|
29
|
+
path: [...refs.path, 'allOf', item[originalIndex]],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const [left, right] = half(ensureOriginalIndex(jsonSchema.allOf));
|
|
33
|
+
return z.intersection(parseAllOf({ allOf: left }, refs), parseAllOf({ allOf: right }, refs));
|
|
34
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { parseSchema } from './parse-schema';
|
|
3
|
+
export const parseAnyOf = (jsonSchema, refs) => {
|
|
4
|
+
return jsonSchema.anyOf.length
|
|
5
|
+
? jsonSchema.anyOf.length === 1
|
|
6
|
+
? parseSchema(jsonSchema.anyOf[0], {
|
|
7
|
+
...refs,
|
|
8
|
+
path: [...refs.path, 'anyOf', 0],
|
|
9
|
+
})
|
|
10
|
+
: z.union(jsonSchema.anyOf.map((schema, i) => parseSchema(schema, { ...refs, path: [...refs.path, 'anyOf', i] })))
|
|
11
|
+
: z.any();
|
|
12
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { parseSchema } from './parse-schema';
|
|
3
|
+
import { extendSchemaWithMessage } from '../utils/extend-schema';
|
|
4
|
+
export const parseArray = (jsonSchema, refs) => {
|
|
5
|
+
if (Array.isArray(jsonSchema.items)) {
|
|
6
|
+
return z.tuple(jsonSchema.items.map((v, i) => parseSchema(v, { ...refs, path: [...refs.path, 'items', i] })));
|
|
7
|
+
}
|
|
8
|
+
let zodSchema = !jsonSchema.items
|
|
9
|
+
? z.array(z.any())
|
|
10
|
+
: z.array(parseSchema(jsonSchema.items, { ...refs, path: [...refs.path, 'items'] }));
|
|
11
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'minItems', (zs, minItems, errorMessage) => zs.min(minItems, errorMessage));
|
|
12
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'maxItems', (zs, maxItems, errorMessage) => zs.max(maxItems, errorMessage));
|
|
13
|
+
return zodSchema;
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const parseEnum = (jsonSchema) => {
|
|
3
|
+
if (jsonSchema.enum.length === 0) {
|
|
4
|
+
return z.never();
|
|
5
|
+
}
|
|
6
|
+
if (jsonSchema.enum.length === 1) {
|
|
7
|
+
// union does not work when there is only one element
|
|
8
|
+
return z.literal(jsonSchema.enum[0]);
|
|
9
|
+
}
|
|
10
|
+
if (jsonSchema.enum.every((x) => typeof x === 'string')) {
|
|
11
|
+
return z.enum(jsonSchema.enum);
|
|
12
|
+
}
|
|
13
|
+
return z.union(jsonSchema.enum.map((x) => z.literal(x)));
|
|
14
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { parseSchema } from './parse-schema';
|
|
3
|
+
export const parseIfThenElse = (jsonSchema, refs) => {
|
|
4
|
+
const $if = parseSchema(jsonSchema.if, { ...refs, path: [...refs.path, 'if'] });
|
|
5
|
+
const $then = parseSchema(jsonSchema.then, {
|
|
6
|
+
...refs,
|
|
7
|
+
path: [...refs.path, 'then'],
|
|
8
|
+
});
|
|
9
|
+
const $else = parseSchema(jsonSchema.else, {
|
|
10
|
+
...refs,
|
|
11
|
+
path: [...refs.path, 'else'],
|
|
12
|
+
});
|
|
13
|
+
return z.union([$then, $else]).superRefine((value, ctx) => {
|
|
14
|
+
const result = $if.safeParse(value).success ? $then.safeParse(value) : $else.safeParse(value);
|
|
15
|
+
if (!result.success) {
|
|
16
|
+
result.error.errors.forEach((error) => ctx.addIssue(error));
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { parseSchema } from './parse-schema';
|
|
3
|
+
export const parseNot = (jsonSchema, refs) => {
|
|
4
|
+
return z.any().refine((value) => !parseSchema(jsonSchema.not, {
|
|
5
|
+
...refs,
|
|
6
|
+
path: [...refs.path, 'not'],
|
|
7
|
+
}).safeParse(value).success, 'Invalid input: Should NOT be valid against schema');
|
|
8
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { parseSchema } from './parse-schema';
|
|
2
|
+
import { omit } from '../utils/omit';
|
|
3
|
+
/**
|
|
4
|
+
* For compatibility with open api 3.0 nullable
|
|
5
|
+
*/
|
|
6
|
+
export const parseNullable = (jsonSchema, refs) => {
|
|
7
|
+
return parseSchema(omit(jsonSchema, 'nullable'), refs, true).nullable();
|
|
8
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { extendSchemaWithMessage } from '../utils/extend-schema';
|
|
3
|
+
export const parseNumber = (jsonSchema) => {
|
|
4
|
+
let zodSchema = z.number();
|
|
5
|
+
let isInteger = false;
|
|
6
|
+
if (jsonSchema.type === 'integer') {
|
|
7
|
+
isInteger = true;
|
|
8
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'type', (zs, _, errorMsg) => zs.int(errorMsg));
|
|
9
|
+
}
|
|
10
|
+
else if (jsonSchema.format === 'int64') {
|
|
11
|
+
isInteger = true;
|
|
12
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'format', (zs, _, errorMsg) => zs.int(errorMsg));
|
|
13
|
+
}
|
|
14
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'multipleOf', (zs, multipleOf, errorMsg) => {
|
|
15
|
+
if (multipleOf === 1) {
|
|
16
|
+
if (isInteger)
|
|
17
|
+
return zs;
|
|
18
|
+
return zs.int(errorMsg);
|
|
19
|
+
}
|
|
20
|
+
return zs.multipleOf(multipleOf, errorMsg);
|
|
21
|
+
});
|
|
22
|
+
if (typeof jsonSchema.minimum === 'number') {
|
|
23
|
+
if (jsonSchema.exclusiveMinimum === true) {
|
|
24
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'minimum', (zs, minimum, errorMsg) => zs.gt(minimum, errorMsg));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'minimum', (zs, minimum, errorMsg) => zs.gte(minimum, errorMsg));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if (typeof jsonSchema.exclusiveMinimum === 'number') {
|
|
31
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'exclusiveMinimum', (zs, exclusiveMinimum, errorMsg) => zs.gt(exclusiveMinimum, errorMsg));
|
|
32
|
+
}
|
|
33
|
+
if (typeof jsonSchema.maximum === 'number') {
|
|
34
|
+
if (jsonSchema.exclusiveMaximum === true) {
|
|
35
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'maximum', (zs, maximum, errorMsg) => zs.lt(maximum, errorMsg));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'maximum', (zs, maximum, errorMsg) => zs.lte(maximum, errorMsg));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else if (typeof jsonSchema.exclusiveMaximum === 'number') {
|
|
42
|
+
zodSchema = extendSchemaWithMessage(zodSchema, jsonSchema, 'exclusiveMaximum', (zs, exclusiveMaximum, errorMsg) => zs.lt(exclusiveMaximum, errorMsg));
|
|
43
|
+
}
|
|
44
|
+
return zodSchema;
|
|
45
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import { parseAllOf } from './parse-all-of';
|
|
3
|
+
import { parseAnyOf } from './parse-any-of';
|
|
4
|
+
import { parseOneOf } from './parse-one-of';
|
|
5
|
+
import { parseSchema } from './parse-schema';
|
|
6
|
+
import { its } from '../utils/its';
|
|
7
|
+
function parseObjectProperties(objectSchema, refs) {
|
|
8
|
+
if (!objectSchema.properties) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
const propertyKeys = Object.keys(objectSchema.properties);
|
|
12
|
+
if (propertyKeys.length === 0) {
|
|
13
|
+
return z.object({});
|
|
14
|
+
}
|
|
15
|
+
const properties = {};
|
|
16
|
+
for (const key of propertyKeys) {
|
|
17
|
+
const propJsonSchema = objectSchema.properties[key];
|
|
18
|
+
const propZodSchema = parseSchema(propJsonSchema, {
|
|
19
|
+
...refs,
|
|
20
|
+
path: [...refs.path, 'properties', key],
|
|
21
|
+
});
|
|
22
|
+
const hasDefault = typeof propJsonSchema === 'object' && propJsonSchema.default !== undefined;
|
|
23
|
+
const required = Array.isArray(objectSchema.required)
|
|
24
|
+
? objectSchema.required.includes(key)
|
|
25
|
+
: typeof propJsonSchema === 'object' && propJsonSchema.required === true;
|
|
26
|
+
const isOptional = !hasDefault && !required;
|
|
27
|
+
properties[key] = isOptional ? propZodSchema.optional() : propZodSchema;
|
|
28
|
+
}
|
|
29
|
+
return z.object(properties);
|
|
30
|
+
}
|
|
31
|
+
export function parseObject(objectSchema, refs) {
|
|
32
|
+
const hasPatternProperties = Object.keys(objectSchema.patternProperties ?? {}).length > 0;
|
|
33
|
+
const propertiesSchema = parseObjectProperties(objectSchema, refs);
|
|
34
|
+
let zodSchema = propertiesSchema;
|
|
35
|
+
const additionalProperties = objectSchema.additionalProperties !== undefined
|
|
36
|
+
? parseSchema(objectSchema.additionalProperties, {
|
|
37
|
+
...refs,
|
|
38
|
+
path: [...refs.path, 'additionalProperties'],
|
|
39
|
+
})
|
|
40
|
+
: undefined;
|
|
41
|
+
if (objectSchema.patternProperties) {
|
|
42
|
+
const parsedPatternProperties = Object.fromEntries(Object.entries(objectSchema.patternProperties).map(([key, value]) => {
|
|
43
|
+
return [
|
|
44
|
+
key,
|
|
45
|
+
parseSchema(value, {
|
|
46
|
+
...refs,
|
|
47
|
+
path: [...refs.path, 'patternProperties', key],
|
|
48
|
+
}),
|
|
49
|
+
];
|
|
50
|
+
}));
|
|
51
|
+
const patternPropertyValues = Object.values(parsedPatternProperties);
|
|
52
|
+
if (propertiesSchema) {
|
|
53
|
+
if (additionalProperties) {
|
|
54
|
+
zodSchema = propertiesSchema.catchall(z.union([...patternPropertyValues, additionalProperties]));
|
|
55
|
+
}
|
|
56
|
+
else if (Object.keys(parsedPatternProperties).length > 1) {
|
|
57
|
+
zodSchema = propertiesSchema.catchall(z.union(patternPropertyValues));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
zodSchema = propertiesSchema.catchall(patternPropertyValues[0]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
if (additionalProperties) {
|
|
65
|
+
zodSchema = z.record(z.union([...patternPropertyValues, additionalProperties]));
|
|
66
|
+
}
|
|
67
|
+
else if (patternPropertyValues.length > 1) {
|
|
68
|
+
zodSchema = z.record(z.union(patternPropertyValues));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
zodSchema = z.record(patternPropertyValues[0]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const objectPropertyKeys = new Set(Object.keys(objectSchema.properties ?? {}));
|
|
75
|
+
zodSchema = zodSchema.superRefine((value, ctx) => {
|
|
76
|
+
for (const key in value) {
|
|
77
|
+
let wasMatched = objectPropertyKeys.has(key);
|
|
78
|
+
for (const patternPropertyKey in objectSchema.patternProperties) {
|
|
79
|
+
const regex = new RegExp(patternPropertyKey);
|
|
80
|
+
if (key.match(regex)) {
|
|
81
|
+
wasMatched = true;
|
|
82
|
+
const result = parsedPatternProperties[patternPropertyKey].safeParse(value[key]);
|
|
83
|
+
if (!result.success) {
|
|
84
|
+
ctx.addIssue({
|
|
85
|
+
path: [...ctx.path, key],
|
|
86
|
+
code: 'custom',
|
|
87
|
+
message: `Invalid input: Key matching regex /${key}/ must match schema`,
|
|
88
|
+
params: {
|
|
89
|
+
issues: result.error.issues,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!wasMatched && additionalProperties) {
|
|
96
|
+
const result = additionalProperties.safeParse(value[key]);
|
|
97
|
+
if (!result.success) {
|
|
98
|
+
ctx.addIssue({
|
|
99
|
+
path: [...ctx.path, key],
|
|
100
|
+
code: 'custom',
|
|
101
|
+
message: 'Invalid input: must match catchall schema',
|
|
102
|
+
params: {
|
|
103
|
+
issues: result.error.issues,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
let output;
|
|
112
|
+
if (propertiesSchema) {
|
|
113
|
+
if (hasPatternProperties) {
|
|
114
|
+
output = zodSchema;
|
|
115
|
+
}
|
|
116
|
+
else if (additionalProperties) {
|
|
117
|
+
if (additionalProperties instanceof z.ZodNever) {
|
|
118
|
+
output = propertiesSchema.strict();
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
output = propertiesSchema.catchall(additionalProperties);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
output = zodSchema;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
if (hasPatternProperties) {
|
|
130
|
+
output = zodSchema;
|
|
131
|
+
}
|
|
132
|
+
else if (additionalProperties) {
|
|
133
|
+
output = z.record(additionalProperties);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
output = z.record(z.any());
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (its.an.anyOf(objectSchema)) {
|
|
140
|
+
output = output.and(parseAnyOf({
|
|
141
|
+
...objectSchema,
|
|
142
|
+
anyOf: objectSchema.anyOf.map((x) => typeof x === 'object' &&
|
|
143
|
+
!x.type &&
|
|
144
|
+
(x.properties ?? x.additionalProperties ?? x.patternProperties)
|
|
145
|
+
? { ...x, type: 'object' }
|
|
146
|
+
: x),
|
|
147
|
+
}, refs));
|
|
148
|
+
}
|
|
149
|
+
if (its.a.oneOf(objectSchema)) {
|
|
150
|
+
output = output.and(parseOneOf({
|
|
151
|
+
...objectSchema,
|
|
152
|
+
oneOf: objectSchema.oneOf.map((x) => typeof x === 'object' &&
|
|
153
|
+
!x.type &&
|
|
154
|
+
(x.properties ?? x.additionalProperties ?? x.patternProperties)
|
|
155
|
+
? { ...x, type: 'object' }
|
|
156
|
+
: x),
|
|
157
|
+
}, refs));
|
|
158
|
+
}
|
|
159
|
+
if (its.an.allOf(objectSchema)) {
|
|
160
|
+
output = output.and(parseAllOf({
|
|
161
|
+
...objectSchema,
|
|
162
|
+
allOf: objectSchema.allOf.map((x) => typeof x === 'object' &&
|
|
163
|
+
!x.type &&
|
|
164
|
+
(x.properties ?? x.additionalProperties ?? x.patternProperties)
|
|
165
|
+
? { ...x, type: 'object' }
|
|
166
|
+
: x),
|
|
167
|
+
}, refs));
|
|
168
|
+
}
|
|
169
|
+
return output;
|
|
170
|
+
}
|