@kubb/plugin-zod 5.8.0 → 5.8.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.js CHANGED
@@ -1259,6 +1259,37 @@ function printWithOmit(ctx, node, modify, mini = false) {
1259
1259
  }
1260
1260
  // src/printers/zodNodes.ts
1261
1261
  /**
1262
+ * Reads a union of bare single-value enums as one enum, except under `xor` or an enum override, which need each member.
1263
+ * Only a numeric union with a `format` coerces, because it printed as `z.coerce.number()` before the adapter kept its values.
1264
+ */
1265
+ function getLiteralUnion({ node, options }) {
1266
+ if (node.strategy === "one" && options.oneOfType === "xor" || options.nodes?.enum) return void 0;
1267
+ const values = (node.members ?? []).map((member) => {
1268
+ const enumNode = ast.narrowSchema(member, ast.schemaTypes.enum);
1269
+ return enumNode && !enumNode.name && !enumNode.nullable && !enumNode.namedEnumValues && enumNode.enumValues?.length === 1 ? enumNode.enumValues[0] : void 0;
1270
+ });
1271
+ if (!values.length || !values.every((value) => value !== void 0 && value !== null)) return void 0;
1272
+ return {
1273
+ values,
1274
+ coerce: !!node.format && values.every((value) => typeof value === "number") && shouldCoerce(options.coercion, "numbers")
1275
+ };
1276
+ }
1277
+ /**
1278
+ * Whether a discriminated union member's discriminator property prints as a coerced literal union.
1279
+ */
1280
+ function hasCoercedDiscriminator({ member, propertyName, options }) {
1281
+ return ast.resolveSchemaProperties({
1282
+ node: member,
1283
+ propertyName
1284
+ }).some(({ schema }) => {
1285
+ const resolved = syncSchemaRef(schema);
1286
+ return resolved.type === "union" && !!getLiteralUnion({
1287
+ node: resolved,
1288
+ options
1289
+ })?.coerce;
1290
+ });
1291
+ }
1292
+ /**
1262
1293
  * Builds the scalar handlers both dialects share. They never recurse into children. The temporal
1263
1294
  * scalars and `bigint` differ per dialect, so each printer adds its own.
1264
1295
  */
@@ -1397,8 +1428,21 @@ function buildZodNodes(dialect, cyclicSchemas) {
1397
1428
  return `z.tuple(${buildList(mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
1398
1429
  },
1399
1430
  union(node) {
1431
+ const literalUnion = getLiteralUnion({
1432
+ node,
1433
+ options: this.options
1434
+ });
1435
+ if (literalUnion) {
1436
+ const schema = buildEnum(literalUnion.values);
1437
+ return literalUnion.coerce ? dialect.coercedNumber(schema) : schema;
1438
+ }
1400
1439
  const nodeMembers = node.members ?? [];
1401
- const isDiscriminated = !!node.discriminatorPropertyName && nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemas));
1440
+ const { discriminatorPropertyName } = node;
1441
+ const isDiscriminated = !!discriminatorPropertyName && nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemas)) && !nodeMembers.some((m) => hasCoercedDiscriminator({
1442
+ member: m,
1443
+ propertyName: discriminatorPropertyName,
1444
+ options: this.options
1445
+ }));
1402
1446
  const isXor = node.strategy === "one" && !isDiscriminated && this.options.oneOfType === "xor";
1403
1447
  const isStrict = node.strategy === "one" && !isXor && !unionsWithSiblings.has(node);
1404
1448
  const members = mapSchemaMembers(node, (memberNode) => this.transform(isStrict ? strictOneOfNode(memberNode) : memberNode)).map(({ schema, output }) => output && isStrict && dialect.strictMember ? dialect.strictMember(output, schema, cyclicSchemas) : output).filter(Boolean);
@@ -1584,6 +1628,7 @@ const standardDialect = {
1584
1628
  patternKey: patternKeySchema,
1585
1629
  objectShape: buildZodObjectShape,
1586
1630
  coercedInt: "z.coerce.number().int()",
1631
+ coercedNumber: (schema) => `z.coerce.number().pipe(${schema})`,
1587
1632
  catchall: (object, value) => `${object}.catchall(${value})`,
1588
1633
  nullable: (value) => `${value}.nullable()`,
1589
1634
  unique: (array) => `${array}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`,
@@ -1692,6 +1737,7 @@ const miniDialect = {
1692
1737
  patternKey: patternKeySchemaMini,
1693
1738
  objectShape: buildZodMiniObjectShape,
1694
1739
  coercedInt: "z.coerce.number().check(z.int())",
1740
+ coercedNumber: (schema) => `z.pipe(z.coerce.number(), ${schema})`,
1695
1741
  catchall: (object, value) => `z.catchall(${object}, ${value})`,
1696
1742
  nullable: (value) => `z.nullable(${value})`,
1697
1743
  unique: (array) => `${array}.check(z.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" }))`,
@@ -2122,7 +2168,7 @@ var compatibility = {
2122
2168
  "node": ">=22.22"
2123
2169
  };
2124
2170
  // package.json
2125
- var version = "5.8.0";
2171
+ var version = "5.8.1";
2126
2172
  // src/resolvers/resolverZod.ts
2127
2173
  /**
2128
2174
  * Default resolver used by `@kubb/plugin-zod`. Decides the names and file