@globalart/nestjs-swagger 1.3.0 → 1.4.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/dist/index.cjs +95 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -1
- package/dist/index.d.mts +22 -1
- package/dist/index.mjs +91 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -9
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value:
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let _nestjs_common = require("@nestjs/common");
|
|
3
3
|
let _nestjs_swagger = require("@nestjs/swagger");
|
|
4
|
-
|
|
5
4
|
//#region src/constants.ts
|
|
6
5
|
const API_RESPONSE_DESCRIPTION = "If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text";
|
|
7
6
|
const ERROR_DESCRIPTIONS = {
|
|
@@ -15,22 +14,19 @@ const ERROR_DESCRIPTIONS = {
|
|
|
15
14
|
INTERNAL_SERVER_ERROR: "Internal server error",
|
|
16
15
|
SERVICE_UNAVAILABLE: "Service temporarily unavailable"
|
|
17
16
|
};
|
|
18
|
-
|
|
19
17
|
//#endregion
|
|
20
|
-
//#region \0@oxc-project+runtime@0.
|
|
18
|
+
//#region \0@oxc-project+runtime@0.115.0/helpers/decorateMetadata.js
|
|
21
19
|
function __decorateMetadata(k, v) {
|
|
22
20
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
23
21
|
}
|
|
24
|
-
|
|
25
22
|
//#endregion
|
|
26
|
-
//#region \0@oxc-project+runtime@0.
|
|
23
|
+
//#region \0@oxc-project+runtime@0.115.0/helpers/decorate.js
|
|
27
24
|
function __decorate(decorators, target, key, desc) {
|
|
28
25
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
29
26
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
30
27
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
31
28
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
32
29
|
}
|
|
33
|
-
|
|
34
30
|
//#endregion
|
|
35
31
|
//#region src/dtos/index.ts
|
|
36
32
|
var PaginatedResponseDto = class {
|
|
@@ -42,7 +38,6 @@ var PaginatedResponseDto = class {
|
|
|
42
38
|
__decorate([(0, _nestjs_swagger.ApiProperty)(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "totalCount", void 0);
|
|
43
39
|
__decorate([(0, _nestjs_swagger.ApiProperty)(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "offset", void 0);
|
|
44
40
|
__decorate([(0, _nestjs_swagger.ApiProperty)(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "limit", void 0);
|
|
45
|
-
|
|
46
41
|
//#endregion
|
|
47
42
|
//#region src/decorators/index.ts
|
|
48
43
|
const SwaggerDocumentation = (data) => {
|
|
@@ -79,9 +74,100 @@ const SwaggerDocumentation = (data) => {
|
|
|
79
74
|
else decorators.push((0, _nestjs_swagger.ApiOkResponse)({ description: API_RESPONSE_DESCRIPTION }));
|
|
80
75
|
return (0, _nestjs_common.applyDecorators)(...decorators);
|
|
81
76
|
};
|
|
82
|
-
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/swagger.service.ts
|
|
79
|
+
var OpenApiDocsBuilder = class {
|
|
80
|
+
constructor(doc, metaTags) {
|
|
81
|
+
this.doc = doc;
|
|
82
|
+
this.metaTags = metaTags;
|
|
83
|
+
}
|
|
84
|
+
stripMetaTags() {
|
|
85
|
+
return this.mapOperations((op) => ({
|
|
86
|
+
...op,
|
|
87
|
+
tags: this.removeMeta(op.tags)
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
filterByTag(tag) {
|
|
91
|
+
const filteredPaths = {};
|
|
92
|
+
for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {
|
|
93
|
+
const filteredMethods = {};
|
|
94
|
+
for (const [method, operation] of Object.entries(methods)) {
|
|
95
|
+
const op = operation;
|
|
96
|
+
if (op.tags?.includes(tag)) filteredMethods[method] = {
|
|
97
|
+
...op,
|
|
98
|
+
tags: this.removeMeta(op.tags)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (Object.keys(filteredMethods).length > 0) filteredPaths[path] = filteredMethods;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
...this.doc,
|
|
105
|
+
paths: filteredPaths
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
mapOperations(fn) {
|
|
109
|
+
const paths = {};
|
|
110
|
+
for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {
|
|
111
|
+
const mapped = {};
|
|
112
|
+
for (const [method, operation] of Object.entries(methods)) mapped[method] = fn(operation);
|
|
113
|
+
paths[path] = mapped;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
...this.doc,
|
|
117
|
+
paths
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
removeMeta(tags) {
|
|
121
|
+
return (tags ?? []).filter((t) => !this.metaTags.includes(t));
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
let SwaggerService = class SwaggerService {
|
|
125
|
+
app = null;
|
|
126
|
+
documents = {};
|
|
127
|
+
versions = [];
|
|
128
|
+
metaTags = [
|
|
129
|
+
"protected",
|
|
130
|
+
"private",
|
|
131
|
+
"support"
|
|
132
|
+
];
|
|
133
|
+
setApp(app) {
|
|
134
|
+
this.app = app;
|
|
135
|
+
}
|
|
136
|
+
setVersions(versions) {
|
|
137
|
+
this.versions = versions;
|
|
138
|
+
}
|
|
139
|
+
setMetaTags(tags) {
|
|
140
|
+
this.metaTags = tags;
|
|
141
|
+
}
|
|
142
|
+
getDocument(key, serverUrl) {
|
|
143
|
+
const doc = this.documents[key];
|
|
144
|
+
if (!doc) return void 0;
|
|
145
|
+
if (!serverUrl) return doc;
|
|
146
|
+
return {
|
|
147
|
+
...doc,
|
|
148
|
+
servers: [{ url: serverUrl }]
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
init() {
|
|
152
|
+
if (!this.app) throw new Error("App not found");
|
|
153
|
+
for (const version of this.versions) {
|
|
154
|
+
const { config, filterTag } = version;
|
|
155
|
+
const builder = new OpenApiDocsBuilder(_nestjs_swagger.SwaggerModule.createDocument(this.app, config), this.metaTags);
|
|
156
|
+
const document = filterTag ? builder.filterByTag(filterTag) : builder.stripMetaTags();
|
|
157
|
+
this.documents[version.name] = document;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
SwaggerService = __decorate([(0, _nestjs_common.Injectable)()], SwaggerService);
|
|
83
162
|
//#endregion
|
|
84
163
|
exports.API_RESPONSE_DESCRIPTION = API_RESPONSE_DESCRIPTION;
|
|
85
164
|
exports.ERROR_DESCRIPTIONS = ERROR_DESCRIPTIONS;
|
|
86
165
|
exports.SwaggerDocumentation = SwaggerDocumentation;
|
|
166
|
+
Object.defineProperty(exports, "SwaggerService", {
|
|
167
|
+
enumerable: true,
|
|
168
|
+
get: function() {
|
|
169
|
+
return SwaggerService;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
87
173
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/constants.ts","../src/dtos/index.ts","../src/decorators/index.ts"],"sourcesContent":["export const API_RESPONSE_DESCRIPTION =\n \"If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text\";\n\nexport const ERROR_DESCRIPTIONS = {\n BAD_REQUEST: \"Invalid request data or parameters\",\n UNAUTHORIZED: \"Authentication required\",\n FORBIDDEN: \"Access denied\",\n NOT_FOUND: \"Resource not found\",\n CONFLICT: \"Resource already exists or conflict detected\",\n UNPROCESSABLE_ENTITY: \"Validation error\",\n RATE_LIMIT_EXCEEDED: \"Rate limit exceeded. Too many requests\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n SERVICE_UNAVAILABLE: \"Service temporarily unavailable\",\n};\n","import { ApiProperty } from \"@nestjs/swagger\";\n\nexport class PaginatedResponseDto<T> {\n data!: T[];\n\n @ApiProperty()\n totalCount!: number;\n\n @ApiProperty()\n offset!: number;\n\n @ApiProperty()\n limit!: number;\n}\n","import { applyDecorators } from \"@nestjs/common\";\nimport {\n ApiBadRequestResponse,\n ApiConflictResponse,\n ApiExtraModels,\n ApiForbiddenResponse,\n ApiInternalServerErrorResponse,\n ApiNotFoundResponse,\n ApiOkResponse,\n ApiOperation,\n ApiServiceUnavailableResponse,\n ApiTooManyRequestsResponse,\n ApiUnauthorizedResponse,\n ApiUnprocessableEntityResponse,\n getSchemaPath,\n} from \"@nestjs/swagger\";\nimport { API_RESPONSE_DESCRIPTION } from \"../constants\";\nimport { PaginatedResponseDto } from \"../dtos\";\nimport { SwaggerDocumentationOptions } from \"../interfaces\";\nimport { createHash } from \"crypto\";\n\n// SwaggerDocumentation is a decorator function to generate Swagger documentation for endpoints based on the provided options.\nexport const SwaggerDocumentation = (data: SwaggerDocumentationOptions) => {\n const operationId = data.operationId;\n\n const decorators = [\n ApiOperation({\n operationId,\n description: data.endpointDescription,\n summary: data.endpointSummary,\n deprecated: data.deprecated,\n }),\n ];\n\n if (data.error400Description) {\n decorators.push(\n ApiBadRequestResponse({\n description: data.error400Description,\n })\n );\n }\n\n if (data.error401Description) {\n decorators.push(\n ApiUnauthorizedResponse({\n description: data.error401Description,\n })\n );\n }\n\n if (data.error403Description) {\n decorators.push(\n ApiForbiddenResponse({\n description: data.error403Description,\n })\n );\n }\n\n if (data.error404Description) {\n decorators.push(\n ApiNotFoundResponse({\n description: data.error404Description,\n })\n );\n }\n\n if (data.error409Description) {\n decorators.push(\n ApiConflictResponse({\n description: data.error409Description,\n })\n );\n }\n\n if (data.error422Description) {\n decorators.push(\n ApiUnprocessableEntityResponse({\n description: data.error422Description,\n })\n );\n }\n\n if (data.error429Description) {\n decorators.push(\n ApiTooManyRequestsResponse({\n description: data.error429Description,\n })\n );\n }\n\n if (data.error500Description) {\n decorators.push(\n ApiInternalServerErrorResponse({\n description: data.error500Description,\n })\n );\n }\n\n if (data.error503Description) {\n decorators.push(\n ApiServiceUnavailableResponse({\n description: data.error503Description,\n })\n );\n }\n\n if (data.isPaginated && data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: {\n allOf: [\n { $ref: getSchemaPath(PaginatedResponseDto) },\n {\n properties: {\n data: {\n type: \"array\",\n items: {\n $ref: getSchemaPath(data.responseDto),\n },\n },\n },\n },\n ],\n },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto, PaginatedResponseDto)\n );\n } else if (data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: data.isArray\n ? {\n type: \"array\",\n items: { $ref: getSchemaPath(data.responseDto) },\n }\n : { $ref: getSchemaPath(data.responseDto) },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto)\n );\n } else {\n decorators.push(\n ApiOkResponse({\n description: API_RESPONSE_DESCRIPTION,\n })\n );\n }\n\n return applyDecorators(...decorators);\n};\n"],"mappings":";;;;;AAAA,MAAa,2BACX;AAEF,MAAa,qBAAqB;CAChC,aAAa;CACb,cAAc;CACd,WAAW;CACX,WAAW;CACX,UAAU;CACV,sBAAsB;CACtB,qBAAqB;CACrB,uBAAuB;CACvB,qBAAqB;CACtB;;;;;;;;;;;;;;;;;;;ACXD,IAAa,uBAAb,MAAqC;CACnC;CAEA,AACA;CAEA,AACA;CAEA,AACA;;8CAPc;8CAGA;8CAGA;;;;ACWhB,MAAa,wBAAwB,SAAsC;CACzE,MAAM,cAAc,KAAK;CAEzB,MAAM,aAAa,mCACJ;EACX;EACA,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,YAAY,KAAK;EAClB,CAAC,CACH;AAED,KAAI,KAAK,oBACP,YAAW,gDACa,EACpB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,kDACe,EACtB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,+CACY,EACnB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,8CACW,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,8CACW,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,yDACsB,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,qDACkB,EACzB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,yDACsB,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,wDACqB,EAC5B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,eAAe,KAAK,YAC3B,YAAW,wCACK;EACZ,QAAQ,EACN,OAAO,CACL,EAAE,yCAAoB,qBAAqB,EAAE,EAC7C,EACE,YAAY,EACV,MAAM;GACJ,MAAM;GACN,OAAO,EACL,yCAAoB,KAAK,YAAY,EACtC;GACF,EACF,EACF,CACF,EACF;EACD,aAAa;EACd,CAAC,sCACa,KAAK,aAAa,qBAAqB,CACvD;UACQ,KAAK,YACd,YAAW,wCACK;EACZ,QAAQ,KAAK,UACT;GACE,MAAM;GACN,OAAO,EAAE,yCAAoB,KAAK,YAAY,EAAE;GACjD,GACD,EAAE,yCAAoB,KAAK,YAAY,EAAE;EAC7C,aAAa;EACd,CAAC,sCACa,KAAK,YAAY,CACjC;KAED,YAAW,wCACK,EACZ,aAAa,0BACd,CAAC,CACH;AAGH,4CAAuB,GAAG,WAAW"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["SwaggerModule"],"sources":["../src/constants.ts","../src/dtos/index.ts","../src/decorators/index.ts","../src/swagger.service.ts"],"sourcesContent":["export const API_RESPONSE_DESCRIPTION =\n \"If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text\";\n\nexport const ERROR_DESCRIPTIONS = {\n BAD_REQUEST: \"Invalid request data or parameters\",\n UNAUTHORIZED: \"Authentication required\",\n FORBIDDEN: \"Access denied\",\n NOT_FOUND: \"Resource not found\",\n CONFLICT: \"Resource already exists or conflict detected\",\n UNPROCESSABLE_ENTITY: \"Validation error\",\n RATE_LIMIT_EXCEEDED: \"Rate limit exceeded. Too many requests\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n SERVICE_UNAVAILABLE: \"Service temporarily unavailable\",\n};\n","import { ApiProperty } from \"@nestjs/swagger\";\n\nexport class PaginatedResponseDto<T> {\n data!: T[];\n\n @ApiProperty()\n totalCount!: number;\n\n @ApiProperty()\n offset!: number;\n\n @ApiProperty()\n limit!: number;\n}\n","import { applyDecorators } from \"@nestjs/common\";\nimport {\n ApiBadRequestResponse,\n ApiConflictResponse,\n ApiExtraModels,\n ApiForbiddenResponse,\n ApiInternalServerErrorResponse,\n ApiNotFoundResponse,\n ApiOkResponse,\n ApiOperation,\n ApiServiceUnavailableResponse,\n ApiTooManyRequestsResponse,\n ApiUnauthorizedResponse,\n ApiUnprocessableEntityResponse,\n getSchemaPath,\n} from \"@nestjs/swagger\";\nimport { API_RESPONSE_DESCRIPTION } from \"../constants\";\nimport { PaginatedResponseDto } from \"../dtos\";\nimport { SwaggerDocumentationOptions } from \"../interfaces\";\nimport { createHash } from \"crypto\";\n\n// SwaggerDocumentation is a decorator function to generate Swagger documentation for endpoints based on the provided options.\nexport const SwaggerDocumentation = (data: SwaggerDocumentationOptions) => {\n const operationId = data.operationId;\n\n const decorators = [\n ApiOperation({\n operationId,\n description: data.endpointDescription,\n summary: data.endpointSummary,\n deprecated: data.deprecated,\n }),\n ];\n\n if (data.error400Description) {\n decorators.push(\n ApiBadRequestResponse({\n description: data.error400Description,\n })\n );\n }\n\n if (data.error401Description) {\n decorators.push(\n ApiUnauthorizedResponse({\n description: data.error401Description,\n })\n );\n }\n\n if (data.error403Description) {\n decorators.push(\n ApiForbiddenResponse({\n description: data.error403Description,\n })\n );\n }\n\n if (data.error404Description) {\n decorators.push(\n ApiNotFoundResponse({\n description: data.error404Description,\n })\n );\n }\n\n if (data.error409Description) {\n decorators.push(\n ApiConflictResponse({\n description: data.error409Description,\n })\n );\n }\n\n if (data.error422Description) {\n decorators.push(\n ApiUnprocessableEntityResponse({\n description: data.error422Description,\n })\n );\n }\n\n if (data.error429Description) {\n decorators.push(\n ApiTooManyRequestsResponse({\n description: data.error429Description,\n })\n );\n }\n\n if (data.error500Description) {\n decorators.push(\n ApiInternalServerErrorResponse({\n description: data.error500Description,\n })\n );\n }\n\n if (data.error503Description) {\n decorators.push(\n ApiServiceUnavailableResponse({\n description: data.error503Description,\n })\n );\n }\n\n if (data.isPaginated && data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: {\n allOf: [\n { $ref: getSchemaPath(PaginatedResponseDto) },\n {\n properties: {\n data: {\n type: \"array\",\n items: {\n $ref: getSchemaPath(data.responseDto),\n },\n },\n },\n },\n ],\n },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto, PaginatedResponseDto)\n );\n } else if (data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: data.isArray\n ? {\n type: \"array\",\n items: { $ref: getSchemaPath(data.responseDto) },\n }\n : { $ref: getSchemaPath(data.responseDto) },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto)\n );\n } else {\n decorators.push(\n ApiOkResponse({\n description: API_RESPONSE_DESCRIPTION,\n })\n );\n }\n\n return applyDecorators(...decorators);\n};\n","import { INestApplication, Injectable } from '@nestjs/common';\nimport { OpenAPIObject, SwaggerModule } from '@nestjs/swagger';\n\ntype Paths = OpenAPIObject['paths'];\n\nclass OpenApiDocsBuilder {\n constructor(\n private readonly doc: OpenAPIObject,\n private readonly metaTags: string[],\n ) {}\n\n stripMetaTags(): OpenAPIObject {\n return this.mapOperations((op) => ({ ...op, tags: this.removeMeta(op.tags) }));\n }\n\n filterByTag(tag: string): OpenAPIObject {\n const filteredPaths: Paths = {};\n for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {\n const filteredMethods: Record<string, unknown> = {};\n for (const [method, operation] of Object.entries(methods as Record<string, unknown>)) {\n const op = operation as { tags?: string[] };\n if (op.tags?.includes(tag)) {\n filteredMethods[method] = { ...op, tags: this.removeMeta(op.tags) };\n }\n }\n if (Object.keys(filteredMethods).length > 0) {\n filteredPaths[path] = filteredMethods as Paths[string];\n }\n }\n return { ...this.doc, paths: filteredPaths };\n }\n\n private mapOperations(fn: (op: { tags?: string[] }) => unknown): OpenAPIObject {\n const paths: Paths = {};\n for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {\n const mapped: Record<string, unknown> = {};\n for (const [method, operation] of Object.entries(methods as Record<string, unknown>)) {\n mapped[method] = fn(operation as { tags?: string[] });\n }\n paths[path] = mapped as Paths[string];\n }\n return { ...this.doc, paths };\n }\n\n private removeMeta(tags?: string[]): string[] {\n return (tags ?? []).filter((t) => !this.metaTags.includes(t));\n }\n}\n\ninterface Version {\n name: string;\n url: string;\n config: Omit<OpenAPIObject, 'paths'>;\n filterTag?: string;\n}\n\n@Injectable()\nexport class SwaggerService {\n private app: INestApplication | null = null;\n private documents: Record<string, OpenAPIObject> = {};\n private versions: Version[] = [];\n private metaTags: string[] = ['protected', 'private', 'support'];\n\n setApp(app: any) {\n this.app = app;\n }\n\n setVersions(versions: Version[]) {\n this.versions = versions;\n }\n\n setMetaTags(tags: string[]) {\n this.metaTags = tags;\n }\n\n getDocument(key: string, serverUrl?: string): OpenAPIObject | undefined {\n const doc = this.documents[key];\n if (!doc) return undefined;\n if (!serverUrl) return doc;\n return { ...doc, servers: [{ url: serverUrl }] };\n }\n\n init() {\n if (!this.app) {\n throw new Error('App not found');\n }\n\n for (const version of this.versions) {\n const { config, filterTag } = version;\n const tempDoc = SwaggerModule.createDocument(this.app, config);\n const builder = new OpenApiDocsBuilder(tempDoc, this.metaTags);\n\n const document = filterTag\n ? builder.filterByTag(filterTag)\n : builder.stripMetaTags();\n\n this.documents[version.name] = document;\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { OpenAPIObject } from "@nestjs/swagger";
|
|
2
|
+
|
|
1
3
|
//#region src/constants.d.ts
|
|
2
4
|
declare const API_RESPONSE_DESCRIPTION = "If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text";
|
|
3
5
|
declare const ERROR_DESCRIPTIONS: {
|
|
@@ -37,5 +39,24 @@ interface SwaggerDocumentationOptions extends SwaggerDocumentationErrorStatus {
|
|
|
37
39
|
//#region src/decorators/index.d.ts
|
|
38
40
|
declare const SwaggerDocumentation: (data: SwaggerDocumentationOptions) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
39
41
|
//#endregion
|
|
40
|
-
|
|
42
|
+
//#region src/swagger.service.d.ts
|
|
43
|
+
interface Version {
|
|
44
|
+
name: string;
|
|
45
|
+
url: string;
|
|
46
|
+
config: Omit<OpenAPIObject, 'paths'>;
|
|
47
|
+
filterTag?: string;
|
|
48
|
+
}
|
|
49
|
+
declare class SwaggerService {
|
|
50
|
+
private app;
|
|
51
|
+
private documents;
|
|
52
|
+
private versions;
|
|
53
|
+
private metaTags;
|
|
54
|
+
setApp(app: any): void;
|
|
55
|
+
setVersions(versions: Version[]): void;
|
|
56
|
+
setMetaTags(tags: string[]): void;
|
|
57
|
+
getDocument(key: string, serverUrl?: string): OpenAPIObject | undefined;
|
|
58
|
+
init(): void;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation, SwaggerDocumentationErrorStatus, SwaggerDocumentationOptions, SwaggerService };
|
|
41
62
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { OpenAPIObject } from "@nestjs/swagger";
|
|
2
|
+
|
|
1
3
|
//#region src/constants.d.ts
|
|
2
4
|
declare const API_RESPONSE_DESCRIPTION = "If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text";
|
|
3
5
|
declare const ERROR_DESCRIPTIONS: {
|
|
@@ -37,5 +39,24 @@ interface SwaggerDocumentationOptions extends SwaggerDocumentationErrorStatus {
|
|
|
37
39
|
//#region src/decorators/index.d.ts
|
|
38
40
|
declare const SwaggerDocumentation: (data: SwaggerDocumentationOptions) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
39
41
|
//#endregion
|
|
40
|
-
|
|
42
|
+
//#region src/swagger.service.d.ts
|
|
43
|
+
interface Version {
|
|
44
|
+
name: string;
|
|
45
|
+
url: string;
|
|
46
|
+
config: Omit<OpenAPIObject, 'paths'>;
|
|
47
|
+
filterTag?: string;
|
|
48
|
+
}
|
|
49
|
+
declare class SwaggerService {
|
|
50
|
+
private app;
|
|
51
|
+
private documents;
|
|
52
|
+
private versions;
|
|
53
|
+
private metaTags;
|
|
54
|
+
setApp(app: any): void;
|
|
55
|
+
setVersions(versions: Version[]): void;
|
|
56
|
+
setMetaTags(tags: string[]): void;
|
|
57
|
+
getDocument(key: string, serverUrl?: string): OpenAPIObject | undefined;
|
|
58
|
+
init(): void;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation, SwaggerDocumentationErrorStatus, SwaggerDocumentationOptions, SwaggerService };
|
|
41
62
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { applyDecorators } from "@nestjs/common";
|
|
2
|
-
import { ApiBadRequestResponse, ApiConflictResponse, ApiExtraModels, ApiForbiddenResponse, ApiInternalServerErrorResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiProperty, ApiServiceUnavailableResponse, ApiTooManyRequestsResponse, ApiUnauthorizedResponse, ApiUnprocessableEntityResponse, getSchemaPath } from "@nestjs/swagger";
|
|
3
|
-
|
|
1
|
+
import { Injectable, applyDecorators } from "@nestjs/common";
|
|
2
|
+
import { ApiBadRequestResponse, ApiConflictResponse, ApiExtraModels, ApiForbiddenResponse, ApiInternalServerErrorResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiProperty, ApiServiceUnavailableResponse, ApiTooManyRequestsResponse, ApiUnauthorizedResponse, ApiUnprocessableEntityResponse, SwaggerModule, getSchemaPath } from "@nestjs/swagger";
|
|
4
3
|
//#region src/constants.ts
|
|
5
4
|
const API_RESPONSE_DESCRIPTION = "If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text";
|
|
6
5
|
const ERROR_DESCRIPTIONS = {
|
|
@@ -14,22 +13,19 @@ const ERROR_DESCRIPTIONS = {
|
|
|
14
13
|
INTERNAL_SERVER_ERROR: "Internal server error",
|
|
15
14
|
SERVICE_UNAVAILABLE: "Service temporarily unavailable"
|
|
16
15
|
};
|
|
17
|
-
|
|
18
16
|
//#endregion
|
|
19
|
-
//#region \0@oxc-project+runtime@0.
|
|
17
|
+
//#region \0@oxc-project+runtime@0.115.0/helpers/decorateMetadata.js
|
|
20
18
|
function __decorateMetadata(k, v) {
|
|
21
19
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
20
|
}
|
|
23
|
-
|
|
24
21
|
//#endregion
|
|
25
|
-
//#region \0@oxc-project+runtime@0.
|
|
22
|
+
//#region \0@oxc-project+runtime@0.115.0/helpers/decorate.js
|
|
26
23
|
function __decorate(decorators, target, key, desc) {
|
|
27
24
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
28
25
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
29
26
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
30
27
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
31
28
|
}
|
|
32
|
-
|
|
33
29
|
//#endregion
|
|
34
30
|
//#region src/dtos/index.ts
|
|
35
31
|
var PaginatedResponseDto = class {
|
|
@@ -41,7 +37,6 @@ var PaginatedResponseDto = class {
|
|
|
41
37
|
__decorate([ApiProperty(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "totalCount", void 0);
|
|
42
38
|
__decorate([ApiProperty(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "offset", void 0);
|
|
43
39
|
__decorate([ApiProperty(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "limit", void 0);
|
|
44
|
-
|
|
45
40
|
//#endregion
|
|
46
41
|
//#region src/decorators/index.ts
|
|
47
42
|
const SwaggerDocumentation = (data) => {
|
|
@@ -78,7 +73,92 @@ const SwaggerDocumentation = (data) => {
|
|
|
78
73
|
else decorators.push(ApiOkResponse({ description: API_RESPONSE_DESCRIPTION }));
|
|
79
74
|
return applyDecorators(...decorators);
|
|
80
75
|
};
|
|
81
|
-
|
|
82
76
|
//#endregion
|
|
83
|
-
|
|
77
|
+
//#region src/swagger.service.ts
|
|
78
|
+
var OpenApiDocsBuilder = class {
|
|
79
|
+
constructor(doc, metaTags) {
|
|
80
|
+
this.doc = doc;
|
|
81
|
+
this.metaTags = metaTags;
|
|
82
|
+
}
|
|
83
|
+
stripMetaTags() {
|
|
84
|
+
return this.mapOperations((op) => ({
|
|
85
|
+
...op,
|
|
86
|
+
tags: this.removeMeta(op.tags)
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
filterByTag(tag) {
|
|
90
|
+
const filteredPaths = {};
|
|
91
|
+
for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {
|
|
92
|
+
const filteredMethods = {};
|
|
93
|
+
for (const [method, operation] of Object.entries(methods)) {
|
|
94
|
+
const op = operation;
|
|
95
|
+
if (op.tags?.includes(tag)) filteredMethods[method] = {
|
|
96
|
+
...op,
|
|
97
|
+
tags: this.removeMeta(op.tags)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (Object.keys(filteredMethods).length > 0) filteredPaths[path] = filteredMethods;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...this.doc,
|
|
104
|
+
paths: filteredPaths
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
mapOperations(fn) {
|
|
108
|
+
const paths = {};
|
|
109
|
+
for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {
|
|
110
|
+
const mapped = {};
|
|
111
|
+
for (const [method, operation] of Object.entries(methods)) mapped[method] = fn(operation);
|
|
112
|
+
paths[path] = mapped;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
...this.doc,
|
|
116
|
+
paths
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
removeMeta(tags) {
|
|
120
|
+
return (tags ?? []).filter((t) => !this.metaTags.includes(t));
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
let SwaggerService = class SwaggerService {
|
|
124
|
+
app = null;
|
|
125
|
+
documents = {};
|
|
126
|
+
versions = [];
|
|
127
|
+
metaTags = [
|
|
128
|
+
"protected",
|
|
129
|
+
"private",
|
|
130
|
+
"support"
|
|
131
|
+
];
|
|
132
|
+
setApp(app) {
|
|
133
|
+
this.app = app;
|
|
134
|
+
}
|
|
135
|
+
setVersions(versions) {
|
|
136
|
+
this.versions = versions;
|
|
137
|
+
}
|
|
138
|
+
setMetaTags(tags) {
|
|
139
|
+
this.metaTags = tags;
|
|
140
|
+
}
|
|
141
|
+
getDocument(key, serverUrl) {
|
|
142
|
+
const doc = this.documents[key];
|
|
143
|
+
if (!doc) return void 0;
|
|
144
|
+
if (!serverUrl) return doc;
|
|
145
|
+
return {
|
|
146
|
+
...doc,
|
|
147
|
+
servers: [{ url: serverUrl }]
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
init() {
|
|
151
|
+
if (!this.app) throw new Error("App not found");
|
|
152
|
+
for (const version of this.versions) {
|
|
153
|
+
const { config, filterTag } = version;
|
|
154
|
+
const builder = new OpenApiDocsBuilder(SwaggerModule.createDocument(this.app, config), this.metaTags);
|
|
155
|
+
const document = filterTag ? builder.filterByTag(filterTag) : builder.stripMetaTags();
|
|
156
|
+
this.documents[version.name] = document;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
SwaggerService = __decorate([Injectable()], SwaggerService);
|
|
161
|
+
//#endregion
|
|
162
|
+
export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation, SwaggerService };
|
|
163
|
+
|
|
84
164
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/constants.ts","../src/dtos/index.ts","../src/decorators/index.ts"],"sourcesContent":["export const API_RESPONSE_DESCRIPTION =\n \"If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text\";\n\nexport const ERROR_DESCRIPTIONS = {\n BAD_REQUEST: \"Invalid request data or parameters\",\n UNAUTHORIZED: \"Authentication required\",\n FORBIDDEN: \"Access denied\",\n NOT_FOUND: \"Resource not found\",\n CONFLICT: \"Resource already exists or conflict detected\",\n UNPROCESSABLE_ENTITY: \"Validation error\",\n RATE_LIMIT_EXCEEDED: \"Rate limit exceeded. Too many requests\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n SERVICE_UNAVAILABLE: \"Service temporarily unavailable\",\n};\n","import { ApiProperty } from \"@nestjs/swagger\";\n\nexport class PaginatedResponseDto<T> {\n data!: T[];\n\n @ApiProperty()\n totalCount!: number;\n\n @ApiProperty()\n offset!: number;\n\n @ApiProperty()\n limit!: number;\n}\n","import { applyDecorators } from \"@nestjs/common\";\nimport {\n ApiBadRequestResponse,\n ApiConflictResponse,\n ApiExtraModels,\n ApiForbiddenResponse,\n ApiInternalServerErrorResponse,\n ApiNotFoundResponse,\n ApiOkResponse,\n ApiOperation,\n ApiServiceUnavailableResponse,\n ApiTooManyRequestsResponse,\n ApiUnauthorizedResponse,\n ApiUnprocessableEntityResponse,\n getSchemaPath,\n} from \"@nestjs/swagger\";\nimport { API_RESPONSE_DESCRIPTION } from \"../constants\";\nimport { PaginatedResponseDto } from \"../dtos\";\nimport { SwaggerDocumentationOptions } from \"../interfaces\";\nimport { createHash } from \"crypto\";\n\n// SwaggerDocumentation is a decorator function to generate Swagger documentation for endpoints based on the provided options.\nexport const SwaggerDocumentation = (data: SwaggerDocumentationOptions) => {\n const operationId = data.operationId;\n\n const decorators = [\n ApiOperation({\n operationId,\n description: data.endpointDescription,\n summary: data.endpointSummary,\n deprecated: data.deprecated,\n }),\n ];\n\n if (data.error400Description) {\n decorators.push(\n ApiBadRequestResponse({\n description: data.error400Description,\n })\n );\n }\n\n if (data.error401Description) {\n decorators.push(\n ApiUnauthorizedResponse({\n description: data.error401Description,\n })\n );\n }\n\n if (data.error403Description) {\n decorators.push(\n ApiForbiddenResponse({\n description: data.error403Description,\n })\n );\n }\n\n if (data.error404Description) {\n decorators.push(\n ApiNotFoundResponse({\n description: data.error404Description,\n })\n );\n }\n\n if (data.error409Description) {\n decorators.push(\n ApiConflictResponse({\n description: data.error409Description,\n })\n );\n }\n\n if (data.error422Description) {\n decorators.push(\n ApiUnprocessableEntityResponse({\n description: data.error422Description,\n })\n );\n }\n\n if (data.error429Description) {\n decorators.push(\n ApiTooManyRequestsResponse({\n description: data.error429Description,\n })\n );\n }\n\n if (data.error500Description) {\n decorators.push(\n ApiInternalServerErrorResponse({\n description: data.error500Description,\n })\n );\n }\n\n if (data.error503Description) {\n decorators.push(\n ApiServiceUnavailableResponse({\n description: data.error503Description,\n })\n );\n }\n\n if (data.isPaginated && data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: {\n allOf: [\n { $ref: getSchemaPath(PaginatedResponseDto) },\n {\n properties: {\n data: {\n type: \"array\",\n items: {\n $ref: getSchemaPath(data.responseDto),\n },\n },\n },\n },\n ],\n },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto, PaginatedResponseDto)\n );\n } else if (data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: data.isArray\n ? {\n type: \"array\",\n items: { $ref: getSchemaPath(data.responseDto) },\n }\n : { $ref: getSchemaPath(data.responseDto) },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto)\n );\n } else {\n decorators.push(\n ApiOkResponse({\n description: API_RESPONSE_DESCRIPTION,\n })\n );\n }\n\n return applyDecorators(...decorators);\n};\n"],"mappings":";;;;AAAA,MAAa,2BACX;AAEF,MAAa,qBAAqB;CAChC,aAAa;CACb,cAAc;CACd,WAAW;CACX,WAAW;CACX,UAAU;CACV,sBAAsB;CACtB,qBAAqB;CACrB,uBAAuB;CACvB,qBAAqB;CACtB;;;;;;;;;;;;;;;;;;;ACXD,IAAa,uBAAb,MAAqC;CACnC;CAEA,AACA;CAEA,AACA;CAEA,AACA;;YAPC,aAAa;YAGb,aAAa;YAGb,aAAa;;;;ACWhB,MAAa,wBAAwB,SAAsC;CACzE,MAAM,cAAc,KAAK;CAEzB,MAAM,aAAa,CACjB,aAAa;EACX;EACA,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,YAAY,KAAK;EAClB,CAAC,CACH;AAED,KAAI,KAAK,oBACP,YAAW,KACT,sBAAsB,EACpB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,wBAAwB,EACtB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,qBAAqB,EACnB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,oBAAoB,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,oBAAoB,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,+BAA+B,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,2BAA2B,EACzB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,+BAA+B,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,8BAA8B,EAC5B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,eAAe,KAAK,YAC3B,YAAW,KACT,cAAc;EACZ,QAAQ,EACN,OAAO,CACL,EAAE,MAAM,cAAc,qBAAqB,EAAE,EAC7C,EACE,YAAY,EACV,MAAM;GACJ,MAAM;GACN,OAAO,EACL,MAAM,cAAc,KAAK,YAAY,EACtC;GACF,EACF,EACF,CACF,EACF;EACD,aAAa;EACd,CAAC,EACF,eAAe,KAAK,aAAa,qBAAqB,CACvD;UACQ,KAAK,YACd,YAAW,KACT,cAAc;EACZ,QAAQ,KAAK,UACT;GACE,MAAM;GACN,OAAO,EAAE,MAAM,cAAc,KAAK,YAAY,EAAE;GACjD,GACD,EAAE,MAAM,cAAc,KAAK,YAAY,EAAE;EAC7C,aAAa;EACd,CAAC,EACF,eAAe,KAAK,YAAY,CACjC;KAED,YAAW,KACT,cAAc,EACZ,aAAa,0BACd,CAAC,CACH;AAGH,QAAO,gBAAgB,GAAG,WAAW"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/constants.ts","../src/dtos/index.ts","../src/decorators/index.ts","../src/swagger.service.ts"],"sourcesContent":["export const API_RESPONSE_DESCRIPTION =\n \"If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text\";\n\nexport const ERROR_DESCRIPTIONS = {\n BAD_REQUEST: \"Invalid request data or parameters\",\n UNAUTHORIZED: \"Authentication required\",\n FORBIDDEN: \"Access denied\",\n NOT_FOUND: \"Resource not found\",\n CONFLICT: \"Resource already exists or conflict detected\",\n UNPROCESSABLE_ENTITY: \"Validation error\",\n RATE_LIMIT_EXCEEDED: \"Rate limit exceeded. Too many requests\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n SERVICE_UNAVAILABLE: \"Service temporarily unavailable\",\n};\n","import { ApiProperty } from \"@nestjs/swagger\";\n\nexport class PaginatedResponseDto<T> {\n data!: T[];\n\n @ApiProperty()\n totalCount!: number;\n\n @ApiProperty()\n offset!: number;\n\n @ApiProperty()\n limit!: number;\n}\n","import { applyDecorators } from \"@nestjs/common\";\nimport {\n ApiBadRequestResponse,\n ApiConflictResponse,\n ApiExtraModels,\n ApiForbiddenResponse,\n ApiInternalServerErrorResponse,\n ApiNotFoundResponse,\n ApiOkResponse,\n ApiOperation,\n ApiServiceUnavailableResponse,\n ApiTooManyRequestsResponse,\n ApiUnauthorizedResponse,\n ApiUnprocessableEntityResponse,\n getSchemaPath,\n} from \"@nestjs/swagger\";\nimport { API_RESPONSE_DESCRIPTION } from \"../constants\";\nimport { PaginatedResponseDto } from \"../dtos\";\nimport { SwaggerDocumentationOptions } from \"../interfaces\";\nimport { createHash } from \"crypto\";\n\n// SwaggerDocumentation is a decorator function to generate Swagger documentation for endpoints based on the provided options.\nexport const SwaggerDocumentation = (data: SwaggerDocumentationOptions) => {\n const operationId = data.operationId;\n\n const decorators = [\n ApiOperation({\n operationId,\n description: data.endpointDescription,\n summary: data.endpointSummary,\n deprecated: data.deprecated,\n }),\n ];\n\n if (data.error400Description) {\n decorators.push(\n ApiBadRequestResponse({\n description: data.error400Description,\n })\n );\n }\n\n if (data.error401Description) {\n decorators.push(\n ApiUnauthorizedResponse({\n description: data.error401Description,\n })\n );\n }\n\n if (data.error403Description) {\n decorators.push(\n ApiForbiddenResponse({\n description: data.error403Description,\n })\n );\n }\n\n if (data.error404Description) {\n decorators.push(\n ApiNotFoundResponse({\n description: data.error404Description,\n })\n );\n }\n\n if (data.error409Description) {\n decorators.push(\n ApiConflictResponse({\n description: data.error409Description,\n })\n );\n }\n\n if (data.error422Description) {\n decorators.push(\n ApiUnprocessableEntityResponse({\n description: data.error422Description,\n })\n );\n }\n\n if (data.error429Description) {\n decorators.push(\n ApiTooManyRequestsResponse({\n description: data.error429Description,\n })\n );\n }\n\n if (data.error500Description) {\n decorators.push(\n ApiInternalServerErrorResponse({\n description: data.error500Description,\n })\n );\n }\n\n if (data.error503Description) {\n decorators.push(\n ApiServiceUnavailableResponse({\n description: data.error503Description,\n })\n );\n }\n\n if (data.isPaginated && data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: {\n allOf: [\n { $ref: getSchemaPath(PaginatedResponseDto) },\n {\n properties: {\n data: {\n type: \"array\",\n items: {\n $ref: getSchemaPath(data.responseDto),\n },\n },\n },\n },\n ],\n },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto, PaginatedResponseDto)\n );\n } else if (data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: data.isArray\n ? {\n type: \"array\",\n items: { $ref: getSchemaPath(data.responseDto) },\n }\n : { $ref: getSchemaPath(data.responseDto) },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto)\n );\n } else {\n decorators.push(\n ApiOkResponse({\n description: API_RESPONSE_DESCRIPTION,\n })\n );\n }\n\n return applyDecorators(...decorators);\n};\n","import { INestApplication, Injectable } from '@nestjs/common';\nimport { OpenAPIObject, SwaggerModule } from '@nestjs/swagger';\n\ntype Paths = OpenAPIObject['paths'];\n\nclass OpenApiDocsBuilder {\n constructor(\n private readonly doc: OpenAPIObject,\n private readonly metaTags: string[],\n ) {}\n\n stripMetaTags(): OpenAPIObject {\n return this.mapOperations((op) => ({ ...op, tags: this.removeMeta(op.tags) }));\n }\n\n filterByTag(tag: string): OpenAPIObject {\n const filteredPaths: Paths = {};\n for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {\n const filteredMethods: Record<string, unknown> = {};\n for (const [method, operation] of Object.entries(methods as Record<string, unknown>)) {\n const op = operation as { tags?: string[] };\n if (op.tags?.includes(tag)) {\n filteredMethods[method] = { ...op, tags: this.removeMeta(op.tags) };\n }\n }\n if (Object.keys(filteredMethods).length > 0) {\n filteredPaths[path] = filteredMethods as Paths[string];\n }\n }\n return { ...this.doc, paths: filteredPaths };\n }\n\n private mapOperations(fn: (op: { tags?: string[] }) => unknown): OpenAPIObject {\n const paths: Paths = {};\n for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {\n const mapped: Record<string, unknown> = {};\n for (const [method, operation] of Object.entries(methods as Record<string, unknown>)) {\n mapped[method] = fn(operation as { tags?: string[] });\n }\n paths[path] = mapped as Paths[string];\n }\n return { ...this.doc, paths };\n }\n\n private removeMeta(tags?: string[]): string[] {\n return (tags ?? []).filter((t) => !this.metaTags.includes(t));\n }\n}\n\ninterface Version {\n name: string;\n url: string;\n config: Omit<OpenAPIObject, 'paths'>;\n filterTag?: string;\n}\n\n@Injectable()\nexport class SwaggerService {\n private app: INestApplication | null = null;\n private documents: Record<string, OpenAPIObject> = {};\n private versions: Version[] = [];\n private metaTags: string[] = ['protected', 'private', 'support'];\n\n setApp(app: any) {\n this.app = app;\n }\n\n setVersions(versions: Version[]) {\n this.versions = versions;\n }\n\n setMetaTags(tags: string[]) {\n this.metaTags = tags;\n }\n\n getDocument(key: string, serverUrl?: string): OpenAPIObject | undefined {\n const doc = this.documents[key];\n if (!doc) return undefined;\n if (!serverUrl) return doc;\n return { ...doc, servers: [{ url: serverUrl }] };\n }\n\n init() {\n if (!this.app) {\n throw new Error('App not found');\n }\n\n for (const version of this.versions) {\n const { config, filterTag } = version;\n const tempDoc = SwaggerModule.createDocument(this.app, config);\n const builder = new OpenApiDocsBuilder(tempDoc, this.metaTags);\n\n const document = filterTag\n ? builder.filterByTag(filterTag)\n : builder.stripMetaTags();\n\n this.documents[version.name] = document;\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalart/nestjs-swagger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A simple documentation builder for NestJS Swagger Module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "GlobalArt, Inc"
|
|
@@ -48,16 +48,18 @@
|
|
|
48
48
|
"publish:npm": "release-it --config ../../.release-it.json"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@nestjs/common": "11.1.14",
|
|
52
|
-
"@nestjs/core": "11.1.14",
|
|
53
|
-
"@nestjs/swagger": "^11.2.6",
|
|
54
|
-
"@nestjs/testing": "11.1.14",
|
|
55
|
-
"@nestjs/typeorm": "^11.0.0",
|
|
56
51
|
"mysql": "^2.18.1"
|
|
57
52
|
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
55
|
+
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
|
56
|
+
"@nestjs/swagger": "^10.0.0 || ^11.0.0",
|
|
57
|
+
"@nestjs/testing": "^10.0.0 || ^11.0.0",
|
|
58
|
+
"@nestjs/typeorm": "^10.0.0 || ^11.0.0"
|
|
59
|
+
},
|
|
58
60
|
"devDependencies": {
|
|
59
61
|
"@types/jest": "^30.0.0",
|
|
60
|
-
"@types/node": "25.
|
|
62
|
+
"@types/node": "25.5.0",
|
|
61
63
|
"coveralls": "^3.1.1",
|
|
62
64
|
"jest": "^30.2.0",
|
|
63
65
|
"prettier": "3.8.1",
|
|
@@ -66,9 +68,9 @@
|
|
|
66
68
|
"rxjs": "^7.8.2",
|
|
67
69
|
"ts-jest": "29.4.6",
|
|
68
70
|
"ts-node": "^10.9.2",
|
|
69
|
-
"tsdown": "0.
|
|
71
|
+
"tsdown": "0.21.5",
|
|
70
72
|
"typeorm": "0.3.28",
|
|
71
|
-
"typescript": "^
|
|
73
|
+
"typescript": "^6.0.2"
|
|
72
74
|
},
|
|
73
75
|
"jest": {
|
|
74
76
|
"coveragePathIgnorePatterns": [
|