@kubb/plugin-zod 5.0.0-beta.64 → 5.0.0-beta.74
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/README.md +2 -2
- package/dist/index.cjs +149 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +76 -16
- package/dist/index.js +150 -47
- package/dist/index.js.map +1 -1
- package/package.json +7 -8
- /package/dist/{chunk-C0LytTxp.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,54 @@
|
|
|
1
|
-
import { t as __name } from "./
|
|
2
|
-
import { Exclude,
|
|
1
|
+
import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
+
import { Exclude, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
|
|
3
3
|
import { AdapterOas } from "@kubb/adapter-oas";
|
|
4
4
|
|
|
5
|
+
//#region ../../internals/shared/src/operation.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Resolver interface for building operation parameters.
|
|
8
|
+
*
|
|
9
|
+
* `ResolverTs` from `@kubb/plugin-ts` satisfies this interface and can be passed directly.
|
|
10
|
+
*/
|
|
11
|
+
type OperationParamsResolver = {
|
|
12
|
+
/**
|
|
13
|
+
* Resolves the type name for an individual parameter.
|
|
14
|
+
*
|
|
15
|
+
* @example Individual path parameter name
|
|
16
|
+
* `resolver.resolveParamName(node, param) // → 'DeletePetPathPetId'`
|
|
17
|
+
*/
|
|
18
|
+
resolveParamName(node: ast.OperationNode, param: ast.ParameterNode): string;
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the request body type name.
|
|
21
|
+
*
|
|
22
|
+
* @example Request body type name
|
|
23
|
+
* `resolver.resolveDataName(node) // → 'CreatePetData'`
|
|
24
|
+
*/
|
|
25
|
+
resolveDataName(node: ast.OperationNode): string;
|
|
26
|
+
/**
|
|
27
|
+
* Resolves the grouped path parameters type name.
|
|
28
|
+
* When the return value equals `resolveParamName`, no indexed access is emitted.
|
|
29
|
+
*
|
|
30
|
+
* @example Grouped path params type name
|
|
31
|
+
* `resolver.resolvePathParamsName(node, param) // → 'DeletePetPathParams'`
|
|
32
|
+
*/
|
|
33
|
+
resolvePathParamsName(node: ast.OperationNode, param: ast.ParameterNode): string;
|
|
34
|
+
/**
|
|
35
|
+
* Resolves the grouped query parameters type name.
|
|
36
|
+
* When the return value equals `resolveParamName`, an inline struct type is emitted instead.
|
|
37
|
+
*
|
|
38
|
+
* @example Grouped query params type name
|
|
39
|
+
* `resolver.resolveQueryParamsName(node, param) // → 'FindPetsByStatusQueryParams'`
|
|
40
|
+
*/
|
|
41
|
+
resolveQueryParamsName(node: ast.OperationNode, param: ast.ParameterNode): string;
|
|
42
|
+
/**
|
|
43
|
+
* Resolves the grouped header parameters type name.
|
|
44
|
+
* When the return value equals `resolveParamName`, an inline struct type is emitted instead.
|
|
45
|
+
*
|
|
46
|
+
* @example Grouped header params type name
|
|
47
|
+
* `resolver.resolveHeaderParamsName(node, param) // → 'DeletePetHeaderParams'`
|
|
48
|
+
*/
|
|
49
|
+
resolveHeaderParamsName(node: ast.OperationNode, param: ast.ParameterNode): string;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
5
52
|
//#region src/printers/printerZod.d.ts
|
|
6
53
|
/**
|
|
7
54
|
* Partial map of node-type overrides for the Zod printer.
|
|
@@ -35,6 +82,13 @@ type PrinterZodOptions = {
|
|
|
35
82
|
* @default 'uuid'
|
|
36
83
|
*/
|
|
37
84
|
guidType?: PluginZod['resolvedOptions']['guidType'];
|
|
85
|
+
/**
|
|
86
|
+
* Output form for an OpenAPI `pattern` inside `.regex(...)`: a regex literal
|
|
87
|
+
* (`'literal'`) or the `RegExp` constructor (`'constructor'`).
|
|
88
|
+
*
|
|
89
|
+
* @default 'literal'
|
|
90
|
+
*/
|
|
91
|
+
regexType?: PluginZod['resolvedOptions']['regexType'];
|
|
38
92
|
/**
|
|
39
93
|
* Date format in the OpenAPI spec (`'date'` or `'date-time'`).
|
|
40
94
|
*/
|
|
@@ -118,6 +172,13 @@ type PrinterZodMiniOptions = {
|
|
|
118
172
|
* @default 'uuid'
|
|
119
173
|
*/
|
|
120
174
|
guidType?: PluginZod['resolvedOptions']['guidType'];
|
|
175
|
+
/**
|
|
176
|
+
* Output form for an OpenAPI `pattern` inside `z.regex(...)`: a regex literal
|
|
177
|
+
* (`'literal'`) or the `RegExp` constructor (`'constructor'`).
|
|
178
|
+
*
|
|
179
|
+
* @default 'literal'
|
|
180
|
+
*/
|
|
181
|
+
regexType?: PluginZod['resolvedOptions']['regexType'];
|
|
121
182
|
/**
|
|
122
183
|
* Hook to transform generated Zod schema before output.
|
|
123
184
|
*/
|
|
@@ -162,7 +223,7 @@ declare const printerZodMini: (options?: PrinterZodMiniOptions | undefined) => a
|
|
|
162
223
|
/**
|
|
163
224
|
* Resolver for Zod that provides naming methods for schema types.
|
|
164
225
|
*/
|
|
165
|
-
type ResolverZod = Resolver &
|
|
226
|
+
type ResolverZod = Resolver & OperationParamsResolver & {
|
|
166
227
|
/**
|
|
167
228
|
* Resolves a camelCase schema function name with a `Schema` suffix.
|
|
168
229
|
*/
|
|
@@ -307,6 +368,14 @@ type Options = OutputOptions & {
|
|
|
307
368
|
* @default 'uuid'
|
|
308
369
|
*/
|
|
309
370
|
guidType?: 'uuid' | 'guid';
|
|
371
|
+
/**
|
|
372
|
+
* Output form for an OpenAPI `pattern` inside `.regex(...)`.
|
|
373
|
+
* - `'literal'` — a regex literal: `.regex(/^[a-z]+$/)`.
|
|
374
|
+
* - `'constructor'` — the `RegExp` constructor: `.regex(new RegExp("^[a-z]+$"))`.
|
|
375
|
+
*
|
|
376
|
+
* @default 'literal'
|
|
377
|
+
*/
|
|
378
|
+
regexType?: 'literal' | 'constructor';
|
|
310
379
|
/**
|
|
311
380
|
* Switch to Zod Mini's functional API for better tree-shaking. Also defaults
|
|
312
381
|
* `importPath` to `'zod/mini'`.
|
|
@@ -324,16 +393,6 @@ type Options = OutputOptions & {
|
|
|
324
393
|
output: string;
|
|
325
394
|
schema: ast.SchemaNode;
|
|
326
395
|
}) => string | undefined;
|
|
327
|
-
/**
|
|
328
|
-
* Rename properties inside path/query/header schemas. Body schemas are unaffected.
|
|
329
|
-
*
|
|
330
|
-
* @note Must match the value of `paramsCasing` on `@kubb/plugin-ts`.
|
|
331
|
-
*/
|
|
332
|
-
paramsCasing?: 'camelcase';
|
|
333
|
-
/**
|
|
334
|
-
* Custom generators that run alongside the built-in Zod generators.
|
|
335
|
-
*/
|
|
336
|
-
generators?: Array<Generator<PluginZod>>;
|
|
337
396
|
/**
|
|
338
397
|
* Override how schema and operation names are built. Methods you omit fall back
|
|
339
398
|
* to the default `resolverZod`.
|
|
@@ -363,9 +422,9 @@ type ResolvedOptions = {
|
|
|
363
422
|
coercion: NonNullable<Options['coercion']>;
|
|
364
423
|
operations: NonNullable<Options['operations']>;
|
|
365
424
|
guidType: NonNullable<Options['guidType']>;
|
|
425
|
+
regexType: NonNullable<Options['regexType']>;
|
|
366
426
|
mini: NonNullable<Options['mini']>;
|
|
367
427
|
wrapOutput: Options['wrapOutput'];
|
|
368
|
-
paramsCasing: Options['paramsCasing'];
|
|
369
428
|
printer: Options['printer'];
|
|
370
429
|
};
|
|
371
430
|
type PluginZod = PluginFactoryOptions<'plugin-zod', Options, ResolvedOptions, ResolverZod>;
|
|
@@ -395,8 +454,9 @@ declare const pluginZodName = "plugin-zod";
|
|
|
395
454
|
/**
|
|
396
455
|
* Generates Zod v4 schemas from an OpenAPI spec. Use them to validate API
|
|
397
456
|
* responses at runtime, build form schemas, or feed back into router libraries
|
|
398
|
-
* that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-
|
|
399
|
-
* set the client's `parser: 'zod'` to validate every response
|
|
457
|
+
* that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-axios` or
|
|
458
|
+
* `@kubb/plugin-fetch` and set the client's `parser: 'zod'` to validate every response
|
|
459
|
+
* automatically.
|
|
400
460
|
*
|
|
401
461
|
* @example
|
|
402
462
|
* ```ts
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as __name } from "./
|
|
1
|
+
import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
|
|
2
2
|
import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
|
|
3
|
-
import { buildList, buildObject, caseParams, containsCircularRef, extractRefName, lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, objectKey, stringify, stringifyObject, syncSchemaRef, toRegExpString } from "@kubb/ast/utils";
|
|
4
3
|
import { Const, File, Type, jsxRenderer } from "@kubb/renderer-jsx";
|
|
4
|
+
import { buildList, buildObject, containsCircularRef, extractRefName, lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, objectKey, stringify, stringifyObject, syncSchemaRef, toRegExpString } from "@kubb/ast/utils";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
6
6
|
//#region ../../internals/utils/src/casing.ts
|
|
7
7
|
/**
|
|
@@ -190,6 +190,27 @@ function ensureValidVarName(name) {
|
|
|
190
190
|
return `_${name}`;
|
|
191
191
|
}
|
|
192
192
|
//#endregion
|
|
193
|
+
//#region ../../internals/shared/src/params.ts
|
|
194
|
+
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
195
|
+
/**
|
|
196
|
+
* Applies camelCase to parameter names and returns a new array without mutating the input.
|
|
197
|
+
*
|
|
198
|
+
* Run it before handing parameters to schema builders so output property keys get the right casing
|
|
199
|
+
* while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
|
|
200
|
+
* original array is returned unchanged. Results are cached per input array.
|
|
201
|
+
*/
|
|
202
|
+
function caseParams(params, casing) {
|
|
203
|
+
if (!casing) return params;
|
|
204
|
+
const cached = caseParamsCache.get(params);
|
|
205
|
+
if (cached) return cached;
|
|
206
|
+
const result = params.map((param) => ({
|
|
207
|
+
...param,
|
|
208
|
+
name: camelCase(param.name)
|
|
209
|
+
}));
|
|
210
|
+
caseParamsCache.set(params, result);
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
//#endregion
|
|
193
214
|
//#region ../../internals/shared/src/operation.ts
|
|
194
215
|
/**
|
|
195
216
|
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
@@ -239,6 +260,17 @@ function resolveContentTypeVariants(entries, baseName) {
|
|
|
239
260
|
};
|
|
240
261
|
});
|
|
241
262
|
}
|
|
263
|
+
function getStatusCodeNumber(statusCode) {
|
|
264
|
+
const code = Number(statusCode);
|
|
265
|
+
return Number.isNaN(code) ? null : code;
|
|
266
|
+
}
|
|
267
|
+
function isSuccessStatusCode(statusCode) {
|
|
268
|
+
const code = getStatusCodeNumber(statusCode);
|
|
269
|
+
return code !== null && code >= 200 && code < 300;
|
|
270
|
+
}
|
|
271
|
+
function getSuccessResponses(responses) {
|
|
272
|
+
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
273
|
+
}
|
|
242
274
|
//#endregion
|
|
243
275
|
//#region ../../internals/shared/src/group.ts
|
|
244
276
|
/**
|
|
@@ -497,6 +529,13 @@ function formatLiteral(v) {
|
|
|
497
529
|
return String(v);
|
|
498
530
|
}
|
|
499
531
|
/**
|
|
532
|
+
* Map a `regexType` to the `func` argument of `toRegExpString`: `'constructor'` emits
|
|
533
|
+
* `new RegExp(...)`, while `'literal'` (the default) emits a regex literal.
|
|
534
|
+
*/
|
|
535
|
+
function regexFunc(regexType) {
|
|
536
|
+
return regexType === "constructor" ? "RegExp" : null;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
500
539
|
* Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
|
|
501
540
|
* using the standard chainable Zod v4 API.
|
|
502
541
|
*/
|
|
@@ -513,11 +552,11 @@ function numberConstraints({ min, max, exclusiveMinimum, exclusiveMaximum, multi
|
|
|
513
552
|
* Build `.min()` / `.max()` / `.regex()` chains for strings/arrays
|
|
514
553
|
* using the standard chainable Zod v4 API.
|
|
515
554
|
*/
|
|
516
|
-
function lengthConstraints({ min, max, pattern }) {
|
|
555
|
+
function lengthConstraints({ min, max, pattern, regexType }) {
|
|
517
556
|
return [
|
|
518
557
|
min !== void 0 ? `.min(${min})` : "",
|
|
519
558
|
max !== void 0 ? `.max(${max})` : "",
|
|
520
|
-
pattern !== void 0 ? `.regex(${toRegExpString(pattern,
|
|
559
|
+
pattern !== void 0 ? `.regex(${toRegExpString(pattern, regexFunc(regexType))})` : ""
|
|
521
560
|
].join("");
|
|
522
561
|
}
|
|
523
562
|
/**
|
|
@@ -535,18 +574,18 @@ function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multip
|
|
|
535
574
|
/**
|
|
536
575
|
* Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
|
|
537
576
|
*/
|
|
538
|
-
function lengthChecksMini({ min, max, pattern }) {
|
|
577
|
+
function lengthChecksMini({ min, max, pattern, regexType }) {
|
|
539
578
|
const checks = [];
|
|
540
579
|
if (min !== void 0) checks.push(`z.minLength(${min})`);
|
|
541
580
|
if (max !== void 0) checks.push(`z.maxLength(${max})`);
|
|
542
|
-
if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern,
|
|
581
|
+
if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, regexFunc(regexType))})`);
|
|
543
582
|
return checks.length ? `.check(${checks.join(", ")})` : "";
|
|
544
583
|
}
|
|
545
584
|
/**
|
|
546
|
-
* Apply nullable / optional / nullish modifiers
|
|
547
|
-
* to a schema value string using the chainable Zod v4 API.
|
|
585
|
+
* Apply nullable / optional / nullish modifiers, an optional `.describe()` call, and an
|
|
586
|
+
* optional `.meta({ examples })` call to a schema value string using the chainable Zod v4 API.
|
|
548
587
|
*/
|
|
549
|
-
function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }) {
|
|
588
|
+
function applyModifiers({ value, nullable, optional, nullish, defaultValue, description, examples }) {
|
|
550
589
|
const withModifier = (() => {
|
|
551
590
|
if (nullish || nullable && optional) return `${value}.nullish()`;
|
|
552
591
|
if (optional) return `${value}.optional()`;
|
|
@@ -554,7 +593,8 @@ function applyModifiers({ value, nullable, optional, nullish, defaultValue, desc
|
|
|
554
593
|
return value;
|
|
555
594
|
})();
|
|
556
595
|
const withDefault = defaultValue !== void 0 ? `${withModifier}.default(${formatDefault(defaultValue)})` : withModifier;
|
|
557
|
-
|
|
596
|
+
const withDescription = description ? `${withDefault}.describe(${stringify(description)})` : withDefault;
|
|
597
|
+
return examples?.length ? `${withDescription}.meta({ examples: [${examples.map(formatDefault).join(", ")}] })` : withDescription;
|
|
558
598
|
}
|
|
559
599
|
/**
|
|
560
600
|
* Apply nullable / optional / nullish modifiers using the functional `zod/mini` API
|
|
@@ -580,10 +620,16 @@ function strictOneOfMember$1(member, node) {
|
|
|
580
620
|
return member;
|
|
581
621
|
}
|
|
582
622
|
__name(strictOneOfMember$1, "strictOneOfMember");
|
|
583
|
-
function getMemberConstraint(member) {
|
|
584
|
-
if (member.primitive === "string") return lengthConstraints(
|
|
623
|
+
function getMemberConstraint({ member, regexType }) {
|
|
624
|
+
if (member.primitive === "string") return lengthConstraints({
|
|
625
|
+
...ast.narrowSchema(member, "string") ?? {},
|
|
626
|
+
regexType
|
|
627
|
+
}) || void 0;
|
|
585
628
|
if (member.primitive === "number" || member.primitive === "integer") return numberConstraints(ast.narrowSchema(member, "number") ?? ast.narrowSchema(member, "integer") ?? {}) || void 0;
|
|
586
|
-
if (member.primitive === "array") return lengthConstraints(
|
|
629
|
+
if (member.primitive === "array") return lengthConstraints({
|
|
630
|
+
...ast.narrowSchema(member, "array") ?? {},
|
|
631
|
+
regexType
|
|
632
|
+
}) || void 0;
|
|
587
633
|
}
|
|
588
634
|
/**
|
|
589
635
|
* Zod v4 printer built with `definePrinter`.
|
|
@@ -597,7 +643,7 @@ function getMemberConstraint(member) {
|
|
|
597
643
|
* const code = printer.print(stringNode) // "z.string()"
|
|
598
644
|
* ```
|
|
599
645
|
*/
|
|
600
|
-
const printerZod = ast.
|
|
646
|
+
const printerZod = ast.createPrinter((options) => {
|
|
601
647
|
return {
|
|
602
648
|
name: "zod",
|
|
603
649
|
options,
|
|
@@ -609,7 +655,10 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
609
655
|
boolean: () => "z.boolean()",
|
|
610
656
|
null: () => "z.null()",
|
|
611
657
|
string(node) {
|
|
612
|
-
return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints(
|
|
658
|
+
return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints({
|
|
659
|
+
...node,
|
|
660
|
+
regexType: this.options.regexType
|
|
661
|
+
})}`;
|
|
613
662
|
},
|
|
614
663
|
number(node) {
|
|
615
664
|
return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number()" : "z.number()"}${numberConstraints(node)}`;
|
|
@@ -637,13 +686,22 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
637
686
|
return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
|
|
638
687
|
},
|
|
639
688
|
uuid(node) {
|
|
640
|
-
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints(
|
|
689
|
+
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints({
|
|
690
|
+
...node,
|
|
691
|
+
regexType: this.options.regexType
|
|
692
|
+
})}`;
|
|
641
693
|
},
|
|
642
694
|
email(node) {
|
|
643
|
-
return `z.email()${lengthConstraints(
|
|
695
|
+
return `z.email()${lengthConstraints({
|
|
696
|
+
...node,
|
|
697
|
+
regexType: this.options.regexType
|
|
698
|
+
})}`;
|
|
644
699
|
},
|
|
645
700
|
url(node) {
|
|
646
|
-
return `z.url()${lengthConstraints(
|
|
701
|
+
return `z.url()${lengthConstraints({
|
|
702
|
+
...node,
|
|
703
|
+
regexType: this.options.regexType
|
|
704
|
+
})}`;
|
|
647
705
|
},
|
|
648
706
|
ipv4: () => "z.ipv4()",
|
|
649
707
|
ipv6: () => "z.ipv6()",
|
|
@@ -688,7 +746,8 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
688
746
|
optional: schema.optional || property.required === false,
|
|
689
747
|
nullish: schema.nullish,
|
|
690
748
|
defaultValue: meta.default,
|
|
691
|
-
description: descriptionToApply
|
|
749
|
+
description: descriptionToApply,
|
|
750
|
+
examples: meta.examples
|
|
692
751
|
});
|
|
693
752
|
return isCyclic(schema) ? lazyGetter({
|
|
694
753
|
name: propName,
|
|
@@ -706,7 +765,10 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
706
765
|
})();
|
|
707
766
|
},
|
|
708
767
|
array(node) {
|
|
709
|
-
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthConstraints(
|
|
768
|
+
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthConstraints({
|
|
769
|
+
...node,
|
|
770
|
+
regexType: this.options.regexType
|
|
771
|
+
})}`;
|
|
710
772
|
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
|
|
711
773
|
},
|
|
712
774
|
tuple(node) {
|
|
@@ -728,7 +790,10 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
728
790
|
const firstBase = this.transform(first);
|
|
729
791
|
if (!firstBase) return "";
|
|
730
792
|
return rest.reduce((acc, member) => {
|
|
731
|
-
const constraint = getMemberConstraint(
|
|
793
|
+
const constraint = getMemberConstraint({
|
|
794
|
+
member,
|
|
795
|
+
regexType: this.options.regexType
|
|
796
|
+
});
|
|
732
797
|
if (constraint) return acc + constraint;
|
|
733
798
|
const transformed = this.transform(member);
|
|
734
799
|
return transformed ? `${acc}.and(${transformed})` : acc;
|
|
@@ -752,7 +817,8 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
752
817
|
optional: meta.optional,
|
|
753
818
|
nullish: meta.nullish,
|
|
754
819
|
defaultValue: meta.default,
|
|
755
|
-
description: meta.description
|
|
820
|
+
description: meta.description,
|
|
821
|
+
examples: meta.examples
|
|
756
822
|
});
|
|
757
823
|
}
|
|
758
824
|
};
|
|
@@ -763,10 +829,16 @@ function strictOneOfMember(member, node) {
|
|
|
763
829
|
if (node.type === "object" && (node.additionalProperties === void 0 || node.additionalProperties === false)) return member.replace(/^z\.object\(/, "z.strictObject(");
|
|
764
830
|
return member;
|
|
765
831
|
}
|
|
766
|
-
function getMemberConstraintMini(member) {
|
|
767
|
-
if (member.primitive === "string") return lengthChecksMini(
|
|
832
|
+
function getMemberConstraintMini({ member, regexType }) {
|
|
833
|
+
if (member.primitive === "string") return lengthChecksMini({
|
|
834
|
+
...ast.narrowSchema(member, "string") ?? {},
|
|
835
|
+
regexType
|
|
836
|
+
}) || void 0;
|
|
768
837
|
if (member.primitive === "number" || member.primitive === "integer") return numberChecksMini(ast.narrowSchema(member, "number") ?? ast.narrowSchema(member, "integer") ?? {}) || void 0;
|
|
769
|
-
if (member.primitive === "array") return lengthChecksMini(
|
|
838
|
+
if (member.primitive === "array") return lengthChecksMini({
|
|
839
|
+
...ast.narrowSchema(member, "array") ?? {},
|
|
840
|
+
regexType
|
|
841
|
+
}) || void 0;
|
|
770
842
|
}
|
|
771
843
|
/**
|
|
772
844
|
* Zod v4 **Mini** printer built with `definePrinter`.
|
|
@@ -780,7 +852,7 @@ function getMemberConstraintMini(member) {
|
|
|
780
852
|
* const code = printer.print(optionalStringNode) // "z.optional(z.string())"
|
|
781
853
|
* ```
|
|
782
854
|
*/
|
|
783
|
-
const printerZodMini = ast.
|
|
855
|
+
const printerZodMini = ast.createPrinter((options) => {
|
|
784
856
|
return {
|
|
785
857
|
name: "zod-mini",
|
|
786
858
|
options,
|
|
@@ -792,7 +864,10 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
792
864
|
boolean: () => "z.boolean()",
|
|
793
865
|
null: () => "z.null()",
|
|
794
866
|
string(node) {
|
|
795
|
-
return `z.string()${lengthChecksMini(
|
|
867
|
+
return `z.string()${lengthChecksMini({
|
|
868
|
+
...node,
|
|
869
|
+
regexType: this.options.regexType
|
|
870
|
+
})}`;
|
|
796
871
|
},
|
|
797
872
|
number(node) {
|
|
798
873
|
return `z.number()${numberChecksMini(node)}`;
|
|
@@ -815,13 +890,22 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
815
890
|
return "z.date()";
|
|
816
891
|
},
|
|
817
892
|
uuid(node) {
|
|
818
|
-
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthChecksMini(
|
|
893
|
+
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthChecksMini({
|
|
894
|
+
...node,
|
|
895
|
+
regexType: this.options.regexType
|
|
896
|
+
})}`;
|
|
819
897
|
},
|
|
820
898
|
email(node) {
|
|
821
|
-
return `z.email()${lengthChecksMini(
|
|
899
|
+
return `z.email()${lengthChecksMini({
|
|
900
|
+
...node,
|
|
901
|
+
regexType: this.options.regexType
|
|
902
|
+
})}`;
|
|
822
903
|
},
|
|
823
904
|
url(node) {
|
|
824
|
-
return `z.url()${lengthChecksMini(
|
|
905
|
+
return `z.url()${lengthChecksMini({
|
|
906
|
+
...node,
|
|
907
|
+
regexType: this.options.regexType
|
|
908
|
+
})}`;
|
|
825
909
|
},
|
|
826
910
|
ipv4: () => "z.ipv4()",
|
|
827
911
|
ipv6: () => "z.ipv6()",
|
|
@@ -871,7 +955,10 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
871
955
|
}))})`;
|
|
872
956
|
},
|
|
873
957
|
array(node) {
|
|
874
|
-
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthChecksMini(
|
|
958
|
+
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthChecksMini({
|
|
959
|
+
...node,
|
|
960
|
+
regexType: this.options.regexType
|
|
961
|
+
})}`;
|
|
875
962
|
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
|
|
876
963
|
},
|
|
877
964
|
tuple(node) {
|
|
@@ -893,7 +980,10 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
893
980
|
const firstBase = this.transform(first);
|
|
894
981
|
if (!firstBase) return "";
|
|
895
982
|
return rest.reduce((acc, member) => {
|
|
896
|
-
const constraint = getMemberConstraintMini(
|
|
983
|
+
const constraint = getMemberConstraintMini({
|
|
984
|
+
member,
|
|
985
|
+
regexType: this.options.regexType
|
|
986
|
+
});
|
|
897
987
|
if (constraint) return acc + constraint;
|
|
898
988
|
const transformed = this.transform(member);
|
|
899
989
|
return transformed ? `z.intersection(${acc}, ${transformed})` : acc;
|
|
@@ -932,7 +1022,7 @@ const zodMiniPrinterCache = /* @__PURE__ */ new WeakMap();
|
|
|
932
1022
|
*/
|
|
933
1023
|
function getStdPrinters(resolver, params) {
|
|
934
1024
|
const cached = zodPrinterCache.get(resolver);
|
|
935
|
-
if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.dateType === params.dateType) return {
|
|
1025
|
+
if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.regexType === params.regexType && cached.dateType === params.dateType) return {
|
|
936
1026
|
output: cached.output,
|
|
937
1027
|
input: cached.input
|
|
938
1028
|
};
|
|
@@ -953,6 +1043,7 @@ function getStdPrinters(resolver, params) {
|
|
|
953
1043
|
input,
|
|
954
1044
|
coercion: params.coercion,
|
|
955
1045
|
guidType: params.guidType,
|
|
1046
|
+
regexType: params.regexType,
|
|
956
1047
|
dateType: params.dateType
|
|
957
1048
|
});
|
|
958
1049
|
return {
|
|
@@ -962,14 +1053,15 @@ function getStdPrinters(resolver, params) {
|
|
|
962
1053
|
}
|
|
963
1054
|
function getMiniPrinter(resolver, params) {
|
|
964
1055
|
const cached = zodMiniPrinterCache.get(resolver);
|
|
965
|
-
if (cached && cached.guidType === params.guidType) return cached.printer;
|
|
1056
|
+
if (cached && cached.guidType === params.guidType && cached.regexType === params.regexType) return cached.printer;
|
|
966
1057
|
const p = printerZodMini({
|
|
967
1058
|
...params,
|
|
968
1059
|
resolver
|
|
969
1060
|
});
|
|
970
1061
|
zodMiniPrinterCache.set(resolver, {
|
|
971
1062
|
printer: p,
|
|
972
|
-
guidType: params.guidType
|
|
1063
|
+
guidType: params.guidType,
|
|
1064
|
+
regexType: params.regexType
|
|
973
1065
|
});
|
|
974
1066
|
return p;
|
|
975
1067
|
}
|
|
@@ -984,7 +1076,7 @@ const zodGenerator = defineGenerator({
|
|
|
984
1076
|
renderer: jsxRenderer,
|
|
985
1077
|
schema(node, ctx) {
|
|
986
1078
|
const { adapter, config, resolver, root } = ctx;
|
|
987
|
-
const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
|
|
1079
|
+
const { output, coercion, guidType, regexType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
|
|
988
1080
|
const dateType = adapter.options.dateType;
|
|
989
1081
|
if (!node.name) return;
|
|
990
1082
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
@@ -1035,6 +1127,7 @@ const zodGenerator = defineGenerator({
|
|
|
1035
1127
|
const stdPrinters = mini ? null : getStdPrinters(resolver, {
|
|
1036
1128
|
coercion,
|
|
1037
1129
|
guidType,
|
|
1130
|
+
regexType,
|
|
1038
1131
|
dateType,
|
|
1039
1132
|
wrapOutput,
|
|
1040
1133
|
cyclicSchemas,
|
|
@@ -1042,6 +1135,7 @@ const zodGenerator = defineGenerator({
|
|
|
1042
1135
|
});
|
|
1043
1136
|
const schemaPrinter = mini ? getMiniPrinter(resolver, {
|
|
1044
1137
|
guidType,
|
|
1138
|
+
regexType,
|
|
1045
1139
|
wrapOutput,
|
|
1046
1140
|
cyclicSchemas,
|
|
1047
1141
|
nodes: printer?.nodes
|
|
@@ -1099,10 +1193,10 @@ const zodGenerator = defineGenerator({
|
|
|
1099
1193
|
operation(node, ctx) {
|
|
1100
1194
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1101
1195
|
const { adapter, config, resolver, root } = ctx;
|
|
1102
|
-
const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group,
|
|
1196
|
+
const { output, coercion, guidType, regexType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
|
|
1103
1197
|
const dateType = adapter.options.dateType;
|
|
1104
1198
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
1105
|
-
const params = caseParams(node.parameters,
|
|
1199
|
+
const params = caseParams(node.parameters, "camelcase");
|
|
1106
1200
|
const meta = { file: resolver.resolveFile({
|
|
1107
1201
|
name: node.operationId,
|
|
1108
1202
|
extname: ".ts",
|
|
@@ -1131,6 +1225,7 @@ const zodGenerator = defineGenerator({
|
|
|
1131
1225
|
}));
|
|
1132
1226
|
const schemaPrinter = mini ? keysToOmit?.length ? printerZodMini({
|
|
1133
1227
|
guidType,
|
|
1228
|
+
regexType,
|
|
1134
1229
|
wrapOutput,
|
|
1135
1230
|
resolver,
|
|
1136
1231
|
keysToOmit,
|
|
@@ -1138,12 +1233,14 @@ const zodGenerator = defineGenerator({
|
|
|
1138
1233
|
nodes: printer?.nodes
|
|
1139
1234
|
}) : getMiniPrinter(resolver, {
|
|
1140
1235
|
guidType,
|
|
1236
|
+
regexType,
|
|
1141
1237
|
wrapOutput,
|
|
1142
1238
|
cyclicSchemas,
|
|
1143
1239
|
nodes: printer?.nodes
|
|
1144
1240
|
}) : keysToOmit?.length ? printerZod({
|
|
1145
1241
|
coercion,
|
|
1146
1242
|
guidType,
|
|
1243
|
+
regexType,
|
|
1147
1244
|
dateType,
|
|
1148
1245
|
wrapOutput,
|
|
1149
1246
|
resolver,
|
|
@@ -1154,6 +1251,7 @@ const zodGenerator = defineGenerator({
|
|
|
1154
1251
|
}) : getStdPrinters(resolver, {
|
|
1155
1252
|
coercion,
|
|
1156
1253
|
guidType,
|
|
1254
|
+
regexType,
|
|
1157
1255
|
dateType,
|
|
1158
1256
|
wrapOutput,
|
|
1159
1257
|
cyclicSchemas,
|
|
@@ -1210,16 +1308,21 @@ const zodGenerator = defineGenerator({
|
|
|
1210
1308
|
});
|
|
1211
1309
|
});
|
|
1212
1310
|
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
|
|
1311
|
+
const successResponsesWithSchema = getSuccessResponses(responsesWithSchema);
|
|
1213
1312
|
const responseUnionSchema = responsesWithSchema.length > 0 ? (() => {
|
|
1214
1313
|
const responseUnionName = resolver.resolveResponseName(node);
|
|
1215
|
-
if (new Set(
|
|
1314
|
+
if (new Set(successResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
|
|
1216
1315
|
name: resolver.resolveSchemaName(schemaName),
|
|
1217
1316
|
path: ""
|
|
1218
1317
|
})).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(responseUnionName)) return null;
|
|
1219
|
-
const members =
|
|
1318
|
+
const members = successResponsesWithSchema.map((res) => ast.factory.createSchema({
|
|
1220
1319
|
type: "ref",
|
|
1221
1320
|
name: resolver.resolveResponseStatusName(node, res.statusCode)
|
|
1222
1321
|
}));
|
|
1322
|
+
if (members.length === 0) return renderSchemaEntry({
|
|
1323
|
+
schema: ast.factory.createSchema({ type: "unknown" }),
|
|
1324
|
+
name: responseUnionName
|
|
1325
|
+
});
|
|
1223
1326
|
return renderSchemaEntry({
|
|
1224
1327
|
schema: members.length === 1 ? members[0] : ast.factory.createSchema({
|
|
1225
1328
|
type: "union",
|
|
@@ -1284,7 +1387,7 @@ const zodGenerator = defineGenerator({
|
|
|
1284
1387
|
},
|
|
1285
1388
|
operations(nodes, ctx) {
|
|
1286
1389
|
const { config, resolver, root } = ctx;
|
|
1287
|
-
const { output, importPath, group, operations
|
|
1390
|
+
const { output, importPath, group, operations } = ctx.options;
|
|
1288
1391
|
if (!operations) return;
|
|
1289
1392
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
1290
1393
|
const meta = { file: resolver.resolveFile({
|
|
@@ -1299,7 +1402,7 @@ const zodGenerator = defineGenerator({
|
|
|
1299
1402
|
return {
|
|
1300
1403
|
node,
|
|
1301
1404
|
data: buildSchemaNames(node, {
|
|
1302
|
-
params: caseParams(node.parameters,
|
|
1405
|
+
params: caseParams(node.parameters, "camelcase"),
|
|
1303
1406
|
resolver
|
|
1304
1407
|
})
|
|
1305
1408
|
};
|
|
@@ -1441,8 +1544,9 @@ const pluginZodName = "plugin-zod";
|
|
|
1441
1544
|
/**
|
|
1442
1545
|
* Generates Zod v4 schemas from an OpenAPI spec. Use them to validate API
|
|
1443
1546
|
* responses at runtime, build form schemas, or feed back into router libraries
|
|
1444
|
-
* that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-
|
|
1445
|
-
* set the client's `parser: 'zod'` to validate every response
|
|
1547
|
+
* that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-axios` or
|
|
1548
|
+
* `@kubb/plugin-fetch` and set the client's `parser: 'zod'` to validate every response
|
|
1549
|
+
* automatically.
|
|
1446
1550
|
*
|
|
1447
1551
|
* @example
|
|
1448
1552
|
* ```ts
|
|
@@ -1467,7 +1571,7 @@ const pluginZod = definePlugin((options) => {
|
|
|
1467
1571
|
const { output = {
|
|
1468
1572
|
path: "zod",
|
|
1469
1573
|
barrel: { type: "named" }
|
|
1470
|
-
}, group, exclude = [], include, override = [], typed = false, operations = false, mini = false, guidType = "uuid", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, wrapOutput = void 0,
|
|
1574
|
+
}, group, exclude = [], include, override = [], typed = false, operations = false, mini = false, guidType = "uuid", regexType = "literal", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, wrapOutput = void 0, printer, resolver: userResolver, macros: userMacros } = options;
|
|
1471
1575
|
const groupConfig = createGroupConfig(group);
|
|
1472
1576
|
return {
|
|
1473
1577
|
name: pluginZodName,
|
|
@@ -1485,9 +1589,9 @@ const pluginZod = definePlugin((options) => {
|
|
|
1485
1589
|
operations,
|
|
1486
1590
|
inferred,
|
|
1487
1591
|
guidType,
|
|
1592
|
+
regexType,
|
|
1488
1593
|
mini,
|
|
1489
1594
|
wrapOutput,
|
|
1490
|
-
paramsCasing,
|
|
1491
1595
|
printer
|
|
1492
1596
|
});
|
|
1493
1597
|
ctx.setResolver(userResolver ? {
|
|
@@ -1496,7 +1600,6 @@ const pluginZod = definePlugin((options) => {
|
|
|
1496
1600
|
} : resolverZod);
|
|
1497
1601
|
if (userMacros?.length) ctx.setMacros(userMacros);
|
|
1498
1602
|
ctx.addGenerator(zodGenerator);
|
|
1499
|
-
for (const gen of userGenerators) ctx.addGenerator(gen);
|
|
1500
1603
|
} }
|
|
1501
1604
|
};
|
|
1502
1605
|
});
|