nestjs-openapi-next 1.0.1 → 1.0.2

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.
@@ -0,0 +1,25 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "WebSearch",
5
+ "WebFetch(domain:spec.openapis.org)",
6
+ "WebFetch(domain:www.openapis.org)",
7
+ "WebFetch(domain:blog.stoplight.io)",
8
+ "WebFetch(domain:apisyouwonthate.com)",
9
+ "WebFetch(domain:github.com)",
10
+ "Bash(gh auth status:*)",
11
+ "Bash(gh issue create:*)",
12
+ "Bash(gh issue view:*)",
13
+ "Bash(gh issue edit:*)",
14
+ "Bash(npm test)",
15
+ "Bash(npm install)",
16
+ "Bash(npm test:*)",
17
+ "Bash(gh pr view:*)",
18
+ "Bash(git checkout:*)",
19
+ "Bash(git add:*)",
20
+ "Bash(git commit -m \"$\\(cat <<''EOF''\ndocs: update README with OAS 3.1/3.2 features\n\nAdd documentation for newly implemented OpenAPI 3.1/3.2 features:\n- JSON Schema Draft 2020-12 alignment\n- type as array support \\(replaces nullable\\)\n- LicenseObject.identifier\n- ServerObject.pathPrefix\n- InfoObject.tags\n- ReferenceObject summary/description override\n- exclusiveMinimum/exclusiveMaximum type change\n\nCloses #7\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
21
+ "Bash(git push:*)",
22
+ "Bash(gh pr create:*)"
23
+ ]
24
+ }
25
+ }
package/README.md CHANGED
@@ -1,24 +1,32 @@
1
1
  # nestjs-openapi-next
2
2
 
3
3
  `nestjs-openapi-next` is a fork of `@nestjs/swagger` (upstream: `nestjs/swagger`).
4
- The goal is to keep upstream behavior as compatible as possible while adding a set of **OpenAPI 3.2** features and widely-used **OpenAPI extension fields** (`x-`) that are commonly consumed by tools like Redoc.
4
+ The goal is to keep upstream behavior as compatible as possible while adding a set of **OpenAPI 3.1/3.2** features and widely-used **OpenAPI extension fields** (`x-`) that are commonly consumed by tools like Redoc.
5
5
 
6
6
  ## Key differences from upstream
7
7
 
8
- - **Richer OpenAPI 3.2 typings**
9
- - e.g. `TagObject.summary`, `OAuthFlowsObject.deviceAuthorization`, etc.
8
+ - **Richer OpenAPI 3.1/3.2 typings**
9
+ - e.g. `TagObject.summary`, `OAuthFlowsObject.deviceAuthorization`, `LicenseObject.identifier`, etc.
10
10
  - **Enhanced tag support**
11
11
  - `@ApiTag(options)` (class/controller-level): defines tag metadata (`summary`, `x-displayName`, `description`, `parent`, `kind`, ...) and merges it into the top-level `document.tags`.
12
12
  - `x-displayName` support for tags, mirrored with `summary` (setting either results in both fields being written with the same value).
13
13
  - Root-level `x-tagGroups` support (commonly used by Redoc). If you use `parent` to form relationships, `x-tagGroups` is auto-derived; you can also set it explicitly via `DocumentBuilder`.
14
- - **Additional OAS 3.2 behaviors**
14
+ - **OAS 3.1 features**
15
+ - JSON Schema Draft 2020-12 alignment (e.g. `$defs`, `prefixItems`, `const`, `contentEncoding`, `contentMediaType`, `contentSchema`).
16
+ - `type` as array support (e.g. `type: ['string', 'null']`) with automatic `nullable` removal.
17
+ - `LicenseObject.identifier` field support via `DocumentBuilder.setLicense()`.
18
+ - `ReferenceObject` with `summary` and `description` override support.
19
+ - `exclusiveMinimum` / `exclusiveMaximum` as number type (changed from boolean in OAS 3.0).
20
+ - **OAS 3.2 features**
15
21
  - HTTP `QUERY` method via `@ApiQueryMethod()` (emits `paths['/x'].query`).
16
22
  - Streaming responses via `@ApiStreamingResponse()` (`itemSchema`, e.g. SSE `text/event-stream`).
17
23
  - OAuth2 Device Authorization Flow typing + `@ApiSecurityDeviceFlow()` helper.
24
+ - `ServerObject.pathPrefix` field support via `DocumentBuilder.addServer()`.
25
+ - `InfoObject.tags` field support via `DocumentBuilder.setInfoTags()`.
18
26
  - **Convenience APIs**
19
27
  - `DocumentBuilder.addServerWithName()` for a non-standard-but-common `server.name`.
20
28
 
21
- Test coverage: `test/openapi-3-2.spec.ts`.
29
+ Test coverage: `test/openapi-3-1.spec.ts`, `test/openapi-3-2.spec.ts`.
22
30
 
23
31
  ## Compatibility
24
32
 
@@ -230,6 +238,131 @@ export class StripeWebhooksController {
230
238
  The generated document will contain `document.webhooks.stripeEvent.post`, and the
231
239
  corresponding route will **not** be emitted under `document.paths`.
232
240
 
241
+ ### 8) `LicenseObject.identifier` (OAS 3.1)
242
+
243
+ OAS 3.1 added an `identifier` field to `LicenseObject` for SPDX license identifiers:
244
+
245
+ ```ts
246
+ const config = new DocumentBuilder()
247
+ .setTitle('Example')
248
+ .setVersion('1.0')
249
+ .setLicense('MIT', 'https://opensource.org/licenses/MIT', 'MIT')
250
+ .build();
251
+ ```
252
+
253
+ This produces:
254
+
255
+ ```yaml
256
+ info:
257
+ license:
258
+ name: MIT
259
+ url: https://opensource.org/licenses/MIT
260
+ identifier: MIT
261
+ ```
262
+
263
+ ### 9) `ServerObject.pathPrefix` (OAS 3.2)
264
+
265
+ OAS 3.2 added a `pathPrefix` field to `ServerObject`:
266
+
267
+ ```ts
268
+ const config = new DocumentBuilder()
269
+ .setTitle('Example')
270
+ .setVersion('1.0')
271
+ .addServer('https://api.example.com', 'Production', {}, '/v1')
272
+ .build();
273
+ ```
274
+
275
+ This produces:
276
+
277
+ ```yaml
278
+ servers:
279
+ - url: https://api.example.com
280
+ description: Production
281
+ pathPrefix: /v1
282
+ ```
283
+
284
+ ### 10) `InfoObject.tags` (OAS 3.2)
285
+
286
+ OAS 3.2 added a `tags` field to `InfoObject` for categorizing the API itself:
287
+
288
+ ```ts
289
+ const config = new DocumentBuilder()
290
+ .setTitle('Example')
291
+ .setVersion('1.0')
292
+ .setInfoTags(['payments', 'commerce'])
293
+ .build();
294
+ ```
295
+
296
+ This produces:
297
+
298
+ ```yaml
299
+ info:
300
+ title: Example
301
+ version: '1.0'
302
+ tags:
303
+ - payments
304
+ - commerce
305
+ ```
306
+
307
+ ### 11) `ReferenceObject` with `summary` / `description` override (OAS 3.1)
308
+
309
+ OAS 3.1 allows `$ref` objects to include `summary` and `description` fields that override the referenced schema's values:
310
+
311
+ ```ts
312
+ import { ApiProperty } from 'nestjs-openapi-next';
313
+
314
+ class CreateUserDto {
315
+ @ApiProperty({
316
+ allOf: [
317
+ {
318
+ $ref: '#/components/schemas/BaseUser',
319
+ summary: 'User base fields',
320
+ description: 'Contains the common user properties'
321
+ }
322
+ ]
323
+ })
324
+ user: BaseUser;
325
+ }
326
+ ```
327
+
328
+ ### 12) `type` as array (OAS 3.1)
329
+
330
+ OAS 3.1 supports `type` as an array for union types. This replaces the `nullable` keyword:
331
+
332
+ ```ts
333
+ import { ApiProperty } from 'nestjs-openapi-next';
334
+
335
+ class UserDto {
336
+ @ApiProperty({ type: ['string', 'null'] })
337
+ nickname: string | null;
338
+ }
339
+ ```
340
+
341
+ This produces `type: ['string', 'null']` instead of `type: 'string', nullable: true`.
342
+
343
+ ### 13) JSON Schema Draft 2020-12 keywords (OAS 3.1)
344
+
345
+ OAS 3.1 aligns with JSON Schema Draft 2020-12, adding support for:
346
+
347
+ - `$defs` - local schema definitions
348
+ - `prefixItems` - tuple validation (replaces `items` array form)
349
+ - `const` - exact value matching
350
+ - `contentEncoding` - encoding for string content (e.g., `base64`)
351
+ - `contentMediaType` - media type for string content
352
+ - `contentSchema` - schema for decoded content
353
+
354
+ ```ts
355
+ import { ApiProperty } from 'nestjs-openapi-next';
356
+
357
+ class FileDto {
358
+ @ApiProperty({
359
+ contentEncoding: 'base64',
360
+ contentMediaType: 'image/png'
361
+ })
362
+ data: string;
363
+ }
364
+ ```
365
+
233
366
  ## License
234
367
 
235
368
  MIT (see `LICENSE`). This repository is a derivative work of the upstream `nestjs/swagger` project under the MIT license.
@@ -8,11 +8,13 @@ export declare class DocumentBuilder {
8
8
  setDescription(description: string): this;
9
9
  setVersion(version: string): this;
10
10
  setTermsOfService(termsOfService: string): this;
11
+ setInfoTags(tags: string[]): this;
11
12
  setContact(name: string, url: string, email: string): this;
12
13
  setLicense(name: string, url: string): this;
14
+ setLicenseWithIdentifier(name: string, identifier: string): this;
13
15
  setOpenAPIVersion(version: string): this;
14
- addServer(url: string, description?: string, variables?: Record<string, ServerVariableObject>): this;
15
- addServerWithName(name: string, url: string, description?: string, variables?: Record<string, ServerVariableObject>): this;
16
+ addServer(url: string, description?: string, pathPrefix?: string, variables?: Record<string, ServerVariableObject>): this;
17
+ addServerWithName(name: string, url: string, description?: string, pathPrefix?: string, variables?: Record<string, ServerVariableObject>): this;
16
18
  setExternalDoc(description: string, url: string): this;
17
19
  setBasePath(path: string): this;
18
20
  addTag(name: string, description?: string, externalDocs?: ExternalDocumentationObject, summary?: string): this;
@@ -27,6 +27,10 @@ class DocumentBuilder {
27
27
  this.document.info.termsOfService = termsOfService;
28
28
  return this;
29
29
  }
30
+ setInfoTags(tags) {
31
+ this.document.info.tags = tags;
32
+ return this;
33
+ }
30
34
  setContact(name, url, email) {
31
35
  this.document.info.contact = { name, url, email };
32
36
  return this;
@@ -35,6 +39,10 @@ class DocumentBuilder {
35
39
  this.document.info.license = { name, url };
36
40
  return this;
37
41
  }
42
+ setLicenseWithIdentifier(name, identifier) {
43
+ this.document.info.license = { name, identifier };
44
+ return this;
45
+ }
38
46
  setOpenAPIVersion(version) {
39
47
  if (version.match(/^\d\.\d\.\d$/)) {
40
48
  this.document.openapi = version;
@@ -44,12 +52,18 @@ class DocumentBuilder {
44
52
  }
45
53
  return this;
46
54
  }
47
- addServer(url, description, variables) {
48
- this.document.servers.push({ url, description, variables });
55
+ addServer(url, description, pathPrefix, variables) {
56
+ this.document.servers.push({ url, description, variables, pathPrefix });
49
57
  return this;
50
58
  }
51
- addServerWithName(name, url, description, variables) {
52
- this.document.servers.push({ name, url, description, variables });
59
+ addServerWithName(name, url, description, pathPrefix, variables) {
60
+ this.document.servers.push({
61
+ name,
62
+ url,
63
+ description,
64
+ variables,
65
+ pathPrefix
66
+ });
53
67
  return this;
54
68
  }
55
69
  setExternalDoc(description, url) {
@@ -6,6 +6,29 @@ export declare const exploreApiParametersMetadata: (schemas: Record<string, Sche
6
6
  schema: {
7
7
  type: string;
8
8
  items: any;
9
+ $schema?: string;
10
+ $id?: string;
11
+ $defs?: Record<string, SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject>;
12
+ $dynamicAnchor?: string;
13
+ $dynamicRef?: string;
14
+ $anchor?: string;
15
+ const?: any;
16
+ contentMediaType?: string;
17
+ contentEncoding?: string;
18
+ contentSchema?: SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject;
19
+ if?: SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject;
20
+ then?: SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject;
21
+ else?: SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject;
22
+ dependentSchemas?: Record<string, SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject>;
23
+ dependentRequired?: Record<string, string[]>;
24
+ prefixItems?: (SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject)[];
25
+ unevaluatedProperties?: SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject | boolean;
26
+ unevaluatedItems?: SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject | boolean;
27
+ contains?: SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject;
28
+ minContains?: number;
29
+ maxContains?: number;
30
+ $comment?: string;
31
+ propertyNames?: SchemaObject | import("../interfaces/open-api-spec.interface").ReferenceObject;
9
32
  nullable?: boolean;
10
33
  discriminator?: import("../interfaces/open-api-spec.interface").DiscriminatorObject;
11
34
  readOnly?: boolean;
@@ -28,9 +51,9 @@ export declare const exploreApiParametersMetadata: (schemas: Record<string, Sche
28
51
  title?: string;
29
52
  multipleOf?: number;
30
53
  maximum?: number;
31
- exclusiveMaximum?: boolean;
54
+ exclusiveMaximum?: boolean | number;
32
55
  minimum?: number;
33
- exclusiveMinimum?: boolean;
56
+ exclusiveMinimum?: boolean | number;
34
57
  maxLength?: number;
35
58
  minLength?: number;
36
59
  pattern?: string;
@@ -20,6 +20,7 @@ export interface InfoObject {
20
20
  contact?: ContactObject;
21
21
  license?: LicenseObject;
22
22
  version: string;
23
+ tags?: string[];
23
24
  }
24
25
  export interface ContactObject {
25
26
  name?: string;
@@ -29,10 +30,12 @@ export interface ContactObject {
29
30
  export interface LicenseObject {
30
31
  name: string;
31
32
  url?: string;
33
+ identifier?: string;
32
34
  }
33
35
  export interface ServerObject {
34
36
  name?: string;
35
37
  url: string;
38
+ pathPrefix?: string;
36
39
  description?: string;
37
40
  variables?: Record<string, ServerVariableObject>;
38
41
  }
@@ -170,8 +173,33 @@ export interface TagObject {
170
173
  export type ExamplesObject = Record<string, ExampleObject | ReferenceObject>;
171
174
  export interface ReferenceObject {
172
175
  $ref: string;
176
+ summary?: string;
177
+ description?: string;
173
178
  }
174
179
  export interface SchemaObject {
180
+ $schema?: string;
181
+ $id?: string;
182
+ $defs?: Record<string, SchemaObject | ReferenceObject>;
183
+ $dynamicAnchor?: string;
184
+ $dynamicRef?: string;
185
+ $anchor?: string;
186
+ const?: any;
187
+ contentMediaType?: string;
188
+ contentEncoding?: string;
189
+ contentSchema?: SchemaObject | ReferenceObject;
190
+ if?: SchemaObject | ReferenceObject;
191
+ then?: SchemaObject | ReferenceObject;
192
+ else?: SchemaObject | ReferenceObject;
193
+ dependentSchemas?: Record<string, SchemaObject | ReferenceObject>;
194
+ dependentRequired?: Record<string, string[]>;
195
+ prefixItems?: (SchemaObject | ReferenceObject)[];
196
+ unevaluatedProperties?: SchemaObject | ReferenceObject | boolean;
197
+ unevaluatedItems?: SchemaObject | ReferenceObject | boolean;
198
+ contains?: SchemaObject | ReferenceObject;
199
+ minContains?: number;
200
+ maxContains?: number;
201
+ $comment?: string;
202
+ propertyNames?: SchemaObject | ReferenceObject;
175
203
  nullable?: boolean;
176
204
  discriminator?: DiscriminatorObject;
177
205
  readOnly?: boolean;
@@ -181,12 +209,12 @@ export interface SchemaObject {
181
209
  example?: any;
182
210
  examples?: any[] | Record<string, any>;
183
211
  deprecated?: boolean;
184
- type?: string;
212
+ type?: string | string[];
185
213
  allOf?: (SchemaObject | ReferenceObject)[];
186
214
  oneOf?: (SchemaObject | ReferenceObject)[];
187
215
  anyOf?: (SchemaObject | ReferenceObject)[];
188
216
  not?: SchemaObject | ReferenceObject;
189
- items?: SchemaObject | ReferenceObject;
217
+ items?: SchemaObject | ReferenceObject | boolean;
190
218
  properties?: Record<string, SchemaObject | ReferenceObject>;
191
219
  additionalProperties?: SchemaObject | ReferenceObject | boolean;
192
220
  patternProperties?: Record<string, SchemaObject | ReferenceObject> | undefined;
@@ -196,9 +224,9 @@ export interface SchemaObject {
196
224
  title?: string;
197
225
  multipleOf?: number;
198
226
  maximum?: number;
199
- exclusiveMaximum?: boolean;
227
+ exclusiveMaximum?: boolean | number;
200
228
  minimum?: number;
201
- exclusiveMinimum?: boolean;
229
+ exclusiveMinimum?: boolean | number;
202
230
  maxLength?: number;
203
231
  minLength?: number;
204
232
  pattern?: string;
@@ -8,7 +8,7 @@ interface SchemaObjectCommonMetadata extends Omit<SchemaObject, 'type' | 'requir
8
8
  enum?: EnumAllowedTypes;
9
9
  }
10
10
  export type SchemaObjectMetadata = (SchemaObjectCommonMetadata & {
11
- type?: Type<unknown> | Function | [Function] | 'array' | 'string' | 'number' | 'boolean' | 'integer' | 'null';
11
+ type?: Type<unknown> | Function | [Function] | 'array' | 'string' | 'number' | 'boolean' | 'integer' | 'file' | 'null';
12
12
  required?: boolean;
13
13
  }) | ({
14
14
  type?: Type<unknown> | Function | [Function] | Record<string, any>;
@@ -15,6 +15,29 @@ export declare class SchemaObjectFactory {
15
15
  type: string;
16
16
  items: {
17
17
  $ref: string;
18
+ $schema?: string;
19
+ $id?: string;
20
+ $defs?: Record<string, SchemaObject | ReferenceObject>;
21
+ $dynamicAnchor?: string;
22
+ $dynamicRef?: string;
23
+ $anchor?: string;
24
+ const?: any;
25
+ contentMediaType?: string;
26
+ contentEncoding?: string;
27
+ contentSchema?: SchemaObject | ReferenceObject;
28
+ if?: SchemaObject | ReferenceObject;
29
+ then?: SchemaObject | ReferenceObject;
30
+ else?: SchemaObject | ReferenceObject;
31
+ dependentSchemas?: Record<string, SchemaObject | ReferenceObject>;
32
+ dependentRequired?: Record<string, string[]>;
33
+ prefixItems?: (SchemaObject | ReferenceObject)[];
34
+ unevaluatedProperties?: SchemaObject | ReferenceObject | boolean;
35
+ unevaluatedItems?: SchemaObject | ReferenceObject | boolean;
36
+ contains?: SchemaObject | ReferenceObject;
37
+ minContains?: number;
38
+ maxContains?: number;
39
+ $comment?: string;
40
+ propertyNames?: SchemaObject | ReferenceObject;
18
41
  nullable?: boolean;
19
42
  discriminator?: import("../interfaces/open-api-spec.interface").DiscriminatorObject;
20
43
  readOnly?: boolean;
@@ -24,12 +47,12 @@ export declare class SchemaObjectFactory {
24
47
  example?: any;
25
48
  examples?: any[] | Record<string, any>;
26
49
  deprecated?: boolean;
27
- type?: string;
50
+ type?: string | string[];
28
51
  allOf?: (SchemaObject | ReferenceObject)[];
29
52
  oneOf?: (SchemaObject | ReferenceObject)[];
30
53
  anyOf?: (SchemaObject | ReferenceObject)[];
31
54
  not?: SchemaObject | ReferenceObject;
32
- items?: SchemaObject | ReferenceObject;
55
+ items?: SchemaObject | ReferenceObject | boolean;
33
56
  properties?: Record<string, SchemaObject | ReferenceObject>;
34
57
  additionalProperties?: SchemaObject | ReferenceObject | boolean;
35
58
  patternProperties?: Record<string, SchemaObject | ReferenceObject> | undefined;
@@ -39,9 +62,9 @@ export declare class SchemaObjectFactory {
39
62
  title?: string;
40
63
  multipleOf?: number;
41
64
  maximum?: number;
42
- exclusiveMaximum?: boolean;
65
+ exclusiveMaximum?: boolean | number;
43
66
  minimum?: number;
44
- exclusiveMinimum?: boolean;
67
+ exclusiveMinimum?: boolean | number;
45
68
  maxLength?: number;
46
69
  minLength?: number;
47
70
  pattern?: string;
@@ -55,6 +78,8 @@ export declare class SchemaObjectFactory {
55
78
  'x-enumNames'?: string[];
56
79
  } | {
57
80
  $ref: string;
81
+ summary?: string;
82
+ description?: string;
58
83
  };
59
84
  };
60
85
  type?: Type<unknown>;
@@ -70,6 +95,29 @@ export declare class SchemaObjectFactory {
70
95
  name: string | number | object;
71
96
  schema: {
72
97
  $ref: string;
98
+ $schema?: string;
99
+ $id?: string;
100
+ $defs?: Record<string, SchemaObject | ReferenceObject>;
101
+ $dynamicAnchor?: string;
102
+ $dynamicRef?: string;
103
+ $anchor?: string;
104
+ const?: any;
105
+ contentMediaType?: string;
106
+ contentEncoding?: string;
107
+ contentSchema?: SchemaObject | ReferenceObject;
108
+ if?: SchemaObject | ReferenceObject;
109
+ then?: SchemaObject | ReferenceObject;
110
+ else?: SchemaObject | ReferenceObject;
111
+ dependentSchemas?: Record<string, SchemaObject | ReferenceObject>;
112
+ dependentRequired?: Record<string, string[]>;
113
+ prefixItems?: (SchemaObject | ReferenceObject)[];
114
+ unevaluatedProperties?: SchemaObject | ReferenceObject | boolean;
115
+ unevaluatedItems?: SchemaObject | ReferenceObject | boolean;
116
+ contains?: SchemaObject | ReferenceObject;
117
+ minContains?: number;
118
+ maxContains?: number;
119
+ $comment?: string;
120
+ propertyNames?: SchemaObject | ReferenceObject;
73
121
  nullable?: boolean;
74
122
  discriminator?: import("../interfaces/open-api-spec.interface").DiscriminatorObject;
75
123
  readOnly?: boolean;
@@ -79,12 +127,12 @@ export declare class SchemaObjectFactory {
79
127
  example?: any;
80
128
  examples?: any[] | Record<string, any>;
81
129
  deprecated?: boolean;
82
- type?: string;
130
+ type?: string | string[];
83
131
  allOf?: (SchemaObject | ReferenceObject)[];
84
132
  oneOf?: (SchemaObject | ReferenceObject)[];
85
133
  anyOf?: (SchemaObject | ReferenceObject)[];
86
134
  not?: SchemaObject | ReferenceObject;
87
- items?: SchemaObject | ReferenceObject;
135
+ items?: SchemaObject | ReferenceObject | boolean;
88
136
  properties?: Record<string, SchemaObject | ReferenceObject>;
89
137
  additionalProperties?: SchemaObject | ReferenceObject | boolean;
90
138
  patternProperties?: Record<string, SchemaObject | ReferenceObject> | undefined;
@@ -94,9 +142,9 @@ export declare class SchemaObjectFactory {
94
142
  title?: string;
95
143
  multipleOf?: number;
96
144
  maximum?: number;
97
- exclusiveMaximum?: boolean;
145
+ exclusiveMaximum?: boolean | number;
98
146
  minimum?: number;
99
- exclusiveMinimum?: boolean;
147
+ exclusiveMinimum?: boolean | number;
100
148
  maxLength?: number;
101
149
  minLength?: number;
102
150
  pattern?: string;
@@ -110,6 +158,8 @@ export declare class SchemaObjectFactory {
110
158
  'x-enumNames'?: string[];
111
159
  } | {
112
160
  $ref: string;
161
+ summary?: string;
162
+ description?: string;
113
163
  };
114
164
  type?: Type<unknown>;
115
165
  in?: import("../interfaces/open-api-spec.interface").ParameterLocation | "body" | "placeholder";
@@ -305,7 +305,8 @@ class SchemaObjectFactory {
305
305
  transformToArraySchemaProperty(metadata, key, type) {
306
306
  const keysToRemove = ['type', 'enum'];
307
307
  const [movedProperties, keysToMove] = this.extractPropertyModifiers(metadata);
308
- const schemaHost = Object.assign(Object.assign({}, (0, lodash_1.omit)(metadata, [...keysToRemove, ...keysToMove])), { name: metadata.name || key, type: 'array', items: (0, lodash_1.isString)(type)
308
+ const schemaHost = Object.assign(Object.assign({}, (0, lodash_1.omit)(metadata, [...keysToRemove, ...keysToMove])), { name: metadata.name || key, type: 'array', items: metadata.items
309
+ ? Object.assign(Object.assign({}, metadata.items), movedProperties) : (0, lodash_1.isString)(type)
309
310
  ? Object.assign({ type }, movedProperties) : Object.assign(Object.assign({}, type), movedProperties) });
310
311
  schemaHost.items = (0, lodash_1.omitBy)(schemaHost.items, shared_utils_1.isUndefined);
311
312
  return schemaHost;
@@ -8,6 +8,29 @@ export declare class SwaggerTypesMapper {
8
8
  schema: {
9
9
  type: string;
10
10
  items: any;
11
+ $schema?: string;
12
+ $id?: string;
13
+ $defs?: Record<string, SchemaObject | ReferenceObject>;
14
+ $dynamicAnchor?: string;
15
+ $dynamicRef?: string;
16
+ $anchor?: string;
17
+ const?: any;
18
+ contentMediaType?: string;
19
+ contentEncoding?: string;
20
+ contentSchema?: SchemaObject | ReferenceObject;
21
+ if?: SchemaObject | ReferenceObject;
22
+ then?: SchemaObject | ReferenceObject;
23
+ else?: SchemaObject | ReferenceObject;
24
+ dependentSchemas?: Record<string, SchemaObject | ReferenceObject>;
25
+ dependentRequired?: Record<string, string[]>;
26
+ prefixItems?: (SchemaObject | ReferenceObject)[];
27
+ unevaluatedProperties?: SchemaObject | ReferenceObject | boolean;
28
+ unevaluatedItems?: SchemaObject | ReferenceObject | boolean;
29
+ contains?: SchemaObject | ReferenceObject;
30
+ minContains?: number;
31
+ maxContains?: number;
32
+ $comment?: string;
33
+ propertyNames?: SchemaObject | ReferenceObject;
11
34
  nullable?: boolean;
12
35
  discriminator?: import("../interfaces/open-api-spec.interface").DiscriminatorObject;
13
36
  readOnly?: boolean;
@@ -30,9 +53,9 @@ export declare class SwaggerTypesMapper {
30
53
  title?: string;
31
54
  multipleOf?: number;
32
55
  maximum?: number;
33
- exclusiveMaximum?: boolean;
56
+ exclusiveMaximum?: boolean | number;
34
57
  minimum?: number;
35
- exclusiveMinimum?: boolean;
58
+ exclusiveMinimum?: boolean | number;
36
59
  maxLength?: number;
37
60
  minLength?: number;
38
61
  pattern?: string;
@@ -75,6 +98,29 @@ export declare class SwaggerTypesMapper {
75
98
  schema: {
76
99
  type: string;
77
100
  items: any;
101
+ $schema?: string;
102
+ $id?: string;
103
+ $defs?: Record<string, SchemaObject | ReferenceObject>;
104
+ $dynamicAnchor?: string;
105
+ $dynamicRef?: string;
106
+ $anchor?: string;
107
+ const?: any;
108
+ contentMediaType?: string;
109
+ contentEncoding?: string;
110
+ contentSchema?: SchemaObject | ReferenceObject;
111
+ if?: SchemaObject | ReferenceObject;
112
+ then?: SchemaObject | ReferenceObject;
113
+ else?: SchemaObject | ReferenceObject;
114
+ dependentSchemas?: Record<string, SchemaObject | ReferenceObject>;
115
+ dependentRequired?: Record<string, string[]>;
116
+ prefixItems?: (SchemaObject | ReferenceObject)[];
117
+ unevaluatedProperties?: SchemaObject | ReferenceObject | boolean;
118
+ unevaluatedItems?: SchemaObject | ReferenceObject | boolean;
119
+ contains?: SchemaObject | ReferenceObject;
120
+ minContains?: number;
121
+ maxContains?: number;
122
+ $comment?: string;
123
+ propertyNames?: SchemaObject | ReferenceObject;
78
124
  nullable?: boolean;
79
125
  discriminator?: import("../interfaces/open-api-spec.interface").DiscriminatorObject;
80
126
  readOnly?: boolean;
@@ -97,9 +143,9 @@ export declare class SwaggerTypesMapper {
97
143
  title?: string;
98
144
  multipleOf?: number;
99
145
  maximum?: number;
100
- exclusiveMaximum?: boolean;
146
+ exclusiveMaximum?: boolean | number;
101
147
  minimum?: number;
102
- exclusiveMinimum?: boolean;
148
+ exclusiveMinimum?: boolean | number;
103
149
  maxLength?: number;
104
150
  minLength?: number;
105
151
  pattern?: string;
@@ -117,6 +163,29 @@ export declare class SwaggerTypesMapper {
117
163
  schema: {
118
164
  type: string;
119
165
  items: any;
166
+ $schema?: string;
167
+ $id?: string;
168
+ $defs?: Record<string, SchemaObject | ReferenceObject>;
169
+ $dynamicAnchor?: string;
170
+ $dynamicRef?: string;
171
+ $anchor?: string;
172
+ const?: any;
173
+ contentMediaType?: string;
174
+ contentEncoding?: string;
175
+ contentSchema?: SchemaObject | ReferenceObject;
176
+ if?: SchemaObject | ReferenceObject;
177
+ then?: SchemaObject | ReferenceObject;
178
+ else?: SchemaObject | ReferenceObject;
179
+ dependentSchemas?: Record<string, SchemaObject | ReferenceObject>;
180
+ dependentRequired?: Record<string, string[]>;
181
+ prefixItems?: (SchemaObject | ReferenceObject)[];
182
+ unevaluatedProperties?: SchemaObject | ReferenceObject | boolean;
183
+ unevaluatedItems?: SchemaObject | ReferenceObject | boolean;
184
+ contains?: SchemaObject | ReferenceObject;
185
+ minContains?: number;
186
+ maxContains?: number;
187
+ $comment?: string;
188
+ propertyNames?: SchemaObject | ReferenceObject;
120
189
  nullable?: boolean;
121
190
  discriminator?: import("../interfaces/open-api-spec.interface").DiscriminatorObject;
122
191
  readOnly?: boolean;
@@ -139,9 +208,9 @@ export declare class SwaggerTypesMapper {
139
208
  title?: string;
140
209
  multipleOf?: number;
141
210
  maximum?: number;
142
- exclusiveMaximum?: boolean;
211
+ exclusiveMaximum?: boolean | number;
143
212
  minimum?: number;
144
- exclusiveMinimum?: boolean;
213
+ exclusiveMinimum?: boolean | number;
145
214
  maxLength?: number;
146
215
  minLength?: number;
147
216
  pattern?: string;
@@ -168,6 +237,29 @@ export declare class SwaggerTypesMapper {
168
237
  schema: {
169
238
  type: string;
170
239
  items: any;
240
+ $schema?: string;
241
+ $id?: string;
242
+ $defs?: Record<string, SchemaObject | ReferenceObject>;
243
+ $dynamicAnchor?: string;
244
+ $dynamicRef?: string;
245
+ $anchor?: string;
246
+ const?: any;
247
+ contentMediaType?: string;
248
+ contentEncoding?: string;
249
+ contentSchema?: SchemaObject | ReferenceObject;
250
+ if?: SchemaObject | ReferenceObject;
251
+ then?: SchemaObject | ReferenceObject;
252
+ else?: SchemaObject | ReferenceObject;
253
+ dependentSchemas?: Record<string, SchemaObject | ReferenceObject>;
254
+ dependentRequired?: Record<string, string[]>;
255
+ prefixItems?: (SchemaObject | ReferenceObject)[];
256
+ unevaluatedProperties?: SchemaObject | ReferenceObject | boolean;
257
+ unevaluatedItems?: SchemaObject | ReferenceObject | boolean;
258
+ contains?: SchemaObject | ReferenceObject;
259
+ minContains?: number;
260
+ maxContains?: number;
261
+ $comment?: string;
262
+ propertyNames?: SchemaObject | ReferenceObject;
171
263
  nullable?: boolean;
172
264
  discriminator?: import("../interfaces/open-api-spec.interface").DiscriminatorObject;
173
265
  readOnly?: boolean;
@@ -190,9 +282,9 @@ export declare class SwaggerTypesMapper {
190
282
  title?: string;
191
283
  multipleOf?: number;
192
284
  maximum?: number;
193
- exclusiveMaximum?: boolean;
285
+ exclusiveMaximum?: boolean | number;
194
286
  minimum?: number;
195
- exclusiveMinimum?: boolean;
287
+ exclusiveMinimum?: boolean | number;
196
288
  maxLength?: number;
197
289
  minLength?: number;
198
290
  pattern?: string;
@@ -206,15 +298,38 @@ export declare class SwaggerTypesMapper {
206
298
  'x-enumNames'?: string[];
207
299
  };
208
300
  name?: string | number | object;
209
- type?: import("@nestjs/common").Type<unknown> & string;
301
+ type?: import("@nestjs/common").Type<unknown> & (string | string[]);
210
302
  in?: import("../interfaces/open-api-spec.interface").ParameterLocation | "body" | "placeholder";
211
303
  isArray?: boolean;
212
- items?: SchemaObject | (SchemaObject & ReferenceObject);
304
+ items?: SchemaObject & (boolean | SchemaObject | ReferenceObject);
213
305
  required?: boolean & string[];
214
306
  enum?: unknown[] & any[];
215
307
  enumName?: string;
216
308
  enumSchema?: import("../interfaces/enum-schema-attributes.interface").EnumSchemaAttributes;
217
309
  selfRequired?: boolean;
310
+ $schema?: string;
311
+ $id?: string;
312
+ $defs?: Record<string, SchemaObject | ReferenceObject>;
313
+ $dynamicAnchor?: string;
314
+ $dynamicRef?: string;
315
+ $anchor?: string;
316
+ const?: any;
317
+ contentMediaType?: string;
318
+ contentEncoding?: string;
319
+ contentSchema?: SchemaObject | ReferenceObject;
320
+ if?: SchemaObject | ReferenceObject;
321
+ then?: SchemaObject | ReferenceObject;
322
+ else?: SchemaObject | ReferenceObject;
323
+ dependentSchemas?: Record<string, SchemaObject | ReferenceObject>;
324
+ dependentRequired?: Record<string, string[]>;
325
+ prefixItems?: (SchemaObject | ReferenceObject)[];
326
+ unevaluatedProperties?: SchemaObject | ReferenceObject | boolean;
327
+ unevaluatedItems?: SchemaObject | ReferenceObject | boolean;
328
+ contains?: SchemaObject | ReferenceObject;
329
+ minContains?: number;
330
+ maxContains?: number;
331
+ $comment?: string;
332
+ propertyNames?: SchemaObject | ReferenceObject;
218
333
  nullable?: boolean;
219
334
  discriminator?: import("../interfaces/open-api-spec.interface").DiscriminatorObject;
220
335
  readOnly?: boolean;
@@ -237,9 +352,9 @@ export declare class SwaggerTypesMapper {
237
352
  title?: string;
238
353
  multipleOf?: number;
239
354
  maximum?: number;
240
- exclusiveMaximum?: boolean;
355
+ exclusiveMaximum?: boolean | number;
241
356
  minimum?: number;
242
- exclusiveMinimum?: boolean;
357
+ exclusiveMinimum?: boolean | number;
243
358
  maxLength?: number;
244
359
  minLength?: number;
245
360
  pattern?: string;
@@ -196,7 +196,9 @@ class SwaggerExplorer {
196
196
  return Object.assign(Object.assign(Object.assign({ method: httpMethodKey, path: fullPath === '' ? '/' : fullPath }, (isWebhook
197
197
  ? {
198
198
  isWebhook: true,
199
- webhookName: typeof webhookMetadata === 'string' ? webhookMetadata : method.name
199
+ webhookName: typeof webhookMetadata === 'string'
200
+ ? webhookMetadata
201
+ : method.name
200
202
  }
201
203
  : {})), { operationId: this.getOperationId(instance, methodKey, pathVersion) }), apiExtension);
202
204
  }));
@@ -21,6 +21,304 @@ const normalize_rel_path_1 = require("./utils/normalize-rel-path");
21
21
  const resolve_path_util_1 = require("./utils/resolve-path.util");
22
22
  const validate_global_prefix_util_1 = require("./utils/validate-global-prefix.util");
23
23
  const validate_path_util_1 = require("./utils/validate-path.util");
24
+ const NULL_TYPE_SCHEMA = { type: 'null' };
25
+ function isReferenceObject(value) {
26
+ return !!(value === null || value === void 0 ? void 0 : value.$ref);
27
+ }
28
+ function isOas31OrAbove(openapi) {
29
+ const [majorStr, minorStr] = (openapi || '').split('.');
30
+ const major = Number(majorStr);
31
+ const minor = Number(minorStr);
32
+ if (Number.isNaN(major) || Number.isNaN(minor)) {
33
+ return false;
34
+ }
35
+ return major > 3 || (major === 3 && minor >= 1);
36
+ }
37
+ function appendNullOption(schemas) {
38
+ const hasNull = schemas.some((item) => !isReferenceObject(item) &&
39
+ (item.type === 'null' ||
40
+ (Array.isArray(item.type) && item.type.includes('null'))));
41
+ return hasNull ? schemas : schemas.concat(NULL_TYPE_SCHEMA);
42
+ }
43
+ function normalizeNullableSchema(schema) {
44
+ if (!schema) {
45
+ return schema;
46
+ }
47
+ if (isReferenceObject(schema)) {
48
+ return schema;
49
+ }
50
+ const converted = Object.assign({}, schema);
51
+ if (converted.properties) {
52
+ converted.properties = Object.entries(converted.properties).reduce((acc, [key, value]) => {
53
+ acc[key] = normalizeNullableSchema(value);
54
+ return acc;
55
+ }, {});
56
+ }
57
+ if (converted.patternProperties) {
58
+ converted.patternProperties = Object.entries(converted.patternProperties).reduce((acc, [key, value]) => {
59
+ acc[key] = normalizeNullableSchema(value);
60
+ return acc;
61
+ }, {});
62
+ }
63
+ if (converted.additionalProperties &&
64
+ typeof converted.additionalProperties === 'object') {
65
+ converted.additionalProperties = normalizeNullableSchema(converted.additionalProperties);
66
+ }
67
+ if (converted.items && typeof converted.items !== 'boolean') {
68
+ converted.items = normalizeNullableSchema(converted.items);
69
+ }
70
+ if (converted.allOf) {
71
+ converted.allOf = converted.allOf.map((item) => normalizeNullableSchema(item));
72
+ }
73
+ if (converted.oneOf) {
74
+ converted.oneOf = converted.oneOf.map((item) => normalizeNullableSchema(item));
75
+ }
76
+ if (converted.anyOf) {
77
+ converted.anyOf = converted.anyOf.map((item) => normalizeNullableSchema(item));
78
+ }
79
+ if (converted.not) {
80
+ converted.not = normalizeNullableSchema(converted.not);
81
+ }
82
+ const exclusiveMinimum = converted.exclusiveMinimum;
83
+ if (typeof exclusiveMinimum === 'boolean') {
84
+ if (exclusiveMinimum === true && typeof converted.minimum === 'number') {
85
+ converted.exclusiveMinimum = converted.minimum;
86
+ delete converted.minimum;
87
+ }
88
+ else {
89
+ delete converted.exclusiveMinimum;
90
+ }
91
+ }
92
+ const exclusiveMaximum = converted.exclusiveMaximum;
93
+ if (typeof exclusiveMaximum === 'boolean') {
94
+ if (exclusiveMaximum === true && typeof converted.maximum === 'number') {
95
+ converted.exclusiveMaximum = converted.maximum;
96
+ delete converted.maximum;
97
+ }
98
+ else {
99
+ delete converted.exclusiveMaximum;
100
+ }
101
+ }
102
+ const isNullable = converted.nullable === true;
103
+ if (converted.nullable !== undefined) {
104
+ delete converted.nullable;
105
+ }
106
+ if (!isNullable) {
107
+ return converted;
108
+ }
109
+ if (converted.type !== undefined) {
110
+ const types = Array.isArray(converted.type)
111
+ ? converted.type
112
+ : [converted.type];
113
+ converted.type = types.includes('null') ? types : [...types, 'null'];
114
+ return converted;
115
+ }
116
+ if (converted.oneOf) {
117
+ converted.oneOf = appendNullOption(converted.oneOf);
118
+ return converted;
119
+ }
120
+ if (converted.anyOf) {
121
+ converted.anyOf = appendNullOption(converted.anyOf);
122
+ return converted;
123
+ }
124
+ if (converted.allOf) {
125
+ return {
126
+ anyOf: appendNullOption([converted])
127
+ };
128
+ }
129
+ return {
130
+ anyOf: appendNullOption([converted])
131
+ };
132
+ }
133
+ function transformMediaType(mediaType) {
134
+ const transformed = Object.assign({}, mediaType);
135
+ if (mediaType.schema) {
136
+ transformed.schema = normalizeNullableSchema(mediaType.schema);
137
+ }
138
+ if (mediaType.itemSchema) {
139
+ transformed.itemSchema = normalizeNullableSchema(mediaType.itemSchema);
140
+ }
141
+ return transformed;
142
+ }
143
+ function transformContent(content) {
144
+ if (!content) {
145
+ return content;
146
+ }
147
+ return Object.entries(content).reduce((acc, [key, value]) => {
148
+ acc[key] = transformMediaType(value);
149
+ return acc;
150
+ }, {});
151
+ }
152
+ function transformParameter(parameter) {
153
+ if (isReferenceObject(parameter)) {
154
+ return parameter;
155
+ }
156
+ const transformed = Object.assign({}, parameter);
157
+ if (parameter.schema) {
158
+ transformed.schema = normalizeNullableSchema(parameter.schema);
159
+ }
160
+ if (parameter.content) {
161
+ transformed.content =
162
+ transformContent(parameter.content) || parameter.content;
163
+ }
164
+ return transformed;
165
+ }
166
+ function transformHeaders(headers) {
167
+ if (!headers) {
168
+ return headers;
169
+ }
170
+ return Object.entries(headers).reduce((acc, [key, value]) => {
171
+ if (isReferenceObject(value)) {
172
+ acc[key] = value;
173
+ return acc;
174
+ }
175
+ const header = value;
176
+ const transformed = Object.assign({}, header);
177
+ if (header.schema) {
178
+ transformed.schema = normalizeNullableSchema(header.schema);
179
+ }
180
+ if (header.content) {
181
+ transformed.content = transformContent(header.content) || header.content;
182
+ }
183
+ acc[key] = transformed;
184
+ return acc;
185
+ }, {});
186
+ }
187
+ function transformRequestBody(requestBody) {
188
+ if (isReferenceObject(requestBody)) {
189
+ return requestBody;
190
+ }
191
+ const transformed = Object.assign({}, requestBody);
192
+ if (requestBody.content) {
193
+ transformed.content =
194
+ transformContent(requestBody.content) || requestBody.content;
195
+ }
196
+ return transformed;
197
+ }
198
+ function transformResponse(response) {
199
+ if (isReferenceObject(response)) {
200
+ return response;
201
+ }
202
+ const transformed = Object.assign({}, response);
203
+ if (response.content) {
204
+ transformed.content =
205
+ transformContent(response.content) || response.content;
206
+ }
207
+ if (response.headers) {
208
+ transformed.headers =
209
+ transformHeaders(response.headers) || response.headers;
210
+ }
211
+ return transformed;
212
+ }
213
+ function transformResponses(responses) {
214
+ return Object.entries(responses).reduce((acc, [status, response]) => {
215
+ if (response === undefined) {
216
+ acc[status] = response;
217
+ return acc;
218
+ }
219
+ acc[status] = transformResponse(response);
220
+ return acc;
221
+ }, {});
222
+ }
223
+ function transformCallbacks(callbacks) {
224
+ return Object.entries(callbacks).reduce((acc, [name, callback]) => {
225
+ if (isReferenceObject(callback)) {
226
+ acc[name] = callback;
227
+ return acc;
228
+ }
229
+ const transformedCallback = {};
230
+ Object.entries(callback).forEach(([path, pathItem]) => {
231
+ transformedCallback[path] = transformPathItem(pathItem);
232
+ });
233
+ acc[name] = transformedCallback;
234
+ return acc;
235
+ }, {});
236
+ }
237
+ function transformOperation(operation) {
238
+ const transformed = Object.assign({}, operation);
239
+ if (operation.parameters) {
240
+ transformed.parameters = operation.parameters.map(transformParameter);
241
+ }
242
+ if (operation.requestBody) {
243
+ transformed.requestBody = transformRequestBody(operation.requestBody);
244
+ }
245
+ if (operation.responses) {
246
+ transformed.responses = transformResponses(operation.responses);
247
+ }
248
+ if (operation.callbacks) {
249
+ transformed.callbacks = transformCallbacks(operation.callbacks);
250
+ }
251
+ return transformed;
252
+ }
253
+ function transformPathItem(pathItem) {
254
+ const transformed = Object.assign({}, pathItem);
255
+ if (pathItem.parameters) {
256
+ transformed.parameters = pathItem.parameters.map(transformParameter);
257
+ }
258
+ const operationKeys = [
259
+ 'get',
260
+ 'put',
261
+ 'post',
262
+ 'delete',
263
+ 'options',
264
+ 'head',
265
+ 'patch',
266
+ 'trace',
267
+ 'search',
268
+ 'query'
269
+ ];
270
+ operationKeys.forEach((operationKey) => {
271
+ const operation = pathItem[operationKey];
272
+ if (operation) {
273
+ transformed[operationKey] = transformOperation(operation);
274
+ }
275
+ });
276
+ return transformed;
277
+ }
278
+ function transformPathItems(paths) {
279
+ if (!paths) {
280
+ return paths;
281
+ }
282
+ return Object.entries(paths).reduce((acc, [path, pathItem]) => {
283
+ acc[path] = transformPathItem(pathItem);
284
+ return acc;
285
+ }, {});
286
+ }
287
+ function normalizeNullableForOas31(document) {
288
+ var _a, _b, _c, _d, _e, _f;
289
+ if ((_a = document.components) === null || _a === void 0 ? void 0 : _a.schemas) {
290
+ Object.entries(document.components.schemas).forEach(([name, schema]) => {
291
+ document.components.schemas[name] = normalizeNullableSchema(schema);
292
+ });
293
+ }
294
+ if ((_b = document.components) === null || _b === void 0 ? void 0 : _b.parameters) {
295
+ Object.entries(document.components.parameters).forEach(([name, parameter]) => {
296
+ document.components.parameters[name] = transformParameter(parameter);
297
+ });
298
+ }
299
+ if ((_c = document.components) === null || _c === void 0 ? void 0 : _c.requestBodies) {
300
+ Object.entries(document.components.requestBodies).forEach(([name, body]) => {
301
+ document.components.requestBodies[name] = transformRequestBody(body);
302
+ });
303
+ }
304
+ if ((_d = document.components) === null || _d === void 0 ? void 0 : _d.responses) {
305
+ Object.entries(document.components.responses).forEach(([name, response]) => {
306
+ document.components.responses[name] = transformResponse(response);
307
+ });
308
+ }
309
+ if ((_e = document.components) === null || _e === void 0 ? void 0 : _e.headers) {
310
+ document.components.headers =
311
+ transformHeaders(document.components.headers) ||
312
+ document.components.headers;
313
+ }
314
+ if ((_f = document.components) === null || _f === void 0 ? void 0 : _f.callbacks) {
315
+ document.components.callbacks = transformCallbacks(document.components.callbacks);
316
+ }
317
+ document.paths = transformPathItems(document.paths) || {};
318
+ if (document.webhooks) {
319
+ document.webhooks = transformPathItems(document.webhooks);
320
+ }
321
+ }
24
322
  class SwaggerModule {
25
323
  static mergeWebhooks(configWebhooks, scannedWebhooks) {
26
324
  if (!configWebhooks && !scannedWebhooks) {
@@ -73,8 +371,16 @@ class SwaggerModule {
73
371
  groupToTags.set(parent, []);
74
372
  groupToSeen.set(parent, new Set());
75
373
  }
76
- const list = groupToTags.get(parent);
77
- const seen = groupToSeen.get(parent);
374
+ let list = groupToTags.get(parent);
375
+ if (!list) {
376
+ list = [];
377
+ groupToTags.set(parent, list);
378
+ }
379
+ let seen = groupToSeen.get(parent);
380
+ if (!seen) {
381
+ seen = new Set();
382
+ groupToSeen.set(parent, seen);
383
+ }
78
384
  if (!seen.has(tag.name)) {
79
385
  seen.add(tag.name);
80
386
  list.push(tag.name);
@@ -107,6 +413,9 @@ class SwaggerModule {
107
413
  const mergedTags = SwaggerModule.mergeTags(config.tags, document.tags);
108
414
  const mergedWebhooks = SwaggerModule.mergeWebhooks(config.webhooks, document.webhooks);
109
415
  const mergedDocument = Object.assign(Object.assign(Object.assign(Object.assign({ openapi: '3.0.0', paths: {} }, config), document), (mergedTags ? { tags: mergedTags } : {})), (mergedWebhooks ? { webhooks: mergedWebhooks } : {}));
416
+ if (isOas31OrAbove(mergedDocument.openapi)) {
417
+ normalizeNullableForOas31(mergedDocument);
418
+ }
110
419
  if (mergedDocument['x-tagGroups'] === undefined) {
111
420
  const xTagGroups = SwaggerModule.buildXTagGroups(mergedDocument.tags);
112
421
  if (xTagGroups) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nestjs-openapi-next",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "A fork of @nestjs/swagger support OAS 3.2",
5
5
  "author": "undownding",
6
6
  "license": "MIT",
@@ -32,14 +32,14 @@
32
32
  "js-yaml": "4.1.1",
33
33
  "lodash": "4.17.21",
34
34
  "path-to-regexp": "8.3.0",
35
- "swagger-ui-dist": "5.30.2"
35
+ "swagger-ui-dist": "5.31.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@commitlint/cli": "20.3.0",
39
39
  "@commitlint/config-angular": "20.3.0",
40
40
  "@eslint/eslintrc": "3.3.3",
41
41
  "@eslint/js": "9.39.2",
42
- "@fastify/static": "8.3.0",
42
+ "@fastify/static": "9.0.0",
43
43
  "@nestjs/common": "11.1.11",
44
44
  "@nestjs/core": "11.1.11",
45
45
  "@nestjs/platform-express": "11.1.11",
@@ -64,15 +64,15 @@
64
64
  "prettier": "3.7.4",
65
65
  "prettier-v2": "npm:prettier@2.8.8",
66
66
  "reflect-metadata": "0.2.2",
67
- "release-it": "19.2.2",
68
- "supertest": "7.1.4",
67
+ "release-it": "19.2.3",
68
+ "supertest": "7.2.2",
69
69
  "swagger-parser": "10.0.3",
70
70
  "ts-jest": "29.4.6",
71
71
  "typescript": "5.9.3",
72
- "typescript-eslint": "8.51.0"
72
+ "typescript-eslint": "8.52.0"
73
73
  },
74
74
  "peerDependencies": {
75
- "@fastify/static": "^8.0.0",
75
+ "@fastify/static": "^8.0.0 || ^9.0.0",
76
76
  "@nestjs/common": "^11.0.1",
77
77
  "@nestjs/core": "^11.0.1",
78
78
  "class-transformer": "*",
@@ -1,70 +0,0 @@
1
- <component name="ProjectCodeStyleConfiguration">
2
- <code_scheme name="Project" version="173">
3
- <HTMLCodeStyleSettings>
4
- <option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
5
- </HTMLCodeStyleSettings>
6
- <JSCodeStyleSettings version="0">
7
- <option name="FORCE_SEMICOLON_STYLE" value="true" />
8
- <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
9
- <option name="FORCE_QUOTE_STYlE" value="true" />
10
- <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
11
- <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
12
- <option name="SPACES_WITHIN_IMPORTS" value="true" />
13
- </JSCodeStyleSettings>
14
- <JetCodeStyleSettings>
15
- <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
16
- </JetCodeStyleSettings>
17
- <TypeScriptCodeStyleSettings version="0">
18
- <option name="FORCE_SEMICOLON_STYLE" value="true" />
19
- <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
20
- <option name="FORCE_QUOTE_STYlE" value="true" />
21
- <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
22
- <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
23
- <option name="SPACES_WITHIN_IMPORTS" value="true" />
24
- </TypeScriptCodeStyleSettings>
25
- <VueCodeStyleSettings>
26
- <option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
27
- <option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
28
- </VueCodeStyleSettings>
29
- <codeStyleSettings language="HTML">
30
- <option name="SOFT_MARGINS" value="80" />
31
- <indentOptions>
32
- <option name="INDENT_SIZE" value="2" />
33
- <option name="CONTINUATION_INDENT_SIZE" value="2" />
34
- <option name="TAB_SIZE" value="2" />
35
- </indentOptions>
36
- </codeStyleSettings>
37
- <codeStyleSettings language="JAVA">
38
- <indentOptions>
39
- <option name="USE_TAB_CHARACTER" value="true" />
40
- <option name="SMART_TABS" value="true" />
41
- </indentOptions>
42
- </codeStyleSettings>
43
- <codeStyleSettings language="JavaScript">
44
- <option name="SOFT_MARGINS" value="80" />
45
- <indentOptions>
46
- <option name="INDENT_SIZE" value="2" />
47
- <option name="CONTINUATION_INDENT_SIZE" value="2" />
48
- <option name="TAB_SIZE" value="2" />
49
- </indentOptions>
50
- </codeStyleSettings>
51
- <codeStyleSettings language="TypeScript">
52
- <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
53
- <option name="SOFT_MARGINS" value="80" />
54
- <indentOptions>
55
- <option name="INDENT_SIZE" value="2" />
56
- <option name="CONTINUATION_INDENT_SIZE" value="2" />
57
- <option name="TAB_SIZE" value="2" />
58
- </indentOptions>
59
- </codeStyleSettings>
60
- <codeStyleSettings language="Vue">
61
- <option name="SOFT_MARGINS" value="80" />
62
- <indentOptions>
63
- <option name="CONTINUATION_INDENT_SIZE" value="2" />
64
- </indentOptions>
65
- </codeStyleSettings>
66
- <codeStyleSettings language="kotlin">
67
- <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
68
- </codeStyleSettings>
69
- </code_scheme>
70
- </component>
@@ -1,5 +0,0 @@
1
- <component name="ProjectCodeStyleConfiguration">
2
- <state>
3
- <option name="USE_PER_PROJECT_SETTINGS" value="true" />
4
- </state>
5
- </component>
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="TypeScriptCompiler">
4
- <option name="useServicePoweredTypesEnabledManually" value="true" />
5
- </component>
6
- </project>
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="AgentMigrationStateService">
4
- <option name="migrationStatus" value="COMPLETED" />
5
- </component>
6
- </project>
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="Ask2AgentMigrationStateService">
4
- <option name="migrationStatus" value="COMPLETED" />
5
- </component>
6
- </project>
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="EditMigrationStateService">
4
- <option name="migrationStatus" value="COMPLETED" />
5
- </component>
6
- </project>
@@ -1,13 +0,0 @@
1
- .idea
2
- .vscode
3
- node_modules/
4
- dist/
5
- vendor/
6
- cache/
7
- .*/
8
- *.min.*
9
- *.test.*
10
- *.spec.*
11
- *.bundle.*
12
- *.bundle-min.*
13
- *.log
@@ -1,6 +0,0 @@
1
- <component name="InspectionProjectProfileManager">
2
- <profile version="1.0">
3
- <option name="myName" value="Project Default" />
4
- <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
- </profile>
6
- </component>
package/.idea/modules.xml DELETED
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="ProjectModuleManager">
4
- <modules>
5
- <module fileurl="file://$PROJECT_DIR$/.idea/nestjs-openapi-next.iml" filepath="$PROJECT_DIR$/.idea/nestjs-openapi-next.iml" />
6
- </modules>
7
- </component>
8
- </project>
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="WEB_MODULE" version="4">
3
- <component name="NewModuleRootManager">
4
- <content url="file://$MODULE_DIR$" />
5
- <orderEntry type="inheritedJdk" />
6
- <orderEntry type="sourceFolder" forTests="false" />
7
- </component>
8
- </module>
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="PrettierConfiguration">
4
- <option name="myConfigurationMode" value="AUTOMATIC" />
5
- </component>
6
- </project>
package/.idea/vcs.xml DELETED
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="VcsDirectoryMappings">
4
- <mapping directory="" vcs="Git" />
5
- </component>
6
- </project>