@kubb/plugin-zod 5.1.0 → 5.1.1
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 +221 -164
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +18 -6
- package/dist/index.js +221 -164
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -73,14 +73,18 @@ type PrinterZodOptions = {
|
|
|
73
73
|
*/
|
|
74
74
|
cyclicSchemas?: ReadonlySet<string>;
|
|
75
75
|
/**
|
|
76
|
-
*
|
|
77
|
-
* - `'
|
|
78
|
-
* - `'
|
|
76
|
+
* Which way a node converts between its wire type and its runtime type:
|
|
77
|
+
* - `'decode'` (default): wire into runtime, used by response schemas.
|
|
78
|
+
* - `'encode'`: runtime back to wire, used by request bodies and parameters.
|
|
79
79
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
80
|
+
* Named for the conversion rather than the slot, since Zod's own `z.input` and `z.output`
|
|
81
|
+
* describe a different axis and read inverted here: the `'decode'` schema is the one whose
|
|
82
|
+
* `z.input` is the wire type.
|
|
83
|
+
*
|
|
84
|
+
* A handler returning different output per direction makes the generator emit an
|
|
85
|
+
* `${name}InputSchema` variant for that component.
|
|
82
86
|
*/
|
|
83
|
-
direction?: '
|
|
87
|
+
direction?: 'encode' | 'decode';
|
|
84
88
|
/**
|
|
85
89
|
* Custom handler map for node type overrides.
|
|
86
90
|
*/
|
|
@@ -351,6 +355,9 @@ type Options = OutputOptions & {
|
|
|
351
355
|
* validate with `z.coerce.date()` instead of the string-to-Date codec. Fields
|
|
352
356
|
* kept as ISO strings (`z.iso.date()`, `z.iso.datetime()`) are never coerced.
|
|
353
357
|
*
|
|
358
|
+
* `bigint` fields (`format: int64`) always coerce, regardless of this option:
|
|
359
|
+
* `JSON.parse` hands back a `number`, which a plain `z.bigint()` rejects.
|
|
360
|
+
*
|
|
354
361
|
* @default false
|
|
355
362
|
* @see https://zod.dev/?id=coercion-for-primitives
|
|
356
363
|
*/
|
|
@@ -391,6 +398,11 @@ type Options = OutputOptions & {
|
|
|
391
398
|
/**
|
|
392
399
|
* Replace the Zod handler for a specific schema type (`'integer'`, `'date'`, ...).
|
|
393
400
|
* When `mini: true`, overrides target the Zod Mini printer instead.
|
|
401
|
+
*
|
|
402
|
+
* A handler that returns a different expression per `this.options.direction` declares a two-way
|
|
403
|
+
* conversion, such as a `time` field carried as an ISO string but modeled as a
|
|
404
|
+
* `Temporal.PlainTime`. The generator then emits an `${name}InputSchema` variant for request
|
|
405
|
+
* bodies to resolve to, `$ref` included. Ignore `direction` and only the printed output changes.
|
|
394
406
|
*/
|
|
395
407
|
printer?: {
|
|
396
408
|
nodes?: PrinterZodNodes | PrinterZodMiniNodes;
|
package/dist/index.js
CHANGED
|
@@ -779,68 +779,6 @@ function shouldCoerce(coercion, type) {
|
|
|
779
779
|
return !!coercion[type];
|
|
780
780
|
}
|
|
781
781
|
/**
|
|
782
|
-
* Registered codecs, checked in order.
|
|
783
|
-
*/
|
|
784
|
-
const codecs = [{
|
|
785
|
-
matches(node) {
|
|
786
|
-
return node.type === "date" && node.representation === "date";
|
|
787
|
-
},
|
|
788
|
-
decode(node) {
|
|
789
|
-
return node.format === "date" ? "z.iso.date().transform((value) => new Date(value))" : "z.iso.datetime().transform((value) => new Date(value))";
|
|
790
|
-
},
|
|
791
|
-
encode(node) {
|
|
792
|
-
return node.format === "date" ? "z.date().transform((value) => value.toISOString().slice(0, 10))" : "z.date().transform((value) => value.toISOString())";
|
|
793
|
-
}
|
|
794
|
-
}];
|
|
795
|
-
/**
|
|
796
|
-
* Returns the codec for this node, or `undefined` when the node needs no
|
|
797
|
-
* encode/decode (its wire and runtime types match).
|
|
798
|
-
*/
|
|
799
|
-
function getCodec(node) {
|
|
800
|
-
if (!node) return void 0;
|
|
801
|
-
return codecs.find((codec) => codec.matches(node));
|
|
802
|
-
}
|
|
803
|
-
/**
|
|
804
|
-
* Returns `true` when the node itself is encoded/decoded by a codec.
|
|
805
|
-
*/
|
|
806
|
-
function hasCodec(node) {
|
|
807
|
-
return getCodec(node) !== void 0;
|
|
808
|
-
}
|
|
809
|
-
/**
|
|
810
|
-
* Returns `true` when the schema transitively contains a codec node —
|
|
811
|
-
* a value whose runtime type differs from its wire type (see {@link hasCodec}),
|
|
812
|
-
* so it must be decoded (response) or encoded (request) at the validation boundary.
|
|
813
|
-
* `$ref`s are followed via their resolved schema; a `seen` set guards cycles.
|
|
814
|
-
*/
|
|
815
|
-
function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
|
|
816
|
-
if (!node) return false;
|
|
817
|
-
if (hasCodec(node)) return true;
|
|
818
|
-
if (node.type === "ref") {
|
|
819
|
-
if (!node.ref) return false;
|
|
820
|
-
const refName = extractRefName(node.ref);
|
|
821
|
-
if (refName) {
|
|
822
|
-
if (seen.has(refName)) return false;
|
|
823
|
-
seen.add(refName);
|
|
824
|
-
}
|
|
825
|
-
const resolved = syncSchemaRef(node);
|
|
826
|
-
if (resolved.type === "ref") return false;
|
|
827
|
-
return containsCodec(resolved, seen);
|
|
828
|
-
}
|
|
829
|
-
const children = [];
|
|
830
|
-
if ("properties" in node && node.properties) children.push(...node.properties.map((prop) => prop.schema));
|
|
831
|
-
if ("items" in node && node.items) children.push(...node.items);
|
|
832
|
-
if ("members" in node && node.members) children.push(...node.members);
|
|
833
|
-
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
|
|
834
|
-
return children.some((child) => containsCodec(child, seen));
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* Collects the names of `$ref` schemas that transitively contain a codec, so the generator can route
|
|
838
|
-
* them to their input (encode) variant.
|
|
839
|
-
*/
|
|
840
|
-
function collectCodecRefNames(node) {
|
|
841
|
-
return ast.collectSync(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? ast.resolveRefName(n) ?? void 0 : void 0 });
|
|
842
|
-
}
|
|
843
|
-
/**
|
|
844
782
|
* Whether the node is a plain inline object whose shape can be lifted into an `.extend({ … })`
|
|
845
783
|
* argument. A catchall, `patternProperties`, or a nullable/optional wrapper cannot, so those stay
|
|
846
784
|
* on `.and(…)`.
|
|
@@ -1153,6 +1091,168 @@ function buildZodObjectShape(ctx, node) {
|
|
|
1153
1091
|
}));
|
|
1154
1092
|
}
|
|
1155
1093
|
/**
|
|
1094
|
+
* Types the direction probe skips. They delegate to their children rather than reading
|
|
1095
|
+
* `direction` themselves, so {@link containsDirectionalNode} walks into the children instead.
|
|
1096
|
+
*/
|
|
1097
|
+
const CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
1098
|
+
"object",
|
|
1099
|
+
"array",
|
|
1100
|
+
"tuple",
|
|
1101
|
+
"union",
|
|
1102
|
+
"intersection",
|
|
1103
|
+
"ref"
|
|
1104
|
+
]);
|
|
1105
|
+
/**
|
|
1106
|
+
* Runs the node's effective handler (a `printer.nodes` override, else the built-in) once per
|
|
1107
|
+
* direction and reports whether the two disagree. That difference is what makes a component
|
|
1108
|
+
* need an `${name}InputSchema` variant.
|
|
1109
|
+
*/
|
|
1110
|
+
function variesByDirection({ node, printerOptions }) {
|
|
1111
|
+
if (CONTAINER_TYPES.has(node.type)) return false;
|
|
1112
|
+
const handler = printerOptions.nodes?.[node.type] ?? scalarNodes[node.type];
|
|
1113
|
+
if (!handler) return false;
|
|
1114
|
+
const call = (direction) => {
|
|
1115
|
+
const context = {
|
|
1116
|
+
options: {
|
|
1117
|
+
...printerOptions,
|
|
1118
|
+
direction
|
|
1119
|
+
},
|
|
1120
|
+
transform: () => null,
|
|
1121
|
+
base: () => null
|
|
1122
|
+
};
|
|
1123
|
+
return handler.call(context, node);
|
|
1124
|
+
};
|
|
1125
|
+
return call("decode") !== call("encode");
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* Whether the schema transitively contains a node that prints differently per direction, so it
|
|
1129
|
+
* must decode on responses and encode on requests. Follows `$ref`s through their resolved
|
|
1130
|
+
* schema, with `seen` guarding cycles.
|
|
1131
|
+
*/
|
|
1132
|
+
function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */ new Set() }) {
|
|
1133
|
+
if (!node) return false;
|
|
1134
|
+
if (node.type === "ref") {
|
|
1135
|
+
if (!node.ref) return false;
|
|
1136
|
+
const refName = extractRefName(node.ref);
|
|
1137
|
+
if (refName) {
|
|
1138
|
+
if (seen.has(refName)) return false;
|
|
1139
|
+
seen.add(refName);
|
|
1140
|
+
}
|
|
1141
|
+
const resolved = syncSchemaRef(node);
|
|
1142
|
+
if (resolved.type === "ref") return false;
|
|
1143
|
+
return containsDirectionalNode({
|
|
1144
|
+
node: resolved,
|
|
1145
|
+
printerOptions,
|
|
1146
|
+
seen
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
if (variesByDirection({
|
|
1150
|
+
node,
|
|
1151
|
+
printerOptions
|
|
1152
|
+
})) return true;
|
|
1153
|
+
const children = [];
|
|
1154
|
+
if ("properties" in node && node.properties) children.push(...node.properties.map((prop) => prop.schema));
|
|
1155
|
+
if ("items" in node && node.items) children.push(...node.items);
|
|
1156
|
+
if ("members" in node && node.members) children.push(...node.members);
|
|
1157
|
+
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
|
|
1158
|
+
return children.some((child) => containsDirectionalNode({
|
|
1159
|
+
node: child,
|
|
1160
|
+
printerOptions,
|
|
1161
|
+
seen
|
|
1162
|
+
}));
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Names of the `$ref` schemas the generator should route to their input (encode) variant.
|
|
1166
|
+
*/
|
|
1167
|
+
function collectDirectionalRefNames({ node, printerOptions }) {
|
|
1168
|
+
return ast.collectSync(node, { schema: (n) => n.type === "ref" && n.ref && containsDirectionalNode({
|
|
1169
|
+
node: n,
|
|
1170
|
+
printerOptions
|
|
1171
|
+
}) ? ast.resolveRefName(n) ?? void 0 : void 0 });
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Handlers that never recurse into children, so {@link variesByDirection} can call one directly
|
|
1175
|
+
* to probe both directions without building a printer.
|
|
1176
|
+
*
|
|
1177
|
+
* `date` is the built-in two-way conversion, decoding `string → Date` on responses and encoding
|
|
1178
|
+
* back on requests, keeping `date` and `date-time` precision apart. Only `representation: 'date'`
|
|
1179
|
+
* fields convert; ISO-string fields print `z.iso.date()` either way. A `printer.nodes.date`
|
|
1180
|
+
* override replaces the whole handler, direction branch included.
|
|
1181
|
+
*/
|
|
1182
|
+
const scalarNodes = {
|
|
1183
|
+
any: () => "z.any()",
|
|
1184
|
+
unknown: () => "z.unknown()",
|
|
1185
|
+
void: () => "z.void()",
|
|
1186
|
+
never: () => "z.never()",
|
|
1187
|
+
boolean: () => "z.boolean()",
|
|
1188
|
+
null: () => "z.null()",
|
|
1189
|
+
string(node) {
|
|
1190
|
+
const base = shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()";
|
|
1191
|
+
const pattern = node.pattern ?? integerFormatPattern(node.format);
|
|
1192
|
+
return `${base}${lengthConstraints({
|
|
1193
|
+
...node,
|
|
1194
|
+
pattern,
|
|
1195
|
+
regexType: this.options.regexType
|
|
1196
|
+
})}`;
|
|
1197
|
+
},
|
|
1198
|
+
number(node) {
|
|
1199
|
+
return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number()" : "z.number()"}${numberConstraints(node)}`;
|
|
1200
|
+
},
|
|
1201
|
+
integer(node) {
|
|
1202
|
+
return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number().int()" : "z.int()"}${numberConstraints(node)}`;
|
|
1203
|
+
},
|
|
1204
|
+
bigint() {
|
|
1205
|
+
return "z.coerce.bigint()";
|
|
1206
|
+
},
|
|
1207
|
+
date(node) {
|
|
1208
|
+
if (node.representation !== "date") return "z.iso.date()";
|
|
1209
|
+
if (this.options.direction === "encode") return node.format === "date" ? "z.date().transform((value) => value.toISOString().slice(0, 10))" : "z.date().transform((value) => value.toISOString())";
|
|
1210
|
+
const decoded = node.format === "date" ? "z.iso.date().transform((value) => new Date(value))" : "z.iso.datetime().transform((value) => new Date(value))";
|
|
1211
|
+
return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : decoded;
|
|
1212
|
+
},
|
|
1213
|
+
datetime(node) {
|
|
1214
|
+
const offset = node.offset || this.options.dateType === "stringOffset";
|
|
1215
|
+
const local = node.local || this.options.dateType === "stringLocal";
|
|
1216
|
+
if (offset) return "z.iso.datetime({ offset: true })";
|
|
1217
|
+
if (local) return "z.iso.datetime({ local: true })";
|
|
1218
|
+
return "z.iso.datetime()";
|
|
1219
|
+
},
|
|
1220
|
+
time(node) {
|
|
1221
|
+
if (node.representation === "string") return "z.iso.time()";
|
|
1222
|
+
return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
|
|
1223
|
+
},
|
|
1224
|
+
uuid(node) {
|
|
1225
|
+
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints({
|
|
1226
|
+
...node,
|
|
1227
|
+
regexType: this.options.regexType
|
|
1228
|
+
})}`;
|
|
1229
|
+
},
|
|
1230
|
+
email(node) {
|
|
1231
|
+
return `z.email()${lengthConstraints({
|
|
1232
|
+
...node,
|
|
1233
|
+
regexType: this.options.regexType
|
|
1234
|
+
})}`;
|
|
1235
|
+
},
|
|
1236
|
+
url(node) {
|
|
1237
|
+
return `z.url()${lengthConstraints({
|
|
1238
|
+
...node,
|
|
1239
|
+
regexType: this.options.regexType
|
|
1240
|
+
})}`;
|
|
1241
|
+
},
|
|
1242
|
+
ipv4: () => "z.ipv4()",
|
|
1243
|
+
ipv6: () => "z.ipv6()",
|
|
1244
|
+
blob: () => "z.instanceof(File)",
|
|
1245
|
+
enum(node) {
|
|
1246
|
+
const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
|
|
1247
|
+
if (node.namedEnumValues?.length) {
|
|
1248
|
+
const literals = nonNullValues.map((v) => `z.literal(${formatLiteral(v)})`);
|
|
1249
|
+
if (literals.length === 1) return literals[0];
|
|
1250
|
+
return `z.union([${literals.join(", ")}])`;
|
|
1251
|
+
}
|
|
1252
|
+
return buildEnum(nonNullValues);
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
/**
|
|
1156
1256
|
* Zod v4 printer built with `definePrinter`.
|
|
1157
1257
|
*
|
|
1158
1258
|
* Converts a `SchemaNode` AST into a Zod v4 code string using the chainable API
|
|
@@ -1170,84 +1270,15 @@ const printerZod = ast.createPrinter((options) => {
|
|
|
1170
1270
|
name: "zod",
|
|
1171
1271
|
options,
|
|
1172
1272
|
nodes: {
|
|
1173
|
-
|
|
1174
|
-
unknown: () => "z.unknown()",
|
|
1175
|
-
void: () => "z.void()",
|
|
1176
|
-
never: () => "z.never()",
|
|
1177
|
-
boolean: () => "z.boolean()",
|
|
1178
|
-
null: () => "z.null()",
|
|
1179
|
-
string(node) {
|
|
1180
|
-
const base = shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()";
|
|
1181
|
-
const pattern = node.pattern ?? integerFormatPattern(node.format);
|
|
1182
|
-
return `${base}${lengthConstraints({
|
|
1183
|
-
...node,
|
|
1184
|
-
pattern,
|
|
1185
|
-
regexType: this.options.regexType
|
|
1186
|
-
})}`;
|
|
1187
|
-
},
|
|
1188
|
-
number(node) {
|
|
1189
|
-
return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number()" : "z.number()"}${numberConstraints(node)}`;
|
|
1190
|
-
},
|
|
1191
|
-
integer(node) {
|
|
1192
|
-
return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number().int()" : "z.int()"}${numberConstraints(node)}`;
|
|
1193
|
-
},
|
|
1194
|
-
bigint() {
|
|
1195
|
-
return shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.bigint()" : "z.bigint()";
|
|
1196
|
-
},
|
|
1197
|
-
date(node) {
|
|
1198
|
-
const codec = getCodec(node);
|
|
1199
|
-
if (codec) {
|
|
1200
|
-
if (this.options.direction === "input") return codec.encode(node);
|
|
1201
|
-
return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : codec.decode(node);
|
|
1202
|
-
}
|
|
1203
|
-
return "z.iso.date()";
|
|
1204
|
-
},
|
|
1205
|
-
datetime(node) {
|
|
1206
|
-
const offset = node.offset || this.options.dateType === "stringOffset";
|
|
1207
|
-
const local = node.local || this.options.dateType === "stringLocal";
|
|
1208
|
-
if (offset) return "z.iso.datetime({ offset: true })";
|
|
1209
|
-
if (local) return "z.iso.datetime({ local: true })";
|
|
1210
|
-
return "z.iso.datetime()";
|
|
1211
|
-
},
|
|
1212
|
-
time(node) {
|
|
1213
|
-
if (node.representation === "string") return "z.iso.time()";
|
|
1214
|
-
return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
|
|
1215
|
-
},
|
|
1216
|
-
uuid(node) {
|
|
1217
|
-
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints({
|
|
1218
|
-
...node,
|
|
1219
|
-
regexType: this.options.regexType
|
|
1220
|
-
})}`;
|
|
1221
|
-
},
|
|
1222
|
-
email(node) {
|
|
1223
|
-
return `z.email()${lengthConstraints({
|
|
1224
|
-
...node,
|
|
1225
|
-
regexType: this.options.regexType
|
|
1226
|
-
})}`;
|
|
1227
|
-
},
|
|
1228
|
-
url(node) {
|
|
1229
|
-
return `z.url()${lengthConstraints({
|
|
1230
|
-
...node,
|
|
1231
|
-
regexType: this.options.regexType
|
|
1232
|
-
})}`;
|
|
1233
|
-
},
|
|
1234
|
-
ipv4: () => "z.ipv4()",
|
|
1235
|
-
ipv6: () => "z.ipv6()",
|
|
1236
|
-
blob: () => "z.instanceof(File)",
|
|
1237
|
-
enum(node) {
|
|
1238
|
-
const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
|
|
1239
|
-
if (node.namedEnumValues?.length) {
|
|
1240
|
-
const literals = nonNullValues.map((v) => `z.literal(${formatLiteral(v)})`);
|
|
1241
|
-
if (literals.length === 1) return literals[0];
|
|
1242
|
-
return `z.union([${literals.join(", ")}])`;
|
|
1243
|
-
}
|
|
1244
|
-
return buildEnum(nonNullValues);
|
|
1245
|
-
},
|
|
1273
|
+
...scalarNodes,
|
|
1246
1274
|
ref(node) {
|
|
1247
1275
|
if (!node.name) return null;
|
|
1248
1276
|
const refName = ast.resolveRefName(node);
|
|
1249
1277
|
if (!refName) return null;
|
|
1250
|
-
const useInputVariant = node.ref != null && this.options.direction === "
|
|
1278
|
+
const useInputVariant = node.ref != null && this.options.direction === "encode" && containsDirectionalNode({
|
|
1279
|
+
node,
|
|
1280
|
+
printerOptions: this.options
|
|
1281
|
+
});
|
|
1251
1282
|
const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.schema.inputName(refName) ?? refName : this.options.resolver?.name(refName) ?? refName : node.name;
|
|
1252
1283
|
if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
|
|
1253
1284
|
return resolvedName;
|
|
@@ -1431,7 +1462,7 @@ const printerZodMini = ast.createPrinter((options) => {
|
|
|
1431
1462
|
return `z.int()${numberChecksMini(node)}`;
|
|
1432
1463
|
},
|
|
1433
1464
|
bigint(node) {
|
|
1434
|
-
return `z.bigint()${numberChecksMini(node)}`;
|
|
1465
|
+
return `z.coerce.bigint()${numberChecksMini(node)}`;
|
|
1435
1466
|
},
|
|
1436
1467
|
date(node) {
|
|
1437
1468
|
if (node.representation === "string") return "z.iso.date()";
|
|
@@ -1574,29 +1605,28 @@ const printerZodMini = ast.createPrinter((options) => {
|
|
|
1574
1605
|
const zodPrinterCache = /* @__PURE__ */ new WeakMap();
|
|
1575
1606
|
const zodMiniPrinterCache = /* @__PURE__ */ new WeakMap();
|
|
1576
1607
|
/**
|
|
1577
|
-
*
|
|
1578
|
-
*
|
|
1579
|
-
* `string → Date` for responses. Schemas without `dateType: 'date'` fields print identically.
|
|
1608
|
+
* Cached printer per direction for a resolver, built on first use. Schemas holding nothing that
|
|
1609
|
+
* converts print the same either way.
|
|
1580
1610
|
*/
|
|
1581
1611
|
function getStdPrinters(resolver, params) {
|
|
1582
1612
|
const cached = zodPrinterCache.get(resolver);
|
|
1583
1613
|
if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.regexType === params.regexType && cached.dateType === params.dateType && cached.nodes === params.nodes) return {
|
|
1584
|
-
|
|
1585
|
-
|
|
1614
|
+
decode: cached.decode,
|
|
1615
|
+
encode: cached.encode
|
|
1586
1616
|
};
|
|
1587
|
-
const
|
|
1617
|
+
const decode = printerZod({
|
|
1588
1618
|
...params,
|
|
1589
1619
|
resolver,
|
|
1590
|
-
direction: "
|
|
1620
|
+
direction: "decode"
|
|
1591
1621
|
});
|
|
1592
|
-
const
|
|
1622
|
+
const encode = printerZod({
|
|
1593
1623
|
...params,
|
|
1594
1624
|
resolver,
|
|
1595
|
-
direction: "
|
|
1625
|
+
direction: "encode"
|
|
1596
1626
|
});
|
|
1597
1627
|
zodPrinterCache.set(resolver, {
|
|
1598
|
-
|
|
1599
|
-
|
|
1628
|
+
decode,
|
|
1629
|
+
encode,
|
|
1600
1630
|
coercion: params.coercion,
|
|
1601
1631
|
guidType: params.guidType,
|
|
1602
1632
|
regexType: params.regexType,
|
|
@@ -1604,8 +1634,8 @@ function getStdPrinters(resolver, params) {
|
|
|
1604
1634
|
nodes: params.nodes
|
|
1605
1635
|
});
|
|
1606
1636
|
return {
|
|
1607
|
-
|
|
1608
|
-
|
|
1637
|
+
decode,
|
|
1638
|
+
encode
|
|
1609
1639
|
};
|
|
1610
1640
|
}
|
|
1611
1641
|
function getMiniPrinter(resolver, params) {
|
|
@@ -1639,15 +1669,30 @@ const zodGenerator = defineGenerator({
|
|
|
1639
1669
|
if (!node.name) return;
|
|
1640
1670
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
1641
1671
|
const cyclicSchemas = new Set(ctx.meta.circularNames);
|
|
1642
|
-
const
|
|
1643
|
-
|
|
1672
|
+
const printerOptions = {
|
|
1673
|
+
coercion,
|
|
1674
|
+
guidType,
|
|
1675
|
+
regexType,
|
|
1676
|
+
dateType,
|
|
1677
|
+
resolver,
|
|
1678
|
+
cyclicSchemas,
|
|
1679
|
+
nodes: printer?.nodes
|
|
1680
|
+
};
|
|
1681
|
+
const hasDirectionalNode = !mini && containsDirectionalNode({
|
|
1682
|
+
node,
|
|
1683
|
+
printerOptions
|
|
1684
|
+
});
|
|
1685
|
+
const directionalRefNames = new Set(hasDirectionalNode ? collectDirectionalRefNames({
|
|
1686
|
+
node,
|
|
1687
|
+
printerOptions
|
|
1688
|
+
}) : []);
|
|
1644
1689
|
const importEntries = resolver.imports({
|
|
1645
1690
|
node,
|
|
1646
1691
|
root,
|
|
1647
1692
|
output,
|
|
1648
1693
|
group: group ?? void 0
|
|
1649
1694
|
});
|
|
1650
|
-
const inputImportEntries =
|
|
1695
|
+
const inputImportEntries = hasDirectionalNode ? [...directionalRefNames].map((schemaName) => ({
|
|
1651
1696
|
name: [resolver.schema.inputName(schemaName)],
|
|
1652
1697
|
path: resolver.file({
|
|
1653
1698
|
name: schemaName,
|
|
@@ -1688,7 +1733,7 @@ const zodGenerator = defineGenerator({
|
|
|
1688
1733
|
regexType,
|
|
1689
1734
|
cyclicSchemas,
|
|
1690
1735
|
nodes: printer?.nodes
|
|
1691
|
-
}) : stdPrinters.
|
|
1736
|
+
}) : stdPrinters.decode;
|
|
1692
1737
|
return /* @__PURE__ */ jsxs(File, {
|
|
1693
1738
|
baseName: meta.file.baseName,
|
|
1694
1739
|
path: meta.file.path,
|
|
@@ -1731,10 +1776,10 @@ const zodGenerator = defineGenerator({
|
|
|
1731
1776
|
inferTypeName,
|
|
1732
1777
|
cyclic: cyclicSchemas.has(node.name)
|
|
1733
1778
|
}),
|
|
1734
|
-
|
|
1779
|
+
hasDirectionalNode && stdPrinters && /* @__PURE__ */ jsx(Zod, {
|
|
1735
1780
|
name: resolver.schema.inputName(node.name),
|
|
1736
1781
|
node,
|
|
1737
|
-
printer: stdPrinters.
|
|
1782
|
+
printer: stdPrinters.encode,
|
|
1738
1783
|
inferTypeName: inferred ? resolver.schema.inputTypeName(node.name) : null,
|
|
1739
1784
|
cyclic: cyclicSchemas.has(node.name)
|
|
1740
1785
|
})
|
|
@@ -1757,16 +1802,28 @@ const zodGenerator = defineGenerator({
|
|
|
1757
1802
|
group: group ?? void 0
|
|
1758
1803
|
}) };
|
|
1759
1804
|
const cyclicSchemas = new Set(ctx.meta.circularNames);
|
|
1760
|
-
|
|
1805
|
+
const printerOptions = {
|
|
1806
|
+
coercion,
|
|
1807
|
+
guidType,
|
|
1808
|
+
regexType,
|
|
1809
|
+
dateType,
|
|
1810
|
+
resolver,
|
|
1811
|
+
cyclicSchemas,
|
|
1812
|
+
nodes: printer?.nodes
|
|
1813
|
+
};
|
|
1814
|
+
function renderSchemaEntry({ schema, name, keysToOmit, direction = "decode" }) {
|
|
1761
1815
|
if (!schema) return null;
|
|
1762
1816
|
const inferTypeName = inferred ? resolver.schema.type(name) : null;
|
|
1763
|
-
const
|
|
1817
|
+
const directionalRefNames = direction === "encode" && !mini ? new Set(collectDirectionalRefNames({
|
|
1818
|
+
node: schema,
|
|
1819
|
+
printerOptions
|
|
1820
|
+
})) : null;
|
|
1764
1821
|
const imports = resolver.imports({
|
|
1765
1822
|
node: schema,
|
|
1766
1823
|
root,
|
|
1767
1824
|
output,
|
|
1768
1825
|
group: group ?? void 0,
|
|
1769
|
-
name: (schemaName) =>
|
|
1826
|
+
name: (schemaName) => directionalRefNames?.has(schemaName) ? resolver.schema.inputName(schemaName) : resolver.name(schemaName)
|
|
1770
1827
|
});
|
|
1771
1828
|
const schemaPrinter = mini ? keysToOmit?.length ? printerZodMini({
|
|
1772
1829
|
guidType,
|
|
@@ -1855,7 +1912,7 @@ const zodGenerator = defineGenerator({
|
|
|
1855
1912
|
const paramSchemas = node.parameters.map((param) => renderSchemaEntry({
|
|
1856
1913
|
schema: param.schema,
|
|
1857
1914
|
name: resolver.param.name(node, param),
|
|
1858
|
-
direction: "
|
|
1915
|
+
direction: "encode"
|
|
1859
1916
|
}));
|
|
1860
1917
|
const responseSchemas = node.responses.map((res) => {
|
|
1861
1918
|
const variants = (res.content ?? []).filter((entry) => entry.schema);
|
|
@@ -1893,13 +1950,13 @@ const zodGenerator = defineGenerator({
|
|
|
1893
1950
|
},
|
|
1894
1951
|
name: resolver.response.body(node),
|
|
1895
1952
|
keysToOmit: entry.keysToOmit,
|
|
1896
|
-
direction: "
|
|
1953
|
+
direction: "encode"
|
|
1897
1954
|
});
|
|
1898
1955
|
}
|
|
1899
1956
|
return buildContentTypeVariants(requestBodyContent, resolver.response.body(node), (schema) => ({
|
|
1900
1957
|
...schema,
|
|
1901
1958
|
description: node.requestBody.description ?? schema.description
|
|
1902
|
-
}), "
|
|
1959
|
+
}), "encode");
|
|
1903
1960
|
})();
|
|
1904
1961
|
const { path, query, header } = getOperationParameters(node);
|
|
1905
1962
|
const paramGroupSchemas = inferred ? [
|
|
@@ -1918,12 +1975,12 @@ const zodGenerator = defineGenerator({
|
|
|
1918
1975
|
].filter(({ params }) => params.length > 0).map(({ kind, params }) => renderSchemaEntry({
|
|
1919
1976
|
schema: buildGroupedParamsSchema({ params }),
|
|
1920
1977
|
name: resolver.param[kind](node, params[0]),
|
|
1921
|
-
direction: "
|
|
1978
|
+
direction: "encode"
|
|
1922
1979
|
})) : [];
|
|
1923
1980
|
const optionsSchema = inferred ? renderSchemaEntry({
|
|
1924
1981
|
schema: buildOptionsSchema(node, resolver),
|
|
1925
1982
|
name: resolver.name(`${node.operationId} Options`),
|
|
1926
|
-
direction: "
|
|
1983
|
+
direction: "encode"
|
|
1927
1984
|
}) : null;
|
|
1928
1985
|
const responsesSchema = inferred ? renderSchemaEntry({
|
|
1929
1986
|
schema: buildResponses(node, resolver),
|