@gabrielbryk/json-schema-to-zod 2.7.2
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/.prettierrc.json +3 -0
- package/CONTRIBUTING.md +9 -0
- package/LICENSE +15 -0
- package/README.md +157 -0
- package/createIndex.ts +32 -0
- package/dist/cjs/Types.js +2 -0
- package/dist/cjs/cli.js +70 -0
- package/dist/cjs/index.js +44 -0
- package/dist/cjs/jsonSchemaToZod.js +78 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/parsers/parseAllOf.js +40 -0
- package/dist/cjs/parsers/parseAnyOf.js +18 -0
- package/dist/cjs/parsers/parseArray.js +71 -0
- package/dist/cjs/parsers/parseBoolean.js +7 -0
- package/dist/cjs/parsers/parseConst.js +7 -0
- package/dist/cjs/parsers/parseDefault.js +8 -0
- package/dist/cjs/parsers/parseEnum.js +21 -0
- package/dist/cjs/parsers/parseIfThenElse.js +34 -0
- package/dist/cjs/parsers/parseMultipleType.js +10 -0
- package/dist/cjs/parsers/parseNot.js +12 -0
- package/dist/cjs/parsers/parseNull.js +7 -0
- package/dist/cjs/parsers/parseNullable.js +12 -0
- package/dist/cjs/parsers/parseNumber.js +74 -0
- package/dist/cjs/parsers/parseObject.js +286 -0
- package/dist/cjs/parsers/parseOneOf.js +53 -0
- package/dist/cjs/parsers/parseSchema.js +285 -0
- package/dist/cjs/parsers/parseSimpleDiscriminatedOneOf.js +29 -0
- package/dist/cjs/parsers/parseString.js +77 -0
- package/dist/cjs/utils/anyOrUnknown.js +14 -0
- package/dist/cjs/utils/cliTools.js +108 -0
- package/dist/cjs/utils/half.js +7 -0
- package/dist/cjs/utils/jsdocs.js +20 -0
- package/dist/cjs/utils/omit.js +10 -0
- package/dist/cjs/utils/withMessage.js +22 -0
- package/dist/cjs/zodToJsonSchema.js +89 -0
- package/dist/esm/Types.js +1 -0
- package/dist/esm/cli.js +68 -0
- package/dist/esm/index.js +28 -0
- package/dist/esm/jsonSchemaToZod.js +74 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/parsers/parseAllOf.js +37 -0
- package/dist/esm/parsers/parseAnyOf.js +14 -0
- package/dist/esm/parsers/parseArray.js +67 -0
- package/dist/esm/parsers/parseBoolean.js +3 -0
- package/dist/esm/parsers/parseConst.js +3 -0
- package/dist/esm/parsers/parseDefault.js +4 -0
- package/dist/esm/parsers/parseEnum.js +17 -0
- package/dist/esm/parsers/parseIfThenElse.js +30 -0
- package/dist/esm/parsers/parseMultipleType.js +6 -0
- package/dist/esm/parsers/parseNot.js +8 -0
- package/dist/esm/parsers/parseNull.js +3 -0
- package/dist/esm/parsers/parseNullable.js +8 -0
- package/dist/esm/parsers/parseNumber.js +70 -0
- package/dist/esm/parsers/parseObject.js +283 -0
- package/dist/esm/parsers/parseOneOf.js +49 -0
- package/dist/esm/parsers/parseSchema.js +281 -0
- package/dist/esm/parsers/parseSimpleDiscriminatedOneOf.js +25 -0
- package/dist/esm/parsers/parseString.js +73 -0
- package/dist/esm/utils/anyOrUnknown.js +10 -0
- package/dist/esm/utils/cliTools.js +102 -0
- package/dist/esm/utils/half.js +3 -0
- package/dist/esm/utils/jsdocs.js +15 -0
- package/dist/esm/utils/omit.js +6 -0
- package/dist/esm/utils/withMessage.js +19 -0
- package/dist/esm/zodToJsonSchema.js +86 -0
- package/dist/types/Types.d.ts +125 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/jsonSchemaToZod.d.ts +2 -0
- package/dist/types/parsers/parseAllOf.d.ts +4 -0
- package/dist/types/parsers/parseAnyOf.d.ts +4 -0
- package/dist/types/parsers/parseArray.d.ts +4 -0
- package/dist/types/parsers/parseBoolean.d.ts +4 -0
- package/dist/types/parsers/parseConst.d.ts +4 -0
- package/dist/types/parsers/parseDefault.d.ts +2 -0
- package/dist/types/parsers/parseEnum.d.ts +4 -0
- package/dist/types/parsers/parseIfThenElse.d.ts +6 -0
- package/dist/types/parsers/parseMultipleType.d.ts +4 -0
- package/dist/types/parsers/parseNot.d.ts +4 -0
- package/dist/types/parsers/parseNull.d.ts +4 -0
- package/dist/types/parsers/parseNullable.d.ts +7 -0
- package/dist/types/parsers/parseNumber.d.ts +4 -0
- package/dist/types/parsers/parseObject.d.ts +4 -0
- package/dist/types/parsers/parseOneOf.d.ts +4 -0
- package/dist/types/parsers/parseSchema.d.ts +50 -0
- package/dist/types/parsers/parseSimpleDiscriminatedOneOf.d.ts +2 -0
- package/dist/types/parsers/parseString.d.ts +4 -0
- package/dist/types/utils/anyOrUnknown.d.ts +9 -0
- package/dist/types/utils/cliTools.d.ts +28 -0
- package/dist/types/utils/half.d.ts +1 -0
- package/dist/types/utils/jsdocs.d.ts +3 -0
- package/dist/types/utils/omit.d.ts +1 -0
- package/dist/types/utils/withMessage.d.ts +10 -0
- package/dist/types/zodToJsonSchema.d.ts +26 -0
- package/jest.config.js +4 -0
- package/package.json +83 -0
- package/postcjs.js +1 -0
- package/postesm.js +1 -0
- package/scripts/generateWorkflowSchema.ts +82 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.its = exports.parseSchema = void 0;
|
|
4
|
+
const parseAnyOf_js_1 = require("./parseAnyOf.js");
|
|
5
|
+
const parseBoolean_js_1 = require("./parseBoolean.js");
|
|
6
|
+
const parseDefault_js_1 = require("./parseDefault.js");
|
|
7
|
+
const parseMultipleType_js_1 = require("./parseMultipleType.js");
|
|
8
|
+
const parseNot_js_1 = require("./parseNot.js");
|
|
9
|
+
const parseNull_js_1 = require("./parseNull.js");
|
|
10
|
+
const parseAllOf_js_1 = require("./parseAllOf.js");
|
|
11
|
+
const parseArray_js_1 = require("./parseArray.js");
|
|
12
|
+
const parseConst_js_1 = require("./parseConst.js");
|
|
13
|
+
const parseEnum_js_1 = require("./parseEnum.js");
|
|
14
|
+
const parseIfThenElse_js_1 = require("./parseIfThenElse.js");
|
|
15
|
+
const parseNumber_js_1 = require("./parseNumber.js");
|
|
16
|
+
const parseObject_js_1 = require("./parseObject.js");
|
|
17
|
+
const parseString_js_1 = require("./parseString.js");
|
|
18
|
+
const parseOneOf_js_1 = require("./parseOneOf.js");
|
|
19
|
+
const parseSimpleDiscriminatedOneOf_js_1 = require("./parseSimpleDiscriminatedOneOf.js");
|
|
20
|
+
const parseNullable_js_1 = require("./parseNullable.js");
|
|
21
|
+
const anyOrUnknown_js_1 = require("../utils/anyOrUnknown.js");
|
|
22
|
+
const parseSchema = (schema, refs = { seen: new Map(), path: [] }, blockMeta) => {
|
|
23
|
+
// Ensure ref bookkeeping exists so $ref declarations and getter-based recursion work
|
|
24
|
+
refs.root = refs.root ?? schema;
|
|
25
|
+
refs.declarations = refs.declarations ?? new Map();
|
|
26
|
+
refs.inProgress = refs.inProgress ?? new Set();
|
|
27
|
+
refs.refNameByPointer = refs.refNameByPointer ?? new Map();
|
|
28
|
+
refs.usedNames = refs.usedNames ?? new Set();
|
|
29
|
+
if (typeof schema !== "object")
|
|
30
|
+
return schema ? (0, anyOrUnknown_js_1.anyOrUnknown)(refs) : "z.never()";
|
|
31
|
+
if (refs.parserOverride) {
|
|
32
|
+
const custom = refs.parserOverride(schema, refs);
|
|
33
|
+
if (typeof custom === "string") {
|
|
34
|
+
return custom;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
let seen = refs.seen.get(schema);
|
|
38
|
+
if (seen) {
|
|
39
|
+
if (seen.r !== undefined) {
|
|
40
|
+
return seen.r;
|
|
41
|
+
}
|
|
42
|
+
if (refs.depth === undefined || seen.n >= refs.depth) {
|
|
43
|
+
return (0, anyOrUnknown_js_1.anyOrUnknown)(refs);
|
|
44
|
+
}
|
|
45
|
+
seen.n += 1;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
seen = { r: undefined, n: 0 };
|
|
49
|
+
refs.seen.set(schema, seen);
|
|
50
|
+
}
|
|
51
|
+
if (exports.its.a.ref(schema)) {
|
|
52
|
+
const parsedRef = parseRef(schema, refs);
|
|
53
|
+
seen.r = parsedRef;
|
|
54
|
+
return parsedRef;
|
|
55
|
+
}
|
|
56
|
+
let parsed = selectParser(schema, refs);
|
|
57
|
+
if (!blockMeta) {
|
|
58
|
+
if (!refs.withoutDescribes) {
|
|
59
|
+
parsed = addDescribes(schema, parsed, refs);
|
|
60
|
+
}
|
|
61
|
+
if (!refs.withoutDefaults) {
|
|
62
|
+
parsed = addDefaults(schema, parsed);
|
|
63
|
+
}
|
|
64
|
+
parsed = addAnnotations(schema, parsed);
|
|
65
|
+
}
|
|
66
|
+
seen.r = parsed;
|
|
67
|
+
return parsed;
|
|
68
|
+
};
|
|
69
|
+
exports.parseSchema = parseSchema;
|
|
70
|
+
const parseRef = (schema, refs) => {
|
|
71
|
+
const resolved = resolveRef(refs.root, schema.$ref);
|
|
72
|
+
if (!resolved) {
|
|
73
|
+
return (0, anyOrUnknown_js_1.anyOrUnknown)(refs);
|
|
74
|
+
}
|
|
75
|
+
const { schema: target, path } = resolved;
|
|
76
|
+
const refName = getOrCreateRefName(schema.$ref, path, refs);
|
|
77
|
+
if (!refs.declarations.has(refName) && !refs.inProgress.has(refName)) {
|
|
78
|
+
refs.inProgress.add(refName);
|
|
79
|
+
const declaration = (0, exports.parseSchema)(target, {
|
|
80
|
+
...refs,
|
|
81
|
+
path,
|
|
82
|
+
currentSchemaName: refName,
|
|
83
|
+
root: refs.root,
|
|
84
|
+
});
|
|
85
|
+
refs.inProgress.delete(refName);
|
|
86
|
+
refs.declarations.set(refName, declaration);
|
|
87
|
+
}
|
|
88
|
+
return refName;
|
|
89
|
+
};
|
|
90
|
+
const addDescribes = (schema, parsed, refs) => {
|
|
91
|
+
// Use .meta() for richer metadata when withMeta is enabled
|
|
92
|
+
if (refs?.withMeta) {
|
|
93
|
+
const meta = {};
|
|
94
|
+
if (schema.$id)
|
|
95
|
+
meta.id = schema.$id;
|
|
96
|
+
if (schema.title)
|
|
97
|
+
meta.title = schema.title;
|
|
98
|
+
if (schema.description)
|
|
99
|
+
meta.description = schema.description;
|
|
100
|
+
if (schema.examples)
|
|
101
|
+
meta.examples = schema.examples;
|
|
102
|
+
if (schema.deprecated)
|
|
103
|
+
meta.deprecated = schema.deprecated;
|
|
104
|
+
if (Object.keys(meta).length > 0) {
|
|
105
|
+
parsed += `.meta(${JSON.stringify(meta)})`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (schema.description) {
|
|
109
|
+
parsed += `.describe(${JSON.stringify(schema.description)})`;
|
|
110
|
+
}
|
|
111
|
+
return parsed;
|
|
112
|
+
};
|
|
113
|
+
const resolveRef = (root, ref) => {
|
|
114
|
+
if (!root || !ref.startsWith("#/"))
|
|
115
|
+
return undefined;
|
|
116
|
+
const rawSegments = ref
|
|
117
|
+
.slice(2)
|
|
118
|
+
.split("/")
|
|
119
|
+
.filter((segment) => segment.length > 0)
|
|
120
|
+
.map(decodePointerSegment);
|
|
121
|
+
let current = root;
|
|
122
|
+
for (const segment of rawSegments) {
|
|
123
|
+
if (typeof current !== "object" || current === null)
|
|
124
|
+
return undefined;
|
|
125
|
+
current = current[segment];
|
|
126
|
+
}
|
|
127
|
+
return { schema: current, path: rawSegments };
|
|
128
|
+
};
|
|
129
|
+
const decodePointerSegment = (segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
130
|
+
const getOrCreateRefName = (pointer, path, refs) => {
|
|
131
|
+
if (refs.refNameByPointer?.has(pointer)) {
|
|
132
|
+
return refs.refNameByPointer.get(pointer);
|
|
133
|
+
}
|
|
134
|
+
const preferred = buildNameFromPath(path, refs.usedNames);
|
|
135
|
+
refs.refNameByPointer?.set(pointer, preferred);
|
|
136
|
+
refs.usedNames?.add(preferred);
|
|
137
|
+
return preferred;
|
|
138
|
+
};
|
|
139
|
+
const buildNameFromPath = (path, used) => {
|
|
140
|
+
const filtered = path.filter((segment) => segment !== "$defs" && segment !== "definitions" && segment !== "properties");
|
|
141
|
+
const base = filtered.length
|
|
142
|
+
? filtered
|
|
143
|
+
.map((segment) => typeof segment === "number"
|
|
144
|
+
? `Ref${segment}`
|
|
145
|
+
: segment
|
|
146
|
+
.replace(/[^a-zA-Z0-9_$]/g, " ")
|
|
147
|
+
.split(" ")
|
|
148
|
+
.filter(Boolean)
|
|
149
|
+
.map(capitalize)
|
|
150
|
+
.join(""))
|
|
151
|
+
.join("")
|
|
152
|
+
: "Ref";
|
|
153
|
+
const sanitized = sanitizeIdentifier(base || "Ref");
|
|
154
|
+
if (!used || !used.has(sanitized))
|
|
155
|
+
return sanitized;
|
|
156
|
+
let counter = 2;
|
|
157
|
+
let candidate = `${sanitized}${counter}`;
|
|
158
|
+
while (used.has(candidate)) {
|
|
159
|
+
counter += 1;
|
|
160
|
+
candidate = `${sanitized}${counter}`;
|
|
161
|
+
}
|
|
162
|
+
return candidate;
|
|
163
|
+
};
|
|
164
|
+
const sanitizeIdentifier = (value) => {
|
|
165
|
+
const cleaned = value.replace(/^[^a-zA-Z_$]+/, "").replace(/[^a-zA-Z0-9_$]/g, "");
|
|
166
|
+
return cleaned || "Ref";
|
|
167
|
+
};
|
|
168
|
+
const capitalize = (value) => value.length ? value[0].toUpperCase() + value.slice(1) : value;
|
|
169
|
+
const addDefaults = (schema, parsed) => {
|
|
170
|
+
if (schema.default !== undefined) {
|
|
171
|
+
parsed += `.default(${JSON.stringify(schema.default)})`;
|
|
172
|
+
}
|
|
173
|
+
return parsed;
|
|
174
|
+
};
|
|
175
|
+
const addAnnotations = (schema, parsed) => {
|
|
176
|
+
if (schema.readOnly) {
|
|
177
|
+
parsed += ".readonly()";
|
|
178
|
+
}
|
|
179
|
+
return parsed;
|
|
180
|
+
};
|
|
181
|
+
const selectParser = (schema, refs) => {
|
|
182
|
+
if (exports.its.a.nullable(schema)) {
|
|
183
|
+
return (0, parseNullable_js_1.parseNullable)(schema, refs);
|
|
184
|
+
}
|
|
185
|
+
else if (exports.its.an.object(schema)) {
|
|
186
|
+
return (0, parseObject_js_1.parseObject)(schema, refs);
|
|
187
|
+
}
|
|
188
|
+
else if (exports.its.an.array(schema)) {
|
|
189
|
+
return (0, parseArray_js_1.parseArray)(schema, refs);
|
|
190
|
+
}
|
|
191
|
+
else if (exports.its.an.anyOf(schema)) {
|
|
192
|
+
return (0, parseAnyOf_js_1.parseAnyOf)(schema, refs);
|
|
193
|
+
}
|
|
194
|
+
else if (exports.its.an.allOf(schema)) {
|
|
195
|
+
return (0, parseAllOf_js_1.parseAllOf)(schema, refs);
|
|
196
|
+
}
|
|
197
|
+
else if (exports.its.a.simpleDiscriminatedOneOf(schema)) {
|
|
198
|
+
return (0, parseSimpleDiscriminatedOneOf_js_1.parseSimpleDiscriminatedOneOf)(schema, refs);
|
|
199
|
+
}
|
|
200
|
+
else if (exports.its.a.oneOf(schema)) {
|
|
201
|
+
return (0, parseOneOf_js_1.parseOneOf)(schema, refs);
|
|
202
|
+
}
|
|
203
|
+
else if (exports.its.a.not(schema)) {
|
|
204
|
+
return (0, parseNot_js_1.parseNot)(schema, refs);
|
|
205
|
+
}
|
|
206
|
+
else if (exports.its.an.enum(schema)) {
|
|
207
|
+
return (0, parseEnum_js_1.parseEnum)(schema); //<-- needs to come before primitives
|
|
208
|
+
}
|
|
209
|
+
else if (exports.its.a.const(schema)) {
|
|
210
|
+
return (0, parseConst_js_1.parseConst)(schema);
|
|
211
|
+
}
|
|
212
|
+
else if (exports.its.a.multipleType(schema)) {
|
|
213
|
+
return (0, parseMultipleType_js_1.parseMultipleType)(schema, refs);
|
|
214
|
+
}
|
|
215
|
+
else if (exports.its.a.primitive(schema, "string")) {
|
|
216
|
+
return (0, parseString_js_1.parseString)(schema);
|
|
217
|
+
}
|
|
218
|
+
else if (exports.its.a.primitive(schema, "number") ||
|
|
219
|
+
exports.its.a.primitive(schema, "integer")) {
|
|
220
|
+
return (0, parseNumber_js_1.parseNumber)(schema);
|
|
221
|
+
}
|
|
222
|
+
else if (exports.its.a.primitive(schema, "boolean")) {
|
|
223
|
+
return (0, parseBoolean_js_1.parseBoolean)(schema);
|
|
224
|
+
}
|
|
225
|
+
else if (exports.its.a.primitive(schema, "null")) {
|
|
226
|
+
return (0, parseNull_js_1.parseNull)(schema);
|
|
227
|
+
}
|
|
228
|
+
else if (exports.its.a.conditional(schema)) {
|
|
229
|
+
return (0, parseIfThenElse_js_1.parseIfThenElse)(schema, refs);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
return (0, parseDefault_js_1.parseDefault)(schema, refs);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
exports.its = {
|
|
236
|
+
an: {
|
|
237
|
+
object: (x) => x.type === "object",
|
|
238
|
+
array: (x) => x.type === "array",
|
|
239
|
+
anyOf: (x) => x.anyOf !== undefined,
|
|
240
|
+
allOf: (x) => x.allOf !== undefined,
|
|
241
|
+
enum: (x) => x.enum !== undefined,
|
|
242
|
+
},
|
|
243
|
+
a: {
|
|
244
|
+
nullable: (x) => x.nullable === true,
|
|
245
|
+
multipleType: (x) => Array.isArray(x.type),
|
|
246
|
+
not: (x) => x.not !== undefined,
|
|
247
|
+
ref: (x) => typeof x.$ref === "string",
|
|
248
|
+
const: (x) => x.const !== undefined,
|
|
249
|
+
primitive: (x, p) => x.type === p,
|
|
250
|
+
conditional: (x) => Boolean("if" in x && x.if && "then" in x && "else" in x && x.then && x.else),
|
|
251
|
+
simpleDiscriminatedOneOf: (x) => {
|
|
252
|
+
if (!x.oneOf ||
|
|
253
|
+
!Array.isArray(x.oneOf) ||
|
|
254
|
+
x.oneOf.length === 0 ||
|
|
255
|
+
!x.discriminator ||
|
|
256
|
+
typeof x.discriminator !== "object" ||
|
|
257
|
+
!("propertyName" in x.discriminator) ||
|
|
258
|
+
typeof x.discriminator.propertyName !== "string") {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
const discriminatorProp = x.discriminator.propertyName;
|
|
262
|
+
return x.oneOf.every((schema) => {
|
|
263
|
+
if (!schema ||
|
|
264
|
+
typeof schema !== "object" ||
|
|
265
|
+
schema.type !== "object" ||
|
|
266
|
+
!schema.properties ||
|
|
267
|
+
typeof schema.properties !== "object" ||
|
|
268
|
+
!(discriminatorProp in schema.properties)) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
const property = schema.properties[discriminatorProp];
|
|
272
|
+
return (property &&
|
|
273
|
+
typeof property === "object" &&
|
|
274
|
+
(property.type === undefined || property.type === "string") &&
|
|
275
|
+
// Ensure discriminator has a constant value (const or single-value enum)
|
|
276
|
+
(property.const !== undefined ||
|
|
277
|
+
(property.enum && Array.isArray(property.enum) && property.enum.length === 1)) &&
|
|
278
|
+
// Ensure discriminator property is required
|
|
279
|
+
Array.isArray(schema.required) &&
|
|
280
|
+
schema.required.includes(discriminatorProp));
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
oneOf: (x) => x.oneOf !== undefined,
|
|
284
|
+
},
|
|
285
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSimpleDiscriminatedOneOf = void 0;
|
|
4
|
+
const parseSchema_js_1 = require("./parseSchema.js");
|
|
5
|
+
const anyOrUnknown_js_1 = require("../utils/anyOrUnknown.js");
|
|
6
|
+
const parseSimpleDiscriminatedOneOf = (schema, refs) => {
|
|
7
|
+
const discriminator = schema.discriminator.propertyName;
|
|
8
|
+
const entries = schema.oneOf.map((option, i) => {
|
|
9
|
+
const opt = option;
|
|
10
|
+
const discriminatorSchema = opt.properties[discriminator];
|
|
11
|
+
const value = discriminatorSchema.const ??
|
|
12
|
+
(discriminatorSchema.enum && discriminatorSchema.enum[0]);
|
|
13
|
+
const parsed = (0, parseSchema_js_1.parseSchema)(option, {
|
|
14
|
+
...refs,
|
|
15
|
+
path: [...refs.path, "oneOf", i],
|
|
16
|
+
});
|
|
17
|
+
const key = typeof value === "string" ? JSON.stringify(value) : JSON.stringify(String(value));
|
|
18
|
+
return `${key}: ${parsed}`;
|
|
19
|
+
});
|
|
20
|
+
return schema.oneOf.length
|
|
21
|
+
? schema.oneOf.length === 1
|
|
22
|
+
? (0, parseSchema_js_1.parseSchema)(schema.oneOf[0], {
|
|
23
|
+
...refs,
|
|
24
|
+
path: [...refs.path, "oneOf", 0],
|
|
25
|
+
})
|
|
26
|
+
: `z.discriminatedUnion("${discriminator}", { ${entries.join(", ")} })`
|
|
27
|
+
: (0, anyOrUnknown_js_1.anyOrUnknown)(refs);
|
|
28
|
+
};
|
|
29
|
+
exports.parseSimpleDiscriminatedOneOf = parseSimpleDiscriminatedOneOf;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseString = void 0;
|
|
4
|
+
const withMessage_js_1 = require("../utils/withMessage.js");
|
|
5
|
+
const parseSchema_js_1 = require("./parseSchema.js");
|
|
6
|
+
const parseString = (schema) => {
|
|
7
|
+
let r = "z.string()";
|
|
8
|
+
r += (0, withMessage_js_1.withMessage)(schema, "format", ({ value }) => {
|
|
9
|
+
switch (value) {
|
|
10
|
+
case "email":
|
|
11
|
+
return [".email(", ")"];
|
|
12
|
+
case "ip":
|
|
13
|
+
return [".ip(", ")"];
|
|
14
|
+
case "ipv4":
|
|
15
|
+
return ['.ip({ version: "v4"', ", message: ", " })"];
|
|
16
|
+
case "ipv6":
|
|
17
|
+
return ['.ip({ version: "v6"', ", message: ", " })"];
|
|
18
|
+
case "uri":
|
|
19
|
+
return [".url(", ")"];
|
|
20
|
+
case "uuid":
|
|
21
|
+
return [".uuid(", ")"];
|
|
22
|
+
case "date-time":
|
|
23
|
+
return [".datetime({ offset: true", ", message: ", " })"];
|
|
24
|
+
case "time":
|
|
25
|
+
return [".time(", ")"];
|
|
26
|
+
case "date":
|
|
27
|
+
return [".date(", ")"];
|
|
28
|
+
case "binary":
|
|
29
|
+
return [".base64(", ")"];
|
|
30
|
+
case "duration":
|
|
31
|
+
return [".duration(", ")"];
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
r += (0, withMessage_js_1.withMessage)(schema, "pattern", ({ json }) => [
|
|
35
|
+
`.regex(new RegExp(${json})`,
|
|
36
|
+
", ",
|
|
37
|
+
")",
|
|
38
|
+
]);
|
|
39
|
+
r += (0, withMessage_js_1.withMessage)(schema, "minLength", ({ json }) => [
|
|
40
|
+
`.min(${json}`,
|
|
41
|
+
", ",
|
|
42
|
+
")",
|
|
43
|
+
]);
|
|
44
|
+
r += (0, withMessage_js_1.withMessage)(schema, "maxLength", ({ json }) => [
|
|
45
|
+
`.max(${json}`,
|
|
46
|
+
", ",
|
|
47
|
+
")",
|
|
48
|
+
]);
|
|
49
|
+
r += (0, withMessage_js_1.withMessage)(schema, "contentEncoding", ({ value }) => {
|
|
50
|
+
if (value === "base64") {
|
|
51
|
+
return [".base64(", ")"];
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
const contentMediaType = (0, withMessage_js_1.withMessage)(schema, "contentMediaType", ({ value }) => {
|
|
55
|
+
if (value === "application/json") {
|
|
56
|
+
return [
|
|
57
|
+
".transform((str, ctx) => { try { return JSON.parse(str); } catch (err) { ctx.addIssue({ code: \"custom\", message: \"Invalid JSON\" }); }}",
|
|
58
|
+
", ",
|
|
59
|
+
")"
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
if (contentMediaType != "") {
|
|
64
|
+
r += contentMediaType;
|
|
65
|
+
r += (0, withMessage_js_1.withMessage)(schema, "contentSchema", ({ value }) => {
|
|
66
|
+
if (value && value instanceof Object) {
|
|
67
|
+
return [
|
|
68
|
+
`.pipe(${(0, parseSchema_js_1.parseSchema)(value)}`,
|
|
69
|
+
", ",
|
|
70
|
+
")"
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return r;
|
|
76
|
+
};
|
|
77
|
+
exports.parseString = parseString;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.anyOrUnknown = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Returns "z.unknown()" if the useUnknown option is enabled, otherwise "z.any()".
|
|
6
|
+
* This helper is used throughout the library for fallback cases.
|
|
7
|
+
*
|
|
8
|
+
* @param refs - The refs object containing options
|
|
9
|
+
* @returns The appropriate Zod schema string
|
|
10
|
+
*/
|
|
11
|
+
const anyOrUnknown = (refs) => {
|
|
12
|
+
return refs?.useUnknown ? "z.unknown()" : "z.any()";
|
|
13
|
+
};
|
|
14
|
+
exports.anyOrUnknown = anyOrUnknown;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseArgs = parseArgs;
|
|
4
|
+
exports.parseOrReadJSON = parseOrReadJSON;
|
|
5
|
+
exports.readPipe = readPipe;
|
|
6
|
+
exports.printParams = printParams;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
function parseArgs(params, args, help) {
|
|
9
|
+
const result = {};
|
|
10
|
+
if (help) {
|
|
11
|
+
let index = args.indexOf("--help");
|
|
12
|
+
if (index === -1) {
|
|
13
|
+
index = args.indexOf("-h");
|
|
14
|
+
}
|
|
15
|
+
if (index !== -1) {
|
|
16
|
+
printParams({
|
|
17
|
+
...params,
|
|
18
|
+
help: {
|
|
19
|
+
shorthand: "h",
|
|
20
|
+
description: typeof help === "string" ? help : "Display this message :)",
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
for (const name in params) {
|
|
27
|
+
const { shorthand, required, value } = params[name];
|
|
28
|
+
let index = args.indexOf("--" + name);
|
|
29
|
+
if (index === -1 && shorthand) {
|
|
30
|
+
index = args.indexOf("-" + shorthand);
|
|
31
|
+
}
|
|
32
|
+
if (index === -1) {
|
|
33
|
+
if (required || required === "") {
|
|
34
|
+
throw new Error(typeof required === "string" && required !== ""
|
|
35
|
+
? required
|
|
36
|
+
: `Missing required argument ${name}`);
|
|
37
|
+
}
|
|
38
|
+
result[name] = false;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (value) {
|
|
42
|
+
const val = args[index + 1];
|
|
43
|
+
if (val === undefined) {
|
|
44
|
+
throw new Error(`Expected a value for argument ${name}`);
|
|
45
|
+
}
|
|
46
|
+
if (value === "number") {
|
|
47
|
+
const asNumber = Number(val);
|
|
48
|
+
if (isNaN(asNumber)) {
|
|
49
|
+
throw new Error(`Value of argument ${name} must be a valid number`);
|
|
50
|
+
}
|
|
51
|
+
result[name] = asNumber;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(value) && !value.includes(val)) {
|
|
55
|
+
throw new Error(`Value of argument ${name} must be one of ${value}`);
|
|
56
|
+
}
|
|
57
|
+
result[name] = val;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
result[name] = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
function parseOrReadJSON(jsonOrPath) {
|
|
66
|
+
jsonOrPath = jsonOrPath.trim();
|
|
67
|
+
if (jsonOrPath.length < 255 &&
|
|
68
|
+
(0, fs_1.statSync)(jsonOrPath, { throwIfNoEntry: false })?.isFile()) {
|
|
69
|
+
jsonOrPath = (0, fs_1.readFileSync)(jsonOrPath, "utf-8");
|
|
70
|
+
}
|
|
71
|
+
return JSON.parse(jsonOrPath);
|
|
72
|
+
}
|
|
73
|
+
function readPipe() {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
let buf = "";
|
|
76
|
+
process.stdin
|
|
77
|
+
.setEncoding("utf-8")
|
|
78
|
+
.on("end", () => resolve(buf))
|
|
79
|
+
.on("error", reject)
|
|
80
|
+
.on("readable", () => {
|
|
81
|
+
let chunk;
|
|
82
|
+
while ((chunk = process.stdin.read()) != null) {
|
|
83
|
+
buf += chunk;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function printParams(params) {
|
|
89
|
+
const longest = Object.keys(params).reduce((l, c) => (c.length > l ? c.length : l), 5);
|
|
90
|
+
const header = "Name " + " ".repeat(longest - 2) + "Short Description";
|
|
91
|
+
console.log(header);
|
|
92
|
+
for (const name in params) {
|
|
93
|
+
let { shorthand, description } = params[name];
|
|
94
|
+
if (shorthand) {
|
|
95
|
+
shorthand = " -" + shorthand;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
shorthand = " ";
|
|
99
|
+
}
|
|
100
|
+
if (description) {
|
|
101
|
+
description = " " + description;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
description = "";
|
|
105
|
+
}
|
|
106
|
+
console.log("--" + name + " ".repeat(longest - name.length) + shorthand + description);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addJsdocs = exports.expandJsdocs = void 0;
|
|
4
|
+
const expandJsdocs = (jsdocs) => {
|
|
5
|
+
const lines = jsdocs.split("\n");
|
|
6
|
+
const result = lines.length === 1
|
|
7
|
+
? lines[0]
|
|
8
|
+
: `\n${lines.map(x => `* ${x}`)
|
|
9
|
+
.join("\n")}\n`;
|
|
10
|
+
return `/**${result}*/\n`;
|
|
11
|
+
};
|
|
12
|
+
exports.expandJsdocs = expandJsdocs;
|
|
13
|
+
const addJsdocs = (schema, parsed) => {
|
|
14
|
+
const description = schema.description;
|
|
15
|
+
if (!description) {
|
|
16
|
+
return parsed;
|
|
17
|
+
}
|
|
18
|
+
return `\n${(0, exports.expandJsdocs)(description)}${parsed}`;
|
|
19
|
+
};
|
|
20
|
+
exports.addJsdocs = addJsdocs;
|
|
@@ -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,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withMessage = withMessage;
|
|
4
|
+
function withMessage(schema, key, get) {
|
|
5
|
+
const value = schema[key];
|
|
6
|
+
let r = "";
|
|
7
|
+
if (value !== undefined) {
|
|
8
|
+
const got = get({ value, json: JSON.stringify(value) });
|
|
9
|
+
if (got) {
|
|
10
|
+
const opener = got[0];
|
|
11
|
+
const prefix = got.length === 3 ? got[1] : "";
|
|
12
|
+
const closer = got.length === 3 ? got[2] : got[1];
|
|
13
|
+
r += opener;
|
|
14
|
+
if (schema.errorMessage?.[key] !== undefined) {
|
|
15
|
+
r += prefix + JSON.stringify(schema.errorMessage[key]);
|
|
16
|
+
}
|
|
17
|
+
r;
|
|
18
|
+
r += closer;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return r;
|
|
22
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Post-processor for Zod's z.toJSONSchema() output.
|
|
4
|
+
*
|
|
5
|
+
* When `preserveJsonSchemaForRoundTrip` was used during JSON Schema → Zod conversion,
|
|
6
|
+
* this function reconstructs the original JSON Schema features from the stored __jsonSchema meta.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* 1. Convert JSON Schema to Zod code with `preserveJsonSchemaForRoundTrip: true`
|
|
10
|
+
* 2. Evaluate the Zod code to get a schema instance
|
|
11
|
+
* 3. Call Zod's `z.toJSONSchema(schema)` to get JSON Schema output
|
|
12
|
+
* 4. Pass that output to `reconstructJsonSchema()` to restore preserved features
|
|
13
|
+
*
|
|
14
|
+
* Handles:
|
|
15
|
+
* - patternProperties (stored in __jsonSchema.patternProperties)
|
|
16
|
+
* - if/then/else conditionals (stored in __jsonSchema.conditional)
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.reconstructJsonSchema = reconstructJsonSchema;
|
|
20
|
+
/**
|
|
21
|
+
* Recursively process a JSON Schema to reconstruct original features from __jsonSchema meta.
|
|
22
|
+
*
|
|
23
|
+
* Handles special cases:
|
|
24
|
+
* - allOf[object, {__jsonSchema: {conditional: ...}}] -> object with if/then/else at top level
|
|
25
|
+
* - patternProperties meta -> patternProperties at current level
|
|
26
|
+
*/
|
|
27
|
+
function reconstructJsonSchema(schema) {
|
|
28
|
+
if (typeof schema !== "object" || schema === null) {
|
|
29
|
+
return schema;
|
|
30
|
+
}
|
|
31
|
+
const result = { ...schema };
|
|
32
|
+
// Handle allOf structures created by .and() with conditionals
|
|
33
|
+
// Pattern: allOf: [mainSchema, {__jsonSchema: {conditional: ...}, anyOf: [...]}]
|
|
34
|
+
if (Array.isArray(result.allOf) &&
|
|
35
|
+
result.allOf.length === 2 &&
|
|
36
|
+
typeof result.allOf[1] === "object" &&
|
|
37
|
+
result.allOf[1] !== null) {
|
|
38
|
+
const secondElement = result.allOf[1];
|
|
39
|
+
// Check if second element has conditional meta
|
|
40
|
+
if (secondElement.__jsonSchema &&
|
|
41
|
+
typeof secondElement.__jsonSchema === "object" &&
|
|
42
|
+
secondElement.__jsonSchema.conditional) {
|
|
43
|
+
// Extract the main schema and conditional
|
|
44
|
+
const mainSchema = reconstructJsonSchema(result.allOf[0]);
|
|
45
|
+
const conditionalMeta = secondElement.__jsonSchema
|
|
46
|
+
.conditional;
|
|
47
|
+
// Merge: main schema + if/then/else at top level
|
|
48
|
+
const merged = {
|
|
49
|
+
...mainSchema,
|
|
50
|
+
if: conditionalMeta.if,
|
|
51
|
+
then: conditionalMeta.then,
|
|
52
|
+
else: conditionalMeta.else,
|
|
53
|
+
};
|
|
54
|
+
// Recursively process the merged result
|
|
55
|
+
return reconstructJsonSchema(merged);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Check for __jsonSchema meta at this level
|
|
59
|
+
if (result.__jsonSchema && typeof result.__jsonSchema === "object") {
|
|
60
|
+
const preserved = result.__jsonSchema;
|
|
61
|
+
// Reconstruct patternProperties
|
|
62
|
+
if (preserved.patternProperties) {
|
|
63
|
+
result.patternProperties = preserved.patternProperties;
|
|
64
|
+
}
|
|
65
|
+
// Reconstruct if/then/else conditional (for non-allOf cases)
|
|
66
|
+
if (preserved.conditional) {
|
|
67
|
+
const conditional = preserved.conditional;
|
|
68
|
+
result.if = conditional.if;
|
|
69
|
+
result.then = conditional.then;
|
|
70
|
+
result.else = conditional.else;
|
|
71
|
+
}
|
|
72
|
+
// Remove the __jsonSchema meta from the output
|
|
73
|
+
delete result.__jsonSchema;
|
|
74
|
+
}
|
|
75
|
+
// Recursively process nested schemas
|
|
76
|
+
for (const [key, value] of Object.entries(result)) {
|
|
77
|
+
if (typeof value === "object" && value !== null) {
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
result[key] = value.map((item) => typeof item === "object" && item !== null
|
|
80
|
+
? reconstructJsonSchema(item)
|
|
81
|
+
: item);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
result[key] = reconstructJsonSchema(value);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|