@gabrielbryk/json-schema-to-zod 2.7.4 → 2.8.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/CHANGELOG.md +10 -1
- package/dist/cjs/generators/generateBundle.js +311 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/jsonSchemaToZod.js +96 -2
- package/dist/cjs/parsers/parseArray.js +34 -15
- package/dist/cjs/parsers/parseIfThenElse.js +2 -1
- package/dist/cjs/parsers/parseNumber.js +81 -39
- package/dist/cjs/parsers/parseObject.js +24 -0
- package/dist/cjs/parsers/parseSchema.js +23 -1
- package/dist/cjs/parsers/parseString.js +294 -54
- package/dist/cjs/utils/cycles.js +113 -0
- package/dist/cjs/utils/withMessage.js +4 -5
- package/dist/esm/Types.js +2 -1
- package/dist/esm/cli.js +12 -10
- package/dist/esm/generators/generateBundle.js +311 -0
- package/dist/esm/index.js +46 -28
- package/dist/esm/jsonSchemaToZod.js +105 -7
- package/dist/esm/parsers/parseAllOf.js +8 -5
- package/dist/esm/parsers/parseAnyOf.js +10 -6
- package/dist/esm/parsers/parseArray.js +47 -24
- package/dist/esm/parsers/parseBoolean.js +5 -1
- package/dist/esm/parsers/parseConst.js +5 -1
- package/dist/esm/parsers/parseDefault.js +7 -3
- package/dist/esm/parsers/parseEnum.js +5 -1
- package/dist/esm/parsers/parseIfThenElse.js +11 -6
- package/dist/esm/parsers/parseMultipleType.js +7 -3
- package/dist/esm/parsers/parseNot.js +8 -4
- package/dist/esm/parsers/parseNull.js +5 -1
- package/dist/esm/parsers/parseNullable.js +8 -4
- package/dist/esm/parsers/parseNumber.js +88 -42
- package/dist/esm/parsers/parseObject.js +52 -25
- package/dist/esm/parsers/parseOneOf.js +10 -6
- package/dist/esm/parsers/parseSchema.js +85 -59
- package/dist/esm/parsers/parseSimpleDiscriminatedOneOf.js +10 -6
- package/dist/esm/parsers/parseString.js +303 -59
- package/dist/esm/utils/anyOrUnknown.js +5 -1
- package/dist/esm/utils/cliTools.js +13 -7
- package/dist/esm/utils/cycles.js +113 -0
- package/dist/esm/utils/half.js +5 -1
- package/dist/esm/utils/jsdocs.js +8 -3
- package/dist/esm/utils/omit.js +5 -1
- package/dist/esm/utils/withMessage.js +8 -6
- package/dist/esm/zodToJsonSchema.js +4 -1
- package/dist/types/Types.d.ts +8 -0
- package/dist/types/generators/generateBundle.d.ts +57 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/parsers/parseString.d.ts +2 -2
- package/dist/types/utils/cycles.d.ts +7 -0
- package/dist/types/utils/jsdocs.d.ts +1 -1
- package/dist/types/utils/withMessage.d.ts +6 -1
- package/package.json +1 -1
|
@@ -1,73 +1,317 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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, refs) => {
|
|
7
|
+
const formatError = schema.errorMessage?.format;
|
|
8
|
+
const refContext = ensureRefs(refs);
|
|
9
|
+
const topLevelFormatMap = {
|
|
10
|
+
email: "z.email",
|
|
11
|
+
ipv4: "z.ipv4",
|
|
12
|
+
ipv6: "z.ipv6",
|
|
13
|
+
uri: "z.url",
|
|
14
|
+
uuid: "z.uuid",
|
|
15
|
+
cuid: "z.cuid",
|
|
16
|
+
cuid2: "z.cuid2",
|
|
17
|
+
nanoid: "z.nanoid",
|
|
18
|
+
ulid: "z.ulid",
|
|
19
|
+
jwt: "z.jwt",
|
|
20
|
+
e164: "z.e164",
|
|
21
|
+
base64url: "z.base64url",
|
|
22
|
+
base64: "z.base64",
|
|
23
|
+
emoji: "z.emoji",
|
|
24
|
+
"idn-email": "z.email",
|
|
25
|
+
};
|
|
26
|
+
const formatFn = schema.format && topLevelFormatMap[schema.format];
|
|
27
|
+
const formatParam = formatError !== undefined ? `{ error: ${JSON.stringify(formatError)} }` : "";
|
|
28
|
+
let r = formatFn ? `${formatFn}(${formatParam})` : "z.string()";
|
|
29
|
+
const formatHandled = Boolean(formatFn);
|
|
30
|
+
let formatWasHandled = formatHandled;
|
|
31
|
+
if (!formatHandled) {
|
|
32
|
+
r += (0, withMessage_js_1.withMessage)(schema, "format", ({ value }) => {
|
|
33
|
+
switch (value) {
|
|
34
|
+
case "email":
|
|
35
|
+
formatWasHandled = true;
|
|
36
|
+
return {
|
|
37
|
+
opener: ".email(",
|
|
38
|
+
closer: ")",
|
|
39
|
+
messagePrefix: "{ error: ",
|
|
40
|
+
messageCloser: " })",
|
|
41
|
+
};
|
|
42
|
+
case "ip":
|
|
43
|
+
formatWasHandled = true;
|
|
44
|
+
return {
|
|
45
|
+
opener: ".ip(",
|
|
46
|
+
closer: ")",
|
|
47
|
+
messagePrefix: "{ error: ",
|
|
48
|
+
messageCloser: " })",
|
|
49
|
+
};
|
|
50
|
+
case "ipv4":
|
|
51
|
+
formatWasHandled = true;
|
|
52
|
+
return {
|
|
53
|
+
opener: '.ip({ version: "v4"',
|
|
54
|
+
closer: " })",
|
|
55
|
+
messagePrefix: ", error: ",
|
|
56
|
+
messageCloser: " })",
|
|
57
|
+
};
|
|
58
|
+
case "ipv6":
|
|
59
|
+
formatWasHandled = true;
|
|
60
|
+
return {
|
|
61
|
+
opener: '.ip({ version: "v6"',
|
|
62
|
+
closer: " })",
|
|
63
|
+
messagePrefix: ", error: ",
|
|
64
|
+
messageCloser: " })",
|
|
65
|
+
};
|
|
66
|
+
case "uri":
|
|
67
|
+
formatWasHandled = true;
|
|
68
|
+
return {
|
|
69
|
+
opener: ".url(",
|
|
70
|
+
closer: ")",
|
|
71
|
+
messagePrefix: "{ error: ",
|
|
72
|
+
messageCloser: " })",
|
|
73
|
+
};
|
|
74
|
+
case "uuid":
|
|
75
|
+
formatWasHandled = true;
|
|
76
|
+
return {
|
|
77
|
+
opener: ".uuid(",
|
|
78
|
+
closer: ")",
|
|
79
|
+
messagePrefix: "{ error: ",
|
|
80
|
+
messageCloser: " })",
|
|
81
|
+
};
|
|
82
|
+
case "cuid":
|
|
83
|
+
formatWasHandled = true;
|
|
84
|
+
return {
|
|
85
|
+
opener: ".cuid(",
|
|
86
|
+
closer: ")",
|
|
87
|
+
messagePrefix: "{ error: ",
|
|
88
|
+
messageCloser: " })",
|
|
89
|
+
};
|
|
90
|
+
case "cuid2":
|
|
91
|
+
formatWasHandled = true;
|
|
92
|
+
return {
|
|
93
|
+
opener: ".cuid2(",
|
|
94
|
+
closer: ")",
|
|
95
|
+
messagePrefix: "{ error: ",
|
|
96
|
+
messageCloser: " })",
|
|
97
|
+
};
|
|
98
|
+
case "nanoid":
|
|
99
|
+
formatWasHandled = true;
|
|
100
|
+
return {
|
|
101
|
+
opener: ".nanoid(",
|
|
102
|
+
closer: ")",
|
|
103
|
+
messagePrefix: "{ error: ",
|
|
104
|
+
messageCloser: " })",
|
|
105
|
+
};
|
|
106
|
+
case "ulid":
|
|
107
|
+
formatWasHandled = true;
|
|
108
|
+
return {
|
|
109
|
+
opener: ".ulid(",
|
|
110
|
+
closer: ")",
|
|
111
|
+
messagePrefix: "{ error: ",
|
|
112
|
+
messageCloser: " })",
|
|
113
|
+
};
|
|
114
|
+
case "jwt":
|
|
115
|
+
formatWasHandled = true;
|
|
116
|
+
return {
|
|
117
|
+
opener: ".jwt(",
|
|
118
|
+
closer: ")",
|
|
119
|
+
messagePrefix: "{ error: ",
|
|
120
|
+
messageCloser: " })",
|
|
121
|
+
};
|
|
122
|
+
case "e164":
|
|
123
|
+
formatWasHandled = true;
|
|
124
|
+
return {
|
|
125
|
+
opener: ".e164(",
|
|
126
|
+
closer: ")",
|
|
127
|
+
messagePrefix: "{ error: ",
|
|
128
|
+
messageCloser: " })",
|
|
129
|
+
};
|
|
130
|
+
case "base64url":
|
|
131
|
+
formatWasHandled = true;
|
|
132
|
+
return {
|
|
133
|
+
opener: ".base64url(",
|
|
134
|
+
closer: ")",
|
|
135
|
+
messagePrefix: "{ error: ",
|
|
136
|
+
messageCloser: " })",
|
|
137
|
+
};
|
|
138
|
+
case "emoji":
|
|
139
|
+
formatWasHandled = true;
|
|
140
|
+
return {
|
|
141
|
+
opener: ".emoji(",
|
|
142
|
+
closer: ")",
|
|
143
|
+
messagePrefix: "{ error: ",
|
|
144
|
+
messageCloser: " })",
|
|
145
|
+
};
|
|
146
|
+
case "date-time":
|
|
147
|
+
formatWasHandled = true;
|
|
148
|
+
return {
|
|
149
|
+
opener: ".datetime({ offset: true",
|
|
150
|
+
closer: " })",
|
|
151
|
+
messagePrefix: ", error: ",
|
|
152
|
+
messageCloser: " })",
|
|
153
|
+
};
|
|
154
|
+
case "time":
|
|
155
|
+
formatWasHandled = true;
|
|
156
|
+
return {
|
|
157
|
+
opener: ".time(",
|
|
158
|
+
closer: ")",
|
|
159
|
+
messagePrefix: "{ error: ",
|
|
160
|
+
messageCloser: " })",
|
|
161
|
+
};
|
|
162
|
+
case "date":
|
|
163
|
+
formatWasHandled = true;
|
|
164
|
+
return {
|
|
165
|
+
opener: ".date(",
|
|
166
|
+
closer: ")",
|
|
167
|
+
messagePrefix: "{ error: ",
|
|
168
|
+
messageCloser: " })",
|
|
169
|
+
};
|
|
170
|
+
case "binary":
|
|
171
|
+
formatWasHandled = true;
|
|
172
|
+
return {
|
|
173
|
+
opener: ".base64(",
|
|
174
|
+
closer: ")",
|
|
175
|
+
messagePrefix: "{ error: ",
|
|
176
|
+
messageCloser: " })",
|
|
177
|
+
};
|
|
178
|
+
case "duration":
|
|
179
|
+
formatWasHandled = true;
|
|
180
|
+
return {
|
|
181
|
+
opener: ".duration(",
|
|
182
|
+
closer: ")",
|
|
183
|
+
messagePrefix: "{ error: ",
|
|
184
|
+
messageCloser: " })",
|
|
185
|
+
};
|
|
186
|
+
case "hostname":
|
|
187
|
+
case "idn-hostname":
|
|
188
|
+
formatWasHandled = true;
|
|
189
|
+
return {
|
|
190
|
+
opener: ".refine((val) => { if (typeof val !== \"string\" || val.length === 0 || val.length > 253) return false; return val.split(\".\").every((label) => label.length > 0 && label.length <= 63 && /^[A-Za-z0-9-]+$/.test(label) && label[0] !== \"-\" && label[label.length - 1] !== \"-\"); }",
|
|
191
|
+
closer: ")",
|
|
192
|
+
messagePrefix: ", { error: ",
|
|
193
|
+
messageCloser: " })",
|
|
194
|
+
};
|
|
195
|
+
case "idn-email":
|
|
196
|
+
formatWasHandled = true;
|
|
197
|
+
return {
|
|
198
|
+
opener: ".email(",
|
|
199
|
+
closer: ")",
|
|
200
|
+
messagePrefix: "{ error: ",
|
|
201
|
+
messageCloser: " })",
|
|
202
|
+
};
|
|
203
|
+
case "uri-reference":
|
|
204
|
+
case "iri":
|
|
205
|
+
case "iri-reference":
|
|
206
|
+
formatWasHandled = true;
|
|
207
|
+
return {
|
|
208
|
+
opener: '.refine((val) => { try { new URL(val, "http://example.com"); return true; } catch { return false; } }',
|
|
209
|
+
closer: ")",
|
|
210
|
+
messagePrefix: ", { error: ",
|
|
211
|
+
messageCloser: " })",
|
|
212
|
+
};
|
|
213
|
+
case "json-pointer":
|
|
214
|
+
formatWasHandled = true;
|
|
215
|
+
return {
|
|
216
|
+
opener: ".refine((val) => typeof val === \"string\" && /^(?:\\/(?:[^/~]|~[01])*)*$/.test(val)",
|
|
217
|
+
closer: ")",
|
|
218
|
+
messagePrefix: ", { error: ",
|
|
219
|
+
messageCloser: " })",
|
|
220
|
+
};
|
|
221
|
+
case "relative-json-pointer":
|
|
222
|
+
formatWasHandled = true;
|
|
223
|
+
return {
|
|
224
|
+
opener: ".refine((val) => typeof val === \"string\" && /^(?:0|[1-9][0-9]*)(?:#|(?:\\/(?:[^/~]|~[01])*))*$/.test(val)",
|
|
225
|
+
closer: ")",
|
|
226
|
+
messagePrefix: ", { error: ",
|
|
227
|
+
messageCloser: " })",
|
|
228
|
+
};
|
|
229
|
+
case "uri-template":
|
|
230
|
+
formatWasHandled = true;
|
|
231
|
+
return {
|
|
232
|
+
opener: ".refine((val) => { if (typeof val !== \"string\") return false; const opens = (val.match(/\\{/g) || []).length; const closes = (val.match(/\\}/g) || []).length; return opens === closes; }",
|
|
233
|
+
closer: ")",
|
|
234
|
+
messagePrefix: ", { error: ",
|
|
235
|
+
messageCloser: " })",
|
|
236
|
+
};
|
|
237
|
+
case "regex":
|
|
238
|
+
formatWasHandled = true;
|
|
239
|
+
return {
|
|
240
|
+
opener: ".refine((val) => { try { new RegExp(val); return true; } catch { return false; } }",
|
|
241
|
+
closer: ")",
|
|
242
|
+
messagePrefix: ", { error: ",
|
|
243
|
+
messageCloser: " })",
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
if (schema.format && !formatWasHandled) {
|
|
249
|
+
refContext.onUnknownFormat?.(schema.format, refContext.path);
|
|
250
|
+
}
|
|
251
|
+
r += (0, withMessage_js_1.withMessage)(schema, "pattern", ({ json }) => ({
|
|
252
|
+
opener: `.regex(new RegExp(${json})`,
|
|
253
|
+
closer: ")",
|
|
254
|
+
messagePrefix: ", { error: ",
|
|
255
|
+
messageCloser: " })",
|
|
256
|
+
}));
|
|
257
|
+
r += (0, withMessage_js_1.withMessage)(schema, "minLength", ({ json }) => ({
|
|
258
|
+
opener: `.min(${json}`,
|
|
259
|
+
closer: ")",
|
|
260
|
+
messagePrefix: ", { error: ",
|
|
261
|
+
messageCloser: " })",
|
|
262
|
+
}));
|
|
263
|
+
r += (0, withMessage_js_1.withMessage)(schema, "maxLength", ({ json }) => ({
|
|
264
|
+
opener: `.max(${json}`,
|
|
265
|
+
closer: ")",
|
|
266
|
+
messagePrefix: ", { error: ",
|
|
267
|
+
messageCloser: " })",
|
|
268
|
+
}));
|
|
269
|
+
r += (0, withMessage_js_1.withMessage)(schema, "contentEncoding", ({ value }) => {
|
|
47
270
|
if (value === "base64") {
|
|
48
|
-
return
|
|
271
|
+
return {
|
|
272
|
+
opener: ".base64(",
|
|
273
|
+
closer: ")",
|
|
274
|
+
messagePrefix: "{ error: ",
|
|
275
|
+
messageCloser: " })",
|
|
276
|
+
};
|
|
49
277
|
}
|
|
50
278
|
});
|
|
51
|
-
const contentMediaType = withMessage(schema, "contentMediaType", ({ value }) => {
|
|
279
|
+
const contentMediaType = (0, withMessage_js_1.withMessage)(schema, "contentMediaType", ({ value }) => {
|
|
52
280
|
if (value === "application/json") {
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
|
|
281
|
+
return {
|
|
282
|
+
opener: '.transform((str, ctx) => { try { return JSON.parse(str); } catch (err) { ctx.addIssue({ code: "custom", message: "Invalid JSON" }); }}',
|
|
283
|
+
closer: ")",
|
|
284
|
+
messagePrefix: ", { error: ",
|
|
285
|
+
messageCloser: " })",
|
|
286
|
+
};
|
|
58
287
|
}
|
|
59
288
|
});
|
|
60
289
|
if (contentMediaType != "") {
|
|
61
290
|
r += contentMediaType;
|
|
62
|
-
r += withMessage(schema, "contentSchema", ({ value }) => {
|
|
291
|
+
r += (0, withMessage_js_1.withMessage)(schema, "contentSchema", ({ value }) => {
|
|
63
292
|
if (value && value instanceof Object) {
|
|
64
|
-
return
|
|
65
|
-
`.pipe(${parseSchema(value)}`,
|
|
66
|
-
|
|
67
|
-
"
|
|
68
|
-
|
|
293
|
+
return {
|
|
294
|
+
opener: `.pipe(${(0, parseSchema_js_1.parseSchema)(value, refContext)}`,
|
|
295
|
+
closer: ")",
|
|
296
|
+
messagePrefix: ", { error: ",
|
|
297
|
+
messageCloser: " })",
|
|
298
|
+
};
|
|
69
299
|
}
|
|
70
300
|
});
|
|
71
301
|
}
|
|
72
302
|
return r;
|
|
73
303
|
};
|
|
304
|
+
exports.parseString = parseString;
|
|
305
|
+
function ensureRefs(refs) {
|
|
306
|
+
if (refs)
|
|
307
|
+
return refs;
|
|
308
|
+
return {
|
|
309
|
+
path: [],
|
|
310
|
+
seen: new Map(),
|
|
311
|
+
declarations: new Map(),
|
|
312
|
+
dependencies: new Map(),
|
|
313
|
+
inProgress: new Set(),
|
|
314
|
+
refNameByPointer: new Map(),
|
|
315
|
+
usedNames: new Set(),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.anyOrUnknown = void 0;
|
|
1
4
|
/**
|
|
2
5
|
* Returns "z.unknown()" if the useUnknown option is enabled, otherwise "z.any()".
|
|
3
6
|
* This helper is used throughout the library for fallback cases.
|
|
@@ -5,6 +8,7 @@
|
|
|
5
8
|
* @param refs - The refs object containing options
|
|
6
9
|
* @returns The appropriate Zod schema string
|
|
7
10
|
*/
|
|
8
|
-
|
|
11
|
+
const anyOrUnknown = (refs) => {
|
|
9
12
|
return refs?.useUnknown ? "z.unknown()" : "z.any()";
|
|
10
13
|
};
|
|
14
|
+
exports.anyOrUnknown = anyOrUnknown;
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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) {
|
|
3
9
|
const result = {};
|
|
4
10
|
if (help) {
|
|
5
11
|
let index = args.indexOf("--help");
|
|
@@ -56,15 +62,15 @@ export function parseArgs(params, args, help) {
|
|
|
56
62
|
}
|
|
57
63
|
return result;
|
|
58
64
|
}
|
|
59
|
-
|
|
65
|
+
function parseOrReadJSON(jsonOrPath) {
|
|
60
66
|
jsonOrPath = jsonOrPath.trim();
|
|
61
67
|
if (jsonOrPath.length < 255 &&
|
|
62
|
-
statSync(jsonOrPath, { throwIfNoEntry: false })?.isFile()) {
|
|
63
|
-
jsonOrPath = readFileSync(jsonOrPath, "utf-8");
|
|
68
|
+
(0, fs_1.statSync)(jsonOrPath, { throwIfNoEntry: false })?.isFile()) {
|
|
69
|
+
jsonOrPath = (0, fs_1.readFileSync)(jsonOrPath, "utf-8");
|
|
64
70
|
}
|
|
65
71
|
return JSON.parse(jsonOrPath);
|
|
66
72
|
}
|
|
67
|
-
|
|
73
|
+
function readPipe() {
|
|
68
74
|
return new Promise((resolve, reject) => {
|
|
69
75
|
let buf = "";
|
|
70
76
|
process.stdin
|
|
@@ -79,7 +85,7 @@ export function readPipe() {
|
|
|
79
85
|
});
|
|
80
86
|
});
|
|
81
87
|
}
|
|
82
|
-
|
|
88
|
+
function printParams(params) {
|
|
83
89
|
const longest = Object.keys(params).reduce((l, c) => (c.length > l ? c.length : l), 5);
|
|
84
90
|
const header = "Name " + " ".repeat(longest - 2) + "Short Description";
|
|
85
91
|
console.log(header);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeScc = exports.detectCycles = exports.findRefDependencies = void 0;
|
|
4
|
+
const findRefDependencies = (schema, validDefNames) => {
|
|
5
|
+
const deps = new Set();
|
|
6
|
+
function traverse(obj) {
|
|
7
|
+
if (obj === null || typeof obj !== "object")
|
|
8
|
+
return;
|
|
9
|
+
if (Array.isArray(obj)) {
|
|
10
|
+
obj.forEach(traverse);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const record = obj;
|
|
14
|
+
if (typeof record["$ref"] === "string") {
|
|
15
|
+
const ref = record["$ref"];
|
|
16
|
+
const match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/);
|
|
17
|
+
if (match && validDefNames.includes(match[1])) {
|
|
18
|
+
deps.add(match[1]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
for (const value of Object.values(record)) {
|
|
22
|
+
traverse(value);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
traverse(schema);
|
|
26
|
+
return deps;
|
|
27
|
+
};
|
|
28
|
+
exports.findRefDependencies = findRefDependencies;
|
|
29
|
+
const detectCycles = (defNames, deps) => {
|
|
30
|
+
const cycleNodes = new Set();
|
|
31
|
+
const visited = new Set();
|
|
32
|
+
const recursionStack = new Set();
|
|
33
|
+
function dfs(node, path) {
|
|
34
|
+
if (recursionStack.has(node)) {
|
|
35
|
+
const cycleStart = path.indexOf(node);
|
|
36
|
+
for (let i = cycleStart; i < path.length; i++) {
|
|
37
|
+
cycleNodes.add(path[i]);
|
|
38
|
+
}
|
|
39
|
+
cycleNodes.add(node);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (visited.has(node))
|
|
43
|
+
return;
|
|
44
|
+
visited.add(node);
|
|
45
|
+
recursionStack.add(node);
|
|
46
|
+
const targets = deps.get(node);
|
|
47
|
+
if (targets) {
|
|
48
|
+
for (const dep of targets) {
|
|
49
|
+
dfs(dep, [...path, node]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
recursionStack.delete(node);
|
|
53
|
+
}
|
|
54
|
+
for (const defName of defNames) {
|
|
55
|
+
if (!visited.has(defName))
|
|
56
|
+
dfs(defName, []);
|
|
57
|
+
}
|
|
58
|
+
return cycleNodes;
|
|
59
|
+
};
|
|
60
|
+
exports.detectCycles = detectCycles;
|
|
61
|
+
const computeScc = (defNames, deps) => {
|
|
62
|
+
// Tarjan's algorithm, keeps mapping for quick "is this ref in my cycle?"
|
|
63
|
+
const index = new Map();
|
|
64
|
+
const lowlink = new Map();
|
|
65
|
+
const stack = [];
|
|
66
|
+
const onStack = new Set();
|
|
67
|
+
const componentByName = new Map();
|
|
68
|
+
const cycleMembers = new Set();
|
|
69
|
+
let currentIndex = 0;
|
|
70
|
+
let componentId = 0;
|
|
71
|
+
const strongConnect = (v) => {
|
|
72
|
+
index.set(v, currentIndex);
|
|
73
|
+
lowlink.set(v, currentIndex);
|
|
74
|
+
currentIndex += 1;
|
|
75
|
+
stack.push(v);
|
|
76
|
+
onStack.add(v);
|
|
77
|
+
const neighbors = deps.get(v);
|
|
78
|
+
if (neighbors) {
|
|
79
|
+
for (const w of neighbors) {
|
|
80
|
+
if (!index.has(w)) {
|
|
81
|
+
strongConnect(w);
|
|
82
|
+
lowlink.set(v, Math.min(lowlink.get(v), lowlink.get(w)));
|
|
83
|
+
}
|
|
84
|
+
else if (onStack.has(w)) {
|
|
85
|
+
lowlink.set(v, Math.min(lowlink.get(v), index.get(w)));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (lowlink.get(v) === index.get(v)) {
|
|
90
|
+
const component = [];
|
|
91
|
+
let w;
|
|
92
|
+
do {
|
|
93
|
+
w = stack.pop();
|
|
94
|
+
if (w === undefined)
|
|
95
|
+
break;
|
|
96
|
+
onStack.delete(w);
|
|
97
|
+
component.push(w);
|
|
98
|
+
componentByName.set(w, componentId);
|
|
99
|
+
} while (w !== v);
|
|
100
|
+
if (component.length > 1) {
|
|
101
|
+
component.forEach((name) => cycleMembers.add(name));
|
|
102
|
+
}
|
|
103
|
+
componentId += 1;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
for (const name of defNames) {
|
|
107
|
+
if (!index.has(name)) {
|
|
108
|
+
strongConnect(name);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { cycleMembers, componentByName };
|
|
112
|
+
};
|
|
113
|
+
exports.computeScc = computeScc;
|
package/dist/esm/utils/half.js
CHANGED
package/dist/esm/utils/jsdocs.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addJsdocs = exports.expandJsdocs = void 0;
|
|
4
|
+
const expandJsdocs = (jsdocs) => {
|
|
2
5
|
const lines = jsdocs.split("\n");
|
|
3
6
|
const result = lines.length === 1
|
|
4
7
|
? lines[0]
|
|
@@ -6,10 +9,12 @@ export const expandJsdocs = (jsdocs) => {
|
|
|
6
9
|
.join("\n")}\n`;
|
|
7
10
|
return `/**${result}*/\n`;
|
|
8
11
|
};
|
|
9
|
-
|
|
12
|
+
exports.expandJsdocs = expandJsdocs;
|
|
13
|
+
const addJsdocs = (schema, parsed) => {
|
|
10
14
|
const description = schema.description;
|
|
11
15
|
if (!description) {
|
|
12
16
|
return parsed;
|
|
13
17
|
}
|
|
14
|
-
return `\n${expandJsdocs(description)}${parsed}`;
|
|
18
|
+
return `\n${(0, exports.expandJsdocs)(description)}${parsed}`;
|
|
15
19
|
};
|
|
20
|
+
exports.addJsdocs = addJsdocs;
|
package/dist/esm/utils/omit.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
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) => {
|
|
2
5
|
if (!keys.includes(key)) {
|
|
3
6
|
acc[key] = obj[key];
|
|
4
7
|
}
|
|
5
8
|
return acc;
|
|
6
9
|
}, {});
|
|
10
|
+
exports.omit = omit;
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withMessage = withMessage;
|
|
4
|
+
function withMessage(schema, key, get) {
|
|
2
5
|
const value = schema[key];
|
|
3
6
|
let r = "";
|
|
4
7
|
if (value !== undefined) {
|
|
5
8
|
const got = get({ value, json: JSON.stringify(value) });
|
|
6
9
|
if (got) {
|
|
7
|
-
const opener = got
|
|
8
|
-
const prefix = got.length === 3 ? got[1] : "";
|
|
9
|
-
const closer = got.length === 3 ? got[2] : got[1];
|
|
10
|
+
const { opener, closer, messagePrefix = "", messageCloser } = got;
|
|
10
11
|
r += opener;
|
|
11
12
|
if (schema.errorMessage?.[key] !== undefined) {
|
|
12
|
-
r +=
|
|
13
|
+
r += messagePrefix + JSON.stringify(schema.errorMessage[key]);
|
|
14
|
+
r += messageCloser ?? closer;
|
|
15
|
+
return r;
|
|
13
16
|
}
|
|
14
|
-
r;
|
|
15
17
|
r += closer;
|
|
16
18
|
}
|
|
17
19
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Post-processor for Zod's z.toJSONSchema() output.
|
|
3
4
|
*
|
|
@@ -14,6 +15,8 @@
|
|
|
14
15
|
* - patternProperties (stored in __jsonSchema.patternProperties)
|
|
15
16
|
* - if/then/else conditionals (stored in __jsonSchema.conditional)
|
|
16
17
|
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.reconstructJsonSchema = reconstructJsonSchema;
|
|
17
20
|
/**
|
|
18
21
|
* Recursively process a JSON Schema to reconstruct original features from __jsonSchema meta.
|
|
19
22
|
*
|
|
@@ -21,7 +24,7 @@
|
|
|
21
24
|
* - allOf[object, {__jsonSchema: {conditional: ...}}] -> object with if/then/else at top level
|
|
22
25
|
* - patternProperties meta -> patternProperties at current level
|
|
23
26
|
*/
|
|
24
|
-
|
|
27
|
+
function reconstructJsonSchema(schema) {
|
|
25
28
|
if (typeof schema !== "object" || schema === null) {
|
|
26
29
|
return schema;
|
|
27
30
|
}
|
package/dist/types/Types.d.ts
CHANGED
|
@@ -94,6 +94,11 @@ export type Options = {
|
|
|
94
94
|
* @default false
|
|
95
95
|
*/
|
|
96
96
|
strictOneOf?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Called when a string format is encountered that has no built-in mapping.
|
|
99
|
+
* Can be used to log or throw on unknown formats.
|
|
100
|
+
*/
|
|
101
|
+
onUnknownFormat?: (format: string, path: (string | number)[]) => void;
|
|
97
102
|
};
|
|
98
103
|
export type Refs = Options & {
|
|
99
104
|
path: (string | number)[];
|
|
@@ -103,10 +108,13 @@ export type Refs = Options & {
|
|
|
103
108
|
}>;
|
|
104
109
|
root?: JsonSchema;
|
|
105
110
|
declarations?: Map<string, string>;
|
|
111
|
+
dependencies?: Map<string, Set<string>>;
|
|
106
112
|
inProgress?: Set<string>;
|
|
107
113
|
refNameByPointer?: Map<string, string>;
|
|
108
114
|
usedNames?: Set<string>;
|
|
109
115
|
currentSchemaName?: string;
|
|
116
|
+
cycleRefNames?: Set<string>;
|
|
117
|
+
cycleComponentByName?: Map<string, number>;
|
|
110
118
|
};
|
|
111
119
|
export type SimpleDiscriminatedOneOfSchema<D extends string = string> = JsonSchemaObject & {
|
|
112
120
|
oneOf: (JsonSchemaObject & {
|