@hazeljs/swagger 0.8.6 → 0.8.7
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 +78 -516
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/openapi-document.test.d.ts +2 -0
- package/dist/openapi-document.test.d.ts.map +1 -0
- package/dist/openapi-document.test.js +42 -0
- package/dist/swagger-config.d.ts +5 -0
- package/dist/swagger-config.d.ts.map +1 -0
- package/dist/swagger-config.js +15 -0
- package/dist/swagger.controller.d.ts +2 -1
- package/dist/swagger.controller.d.ts.map +1 -1
- package/dist/swagger.controller.js +44 -85
- package/dist/swagger.controller.test.js +41 -156
- package/dist/swagger.module.d.ts +7 -0
- package/dist/swagger.module.d.ts.map +1 -1
- package/dist/swagger.module.js +16 -0
- package/dist/swagger.service.d.ts +14 -27
- package/dist/swagger.service.d.ts.map +1 -1
- package/dist/swagger.service.js +143 -162
- package/dist/swagger.service.test.js +164 -22
- package/dist/swagger.types.d.ts +52 -1
- package/dist/swagger.types.d.ts.map +1 -1
- package/package.json +4 -8
|
@@ -1,36 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { SwaggerBuildOptions, SwaggerSpec } from './swagger.types';
|
|
2
2
|
import { Type } from '@hazeljs/core';
|
|
3
|
-
export interface AutoSwaggerOptions {
|
|
4
|
-
title?: string;
|
|
5
|
-
description?: string;
|
|
6
|
-
version?: string;
|
|
7
|
-
autoGenerateOperations?: boolean;
|
|
8
|
-
}
|
|
9
|
-
export interface SwaggerSpec {
|
|
10
|
-
openapi: string;
|
|
11
|
-
info: {
|
|
12
|
-
title?: string;
|
|
13
|
-
description?: string;
|
|
14
|
-
version?: string;
|
|
15
|
-
};
|
|
16
|
-
paths: Record<string, Record<string, SwaggerOperation>>;
|
|
17
|
-
components: {
|
|
18
|
-
schemas: Record<string, SwaggerSchema>;
|
|
19
|
-
};
|
|
20
|
-
tags?: Array<{
|
|
21
|
-
name: string;
|
|
22
|
-
description: string;
|
|
23
|
-
}>;
|
|
24
|
-
}
|
|
25
3
|
export declare class SwaggerService {
|
|
26
4
|
private spec;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
5
|
+
/** Build spec by walking the module tree (imports + controllers). */
|
|
6
|
+
generateAutoSpec(moduleType: Type<unknown>, options?: SwaggerBuildOptions): SwaggerSpec;
|
|
7
|
+
/**
|
|
8
|
+
* Build spec from an explicit controller list.
|
|
9
|
+
* Controllers do not require `@Swagger` on the class; routes without `@ApiOperation`
|
|
10
|
+
* are filled when `autoGenerateOperations` is true (default).
|
|
11
|
+
*/
|
|
12
|
+
generateSpec(controllers: Type<unknown>[], options?: SwaggerBuildOptions): SwaggerSpec;
|
|
13
|
+
private buildOpenApiFromControllers;
|
|
14
|
+
private normalizePrefix;
|
|
15
|
+
private joinPathSegments;
|
|
16
|
+
private processControllerRoutes;
|
|
17
|
+
private processRoute;
|
|
30
18
|
private generateAutoOperation;
|
|
31
19
|
private extractPathParameters;
|
|
32
20
|
private addDefaultSchemas;
|
|
33
|
-
generateSpec(controllers: Type<unknown>[]): SwaggerSpec;
|
|
34
21
|
private normalizePath;
|
|
35
22
|
}
|
|
36
23
|
//# sourceMappingURL=swagger.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swagger.service.d.ts","sourceRoot":"","sources":["../src/swagger.service.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"swagger.service.d.ts","sourceRoot":"","sources":["../src/swagger.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EAGnB,WAAW,EACZ,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AASrC,qBACa,cAAc;IACzB,OAAO,CAAC,IAAI,CAOV;IAEF,qEAAqE;IACrE,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,WAAW;IAWvF;;;;OAIG;IACH,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,WAAW;IAoBtF,OAAO,CAAC,2BAA2B;IAgFnC,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,uBAAuB;IA2B/B,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,qBAAqB;IA+F7B,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,iBAAiB;IAwCzB,OAAO,CAAC,aAAa;CAOtB"}
|
package/dist/swagger.service.js
CHANGED
|
@@ -25,76 +25,144 @@ let SwaggerService = class SwaggerService {
|
|
|
25
25
|
},
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
/** Build spec by walking the module tree (imports + controllers). */
|
|
29
29
|
generateAutoSpec(moduleType, options) {
|
|
30
30
|
try {
|
|
31
31
|
core_2.default.debug('Auto-generating Swagger spec from module:', moduleType.name);
|
|
32
|
-
// Reset spec
|
|
33
|
-
this.spec = {
|
|
34
|
-
openapi: '3.0.0',
|
|
35
|
-
info: {
|
|
36
|
-
title: options?.title || 'HazelJS API',
|
|
37
|
-
description: options?.description || 'Auto-generated API documentation',
|
|
38
|
-
version: options?.version || '1.0.0',
|
|
39
|
-
},
|
|
40
|
-
paths: {},
|
|
41
|
-
components: {
|
|
42
|
-
schemas: {},
|
|
43
|
-
},
|
|
44
|
-
tags: [],
|
|
45
|
-
};
|
|
46
32
|
const controllers = (0, core_3.collectControllersFromModule)(moduleType);
|
|
47
|
-
|
|
48
|
-
controllers.forEach((controller) => {
|
|
49
|
-
this.processControllerAuto(controller, options?.autoGenerateOperations !== false);
|
|
50
|
-
});
|
|
51
|
-
// Add default error schemas
|
|
52
|
-
this.addDefaultSchemas();
|
|
53
|
-
core_2.default.debug('Auto-generated Swagger specification completed');
|
|
54
|
-
return this.spec;
|
|
33
|
+
return this.buildOpenApiFromControllers(controllers, options);
|
|
55
34
|
}
|
|
56
35
|
catch (error) {
|
|
57
36
|
core_2.default.error('Failed to auto-generate Swagger specification:', error);
|
|
58
37
|
throw error;
|
|
59
38
|
}
|
|
60
39
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Build spec from an explicit controller list.
|
|
42
|
+
* Controllers do not require `@Swagger` on the class; routes without `@ApiOperation`
|
|
43
|
+
* are filled when `autoGenerateOperations` is true (default).
|
|
44
|
+
*/
|
|
45
|
+
generateSpec(controllers, options) {
|
|
46
|
+
try {
|
|
47
|
+
if (!Array.isArray(controllers)) {
|
|
48
|
+
throw new Error('Controllers must be an array');
|
|
49
|
+
}
|
|
50
|
+
core_2.default.debug('Generating spec for controllers:', controllers.map((c) => c?.name || 'undefined'));
|
|
51
|
+
return this.buildOpenApiFromControllers(controllers, options);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
55
|
+
core_2.default.error('Failed to generate Swagger specification:', error);
|
|
56
|
+
}
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
buildOpenApiFromControllers(controllers, options = {}) {
|
|
61
|
+
const autoGenerateOps = options.autoGenerateOperations !== false;
|
|
62
|
+
this.spec = {
|
|
63
|
+
openapi: '3.0.0',
|
|
64
|
+
info: {},
|
|
65
|
+
paths: {},
|
|
66
|
+
components: {
|
|
67
|
+
schemas: {},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
if (options.title !== undefined) {
|
|
71
|
+
this.spec.info.title = options.title;
|
|
72
|
+
}
|
|
73
|
+
if (options.description !== undefined) {
|
|
74
|
+
this.spec.info.description = options.description;
|
|
75
|
+
}
|
|
76
|
+
if (options.version !== undefined) {
|
|
77
|
+
this.spec.info.version = options.version;
|
|
78
|
+
}
|
|
79
|
+
if (options.servers?.length) {
|
|
80
|
+
this.spec.servers = options.servers;
|
|
81
|
+
}
|
|
82
|
+
if (options.securitySchemes && Object.keys(options.securitySchemes).length > 0) {
|
|
83
|
+
this.spec.components.securitySchemes = { ...options.securitySchemes };
|
|
84
|
+
}
|
|
85
|
+
if (options.security?.length) {
|
|
86
|
+
this.spec.security = options.security;
|
|
87
|
+
}
|
|
88
|
+
this.addDefaultSchemas();
|
|
89
|
+
const pathPrefix = this.normalizePrefix(options.globalPrefix);
|
|
90
|
+
for (const controller of controllers) {
|
|
91
|
+
if (!controller || typeof controller !== 'function') {
|
|
92
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
93
|
+
core_2.default.warn('Invalid controller found:', controller);
|
|
94
|
+
}
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const swaggerOptions = (0, swagger_decorator_1.getSwaggerMetadata)(controller.prototype);
|
|
98
|
+
if (swaggerOptions) {
|
|
99
|
+
if (!this.spec.info.title) {
|
|
100
|
+
this.spec.info = {
|
|
101
|
+
title: swaggerOptions.title,
|
|
102
|
+
description: swaggerOptions.description,
|
|
103
|
+
version: swaggerOptions.version,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (swaggerOptions.tags && !this.spec.tags?.length) {
|
|
107
|
+
this.spec.tags = swaggerOptions.tags;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
this.processControllerRoutes(controller, pathPrefix, autoGenerateOps);
|
|
111
|
+
}
|
|
112
|
+
if (!this.spec.info.title) {
|
|
113
|
+
this.spec.info.title = 'HazelJS API';
|
|
114
|
+
}
|
|
115
|
+
if (!this.spec.info.description) {
|
|
116
|
+
this.spec.info.description = 'API documentation';
|
|
117
|
+
}
|
|
118
|
+
if (!this.spec.info.version) {
|
|
119
|
+
this.spec.info.version = '1.0.0';
|
|
120
|
+
}
|
|
121
|
+
core_2.default.debug('Generated Swagger specification:', this.spec);
|
|
122
|
+
return this.spec;
|
|
123
|
+
}
|
|
124
|
+
normalizePrefix(prefix) {
|
|
125
|
+
if (!prefix)
|
|
126
|
+
return '';
|
|
127
|
+
let p = prefix.startsWith('/') ? prefix : `/${prefix}`;
|
|
128
|
+
p = p.replace(/\/$/, '');
|
|
129
|
+
return p;
|
|
130
|
+
}
|
|
131
|
+
joinPathSegments(...segments) {
|
|
132
|
+
const parts = [];
|
|
133
|
+
for (const seg of segments) {
|
|
134
|
+
if (!seg)
|
|
135
|
+
continue;
|
|
136
|
+
for (const piece of String(seg).split('/')) {
|
|
137
|
+
if (piece)
|
|
138
|
+
parts.push(piece);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return parts.length ? `/${parts.join('/')}` : '';
|
|
142
|
+
}
|
|
143
|
+
processControllerRoutes(controller, pathPrefix, autoGenerateOps) {
|
|
65
144
|
const controllerMetadata = Reflect.getMetadata('hazel:controller', controller) || {};
|
|
66
145
|
const basePath = controllerMetadata.path || '';
|
|
67
|
-
// Get API tags from metadata
|
|
68
146
|
const apiTags = Reflect.getMetadata('hazel:api:tags', controller) || [];
|
|
69
|
-
// Add controller as a tag if not already present
|
|
70
|
-
if (!this.spec.tags)
|
|
71
|
-
this.spec.tags = [];
|
|
72
147
|
const controllerTag = {
|
|
73
148
|
name: apiTags.length > 0 ? apiTags[0] : controller.name,
|
|
74
149
|
description: `${controller.name} endpoints`,
|
|
75
150
|
};
|
|
76
|
-
if (!this.spec.tags.find((tag) => tag.name === controllerTag.name)) {
|
|
77
|
-
this.spec.tags.push(controllerTag);
|
|
78
|
-
}
|
|
79
|
-
// Get route metadata
|
|
80
151
|
const routes = Reflect.getMetadata('hazel:routes', controller) || [];
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
152
|
+
for (const route of routes) {
|
|
153
|
+
this.processRoute(controller, route, basePath, pathPrefix, controllerTag.name, autoGenerateOps);
|
|
154
|
+
}
|
|
85
155
|
}
|
|
86
|
-
|
|
156
|
+
processRoute(controller, route, basePath, pathPrefix, tag, autoGenerateOps) {
|
|
87
157
|
const { path, method, propertyKey } = route;
|
|
88
|
-
const fullPath = this.normalizePath(
|
|
89
|
-
|
|
158
|
+
const fullPath = this.normalizePath(this.joinPathSegments(pathPrefix, basePath, path));
|
|
159
|
+
const pathForParams = this.joinPathSegments(basePath, path);
|
|
90
160
|
let operation = (0, swagger_decorator_1.getOperationMetadata)(controller.prototype, propertyKey);
|
|
91
|
-
// Auto-generate operation if not found and auto-generation is enabled
|
|
92
161
|
if (!operation && autoGenerateOps) {
|
|
93
|
-
operation = this.generateAutoOperation(method, propertyKey, tag,
|
|
162
|
+
operation = this.generateAutoOperation(method, propertyKey, tag, pathForParams);
|
|
94
163
|
}
|
|
95
164
|
if (!operation)
|
|
96
165
|
return;
|
|
97
|
-
// Add operation to paths
|
|
98
166
|
const pathItem = this.spec.paths[fullPath] || {};
|
|
99
167
|
pathItem[method.toLowerCase()] = {
|
|
100
168
|
...operation,
|
|
@@ -102,18 +170,19 @@ let SwaggerService = class SwaggerService {
|
|
|
102
170
|
};
|
|
103
171
|
this.spec.paths[fullPath] = pathItem;
|
|
104
172
|
}
|
|
105
|
-
generateAutoOperation(method, propertyKey, tag,
|
|
173
|
+
generateAutoOperation(method, propertyKey, tag, pathForParams) {
|
|
106
174
|
const methodName = String(propertyKey);
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
|
|
175
|
+
const m = method.toLowerCase();
|
|
176
|
+
const isGetMethod = m === 'get';
|
|
177
|
+
const isPostMethod = m === 'post';
|
|
178
|
+
const isPutMethod = m === 'put';
|
|
179
|
+
const isPatchMethod = m === 'patch';
|
|
180
|
+
const isDeleteMethod = m === 'delete';
|
|
112
181
|
let summary = '';
|
|
113
182
|
if (methodName.includes('create') || isPostMethod) {
|
|
114
183
|
summary = `Create new resource`;
|
|
115
184
|
}
|
|
116
|
-
else if (methodName.includes('update') || isPutMethod) {
|
|
185
|
+
else if (methodName.includes('update') || isPutMethod || isPatchMethod) {
|
|
117
186
|
summary = `Update resource`;
|
|
118
187
|
}
|
|
119
188
|
else if (methodName.includes('delete') || isDeleteMethod) {
|
|
@@ -125,6 +194,7 @@ let SwaggerService = class SwaggerService {
|
|
|
125
194
|
else {
|
|
126
195
|
summary = `${method.toUpperCase()} ${methodName}`;
|
|
127
196
|
}
|
|
197
|
+
const errorSchema = { $ref: '#/components/schemas/Error' };
|
|
128
198
|
const operation = {
|
|
129
199
|
summary,
|
|
130
200
|
description: `Auto-generated ${method.toUpperCase()} operation`,
|
|
@@ -145,10 +215,25 @@ let SwaggerService = class SwaggerService {
|
|
|
145
215
|
},
|
|
146
216
|
},
|
|
147
217
|
},
|
|
218
|
+
'400': {
|
|
219
|
+
description: 'Bad request',
|
|
220
|
+
content: {
|
|
221
|
+
'application/json': {
|
|
222
|
+
schema: errorSchema,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
'500': {
|
|
227
|
+
description: 'Internal server error',
|
|
228
|
+
content: {
|
|
229
|
+
'application/json': {
|
|
230
|
+
schema: errorSchema,
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
148
234
|
},
|
|
149
235
|
};
|
|
150
|
-
|
|
151
|
-
const pathParams = this.extractPathParameters(route.path);
|
|
236
|
+
const pathParams = this.extractPathParameters(pathForParams);
|
|
152
237
|
if (pathParams.length > 0) {
|
|
153
238
|
operation.parameters = pathParams.map((param) => ({
|
|
154
239
|
name: param,
|
|
@@ -157,8 +242,7 @@ let SwaggerService = class SwaggerService {
|
|
|
157
242
|
schema: { type: 'string' },
|
|
158
243
|
}));
|
|
159
244
|
}
|
|
160
|
-
|
|
161
|
-
if (isPostMethod || isPutMethod) {
|
|
245
|
+
if (isPostMethod || isPutMethod || isPatchMethod) {
|
|
162
246
|
operation.requestBody = {
|
|
163
247
|
required: true,
|
|
164
248
|
content: {
|
|
@@ -170,38 +254,18 @@ let SwaggerService = class SwaggerService {
|
|
|
170
254
|
},
|
|
171
255
|
};
|
|
172
256
|
}
|
|
173
|
-
// Add common error responses
|
|
174
|
-
if (operation.responses) {
|
|
175
|
-
operation.responses['400'] = {
|
|
176
|
-
description: 'Bad request',
|
|
177
|
-
content: {
|
|
178
|
-
'application/json': {
|
|
179
|
-
schema: { type: 'object' },
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
operation.responses['500'] = {
|
|
184
|
-
description: 'Internal server error',
|
|
185
|
-
content: {
|
|
186
|
-
'application/json': {
|
|
187
|
-
schema: { type: 'object' },
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
257
|
return operation;
|
|
193
258
|
}
|
|
194
|
-
extractPathParameters(
|
|
259
|
+
extractPathParameters(routePath) {
|
|
195
260
|
const params = [];
|
|
196
261
|
const paramRegex = /:([^/]+)/g;
|
|
197
262
|
let match;
|
|
198
|
-
while ((match = paramRegex.exec(
|
|
263
|
+
while ((match = paramRegex.exec(routePath)) !== null) {
|
|
199
264
|
params.push(match[1]);
|
|
200
265
|
}
|
|
201
266
|
return params;
|
|
202
267
|
}
|
|
203
268
|
addDefaultSchemas() {
|
|
204
|
-
// Add common error schemas
|
|
205
269
|
this.spec.components.schemas.Error = {
|
|
206
270
|
type: 'object',
|
|
207
271
|
properties: {
|
|
@@ -239,95 +303,12 @@ let SwaggerService = class SwaggerService {
|
|
|
239
303
|
},
|
|
240
304
|
};
|
|
241
305
|
}
|
|
242
|
-
generateSpec(controllers) {
|
|
243
|
-
try {
|
|
244
|
-
if (!Array.isArray(controllers)) {
|
|
245
|
-
throw new Error('Controllers must be an array');
|
|
246
|
-
}
|
|
247
|
-
core_2.default.debug('Generating spec for controllers:', controllers.map((c) => c?.name || 'undefined'));
|
|
248
|
-
// Reset spec
|
|
249
|
-
this.spec = {
|
|
250
|
-
openapi: '3.0.0',
|
|
251
|
-
info: {},
|
|
252
|
-
paths: {},
|
|
253
|
-
components: {
|
|
254
|
-
schemas: {},
|
|
255
|
-
},
|
|
256
|
-
};
|
|
257
|
-
// Process each controller
|
|
258
|
-
controllers.forEach((controller) => {
|
|
259
|
-
if (!controller || typeof controller !== 'function') {
|
|
260
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
261
|
-
core_2.default.warn('Invalid controller found:', controller);
|
|
262
|
-
}
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
// Get Swagger metadata from the controller prototype
|
|
266
|
-
const swaggerOptions = (0, swagger_decorator_1.getSwaggerMetadata)(controller.prototype);
|
|
267
|
-
if (!swaggerOptions) {
|
|
268
|
-
core_2.default.debug(`No Swagger metadata found for controller: ${controller.name}`);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
core_2.default.debug(`Processing controller: ${controller.name}`, swaggerOptions);
|
|
272
|
-
// Update info if not already set
|
|
273
|
-
if (!this.spec.info.title) {
|
|
274
|
-
this.spec.info = {
|
|
275
|
-
title: swaggerOptions.title,
|
|
276
|
-
description: swaggerOptions.description,
|
|
277
|
-
version: swaggerOptions.version,
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
// Add tags if not already set
|
|
281
|
-
if (swaggerOptions.tags && !this.spec.tags) {
|
|
282
|
-
this.spec.tags = swaggerOptions.tags;
|
|
283
|
-
}
|
|
284
|
-
// Get controller path from metadata
|
|
285
|
-
const controllerMetadata = Reflect.getMetadata('hazel:controller', controller) || {};
|
|
286
|
-
const basePath = controllerMetadata.path || '';
|
|
287
|
-
// Get route metadata
|
|
288
|
-
const routes = Reflect.getMetadata('hazel:routes', controller);
|
|
289
|
-
if (!routes) {
|
|
290
|
-
core_2.default.debug(`No routes found for controller: ${controller.name}`);
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
core_2.default.debug(`Found routes for ${controller.name}:`, routes);
|
|
294
|
-
// Process each route
|
|
295
|
-
routes.forEach((route) => {
|
|
296
|
-
const { path, method, propertyKey } = route;
|
|
297
|
-
const fullPath = this.normalizePath(`${basePath}${path}`);
|
|
298
|
-
const operation = (0, swagger_decorator_1.getOperationMetadata)(controller.prototype, propertyKey);
|
|
299
|
-
if (!operation) {
|
|
300
|
-
core_2.default.debug(`No operation metadata found for method: ${String(propertyKey)}`);
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
core_2.default.debug(`Adding operation for ${method} ${fullPath}`);
|
|
304
|
-
// Add operation to paths
|
|
305
|
-
const pathItem = this.spec.paths[fullPath] || {};
|
|
306
|
-
pathItem[method.toLowerCase()] = {
|
|
307
|
-
...operation,
|
|
308
|
-
tags: operation.tags || [controller.name],
|
|
309
|
-
};
|
|
310
|
-
this.spec.paths[fullPath] = pathItem;
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
core_2.default.debug('Generated Swagger specification:', this.spec);
|
|
314
|
-
return this.spec;
|
|
315
|
-
}
|
|
316
|
-
catch (error) {
|
|
317
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
318
|
-
core_2.default.error('Failed to generate Swagger specification:', error);
|
|
319
|
-
}
|
|
320
|
-
throw error;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
306
|
normalizePath(path) {
|
|
324
|
-
// Remove trailing slash
|
|
325
307
|
let normalized = path.replace(/\/$/, '');
|
|
326
|
-
// Ensure path starts with slash
|
|
327
308
|
if (!normalized.startsWith('/')) {
|
|
328
309
|
normalized = '/' + normalized;
|
|
329
310
|
}
|
|
330
|
-
return normalized;
|
|
311
|
+
return normalized || '/';
|
|
331
312
|
}
|
|
332
313
|
};
|
|
333
314
|
exports.SwaggerService = SwaggerService;
|