nestjs-openapi-next 1.0.3 → 1.0.4
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 +1 -1
- package/dist/swagger-module.d.ts +0 -1
- package/dist/swagger-module.js +6 -95
- package/dist/swagger-scanner.js +6 -1
- package/dist/utils/build-x-tag-groups.util.d.ts +5 -0
- package/dist/utils/build-x-tag-groups.util.js +68 -0
- package/dist/utils/collect-operation-tag-names.util.d.ts +2 -0
- package/dist/utils/collect-operation-tag-names.util.js +52 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -100,7 +100,7 @@ This fork treats tag `summary` and `x-displayName` as equivalent display fields:
|
|
|
100
100
|
|
|
101
101
|
#### Auto-derived (recommended)
|
|
102
102
|
|
|
103
|
-
If you use tag `parent` relationships (via `@ApiTag()`), the root-level `x-tagGroups` will be derived automatically:
|
|
103
|
+
If you use tag `parent` relationships (via `@ApiTag()`), the root-level `x-tagGroups` will be derived automatically (both in the scanned output and in the final document), so downstream generators (e.g. `.tags`) can render grouped tags correctly:
|
|
104
104
|
|
|
105
105
|
```ts
|
|
106
106
|
@ApiTag({ name: 'Customers' })
|
package/dist/swagger-module.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { HttpServer } from '@nestjs/common/interfaces/http/http-server.interface
|
|
|
3
3
|
import { OpenAPIObject, SwaggerCustomOptions, SwaggerDocumentOptions } from './interfaces';
|
|
4
4
|
export declare class SwaggerModule {
|
|
5
5
|
private static readonly metadataLoader;
|
|
6
|
-
private static readonly HTTP_METHODS;
|
|
7
6
|
private static collectOperationTagNames;
|
|
8
7
|
private static mergeWebhooks;
|
|
9
8
|
private static mergeTags;
|
package/dist/swagger-module.js
CHANGED
|
@@ -21,6 +21,8 @@ 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 build_x_tag_groups_util_1 = require("./utils/build-x-tag-groups.util");
|
|
25
|
+
const collect_operation_tag_names_util_1 = require("./utils/collect-operation-tag-names.util");
|
|
24
26
|
const NULL_TYPE_SCHEMA = { type: 'null' };
|
|
25
27
|
function isReferenceObject(value) {
|
|
26
28
|
return !!(value === null || value === void 0 ? void 0 : value.$ref);
|
|
@@ -321,41 +323,7 @@ function normalizeNullableForOas31(document) {
|
|
|
321
323
|
}
|
|
322
324
|
class SwaggerModule {
|
|
323
325
|
static collectOperationTagNames(paths, webhooks) {
|
|
324
|
-
|
|
325
|
-
const seen = new Set();
|
|
326
|
-
const collectFromItems = (items) => {
|
|
327
|
-
if (!items) {
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
for (const pathItem of Object.values(items)) {
|
|
331
|
-
if (!pathItem || typeof pathItem !== 'object') {
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
for (const [key, operation] of Object.entries(pathItem)) {
|
|
335
|
-
if (!SwaggerModule.HTTP_METHODS.has(String(key).toLowerCase())) {
|
|
336
|
-
continue;
|
|
337
|
-
}
|
|
338
|
-
const tags = operation === null || operation === void 0 ? void 0 : operation.tags;
|
|
339
|
-
if (!Array.isArray(tags)) {
|
|
340
|
-
continue;
|
|
341
|
-
}
|
|
342
|
-
for (const t of tags) {
|
|
343
|
-
if (typeof t !== 'string') {
|
|
344
|
-
continue;
|
|
345
|
-
}
|
|
346
|
-
const trimmed = t.trim();
|
|
347
|
-
if (!trimmed || seen.has(trimmed)) {
|
|
348
|
-
continue;
|
|
349
|
-
}
|
|
350
|
-
seen.add(trimmed);
|
|
351
|
-
names.push(trimmed);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
|
-
collectFromItems(paths);
|
|
357
|
-
collectFromItems(webhooks);
|
|
358
|
-
return names;
|
|
326
|
+
return (0, collect_operation_tag_names_util_1.collectOperationTagNames)(paths, webhooks);
|
|
359
327
|
}
|
|
360
328
|
static mergeWebhooks(configWebhooks, scannedWebhooks) {
|
|
361
329
|
if (!configWebhooks && !scannedWebhooks) {
|
|
@@ -401,55 +369,8 @@ class SwaggerModule {
|
|
|
401
369
|
const merged = [...byName.values()];
|
|
402
370
|
return merged.length > 0 ? merged : undefined;
|
|
403
371
|
}
|
|
404
|
-
static buildXTagGroups(tags) {
|
|
405
|
-
|
|
406
|
-
return undefined;
|
|
407
|
-
}
|
|
408
|
-
const groupToTags = new Map();
|
|
409
|
-
const groupToSeen = new Map();
|
|
410
|
-
for (const tag of tags) {
|
|
411
|
-
const parent = tag.parent;
|
|
412
|
-
if (!parent) {
|
|
413
|
-
continue;
|
|
414
|
-
}
|
|
415
|
-
if (!groupToTags.has(parent)) {
|
|
416
|
-
groupToTags.set(parent, []);
|
|
417
|
-
groupToSeen.set(parent, new Set());
|
|
418
|
-
}
|
|
419
|
-
let list = groupToTags.get(parent);
|
|
420
|
-
if (!list) {
|
|
421
|
-
list = [];
|
|
422
|
-
groupToTags.set(parent, list);
|
|
423
|
-
}
|
|
424
|
-
let seen = groupToSeen.get(parent);
|
|
425
|
-
if (!seen) {
|
|
426
|
-
seen = new Set();
|
|
427
|
-
groupToSeen.set(parent, seen);
|
|
428
|
-
}
|
|
429
|
-
if (!seen.has(tag.name)) {
|
|
430
|
-
seen.add(tag.name);
|
|
431
|
-
list.push(tag.name);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
if (groupToTags.size === 0) {
|
|
435
|
-
return undefined;
|
|
436
|
-
}
|
|
437
|
-
const allTagNames = new Set(tags.map((t) => t.name));
|
|
438
|
-
return [...groupToTags.entries()].map(([name, childTags]) => {
|
|
439
|
-
const finalTags = [];
|
|
440
|
-
const seen = new Set();
|
|
441
|
-
if (allTagNames.has(name)) {
|
|
442
|
-
seen.add(name);
|
|
443
|
-
finalTags.push(name);
|
|
444
|
-
}
|
|
445
|
-
for (const t of childTags) {
|
|
446
|
-
if (!seen.has(t)) {
|
|
447
|
-
seen.add(t);
|
|
448
|
-
finalTags.push(t);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
return { name, tags: finalTags };
|
|
452
|
-
});
|
|
372
|
+
static buildXTagGroups(tags, operationTagNames) {
|
|
373
|
+
return (0, build_x_tag_groups_util_1.buildXTagGroups)(tags, operationTagNames);
|
|
453
374
|
}
|
|
454
375
|
static createDocument(app, config, options = {}) {
|
|
455
376
|
const swaggerScanner = new swagger_scanner_1.SwaggerScanner();
|
|
@@ -463,7 +384,7 @@ class SwaggerModule {
|
|
|
463
384
|
normalizeNullableForOas31(mergedDocument);
|
|
464
385
|
}
|
|
465
386
|
if (mergedDocument['x-tagGroups'] === undefined) {
|
|
466
|
-
const xTagGroups = SwaggerModule.buildXTagGroups(mergedDocument.tags);
|
|
387
|
+
const xTagGroups = SwaggerModule.buildXTagGroups(mergedDocument.tags, operationTagNames);
|
|
467
388
|
if (xTagGroups) {
|
|
468
389
|
mergedDocument['x-tagGroups'] = xTagGroups;
|
|
469
390
|
}
|
|
@@ -636,13 +557,3 @@ class SwaggerModule {
|
|
|
636
557
|
}
|
|
637
558
|
exports.SwaggerModule = SwaggerModule;
|
|
638
559
|
SwaggerModule.metadataLoader = new metadata_loader_1.MetadataLoader();
|
|
639
|
-
SwaggerModule.HTTP_METHODS = new Set([
|
|
640
|
-
'get',
|
|
641
|
-
'put',
|
|
642
|
-
'post',
|
|
643
|
-
'delete',
|
|
644
|
-
'options',
|
|
645
|
-
'head',
|
|
646
|
-
'patch',
|
|
647
|
-
'trace'
|
|
648
|
-
]);
|
package/dist/swagger-scanner.js
CHANGED
|
@@ -11,6 +11,8 @@ const swagger_explorer_1 = require("./swagger-explorer");
|
|
|
11
11
|
const swagger_transformer_1 = require("./swagger-transformer");
|
|
12
12
|
const get_global_prefix_1 = require("./utils/get-global-prefix");
|
|
13
13
|
const strip_last_slash_util_1 = require("./utils/strip-last-slash.util");
|
|
14
|
+
const build_x_tag_groups_util_1 = require("./utils/build-x-tag-groups.util");
|
|
15
|
+
const collect_operation_tag_names_util_1 = require("./utils/collect-operation-tag-names.util");
|
|
14
16
|
class SwaggerScanner {
|
|
15
17
|
constructor() {
|
|
16
18
|
this.transformer = new swagger_transformer_1.SwaggerTransformer();
|
|
@@ -56,7 +58,10 @@ class SwaggerScanner {
|
|
|
56
58
|
});
|
|
57
59
|
const schemas = this.explorer.getSchemas();
|
|
58
60
|
this.addExtraModels(schemas, extraModels);
|
|
59
|
-
|
|
61
|
+
const normalized = this.transformer.normalizePaths((0, lodash_1.flatten)(denormalizedPaths));
|
|
62
|
+
const operationTagNames = (0, collect_operation_tag_names_util_1.collectOperationTagNames)(normalized.paths, normalized.webhooks);
|
|
63
|
+
const xTagGroups = (0, build_x_tag_groups_util_1.buildXTagGroups)(tagGroups, operationTagNames);
|
|
64
|
+
return Object.assign(Object.assign(Object.assign(Object.assign({}, normalized), (tagGroups.length > 0 ? { tags: tagGroups } : {})), (xTagGroups ? { 'x-tagGroups': xTagGroups } : {})), { components: {
|
|
60
65
|
schemas: schemas
|
|
61
66
|
} });
|
|
62
67
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildXTagGroups = buildXTagGroups;
|
|
4
|
+
function buildXTagGroups(tags, operationTagNames) {
|
|
5
|
+
const opNames = new Set((operationTagNames || [])
|
|
6
|
+
.filter((t) => typeof t === 'string')
|
|
7
|
+
.map((t) => t.trim())
|
|
8
|
+
.filter(Boolean));
|
|
9
|
+
if ((!tags || tags.length === 0) && opNames.size === 0) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const groupToChildTags = new Map();
|
|
13
|
+
const groupToSeen = new Map();
|
|
14
|
+
const childToParent = new Map();
|
|
15
|
+
for (const tag of tags || []) {
|
|
16
|
+
const parent = tag.parent;
|
|
17
|
+
if (!parent) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
childToParent.set(tag.name, parent);
|
|
21
|
+
if (!groupToChildTags.has(parent)) {
|
|
22
|
+
groupToChildTags.set(parent, []);
|
|
23
|
+
groupToSeen.set(parent, new Set());
|
|
24
|
+
}
|
|
25
|
+
let list = groupToChildTags.get(parent);
|
|
26
|
+
if (!list) {
|
|
27
|
+
list = [];
|
|
28
|
+
groupToChildTags.set(parent, list);
|
|
29
|
+
}
|
|
30
|
+
let seen = groupToSeen.get(parent);
|
|
31
|
+
if (!seen) {
|
|
32
|
+
seen = new Set();
|
|
33
|
+
groupToSeen.set(parent, seen);
|
|
34
|
+
}
|
|
35
|
+
if (!seen.has(tag.name)) {
|
|
36
|
+
seen.add(tag.name);
|
|
37
|
+
list.push(tag.name);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const name of opNames) {
|
|
41
|
+
if (childToParent.has(name)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (!groupToChildTags.has(name)) {
|
|
45
|
+
groupToChildTags.set(name, []);
|
|
46
|
+
groupToSeen.set(name, new Set());
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (groupToChildTags.size === 0) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const allTagNames = new Set((tags || []).map((t) => t.name));
|
|
53
|
+
return [...groupToChildTags.entries()].map(([name, childTags]) => {
|
|
54
|
+
const finalTags = [];
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
if (allTagNames.has(name) || opNames.has(name)) {
|
|
57
|
+
seen.add(name);
|
|
58
|
+
finalTags.push(name);
|
|
59
|
+
}
|
|
60
|
+
for (const t of childTags) {
|
|
61
|
+
if (!seen.has(t)) {
|
|
62
|
+
seen.add(t);
|
|
63
|
+
finalTags.push(t);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { name, tags: finalTags };
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectOperationTagNames = collectOperationTagNames;
|
|
4
|
+
const HTTP_METHODS = new Set([
|
|
5
|
+
'get',
|
|
6
|
+
'put',
|
|
7
|
+
'post',
|
|
8
|
+
'delete',
|
|
9
|
+
'options',
|
|
10
|
+
'head',
|
|
11
|
+
'patch',
|
|
12
|
+
'trace',
|
|
13
|
+
'search',
|
|
14
|
+
'query'
|
|
15
|
+
]);
|
|
16
|
+
function collectOperationTagNames(paths, webhooks) {
|
|
17
|
+
const names = [];
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
const collectFromItems = (items) => {
|
|
20
|
+
if (!items) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
for (const pathItem of Object.values(items)) {
|
|
24
|
+
if (!pathItem || typeof pathItem !== 'object') {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
for (const [key, operation] of Object.entries(pathItem)) {
|
|
28
|
+
if (!HTTP_METHODS.has(String(key).toLowerCase())) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const tags = operation === null || operation === void 0 ? void 0 : operation.tags;
|
|
32
|
+
if (!Array.isArray(tags)) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
for (const t of tags) {
|
|
36
|
+
if (typeof t !== 'string') {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const trimmed = t.trim();
|
|
40
|
+
if (!trimmed || seen.has(trimmed)) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
seen.add(trimmed);
|
|
44
|
+
names.push(trimmed);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
collectFromItems(paths);
|
|
50
|
+
collectFromItems(webhooks);
|
|
51
|
+
return names;
|
|
52
|
+
}
|