@kubb/plugin-zod 5.0.0-beta.84 → 5.0.0-beta.85
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/dist/index.cjs +280 -137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +118 -137
- package/dist/index.js +281 -138
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -51,31 +51,6 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
|
51
51
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
54
|
-
//#region ../../internals/utils/src/fs.ts
|
|
55
|
-
/**
|
|
56
|
-
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
57
|
-
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
58
|
-
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
59
|
-
*
|
|
60
|
-
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
61
|
-
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
62
|
-
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
63
|
-
* absolute path, letting generated files escape the configured output directory.
|
|
64
|
-
*
|
|
65
|
-
* @example Nested path from a dotted name
|
|
66
|
-
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
67
|
-
*
|
|
68
|
-
* @example PascalCase the final segment
|
|
69
|
-
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
70
|
-
*
|
|
71
|
-
* @example Suffix applied to the final segment only
|
|
72
|
-
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
73
|
-
*/
|
|
74
|
-
function toFilePath(name, caseLast = camelCase) {
|
|
75
|
-
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
76
|
-
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
77
|
-
}
|
|
78
|
-
//#endregion
|
|
79
54
|
//#region ../../internals/utils/src/reserved.ts
|
|
80
55
|
/**
|
|
81
56
|
* JavaScript and Java reserved words.
|
|
@@ -198,6 +173,188 @@ function ensureValidVarName(name) {
|
|
|
198
173
|
if (!name || isValidVarName(name)) return name;
|
|
199
174
|
return `_${name}`;
|
|
200
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
178
|
+
*
|
|
179
|
+
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
180
|
+
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
181
|
+
* deciding whether an object key needs quoting.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* isIdentifier('name') // true
|
|
186
|
+
* isIdentifier('x-total')// false
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
function isIdentifier(name) {
|
|
190
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region ../../internals/utils/src/strings.ts
|
|
194
|
+
/**
|
|
195
|
+
* Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
|
|
196
|
+
* any backslash or single quote in the content.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* singleQuote('foo') // "'foo'"
|
|
201
|
+
* singleQuote("o'clock") // "'o\\'clock'"
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
function singleQuote(value) {
|
|
205
|
+
if (value === void 0 || value === null) return "''";
|
|
206
|
+
return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
|
|
210
|
+
* Returns the string unchanged when no balanced quote pair is found.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* trimQuotes('"hello"') // 'hello'
|
|
215
|
+
* trimQuotes('hello') // 'hello'
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
function trimQuotes(text) {
|
|
219
|
+
if (text.length >= 2) {
|
|
220
|
+
const first = text[0];
|
|
221
|
+
const last = text[text.length - 1];
|
|
222
|
+
if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
|
|
223
|
+
}
|
|
224
|
+
return text;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
|
|
228
|
+
*
|
|
229
|
+
* Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
|
|
230
|
+
* code matches the repo style without a formatter.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```ts
|
|
234
|
+
* stringify('hello') // "'hello'"
|
|
235
|
+
* stringify('"hello"') // "'hello'"
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
function stringify(value) {
|
|
239
|
+
if (value === void 0 || value === null) return "''";
|
|
240
|
+
return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
|
|
244
|
+
* Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
|
|
245
|
+
* Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")'
|
|
250
|
+
* toRegExpString('^(?im)foo', null) // '/^foo/im'
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
function toRegExpString(text, func = "RegExp") {
|
|
254
|
+
const raw = trimQuotes(text);
|
|
255
|
+
const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
|
|
256
|
+
const replacementTarget = match?.[1] ?? "";
|
|
257
|
+
const matchedFlags = match?.[2];
|
|
258
|
+
const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
|
|
259
|
+
const { source, flags } = new RegExp(cleaned, matchedFlags);
|
|
260
|
+
if (func === null) return `/${source}/${flags}`;
|
|
261
|
+
return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region ../../internals/utils/src/codegen.ts
|
|
265
|
+
const INDENT = " ";
|
|
266
|
+
/**
|
|
267
|
+
* Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
|
|
268
|
+
*/
|
|
269
|
+
function indentLines(text) {
|
|
270
|
+
if (!text) return "";
|
|
271
|
+
return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n");
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Renders an object key, quoting it with single quotes only when it is not a valid identifier.
|
|
275
|
+
* Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```ts
|
|
279
|
+
* objectKey('name') // 'name'
|
|
280
|
+
* objectKey('x-total') // "'x-total'"
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
function objectKey(name) {
|
|
284
|
+
return isIdentifier(name) ? name : singleQuote(name);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
|
|
288
|
+
* level and closing the brace at column zero. Entries that are themselves multi-line objects indent
|
|
289
|
+
* cumulatively. Each entry ends with a trailing comma to match the formatter's multi-line style.
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```ts
|
|
293
|
+
* buildObject(['id: z.number()', 'name: z.string()'])
|
|
294
|
+
* // '{\n id: z.number(),\n name: z.string(),\n}'
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
function buildObject(entries) {
|
|
298
|
+
if (entries.length === 0) return "{}";
|
|
299
|
+
return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on
|
|
303
|
+
* one line when no item spans multiple lines, and otherwise puts each item on its own line, indented
|
|
304
|
+
* one level with a trailing comma and the closing bracket at column zero. Used for member lists such
|
|
305
|
+
* as `z.union([…])` and `z.array([…])`.
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```ts
|
|
309
|
+
* buildList(['z.string()', 'z.number()'])
|
|
310
|
+
* // '[z.string(), z.number()]'
|
|
311
|
+
* ```
|
|
312
|
+
*/
|
|
313
|
+
function buildList(items, brackets = ["[", "]"]) {
|
|
314
|
+
const [open, close] = brackets;
|
|
315
|
+
if (items.length === 0) return `${open}${close}`;
|
|
316
|
+
if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`;
|
|
317
|
+
return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Emits a lazy getter for a circular-ref property position, `get name() { return body }`. The key
|
|
321
|
+
* is quoted only when it is not a valid identifier. Used by the string printers to defer evaluation
|
|
322
|
+
* of a recursive schema until first access.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* lazyGetter({ name: 'parent', body: 'z.lazy(() => Pet)' })
|
|
327
|
+
* // "get parent() { return z.lazy(() => Pet) }"
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
function lazyGetter({ name, body }) {
|
|
331
|
+
return `get ${objectKey(name)}() { return ${body} }`;
|
|
332
|
+
}
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region ../../internals/utils/src/fs.ts
|
|
335
|
+
/**
|
|
336
|
+
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
337
|
+
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
338
|
+
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
339
|
+
*
|
|
340
|
+
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
341
|
+
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
342
|
+
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
343
|
+
* absolute path, letting generated files escape the configured output directory.
|
|
344
|
+
*
|
|
345
|
+
* @example Nested path from a dotted name
|
|
346
|
+
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
347
|
+
*
|
|
348
|
+
* @example PascalCase the final segment
|
|
349
|
+
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
350
|
+
*
|
|
351
|
+
* @example Suffix applied to the final segment only
|
|
352
|
+
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
353
|
+
*/
|
|
354
|
+
function toFilePath(name, caseLast = camelCase) {
|
|
355
|
+
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
356
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
357
|
+
}
|
|
201
358
|
//#endregion
|
|
202
359
|
//#region ../../internals/shared/src/params.ts
|
|
203
360
|
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -463,7 +620,7 @@ function isObjectComposableIntersection(node, cyclicSchemas) {
|
|
|
463
620
|
* Objects become `{}`, primitives become their string representation, strings are quoted.
|
|
464
621
|
*/
|
|
465
622
|
function formatDefault(value) {
|
|
466
|
-
if (typeof value === "string") return
|
|
623
|
+
if (typeof value === "string") return stringify(value);
|
|
467
624
|
if (typeof value === "object" && value !== null) return "{}";
|
|
468
625
|
return String(value ?? "");
|
|
469
626
|
}
|
|
@@ -499,7 +656,7 @@ function defaultLiteral(node, value) {
|
|
|
499
656
|
* Strings are quoted; numbers and booleans are emitted raw.
|
|
500
657
|
*/
|
|
501
658
|
function formatLiteral(v) {
|
|
502
|
-
if (typeof v === "string") return
|
|
659
|
+
if (typeof v === "string") return stringify(v);
|
|
503
660
|
return String(v);
|
|
504
661
|
}
|
|
505
662
|
/**
|
|
@@ -541,8 +698,7 @@ function patternKeySchemaMini({ patterns, regexType }) {
|
|
|
541
698
|
})}))`;
|
|
542
699
|
}
|
|
543
700
|
function patternKeySource({ patterns, regexType }) {
|
|
544
|
-
|
|
545
|
-
return kubb_kit.ast.toRegExpString(source, regexFunc(regexType));
|
|
701
|
+
return toRegExpString(patterns.length === 1 ? patterns[0] : patterns.map((pattern) => `(${pattern})`).join("|"), regexFunc(regexType));
|
|
546
702
|
}
|
|
547
703
|
/**
|
|
548
704
|
* Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
|
|
@@ -565,7 +721,7 @@ function lengthConstraints({ min, max, pattern, regexType }) {
|
|
|
565
721
|
return [
|
|
566
722
|
min !== void 0 ? `.min(${min})` : "",
|
|
567
723
|
max !== void 0 ? `.max(${max})` : "",
|
|
568
|
-
pattern !== void 0 ? `.regex(${
|
|
724
|
+
pattern !== void 0 ? `.regex(${toRegExpString(pattern, regexFunc(regexType))})` : ""
|
|
569
725
|
].join("");
|
|
570
726
|
}
|
|
571
727
|
/**
|
|
@@ -587,7 +743,7 @@ function lengthChecksMini({ min, max, pattern, regexType }) {
|
|
|
587
743
|
const checks = [];
|
|
588
744
|
if (min !== void 0) checks.push(`z.minLength(${min})`);
|
|
589
745
|
if (max !== void 0) checks.push(`z.maxLength(${max})`);
|
|
590
|
-
if (pattern !== void 0) checks.push(`z.regex(${
|
|
746
|
+
if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, regexFunc(regexType))})`);
|
|
591
747
|
return checks.length ? `.check(${checks.join(", ")})` : "";
|
|
592
748
|
}
|
|
593
749
|
/**
|
|
@@ -603,7 +759,7 @@ function applyModifiers({ value, schema, nullable, optional, nullish, defaultVal
|
|
|
603
759
|
})();
|
|
604
760
|
const literal = defaultValue !== void 0 ? defaultLiteral(schema, defaultValue) : null;
|
|
605
761
|
const withDefault = literal !== null ? `${withModifier}.default(${literal})` : withModifier;
|
|
606
|
-
const withDescription = description ? `${withDefault}.describe(${
|
|
762
|
+
const withDescription = description ? `${withDefault}.describe(${stringify(description)})` : withDefault;
|
|
607
763
|
return examples?.length ? `${withDescription}.meta({ examples: [${examples.map(formatDefault).join(", ")}] })` : withDescription;
|
|
608
764
|
}
|
|
609
765
|
function modifierDepth(schema) {
|
|
@@ -674,7 +830,7 @@ function buildZodObjectShape(ctx, node) {
|
|
|
674
830
|
const objectNode = kubb_kit.ast.narrowSchema(node, "object");
|
|
675
831
|
if (!objectNode) return "{}";
|
|
676
832
|
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && kubb_kit.ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
|
|
677
|
-
|
|
833
|
+
return buildObject(kubb_kit.ast.mapSchemaProperties(objectNode, (schema) => {
|
|
678
834
|
const hasSelfRef = isCyclic(schema);
|
|
679
835
|
const savedCyclicSchemas = ctx.options.cyclicSchemas;
|
|
680
836
|
if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
|
|
@@ -695,12 +851,11 @@ function buildZodObjectShape(ctx, node) {
|
|
|
695
851
|
description: descriptionToApply,
|
|
696
852
|
examples: meta.examples
|
|
697
853
|
});
|
|
698
|
-
return isCyclic(schema) ?
|
|
854
|
+
return isCyclic(schema) ? lazyGetter({
|
|
699
855
|
name: propName,
|
|
700
856
|
body: value
|
|
701
|
-
}) : `${
|
|
702
|
-
});
|
|
703
|
-
return kubb_kit.ast.buildObject(entries);
|
|
857
|
+
}) : `${objectKey(propName)}: ${value}`;
|
|
858
|
+
}));
|
|
704
859
|
}
|
|
705
860
|
/**
|
|
706
861
|
* Zod v4 printer built with `definePrinter`.
|
|
@@ -794,7 +949,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
794
949
|
if (!node.name) return null;
|
|
795
950
|
const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? kubb_kit.ast.extractRefName(node.ref) ?? node.name : node.name;
|
|
796
951
|
const useInputVariant = node.ref != null && this.options.direction === "input" && containsCodec(node);
|
|
797
|
-
const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.
|
|
952
|
+
const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.schema.inputName(refName) ?? refName : this.options.resolver?.name(refName) ?? refName : node.name;
|
|
798
953
|
if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
|
|
799
954
|
return resolvedName;
|
|
800
955
|
},
|
|
@@ -833,8 +988,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
833
988
|
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
|
|
834
989
|
},
|
|
835
990
|
tuple(node) {
|
|
836
|
-
|
|
837
|
-
return `z.tuple(${kubb_kit.ast.buildList(items)})`;
|
|
991
|
+
return `z.tuple(${buildList(kubb_kit.ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
|
|
838
992
|
},
|
|
839
993
|
union(node) {
|
|
840
994
|
const nodeMembers = node.members ?? [];
|
|
@@ -842,8 +996,8 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
842
996
|
if (members.length === 0) return "";
|
|
843
997
|
if (members.length === 1) return members[0];
|
|
844
998
|
const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
|
|
845
|
-
if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${
|
|
846
|
-
return `z.union(${
|
|
999
|
+
if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
|
|
1000
|
+
return `z.union(${buildList(members)})`;
|
|
847
1001
|
},
|
|
848
1002
|
intersection(node) {
|
|
849
1003
|
const members = node.members ?? [];
|
|
@@ -915,7 +1069,7 @@ function buildZodMiniObjectShape(ctx, node) {
|
|
|
915
1069
|
const objectNode = kubb_kit.ast.narrowSchema(node, "object");
|
|
916
1070
|
if (!objectNode) return "{}";
|
|
917
1071
|
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && kubb_kit.ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
|
|
918
|
-
|
|
1072
|
+
return buildObject(kubb_kit.ast.mapSchemaProperties(objectNode, (schema) => {
|
|
919
1073
|
const hasSelfRef = isCyclic(schema);
|
|
920
1074
|
const savedCyclicSchemas = ctx.options.cyclicSchemas;
|
|
921
1075
|
if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
|
|
@@ -933,12 +1087,11 @@ function buildZodMiniObjectShape(ctx, node) {
|
|
|
933
1087
|
nullish: schema.nullish,
|
|
934
1088
|
defaultValue: meta.default
|
|
935
1089
|
});
|
|
936
|
-
return isCyclic(schema) ?
|
|
1090
|
+
return isCyclic(schema) ? lazyGetter({
|
|
937
1091
|
name: propName,
|
|
938
1092
|
body: value
|
|
939
|
-
}) : `${
|
|
940
|
-
});
|
|
941
|
-
return kubb_kit.ast.buildObject(entries);
|
|
1093
|
+
}) : `${objectKey(propName)}: ${value}`;
|
|
1094
|
+
}));
|
|
942
1095
|
}
|
|
943
1096
|
/**
|
|
944
1097
|
* Zod v4 Mini printer built with `definePrinter`.
|
|
@@ -1023,7 +1176,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1023
1176
|
ref(node) {
|
|
1024
1177
|
if (!node.name) return null;
|
|
1025
1178
|
const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? kubb_kit.ast.extractRefName(node.ref) ?? node.name : node.name;
|
|
1026
|
-
const resolvedName = node.ref ? this.options.resolver?.
|
|
1179
|
+
const resolvedName = node.ref ? this.options.resolver?.name(refName) ?? refName : node.name;
|
|
1027
1180
|
if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
|
|
1028
1181
|
return resolvedName;
|
|
1029
1182
|
},
|
|
@@ -1060,8 +1213,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1060
1213
|
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
|
|
1061
1214
|
},
|
|
1062
1215
|
tuple(node) {
|
|
1063
|
-
|
|
1064
|
-
return `z.tuple(${kubb_kit.ast.buildList(items)})`;
|
|
1216
|
+
return `z.tuple(${buildList(kubb_kit.ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
|
|
1065
1217
|
},
|
|
1066
1218
|
union(node) {
|
|
1067
1219
|
const nodeMembers = node.members ?? [];
|
|
@@ -1069,8 +1221,8 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1069
1221
|
if (members.length === 0) return "";
|
|
1070
1222
|
if (members.length === 1) return members[0];
|
|
1071
1223
|
const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
|
|
1072
|
-
if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${
|
|
1073
|
-
return `z.union(${
|
|
1224
|
+
if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
|
|
1225
|
+
return `z.union(${buildList(members)})`;
|
|
1074
1226
|
},
|
|
1075
1227
|
intersection(node) {
|
|
1076
1228
|
const members = node.members ?? [];
|
|
@@ -1190,22 +1342,20 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1190
1342
|
const hasCodec = !mini && containsCodec(node);
|
|
1191
1343
|
const codecRefNames = new Set(hasCodec ? collectCodecRefNames(node) : []);
|
|
1192
1344
|
const importEntries = adapter.getImports(node, (schemaName) => ({
|
|
1193
|
-
name: resolver.
|
|
1194
|
-
path: resolver.
|
|
1345
|
+
name: resolver.name(schemaName),
|
|
1346
|
+
path: resolver.file({
|
|
1195
1347
|
name: schemaName,
|
|
1196
|
-
extname: ".ts"
|
|
1197
|
-
}, {
|
|
1348
|
+
extname: ".ts",
|
|
1198
1349
|
root,
|
|
1199
1350
|
output,
|
|
1200
1351
|
group: group ?? void 0
|
|
1201
1352
|
}).path
|
|
1202
1353
|
}));
|
|
1203
1354
|
const inputImportEntries = hasCodec ? [...codecRefNames].map((schemaName) => ({
|
|
1204
|
-
name: [resolver.
|
|
1205
|
-
path: resolver.
|
|
1355
|
+
name: [resolver.schema.inputName(schemaName)],
|
|
1356
|
+
path: resolver.file({
|
|
1206
1357
|
name: schemaName,
|
|
1207
|
-
extname: ".ts"
|
|
1208
|
-
}, {
|
|
1358
|
+
extname: ".ts",
|
|
1209
1359
|
root,
|
|
1210
1360
|
output,
|
|
1211
1361
|
group: group ?? void 0
|
|
@@ -1219,17 +1369,16 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1219
1369
|
return true;
|
|
1220
1370
|
});
|
|
1221
1371
|
const meta = {
|
|
1222
|
-
name: resolver.
|
|
1223
|
-
file: resolver.
|
|
1372
|
+
name: resolver.name(node.name),
|
|
1373
|
+
file: resolver.file({
|
|
1224
1374
|
name: node.name,
|
|
1225
|
-
extname: ".ts"
|
|
1226
|
-
}, {
|
|
1375
|
+
extname: ".ts",
|
|
1227
1376
|
root,
|
|
1228
1377
|
output,
|
|
1229
1378
|
group: group ?? void 0
|
|
1230
1379
|
})
|
|
1231
1380
|
};
|
|
1232
|
-
const inferTypeName = inferred ? resolver.
|
|
1381
|
+
const inferTypeName = inferred ? resolver.schema.typeName(node.name) : null;
|
|
1233
1382
|
const nameMapping = adapter.options.nameMapping;
|
|
1234
1383
|
const stdPrinters = mini ? null : getStdPrinters(resolver, {
|
|
1235
1384
|
coercion,
|
|
@@ -1251,7 +1400,7 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1251
1400
|
baseName: meta.file.baseName,
|
|
1252
1401
|
path: meta.file.path,
|
|
1253
1402
|
meta: meta.file.meta,
|
|
1254
|
-
banner: resolver.
|
|
1403
|
+
banner: resolver.default.banner(ctx.meta, {
|
|
1255
1404
|
output,
|
|
1256
1405
|
config,
|
|
1257
1406
|
file: {
|
|
@@ -1259,7 +1408,7 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1259
1408
|
baseName: meta.file.baseName
|
|
1260
1409
|
}
|
|
1261
1410
|
}),
|
|
1262
|
-
footer: resolver.
|
|
1411
|
+
footer: resolver.default.footer(ctx.meta, {
|
|
1263
1412
|
output,
|
|
1264
1413
|
config,
|
|
1265
1414
|
file: {
|
|
@@ -1290,10 +1439,10 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1290
1439
|
cyclic: cyclicSchemas.has(node.name)
|
|
1291
1440
|
}),
|
|
1292
1441
|
hasCodec && stdPrinters && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Zod, {
|
|
1293
|
-
name: resolver.
|
|
1442
|
+
name: resolver.schema.inputName(node.name),
|
|
1294
1443
|
node,
|
|
1295
1444
|
printer: stdPrinters.input,
|
|
1296
|
-
inferTypeName: inferred ? resolver.
|
|
1445
|
+
inferTypeName: inferred ? resolver.schema.inputTypeName(node.name) : null,
|
|
1297
1446
|
cyclic: cyclicSchemas.has(node.name)
|
|
1298
1447
|
})
|
|
1299
1448
|
]
|
|
@@ -1306,12 +1455,11 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1306
1455
|
const dateType = adapter.options.dateType;
|
|
1307
1456
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
1308
1457
|
const params = caseParams(node.parameters, "camelcase");
|
|
1309
|
-
const meta = { file: resolver.
|
|
1458
|
+
const meta = { file: resolver.file({
|
|
1310
1459
|
name: node.operationId,
|
|
1311
1460
|
extname: ".ts",
|
|
1312
1461
|
tag: node.tags[0] ?? "default",
|
|
1313
|
-
path: node.path
|
|
1314
|
-
}, {
|
|
1462
|
+
path: node.path,
|
|
1315
1463
|
root,
|
|
1316
1464
|
output,
|
|
1317
1465
|
group: group ?? void 0
|
|
@@ -1320,14 +1468,13 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1320
1468
|
const nameMapping = adapter.options.nameMapping;
|
|
1321
1469
|
function renderSchemaEntry({ schema, name, keysToOmit, direction = "output" }) {
|
|
1322
1470
|
if (!schema) return null;
|
|
1323
|
-
const inferTypeName = inferred ? resolver.
|
|
1471
|
+
const inferTypeName = inferred ? resolver.schema.type(name) : null;
|
|
1324
1472
|
const codecRefNames = direction === "input" && !mini ? new Set(collectCodecRefNames(schema)) : null;
|
|
1325
1473
|
const imports = adapter.getImports(schema, (schemaName) => ({
|
|
1326
|
-
name: codecRefNames?.has(schemaName) ? resolver.
|
|
1327
|
-
path: resolver.
|
|
1474
|
+
name: codecRefNames?.has(schemaName) ? resolver.schema.inputName(schemaName) : resolver.name(schemaName),
|
|
1475
|
+
path: resolver.file({
|
|
1328
1476
|
name: schemaName,
|
|
1329
|
-
extname: ".ts"
|
|
1330
|
-
}, {
|
|
1477
|
+
extname: ".ts",
|
|
1331
1478
|
root,
|
|
1332
1479
|
output,
|
|
1333
1480
|
group: group ?? void 0
|
|
@@ -1405,30 +1552,30 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1405
1552
|
}
|
|
1406
1553
|
const paramSchemas = params.map((param) => renderSchemaEntry({
|
|
1407
1554
|
schema: param.schema,
|
|
1408
|
-
name: resolver.
|
|
1555
|
+
name: resolver.param.name(node, param),
|
|
1409
1556
|
direction: "input"
|
|
1410
1557
|
}));
|
|
1411
1558
|
const responseSchemas = node.responses.map((res) => {
|
|
1412
1559
|
const variants = (res.content ?? []).filter((entry) => entry.schema);
|
|
1413
|
-
if (variants.length > 1) return buildContentTypeVariants(res.content, resolver.
|
|
1560
|
+
if (variants.length > 1) return buildContentTypeVariants(res.content, resolver.response.status(node, res.statusCode));
|
|
1414
1561
|
const primary = variants[0] ?? res.content?.[0];
|
|
1415
1562
|
return renderSchemaEntry({
|
|
1416
1563
|
schema: primary?.schema ?? null,
|
|
1417
|
-
name: resolver.
|
|
1564
|
+
name: resolver.response.status(node, res.statusCode),
|
|
1418
1565
|
keysToOmit: primary?.keysToOmit
|
|
1419
1566
|
});
|
|
1420
1567
|
});
|
|
1421
1568
|
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
|
|
1422
1569
|
const successResponsesWithSchema = getSuccessResponses(responsesWithSchema);
|
|
1423
1570
|
const responseUnionSchema = responsesWithSchema.length > 0 ? (() => {
|
|
1424
|
-
const responseUnionName = resolver.
|
|
1571
|
+
const responseUnionName = resolver.response.response(node);
|
|
1425
1572
|
if (new Set(successResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
|
|
1426
|
-
name: resolver.
|
|
1573
|
+
name: resolver.name(schemaName),
|
|
1427
1574
|
path: ""
|
|
1428
1575
|
})).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(responseUnionName)) return null;
|
|
1429
1576
|
const members = successResponsesWithSchema.map((res) => kubb_kit.ast.factory.createSchema({
|
|
1430
1577
|
type: "ref",
|
|
1431
|
-
name: resolver.
|
|
1578
|
+
name: resolver.response.status(node, res.statusCode)
|
|
1432
1579
|
}));
|
|
1433
1580
|
if (members.length === 0) return renderSchemaEntry({
|
|
1434
1581
|
schema: kubb_kit.ast.factory.createSchema({ type: "unknown" }),
|
|
@@ -1444,14 +1591,14 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1444
1591
|
})() : null;
|
|
1445
1592
|
const errorResponsesWithSchema = responsesWithSchema.filter((res) => !isSuccessStatusCode(res.statusCode));
|
|
1446
1593
|
const errorUnionSchema = errorResponsesWithSchema.length > 0 ? (() => {
|
|
1447
|
-
const errorUnionName = resolver.
|
|
1594
|
+
const errorUnionName = resolver.response.error(node);
|
|
1448
1595
|
if (new Set(errorResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
|
|
1449
|
-
name: resolver.
|
|
1596
|
+
name: resolver.name(schemaName),
|
|
1450
1597
|
path: ""
|
|
1451
1598
|
})).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(errorUnionName)) return null;
|
|
1452
1599
|
const members = errorResponsesWithSchema.map((res) => kubb_kit.ast.factory.createSchema({
|
|
1453
1600
|
type: "ref",
|
|
1454
|
-
name: resolver.
|
|
1601
|
+
name: resolver.response.status(node, res.statusCode)
|
|
1455
1602
|
}));
|
|
1456
1603
|
return renderSchemaEntry({
|
|
1457
1604
|
schema: members.length === 1 ? members[0] : kubb_kit.ast.factory.createSchema({
|
|
@@ -1472,12 +1619,12 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1472
1619
|
...entry.schema,
|
|
1473
1620
|
description: node.requestBody.description ?? entry.schema.description
|
|
1474
1621
|
},
|
|
1475
|
-
name: resolver.
|
|
1622
|
+
name: resolver.response.body(node),
|
|
1476
1623
|
keysToOmit: entry.keysToOmit,
|
|
1477
1624
|
direction: "input"
|
|
1478
1625
|
});
|
|
1479
1626
|
}
|
|
1480
|
-
return buildContentTypeVariants(requestBodyContent, resolver.
|
|
1627
|
+
return buildContentTypeVariants(requestBodyContent, resolver.response.body(node), (schema) => ({
|
|
1481
1628
|
...schema,
|
|
1482
1629
|
description: node.requestBody.description ?? schema.description
|
|
1483
1630
|
}), "input");
|
|
@@ -1486,7 +1633,7 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1486
1633
|
baseName: meta.file.baseName,
|
|
1487
1634
|
path: meta.file.path,
|
|
1488
1635
|
meta: meta.file.meta,
|
|
1489
|
-
banner: resolver.
|
|
1636
|
+
banner: resolver.default.banner(ctx.meta, {
|
|
1490
1637
|
output,
|
|
1491
1638
|
config,
|
|
1492
1639
|
file: {
|
|
@@ -1494,7 +1641,7 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1494
1641
|
baseName: meta.file.baseName
|
|
1495
1642
|
}
|
|
1496
1643
|
}),
|
|
1497
|
-
footer: resolver.
|
|
1644
|
+
footer: resolver.default.footer(ctx.meta, {
|
|
1498
1645
|
output,
|
|
1499
1646
|
config,
|
|
1500
1647
|
file: {
|
|
@@ -1530,64 +1677,63 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1530
1677
|
* ```ts
|
|
1531
1678
|
* import { resolverZod } from '@kubb/plugin-zod'
|
|
1532
1679
|
*
|
|
1533
|
-
* resolverZod.
|
|
1534
|
-
* resolverZod.
|
|
1680
|
+
* resolverZod.name('list pets') // 'listPetsSchema'
|
|
1681
|
+
* resolverZod.schema.typeName('pet') // 'PetSchemaType'
|
|
1535
1682
|
* ```
|
|
1536
1683
|
*/
|
|
1537
|
-
const resolverZod = (0, kubb_kit.
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
},
|
|
1548
|
-
resolveSchemaTypeName(name) {
|
|
1684
|
+
const resolverZod = (0, kubb_kit.createResolver)({
|
|
1685
|
+
pluginName: "plugin-zod",
|
|
1686
|
+
name(name) {
|
|
1687
|
+
return ensureValidVarName(camelCase(name, { suffix: "schema" }));
|
|
1688
|
+
},
|
|
1689
|
+
file: { baseName({ name, extname }) {
|
|
1690
|
+
return `${toFilePath(name, (part) => camelCase(part, { suffix: "schema" }))}${extname}`;
|
|
1691
|
+
} },
|
|
1692
|
+
schema: {
|
|
1693
|
+
typeName(name) {
|
|
1549
1694
|
return ensureValidVarName(pascalCase(name, { suffix: "schema type" }));
|
|
1550
1695
|
},
|
|
1551
|
-
|
|
1552
|
-
return this.resolveSchemaName(`${name} input`);
|
|
1553
|
-
},
|
|
1554
|
-
resolveInputSchemaTypeName(name) {
|
|
1555
|
-
return this.resolveSchemaTypeName(`${name} input`);
|
|
1556
|
-
},
|
|
1557
|
-
resolveTypeName(name) {
|
|
1696
|
+
type(name) {
|
|
1558
1697
|
return ensureValidVarName(pascalCase(name, { suffix: "type" }));
|
|
1559
1698
|
},
|
|
1560
|
-
|
|
1561
|
-
return this.
|
|
1562
|
-
},
|
|
1563
|
-
resolveParamName(node, param) {
|
|
1564
|
-
return this.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`);
|
|
1699
|
+
inputName(name) {
|
|
1700
|
+
return this.name(`${name} input`);
|
|
1565
1701
|
},
|
|
1566
|
-
|
|
1567
|
-
return this.
|
|
1702
|
+
inputTypeName(name) {
|
|
1703
|
+
return this.schema.typeName(`${name} input`);
|
|
1704
|
+
}
|
|
1705
|
+
},
|
|
1706
|
+
param: {
|
|
1707
|
+
name(node, param) {
|
|
1708
|
+
return this.name(`${node.operationId} ${param.in} ${param.name}`);
|
|
1568
1709
|
},
|
|
1569
|
-
|
|
1570
|
-
return this.
|
|
1710
|
+
path(node, param) {
|
|
1711
|
+
return this.param.name(node, param);
|
|
1571
1712
|
},
|
|
1572
|
-
|
|
1573
|
-
return this.
|
|
1713
|
+
query(node, param) {
|
|
1714
|
+
return this.param.name(node, param);
|
|
1574
1715
|
},
|
|
1575
|
-
|
|
1576
|
-
return this.
|
|
1716
|
+
headers(node, param) {
|
|
1717
|
+
return this.param.name(node, param);
|
|
1718
|
+
}
|
|
1719
|
+
},
|
|
1720
|
+
response: {
|
|
1721
|
+
status(node, statusCode) {
|
|
1722
|
+
return this.name(`${node.operationId} Status ${statusCode}`);
|
|
1577
1723
|
},
|
|
1578
|
-
|
|
1579
|
-
return this.
|
|
1724
|
+
body(node) {
|
|
1725
|
+
return this.name(`${node.operationId} Body`);
|
|
1580
1726
|
},
|
|
1581
|
-
|
|
1582
|
-
return this.
|
|
1727
|
+
responses(node) {
|
|
1728
|
+
return this.name(`${node.operationId} Responses`);
|
|
1583
1729
|
},
|
|
1584
|
-
|
|
1585
|
-
return this.
|
|
1730
|
+
response(node) {
|
|
1731
|
+
return this.name(`${node.operationId} Response`);
|
|
1586
1732
|
},
|
|
1587
|
-
|
|
1588
|
-
return this.
|
|
1733
|
+
error(node) {
|
|
1734
|
+
return this.name(`${node.operationId} Error`);
|
|
1589
1735
|
}
|
|
1590
|
-
}
|
|
1736
|
+
}
|
|
1591
1737
|
});
|
|
1592
1738
|
//#endregion
|
|
1593
1739
|
//#region src/plugin.ts
|
|
@@ -1646,10 +1792,7 @@ const pluginZod = (0, kubb_kit.definePlugin)((options) => {
|
|
|
1646
1792
|
mini,
|
|
1647
1793
|
printer
|
|
1648
1794
|
});
|
|
1649
|
-
ctx.setResolver(userResolver ?
|
|
1650
|
-
...resolverZod,
|
|
1651
|
-
...userResolver
|
|
1652
|
-
} : resolverZod);
|
|
1795
|
+
ctx.setResolver(userResolver ? kubb_kit.Resolver.merge(resolverZod, userResolver) : resolverZod);
|
|
1653
1796
|
if (userMacros?.length) ctx.setMacros(userMacros);
|
|
1654
1797
|
ctx.addGenerator(zodGenerator);
|
|
1655
1798
|
} }
|