@nestia/core 0.1.4 → 0.1.5

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 (49) hide show
  1. package/lib/decorators/DynamicModule.d.ts +3 -0
  2. package/lib/decorators/DynamicModule.js +73 -0
  3. package/lib/decorators/DynamicModule.js.map +1 -0
  4. package/lib/decorators/EncryptedModule.js +16 -137
  5. package/lib/decorators/EncryptedModule.js.map +1 -1
  6. package/lib/decorators/internal/headers_to_object.d.ts +3 -1
  7. package/lib/decorators/internal/headers_to_object.js +0 -3
  8. package/lib/decorators/internal/headers_to_object.js.map +1 -1
  9. package/lib/decorators/internal/load_controller.d.ts +2 -0
  10. package/lib/decorators/internal/load_controller.js +153 -0
  11. package/lib/decorators/internal/load_controller.js.map +1 -0
  12. package/lib/decorators/internal/route_error.d.ts +3 -1
  13. package/lib/decorators/internal/route_error.js +0 -3
  14. package/lib/decorators/internal/route_error.js.map +1 -1
  15. package/lib/module.d.ts +2 -0
  16. package/lib/module.js +2 -0
  17. package/lib/module.js.map +1 -1
  18. package/package.json +1 -1
  19. package/src/decorators/DynamicModule.ts +16 -0
  20. package/src/decorators/EncryptedBody.ts +102 -102
  21. package/src/decorators/EncryptedController.ts +43 -43
  22. package/src/decorators/EncryptedModule.ts +77 -127
  23. package/src/decorators/EncryptedRoute.ts +203 -203
  24. package/src/decorators/PlainBody.ts +38 -38
  25. package/src/decorators/TypedBody.ts +49 -49
  26. package/src/decorators/TypedParam.ts +70 -70
  27. package/src/decorators/TypedRoute.ts +149 -149
  28. package/src/decorators/internal/EncryptedConstant.ts +4 -4
  29. package/src/decorators/internal/get_path_and_stringify.ts +77 -77
  30. package/src/decorators/internal/headers_to_object.ts +10 -13
  31. package/src/decorators/internal/load_controller.ts +35 -0
  32. package/src/decorators/internal/route_error.ts +38 -41
  33. package/src/decorators/internal/validate_request_body.ts +59 -59
  34. package/src/index.ts +5 -5
  35. package/src/module.ts +11 -9
  36. package/src/options/INestiaTransformOptions.ts +6 -6
  37. package/src/options/INestiaTransformProject.ts +7 -6
  38. package/src/options/IRequestBodyValidator.ts +20 -20
  39. package/src/options/IResponseBodyStringifier.ts +25 -25
  40. package/src/transform.ts +20 -20
  41. package/src/transformers/BodyTransformer.ts +106 -106
  42. package/src/transformers/FileTransformer.ts +49 -49
  43. package/src/transformers/MethodTransformer.ts +91 -91
  44. package/src/transformers/NodeTransformer.ts +18 -18
  45. package/src/transformers/ParameterTransformer.ts +45 -45
  46. package/src/transformers/RouteTransformer.ts +131 -131
  47. package/src/typings/Creator.ts +3 -3
  48. package/src/utils/ExceptionManager.ts +126 -126
  49. package/src/utils/Singleton.ts +20 -20
@@ -1,70 +1,70 @@
1
- import {
2
- BadRequestException,
3
- ExecutionContext,
4
- createParamDecorator,
5
- } from "@nestjs/common";
6
- import type express from "express";
7
-
8
- /**
9
- * URL parameter decorator with type.
10
- *
11
- * `TypedParam` is a decorator function getting specific typed parameter from the HTTP
12
- * request URL. It's almost same with the {@link nest.Param}, but `TypedParam` can specify
13
- * the parameter type manually. Beside, the {@link nest.Param} always parses all of the
14
- * parameters as string type.
15
- *
16
- * ```typescript
17
- * \@TypedRoute.Get("shopping/sales/:section/:id/:paused")
18
- * public async pause
19
- * (
20
- * \@TypedParam("section", "string") section: string,
21
- * \@TypedParam("id", "number") id: number,
22
- * \@TypedParam("paused", "boolean", true) paused: boolean | null
23
- * ): Promise<void>;
24
- * ```
25
- *
26
- * @param name URL Parameter name
27
- * @param type Type of the URL parameter
28
- * @returns Parameter decorator
29
- *
30
- * @author Jeongho Nam - https://github.com/samchon
31
- */
32
- export function TypedParam(
33
- name: string,
34
- type: "boolean" | "number" | "string" | "uuid" = "string",
35
- nullable: boolean = false,
36
- ) {
37
- return createParamDecorator(function TypedParam(
38
- {}: any,
39
- ctx: ExecutionContext,
40
- ) {
41
- const request: express.Request = ctx.switchToHttp().getRequest();
42
- const str: string = request.params[name];
43
-
44
- if (nullable === true && str === "null") return null;
45
- else if (type === "boolean") {
46
- if (str === "true" || str === "1") return true;
47
- else if (str === "false" || str === "0") return false;
48
- else
49
- throw new BadRequestException(
50
- `Value of the URL parameter '${name}' is not a boolean.`,
51
- );
52
- } else if (type === "number") {
53
- const value: number = Number(str);
54
- if (isNaN(value))
55
- throw new BadRequestException(
56
- `Value of the URL parameter "${name}" is not a number.`,
57
- );
58
- return value;
59
- } else if (type === "uuid") {
60
- if (UUID_PATTERN.test(str) === false)
61
- throw new BadRequestException(
62
- `Value of the URL parameter "${name}" is not a valid UUID.`,
63
- );
64
- return str;
65
- } else return str;
66
- })(name);
67
- }
68
-
69
- const UUID_PATTERN =
70
- /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i;
1
+ import {
2
+ BadRequestException,
3
+ ExecutionContext,
4
+ createParamDecorator,
5
+ } from "@nestjs/common";
6
+ import type express from "express";
7
+
8
+ /**
9
+ * URL parameter decorator with type.
10
+ *
11
+ * `TypedParam` is a decorator function getting specific typed parameter from the HTTP
12
+ * request URL. It's almost same with the {@link nest.Param}, but `TypedParam` can specify
13
+ * the parameter type manually. Beside, the {@link nest.Param} always parses all of the
14
+ * parameters as string type.
15
+ *
16
+ * ```typescript
17
+ * \@TypedRoute.Get("shopping/sales/:section/:id/:paused")
18
+ * public async pause
19
+ * (
20
+ * \@TypedParam("section", "string") section: string,
21
+ * \@TypedParam("id", "number") id: number,
22
+ * \@TypedParam("paused", "boolean", true) paused: boolean | null
23
+ * ): Promise<void>;
24
+ * ```
25
+ *
26
+ * @param name URL Parameter name
27
+ * @param type Type of the URL parameter
28
+ * @returns Parameter decorator
29
+ *
30
+ * @author Jeongho Nam - https://github.com/samchon
31
+ */
32
+ export function TypedParam(
33
+ name: string,
34
+ type: "boolean" | "number" | "string" | "uuid" = "string",
35
+ nullable: boolean = false,
36
+ ) {
37
+ return createParamDecorator(function TypedParam(
38
+ {}: any,
39
+ ctx: ExecutionContext,
40
+ ) {
41
+ const request: express.Request = ctx.switchToHttp().getRequest();
42
+ const str: string = request.params[name];
43
+
44
+ if (nullable === true && str === "null") return null;
45
+ else if (type === "boolean") {
46
+ if (str === "true" || str === "1") return true;
47
+ else if (str === "false" || str === "0") return false;
48
+ else
49
+ throw new BadRequestException(
50
+ `Value of the URL parameter '${name}' is not a boolean.`,
51
+ );
52
+ } else if (type === "number") {
53
+ const value: number = Number(str);
54
+ if (isNaN(value))
55
+ throw new BadRequestException(
56
+ `Value of the URL parameter "${name}" is not a number.`,
57
+ );
58
+ return value;
59
+ } else if (type === "uuid") {
60
+ if (UUID_PATTERN.test(str) === false)
61
+ throw new BadRequestException(
62
+ `Value of the URL parameter "${name}" is not a valid UUID.`,
63
+ );
64
+ return str;
65
+ } else return str;
66
+ })(name);
67
+ }
68
+
69
+ const UUID_PATTERN =
70
+ /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i;
@@ -1,149 +1,149 @@
1
- import {
2
- CallHandler,
3
- Delete,
4
- ExecutionContext,
5
- Get,
6
- NestInterceptor,
7
- Patch,
8
- Post,
9
- Put,
10
- UseInterceptors,
11
- applyDecorators,
12
- } from "@nestjs/common";
13
- import { HttpArgumentsHost } from "@nestjs/common/interfaces";
14
- import express from "express";
15
- import { Observable, catchError, map } from "rxjs";
16
- import {
17
- assertStringify,
18
- isStringify,
19
- stringify,
20
- validateStringify,
21
- } from "typia";
22
-
23
- import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
24
- import { get_path_and_stringify } from "./internal/get_path_and_stringify";
25
- import { route_error } from "./internal/route_error";
26
-
27
- /**
28
- * Safe router decorator functions.
29
- *
30
- * `TypedRoute` is a module containing router decorator functions which can boost up
31
- * JSON string conversion speed about 5x times faster, through
32
- * [`typia.stringify()`](https://github.com/samchon/typia#fastest-json-string-conversion).
33
- *
34
- * Also, router functions in `TypedRoute` can convert custom error classes to the
35
- * regular {@link nest.HttpException} class automatically, through
36
- * {@link ExceptionManager}.
37
- *
38
- * @author Jeongho Nam - https://github.com/samchon
39
- */
40
- export namespace TypedRoute {
41
- /**
42
- * Router decorator function for the GET method.
43
- *
44
- * @param path Path of the HTTP request
45
- * @returns Method decorator
46
- */
47
- export const Get = Generator("Get");
48
-
49
- /**
50
- * Router decorator function for the POST method.
51
- *
52
- * @param path Path of the HTTP request
53
- * @returns Method decorator
54
- */
55
- export const Post = Generator("Post");
56
-
57
- /**
58
- * Router decorator function for the PATH method.
59
- *
60
- * @param path Path of the HTTP request
61
- * @returns Method decorator
62
- */
63
- export const Patch = Generator("Patch");
64
-
65
- /**
66
- * Router decorator function for the PUT method.
67
- *
68
- * @param path Path of the HTTP request
69
- * @returns Method decorator
70
- */
71
- export const Put = Generator("Put");
72
-
73
- /**
74
- * Router decorator function for the DELETE method.
75
- *
76
- * @param path Path of the HTTP request
77
- * @returns Method decorator
78
- */
79
- export const Delete = Generator("Delete");
80
-
81
- /**
82
- * @internal
83
- */
84
- function Generator(method: "Get" | "Post" | "Put" | "Patch" | "Delete") {
85
- function route(path?: string | string[]): MethodDecorator;
86
- function route<T>(
87
- stringify?: IResponseBodyStringifier<T>,
88
- ): MethodDecorator;
89
- function route<T>(
90
- path: string | string[],
91
- stringify?: IResponseBodyStringifier<T>,
92
- ): MethodDecorator;
93
-
94
- function route(...args: any[]): MethodDecorator {
95
- const [path, stringify] = get_path_and_stringify(
96
- `TypedRoute.${method}`,
97
- )(...args);
98
- return applyDecorators(
99
- ROUTERS[method](path),
100
- UseInterceptors(new TypedRouteInterceptor(stringify)),
101
- );
102
- }
103
- return route;
104
- }
105
- }
106
- for (const method of [
107
- assertStringify,
108
- isStringify,
109
- stringify,
110
- validateStringify,
111
- ]) {
112
- Object.assign(TypedRoute.Get, method);
113
- Object.assign(TypedRoute.Delete, method);
114
- Object.assign(TypedRoute.Post, method);
115
- Object.assign(TypedRoute.Put, method);
116
- Object.assign(TypedRoute.Patch, method);
117
- }
118
-
119
- /**
120
- * @internal
121
- */
122
- class TypedRouteInterceptor implements NestInterceptor {
123
- public constructor(private readonly stringify: (input: any) => string) {}
124
-
125
- public intercept(
126
- context: ExecutionContext,
127
- next: CallHandler,
128
- ): Observable<any> {
129
- const http: HttpArgumentsHost = context.switchToHttp();
130
- const response: express.Response = http.getResponse();
131
- response.header("Content-Type", "application/json");
132
-
133
- return next.handle().pipe(
134
- map((value) => this.stringify(value)),
135
- catchError((err) => route_error(http.getRequest(), err)),
136
- );
137
- }
138
- }
139
-
140
- /**
141
- * @internal
142
- */
143
- const ROUTERS = {
144
- Get,
145
- Post,
146
- Patch,
147
- Put,
148
- Delete,
149
- };
1
+ import {
2
+ CallHandler,
3
+ Delete,
4
+ ExecutionContext,
5
+ Get,
6
+ NestInterceptor,
7
+ Patch,
8
+ Post,
9
+ Put,
10
+ UseInterceptors,
11
+ applyDecorators,
12
+ } from "@nestjs/common";
13
+ import { HttpArgumentsHost } from "@nestjs/common/interfaces";
14
+ import express from "express";
15
+ import { Observable, catchError, map } from "rxjs";
16
+ import {
17
+ assertStringify,
18
+ isStringify,
19
+ stringify,
20
+ validateStringify,
21
+ } from "typia";
22
+
23
+ import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
24
+ import { get_path_and_stringify } from "./internal/get_path_and_stringify";
25
+ import { route_error } from "./internal/route_error";
26
+
27
+ /**
28
+ * Safe router decorator functions.
29
+ *
30
+ * `TypedRoute` is a module containing router decorator functions which can boost up
31
+ * JSON string conversion speed about 5x times faster, through
32
+ * [`typia.stringify()`](https://github.com/samchon/typia#fastest-json-string-conversion).
33
+ *
34
+ * Also, router functions in `TypedRoute` can convert custom error classes to the
35
+ * regular {@link nest.HttpException} class automatically, through
36
+ * {@link ExceptionManager}.
37
+ *
38
+ * @author Jeongho Nam - https://github.com/samchon
39
+ */
40
+ export namespace TypedRoute {
41
+ /**
42
+ * Router decorator function for the GET method.
43
+ *
44
+ * @param path Path of the HTTP request
45
+ * @returns Method decorator
46
+ */
47
+ export const Get = Generator("Get");
48
+
49
+ /**
50
+ * Router decorator function for the POST method.
51
+ *
52
+ * @param path Path of the HTTP request
53
+ * @returns Method decorator
54
+ */
55
+ export const Post = Generator("Post");
56
+
57
+ /**
58
+ * Router decorator function for the PATH method.
59
+ *
60
+ * @param path Path of the HTTP request
61
+ * @returns Method decorator
62
+ */
63
+ export const Patch = Generator("Patch");
64
+
65
+ /**
66
+ * Router decorator function for the PUT method.
67
+ *
68
+ * @param path Path of the HTTP request
69
+ * @returns Method decorator
70
+ */
71
+ export const Put = Generator("Put");
72
+
73
+ /**
74
+ * Router decorator function for the DELETE method.
75
+ *
76
+ * @param path Path of the HTTP request
77
+ * @returns Method decorator
78
+ */
79
+ export const Delete = Generator("Delete");
80
+
81
+ /**
82
+ * @internal
83
+ */
84
+ function Generator(method: "Get" | "Post" | "Put" | "Patch" | "Delete") {
85
+ function route(path?: string | string[]): MethodDecorator;
86
+ function route<T>(
87
+ stringify?: IResponseBodyStringifier<T>,
88
+ ): MethodDecorator;
89
+ function route<T>(
90
+ path: string | string[],
91
+ stringify?: IResponseBodyStringifier<T>,
92
+ ): MethodDecorator;
93
+
94
+ function route(...args: any[]): MethodDecorator {
95
+ const [path, stringify] = get_path_and_stringify(
96
+ `TypedRoute.${method}`,
97
+ )(...args);
98
+ return applyDecorators(
99
+ ROUTERS[method](path),
100
+ UseInterceptors(new TypedRouteInterceptor(stringify)),
101
+ );
102
+ }
103
+ return route;
104
+ }
105
+ }
106
+ for (const method of [
107
+ assertStringify,
108
+ isStringify,
109
+ stringify,
110
+ validateStringify,
111
+ ]) {
112
+ Object.assign(TypedRoute.Get, method);
113
+ Object.assign(TypedRoute.Delete, method);
114
+ Object.assign(TypedRoute.Post, method);
115
+ Object.assign(TypedRoute.Put, method);
116
+ Object.assign(TypedRoute.Patch, method);
117
+ }
118
+
119
+ /**
120
+ * @internal
121
+ */
122
+ class TypedRouteInterceptor implements NestInterceptor {
123
+ public constructor(private readonly stringify: (input: any) => string) {}
124
+
125
+ public intercept(
126
+ context: ExecutionContext,
127
+ next: CallHandler,
128
+ ): Observable<any> {
129
+ const http: HttpArgumentsHost = context.switchToHttp();
130
+ const response: express.Response = http.getResponse();
131
+ response.header("Content-Type", "application/json");
132
+
133
+ return next.handle().pipe(
134
+ map((value) => this.stringify(value)),
135
+ catchError((err) => route_error(http.getRequest(), err)),
136
+ );
137
+ }
138
+ }
139
+
140
+ /**
141
+ * @internal
142
+ */
143
+ const ROUTERS = {
144
+ Get,
145
+ Post,
146
+ Patch,
147
+ Put,
148
+ Delete,
149
+ };
@@ -1,4 +1,4 @@
1
- /**
2
- * @internal
3
- */
4
- export const ENCRYPTION_METADATA_KEY = "nestia:core:encryption:password";
1
+ /**
2
+ * @internal
3
+ */
4
+ export const ENCRYPTION_METADATA_KEY = "nestia:core:encryption:password";
@@ -1,77 +1,77 @@
1
- import { InternalServerErrorException } from "@nestjs/common";
2
- import { IValidation, TypeGuardError } from "typia";
3
-
4
- import { IResponseBodyStringifier } from "../../options/IResponseBodyStringifier";
5
-
6
- export const get_path_and_stringify =
7
- (method: string) =>
8
- (
9
- ...args: any[]
10
- ): [string | string[] | undefined, (input: any) => string] => {
11
- const path: string | string[] | null | undefined =
12
- args[0] === undefined ||
13
- typeof args[0] === "string" ||
14
- Array.isArray(args[0])
15
- ? args[0]
16
- : null;
17
- const functor: IResponseBodyStringifier<any> | undefined =
18
- path === null ? args[0] : args[1];
19
- return [path ?? undefined, take(method)(functor)];
20
- };
21
-
22
- const take =
23
- (method: string) =>
24
- <T>(functor?: IResponseBodyStringifier<T>) => {
25
- if (functor === undefined)
26
- throw new Error(
27
- `Error on nestia.core.${method}(): no stringify function provided.`,
28
- );
29
- else if (functor.type === "stringify") return functor.stringify;
30
- else if (functor.type === "assert") return assert(functor.assert);
31
- else if (functor.type === "is") return is(functor.is);
32
- else if (functor.type === "validate") return validate(functor.validate);
33
- throw new Error(
34
- `Error on nestia.core.${method}(): invalid typed stringify function.`,
35
- );
36
- };
37
-
38
- const assert =
39
- <T>(closure: (data: T) => string) =>
40
- (data: T) => {
41
- try {
42
- return closure(data);
43
- } catch (exp) {
44
- if (exp instanceof TypeGuardError) {
45
- throw new InternalServerErrorException({
46
- path: exp.path,
47
- reason: exp.message,
48
- expected: exp.expected,
49
- value: exp.value,
50
- message: MESSAGE,
51
- });
52
- }
53
- throw exp;
54
- }
55
- };
56
-
57
- const is =
58
- <T>(closure: (data: T) => string | null) =>
59
- (data: T) => {
60
- const result: string | null = closure(data);
61
- if (result === null) throw new InternalServerErrorException(MESSAGE);
62
- return result;
63
- };
64
-
65
- const validate =
66
- <T>(closure: (data: T) => IValidation<string>) =>
67
- (data: T) => {
68
- const result: IValidation<string> = closure(data);
69
- if (result.success === false)
70
- throw new InternalServerErrorException({
71
- errors: result.errors,
72
- message: MESSAGE,
73
- });
74
- return result.data;
75
- };
76
-
77
- const MESSAGE = "Response body data is not following the promised type.";
1
+ import { InternalServerErrorException } from "@nestjs/common";
2
+ import { IValidation, TypeGuardError } from "typia";
3
+
4
+ import { IResponseBodyStringifier } from "../../options/IResponseBodyStringifier";
5
+
6
+ export const get_path_and_stringify =
7
+ (method: string) =>
8
+ (
9
+ ...args: any[]
10
+ ): [string | string[] | undefined, (input: any) => string] => {
11
+ const path: string | string[] | null | undefined =
12
+ args[0] === undefined ||
13
+ typeof args[0] === "string" ||
14
+ Array.isArray(args[0])
15
+ ? args[0]
16
+ : null;
17
+ const functor: IResponseBodyStringifier<any> | undefined =
18
+ path === null ? args[0] : args[1];
19
+ return [path ?? undefined, take(method)(functor)];
20
+ };
21
+
22
+ const take =
23
+ (method: string) =>
24
+ <T>(functor?: IResponseBodyStringifier<T>) => {
25
+ if (functor === undefined)
26
+ throw new Error(
27
+ `Error on nestia.core.${method}(): no stringify function provided.`,
28
+ );
29
+ else if (functor.type === "stringify") return functor.stringify;
30
+ else if (functor.type === "assert") return assert(functor.assert);
31
+ else if (functor.type === "is") return is(functor.is);
32
+ else if (functor.type === "validate") return validate(functor.validate);
33
+ throw new Error(
34
+ `Error on nestia.core.${method}(): invalid typed stringify function.`,
35
+ );
36
+ };
37
+
38
+ const assert =
39
+ <T>(closure: (data: T) => string) =>
40
+ (data: T) => {
41
+ try {
42
+ return closure(data);
43
+ } catch (exp) {
44
+ if (exp instanceof TypeGuardError) {
45
+ throw new InternalServerErrorException({
46
+ path: exp.path,
47
+ reason: exp.message,
48
+ expected: exp.expected,
49
+ value: exp.value,
50
+ message: MESSAGE,
51
+ });
52
+ }
53
+ throw exp;
54
+ }
55
+ };
56
+
57
+ const is =
58
+ <T>(closure: (data: T) => string | null) =>
59
+ (data: T) => {
60
+ const result: string | null = closure(data);
61
+ if (result === null) throw new InternalServerErrorException(MESSAGE);
62
+ return result;
63
+ };
64
+
65
+ const validate =
66
+ <T>(closure: (data: T) => IValidation<string>) =>
67
+ (data: T) => {
68
+ const result: IValidation<string> = closure(data);
69
+ if (result.success === false)
70
+ throw new InternalServerErrorException({
71
+ errors: result.errors,
72
+ message: MESSAGE,
73
+ });
74
+ return result.data;
75
+ };
76
+
77
+ const MESSAGE = "Response body data is not following the promised type.";
@@ -1,13 +1,10 @@
1
- import http from "http";
2
-
3
- /**
4
- * @internal
5
- */
6
- export function headers_to_object(
7
- headers: http.IncomingHttpHeaders,
8
- ): Record<string, string> {
9
- const output: Record<string, string> = {};
10
- for (const [key, value] of Object.entries(headers))
11
- output[key] = value instanceof Array ? value[0] : value || "";
12
- return output;
13
- }
1
+ import http from "http";
2
+
3
+ export function headers_to_object(
4
+ headers: http.IncomingHttpHeaders,
5
+ ): Record<string, string> {
6
+ const output: Record<string, string> = {};
7
+ for (const [key, value] of Object.entries(headers))
8
+ output[key] = value instanceof Array ? value[0] : value || "";
9
+ return output;
10
+ }
@@ -0,0 +1,35 @@
1
+ import is_ts_node from "detect-ts-node";
2
+ import fs from "fs";
3
+
4
+ import { Creator } from "../../typings/Creator";
5
+
6
+ export async function load_controllers(
7
+ path: string,
8
+ ): Promise<Creator<object>[]> {
9
+ const output: any[] = [];
10
+ await iterate(output, path);
11
+ return output;
12
+ }
13
+
14
+ async function iterate(
15
+ controllers: Creator<object>[],
16
+ path: string,
17
+ ): Promise<void> {
18
+ const directory: string[] = await fs.promises.readdir(path);
19
+ for (const file of directory) {
20
+ const current: string = `${path}/${file}`;
21
+ const stats: fs.Stats = await fs.promises.lstat(current);
22
+
23
+ if (stats.isDirectory() === true) await iterate(controllers, current);
24
+ else if (file.substring(file.length - 3) === `.${EXTENSION}`) {
25
+ const external: any = await import(current);
26
+ for (const key in external) {
27
+ const instance: Creator<object> = external[key];
28
+ if (Reflect.getMetadata("path", instance) !== undefined)
29
+ controllers.push(instance);
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ const EXTENSION = is_ts_node ? "ts" : "js";