@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.
Files changed (126) hide show
  1. package/package.json +10 -9
  2. package/readme.md +6 -6
  3. package/src/common/constants/constants.ts +5 -0
  4. package/src/common/decorators/autoInjectable.spec.ts +135 -0
  5. package/src/common/decorators/autoInjectable.ts +59 -0
  6. package/src/common/decorators/configuration.spec.ts +45 -0
  7. package/src/common/decorators/configuration.ts +34 -0
  8. package/src/common/decorators/constant.spec.ts +67 -0
  9. package/src/common/decorators/constant.ts +72 -0
  10. package/src/common/decorators/controller.spec.ts +43 -0
  11. package/src/common/decorators/controller.ts +64 -0
  12. package/src/common/decorators/inject.spec.ts +298 -0
  13. package/src/common/decorators/inject.ts +144 -0
  14. package/src/common/decorators/injectable.spec.ts +43 -0
  15. package/src/common/decorators/injectable.ts +30 -0
  16. package/src/common/decorators/intercept.spec.ts +103 -0
  17. package/src/common/decorators/intercept.ts +77 -0
  18. package/src/common/decorators/interceptor.ts +17 -0
  19. package/src/common/decorators/lazyInject.spec.ts +53 -0
  20. package/src/common/decorators/lazyInject.ts +91 -0
  21. package/src/common/decorators/module.ts +52 -0
  22. package/src/common/decorators/opts.ts +51 -0
  23. package/src/common/decorators/overrideProvider.spec.ts +30 -0
  24. package/src/common/decorators/overrideProvider.ts +15 -0
  25. package/src/common/decorators/scope.spec.ts +25 -0
  26. package/src/common/decorators/scope.ts +13 -0
  27. package/src/common/decorators/service.ts +14 -0
  28. package/src/common/decorators/useOpts.spec.ts +90 -0
  29. package/src/common/decorators/useOpts.ts +61 -0
  30. package/src/common/decorators/value.spec.ts +59 -0
  31. package/src/common/decorators/value.ts +60 -0
  32. package/src/common/domain/Container.spec.ts +85 -0
  33. package/src/common/domain/Container.ts +80 -0
  34. package/src/common/domain/ControllerProvider.spec.ts +55 -0
  35. package/src/common/domain/ControllerProvider.ts +48 -0
  36. package/src/common/domain/InjectablePropertyType.ts +7 -0
  37. package/src/common/domain/LocalsContainer.spec.ts +20 -0
  38. package/src/common/domain/LocalsContainer.ts +11 -0
  39. package/src/common/domain/Provider.spec.ts +107 -0
  40. package/src/common/domain/Provider.ts +205 -0
  41. package/src/common/domain/ProviderScope.ts +5 -0
  42. package/src/common/domain/ProviderType.ts +8 -0
  43. package/src/common/errors/InjectionError.spec.ts +17 -0
  44. package/src/common/errors/InjectionError.ts +68 -0
  45. package/src/common/errors/InvalidPropertyTokenError.ts +13 -0
  46. package/src/common/fn/configuration.spec.ts +42 -0
  47. package/src/common/fn/configuration.ts +22 -0
  48. package/src/common/fn/constant.spec.ts +37 -0
  49. package/src/common/fn/constant.ts +7 -0
  50. package/src/common/fn/inject.spec.ts +54 -0
  51. package/src/common/fn/inject.ts +29 -0
  52. package/src/common/fn/injectMany.ts +16 -0
  53. package/src/common/fn/injectable.spec.ts +87 -0
  54. package/src/common/fn/injectable.ts +15 -0
  55. package/src/common/fn/injector.ts +26 -0
  56. package/src/common/fn/lazyInject.spec.ts +22 -0
  57. package/src/common/fn/lazyInject.ts +36 -0
  58. package/src/common/fn/localsContainer.ts +55 -0
  59. package/src/common/fn/refValue.spec.ts +47 -0
  60. package/src/common/fn/refValue.ts +33 -0
  61. package/src/common/index.ts +63 -0
  62. package/src/common/integration/async-factory.spec.ts +60 -0
  63. package/src/common/integration/di.spec.ts +153 -0
  64. package/src/common/integration/imports.spec.ts +39 -0
  65. package/src/common/integration/request.spec.ts +79 -0
  66. package/src/common/integration/singleton.spec.ts +125 -0
  67. package/src/common/interfaces/DIConfigurationOptions.ts +29 -0
  68. package/src/common/interfaces/DILogger.ts +13 -0
  69. package/src/common/interfaces/DILoggerOptions.ts +54 -0
  70. package/src/common/interfaces/ImportTokenProviderOpts.ts +29 -0
  71. package/src/common/interfaces/InterceptorContext.ts +13 -0
  72. package/src/common/interfaces/InterceptorMethods.ts +5 -0
  73. package/src/common/interfaces/InvokeOptions.ts +28 -0
  74. package/src/common/interfaces/OnDestroy.ts +3 -0
  75. package/src/common/interfaces/OnInit.ts +3 -0
  76. package/src/common/interfaces/ProviderOpts.ts +57 -0
  77. package/src/common/interfaces/RegistrySettings.ts +11 -0
  78. package/src/common/interfaces/ResolvedInvokeOptions.ts +14 -0
  79. package/src/common/interfaces/TokenProvider.ts +3 -0
  80. package/src/common/interfaces/TokenRoute.ts +6 -0
  81. package/src/common/registries/GlobalProviders.spec.ts +94 -0
  82. package/src/common/registries/GlobalProviders.ts +131 -0
  83. package/src/common/registries/ProviderRegistry.spec.ts +36 -0
  84. package/src/common/registries/ProviderRegistry.ts +32 -0
  85. package/src/common/services/DIConfiguration.spec.ts +60 -0
  86. package/src/common/services/DIConfiguration.ts +140 -0
  87. package/src/common/services/DILogger.spec.ts +22 -0
  88. package/src/common/services/DILogger.ts +8 -0
  89. package/src/common/services/InjectorService.spec.ts +793 -0
  90. package/src/common/services/InjectorService.ts +601 -0
  91. package/src/common/utils/colors.spec.ts +9 -0
  92. package/src/common/utils/colors.ts +11 -0
  93. package/src/common/utils/createContainer.spec.ts +18 -0
  94. package/src/common/utils/createContainer.ts +14 -0
  95. package/src/common/utils/discoverHooks.ts +15 -0
  96. package/src/common/utils/getConfiguration.spec.ts +40 -0
  97. package/src/common/utils/getConfiguration.ts +20 -0
  98. package/src/common/utils/getConstructorDependencies.ts +9 -0
  99. package/src/common/utils/providerBuilder.ts +81 -0
  100. package/src/index.ts +2 -0
  101. package/src/node/decorators/injectContext.spec.ts +60 -0
  102. package/src/node/decorators/injectContext.ts +29 -0
  103. package/src/node/domain/ContextLogger.spec.ts +277 -0
  104. package/src/node/domain/ContextLogger.ts +137 -0
  105. package/src/node/domain/DIContext.spec.ts +103 -0
  106. package/src/node/domain/DIContext.ts +115 -0
  107. package/src/node/fn/context.ts +24 -0
  108. package/src/node/fn/logger.spec.ts +46 -0
  109. package/src/node/fn/logger.ts +17 -0
  110. package/src/node/index.ts +16 -0
  111. package/src/node/integration/async-factory-invoke.spec.ts +58 -0
  112. package/src/node/integration/inject-context.spec.ts +29 -0
  113. package/src/node/integration/invoke-oninit.spec.ts +25 -0
  114. package/src/node/interfaces/AlterRunInContext.ts +3 -0
  115. package/src/node/services/DILogger.spec.ts +24 -0
  116. package/src/node/services/DILogger.ts +6 -0
  117. package/src/node/services/DITest.spec.ts +109 -0
  118. package/src/node/services/DITest.ts +119 -0
  119. package/src/node/utils/asyncHookContext.spec.ts +147 -0
  120. package/src/node/utils/asyncHookContext.ts +48 -0
  121. package/src/node/utils/attachLogger.spec.ts +14 -0
  122. package/src/node/utils/attachLogger.ts +7 -0
  123. package/src/node/utils/setLoggerConfiguration.spec.ts +43 -0
  124. package/src/node/utils/setLoggerConfiguration.ts +7 -0
  125. package/src/node/utils/setLoggerFormat.ts +33 -0
  126. 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,7 @@
1
+ export enum InjectablePropertyType {
2
+ METHOD = "method",
3
+ PROPERTY = "property",
4
+ CONSTANT = "constant",
5
+ VALUE = "value",
6
+ INTERCEPTOR = "interceptor"
7
+ }
@@ -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,5 @@
1
+ export enum ProviderScope {
2
+ SINGLETON = "singleton",
3
+ REQUEST = "request",
4
+ INSTANCE = "instance"
5
+ }
@@ -0,0 +1,8 @@
1
+ export enum ProviderType {
2
+ VALUE = "value",
3
+ PROVIDER = "provider",
4
+ MODULE = "module",
5
+ CONTROLLER = "controller",
6
+ INTERCEPTOR = "interceptor",
7
+ MIDDLEWARE = "middleware"
8
+ }
@@ -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
+ });