zod-nest 1.7.1 → 1.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.d.mts CHANGED
@@ -496,6 +496,15 @@ interface ZodBodyOptions {
496
496
  readonly description?: string;
497
497
  /** Whether the body is required. Defaults to `true`. */
498
498
  readonly required?: boolean;
499
+ /**
500
+ * Merge an intersection of `z.object` arms into a single flat object body
501
+ * emitted inline (no `$ref`, no `components.schemas` entry). Use when
502
+ * Swagger UI's `multipart/form-data` `try-it-out` form needs to render the
503
+ * body — the UI doesn't follow `$ref` or unwrap `allOf`. Throws
504
+ * `ZodNestError` if the schema isn't an object or an intersection of
505
+ * objects. No-op for a bare `z.object`. Defaults to `false`.
506
+ */
507
+ readonly flatten?: boolean;
499
508
  }
500
509
  /**
501
510
  * Method-level decorator that wires the OpenAPI `requestBody` for a handler
package/dist/index.d.ts CHANGED
@@ -496,6 +496,15 @@ interface ZodBodyOptions {
496
496
  readonly description?: string;
497
497
  /** Whether the body is required. Defaults to `true`. */
498
498
  readonly required?: boolean;
499
+ /**
500
+ * Merge an intersection of `z.object` arms into a single flat object body
501
+ * emitted inline (no `$ref`, no `components.schemas` entry). Use when
502
+ * Swagger UI's `multipart/form-data` `try-it-out` form needs to render the
503
+ * body — the UI doesn't follow `$ref` or unwrap `allOf`. Throws
504
+ * `ZodNestError` if the schema isn't an object or an intersection of
505
+ * objects. No-op for a bare `z.object`. Defaults to `false`.
506
+ */
507
+ readonly flatten?: boolean;
499
508
  }
500
509
  /**
501
510
  * Method-level decorator that wires the OpenAPI `requestBody` for a handler
package/dist/index.js CHANGED
@@ -1157,22 +1157,6 @@ var resolveSchemaRef = /* @__PURE__ */ __name((schema, options) => {
1157
1157
  };
1158
1158
  }, "resolveSchemaRef");
1159
1159
 
1160
- // src/decorators/zod-body.decorator.ts
1161
- var ZodBody = /* @__PURE__ */ __name((schema, options) => {
1162
- const resolution = resolveSchemaRef(schema, {
1163
- id: options?.id,
1164
- registry: options?.registry
1165
- });
1166
- const apiBodySchema = resolution.kind === "ref" ? resolution.ref : resolution.schema;
1167
- return swagger.ApiBody({
1168
- schema: apiBodySchema,
1169
- ...options?.description !== void 0 ? {
1170
- description: options.description
1171
- } : {},
1172
- required: options?.required ?? true
1173
- });
1174
- }, "ZodBody");
1175
-
1176
1160
  // src/decorators/internal/zod-param-expand.ts
1177
1161
  var isZodObject = /* @__PURE__ */ __name((schema) => schema._zod.def.type === "object", "isZodObject");
1178
1162
  var expandObjectSchema = /* @__PURE__ */ __name((schema, options) => {
@@ -1199,7 +1183,117 @@ var expandObjectSchema = /* @__PURE__ */ __name((schema, options) => {
1199
1183
  }, "expandObjectSchema");
1200
1184
  var paramSchemaBody = /* @__PURE__ */ __name((resolution) => resolution.kind === "ref" ? resolution.ref : resolution.schema, "paramSchemaBody");
1201
1185
 
1202
- // src/decorators/zod-query.decorator.ts
1186
+ // src/decorators/internal/flatten-intersection.ts
1187
+ var intersectionArms = /* @__PURE__ */ __name((schema) => {
1188
+ if (schema._zod.def.type !== "intersection") {
1189
+ return null;
1190
+ }
1191
+ const def = schema._zod.def;
1192
+ return {
1193
+ left: def.left,
1194
+ right: def.right
1195
+ };
1196
+ }, "intersectionArms");
1197
+ var unionOptions = /* @__PURE__ */ __name((schema) => {
1198
+ if (schema._zod.def.type !== "union") {
1199
+ return null;
1200
+ }
1201
+ const def = schema._zod.def;
1202
+ return def.options;
1203
+ }, "unionOptions");
1204
+ var collectObjectShapes = /* @__PURE__ */ __name((schema) => {
1205
+ if (isZodObject(schema)) {
1206
+ return {
1207
+ shapes: [
1208
+ schema.shape
1209
+ ],
1210
+ unionCrossed: false
1211
+ };
1212
+ }
1213
+ const options = unionOptions(schema);
1214
+ if (options !== null) {
1215
+ const allShapes = [];
1216
+ for (const variant of options) {
1217
+ const variantResult = collectObjectShapes(variant);
1218
+ if (variantResult === null) {
1219
+ return null;
1220
+ }
1221
+ allShapes.push(...variantResult.shapes);
1222
+ }
1223
+ return {
1224
+ shapes: allShapes,
1225
+ unionCrossed: true
1226
+ };
1227
+ }
1228
+ const arms = intersectionArms(schema);
1229
+ if (arms === null) {
1230
+ return null;
1231
+ }
1232
+ const left = collectObjectShapes(arms.left);
1233
+ if (left === null) {
1234
+ return null;
1235
+ }
1236
+ const right = collectObjectShapes(arms.right);
1237
+ if (right === null) {
1238
+ return null;
1239
+ }
1240
+ return {
1241
+ shapes: [
1242
+ ...left.shapes,
1243
+ ...right.shapes
1244
+ ],
1245
+ unionCrossed: left.unionCrossed || right.unionCrossed
1246
+ };
1247
+ }, "collectObjectShapes");
1248
+ var flattenObjectIntersection = /* @__PURE__ */ __name((schema, registry, decoratorName) => {
1249
+ const collected = collectObjectShapes(schema);
1250
+ if (collected === null) {
1251
+ throw new ZodNestError(`${decoratorName} \`flatten: true\` requires every leaf of the schema to be a \`z.object({...})\` \u2014 intersections and unions of objects are supported, but primitives, tuples, transforms, and other non-object leaves are not. Drop \`flatten: true\` to emit the original schema with its composition intact.`);
1252
+ }
1253
+ const mergedShape = {};
1254
+ for (const shape of collected.shapes) {
1255
+ Object.assign(mergedShape, shape);
1256
+ }
1257
+ if (collected.unionCrossed) {
1258
+ for (const key of Object.keys(mergedShape)) {
1259
+ const value = mergedShape[key];
1260
+ if (value !== void 0) {
1261
+ mergedShape[key] = value.optional();
1262
+ }
1263
+ }
1264
+ }
1265
+ const merged = zod.z.object(mergedShape);
1266
+ for (const [child, childId] of discoverDependents(schema)) {
1267
+ registry.register(child, childId);
1268
+ }
1269
+ const { schema: body } = toOpenApi(merged, {
1270
+ io: "input",
1271
+ registry
1272
+ });
1273
+ return body;
1274
+ }, "flattenObjectIntersection");
1275
+
1276
+ // src/decorators/zod-body.decorator.ts
1277
+ var ZodBody = /* @__PURE__ */ __name((schema, options) => {
1278
+ const apiBodySchema = resolveBodySchema(schema, options);
1279
+ return swagger.ApiBody({
1280
+ schema: apiBodySchema,
1281
+ ...options?.description !== void 0 ? {
1282
+ description: options.description
1283
+ } : {},
1284
+ required: options?.required ?? true
1285
+ });
1286
+ }, "ZodBody");
1287
+ var resolveBodySchema = /* @__PURE__ */ __name((schema, options) => {
1288
+ if (options?.flatten === true) {
1289
+ return flattenObjectIntersection(schema, options.registry ?? defaultRegistry, "@ZodBody");
1290
+ }
1291
+ const resolution = resolveSchemaRef(schema, {
1292
+ id: options?.id,
1293
+ registry: options?.registry
1294
+ });
1295
+ return resolution.kind === "ref" ? resolution.ref : resolution.schema;
1296
+ }, "resolveBodySchema");
1203
1297
  var ZodQuery = /* @__PURE__ */ __name((schema, options) => {
1204
1298
  const expanded = expandObjectSchema(schema, {
1205
1299
  id: options?.id,
@@ -1458,6 +1552,31 @@ var forEachOperation = /* @__PURE__ */ __name((doc, fn) => {
1458
1552
  }
1459
1553
  }, "forEachOperation");
1460
1554
 
1555
+ // src/document/walk-refs.ts
1556
+ var walkRefs = /* @__PURE__ */ __name((node, visit) => {
1557
+ if (node === null || typeof node !== "object") {
1558
+ return;
1559
+ }
1560
+ if (Array.isArray(node)) {
1561
+ for (const item of node) {
1562
+ walkRefs(item, visit);
1563
+ }
1564
+ return;
1565
+ }
1566
+ const obj = node;
1567
+ for (const key of Object.keys(obj)) {
1568
+ const value = obj[key];
1569
+ if (key === "$ref" && typeof value === "string") {
1570
+ const next = visit(value);
1571
+ if (next !== void 0) {
1572
+ obj[key] = next;
1573
+ }
1574
+ continue;
1575
+ }
1576
+ walkRefs(value, visit);
1577
+ }
1578
+ }, "walkRefs");
1579
+
1461
1580
  // src/document/collect-usage.ts
1462
1581
  var isPlainRecord2 = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isPlainRecord");
1463
1582
  var collectUsage = /* @__PURE__ */ __name((doc, app, registry) => {
@@ -1561,19 +1680,19 @@ var collectRefFromSchema = /* @__PURE__ */ __name((schema, classToDtoId, knownId
1561
1680
  if (!isPlainRecord2(schema)) {
1562
1681
  return;
1563
1682
  }
1564
- const ref = schema.$ref;
1565
- if (typeof ref !== "string" || !ref.startsWith(COMPONENTS_SCHEMAS_PREFIX)) {
1566
- return;
1567
- }
1568
- const className = ref.slice(COMPONENTS_SCHEMAS_PREFIX.length);
1569
- const renamed = classToDtoId.get(className);
1570
- if (renamed !== void 0) {
1571
- ids.add(renamed);
1572
- return;
1573
- }
1574
- if (knownIds.has(className)) {
1575
- ids.add(className);
1576
- }
1683
+ walkRefs(schema, (ref) => {
1684
+ if (!ref.startsWith(COMPONENTS_SCHEMAS_PREFIX)) {
1685
+ return void 0;
1686
+ }
1687
+ const className = ref.slice(COMPONENTS_SCHEMAS_PREFIX.length);
1688
+ const renamed = classToDtoId.get(className);
1689
+ if (renamed !== void 0) {
1690
+ ids.add(renamed);
1691
+ } else if (knownIds.has(className)) {
1692
+ ids.add(className);
1693
+ }
1694
+ return void 0;
1695
+ });
1577
1696
  }, "collectRefFromSchema");
1578
1697
  var collectOutputExposedIds = /* @__PURE__ */ __name((app) => {
1579
1698
  const ids = /* @__PURE__ */ new Set();
@@ -1635,31 +1754,6 @@ var ZodNestDocumentError = class extends ZodNestError {
1635
1754
  }
1636
1755
  };
1637
1756
 
1638
- // src/document/walk-refs.ts
1639
- var walkRefs = /* @__PURE__ */ __name((node, visit) => {
1640
- if (node === null || typeof node !== "object") {
1641
- return;
1642
- }
1643
- if (Array.isArray(node)) {
1644
- for (const item of node) {
1645
- walkRefs(item, visit);
1646
- }
1647
- return;
1648
- }
1649
- const obj = node;
1650
- for (const key of Object.keys(obj)) {
1651
- const value = obj[key];
1652
- if (key === "$ref" && typeof value === "string") {
1653
- const next = visit(value);
1654
- if (next !== void 0) {
1655
- obj[key] = next;
1656
- }
1657
- continue;
1658
- }
1659
- walkRefs(value, visit);
1660
- }
1661
- }, "walkRefs");
1662
-
1663
1757
  // src/document/dangling-refs.ts
1664
1758
  var assertNoDanglingRefs = /* @__PURE__ */ __name((params) => {
1665
1759
  const { doc, collected } = params;