@bool-ts/core 1.3.2 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +11 -0
- package/LICENSE +21 -21
- package/__test/controller.ts +66 -79
- package/__test/index.ts +8 -11
- package/__test/interfaces.ts +7 -7
- package/__test/module.ts +16 -17
- package/__test/repository.ts +16 -16
- package/__test/service.ts +20 -20
- package/bun.lockb +0 -0
- package/dist/decorators/arguments.d.ts +31 -0
- package/dist/decorators/arguments.js +67 -0
- package/dist/decorators/controller.d.ts +2 -2
- package/dist/decorators/controller.js +6 -10
- package/dist/decorators/http.d.ts +1 -1
- package/dist/decorators/http.js +16 -103
- package/dist/decorators/index.d.ts +1 -0
- package/dist/decorators/index.js +7 -26
- package/dist/decorators/inject.js +5 -9
- package/dist/decorators/injectable.d.ts +2 -2
- package/dist/decorators/injectable.js +4 -8
- package/dist/decorators/module.d.ts +4 -2
- package/dist/decorators/module.js +4 -8
- package/dist/decorators/zodSchema.d.ts +1 -1
- package/dist/decorators/zodSchema.js +5 -8
- package/dist/entities/index.d.ts +3 -0
- package/dist/entities/index.js +3 -0
- package/dist/entities/route.d.ts +101 -0
- package/dist/entities/route.js +257 -0
- package/dist/entities/router.d.ts +10 -0
- package/dist/entities/router.js +25 -0
- package/dist/entities/routerGroup.d.ts +14 -0
- package/dist/entities/routerGroup.js +24 -0
- package/dist/hooks/factory.d.ts +12 -12
- package/dist/hooks/factory.js +180 -151
- package/dist/hooks/index.js +2 -7
- package/dist/hooks/injector.js +7 -10
- package/dist/http/clientError.d.ts +1 -1
- package/dist/http/clientError.js +3 -7
- package/dist/http/index.d.ts +12 -2
- package/dist/http/index.js +34 -73
- package/dist/http/serverError.js +3 -7
- package/dist/index.js +5 -21
- package/dist/interfaces/index.js +1 -3
- package/dist/ultils/asyncFunction.js +1 -4
- package/dist/ultils/index.js +1 -17
- package/package.json +30 -33
- package/src/decorators/arguments.ts +128 -0
- package/src/decorators/controller.ts +14 -18
- package/src/decorators/http.ts +81 -195
- package/src/decorators/index.ts +7 -6
- package/src/decorators/inject.ts +13 -19
- package/src/decorators/injectable.ts +11 -12
- package/src/decorators/module.ts +21 -22
- package/src/decorators/zodSchema.ts +20 -27
- package/src/entities/index.ts +3 -0
- package/src/entities/route.ts +328 -0
- package/src/entities/router.ts +35 -0
- package/src/entities/routerGroup.ts +34 -0
- package/src/hooks/factory.ts +285 -205
- package/src/hooks/index.ts +2 -2
- package/src/hooks/injector.ts +43 -43
- package/src/http/clientError.ts +45 -56
- package/src/http/index.ts +63 -72
- package/src/http/serverError.ts +38 -38
- package/src/index.ts +6 -6
- package/src/interfaces/index.ts +3 -3
- package/test.http +30 -28
- package/tsconfig.json +107 -109
package/src/hooks/factory.ts
CHANGED
|
@@ -1,205 +1,285 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import "
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import * as
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export type TBoolFactoryOptions =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}>;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
case "
|
|
58
|
-
return route.
|
|
59
|
-
case "
|
|
60
|
-
return route.
|
|
61
|
-
case "
|
|
62
|
-
return route.
|
|
63
|
-
case "
|
|
64
|
-
return route.
|
|
65
|
-
case "
|
|
66
|
-
return route.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
1
|
+
import "colors";
|
|
2
|
+
import "reflect-metadata";
|
|
3
|
+
|
|
4
|
+
import Qs from "qs";
|
|
5
|
+
import * as Zod from "zod";
|
|
6
|
+
|
|
7
|
+
import { Router, RouterGroup } from "../entities";
|
|
8
|
+
import { type IControllerRoute, type TModuleOptions, controllerKey, controllerRoutesKey, moduleKey } from "../decorators";
|
|
9
|
+
import { HttpClientError, HttpServerError, jsonErrorInfer, type THttpMethods } from "../http";
|
|
10
|
+
import { Injector } from "./injector";
|
|
11
|
+
import { controllerActionArgumentsKey, EArgumentTypes, type TMetadata as TArgumentsMetadata } from "../decorators/arguments";
|
|
12
|
+
|
|
13
|
+
export type TBoolFactoryOptions = Required<{
|
|
14
|
+
port: number;
|
|
15
|
+
}> &
|
|
16
|
+
Partial<{
|
|
17
|
+
prefix: string;
|
|
18
|
+
debug: boolean;
|
|
19
|
+
log: Partial<{
|
|
20
|
+
methods: Array<"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS">;
|
|
21
|
+
}>;
|
|
22
|
+
queryParser: Parameters<typeof Qs.parse>[1];
|
|
23
|
+
}>;
|
|
24
|
+
|
|
25
|
+
export const controllerCreator = (controllerConstructor: new (...args: any[]) => unknown, group: RouterGroup) => {
|
|
26
|
+
if (!Reflect.getOwnMetadataKeys(controllerConstructor).includes(controllerKey)) {
|
|
27
|
+
throw Error(`${controllerConstructor.name} is not a controller.`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const controller = Injector.get(controllerConstructor);
|
|
31
|
+
|
|
32
|
+
if (!controller) {
|
|
33
|
+
throw Error("Can not initialize controller.");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const controllerMetadata = Reflect.getOwnMetadata(controllerKey, controllerConstructor) || "/";
|
|
37
|
+
const routesMetadata = (Reflect.getOwnMetadata(controllerRoutesKey, controllerConstructor) ||
|
|
38
|
+
[]) as Array<IControllerRoute>;
|
|
39
|
+
const router = new Router(controllerMetadata);
|
|
40
|
+
|
|
41
|
+
routesMetadata.forEach((routeMetadata) => {
|
|
42
|
+
if (typeof routeMetadata.descriptor.value !== "function") {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const route = router.route(`/${routeMetadata.path}`);
|
|
47
|
+
const handler = routeMetadata.descriptor.value.bind(controller);
|
|
48
|
+
const routeArgument = {
|
|
49
|
+
constructor: controllerConstructor,
|
|
50
|
+
funcName: routeMetadata.methodName,
|
|
51
|
+
func: handler
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
switch (routeMetadata.httpMethod) {
|
|
55
|
+
case "GET":
|
|
56
|
+
return route.get(routeArgument);
|
|
57
|
+
case "POST":
|
|
58
|
+
return route.post(routeArgument);
|
|
59
|
+
case "PUT":
|
|
60
|
+
return route.put(routeArgument);
|
|
61
|
+
case "PATCH":
|
|
62
|
+
return route.patch(routeArgument);
|
|
63
|
+
case "DELETE":
|
|
64
|
+
return route.delete(routeArgument);
|
|
65
|
+
case "OPTIONS":
|
|
66
|
+
return route.options(routeArgument);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return group.add(router);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const controllerActionArgumentsResolution = async (
|
|
74
|
+
data: unknown,
|
|
75
|
+
zodSchema: Zod.Schema,
|
|
76
|
+
argumentIndex: number,
|
|
77
|
+
funcName: string | symbol
|
|
78
|
+
) => {
|
|
79
|
+
try {
|
|
80
|
+
const validation = await zodSchema.safeParseAsync(data);
|
|
81
|
+
|
|
82
|
+
if (!validation.success) {
|
|
83
|
+
throw new HttpClientError({
|
|
84
|
+
httpCode: 400,
|
|
85
|
+
message: `Validation at the [${funcName.toString()}] method fails at positional argument [${argumentIndex}].`,
|
|
86
|
+
data: validation.error.issues
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return validation.data;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (error instanceof HttpClientError) {
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
throw new HttpServerError({
|
|
97
|
+
httpCode: 500,
|
|
98
|
+
message: `Validation at the [${funcName.toString()}] method error at positional argument [${argumentIndex}].`,
|
|
99
|
+
data: !(error instanceof Error)
|
|
100
|
+
? error
|
|
101
|
+
: [
|
|
102
|
+
{
|
|
103
|
+
message: error.message,
|
|
104
|
+
code: error.name,
|
|
105
|
+
cause: error.cause
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const BoolFactory = (target: new (...args: any[]) => unknown, options: TBoolFactoryOptions) => {
|
|
113
|
+
if (!Reflect.getOwnMetadataKeys(target).includes(moduleKey)) {
|
|
114
|
+
throw Error(`${target.name} is not a module.`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const moduleMetadata = Reflect.getOwnMetadata(moduleKey, target) as TModuleOptions;
|
|
118
|
+
const allowOrigins = !moduleMetadata?.allowOrigins
|
|
119
|
+
? ["*"]
|
|
120
|
+
: typeof moduleMetadata.allowOrigins !== "string"
|
|
121
|
+
? moduleMetadata.allowOrigins
|
|
122
|
+
: [moduleMetadata.allowOrigins];
|
|
123
|
+
const allowMethods = !moduleMetadata?.allowMethods
|
|
124
|
+
? ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
|
|
125
|
+
: moduleMetadata.allowMethods;
|
|
126
|
+
const { allowLogsMethods } = Object.freeze({
|
|
127
|
+
allowLogsMethods: !options?.log?.methods ? ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] : options.log.methods
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const routerGroup = new RouterGroup();
|
|
131
|
+
|
|
132
|
+
moduleMetadata?.controllers &&
|
|
133
|
+
moduleMetadata.controllers.map((controllerConstructor) => controllerCreator(controllerConstructor, routerGroup));
|
|
134
|
+
|
|
135
|
+
Bun.serve({
|
|
136
|
+
port: options.port,
|
|
137
|
+
async fetch(request) {
|
|
138
|
+
const start = performance.now();
|
|
139
|
+
const url = new URL(request.url);
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const headers = request.headers;
|
|
143
|
+
const origin = headers.get("origin");
|
|
144
|
+
const response = new Response();
|
|
145
|
+
|
|
146
|
+
if (!allowOrigins.includes("*")) {
|
|
147
|
+
if (!origin) {
|
|
148
|
+
throw new HttpClientError({
|
|
149
|
+
httpCode: 403,
|
|
150
|
+
message: "Origin not found.",
|
|
151
|
+
data: {
|
|
152
|
+
origin: {
|
|
153
|
+
code: "origin:invalid:0x00001",
|
|
154
|
+
message: "Origin not found."
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!allowOrigins.includes(origin)) {
|
|
161
|
+
throw new HttpClientError({
|
|
162
|
+
httpCode: 403,
|
|
163
|
+
message: "Invalid origin.",
|
|
164
|
+
data: {
|
|
165
|
+
origin: {
|
|
166
|
+
code: "origin:invalid:0x00002",
|
|
167
|
+
message: "Invalid origin."
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
response.headers.set("Access-Control-Allow-Origin", origin || "*");
|
|
175
|
+
response.headers.set("Access-Control-Allow-Headers", "*");
|
|
176
|
+
response.headers.set("Access-Control-Allow-Credentials", "true");
|
|
177
|
+
response.headers.set("Access-Control-Allow-Methods", allowMethods.join(", "));
|
|
178
|
+
|
|
179
|
+
if (!allowMethods.includes(request.method.toUpperCase())) {
|
|
180
|
+
throw new HttpClientError({
|
|
181
|
+
httpCode: 405,
|
|
182
|
+
message: "Method Not Allowed.",
|
|
183
|
+
data: undefined
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const result = routerGroup.find(url.pathname, request.method as keyof THttpMethods);
|
|
188
|
+
|
|
189
|
+
if (!result) {
|
|
190
|
+
throw new HttpClientError({
|
|
191
|
+
httpCode: 404,
|
|
192
|
+
message: "Route not found.",
|
|
193
|
+
data: undefined
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const params = result.params;
|
|
198
|
+
const query = Qs.parse(url.search, options.queryParser);
|
|
199
|
+
|
|
200
|
+
for (let i = 0; i < result.handlers.length; i++) {
|
|
201
|
+
const handler = result.handlers[i];
|
|
202
|
+
const handlerMetadata = (Reflect.getOwnMetadata(
|
|
203
|
+
controllerActionArgumentsKey,
|
|
204
|
+
handler.constructor,
|
|
205
|
+
handler.funcName
|
|
206
|
+
) || {}) as Record<string, TArgumentsMetadata>;
|
|
207
|
+
|
|
208
|
+
const controllerActionArguments = [];
|
|
209
|
+
|
|
210
|
+
if (handlerMetadata) {
|
|
211
|
+
for (const [_key, argsMetadata] of Object.entries(handlerMetadata)) {
|
|
212
|
+
switch (argsMetadata.type) {
|
|
213
|
+
case EArgumentTypes.headers:
|
|
214
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
215
|
+
? headers
|
|
216
|
+
: await controllerActionArgumentsResolution(
|
|
217
|
+
headers,
|
|
218
|
+
argsMetadata.zodSchema,
|
|
219
|
+
argsMetadata.index,
|
|
220
|
+
handler.funcName
|
|
221
|
+
);
|
|
222
|
+
break;
|
|
223
|
+
case EArgumentTypes.body:
|
|
224
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
225
|
+
? await request[argsMetadata.parser || "json"]()
|
|
226
|
+
: await controllerActionArgumentsResolution(
|
|
227
|
+
await request[argsMetadata.parser || "json"](),
|
|
228
|
+
argsMetadata.zodSchema,
|
|
229
|
+
argsMetadata.index,
|
|
230
|
+
handler.funcName
|
|
231
|
+
);
|
|
232
|
+
break;
|
|
233
|
+
case EArgumentTypes.params:
|
|
234
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
235
|
+
? params
|
|
236
|
+
: await controllerActionArgumentsResolution(
|
|
237
|
+
params,
|
|
238
|
+
argsMetadata.zodSchema,
|
|
239
|
+
argsMetadata.index,
|
|
240
|
+
handler.funcName
|
|
241
|
+
);
|
|
242
|
+
break;
|
|
243
|
+
case EArgumentTypes.query:
|
|
244
|
+
controllerActionArguments[argsMetadata.index] = !argsMetadata.zodSchema
|
|
245
|
+
? query
|
|
246
|
+
: await controllerActionArgumentsResolution(
|
|
247
|
+
query,
|
|
248
|
+
argsMetadata.zodSchema,
|
|
249
|
+
argsMetadata.index,
|
|
250
|
+
handler.funcName
|
|
251
|
+
);
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const response = await handler.func(...controllerActionArguments);
|
|
258
|
+
|
|
259
|
+
if (response instanceof Response) {
|
|
260
|
+
return response;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return response;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
return jsonErrorInfer(error);
|
|
267
|
+
} finally {
|
|
268
|
+
const end = performance.now();
|
|
269
|
+
const convertedPID = `${process.pid}`.yellow;
|
|
270
|
+
const convertedMethod = `${request.method.yellow}`.bgBlue;
|
|
271
|
+
const convertedReqIp = `${
|
|
272
|
+
request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "<Unknown>"
|
|
273
|
+
}`.yellow;
|
|
274
|
+
const convertedTime = `${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`.yellow;
|
|
275
|
+
|
|
276
|
+
allowLogsMethods.includes(request.method.toUpperCase()) &&
|
|
277
|
+
console.info(
|
|
278
|
+
`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${url.pathname.blue} - Time: ${convertedTime}`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export default BoolFactory;
|
package/src/hooks/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { BoolFactory } from "./factory";
|
|
2
|
-
export { Injector } from "./injector";
|
|
1
|
+
export { BoolFactory } from "./factory";
|
|
2
|
+
export { Injector } from "./injector";
|
package/src/hooks/injector.ts
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import "reflect-metadata";
|
|
2
|
-
|
|
3
|
-
import { injectableKey, injectKey } from "../decorators";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
interface IInjector {
|
|
7
|
-
get<T>(classDefinition: { new(...args: any[]): T }): T
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const Injector: IInjector = new class {
|
|
11
|
-
|
|
12
|
-
private readonly _mapper: Map<Function, any> = new Map();
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
* @param constructor
|
|
17
|
-
*/
|
|
18
|
-
get<T>(
|
|
19
|
-
classDefinition: { new(...args: any[]): T }
|
|
20
|
-
) {
|
|
21
|
-
if (this._mapper.has(classDefinition)) {
|
|
22
|
-
return this._mapper.get(classDefinition) as T;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const ownMetadataKeys = Reflect.getMetadataKeys(classDefinition);
|
|
26
|
-
|
|
27
|
-
if (!ownMetadataKeys.includes(injectableKey)) {
|
|
28
|
-
throw Error("Missing dependency declaration, please check @Injectable() used on dependency(ies).");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Initialize dependencies injection
|
|
32
|
-
const dependencies: any[] = Reflect.getOwnMetadata(injectKey, classDefinition) || [];
|
|
33
|
-
const injections: any[] = dependencies.map(dependency => Injector.get(dependency));
|
|
34
|
-
const instance = new classDefinition(...injections);
|
|
35
|
-
|
|
36
|
-
this._mapper.set(classDefinition, instance);
|
|
37
|
-
|
|
38
|
-
return instance;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export default Injector;
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
|
|
3
|
+
import { injectableKey, injectKey } from "../decorators";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
interface IInjector {
|
|
7
|
+
get<T>(classDefinition: { new(...args: any[]): T }): T
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Injector: IInjector = new class {
|
|
11
|
+
|
|
12
|
+
private readonly _mapper: Map<Function, any> = new Map();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param constructor
|
|
17
|
+
*/
|
|
18
|
+
get<T>(
|
|
19
|
+
classDefinition: { new(...args: any[]): T }
|
|
20
|
+
) {
|
|
21
|
+
if (this._mapper.has(classDefinition)) {
|
|
22
|
+
return this._mapper.get(classDefinition) as T;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const ownMetadataKeys = Reflect.getMetadataKeys(classDefinition);
|
|
26
|
+
|
|
27
|
+
if (!ownMetadataKeys.includes(injectableKey)) {
|
|
28
|
+
throw Error("Missing dependency declaration, please check @Injectable() used on dependency(ies).");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Initialize dependencies injection
|
|
32
|
+
const dependencies: any[] = Reflect.getOwnMetadata(injectKey, classDefinition) || [];
|
|
33
|
+
const injections: any[] = dependencies.map(dependency => Injector.get(dependency));
|
|
34
|
+
const instance = new classDefinition(...injections);
|
|
35
|
+
|
|
36
|
+
this._mapper.set(classDefinition, instance);
|
|
37
|
+
|
|
38
|
+
return instance;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default Injector;
|