@tsed/di 8.0.1 → 8.0.3
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/package.json +10 -9
- package/readme.md +6 -6
- package/src/common/constants/constants.ts +5 -0
- package/src/common/decorators/autoInjectable.spec.ts +135 -0
- package/src/common/decorators/autoInjectable.ts +59 -0
- package/src/common/decorators/configuration.spec.ts +45 -0
- package/src/common/decorators/configuration.ts +34 -0
- package/src/common/decorators/constant.spec.ts +67 -0
- package/src/common/decorators/constant.ts +72 -0
- package/src/common/decorators/controller.spec.ts +43 -0
- package/src/common/decorators/controller.ts +64 -0
- package/src/common/decorators/inject.spec.ts +298 -0
- package/src/common/decorators/inject.ts +144 -0
- package/src/common/decorators/injectable.spec.ts +43 -0
- package/src/common/decorators/injectable.ts +30 -0
- package/src/common/decorators/intercept.spec.ts +103 -0
- package/src/common/decorators/intercept.ts +77 -0
- package/src/common/decorators/interceptor.ts +17 -0
- package/src/common/decorators/lazyInject.spec.ts +53 -0
- package/src/common/decorators/lazyInject.ts +91 -0
- package/src/common/decorators/module.ts +52 -0
- package/src/common/decorators/opts.ts +51 -0
- package/src/common/decorators/overrideProvider.spec.ts +30 -0
- package/src/common/decorators/overrideProvider.ts +15 -0
- package/src/common/decorators/scope.spec.ts +25 -0
- package/src/common/decorators/scope.ts +13 -0
- package/src/common/decorators/service.ts +14 -0
- package/src/common/decorators/useOpts.spec.ts +90 -0
- package/src/common/decorators/useOpts.ts +61 -0
- package/src/common/decorators/value.spec.ts +59 -0
- package/src/common/decorators/value.ts +60 -0
- package/src/common/domain/Container.spec.ts +85 -0
- package/src/common/domain/Container.ts +80 -0
- package/src/common/domain/ControllerProvider.spec.ts +55 -0
- package/src/common/domain/ControllerProvider.ts +48 -0
- package/src/common/domain/InjectablePropertyType.ts +7 -0
- package/src/common/domain/LocalsContainer.spec.ts +20 -0
- package/src/common/domain/LocalsContainer.ts +11 -0
- package/src/common/domain/Provider.spec.ts +107 -0
- package/src/common/domain/Provider.ts +205 -0
- package/src/common/domain/ProviderScope.ts +5 -0
- package/src/common/domain/ProviderType.ts +8 -0
- package/src/common/errors/InjectionError.spec.ts +17 -0
- package/src/common/errors/InjectionError.ts +68 -0
- package/src/common/errors/InvalidPropertyTokenError.ts +13 -0
- package/src/common/fn/configuration.spec.ts +42 -0
- package/src/common/fn/configuration.ts +22 -0
- package/src/common/fn/constant.spec.ts +37 -0
- package/src/common/fn/constant.ts +7 -0
- package/src/common/fn/inject.spec.ts +54 -0
- package/src/common/fn/inject.ts +29 -0
- package/src/common/fn/injectMany.ts +16 -0
- package/src/common/fn/injectable.spec.ts +87 -0
- package/src/common/fn/injectable.ts +15 -0
- package/src/common/fn/injector.ts +26 -0
- package/src/common/fn/lazyInject.spec.ts +22 -0
- package/src/common/fn/lazyInject.ts +36 -0
- package/src/common/fn/localsContainer.ts +55 -0
- package/src/common/fn/refValue.spec.ts +47 -0
- package/src/common/fn/refValue.ts +33 -0
- package/src/common/index.ts +63 -0
- package/src/common/integration/async-factory.spec.ts +60 -0
- package/src/common/integration/di.spec.ts +153 -0
- package/src/common/integration/imports.spec.ts +39 -0
- package/src/common/integration/request.spec.ts +79 -0
- package/src/common/integration/singleton.spec.ts +125 -0
- package/src/common/interfaces/DIConfigurationOptions.ts +29 -0
- package/src/common/interfaces/DILogger.ts +13 -0
- package/src/common/interfaces/DILoggerOptions.ts +54 -0
- package/src/common/interfaces/ImportTokenProviderOpts.ts +29 -0
- package/src/common/interfaces/InterceptorContext.ts +13 -0
- package/src/common/interfaces/InterceptorMethods.ts +5 -0
- package/src/common/interfaces/InvokeOptions.ts +28 -0
- package/src/common/interfaces/OnDestroy.ts +3 -0
- package/src/common/interfaces/OnInit.ts +3 -0
- package/src/common/interfaces/ProviderOpts.ts +57 -0
- package/src/common/interfaces/RegistrySettings.ts +11 -0
- package/src/common/interfaces/ResolvedInvokeOptions.ts +14 -0
- package/src/common/interfaces/TokenProvider.ts +3 -0
- package/src/common/interfaces/TokenRoute.ts +6 -0
- package/src/common/registries/GlobalProviders.spec.ts +94 -0
- package/src/common/registries/GlobalProviders.ts +131 -0
- package/src/common/registries/ProviderRegistry.spec.ts +36 -0
- package/src/common/registries/ProviderRegistry.ts +32 -0
- package/src/common/services/DIConfiguration.spec.ts +60 -0
- package/src/common/services/DIConfiguration.ts +140 -0
- package/src/common/services/DILogger.spec.ts +22 -0
- package/src/common/services/DILogger.ts +8 -0
- package/src/common/services/InjectorService.spec.ts +793 -0
- package/src/common/services/InjectorService.ts +601 -0
- package/src/common/utils/colors.spec.ts +9 -0
- package/src/common/utils/colors.ts +11 -0
- package/src/common/utils/createContainer.spec.ts +18 -0
- package/src/common/utils/createContainer.ts +14 -0
- package/src/common/utils/discoverHooks.ts +15 -0
- package/src/common/utils/getConfiguration.spec.ts +40 -0
- package/src/common/utils/getConfiguration.ts +20 -0
- package/src/common/utils/getConstructorDependencies.ts +9 -0
- package/src/common/utils/providerBuilder.ts +81 -0
- package/src/index.ts +2 -0
- package/src/node/decorators/injectContext.spec.ts +60 -0
- package/src/node/decorators/injectContext.ts +29 -0
- package/src/node/domain/ContextLogger.spec.ts +277 -0
- package/src/node/domain/ContextLogger.ts +137 -0
- package/src/node/domain/DIContext.spec.ts +103 -0
- package/src/node/domain/DIContext.ts +115 -0
- package/src/node/fn/context.ts +24 -0
- package/src/node/fn/logger.spec.ts +46 -0
- package/src/node/fn/logger.ts +17 -0
- package/src/node/index.ts +16 -0
- package/src/node/integration/async-factory-invoke.spec.ts +58 -0
- package/src/node/integration/inject-context.spec.ts +29 -0
- package/src/node/integration/invoke-oninit.spec.ts +25 -0
- package/src/node/interfaces/AlterRunInContext.ts +3 -0
- package/src/node/services/DILogger.spec.ts +24 -0
- package/src/node/services/DILogger.ts +6 -0
- package/src/node/services/DITest.spec.ts +109 -0
- package/src/node/services/DITest.ts +119 -0
- package/src/node/utils/asyncHookContext.spec.ts +147 -0
- package/src/node/utils/asyncHookContext.ts +48 -0
- package/src/node/utils/attachLogger.spec.ts +14 -0
- package/src/node/utils/attachLogger.ts +7 -0
- package/src/node/utils/setLoggerConfiguration.spec.ts +43 -0
- package/src/node/utils/setLoggerConfiguration.ts +7 -0
- package/src/node/utils/setLoggerFormat.ts +33 -0
- package/src/node/utils/setLoggerLevel.ts +12 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {Container} from "./Container.js";
|
|
2
|
+
import {Provider} from "./Provider.js";
|
|
3
|
+
import {ProviderType} from "./ProviderType.js";
|
|
4
|
+
|
|
5
|
+
describe("Container", () => {
|
|
6
|
+
describe("getProvider()", () => {
|
|
7
|
+
class Test {}
|
|
8
|
+
|
|
9
|
+
it("should return a provider", () => {
|
|
10
|
+
// GIVEN
|
|
11
|
+
const container = new Container();
|
|
12
|
+
const provider = new Provider(Test);
|
|
13
|
+
|
|
14
|
+
container.add(Test, provider);
|
|
15
|
+
|
|
16
|
+
// WHEN
|
|
17
|
+
const result = container.getProvider(Test);
|
|
18
|
+
|
|
19
|
+
// THEN
|
|
20
|
+
expect(result!).toBeInstanceOf(Provider);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe("getProviders()", () => {
|
|
24
|
+
let container: Container;
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
class MyMiddleware {}
|
|
28
|
+
|
|
29
|
+
class MyService {}
|
|
30
|
+
|
|
31
|
+
class MyController {}
|
|
32
|
+
|
|
33
|
+
container = new Container();
|
|
34
|
+
container.addProvider(MyMiddleware, {type: ProviderType.MIDDLEWARE});
|
|
35
|
+
container.addProvider(MyService, {type: ProviderType.PROVIDER});
|
|
36
|
+
container.addProvider(MyController, {type: ProviderType.CONTROLLER});
|
|
37
|
+
|
|
38
|
+
// await container.load();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should return middlewares only", () => {
|
|
42
|
+
const providers = container.getProviders(ProviderType.MIDDLEWARE);
|
|
43
|
+
|
|
44
|
+
const result = providers.find((item: any) => item.type !== ProviderType.MIDDLEWARE);
|
|
45
|
+
|
|
46
|
+
expect(providers[0].type).toEqual(ProviderType.MIDDLEWARE);
|
|
47
|
+
expect(result).toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should return controllers only", () => {
|
|
51
|
+
const providers = container.getProviders(ProviderType.CONTROLLER);
|
|
52
|
+
|
|
53
|
+
const result = providers.find((item: any) => item.type !== ProviderType.CONTROLLER);
|
|
54
|
+
|
|
55
|
+
expect(providers[0].type).toEqual(ProviderType.CONTROLLER);
|
|
56
|
+
expect(result).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should return all providers", () => {
|
|
60
|
+
const providers = container.getProviders();
|
|
61
|
+
const controllers = providers.filter((item: any) => item.type === ProviderType.CONTROLLER);
|
|
62
|
+
const middlewares = providers.filter((item: any) => item.type === ProviderType.MIDDLEWARE);
|
|
63
|
+
|
|
64
|
+
expect(providers.length > 0).toEqual(true);
|
|
65
|
+
expect(controllers.length > 0).toEqual(true);
|
|
66
|
+
expect(middlewares.length > 0).toEqual(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe("addProviders()", () => {
|
|
70
|
+
it("should add providers", () => {
|
|
71
|
+
class Test {}
|
|
72
|
+
|
|
73
|
+
// GIVEN
|
|
74
|
+
const container = new Container();
|
|
75
|
+
const childContainer = new Container();
|
|
76
|
+
childContainer.addProvider(Test);
|
|
77
|
+
|
|
78
|
+
// WHEN
|
|
79
|
+
container.addProviders(childContainer);
|
|
80
|
+
|
|
81
|
+
// THEN
|
|
82
|
+
expect(container.getProvider(Test)!).toBeInstanceOf(Provider);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type {ProviderOpts} from "../interfaces/ProviderOpts.js";
|
|
2
|
+
import type {TokenProvider} from "../interfaces/TokenProvider.js";
|
|
3
|
+
import {GlobalProviders} from "../registries/GlobalProviders.js";
|
|
4
|
+
import {Provider} from "./Provider.js";
|
|
5
|
+
import type {ProviderType} from "./ProviderType.js";
|
|
6
|
+
|
|
7
|
+
export class Container extends Map<TokenProvider, Provider> {
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param token
|
|
11
|
+
* @param settings
|
|
12
|
+
*/
|
|
13
|
+
public add(token: TokenProvider, settings: Partial<ProviderOpts> = {}): this {
|
|
14
|
+
const provider = GlobalProviders.get(token)?.clone() || new Provider(token);
|
|
15
|
+
|
|
16
|
+
Object.assign(provider, settings);
|
|
17
|
+
|
|
18
|
+
return super.set(token, provider);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Add a provider to the
|
|
23
|
+
* @param token
|
|
24
|
+
* @param settings
|
|
25
|
+
*/
|
|
26
|
+
public addProvider(token: TokenProvider, settings: Partial<ProviderOpts> = {}): this {
|
|
27
|
+
return this.add(token, settings);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* @param token
|
|
33
|
+
*/
|
|
34
|
+
public hasProvider(token: TokenProvider) {
|
|
35
|
+
return super.has(token);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Add a provider to the
|
|
40
|
+
* @param token
|
|
41
|
+
* @param provider
|
|
42
|
+
*/
|
|
43
|
+
public setProvider(token: TokenProvider, provider: Provider) {
|
|
44
|
+
return super.set(token, provider);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The getProvider() method returns a specified element from a Map object.
|
|
49
|
+
* @returns {T} Returns the element associated with the specified key or undefined if the key can't be found in the Map object.
|
|
50
|
+
* @param token
|
|
51
|
+
*/
|
|
52
|
+
public getProvider<T extends Provider = Provider>(token: TokenProvider | undefined): T | undefined {
|
|
53
|
+
return super.get(token!) as T;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get all providers registered in the injector container.
|
|
58
|
+
*
|
|
59
|
+
* @param type Filter the list by the given ProviderType.
|
|
60
|
+
* @returns {[TokenProvider , Provider<any>][]}
|
|
61
|
+
*/
|
|
62
|
+
public getProviders(type?: TokenProvider | ProviderType | string | string[]): Provider[] {
|
|
63
|
+
const types = ([] as (string | ProviderType)[]).concat(type as never).map(String);
|
|
64
|
+
|
|
65
|
+
return [...this].reduce((providers, [_, provider]) => {
|
|
66
|
+
if (types.includes(String(provider.type)) || !type) {
|
|
67
|
+
return [...providers, provider];
|
|
68
|
+
}
|
|
69
|
+
return providers;
|
|
70
|
+
}, []);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public addProviders(container: Map<TokenProvider, Provider>) {
|
|
74
|
+
container.forEach((provider) => {
|
|
75
|
+
if (!this.hasProvider(provider.token)) {
|
|
76
|
+
this.setProvider(provider.token, provider.clone());
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {ControllerProvider} from "./ControllerProvider.js";
|
|
2
|
+
import {ProviderScope} from "./ProviderScope.js";
|
|
3
|
+
|
|
4
|
+
class Test {}
|
|
5
|
+
|
|
6
|
+
describe("ControllerProvider", () => {
|
|
7
|
+
let controllerProvider: ControllerProvider;
|
|
8
|
+
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
controllerProvider = new ControllerProvider(Test);
|
|
11
|
+
controllerProvider.path = "/";
|
|
12
|
+
controllerProvider.scope = ProviderScope.REQUEST;
|
|
13
|
+
controllerProvider.middlewares = {
|
|
14
|
+
useBefore: [new Function()],
|
|
15
|
+
use: [new Function()],
|
|
16
|
+
useAfter: [new Function()]
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should have type field to equals to controller", () => {
|
|
21
|
+
expect(controllerProvider.type).toEqual("controller");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should get path", () => {
|
|
25
|
+
expect(controllerProvider.path).toEqual("/");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should get children", () => {
|
|
29
|
+
expect(controllerProvider.children).toHaveLength(0);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should get a scope", () => {
|
|
33
|
+
expect(controllerProvider.scope).toEqual("request");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should have children", () => {
|
|
37
|
+
expect(controllerProvider.hasChildren()).toEqual(false);
|
|
38
|
+
});
|
|
39
|
+
it("should get parent", () => {
|
|
40
|
+
expect(!!controllerProvider.parent).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should have parent", () => {
|
|
44
|
+
expect(!!controllerProvider.hasParent()).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should have a middlewares", () => {
|
|
48
|
+
expect(Array.isArray(controllerProvider.middlewares.use)).toBe(true);
|
|
49
|
+
expect(controllerProvider.middlewares.use![0]).toBeInstanceOf(Function);
|
|
50
|
+
expect(Array.isArray(controllerProvider.middlewares.useAfter)).toBe(true);
|
|
51
|
+
expect(controllerProvider.middlewares.useAfter![0]).toBeInstanceOf(Function);
|
|
52
|
+
expect(Array.isArray(controllerProvider.middlewares.useBefore)).toBe(true);
|
|
53
|
+
expect(controllerProvider.middlewares.useBefore![0]).toBeInstanceOf(Function);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {TokenProvider} from "../interfaces/TokenProvider.js";
|
|
2
|
+
import {Provider} from "./Provider.js";
|
|
3
|
+
import {ProviderType} from "./ProviderType.js";
|
|
4
|
+
|
|
5
|
+
export interface ControllerMiddlewares {
|
|
6
|
+
useBefore: TokenProvider[];
|
|
7
|
+
use: TokenProvider[];
|
|
8
|
+
useAfter: TokenProvider[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class ControllerProvider<T = any> extends Provider<T> {
|
|
12
|
+
public tokenRouter: string;
|
|
13
|
+
|
|
14
|
+
constructor(token: TokenProvider, options: Partial<Provider> = {}) {
|
|
15
|
+
super(token, options);
|
|
16
|
+
this.type = ProviderType.CONTROLLER;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @returns {any[]}
|
|
22
|
+
*/
|
|
23
|
+
get middlewares(): Partial<ControllerMiddlewares> {
|
|
24
|
+
return Object.assign(
|
|
25
|
+
{
|
|
26
|
+
use: [],
|
|
27
|
+
useAfter: [],
|
|
28
|
+
useBefore: []
|
|
29
|
+
},
|
|
30
|
+
this.store.get("middlewares", {})
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param middlewares
|
|
37
|
+
*/
|
|
38
|
+
set middlewares(middlewares: Partial<ControllerMiddlewares>) {
|
|
39
|
+
const mdlwrs = this.middlewares;
|
|
40
|
+
const concat = (key: string, a: any, b: any) => (a[key] = a[key].concat(b[key]));
|
|
41
|
+
|
|
42
|
+
Object.keys(middlewares).forEach((key: string) => {
|
|
43
|
+
concat(key, mdlwrs, middlewares);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this.store.set("middlewares", mdlwrs);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {LocalsContainer} from "./LocalsContainer.js";
|
|
2
|
+
|
|
3
|
+
describe("LocalsContainer", () => {
|
|
4
|
+
describe("destroy()", () => {
|
|
5
|
+
it("should destroy container", async () => {
|
|
6
|
+
// GIVEN
|
|
7
|
+
const instance = {
|
|
8
|
+
$onDestroy: vi.fn().mockResolvedValue(undefined)
|
|
9
|
+
};
|
|
10
|
+
const container = new LocalsContainer();
|
|
11
|
+
container.set("TOKEN", instance);
|
|
12
|
+
|
|
13
|
+
container.hooks.on("$onDestroy", () => instance.$onDestroy());
|
|
14
|
+
|
|
15
|
+
await container.destroy();
|
|
16
|
+
|
|
17
|
+
expect(instance.$onDestroy).toHaveBeenCalledWith();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {Hooks} from "@tsed/hooks";
|
|
2
|
+
|
|
3
|
+
import type {TokenProvider} from "../interfaces/TokenProvider.js";
|
|
4
|
+
|
|
5
|
+
export class LocalsContainer extends Map<TokenProvider, any> {
|
|
6
|
+
readonly hooks = new Hooks();
|
|
7
|
+
|
|
8
|
+
async destroy() {
|
|
9
|
+
await this.hooks.asyncEmit("$onDestroy");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {Provider} from "./Provider.js";
|
|
2
|
+
import {ProviderScope} from "./ProviderScope.js";
|
|
3
|
+
|
|
4
|
+
class T1 {}
|
|
5
|
+
|
|
6
|
+
class T2 {}
|
|
7
|
+
|
|
8
|
+
const S1 = Symbol.for("S1");
|
|
9
|
+
|
|
10
|
+
describe("Provider", () => {
|
|
11
|
+
describe("when is a class", () => {
|
|
12
|
+
it("should wrap the token provided", () => {
|
|
13
|
+
const provider = new Provider(T1);
|
|
14
|
+
provider.scope = ProviderScope.REQUEST;
|
|
15
|
+
provider.customProp = "test";
|
|
16
|
+
|
|
17
|
+
expect(provider.token).toEqual(T1);
|
|
18
|
+
expect(provider.useClass).toEqual(T1);
|
|
19
|
+
expect(!!provider.store).toEqual(true);
|
|
20
|
+
expect(provider.clone()).toEqual(provider);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should override the token provider", () => {
|
|
24
|
+
const provider = new Provider(T1);
|
|
25
|
+
provider.scope = ProviderScope.REQUEST;
|
|
26
|
+
provider.customProp = "test";
|
|
27
|
+
provider.useClass = T2;
|
|
28
|
+
|
|
29
|
+
const cloned = provider.clone();
|
|
30
|
+
|
|
31
|
+
expect(provider.token).toEqual(T1);
|
|
32
|
+
expect(provider.useClass).toEqual(T2);
|
|
33
|
+
expect(!!provider.store).toEqual(true);
|
|
34
|
+
expect(cloned.useClass).toEqual(T2);
|
|
35
|
+
expect(cloned.scope).toEqual(ProviderScope.REQUEST);
|
|
36
|
+
expect(provider.hasChildren()).toEqual(false);
|
|
37
|
+
expect(provider.hasParent()).toEqual(false);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("when is a symbol", () => {
|
|
42
|
+
it("should wrap the token provided", () => {
|
|
43
|
+
const provider = new Provider(S1);
|
|
44
|
+
|
|
45
|
+
expect(provider.token).toEqual(S1);
|
|
46
|
+
expect(!!provider.useClass).toEqual(false);
|
|
47
|
+
expect(!!provider.store).toEqual(true);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe("when is a string", () => {
|
|
52
|
+
it("should wrap the token provided", () => {
|
|
53
|
+
const provider = new Provider("test");
|
|
54
|
+
|
|
55
|
+
expect(provider.token).toEqual("test");
|
|
56
|
+
expect(provider.provide).toEqual("test");
|
|
57
|
+
expect(!!provider.useClass).toEqual(false);
|
|
58
|
+
expect(!!provider.store).toEqual(true);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("clone()", () => {
|
|
63
|
+
it("should clone a provider", () => {
|
|
64
|
+
const provider = new Provider(T1);
|
|
65
|
+
provider.type = "provider";
|
|
66
|
+
provider.scope = ProviderScope.REQUEST;
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("className", () => {
|
|
71
|
+
it("should return the class name", () => {
|
|
72
|
+
expect(new Provider(T1).className).toEqual("T1");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should return the symbol name", () => {
|
|
76
|
+
expect(new Provider(S1).className).toEqual("S1");
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("name", () => {
|
|
81
|
+
it("should return the class name", () => {
|
|
82
|
+
expect(new Provider(T1).name).toEqual("T1");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe("path", () => {
|
|
86
|
+
it("should return set the path", () => {
|
|
87
|
+
const provider = new Provider(T1);
|
|
88
|
+
provider.path = "path";
|
|
89
|
+
expect(provider.path).toEqual("path");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("toString()", () => {
|
|
94
|
+
it("should return the class name", () => {
|
|
95
|
+
expect(new Provider(T1).toString()).toEqual("Token:T1:T1");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe("isAsync()", () => {
|
|
100
|
+
it("should return true", () => {
|
|
101
|
+
const provider = new Provider(T1);
|
|
102
|
+
provider.useAsyncFactory = () => Promise.resolve("test");
|
|
103
|
+
|
|
104
|
+
expect(provider.isAsync()).toEqual(true);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {type AbstractType, classOf, getClassOrSymbol, isClass, nameOf, Store, Type} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
import {DI_USE_PARAM_OPTIONS} from "../constants/constants.js";
|
|
4
|
+
import type {ProviderOpts} from "../interfaces/ProviderOpts.js";
|
|
5
|
+
import type {TokenProvider} from "../interfaces/TokenProvider.js";
|
|
6
|
+
import {discoverHooks} from "../utils/discoverHooks.js";
|
|
7
|
+
import {ProviderScope} from "./ProviderScope.js";
|
|
8
|
+
import {ProviderType} from "./ProviderType.js";
|
|
9
|
+
|
|
10
|
+
export type ProviderHookCallback<T = any> = (instance: T, ...args: unknown[]) => Promise<void> | void;
|
|
11
|
+
|
|
12
|
+
export class Provider<T = any> implements ProviderOpts<T> {
|
|
13
|
+
/**
|
|
14
|
+
* Token group provider to retrieve all provider from the same type
|
|
15
|
+
*/
|
|
16
|
+
public type: ProviderType | TokenProvider = ProviderType.PROVIDER;
|
|
17
|
+
public deps: TokenProvider[];
|
|
18
|
+
public imports: (TokenProvider | [TokenProvider])[];
|
|
19
|
+
public alias: string;
|
|
20
|
+
public priority: number;
|
|
21
|
+
public useFactory?: Function;
|
|
22
|
+
public useAsyncFactory?: Function;
|
|
23
|
+
public useValue?: unknown;
|
|
24
|
+
public hooks: Record<string, ProviderHookCallback<T>> = {};
|
|
25
|
+
#useClass: Type<T>;
|
|
26
|
+
#token: TokenProvider;
|
|
27
|
+
#store: Store;
|
|
28
|
+
#tokenStore: Store;
|
|
29
|
+
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
|
|
32
|
+
constructor(token: TokenProvider<T>, options: Partial<Provider> = {}) {
|
|
33
|
+
this.token = token;
|
|
34
|
+
this.useClass = token as Type<T>;
|
|
35
|
+
|
|
36
|
+
Object.assign(this, options);
|
|
37
|
+
|
|
38
|
+
if (options instanceof Provider) {
|
|
39
|
+
this.#useClass = options.#useClass;
|
|
40
|
+
this.#store = options.#store;
|
|
41
|
+
this.#tokenStore = options.#tokenStore;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get token() {
|
|
46
|
+
return this.#token;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
set token(value: TokenProvider) {
|
|
50
|
+
if (value) {
|
|
51
|
+
this.#token = getClassOrSymbol(value);
|
|
52
|
+
this.#tokenStore = this.#store = Store.from(value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @deprecated
|
|
58
|
+
*/
|
|
59
|
+
get provide(): TokenProvider {
|
|
60
|
+
return this.token;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @deprecated
|
|
65
|
+
* @param value
|
|
66
|
+
*/
|
|
67
|
+
set provide(value: TokenProvider) {
|
|
68
|
+
this.token = value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get useClass(): Type<T> {
|
|
72
|
+
return this.#useClass;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Create a new store if the given value is a class. Otherwise, the value is ignored.
|
|
77
|
+
* @param value
|
|
78
|
+
*/
|
|
79
|
+
set useClass(value: Type<T> | AbstractType<T>) {
|
|
80
|
+
if (isClass(value)) {
|
|
81
|
+
this.#useClass = classOf(value);
|
|
82
|
+
this.#store = Store.from(value);
|
|
83
|
+
this.hooks = discoverHooks(this.#useClass);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get className() {
|
|
88
|
+
return this.name;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get name() {
|
|
92
|
+
return nameOf(this.token);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get store(): Store {
|
|
96
|
+
return this.#store;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get path() {
|
|
100
|
+
return this.store.get("path", "/");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
set path(path: string) {
|
|
104
|
+
this.store.set("path", path);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get the scope of the provider.
|
|
109
|
+
*
|
|
110
|
+
* ::: tip Note
|
|
111
|
+
* Async provider is always a SINGLETON
|
|
112
|
+
* :::
|
|
113
|
+
*
|
|
114
|
+
* @returns {boolean}
|
|
115
|
+
*/
|
|
116
|
+
get scope(): ProviderScope {
|
|
117
|
+
if (this.isAsync()) {
|
|
118
|
+
return ProviderScope.SINGLETON;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return this.get<ProviderScope>("scope", ProviderScope.SINGLETON);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Change the scope value of the provider.
|
|
126
|
+
* @param scope
|
|
127
|
+
*/
|
|
128
|
+
set scope(scope: ProviderScope) {
|
|
129
|
+
this.store.set("scope", scope);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get configuration(): Partial<TsED.Configuration> {
|
|
133
|
+
return this.get("configuration")!;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
set configuration(configuration: Partial<TsED.Configuration>) {
|
|
137
|
+
this.store.set("configuration", configuration);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
get children(): TokenProvider[] {
|
|
141
|
+
return this.store.get("childrenControllers", []);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
set children(children: TokenProvider[]) {
|
|
145
|
+
this.store.set("childrenControllers", children);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
getArgOpts(index: number) {
|
|
149
|
+
return this.store.get(`${DI_USE_PARAM_OPTIONS}:${index}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Retrieves a value from the provider's store.
|
|
154
|
+
* @param key The key to look up
|
|
155
|
+
* @returns The value if found, undefined otherwise
|
|
156
|
+
*/
|
|
157
|
+
get<Type = unknown>(key: string): Type | undefined;
|
|
158
|
+
/**
|
|
159
|
+
* Retrieves a value from the provider's store with a default fallback.
|
|
160
|
+
* @param key The key to look up
|
|
161
|
+
* @param defaultValue The value to return if key is not found
|
|
162
|
+
* @returns The found value or defaultValue
|
|
163
|
+
*/
|
|
164
|
+
get<Type = unknown>(key: string, defaultValue: Type): Type;
|
|
165
|
+
get<Type = unknown>(key: string, defaultValue?: Type): Type | undefined {
|
|
166
|
+
return this.store.get(key) || this.#tokenStore.get(key) || defaultValue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
isAsync(): boolean {
|
|
170
|
+
return !!this.useAsyncFactory;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
clone(): Provider {
|
|
174
|
+
return new (classOf(this))(this.token, this);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
*
|
|
179
|
+
* @returns {boolean}
|
|
180
|
+
*/
|
|
181
|
+
public hasChildren(): boolean {
|
|
182
|
+
return !!this.children.length;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
*
|
|
187
|
+
* @returns {boolean}
|
|
188
|
+
*/
|
|
189
|
+
public hasParent(): boolean {
|
|
190
|
+
return !!this.store.get("parentController");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
toString() {
|
|
194
|
+
return [
|
|
195
|
+
"Token",
|
|
196
|
+
this.name,
|
|
197
|
+
this.useClass && nameOf(this.useClass),
|
|
198
|
+
this.useFactory && "Factory",
|
|
199
|
+
this.useValue && "Value",
|
|
200
|
+
this.useAsyncFactory && "AsyncFactory"
|
|
201
|
+
]
|
|
202
|
+
.filter(Boolean)
|
|
203
|
+
.join(":");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {InjectionError} from "./InjectionError.js";
|
|
2
|
+
|
|
3
|
+
describe("InjectionError", () => {
|
|
4
|
+
it("should create new instance of InjectionError (1)", () => {
|
|
5
|
+
const error = new InjectionError(class Target {}, "SERVICE");
|
|
6
|
+
|
|
7
|
+
expect(error.message).toEqual("Injection failed on Target\nOrigin: SERVICE");
|
|
8
|
+
expect(error.name).toEqual("INJECTION_ERROR");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("should create new instance of InjectionError (2)", () => {
|
|
12
|
+
const error = new InjectionError(class Target {}, new Error("test"));
|
|
13
|
+
|
|
14
|
+
expect(error.message).toEqual("Injection failed on Target\nOrigin: test");
|
|
15
|
+
expect(error.name).toEqual("INJECTION_ERROR");
|
|
16
|
+
});
|
|
17
|
+
});
|