zod-nest 3.6.0 → 3.7.0
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.d.mts +31 -26
- package/dist/index.d.ts +31 -26
- package/dist/index.js +153 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +153 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ A short list of behavioural differences you'll hit on day one. Full migration ta
|
|
|
42
42
|
- **Multi-status `@ZodResponse`** — stack the decorator per status code. In `nestjs-zod`, multi-status required mixing `@ZodSerializerDto` with hand-rolled `@ApiResponse({ status: ... })` calls.
|
|
43
43
|
- **No internal `@HttpCode`** — `@ZodResponse` does **not** call `@HttpCode` under the hood. Status resolution precedence: `@ZodResponse({ status })` → `@HttpCode(...)` on the handler → method default (`POST → 201`, others → `200`). The caller controls `201` vs `200` vs `204` via standard NestJS decorators. `status` accepts numeric codes plus the OpenAPI 3.1 range keys (`'1XX'`…`'5XX'`) and `'default'` (sugar for the resolved method default).
|
|
44
44
|
- **I/O suffix only when needed** — `<Id>Output` is only emitted when the input and output JSON Schemas actually differ. `nestjs-zod` always emitted `_Output`.
|
|
45
|
-
- **OpenAPI 3.1 and 3.2** — no `3.0` fallback. Pick with `DocumentBuilder.setOpenAPIVersion('3.2.0')`; 3.2 is what makes `QUERY` and WebDAV routes conformant,
|
|
45
|
+
- **OpenAPI 3.1 and 3.2** — no `3.0` fallback. Pick with `DocumentBuilder.setOpenAPIVersion('3.2.0')`; 3.2 is what makes `QUERY` and WebDAV routes conformant, what lets a streamed response say `itemSchema` instead of overstating the whole body, what emits Response Object `summary`, and what collapses a named query DTO to `in: querystring`. `$ref`s emit to the final location; `cleanupOpenApiDoc` is unnecessary.
|
|
46
46
|
- **Validation-failure logging out of the box** — `nestjs-zod` has none.
|
|
47
47
|
- **Customizable serialization exception** — both `ZodValidationPipe` and `ZodSerializerInterceptor` accept a factory. `nestjs-zod` only customized the input side.
|
|
48
48
|
- **DTO discriminator** — `Symbol.for('zod-nest.dto')` (cross-realm safe), not `MyDto.isZodDto`.
|
|
@@ -186,7 +186,7 @@ The decorator set: `@ZodBody`, `@ZodQuery`, `@ZodHeaders`, `@ZodCookies`. All ar
|
|
|
186
186
|
|
|
187
187
|
See [`docs/recipes/intersection-with-union.md`](docs/recipes/intersection-with-union.md) for the full pattern.
|
|
188
188
|
|
|
189
|
-
Named query objects (both `@Query() dto` and `@ZodQuery`)
|
|
189
|
+
Named query objects (both `@Query() dto` and `@ZodQuery`) collapse to a single `in: querystring` parameter under OpenAPI 3.2 — the field 3.2 added for exactly this — and expand to one parameter per field under 3.1. Nothing changes on the wire either way. The deprecated `queryParamStyle` / `@ZodQuery({ ref })` flags override the default; see [`docs/swagger-integration.md → Query parameter style`](docs/swagger-integration.md#query-parameter-style).
|
|
190
190
|
|
|
191
191
|
### I/O suffix rules
|
|
192
192
|
|
package/dist/index.d.mts
CHANGED
|
@@ -603,16 +603,19 @@ interface ZodQueryOptions {
|
|
|
603
603
|
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
604
604
|
readonly registry?: ZodNestRegistry;
|
|
605
605
|
/**
|
|
606
|
-
* Override how this query DTO is represented
|
|
607
|
-
*
|
|
606
|
+
* Override how this query DTO is represented, taking precedence over
|
|
607
|
+
* `applyZodNest`'s `queryParamStyle` and the target version:
|
|
608
608
|
*
|
|
609
|
-
* - `true` —
|
|
610
|
-
* `
|
|
609
|
+
* - `true` — collapse to one parameter carrying the whole schema
|
|
610
|
+
* (`in: 'querystring'` under 3.2, `style: 'form'` under 3.1).
|
|
611
611
|
* - `false` — one parameter per top-level property.
|
|
612
|
-
* - unset — follow
|
|
612
|
+
* - unset — follow `queryParamStyle`, then the version (3.2 collapses).
|
|
613
613
|
*
|
|
614
|
-
*
|
|
614
|
+
* Collapsing needs a named schema to reference: `ref: true` on an anonymous
|
|
615
615
|
* schema (no `.meta({ id })` and no `id` option) throws `ZodNestError`.
|
|
616
|
+
*
|
|
617
|
+
* @deprecated Removed in the next major, where 3.1 always expands and 3.2
|
|
618
|
+
* always collapses. Under 3.2 an explicit value warns.
|
|
616
619
|
*/
|
|
617
620
|
readonly ref?: boolean;
|
|
618
621
|
}
|
|
@@ -731,15 +734,14 @@ declare class ZodNestModule {
|
|
|
731
734
|
/**
|
|
732
735
|
* How a named `@Query()` / `@ZodQuery` DTO is represented in the OpenAPI doc:
|
|
733
736
|
*
|
|
734
|
-
* - `'expand'`
|
|
735
|
-
*
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
* document representation collapses to the shared component.
|
|
737
|
+
* - `'expand'` — one parameter per top-level property of the DTO schema.
|
|
738
|
+
* - `'ref'` — collapse to a single parameter carrying the whole schema.
|
|
739
|
+
*
|
|
740
|
+
* Query-only: path / header / cookie markers always expand, since collapsing
|
|
741
|
+
* an object into one parameter is a query serialization.
|
|
740
742
|
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
+
* @deprecated Removed in the next major. 3.2 collapses named query DTOs to
|
|
744
|
+
* `in: 'querystring'` by default, which is what this option approximated.
|
|
743
745
|
*/
|
|
744
746
|
type QueryParamStyle = 'expand' | 'ref';
|
|
745
747
|
|
|
@@ -759,17 +761,17 @@ interface ApplyZodNestOptions {
|
|
|
759
761
|
*/
|
|
760
762
|
strict?: boolean;
|
|
761
763
|
/**
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
+
* Overrides the version-derived default for named `@Query()` / `@ZodQuery`
|
|
765
|
+
* DTOs: `'expand'` for one parameter per property, `'ref'` to collapse to a
|
|
766
|
+
* single parameter carrying the whole schema.
|
|
764
767
|
*
|
|
765
|
-
*
|
|
766
|
-
* -
|
|
767
|
-
*
|
|
768
|
-
* format is unchanged; only the spec representation collapses to the
|
|
769
|
-
* shared component. Note: Swagger UI renders the two forms differently.
|
|
768
|
+
* Left unset, 3.2 collapses (as `in: 'querystring'`) and 3.1 expands.
|
|
769
|
+
* Query-only — path / header / cookie DTOs always expand — and a per-handler
|
|
770
|
+
* `@ZodQuery({ ref })` takes precedence.
|
|
770
771
|
*
|
|
771
|
-
*
|
|
772
|
-
*
|
|
772
|
+
* @deprecated Removed in the next major, where 3.1 always expands and 3.2
|
|
773
|
+
* always collapses. This option existed because 3.1 could not express a
|
|
774
|
+
* whole-query-string schema; 3.2's `querystring` can.
|
|
773
775
|
*/
|
|
774
776
|
queryParamStyle?: QueryParamStyle;
|
|
775
777
|
/**
|
|
@@ -795,9 +797,9 @@ interface ApplyZodNestOptions {
|
|
|
795
797
|
* keyed by the marker's `dtoId` (renaming as needed).
|
|
796
798
|
* - Every `@Query()` / `@Param()` / `@Headers()` / `@Cookie()` marker
|
|
797
799
|
* parameter is expanded into one parameter per top-level property of the
|
|
798
|
-
* DTO's schema (`expandParamMarkers`) — except `@Query()` DTOs under
|
|
799
|
-
*
|
|
800
|
-
*
|
|
800
|
+
* DTO's schema (`expandParamMarkers`) — except named `@Query()` DTOs under
|
|
801
|
+
* 3.2, which collapse to a single `in: 'querystring'` parameter, and their
|
|
802
|
+
* 3.1 equivalent under `queryParamStyle: 'ref'`. The synthetic
|
|
801
803
|
* `components.schemas.Object` that `@nestjs/swagger` materialises for the
|
|
802
804
|
* marker placeholder is pruned when it has no remaining referrers.
|
|
803
805
|
* - The I/O suffix truth table is applied — equal input/output bodies collapse
|
|
@@ -822,6 +824,9 @@ interface ApplyZodNestOptions {
|
|
|
822
824
|
* so a streamed body documents one item rather than the whole sequence.
|
|
823
825
|
* - Response Object `summary` survives only under 3.2; emitting 3.1 drops each
|
|
824
826
|
* one with a warning naming the operation, since 3.1 forbids the field.
|
|
827
|
+
* - Under 3.2 a named query DTO collapses to `in: 'querystring'`, degrading to
|
|
828
|
+
* per-property expansion (with a warning) where that version's coexistence
|
|
829
|
+
* rules forbid it — a sibling `in: 'query'` parameter, or a second candidate.
|
|
825
830
|
*
|
|
826
831
|
* Composable with other doc-transform passes — apply other mutations before
|
|
827
832
|
* or after this function.
|
package/dist/index.d.ts
CHANGED
|
@@ -603,16 +603,19 @@ interface ZodQueryOptions {
|
|
|
603
603
|
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
604
604
|
readonly registry?: ZodNestRegistry;
|
|
605
605
|
/**
|
|
606
|
-
* Override how this query DTO is represented
|
|
607
|
-
*
|
|
606
|
+
* Override how this query DTO is represented, taking precedence over
|
|
607
|
+
* `applyZodNest`'s `queryParamStyle` and the target version:
|
|
608
608
|
*
|
|
609
|
-
* - `true` —
|
|
610
|
-
* `
|
|
609
|
+
* - `true` — collapse to one parameter carrying the whole schema
|
|
610
|
+
* (`in: 'querystring'` under 3.2, `style: 'form'` under 3.1).
|
|
611
611
|
* - `false` — one parameter per top-level property.
|
|
612
|
-
* - unset — follow
|
|
612
|
+
* - unset — follow `queryParamStyle`, then the version (3.2 collapses).
|
|
613
613
|
*
|
|
614
|
-
*
|
|
614
|
+
* Collapsing needs a named schema to reference: `ref: true` on an anonymous
|
|
615
615
|
* schema (no `.meta({ id })` and no `id` option) throws `ZodNestError`.
|
|
616
|
+
*
|
|
617
|
+
* @deprecated Removed in the next major, where 3.1 always expands and 3.2
|
|
618
|
+
* always collapses. Under 3.2 an explicit value warns.
|
|
616
619
|
*/
|
|
617
620
|
readonly ref?: boolean;
|
|
618
621
|
}
|
|
@@ -731,15 +734,14 @@ declare class ZodNestModule {
|
|
|
731
734
|
/**
|
|
732
735
|
* How a named `@Query()` / `@ZodQuery` DTO is represented in the OpenAPI doc:
|
|
733
736
|
*
|
|
734
|
-
* - `'expand'`
|
|
735
|
-
*
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
* document representation collapses to the shared component.
|
|
737
|
+
* - `'expand'` — one parameter per top-level property of the DTO schema.
|
|
738
|
+
* - `'ref'` — collapse to a single parameter carrying the whole schema.
|
|
739
|
+
*
|
|
740
|
+
* Query-only: path / header / cookie markers always expand, since collapsing
|
|
741
|
+
* an object into one parameter is a query serialization.
|
|
740
742
|
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
+
* @deprecated Removed in the next major. 3.2 collapses named query DTOs to
|
|
744
|
+
* `in: 'querystring'` by default, which is what this option approximated.
|
|
743
745
|
*/
|
|
744
746
|
type QueryParamStyle = 'expand' | 'ref';
|
|
745
747
|
|
|
@@ -759,17 +761,17 @@ interface ApplyZodNestOptions {
|
|
|
759
761
|
*/
|
|
760
762
|
strict?: boolean;
|
|
761
763
|
/**
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
+
* Overrides the version-derived default for named `@Query()` / `@ZodQuery`
|
|
765
|
+
* DTOs: `'expand'` for one parameter per property, `'ref'` to collapse to a
|
|
766
|
+
* single parameter carrying the whole schema.
|
|
764
767
|
*
|
|
765
|
-
*
|
|
766
|
-
* -
|
|
767
|
-
*
|
|
768
|
-
* format is unchanged; only the spec representation collapses to the
|
|
769
|
-
* shared component. Note: Swagger UI renders the two forms differently.
|
|
768
|
+
* Left unset, 3.2 collapses (as `in: 'querystring'`) and 3.1 expands.
|
|
769
|
+
* Query-only — path / header / cookie DTOs always expand — and a per-handler
|
|
770
|
+
* `@ZodQuery({ ref })` takes precedence.
|
|
770
771
|
*
|
|
771
|
-
*
|
|
772
|
-
*
|
|
772
|
+
* @deprecated Removed in the next major, where 3.1 always expands and 3.2
|
|
773
|
+
* always collapses. This option existed because 3.1 could not express a
|
|
774
|
+
* whole-query-string schema; 3.2's `querystring` can.
|
|
773
775
|
*/
|
|
774
776
|
queryParamStyle?: QueryParamStyle;
|
|
775
777
|
/**
|
|
@@ -795,9 +797,9 @@ interface ApplyZodNestOptions {
|
|
|
795
797
|
* keyed by the marker's `dtoId` (renaming as needed).
|
|
796
798
|
* - Every `@Query()` / `@Param()` / `@Headers()` / `@Cookie()` marker
|
|
797
799
|
* parameter is expanded into one parameter per top-level property of the
|
|
798
|
-
* DTO's schema (`expandParamMarkers`) — except `@Query()` DTOs under
|
|
799
|
-
*
|
|
800
|
-
*
|
|
800
|
+
* DTO's schema (`expandParamMarkers`) — except named `@Query()` DTOs under
|
|
801
|
+
* 3.2, which collapse to a single `in: 'querystring'` parameter, and their
|
|
802
|
+
* 3.1 equivalent under `queryParamStyle: 'ref'`. The synthetic
|
|
801
803
|
* `components.schemas.Object` that `@nestjs/swagger` materialises for the
|
|
802
804
|
* marker placeholder is pruned when it has no remaining referrers.
|
|
803
805
|
* - The I/O suffix truth table is applied — equal input/output bodies collapse
|
|
@@ -822,6 +824,9 @@ interface ApplyZodNestOptions {
|
|
|
822
824
|
* so a streamed body documents one item rather than the whole sequence.
|
|
823
825
|
* - Response Object `summary` survives only under 3.2; emitting 3.1 drops each
|
|
824
826
|
* one with a warning naming the operation, since 3.1 forbids the field.
|
|
827
|
+
* - Under 3.2 a named query DTO collapses to `in: 'querystring'`, degrading to
|
|
828
|
+
* per-property expansion (with a warning) where that version's coexistence
|
|
829
|
+
* rules forbid it — a sibling `in: 'query'` parameter, or a second candidate.
|
|
825
830
|
*
|
|
826
831
|
* Composable with other doc-transform passes — apply other mutations before
|
|
827
832
|
* or after this function.
|
package/dist/index.js
CHANGED
|
@@ -1430,35 +1430,104 @@ var hintFor = /* @__PURE__ */ chunkEV5I5HGT_js.__name((ref, collected) => {
|
|
|
1430
1430
|
return "no DTO with this id was registered \u2014 check for a meta.id typo or a DTO used without createZodDto";
|
|
1431
1431
|
}, "hintFor");
|
|
1432
1432
|
|
|
1433
|
-
// src/document/
|
|
1433
|
+
// src/document/querystring-param.ts
|
|
1434
|
+
var QUERYSTRING_MEDIA_TYPE = "application/x-www-form-urlencoded";
|
|
1434
1435
|
var isPlainRecord3 = /* @__PURE__ */ chunkEV5I5HGT_js.__name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isPlainRecord");
|
|
1436
|
+
var buildQuerystringParam = /* @__PURE__ */ chunkEV5I5HGT_js.__name((params) => {
|
|
1437
|
+
const { dtoId, body } = params;
|
|
1438
|
+
const required = isPlainRecord3(body) && Array.isArray(body.required) && body.required.length > 0;
|
|
1439
|
+
return {
|
|
1440
|
+
name: dtoId,
|
|
1441
|
+
in: "querystring",
|
|
1442
|
+
required,
|
|
1443
|
+
content: {
|
|
1444
|
+
[QUERYSTRING_MEDIA_TYPE]: {
|
|
1445
|
+
schema: {
|
|
1446
|
+
$ref: `${chunkJ2MGUXBB_js.COMPONENTS_SCHEMAS_PREFIX}${dtoId}`
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
}, "buildQuerystringParam");
|
|
1452
|
+
var hasQueryConflict = /* @__PURE__ */ chunkEV5I5HGT_js.__name((params) => {
|
|
1453
|
+
const { parameters, pathItemParameters, candidateCount } = params;
|
|
1454
|
+
if (candidateCount > 1) {
|
|
1455
|
+
return true;
|
|
1456
|
+
}
|
|
1457
|
+
return containsQueryParam(parameters) || containsQueryParam(pathItemParameters);
|
|
1458
|
+
}, "hasQueryConflict");
|
|
1459
|
+
var conflictingQueryNames = /* @__PURE__ */ chunkEV5I5HGT_js.__name((parameters, pathItemParameters) => [
|
|
1460
|
+
...queryNamesOf(parameters),
|
|
1461
|
+
...queryNamesOf(pathItemParameters)
|
|
1462
|
+
], "conflictingQueryNames");
|
|
1463
|
+
var containsQueryParam = /* @__PURE__ */ chunkEV5I5HGT_js.__name((parameters) => Array.isArray(parameters) && parameters.some(isPlainQueryParam), "containsQueryParam");
|
|
1464
|
+
var queryNamesOf = /* @__PURE__ */ chunkEV5I5HGT_js.__name((parameters) => {
|
|
1465
|
+
if (!Array.isArray(parameters)) {
|
|
1466
|
+
return [];
|
|
1467
|
+
}
|
|
1468
|
+
const names = [];
|
|
1469
|
+
for (const param of parameters) {
|
|
1470
|
+
if (!isPlainQueryParam(param)) {
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
names.push(typeof param.name === "string" ? param.name : "<unnamed>");
|
|
1474
|
+
}
|
|
1475
|
+
return names;
|
|
1476
|
+
}, "queryNamesOf");
|
|
1477
|
+
var isPlainQueryParam = /* @__PURE__ */ chunkEV5I5HGT_js.__name((param) => isPlainRecord3(param) && param.in === "query" && param.__zodNestDto !== true, "isPlainQueryParam");
|
|
1478
|
+
|
|
1479
|
+
// src/document/expand-param-markers.ts
|
|
1480
|
+
var isPlainRecord4 = /* @__PURE__ */ chunkEV5I5HGT_js.__name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isPlainRecord");
|
|
1435
1481
|
var expandParamMarkers = /* @__PURE__ */ chunkEV5I5HGT_js.__name((params) => {
|
|
1436
|
-
const { doc, inputSchemas, outputSchemas } = params;
|
|
1437
|
-
const
|
|
1482
|
+
const { doc, inputSchemas, outputSchemas, queryParamStyle } = params;
|
|
1483
|
+
const emitThirtyTwo = params.emitThirtyTwo ?? false;
|
|
1438
1484
|
const schemas = doc.components?.schemas;
|
|
1439
1485
|
const componentIds = schemas !== null && typeof schemas === "object" ? new Set(Object.keys(schemas)) : /* @__PURE__ */ new Set();
|
|
1486
|
+
if (queryParamStyle !== void 0 && emitThirtyTwo) {
|
|
1487
|
+
warnDeprecatedQueryParamStyle();
|
|
1488
|
+
}
|
|
1489
|
+
const context = {
|
|
1490
|
+
inputSchemas,
|
|
1491
|
+
outputSchemas,
|
|
1492
|
+
queryParamStyle,
|
|
1493
|
+
emitThirtyTwo,
|
|
1494
|
+
componentIds
|
|
1495
|
+
};
|
|
1440
1496
|
let expandedAny = false;
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
return;
|
|
1497
|
+
for (const [path, pathItem] of Object.entries(doc.paths ?? {})) {
|
|
1498
|
+
if (!isPlainRecord4(pathItem)) {
|
|
1499
|
+
continue;
|
|
1445
1500
|
}
|
|
1446
|
-
const
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1501
|
+
for (const { method, operation } of operationEntriesOfPathItem(pathItem)) {
|
|
1502
|
+
const parameters = operation.parameters;
|
|
1503
|
+
if (!Array.isArray(parameters)) {
|
|
1504
|
+
continue;
|
|
1505
|
+
}
|
|
1506
|
+
const next = expandParameterList(parameters, context, {
|
|
1507
|
+
path,
|
|
1508
|
+
method,
|
|
1509
|
+
pathItemParameters: pathItem.parameters
|
|
1510
|
+
});
|
|
1511
|
+
if (next !== parameters) {
|
|
1512
|
+
operation.parameters = next;
|
|
1513
|
+
expandedAny = true;
|
|
1514
|
+
}
|
|
1455
1515
|
}
|
|
1456
|
-
}
|
|
1516
|
+
}
|
|
1457
1517
|
if (expandedAny) {
|
|
1458
1518
|
pruneOrphanObjectSchema(doc);
|
|
1459
1519
|
}
|
|
1460
1520
|
}, "expandParamMarkers");
|
|
1461
|
-
var expandParameterList = /* @__PURE__ */ chunkEV5I5HGT_js.__name((parameters, context) => {
|
|
1521
|
+
var expandParameterList = /* @__PURE__ */ chunkEV5I5HGT_js.__name((parameters, context, scope) => {
|
|
1522
|
+
const candidateCount = countCollapseCandidates(parameters, context);
|
|
1523
|
+
const collapseBlocked = context.emitThirtyTwo && candidateCount > 0 && hasQueryConflict({
|
|
1524
|
+
parameters,
|
|
1525
|
+
pathItemParameters: scope.pathItemParameters,
|
|
1526
|
+
candidateCount
|
|
1527
|
+
});
|
|
1528
|
+
if (collapseBlocked) {
|
|
1529
|
+
warnQuerystringDegraded(scope, parameters, candidateCount);
|
|
1530
|
+
}
|
|
1462
1531
|
let result;
|
|
1463
1532
|
for (let i = 0; i < parameters.length; i++) {
|
|
1464
1533
|
const param = parameters[i];
|
|
@@ -1472,21 +1541,51 @@ var expandParameterList = /* @__PURE__ */ chunkEV5I5HGT_js.__name((parameters, c
|
|
|
1472
1541
|
}
|
|
1473
1542
|
const map = marker.io === "output" ? context.outputSchemas : context.inputSchemas;
|
|
1474
1543
|
const body = map.get(marker.dtoId);
|
|
1475
|
-
result.push(...resolveMarker(marker, body, context));
|
|
1544
|
+
result.push(...resolveMarker(marker, body, context, collapseBlocked));
|
|
1476
1545
|
}
|
|
1477
1546
|
return result ?? parameters;
|
|
1478
1547
|
}, "expandParameterList");
|
|
1479
|
-
var
|
|
1480
|
-
|
|
1481
|
-
if (marker.
|
|
1548
|
+
var wouldCollapse = /* @__PURE__ */ chunkEV5I5HGT_js.__name((marker, context) => marker.in === "query" && prefersCollapse(marker, context) && context.componentIds.has(marker.dtoId), "wouldCollapse");
|
|
1549
|
+
var prefersCollapse = /* @__PURE__ */ chunkEV5I5HGT_js.__name((marker, context) => {
|
|
1550
|
+
if (marker.ref !== void 0) {
|
|
1551
|
+
return marker.ref;
|
|
1552
|
+
}
|
|
1553
|
+
if (context.queryParamStyle !== void 0) {
|
|
1554
|
+
return context.queryParamStyle === "ref";
|
|
1555
|
+
}
|
|
1556
|
+
return context.emitThirtyTwo;
|
|
1557
|
+
}, "prefersCollapse");
|
|
1558
|
+
var countCollapseCandidates = /* @__PURE__ */ chunkEV5I5HGT_js.__name((parameters, context) => {
|
|
1559
|
+
let count = 0;
|
|
1560
|
+
for (const param of parameters) {
|
|
1561
|
+
const marker = readMarker2(param);
|
|
1562
|
+
if (marker !== void 0 && wouldCollapse(marker, context)) {
|
|
1563
|
+
count += 1;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
return count;
|
|
1567
|
+
}, "countCollapseCandidates");
|
|
1568
|
+
var resolveMarker = /* @__PURE__ */ chunkEV5I5HGT_js.__name((marker, body, context, collapseBlocked) => {
|
|
1569
|
+
if (marker.ref !== void 0 && context.emitThirtyTwo) {
|
|
1570
|
+
warnDeprecatedRefOption(marker.dtoId);
|
|
1571
|
+
}
|
|
1572
|
+
if (collapseBlocked || !wouldCollapse(marker, context)) {
|
|
1573
|
+
return expandOne(marker, body);
|
|
1574
|
+
}
|
|
1575
|
+
if (context.emitThirtyTwo) {
|
|
1482
1576
|
return [
|
|
1483
|
-
|
|
1577
|
+
buildQuerystringParam({
|
|
1578
|
+
dtoId: marker.dtoId,
|
|
1579
|
+
body
|
|
1580
|
+
})
|
|
1484
1581
|
];
|
|
1485
1582
|
}
|
|
1486
|
-
return
|
|
1583
|
+
return [
|
|
1584
|
+
buildRefQueryParam(marker, body)
|
|
1585
|
+
];
|
|
1487
1586
|
}, "resolveMarker");
|
|
1488
1587
|
var buildRefQueryParam = /* @__PURE__ */ chunkEV5I5HGT_js.__name((marker, body) => {
|
|
1489
|
-
const required =
|
|
1588
|
+
const required = isPlainRecord4(body) && Array.isArray(body.required) && body.required.length > 0;
|
|
1490
1589
|
return {
|
|
1491
1590
|
name: marker.dtoId,
|
|
1492
1591
|
in: "query",
|
|
@@ -1499,7 +1598,7 @@ var buildRefQueryParam = /* @__PURE__ */ chunkEV5I5HGT_js.__name((marker, body)
|
|
|
1499
1598
|
};
|
|
1500
1599
|
}, "buildRefQueryParam");
|
|
1501
1600
|
var readMarker2 = /* @__PURE__ */ chunkEV5I5HGT_js.__name((value) => {
|
|
1502
|
-
if (!
|
|
1601
|
+
if (!isPlainRecord4(value)) {
|
|
1503
1602
|
return void 0;
|
|
1504
1603
|
}
|
|
1505
1604
|
if (value.__zodNestDto !== true) {
|
|
@@ -1520,7 +1619,7 @@ var readMarker2 = /* @__PURE__ */ chunkEV5I5HGT_js.__name((value) => {
|
|
|
1520
1619
|
return value;
|
|
1521
1620
|
}, "readMarker");
|
|
1522
1621
|
var expandOne = /* @__PURE__ */ chunkEV5I5HGT_js.__name((marker, body) => {
|
|
1523
|
-
if (!
|
|
1622
|
+
if (!isPlainRecord4(body) || !isPlainRecord4(body.properties)) {
|
|
1524
1623
|
throw new ZodNestDocumentError("UNEXPANDABLE_PARAM_DTO", `Cannot expand \`@${capitalize(marker.in)}() x: ${marker.dtoId}\` \u2014 the DTO's schema is not an object with \`properties\`. Non-body parameter DTOs must be object schemas; arrays, unions, primitives, etc. cannot be split into individual parameters. Use \`@Body()\` for non-object DTOs, or restructure the schema as an object whose fields become the params.`, {
|
|
1525
1624
|
dtoId: marker.dtoId,
|
|
1526
1625
|
in: marker.in,
|
|
@@ -1531,7 +1630,7 @@ var expandOne = /* @__PURE__ */ chunkEV5I5HGT_js.__name((marker, body) => {
|
|
|
1531
1630
|
const requiredSet = collectRequired(body.required);
|
|
1532
1631
|
const out = [];
|
|
1533
1632
|
for (const [propName, propSchemaRaw] of Object.entries(properties)) {
|
|
1534
|
-
if (!
|
|
1633
|
+
if (!isPlainRecord4(propSchemaRaw)) {
|
|
1535
1634
|
continue;
|
|
1536
1635
|
}
|
|
1537
1636
|
out.push(buildParameter(marker, propName, propSchemaRaw, requiredSet.has(propName)));
|
|
@@ -1564,6 +1663,22 @@ var buildParameter = /* @__PURE__ */ chunkEV5I5HGT_js.__name((marker, name, sche
|
|
|
1564
1663
|
};
|
|
1565
1664
|
}, "buildParameter");
|
|
1566
1665
|
var capitalize = /* @__PURE__ */ chunkEV5I5HGT_js.__name((value) => value.charAt(0).toUpperCase() + value.slice(1), "capitalize");
|
|
1666
|
+
var warnQuerystringDegraded = /* @__PURE__ */ chunkEV5I5HGT_js.__name((scope, parameters, candidateCount) => {
|
|
1667
|
+
console.warn(`[zod-nest] Expanded the query DTO on \`${scope.method.toUpperCase()} ${scope.path}\` per-property instead of emitting \`in: 'querystring'\`: ${degradeReason(scope, parameters, candidateCount)} The expanded form is spec-valid, so the document still ships.`);
|
|
1668
|
+
}, "warnQuerystringDegraded");
|
|
1669
|
+
var degradeReason = /* @__PURE__ */ chunkEV5I5HGT_js.__name((scope, parameters, candidateCount) => {
|
|
1670
|
+
if (candidateCount > 1) {
|
|
1671
|
+
return `OpenAPI 3.2 allows at most one \`querystring\` parameter per operation, and this one has ${candidateCount} query DTOs.`;
|
|
1672
|
+
}
|
|
1673
|
+
const names = conflictingQueryNames(parameters, scope.pathItemParameters);
|
|
1674
|
+
return `OpenAPI 3.2 forbids a \`querystring\` parameter alongside \`in: 'query'\` parameters (${names.map((name) => `\`${name}\``).join(", ")}).`;
|
|
1675
|
+
}, "degradeReason");
|
|
1676
|
+
var warnDeprecatedQueryParamStyle = /* @__PURE__ */ chunkEV5I5HGT_js.__name(() => {
|
|
1677
|
+
console.warn("[zod-nest] `queryParamStyle` is deprecated and will be removed in the next major: OpenAPI 3.2 emits `in: 'querystring'` for named query DTOs by default, which is what this option approximated. Drop it to take the default.");
|
|
1678
|
+
}, "warnDeprecatedQueryParamStyle");
|
|
1679
|
+
var warnDeprecatedRefOption = /* @__PURE__ */ chunkEV5I5HGT_js.__name((dtoId) => {
|
|
1680
|
+
console.warn(`[zod-nest] \`@ZodQuery({ ref })\` on \`${dtoId}\` is deprecated and will be removed in the next major: OpenAPI 3.2 emits \`in: 'querystring'\` for named query DTOs by default. Drop the option to take the default.`);
|
|
1681
|
+
}, "warnDeprecatedRefOption");
|
|
1567
1682
|
var pruneOrphanObjectSchema = /* @__PURE__ */ chunkEV5I5HGT_js.__name((doc) => {
|
|
1568
1683
|
const schemas = doc.components?.schemas;
|
|
1569
1684
|
if (schemas === void 0 || !Object.prototype.hasOwnProperty.call(schemas, "Object")) {
|
|
@@ -1635,7 +1750,7 @@ var inlineAnonymousBodies = /* @__PURE__ */ chunkEV5I5HGT_js.__name(({ doc, regi
|
|
|
1635
1750
|
`${anonId}${OUTPUT_SUFFIX}`
|
|
1636
1751
|
]) {
|
|
1637
1752
|
const body = schemas[key];
|
|
1638
|
-
if (
|
|
1753
|
+
if (isPlainRecord5(body)) {
|
|
1639
1754
|
bodyByRef.set(`${chunkJ2MGUXBB_js.COMPONENTS_SCHEMAS_PREFIX}${key}`, body);
|
|
1640
1755
|
}
|
|
1641
1756
|
}
|
|
@@ -1661,7 +1776,7 @@ var refsWithin = /* @__PURE__ */ chunkEV5I5HGT_js.__name((schemas, bodyByRef) =>
|
|
|
1661
1776
|
});
|
|
1662
1777
|
return found;
|
|
1663
1778
|
}, "refsWithin");
|
|
1664
|
-
var
|
|
1779
|
+
var isPlainRecord5 = /* @__PURE__ */ chunkEV5I5HGT_js.__name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isPlainRecord");
|
|
1665
1780
|
var inlineRefs = /* @__PURE__ */ chunkEV5I5HGT_js.__name((node, bodyByRef) => {
|
|
1666
1781
|
if (Array.isArray(node)) {
|
|
1667
1782
|
for (const item of node) {
|
|
@@ -1669,7 +1784,7 @@ var inlineRefs = /* @__PURE__ */ chunkEV5I5HGT_js.__name((node, bodyByRef) => {
|
|
|
1669
1784
|
}
|
|
1670
1785
|
return;
|
|
1671
1786
|
}
|
|
1672
|
-
if (!
|
|
1787
|
+
if (!isPlainRecord5(node)) {
|
|
1673
1788
|
return;
|
|
1674
1789
|
}
|
|
1675
1790
|
const ref = node.$ref;
|
|
@@ -1901,7 +2016,7 @@ var applyRefTitles = /* @__PURE__ */ chunkEV5I5HGT_js.__name((doc) => {
|
|
|
1901
2016
|
}
|
|
1902
2017
|
const titleById = /* @__PURE__ */ new Map();
|
|
1903
2018
|
for (const [id, body] of Object.entries(schemas)) {
|
|
1904
|
-
if (
|
|
2019
|
+
if (isPlainRecord6(body) && typeof body.title === "string" && body.title !== "") {
|
|
1905
2020
|
titleById.set(id, body.title);
|
|
1906
2021
|
}
|
|
1907
2022
|
}
|
|
@@ -1911,7 +2026,7 @@ var applyRefTitles = /* @__PURE__ */ chunkEV5I5HGT_js.__name((doc) => {
|
|
|
1911
2026
|
addRefTitles(doc.paths, titleById);
|
|
1912
2027
|
addRefTitles(schemas, titleById);
|
|
1913
2028
|
}, "applyRefTitles");
|
|
1914
|
-
var
|
|
2029
|
+
var isPlainRecord6 = /* @__PURE__ */ chunkEV5I5HGT_js.__name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isPlainRecord");
|
|
1915
2030
|
var addRefTitles = /* @__PURE__ */ chunkEV5I5HGT_js.__name((node, titleById) => {
|
|
1916
2031
|
if (Array.isArray(node)) {
|
|
1917
2032
|
for (const item of node) {
|
|
@@ -1919,7 +2034,7 @@ var addRefTitles = /* @__PURE__ */ chunkEV5I5HGT_js.__name((node, titleById) =>
|
|
|
1919
2034
|
}
|
|
1920
2035
|
return;
|
|
1921
2036
|
}
|
|
1922
|
-
if (!
|
|
2037
|
+
if (!isPlainRecord6(node)) {
|
|
1923
2038
|
return;
|
|
1924
2039
|
}
|
|
1925
2040
|
const ref = node.$ref;
|
|
@@ -2067,6 +2182,8 @@ var withForcedExposure = /* @__PURE__ */ chunkEV5I5HGT_js.__name((collected, reg
|
|
|
2067
2182
|
}, "withForcedExposure");
|
|
2068
2183
|
var applyZodNest = /* @__PURE__ */ chunkEV5I5HGT_js.__name((doc, opts = {}) => {
|
|
2069
2184
|
const registry = opts.registry ?? chunkJ2MGUXBB_js.defaultRegistry;
|
|
2185
|
+
const openApiVersion = resolveOpenApiVersion(doc);
|
|
2186
|
+
const emitThirtyTwo = openApiVersion.startsWith("3.2.");
|
|
2070
2187
|
const collected = collectUsage(doc, registry);
|
|
2071
2188
|
const exposed = withForcedExposure(collected, registry);
|
|
2072
2189
|
const { inputSchemas, outputSchemas } = bulkEmit({
|
|
@@ -2086,7 +2203,8 @@ var applyZodNest = /* @__PURE__ */ chunkEV5I5HGT_js.__name((doc, opts = {}) => {
|
|
|
2086
2203
|
doc,
|
|
2087
2204
|
inputSchemas,
|
|
2088
2205
|
outputSchemas,
|
|
2089
|
-
queryParamStyle: opts.queryParamStyle
|
|
2206
|
+
queryParamStyle: opts.queryParamStyle,
|
|
2207
|
+
emitThirtyTwo
|
|
2090
2208
|
});
|
|
2091
2209
|
rewriteRefs({
|
|
2092
2210
|
doc,
|
|
@@ -2105,8 +2223,6 @@ var applyZodNest = /* @__PURE__ */ chunkEV5I5HGT_js.__name((doc, opts = {}) => {
|
|
|
2105
2223
|
doc,
|
|
2106
2224
|
collected: extended
|
|
2107
2225
|
});
|
|
2108
|
-
const openApiVersion = resolveOpenApiVersion(doc);
|
|
2109
|
-
const emitThirtyTwo = openApiVersion.startsWith("3.2.");
|
|
2110
2226
|
if (emitThirtyTwo) {
|
|
2111
2227
|
relocateExtensionOperations(doc);
|
|
2112
2228
|
}
|