@hazeljs/swagger 0.2.0-alpha.1
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/LICENSE +192 -0
- package/README.md +584 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/swagger.controller.d.ts +12 -0
- package/dist/swagger.controller.d.ts.map +1 -0
- package/dist/swagger.controller.js +243 -0
- package/dist/swagger.controller.test.d.ts +2 -0
- package/dist/swagger.controller.test.d.ts.map +1 -0
- package/dist/swagger.controller.test.js +250 -0
- package/dist/swagger.decorator.d.ts +7 -0
- package/dist/swagger.decorator.d.ts.map +1 -0
- package/dist/swagger.decorator.js +26 -0
- package/dist/swagger.decorator.test.d.ts +2 -0
- package/dist/swagger.decorator.test.d.ts.map +1 -0
- package/dist/swagger.decorator.test.js +72 -0
- package/dist/swagger.module.d.ts +5 -0
- package/dist/swagger.module.d.ts.map +1 -0
- package/dist/swagger.module.js +30 -0
- package/dist/swagger.service.d.ts +24 -0
- package/dist/swagger.service.d.ts.map +1 -0
- package/dist/swagger.service.js +121 -0
- package/dist/swagger.service.test.d.ts +2 -0
- package/dist/swagger.service.test.d.ts.map +1 -0
- package/dist/swagger.service.test.js +364 -0
- package/dist/swagger.types.d.ts +50 -0
- package/dist/swagger.types.d.ts.map +1 -0
- package/dist/swagger.types.js +2 -0
- package/package.json +55 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
var SwaggerController_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.SwaggerController = void 0;
|
|
17
|
+
const core_1 = require("@hazeljs/core");
|
|
18
|
+
const swagger_service_1 = require("./swagger.service");
|
|
19
|
+
const core_2 = require("@hazeljs/core");
|
|
20
|
+
const core_3 = __importDefault(require("@hazeljs/core"));
|
|
21
|
+
const swagger_decorator_1 = require("./swagger.decorator");
|
|
22
|
+
let SwaggerController = SwaggerController_1 = class SwaggerController {
|
|
23
|
+
constructor(swaggerService) {
|
|
24
|
+
this.swaggerService = swaggerService;
|
|
25
|
+
}
|
|
26
|
+
static setRootModule(module) {
|
|
27
|
+
core_3.default.debug(`Setting root module for SwaggerController: ${module.name}`);
|
|
28
|
+
SwaggerController_1.rootModule = module;
|
|
29
|
+
}
|
|
30
|
+
async getSpec(_context) {
|
|
31
|
+
try {
|
|
32
|
+
if (!SwaggerController_1.rootModule) {
|
|
33
|
+
core_3.default.warn('No root module provided');
|
|
34
|
+
return {
|
|
35
|
+
openapi: '3.0.0',
|
|
36
|
+
info: {
|
|
37
|
+
title: 'API Documentation',
|
|
38
|
+
version: '1.0.0',
|
|
39
|
+
description: 'No root module provided',
|
|
40
|
+
},
|
|
41
|
+
paths: {},
|
|
42
|
+
components: {
|
|
43
|
+
schemas: {},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
core_3.default.debug('Root module:', SwaggerController_1.rootModule.name);
|
|
48
|
+
// Get all controllers from the AppModule and its imported modules
|
|
49
|
+
const moduleMetadata = (0, core_2.getModuleMetadata)(SwaggerController_1.rootModule);
|
|
50
|
+
core_3.default.debug('Module metadata:', JSON.stringify(moduleMetadata, null, 2));
|
|
51
|
+
const controllers = new Set();
|
|
52
|
+
// Helper function to recursively collect controllers from modules
|
|
53
|
+
const collectControllers = (moduleRef) => {
|
|
54
|
+
const moduleName = typeof moduleRef === 'function'
|
|
55
|
+
? moduleRef.name
|
|
56
|
+
: moduleRef.module?.name;
|
|
57
|
+
core_3.default.debug(`Collecting controllers from module: ${moduleName}`);
|
|
58
|
+
const metadata = (0, core_2.getModuleMetadata)(moduleRef);
|
|
59
|
+
if (!metadata) {
|
|
60
|
+
core_3.default.warn(`No metadata found for module: ${moduleName}`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Add controllers from current module
|
|
64
|
+
if (metadata.controllers) {
|
|
65
|
+
const validControllers = metadata.controllers.filter((c) => c && typeof c === 'function');
|
|
66
|
+
core_3.default.debug(`${moduleName} controllers:`, validControllers.map((c) => typeof c === 'function' ? c.name : undefined));
|
|
67
|
+
validControllers.forEach((controller) => controllers.add(controller));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
core_3.default.debug(`No controllers found in module: ${moduleName}`);
|
|
71
|
+
}
|
|
72
|
+
// Recursively process imported modules (Type or DynamicModule)
|
|
73
|
+
if (metadata.imports) {
|
|
74
|
+
const validModules = metadata.imports.filter((m) => m && (typeof m === 'function' || (typeof m === 'object' && 'module' in m)));
|
|
75
|
+
core_3.default.debug(`${moduleName} imported modules:`, validModules.map((m) => typeof m === 'function' ? m.name : m.module?.name));
|
|
76
|
+
validModules.forEach((moduleRef) => collectControllers(moduleRef));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
core_3.default.debug(`No imports found in module: ${moduleName}`);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
// Start collecting controllers from the root module
|
|
83
|
+
collectControllers(SwaggerController_1.rootModule);
|
|
84
|
+
const controllerArray = Array.from(controllers);
|
|
85
|
+
core_3.default.debug('Total controllers found:', controllerArray.length);
|
|
86
|
+
core_3.default.debug('Controller names:', controllerArray.map((c) => c.name));
|
|
87
|
+
if (controllerArray.length === 0) {
|
|
88
|
+
core_3.default.warn('No valid controllers found');
|
|
89
|
+
return {
|
|
90
|
+
openapi: '3.0.0',
|
|
91
|
+
info: {
|
|
92
|
+
title: 'API Documentation',
|
|
93
|
+
version: '1.0.0',
|
|
94
|
+
description: 'No controllers found',
|
|
95
|
+
},
|
|
96
|
+
paths: {},
|
|
97
|
+
components: {
|
|
98
|
+
schemas: {},
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const spec = this.swaggerService.generateSpec(controllerArray);
|
|
103
|
+
return spec;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
107
|
+
core_3.default.error('Error generating Swagger spec:', error);
|
|
108
|
+
}
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async getDocs(_context) {
|
|
113
|
+
return `
|
|
114
|
+
<!DOCTYPE html>
|
|
115
|
+
<html>
|
|
116
|
+
<head>
|
|
117
|
+
<title>API Documentation</title>
|
|
118
|
+
<meta charset="utf-8"/>
|
|
119
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
120
|
+
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@4.18.3/swagger-ui.css" />
|
|
121
|
+
<style>
|
|
122
|
+
body {
|
|
123
|
+
margin: 0;
|
|
124
|
+
padding: 20px;
|
|
125
|
+
}
|
|
126
|
+
#swagger-ui {
|
|
127
|
+
max-width: 1460px;
|
|
128
|
+
margin: 0 auto;
|
|
129
|
+
}
|
|
130
|
+
.loading {
|
|
131
|
+
text-align: center;
|
|
132
|
+
padding: 20px;
|
|
133
|
+
font-family: Arial, sans-serif;
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
136
|
+
</head>
|
|
137
|
+
<body>
|
|
138
|
+
<div id="swagger-ui">
|
|
139
|
+
<div class="loading">Loading API Documentation...</div>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<script src="https://unpkg.com/swagger-ui-dist@4.18.3/swagger-ui-bundle.js"></script>
|
|
143
|
+
<script src="https://unpkg.com/swagger-ui-dist@4.18.3/swagger-ui-standalone-preset.js"></script>
|
|
144
|
+
<script>
|
|
145
|
+
// Basic error handling
|
|
146
|
+
window.onerror = function(msg, url, line) {
|
|
147
|
+
document.getElementById('swagger-ui').innerHTML =
|
|
148
|
+
'<div style="color: red; padding: 20px;">Error: ' + msg + '<br>at line ' + line + '</div>';
|
|
149
|
+
return false;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Simple initialization
|
|
153
|
+
const ui = SwaggerUIBundle({
|
|
154
|
+
url: window.location.origin + "/swagger/spec",
|
|
155
|
+
dom_id: '#swagger-ui',
|
|
156
|
+
deepLinking: true,
|
|
157
|
+
presets: [
|
|
158
|
+
SwaggerUIBundle.presets.apis,
|
|
159
|
+
SwaggerUIStandalonePreset
|
|
160
|
+
],
|
|
161
|
+
plugins: [
|
|
162
|
+
SwaggerUIBundle.plugins.DownloadUrl
|
|
163
|
+
],
|
|
164
|
+
layout: "BaseLayout"
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
window.ui = ui;
|
|
168
|
+
</script>
|
|
169
|
+
</body>
|
|
170
|
+
</html>
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
exports.SwaggerController = SwaggerController;
|
|
175
|
+
__decorate([
|
|
176
|
+
(0, core_1.Get)('/spec'),
|
|
177
|
+
(0, swagger_decorator_1.ApiOperation)({
|
|
178
|
+
summary: 'Get OpenAPI specification',
|
|
179
|
+
description: 'Retrieves the OpenAPI specification for the API',
|
|
180
|
+
tags: ['swagger'],
|
|
181
|
+
responses: {
|
|
182
|
+
'200': {
|
|
183
|
+
description: 'OpenAPI specification retrieved successfully',
|
|
184
|
+
content: {
|
|
185
|
+
'application/json': {
|
|
186
|
+
schema: {
|
|
187
|
+
type: 'object',
|
|
188
|
+
properties: {
|
|
189
|
+
openapi: { type: 'string' },
|
|
190
|
+
info: { type: 'object' },
|
|
191
|
+
paths: { type: 'object' },
|
|
192
|
+
components: { type: 'object' },
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
}),
|
|
200
|
+
__metadata("design:type", Function),
|
|
201
|
+
__metadata("design:paramtypes", [Object]),
|
|
202
|
+
__metadata("design:returntype", Promise)
|
|
203
|
+
], SwaggerController.prototype, "getSpec", null);
|
|
204
|
+
__decorate([
|
|
205
|
+
(0, core_1.Get)('/'),
|
|
206
|
+
(0, swagger_decorator_1.ApiOperation)({
|
|
207
|
+
summary: 'Get Swagger UI',
|
|
208
|
+
description: 'Serves the Swagger UI interface',
|
|
209
|
+
tags: ['swagger'],
|
|
210
|
+
responses: {
|
|
211
|
+
'200': {
|
|
212
|
+
description: 'Swagger UI HTML page',
|
|
213
|
+
content: {
|
|
214
|
+
'text/html': {
|
|
215
|
+
schema: {
|
|
216
|
+
type: 'string',
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
}),
|
|
223
|
+
__metadata("design:type", Function),
|
|
224
|
+
__metadata("design:paramtypes", [Object]),
|
|
225
|
+
__metadata("design:returntype", Promise)
|
|
226
|
+
], SwaggerController.prototype, "getDocs", null);
|
|
227
|
+
exports.SwaggerController = SwaggerController = SwaggerController_1 = __decorate([
|
|
228
|
+
(0, swagger_decorator_1.Swagger)({
|
|
229
|
+
title: 'Swagger Documentation',
|
|
230
|
+
description: 'API documentation using Swagger/OpenAPI',
|
|
231
|
+
version: '1.0.0',
|
|
232
|
+
tags: [
|
|
233
|
+
{
|
|
234
|
+
name: 'swagger',
|
|
235
|
+
description: 'Swagger documentation endpoints',
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
}),
|
|
239
|
+
(0, core_1.Controller)({
|
|
240
|
+
path: 'swagger',
|
|
241
|
+
}),
|
|
242
|
+
__metadata("design:paramtypes", [swagger_service_1.SwaggerService])
|
|
243
|
+
], SwaggerController);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swagger.controller.test.d.ts","sourceRoot":"","sources":["../src/swagger.controller.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const swagger_controller_1 = require("./swagger.controller");
|
|
4
|
+
const core_1 = require("@hazeljs/core");
|
|
5
|
+
// Mock the logger and getModuleMetadata
|
|
6
|
+
jest.mock('@hazeljs/core', () => {
|
|
7
|
+
const actual = jest.requireActual('@hazeljs/core');
|
|
8
|
+
return {
|
|
9
|
+
...actual,
|
|
10
|
+
__esModule: true,
|
|
11
|
+
getModuleMetadata: jest.fn(),
|
|
12
|
+
default: {
|
|
13
|
+
error: jest.fn(),
|
|
14
|
+
debug: jest.fn(),
|
|
15
|
+
warn: jest.fn(),
|
|
16
|
+
info: jest.fn(),
|
|
17
|
+
http: jest.fn(),
|
|
18
|
+
silly: jest.fn(),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
describe('SwaggerController', () => {
|
|
23
|
+
let controller;
|
|
24
|
+
let swaggerService;
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
swaggerService = {
|
|
27
|
+
generateSpec: jest.fn(),
|
|
28
|
+
};
|
|
29
|
+
controller = new swagger_controller_1.SwaggerController(swaggerService);
|
|
30
|
+
// Reset all mocks before each test
|
|
31
|
+
jest.clearAllMocks();
|
|
32
|
+
});
|
|
33
|
+
it('should be defined', () => {
|
|
34
|
+
expect(controller).toBeDefined();
|
|
35
|
+
});
|
|
36
|
+
it('should return swagger spec', async () => {
|
|
37
|
+
const mockSpec = {
|
|
38
|
+
openapi: '3.0.0',
|
|
39
|
+
info: {
|
|
40
|
+
title: 'API Documentation',
|
|
41
|
+
version: '1.0.0',
|
|
42
|
+
description: 'No root module provided',
|
|
43
|
+
},
|
|
44
|
+
paths: {},
|
|
45
|
+
components: {
|
|
46
|
+
schemas: {},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
swaggerService.generateSpec.mockReturnValue(mockSpec);
|
|
50
|
+
const spec = await controller.getSpec({});
|
|
51
|
+
expect(spec).toEqual(mockSpec);
|
|
52
|
+
});
|
|
53
|
+
describe('getSpec', () => {
|
|
54
|
+
it('should return Swagger specification', async () => {
|
|
55
|
+
const mockSpec = {
|
|
56
|
+
openapi: '3.0.0',
|
|
57
|
+
info: {
|
|
58
|
+
title: 'API Documentation',
|
|
59
|
+
version: '1.0.0',
|
|
60
|
+
description: 'No root module provided',
|
|
61
|
+
},
|
|
62
|
+
paths: {},
|
|
63
|
+
components: {
|
|
64
|
+
schemas: {},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
// Set up the root module
|
|
68
|
+
class TestModule {
|
|
69
|
+
}
|
|
70
|
+
swagger_controller_1.SwaggerController.setRootModule(TestModule);
|
|
71
|
+
// Mock getModuleMetadata to return some controllers
|
|
72
|
+
core_1.getModuleMetadata.mockReturnValue({
|
|
73
|
+
controllers: [class TestController {
|
|
74
|
+
}],
|
|
75
|
+
imports: [],
|
|
76
|
+
});
|
|
77
|
+
swaggerService.generateSpec.mockReturnValue(mockSpec);
|
|
78
|
+
const context = {};
|
|
79
|
+
const result = await controller.getSpec(context);
|
|
80
|
+
expect(result).toEqual(mockSpec);
|
|
81
|
+
expect(swaggerService.generateSpec).toHaveBeenCalled();
|
|
82
|
+
});
|
|
83
|
+
it('should handle errors', async () => {
|
|
84
|
+
const error = new Error('Test error');
|
|
85
|
+
swaggerService.generateSpec.mockImplementation(() => {
|
|
86
|
+
throw error;
|
|
87
|
+
});
|
|
88
|
+
// Set up the root module
|
|
89
|
+
class TestModule {
|
|
90
|
+
}
|
|
91
|
+
swagger_controller_1.SwaggerController.setRootModule(TestModule);
|
|
92
|
+
// Mock getModuleMetadata to return some controllers
|
|
93
|
+
core_1.getModuleMetadata.mockReturnValue({
|
|
94
|
+
controllers: [class TestController {
|
|
95
|
+
}],
|
|
96
|
+
imports: [],
|
|
97
|
+
});
|
|
98
|
+
const context = {};
|
|
99
|
+
await expect(controller.getSpec(context)).rejects.toThrow('Test error');
|
|
100
|
+
expect(swaggerService.generateSpec).toHaveBeenCalled();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('getSpec edge cases', () => {
|
|
104
|
+
it('should return default spec when no root module is set', async () => {
|
|
105
|
+
// Clear root module by setting it to undefined directly
|
|
106
|
+
swagger_controller_1.SwaggerController.rootModule = undefined;
|
|
107
|
+
const context = {};
|
|
108
|
+
const result = await controller.getSpec(context);
|
|
109
|
+
expect(result).toEqual({
|
|
110
|
+
openapi: '3.0.0',
|
|
111
|
+
info: {
|
|
112
|
+
title: 'API Documentation',
|
|
113
|
+
version: '1.0.0',
|
|
114
|
+
description: 'No root module provided',
|
|
115
|
+
},
|
|
116
|
+
paths: {},
|
|
117
|
+
components: {
|
|
118
|
+
schemas: {},
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
it('should handle module with no metadata', async () => {
|
|
123
|
+
class TestModule {
|
|
124
|
+
}
|
|
125
|
+
swagger_controller_1.SwaggerController.setRootModule(TestModule);
|
|
126
|
+
core_1.getModuleMetadata.mockReturnValue(null);
|
|
127
|
+
const context = {};
|
|
128
|
+
const result = await controller.getSpec(context);
|
|
129
|
+
expect(result).toEqual({
|
|
130
|
+
openapi: '3.0.0',
|
|
131
|
+
info: {
|
|
132
|
+
title: 'API Documentation',
|
|
133
|
+
version: '1.0.0',
|
|
134
|
+
description: 'No controllers found',
|
|
135
|
+
},
|
|
136
|
+
paths: {},
|
|
137
|
+
components: {
|
|
138
|
+
schemas: {},
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
it('should handle module with no controllers', async () => {
|
|
143
|
+
class TestModule {
|
|
144
|
+
}
|
|
145
|
+
swagger_controller_1.SwaggerController.setRootModule(TestModule);
|
|
146
|
+
core_1.getModuleMetadata.mockReturnValue({
|
|
147
|
+
controllers: [],
|
|
148
|
+
imports: [],
|
|
149
|
+
});
|
|
150
|
+
const context = {};
|
|
151
|
+
const result = await controller.getSpec(context);
|
|
152
|
+
expect(result).toEqual({
|
|
153
|
+
openapi: '3.0.0',
|
|
154
|
+
info: {
|
|
155
|
+
title: 'API Documentation',
|
|
156
|
+
version: '1.0.0',
|
|
157
|
+
description: 'No controllers found',
|
|
158
|
+
},
|
|
159
|
+
paths: {},
|
|
160
|
+
components: {
|
|
161
|
+
schemas: {},
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
it('should handle module with no imports', async () => {
|
|
166
|
+
class TestModule {
|
|
167
|
+
}
|
|
168
|
+
class TestController {
|
|
169
|
+
}
|
|
170
|
+
swagger_controller_1.SwaggerController.setRootModule(TestModule);
|
|
171
|
+
core_1.getModuleMetadata.mockReturnValue({
|
|
172
|
+
controllers: [TestController],
|
|
173
|
+
imports: undefined,
|
|
174
|
+
});
|
|
175
|
+
swaggerService.generateSpec.mockReturnValue({
|
|
176
|
+
openapi: '3.0.0',
|
|
177
|
+
info: { title: 'Test API', version: '1.0.0' },
|
|
178
|
+
paths: {},
|
|
179
|
+
components: { schemas: {} },
|
|
180
|
+
});
|
|
181
|
+
const context = {};
|
|
182
|
+
await controller.getSpec(context);
|
|
183
|
+
expect(swaggerService.generateSpec).toHaveBeenCalledWith([TestController]);
|
|
184
|
+
});
|
|
185
|
+
it('should recursively collect controllers from imported modules', async () => {
|
|
186
|
+
class RootModule {
|
|
187
|
+
}
|
|
188
|
+
class ImportedModule {
|
|
189
|
+
}
|
|
190
|
+
class RootController {
|
|
191
|
+
}
|
|
192
|
+
class ImportedController {
|
|
193
|
+
}
|
|
194
|
+
swagger_controller_1.SwaggerController.setRootModule(RootModule);
|
|
195
|
+
core_1.getModuleMetadata.mockImplementation((moduleType) => {
|
|
196
|
+
if (moduleType === RootModule) {
|
|
197
|
+
return {
|
|
198
|
+
controllers: [RootController],
|
|
199
|
+
imports: [ImportedModule],
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (moduleType === ImportedModule) {
|
|
203
|
+
return {
|
|
204
|
+
controllers: [ImportedController],
|
|
205
|
+
imports: [],
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
});
|
|
210
|
+
swaggerService.generateSpec.mockReturnValue({
|
|
211
|
+
openapi: '3.0.0',
|
|
212
|
+
info: { title: 'Test API', version: '1.0.0' },
|
|
213
|
+
paths: {},
|
|
214
|
+
components: { schemas: {} },
|
|
215
|
+
});
|
|
216
|
+
const context = {};
|
|
217
|
+
await controller.getSpec(context);
|
|
218
|
+
expect(swaggerService.generateSpec).toHaveBeenCalledWith(expect.arrayContaining([RootController, ImportedController]));
|
|
219
|
+
});
|
|
220
|
+
it('should filter out invalid controllers', async () => {
|
|
221
|
+
class TestModule {
|
|
222
|
+
}
|
|
223
|
+
class ValidController {
|
|
224
|
+
}
|
|
225
|
+
swagger_controller_1.SwaggerController.setRootModule(TestModule);
|
|
226
|
+
core_1.getModuleMetadata.mockReturnValue({
|
|
227
|
+
controllers: [ValidController, null, undefined, {}],
|
|
228
|
+
imports: [],
|
|
229
|
+
});
|
|
230
|
+
swaggerService.generateSpec.mockReturnValue({
|
|
231
|
+
openapi: '3.0.0',
|
|
232
|
+
info: { title: 'Test API', version: '1.0.0' },
|
|
233
|
+
paths: {},
|
|
234
|
+
components: { schemas: {} },
|
|
235
|
+
});
|
|
236
|
+
const context = {};
|
|
237
|
+
await controller.getSpec(context);
|
|
238
|
+
expect(swaggerService.generateSpec).toHaveBeenCalledWith([ValidController]);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
describe('getDocs', () => {
|
|
242
|
+
it('should return Swagger UI HTML', async () => {
|
|
243
|
+
const context = {};
|
|
244
|
+
const result = await controller.getDocs(context);
|
|
245
|
+
expect(result).toContain('<!DOCTYPE html>');
|
|
246
|
+
expect(result).toContain('API Documentation');
|
|
247
|
+
expect(result).toContain('Loading API Documentation...');
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { SwaggerOptions, SwaggerOperation } from './swagger.types';
|
|
3
|
+
export declare function Swagger(options: SwaggerOptions): ClassDecorator;
|
|
4
|
+
export declare function ApiOperation(operation: SwaggerOperation): MethodDecorator;
|
|
5
|
+
export declare function getSwaggerMetadata(target: object): SwaggerOptions | undefined;
|
|
6
|
+
export declare function getOperationMetadata(target: object, propertyKey: string | symbol): SwaggerOperation | undefined;
|
|
7
|
+
//# sourceMappingURL=swagger.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swagger.decorator.d.ts","sourceRoot":"","sources":["../src/swagger.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAKnE,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAM/D;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,gBAAgB,GAAG,eAAe,CAIzE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE7E;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC3B,gBAAgB,GAAG,SAAS,CAE9B"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Swagger = Swagger;
|
|
4
|
+
exports.ApiOperation = ApiOperation;
|
|
5
|
+
exports.getSwaggerMetadata = getSwaggerMetadata;
|
|
6
|
+
exports.getOperationMetadata = getOperationMetadata;
|
|
7
|
+
require("reflect-metadata");
|
|
8
|
+
const SWAGGER_METADATA_KEY = 'swagger:options';
|
|
9
|
+
const SWAGGER_OPERATION_METADATA_KEY = 'swagger:operation';
|
|
10
|
+
function Swagger(options) {
|
|
11
|
+
return (target) => {
|
|
12
|
+
const metaTarget = typeof target === 'function' ? target.prototype : target;
|
|
13
|
+
Reflect.defineMetadata(SWAGGER_METADATA_KEY, options, metaTarget);
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function ApiOperation(operation) {
|
|
17
|
+
return (target, propertyKey) => {
|
|
18
|
+
Reflect.defineMetadata(SWAGGER_OPERATION_METADATA_KEY, operation, target, propertyKey);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function getSwaggerMetadata(target) {
|
|
22
|
+
return Reflect.getMetadata(SWAGGER_METADATA_KEY, target);
|
|
23
|
+
}
|
|
24
|
+
function getOperationMetadata(target, propertyKey) {
|
|
25
|
+
return Reflect.getMetadata(SWAGGER_OPERATION_METADATA_KEY, target, propertyKey);
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swagger.decorator.test.d.ts","sourceRoot":"","sources":["../src/swagger.decorator.test.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
require("reflect-metadata");
|
|
13
|
+
const swagger_decorator_1 = require("./swagger.decorator");
|
|
14
|
+
describe('Swagger Decorators', () => {
|
|
15
|
+
describe('@Swagger', () => {
|
|
16
|
+
it('should store metadata on the prototype', () => {
|
|
17
|
+
const options = {
|
|
18
|
+
title: 'Test API',
|
|
19
|
+
description: 'Test API description',
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
tags: [{ name: 'test', description: 'Test operations' }],
|
|
22
|
+
};
|
|
23
|
+
let TestController = class TestController {
|
|
24
|
+
};
|
|
25
|
+
TestController = __decorate([
|
|
26
|
+
(0, swagger_decorator_1.Swagger)(options)
|
|
27
|
+
], TestController);
|
|
28
|
+
const metadata = (0, swagger_decorator_1.getSwaggerMetadata)(TestController.prototype);
|
|
29
|
+
expect(metadata).toBeDefined();
|
|
30
|
+
expect(metadata).toEqual(options);
|
|
31
|
+
});
|
|
32
|
+
it('should handle undefined metadata', () => {
|
|
33
|
+
class TestController {
|
|
34
|
+
}
|
|
35
|
+
const metadata = (0, swagger_decorator_1.getSwaggerMetadata)(TestController.prototype);
|
|
36
|
+
expect(metadata).toBeUndefined();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('@ApiOperation', () => {
|
|
40
|
+
it('should store operation metadata on the prototype', () => {
|
|
41
|
+
const operation = {
|
|
42
|
+
summary: 'Test operation',
|
|
43
|
+
description: 'Test operation description',
|
|
44
|
+
tags: ['test'],
|
|
45
|
+
responses: {
|
|
46
|
+
'200': {
|
|
47
|
+
description: 'Success',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
class TestController {
|
|
52
|
+
testMethod() { }
|
|
53
|
+
}
|
|
54
|
+
__decorate([
|
|
55
|
+
(0, swagger_decorator_1.ApiOperation)(operation),
|
|
56
|
+
__metadata("design:type", Function),
|
|
57
|
+
__metadata("design:paramtypes", []),
|
|
58
|
+
__metadata("design:returntype", void 0)
|
|
59
|
+
], TestController.prototype, "testMethod", null);
|
|
60
|
+
const metadata = (0, swagger_decorator_1.getOperationMetadata)(TestController.prototype, 'testMethod');
|
|
61
|
+
expect(metadata).toBeDefined();
|
|
62
|
+
expect(metadata).toEqual(operation);
|
|
63
|
+
});
|
|
64
|
+
it('should handle undefined operation metadata', () => {
|
|
65
|
+
class TestController {
|
|
66
|
+
testMethod() { }
|
|
67
|
+
}
|
|
68
|
+
const metadata = (0, swagger_decorator_1.getOperationMetadata)(TestController.prototype, 'testMethod');
|
|
69
|
+
expect(metadata).toBeUndefined();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swagger.module.d.ts","sourceRoot":"","sources":["../src/swagger.module.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGrC,qBAKa,aAAa;IACxB,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI;CAItD"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.SwaggerModule = void 0;
|
|
13
|
+
const core_1 = require("@hazeljs/core");
|
|
14
|
+
const swagger_service_1 = require("./swagger.service");
|
|
15
|
+
const swagger_controller_1 = require("./swagger.controller");
|
|
16
|
+
const core_2 = __importDefault(require("@hazeljs/core"));
|
|
17
|
+
let SwaggerModule = class SwaggerModule {
|
|
18
|
+
static setRootModule(rootModule) {
|
|
19
|
+
core_2.default.debug('SwaggerModule: Setting root module:', rootModule.name);
|
|
20
|
+
swagger_controller_1.SwaggerController.setRootModule(rootModule);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
exports.SwaggerModule = SwaggerModule;
|
|
24
|
+
exports.SwaggerModule = SwaggerModule = __decorate([
|
|
25
|
+
(0, core_1.HazelModule)({
|
|
26
|
+
providers: [swagger_service_1.SwaggerService],
|
|
27
|
+
controllers: [swagger_controller_1.SwaggerController],
|
|
28
|
+
exports: [swagger_service_1.SwaggerService],
|
|
29
|
+
})
|
|
30
|
+
], SwaggerModule);
|