tspace-spear 1.0.0 → 1.0.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.
Files changed (40) hide show
  1. package/License +1 -1
  2. package/README.md +336 -47
  3. package/build/lib/core/decorators/context.js +10 -9
  4. package/build/lib/core/decorators/context.js.map +1 -0
  5. package/build/lib/core/decorators/controller.js +1 -0
  6. package/build/lib/core/decorators/controller.js.map +1 -0
  7. package/build/lib/core/decorators/headers.js +1 -0
  8. package/build/lib/core/decorators/headers.js.map +1 -0
  9. package/build/lib/core/decorators/index.d.ts +1 -0
  10. package/build/lib/core/decorators/index.js +2 -0
  11. package/build/lib/core/decorators/index.js.map +1 -0
  12. package/build/lib/core/decorators/methods.js +1 -0
  13. package/build/lib/core/decorators/methods.js.map +1 -0
  14. package/build/lib/core/decorators/middleware.d.ts +1 -1
  15. package/build/lib/core/decorators/middleware.js +1 -0
  16. package/build/lib/core/decorators/middleware.js.map +1 -0
  17. package/build/lib/core/decorators/statusCode.js +1 -0
  18. package/build/lib/core/decorators/statusCode.js.map +1 -0
  19. package/build/lib/core/decorators/swagger.d.ts +2 -0
  20. package/build/lib/core/decorators/swagger.js +15 -0
  21. package/build/lib/core/decorators/swagger.js.map +1 -0
  22. package/build/lib/core/server/index.d.ts +53 -24
  23. package/build/lib/core/server/index.js +165 -211
  24. package/build/lib/core/server/index.js.map +1 -0
  25. package/build/lib/core/server/parser-factory.d.ts +26 -0
  26. package/build/lib/core/server/parser-factory.js +413 -0
  27. package/build/lib/core/server/parser-factory.js.map +1 -0
  28. package/build/lib/core/server/router.d.ts +2 -2
  29. package/build/lib/core/server/router.js +1 -0
  30. package/build/lib/core/server/router.js.map +1 -0
  31. package/build/lib/{types → core/types}/index.d.ts +79 -7
  32. package/build/lib/{types → core/types}/index.js +1 -0
  33. package/build/lib/core/types/index.js.map +1 -0
  34. package/build/lib/index.d.ts +4 -13
  35. package/build/lib/index.js +7 -23
  36. package/build/lib/index.js.map +1 -0
  37. package/build/tests/benchmark.test.d.ts +1 -0
  38. package/build/tests/benchmark.test.js +135 -0
  39. package/build/tests/benchmark.test.js.map +1 -0
  40. package/package.json +22 -13
@@ -35,20 +35,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.Application = void 0;
38
+ exports.Application = exports.Spear = void 0;
39
39
  const fs_1 = __importDefault(require("fs"));
40
40
  const path_1 = __importDefault(require("path"));
41
41
  const find_my_way_1 = __importDefault(require("find-my-way"));
42
- const formidable_1 = __importDefault(require("formidable"));
43
42
  const url_1 = require("url");
44
43
  const on_finished_1 = __importDefault(require("on-finished"));
45
- const string_decoder_1 = require("string_decoder");
46
44
  const http_1 = __importStar(require("http"));
45
+ const parser_factory_1 = require("./parser-factory");
47
46
  /**
48
47
  *
49
- * The 'Application' class is used to create a server and handle HTTP requests.
48
+ * The 'Spear' class is used to create a server and handle HTTP requests.
50
49
  *
51
- * @returns {Application} application
50
+ * @returns {Spear} application
52
51
  * @example
53
52
  * new Application()
54
53
  * .get('/' , () => 'Hello world!')
@@ -60,128 +59,62 @@ const http_1 = __importStar(require("http"));
60
59
  * .listen(3000 , () => console.log('server listening on port : 3000'))
61
60
  *
62
61
  */
63
- class Application {
62
+ class Spear {
64
63
  constructor({ controllers, middlewares, globalPrefix, logger } = {}) {
65
64
  this._router = (0, find_my_way_1.default)();
65
+ this._parser = new parser_factory_1.ParserFactory();
66
+ this._swagger = {
67
+ use: false,
68
+ path: '/api/docs',
69
+ servers: [
70
+ {
71
+ url: 'http://localhost:3000'
72
+ }
73
+ ],
74
+ tags: [],
75
+ info: {
76
+ title: "API Documentation",
77
+ description: "This is a sample documentation",
78
+ version: "1.0.0"
79
+ }
80
+ };
81
+ this._swaggerAdditional = [];
66
82
  this._errorHandler = null;
67
83
  this._globalMiddlewares = [];
68
84
  this._formatResponse = null;
69
85
  this._onListeners = [];
70
86
  this._fileUploadOptions = {
71
- limits: Infinity,
72
- useTempFiles: false,
87
+ limit: Infinity,
73
88
  tempFileDir: 'tmp',
74
89
  removeTempFile: {
75
- remove: true,
90
+ remove: false,
76
91
  ms: 1000 * 60 * 10
77
92
  }
78
93
  };
79
- this._filesParser = (req) => __awaiter(this, void 0, void 0, function* () {
80
- try {
81
- const temp = this._fileUploadOptions.tempFileDir;
82
- if (!fs_1.default.existsSync(temp)) {
83
- try {
84
- fs_1.default.mkdirSync(temp, { recursive: true });
85
- }
86
- catch (err) { }
87
- }
88
- const form = (0, formidable_1.default)({ uploadDir: temp });
89
- const [dataBody, dataFiles] = yield form.parse(req);
90
- const files = {};
91
- const body = {};
92
- const removeTemp = (fileTemp) => {
93
- if (!this._fileUploadOptions.removeTempFile.remove)
94
- return;
95
- const remove = () => fs_1.default.unlinkSync(fileTemp);
96
- setTimeout(remove, this._fileUploadOptions.removeTempFile.ms);
97
- };
98
- for (const key in dataFiles) {
99
- const v = dataFiles[key];
100
- if (v == null)
101
- continue;
102
- const file = v[0];
103
- if (file.size > this._fileUploadOptions.limits) {
104
- fs_1.default.unlinkSync(file.filepath);
105
- continue;
106
- }
107
- files[key] = {
108
- size: file.size,
109
- tempFilePath: file.filepath,
110
- tempFileName: file.newFilename,
111
- mimetype: file.mimetype,
112
- name: file.originalFilename
113
- };
114
- removeTemp(file.filepath);
115
- }
116
- for (const key in dataBody) {
117
- const v = dataBody[key];
118
- if (v == null)
119
- continue;
120
- body[key] = v[0];
121
- }
122
- return {
123
- body,
124
- files
125
- };
126
- }
127
- catch (e) {
128
- return {
129
- body: {},
130
- files: {}
131
- };
132
- }
133
- });
134
- this._bodyParser = (req) => {
135
- if ((req === null || req === void 0 ? void 0 : req._writeParserEnd) === true)
136
- return req._bodyParser;
137
- return new Promise((resolve, reject) => {
138
- const decoder = new string_decoder_1.StringDecoder('utf-8');
139
- let payload = '';
140
- req.on('data', (data) => {
141
- payload += decoder.write(data);
142
- });
143
- req.on('end', () => {
144
- try {
145
- payload += decoder.end();
146
- req._writeParserEnd = true;
147
- req._bodyParser = JSON.parse(payload);
148
- return resolve(JSON.parse(payload));
149
- }
150
- catch (e) {
151
- req._writeParserEnd = true;
152
- req._bodyParser = {};
153
- return resolve({});
154
- }
155
- });
156
- req.on('error', (err) => {
157
- req._writeParserEnd = true;
158
- req._bodyParser = {};
159
- return reject(err);
160
- });
161
- });
162
- };
163
94
  this._wrapHandlers = (...handlers) => {
164
95
  return (req, res, params) => __awaiter(this, void 0, void 0, function* () {
165
- const runHandler = (index = 0) => __awaiter(this, void 0, void 0, function* () {
96
+ const runHandler = (...args_1) => __awaiter(this, [...args_1], void 0, function* (index = 0) {
166
97
  const response = this._customizeResponse(req, res);
167
98
  const request = req;
168
99
  const body = request._bodyParser;
169
100
  const files = request._filesParser;
170
101
  const cookies = request._cookiesParser;
102
+ const headers = request.headers;
171
103
  const query = Object.assign({}, (0, url_1.parse)(String(req.url), true).query);
172
- const objectOrNull = (data) => {
104
+ const RecordOrEmptyRecord = (data) => {
173
105
  if (data == null)
174
- return null;
175
- return Object.keys(data).length ? data : null;
106
+ return {};
107
+ return Object.keys(data).length ? data : {};
176
108
  };
177
109
  const ctx = {
178
110
  req: request,
179
111
  res: response,
180
- params: objectOrNull(params),
181
- query: objectOrNull(query),
182
- body: objectOrNull(body),
183
- files: objectOrNull(files),
184
- cookies: objectOrNull(cookies),
112
+ headers: RecordOrEmptyRecord(headers),
113
+ params: RecordOrEmptyRecord(params),
114
+ query: RecordOrEmptyRecord(query),
115
+ body: RecordOrEmptyRecord(body),
116
+ files: RecordOrEmptyRecord(files),
117
+ cookies: RecordOrEmptyRecord(cookies),
185
118
  };
186
119
  if (index === handlers.length - 1) {
187
120
  return this._wrapResponse(handlers[index].bind(handlers[index]))(ctx, this._nextFunction(ctx));
@@ -195,11 +128,12 @@ class Application {
195
128
  const ctx = {
196
129
  req,
197
130
  res: this._customizeResponse(req, res),
198
- params: Object.keys(params).length ? params : null,
199
- query: null,
200
- body: null,
201
- files: null,
202
- cookies: null
131
+ params: Object.keys(params).length ? params : {},
132
+ headers: {},
133
+ query: {},
134
+ body: {},
135
+ files: {},
136
+ cookies: {}
203
137
  };
204
138
  return this._nextFunction(ctx)(err);
205
139
  });
@@ -211,6 +145,12 @@ class Application {
211
145
  this._middlewares = middlewares;
212
146
  this._globalPrefix = globalPrefix == null ? '' : globalPrefix;
213
147
  }
148
+ get instance() {
149
+ return this;
150
+ }
151
+ get routers() {
152
+ return this._router;
153
+ }
214
154
  /**
215
155
  * The 'enableCors' is used to enable the cors origins on the server.
216
156
  *
@@ -225,7 +165,7 @@ class Application {
225
165
  const origin = (_a = req.headers) === null || _a === void 0 ? void 0 : _a.origin;
226
166
  if (origin == null)
227
167
  return next();
228
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
168
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
229
169
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
230
170
  if (origins == null) {
231
171
  res.setHeader('Access-Control-Allow-Origin', '*');
@@ -254,44 +194,20 @@ class Application {
254
194
  this._globalMiddlewares.push(middleware);
255
195
  return this;
256
196
  }
257
- /**
258
- * The 'useRouter' method is used to add the router in the request context.
259
- *
260
- * @parms {Function} router
261
- * @property {Function} router - get() , post() , put() , patch() , delete()
262
- * @returns {this}
263
- */
264
- useRouter(router) {
265
- const routes = router.routes;
266
- for (const { path, method, handlers } of routes) {
267
- let normalizePath = [
268
- this._globalPrefix,
269
- path
270
- ].join('/')
271
- .replace(/\/+/g, '/')
272
- .replace(/\/+$/, '');
273
- normalizePath = normalizePath.startsWith('/') ? normalizePath : `/${normalizePath}`;
274
- this[method](normalizePath, ...handlers);
275
- }
276
- return this;
277
- }
278
197
  /**
279
198
  * The 'useBodyParser' method is a middleware used to parse the request body of incoming HTTP requests.
280
199
  *
281
200
  * @returns {this}
282
201
  */
283
202
  useBodyParser() {
284
- this._globalMiddlewares.push(({ req, res }, next) => __awaiter(this, void 0, void 0, function* () {
203
+ this._globalMiddlewares.push((_a, next_1) => __awaiter(this, [_a, next_1], void 0, function* ({ req, res }, next) {
285
204
  const contentType = req === null || req === void 0 ? void 0 : req.headers['content-type'];
286
205
  const isFileUpload = contentType && contentType.startsWith('multipart/form-data');
287
- const isListMethods = ['POST', 'PATCH', 'PUT'].includes(String(req.method));
288
- if (!isListMethods)
289
- return next();
290
206
  if (isFileUpload)
291
207
  return next();
292
208
  if ((req === null || req === void 0 ? void 0 : req._bodyParser) != null)
293
209
  return next();
294
- req._bodyParser = yield this._bodyParser(req);
210
+ req._bodyParser = yield this._parser.body(req);
295
211
  return next();
296
212
  }));
297
213
  return this;
@@ -305,37 +221,47 @@ class Application {
305
221
  this._globalMiddlewares.push(({ req }, next) => {
306
222
  if ((req === null || req === void 0 ? void 0 : req._cookiesParser) != null)
307
223
  return next();
308
- req._cookiesParser = this._cookiesParser(req);
224
+ req._cookiesParser = this._parser.cookies(req);
309
225
  return next();
310
226
  });
311
227
  return this;
312
228
  }
229
+ /**
230
+ * The 'useRouter' method is used to add the router in the request context.
231
+ *
232
+ * @parms {Function} router
233
+ * @property {Function} router - get() , post() , put() , patch() , delete()
234
+ * @returns {this}
235
+ */
236
+ useRouter(router) {
237
+ const routes = router.routes;
238
+ for (const { path, method, handlers } of routes) {
239
+ this[method](this._normalizePath(this._globalPrefix, path), ...handlers);
240
+ }
241
+ return this;
242
+ }
313
243
  /**
314
244
  * The 'useFileUpload' method is a middleware used to handler file uploads. It adds a file upload of incoming HTTP requests.
315
245
  *
316
246
  * @param {?Object}
317
247
  * @property {?number} limits
318
- * @property {?boolean} useTempFiles
319
248
  * @property {?string} tempFileDir
320
249
  * @property {?Object} removeTempFile
321
250
  * @property {boolean} removeTempFile.remove
322
251
  * @property {number} removeTempFile.ms
323
252
  * @returns
324
253
  */
325
- useFileUpload({ limits, useTempFiles, tempFileDir, removeTempFile } = {}) {
326
- if (limits != null) {
327
- this._fileUploadOptions.limits = limits;
254
+ useFileUpload({ limit, tempFileDir, removeTempFile } = {}) {
255
+ if (limit != null) {
256
+ this._fileUploadOptions.limit = limit;
328
257
  }
329
258
  if (tempFileDir != null) {
330
259
  this._fileUploadOptions.tempFileDir = tempFileDir;
331
260
  }
332
- if (useTempFiles != null) {
333
- this._fileUploadOptions.useTempFiles = useTempFiles;
334
- }
335
261
  if (removeTempFile != null) {
336
262
  this._fileUploadOptions.removeTempFile = removeTempFile;
337
263
  }
338
- this._globalMiddlewares.push(({ req }, next) => __awaiter(this, void 0, void 0, function* () {
264
+ this._globalMiddlewares.push((_a, next_1) => __awaiter(this, [_a, next_1], void 0, function* ({ req }, next) {
339
265
  const contentType = req === null || req === void 0 ? void 0 : req.headers['content-type'];
340
266
  const isFileUpload = contentType && contentType.startsWith('multipart/form-data');
341
267
  const isListMethods = ['POST', 'PATCH', 'PUT'].includes(String(req.method));
@@ -345,13 +271,33 @@ class Application {
345
271
  return next();
346
272
  if ((req === null || req === void 0 ? void 0 : req._filesParser) != null)
347
273
  return next();
348
- const { body, files } = yield this._filesParser(req);
274
+ const { body, files } = yield this._parser.files({ req, options: this._fileUploadOptions });
349
275
  req._filesParser = files;
350
276
  req._bodyParser = body;
351
277
  return next();
352
278
  }));
353
279
  return this;
354
280
  }
281
+ /**
282
+ * The 'useSwagger' method is a middleware used to create swagger api.
283
+ *
284
+ * @param {?Object}
285
+ * @property {?string} path
286
+ * @property {?array} servers
287
+ * @property {?object} info
288
+ * @property {?array} tags
289
+ * @returns
290
+ */
291
+ useSwagger({ path, servers, info, tags } = {}) {
292
+ this._swagger = {
293
+ use: true,
294
+ path: path !== null && path !== void 0 ? path : this._swagger.path,
295
+ servers: servers !== null && servers !== void 0 ? servers : this._swagger.servers,
296
+ tags: tags !== null && tags !== void 0 ? tags : this._swagger.tags,
297
+ info: info !== null && info !== void 0 ? info : this._swagger.info
298
+ };
299
+ return this;
300
+ }
355
301
  /**
356
302
  * The 'formatResponse' method is used to format the response
357
303
  *
@@ -383,11 +329,12 @@ class Application {
383
329
  return notfound({
384
330
  req,
385
331
  res: this._customizeResponse(req, res),
386
- query: null,
387
- files: null,
388
- body: null,
389
- params: null,
390
- cookies: null
332
+ headers: {},
333
+ query: {},
334
+ files: {},
335
+ body: {},
336
+ params: {},
337
+ cookies: {}
391
338
  });
392
339
  };
393
340
  this._onListeners.push(() => {
@@ -406,7 +353,7 @@ class Application {
406
353
  */
407
354
  get(path, ...handlers) {
408
355
  this._onListeners.push(() => {
409
- return this._router.get(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
356
+ return this._router.get(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
410
357
  });
411
358
  return this;
412
359
  }
@@ -421,7 +368,7 @@ class Application {
421
368
  */
422
369
  post(path, ...handlers) {
423
370
  this._onListeners.push(() => {
424
- return this._router.post(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
371
+ return this._router.post(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
425
372
  });
426
373
  return this;
427
374
  }
@@ -436,7 +383,7 @@ class Application {
436
383
  */
437
384
  put(path, ...handlers) {
438
385
  this._onListeners.push(() => {
439
- return this._router.put(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
386
+ return this._router.put(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
440
387
  });
441
388
  return this;
442
389
  }
@@ -451,7 +398,7 @@ class Application {
451
398
  */
452
399
  patch(path, ...handlers) {
453
400
  this._onListeners.push(() => {
454
- return this._router.patch(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
401
+ return this._router.patch(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
455
402
  });
456
403
  return this;
457
404
  }
@@ -466,7 +413,7 @@ class Application {
466
413
  */
467
414
  delete(path, ...handlers) {
468
415
  this._onListeners.push(() => {
469
- return this._router.delete(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
416
+ return this._router.delete(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
470
417
  });
471
418
  return this;
472
419
  }
@@ -481,7 +428,7 @@ class Application {
481
428
  */
482
429
  all(path, ...handlers) {
483
430
  this._onListeners.push(() => {
484
- return this._router.all(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
431
+ return this._router.all(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
485
432
  });
486
433
  return this;
487
434
  }
@@ -492,24 +439,36 @@ class Application {
492
439
  * @param {function} cb
493
440
  * @returns
494
441
  */
495
- listen(port = 3000, cb) {
496
- return __awaiter(this, arguments, void 0, function* () {
497
- if (arguments.length === 1 && typeof port === 'function') {
442
+ listen() {
443
+ var arguments_1 = arguments;
444
+ return __awaiter(this, arguments, void 0, function* (port = 3000, cb) {
445
+ if (arguments_1.length === 1 && typeof port === 'function') {
498
446
  cb = port;
499
447
  port = 3000;
500
448
  }
501
449
  const server = yield this._createServer();
450
+ server.listen(port == null ? 3000 : port, () => {
451
+ if (cb)
452
+ cb({ server, port });
453
+ });
502
454
  server.on('listening', () => {
503
455
  this._onListeners.forEach(listener => listener());
456
+ if (this._swagger.use) {
457
+ const routes = this.routers
458
+ .routes.filter(r => ["GET", "POST", "PUT", "PATCH", "DELETE"].includes(r.method));
459
+ const { path, html, staticSwaggerHandler, staticUrl } = this._parser.swagger(Object.assign(Object.assign({}, this._swagger), { options: this._swaggerAdditional, routes }));
460
+ this.routers.get(staticUrl, staticSwaggerHandler);
461
+ this.routers.get(String(path), (req, res) => {
462
+ res.writeHead(200, { 'Content-Type': 'text/html' });
463
+ res.write(html);
464
+ return res.end();
465
+ });
466
+ }
504
467
  });
505
468
  server.on('error', (_) => {
506
469
  port = Math.floor(Math.random() * 8999) + 1000;
507
470
  server.listen(port);
508
471
  });
509
- server.listen(port == null ? 3000 : port, () => {
510
- if (cb)
511
- cb();
512
- });
513
472
  return;
514
473
  });
515
474
  }
@@ -560,6 +519,7 @@ class Application {
560
519
  }
561
520
  _registerControllers() {
562
521
  return __awaiter(this, void 0, void 0, function* () {
522
+ var _a, _b, _c, _d, _e, _f;
563
523
  if (this._controllers == null)
564
524
  return;
565
525
  if (!Array.isArray(this._controllers)) {
@@ -568,40 +528,40 @@ class Application {
568
528
  const response = yield Promise.resolve(`${file}`).then(s => __importStar(require(s)));
569
529
  const controller = response === null || response === void 0 ? void 0 : response.default;
570
530
  const controllerInstance = new controller();
571
- const prefixPath = Reflect.getMetadata("controllers", controller);
572
- const routers = Reflect.getMetadata("routers", controller);
531
+ const prefixPath = (_a = Reflect.getMetadata("controllers", controller)) !== null && _a !== void 0 ? _a : '';
532
+ const routers = (_b = Reflect.getMetadata("routers", controller)) !== null && _b !== void 0 ? _b : [];
533
+ const swaggers = (_c = Reflect.getMetadata("swaggers", controller)) !== null && _c !== void 0 ? _c : [];
573
534
  if (prefixPath == null)
574
535
  continue;
575
- for (const { method, path, handler } of routers) {
576
- let normalizePath = [
577
- this._globalPrefix,
578
- prefixPath,
579
- path
580
- ].join('/')
581
- .replace(/\/+/g, '/')
582
- .replace(/\/+$/, '');
583
- normalizePath = normalizePath.startsWith('/') ? normalizePath : `/${normalizePath}`;
584
- this[method](normalizePath, this._wrapResponse(controllerInstance[String(handler)].bind(controllerInstance)));
536
+ for (const { method, path, handler } of Array.from(routers)) {
537
+ const find = Array.from(swaggers).find(s => s.handler === handler);
538
+ if (find != null) {
539
+ this._swaggerAdditional = [
540
+ ...this._swaggerAdditional,
541
+ Object.assign(Object.assign({}, find), { path: this._normalizePath(this._globalPrefix, prefixPath, path), method })
542
+ ];
543
+ }
544
+ this[method](this._normalizePath(this._globalPrefix, prefixPath, path), this._wrapResponse(controllerInstance[String(handler)].bind(controllerInstance)));
585
545
  }
586
546
  }
587
547
  return;
588
548
  }
589
549
  for (const controller of this._controllers) {
590
550
  const controllerInstance = new controller();
591
- const prefixPath = Reflect.getMetadata("controllers", controller);
592
- const routers = Reflect.getMetadata("routers", controller);
551
+ const prefixPath = (_d = Reflect.getMetadata("controllers", controller)) !== null && _d !== void 0 ? _d : '';
552
+ const routers = (_e = Reflect.getMetadata("routers", controller)) !== null && _e !== void 0 ? _e : [];
553
+ const swaggers = (_f = Reflect.getMetadata("swaggers", controller)) !== null && _f !== void 0 ? _f : [];
593
554
  if (prefixPath == null)
594
555
  continue;
595
- for (const { method, path, handler } of routers) {
596
- let normalizePath = [
597
- this._globalPrefix,
598
- prefixPath,
599
- path
600
- ].join('/')
601
- .replace(/\/+/g, '/')
602
- .replace(/\/+$/, '');
603
- normalizePath = normalizePath.startsWith('/') ? normalizePath : `/${normalizePath}`;
604
- this[method](normalizePath, this._wrapResponse(controllerInstance[String(handler)].bind(controllerInstance)));
556
+ for (const { method, path, handler } of Array.from(routers)) {
557
+ const find = Array.from(swaggers).find(s => s.handler === handler);
558
+ if (find != null) {
559
+ this._swaggerAdditional = [
560
+ ...this._swaggerAdditional,
561
+ Object.assign(Object.assign({}, find), { path: this._normalizePath(this._globalPrefix, prefixPath, path), method })
562
+ ];
563
+ }
564
+ this[method](this._normalizePath(this._globalPrefix, prefixPath, path), this._wrapResponse(controllerInstance[String(handler)].bind(controllerInstance)));
605
565
  }
606
566
  }
607
567
  });
@@ -626,28 +586,6 @@ class Application {
626
586
  return;
627
587
  });
628
588
  }
629
- _cookiesParser(req) {
630
- var _a;
631
- const cookies = {};
632
- const cookieString = (_a = req.headers) === null || _a === void 0 ? void 0 : _a.cookie;
633
- if (cookieString == null)
634
- return null;
635
- for (const cookie of cookieString.split(';')) {
636
- const [name, value] = cookie.split('=').map(v => v.trim());
637
- cookies[name] = decodeURIComponent(value);
638
- }
639
- for (const name of Object.keys(cookies)) {
640
- const cookie = cookies[name];
641
- if (!cookie.startsWith('Expires='))
642
- continue;
643
- const expiresString = cookie.replace('Expires=', '');
644
- const expiresDate = new Date(expiresString);
645
- if (isNaN(expiresDate.getTime()) || expiresDate < new Date()) {
646
- delete cookies[name];
647
- }
648
- }
649
- return cookies;
650
- }
651
589
  _customizeResponse(req, res) {
652
590
  const response = res;
653
591
  response.json = (results) => {
@@ -837,8 +775,6 @@ class Application {
837
775
  _wrapResponse(handler) {
838
776
  return (ctx, next) => __awaiter(this, void 0, void 0, function* () {
839
777
  const result = yield handler(ctx, next);
840
- if (result == null)
841
- return;
842
778
  if (result instanceof http_1.ServerResponse)
843
779
  return;
844
780
  if (typeof result === 'string') {
@@ -858,11 +794,17 @@ class Application {
858
794
  if (!ctx.res.headersSent) {
859
795
  ctx.res.writeHead(200, { 'Content-Type': 'application/json' });
860
796
  }
797
+ if (Array.isArray(result)) {
798
+ return ctx.res.end(JSON.stringify(this._formatResponse(result)));
799
+ }
861
800
  return ctx.res.end(JSON.stringify(this._formatResponse(Object.assign({}, result), ctx.res.statusCode), null, 2));
862
801
  }
863
802
  if (!ctx.res.headersSent) {
864
803
  ctx.res.writeHead(200, { 'Content-Type': 'application/json' });
865
804
  }
805
+ if (Array.isArray(result)) {
806
+ return ctx.res.end(JSON.stringify(result));
807
+ }
866
808
  return ctx.res.end(JSON.stringify(Object.assign({}, result), null, 2));
867
809
  });
868
810
  }
@@ -876,6 +818,18 @@ class Application {
876
818
  return server;
877
819
  });
878
820
  }
821
+ _normalizePath(...paths) {
822
+ const path = paths
823
+ .join('/')
824
+ .replace(/\/+/g, '/')
825
+ .replace(/\/+$/, '');
826
+ const normalizedPath = path.startsWith('/') ? path : `/${path}`;
827
+ return /\/api\/api/.test(normalizedPath) ? normalizedPath.replace(/\/api\/api\//, "/api/") : normalizedPath;
828
+ }
829
+ }
830
+ exports.Spear = Spear;
831
+ class Application extends Spear {
879
832
  }
880
833
  exports.Application = Application;
881
- exports.default = Application;
834
+ exports.default = Spear;
835
+ //# sourceMappingURL=index.js.map