@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,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Automatically generated by @tsed/barrels.
|
|
3
|
+
*/
|
|
4
|
+
export * from "./constants/constants.js";
|
|
5
|
+
export * from "./decorators/autoInjectable.js";
|
|
6
|
+
export * from "./decorators/configuration.js";
|
|
7
|
+
export * from "./decorators/constant.js";
|
|
8
|
+
export * from "./decorators/controller.js";
|
|
9
|
+
export * from "./decorators/inject.js";
|
|
10
|
+
export * from "./decorators/injectable.js";
|
|
11
|
+
export * from "./decorators/intercept.js";
|
|
12
|
+
export * from "./decorators/interceptor.js";
|
|
13
|
+
export * from "./decorators/lazyInject.js";
|
|
14
|
+
export * from "./decorators/module.js";
|
|
15
|
+
export * from "./decorators/opts.js";
|
|
16
|
+
export * from "./decorators/overrideProvider.js";
|
|
17
|
+
export * from "./decorators/scope.js";
|
|
18
|
+
export * from "./decorators/service.js";
|
|
19
|
+
export * from "./decorators/useOpts.js";
|
|
20
|
+
export * from "./decorators/value.js";
|
|
21
|
+
export * from "./domain/Container.js";
|
|
22
|
+
export * from "./domain/ControllerProvider.js";
|
|
23
|
+
export * from "./domain/InjectablePropertyType.js";
|
|
24
|
+
export * from "./domain/LocalsContainer.js";
|
|
25
|
+
export * from "./domain/Provider.js";
|
|
26
|
+
export * from "./domain/ProviderScope.js";
|
|
27
|
+
export * from "./domain/ProviderType.js";
|
|
28
|
+
export * from "./errors/InjectionError.js";
|
|
29
|
+
export * from "./errors/InvalidPropertyTokenError.js";
|
|
30
|
+
export * from "./fn/configuration.js";
|
|
31
|
+
export * from "./fn/constant.js";
|
|
32
|
+
export * from "./fn/inject.js";
|
|
33
|
+
export * from "./fn/injectable.js";
|
|
34
|
+
export * from "./fn/injectMany.js";
|
|
35
|
+
export * from "./fn/injector.js";
|
|
36
|
+
export * from "./fn/lazyInject.js";
|
|
37
|
+
export * from "./fn/localsContainer.js";
|
|
38
|
+
export * from "./fn/refValue.js";
|
|
39
|
+
export * from "./interfaces/DIConfigurationOptions.js";
|
|
40
|
+
export * from "./interfaces/DILogger.js";
|
|
41
|
+
export * from "./interfaces/DILoggerOptions.js";
|
|
42
|
+
export * from "./interfaces/ImportTokenProviderOpts.js";
|
|
43
|
+
export * from "./interfaces/InterceptorContext.js";
|
|
44
|
+
export * from "./interfaces/InterceptorMethods.js";
|
|
45
|
+
export * from "./interfaces/InvokeOptions.js";
|
|
46
|
+
export * from "./interfaces/OnDestroy.js";
|
|
47
|
+
export * from "./interfaces/OnInit.js";
|
|
48
|
+
export * from "./interfaces/ProviderOpts.js";
|
|
49
|
+
export * from "./interfaces/RegistrySettings.js";
|
|
50
|
+
export * from "./interfaces/ResolvedInvokeOptions.js";
|
|
51
|
+
export * from "./interfaces/TokenProvider.js";
|
|
52
|
+
export * from "./interfaces/TokenRoute.js";
|
|
53
|
+
export * from "./registries/GlobalProviders.js";
|
|
54
|
+
export * from "./registries/ProviderRegistry.js";
|
|
55
|
+
export * from "./services/DIConfiguration.js";
|
|
56
|
+
export * from "./services/DILogger.js";
|
|
57
|
+
export * from "./services/InjectorService.js";
|
|
58
|
+
export * from "./utils/colors.js";
|
|
59
|
+
export * from "./utils/createContainer.js";
|
|
60
|
+
export * from "./utils/discoverHooks.js";
|
|
61
|
+
export * from "./utils/getConfiguration.js";
|
|
62
|
+
export * from "./utils/getConstructorDependencies.js";
|
|
63
|
+
export * from "./utils/providerBuilder.js";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {isPromise} from "@tsed/core";
|
|
2
|
+
import {afterEach, beforeEach} from "vitest";
|
|
3
|
+
|
|
4
|
+
import {Inject} from "../decorators/inject.js";
|
|
5
|
+
import {Injectable} from "../decorators/injectable.js";
|
|
6
|
+
import {Container} from "../domain/Container.js";
|
|
7
|
+
import {destroyInjector, injector} from "../fn/injector.js";
|
|
8
|
+
import {GlobalProviders} from "../registries/GlobalProviders.js";
|
|
9
|
+
import {registerProvider} from "../registries/ProviderRegistry.js";
|
|
10
|
+
import {InjectorService} from "../services/InjectorService.js";
|
|
11
|
+
|
|
12
|
+
describe("DI", () => {
|
|
13
|
+
afterEach(() => destroyInjector());
|
|
14
|
+
describe("create new injector", () => {
|
|
15
|
+
const ASYNC_FACTORY = Symbol.for("ASYNC_FACTORY");
|
|
16
|
+
|
|
17
|
+
registerProvider({
|
|
18
|
+
token: ASYNC_FACTORY,
|
|
19
|
+
|
|
20
|
+
useAsyncFactory() {
|
|
21
|
+
return {
|
|
22
|
+
connection: true,
|
|
23
|
+
close() {}
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
hooks: {
|
|
27
|
+
$onDestroy(instance: any) {
|
|
28
|
+
return instance.close();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
@Injectable()
|
|
34
|
+
class Server {
|
|
35
|
+
@Inject(ASYNC_FACTORY)
|
|
36
|
+
asyncFactory: any;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
afterAll(() => {
|
|
40
|
+
GlobalProviders.delete(Server);
|
|
41
|
+
GlobalProviders.delete(ASYNC_FACTORY);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should load all providers with the SINGLETON scope only", async () => {
|
|
45
|
+
// GIVEN
|
|
46
|
+
const container = new Container();
|
|
47
|
+
container.add(ASYNC_FACTORY);
|
|
48
|
+
container.add(Server);
|
|
49
|
+
|
|
50
|
+
const server = injector().invoke<any>(Server);
|
|
51
|
+
expect(isPromise(server.asyncFactory)).toEqual(true);
|
|
52
|
+
|
|
53
|
+
// WHEN
|
|
54
|
+
await injector().load(container);
|
|
55
|
+
|
|
56
|
+
expect(isPromise(server.asyncFactory)).toEqual(false);
|
|
57
|
+
expect(server.asyncFactory.connection).toEqual(true);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {afterEach} from "vitest";
|
|
2
|
+
|
|
3
|
+
import {Inject} from "../decorators/inject.js";
|
|
4
|
+
import {Injectable} from "../decorators/injectable.js";
|
|
5
|
+
import {Scope} from "../decorators/scope.js";
|
|
6
|
+
import {Service} from "../decorators/service.js";
|
|
7
|
+
import {Container} from "../domain/Container.js";
|
|
8
|
+
import {LocalsContainer} from "../domain/LocalsContainer.js";
|
|
9
|
+
import {ProviderScope} from "../domain/ProviderScope.js";
|
|
10
|
+
import {inject} from "../fn/inject.js";
|
|
11
|
+
import {destroyInjector, injector} from "../fn/injector.js";
|
|
12
|
+
import {OnDestroy} from "../interfaces/OnDestroy.js";
|
|
13
|
+
import {GlobalProviders} from "../registries/GlobalProviders.js";
|
|
14
|
+
|
|
15
|
+
describe("DI", () => {
|
|
16
|
+
afterEach(() => destroyInjector());
|
|
17
|
+
|
|
18
|
+
describe("from injector global container", () => {
|
|
19
|
+
@Service()
|
|
20
|
+
@Scope(ProviderScope.INSTANCE)
|
|
21
|
+
class ServiceInstance {
|
|
22
|
+
constructor() {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Service()
|
|
26
|
+
class ServiceSingleton {
|
|
27
|
+
constructor() {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Service()
|
|
31
|
+
@Scope(ProviderScope.REQUEST)
|
|
32
|
+
class ServiceRequest implements OnDestroy {
|
|
33
|
+
constructor(
|
|
34
|
+
public serviceSingleton: ServiceSingleton,
|
|
35
|
+
public serviceInstance: ServiceInstance
|
|
36
|
+
) {}
|
|
37
|
+
|
|
38
|
+
$onDestroy(): Promise<any> | void {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
afterAll(() => {
|
|
44
|
+
GlobalProviders.delete(ServiceSingleton);
|
|
45
|
+
GlobalProviders.delete(ServiceRequest);
|
|
46
|
+
GlobalProviders.delete(ServiceInstance);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should load all providers with the SINGLETON scope only", async () => {
|
|
50
|
+
// GIVEN
|
|
51
|
+
const providers = new Container();
|
|
52
|
+
providers.add(ServiceInstance);
|
|
53
|
+
providers.add(ServiceSingleton);
|
|
54
|
+
providers.add(ServiceRequest);
|
|
55
|
+
|
|
56
|
+
// WHEN
|
|
57
|
+
await injector().load(providers);
|
|
58
|
+
|
|
59
|
+
// THEN
|
|
60
|
+
expect(injector().get(ServiceSingleton)).toEqual(inject(ServiceSingleton));
|
|
61
|
+
expect(injector().get(ServiceRequest)).toBeInstanceOf(ServiceRequest);
|
|
62
|
+
expect(injector().has(ServiceRequest)).toBeFalsy();
|
|
63
|
+
expect(injector().get(ServiceInstance)).toBeInstanceOf(ServiceInstance);
|
|
64
|
+
expect(injector().has(ServiceRequest)).toBeFalsy();
|
|
65
|
+
|
|
66
|
+
expect(injector().invoke(ServiceRequest) === injector().invoke(ServiceRequest)).toEqual(false);
|
|
67
|
+
expect(inject(ServiceInstance) === inject(ServiceInstance)).toEqual(false);
|
|
68
|
+
|
|
69
|
+
const locals = new LocalsContainer();
|
|
70
|
+
expect(inject(ServiceRequest, {locals})).toEqual(inject(ServiceRequest, {locals}));
|
|
71
|
+
expect(inject(ServiceInstance, {locals}) === inject(ServiceInstance, {locals})).toEqual(false);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe("invoke class with abstract class", () => {
|
|
75
|
+
abstract class BaseService {}
|
|
76
|
+
|
|
77
|
+
@Injectable()
|
|
78
|
+
class NestedService extends BaseService {}
|
|
79
|
+
|
|
80
|
+
class BaseMyService {
|
|
81
|
+
@Inject(NestedService)
|
|
82
|
+
nested: BaseService;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@Injectable()
|
|
86
|
+
class MyService extends BaseMyService {}
|
|
87
|
+
|
|
88
|
+
afterAll(() => {
|
|
89
|
+
GlobalProviders.delete(MyService);
|
|
90
|
+
GlobalProviders.delete(NestedService);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should inject the expected class", async () => {
|
|
94
|
+
const providers = new Container();
|
|
95
|
+
providers.add(MyService);
|
|
96
|
+
providers.add(NestedService);
|
|
97
|
+
|
|
98
|
+
await injector().load(providers);
|
|
99
|
+
|
|
100
|
+
expect(injector().get<MyService>(MyService)!.nested).toBeInstanceOf(NestedService);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe("invoke class with a symbol", () => {
|
|
104
|
+
interface BaseService {}
|
|
105
|
+
|
|
106
|
+
const BaseService: unique symbol = Symbol("BaseService");
|
|
107
|
+
|
|
108
|
+
@Injectable({token: BaseService})
|
|
109
|
+
class NestedService implements BaseService {}
|
|
110
|
+
|
|
111
|
+
@Injectable()
|
|
112
|
+
class MyService {
|
|
113
|
+
@Inject(BaseService)
|
|
114
|
+
nested: BaseService;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
afterAll(() => {
|
|
118
|
+
GlobalProviders.delete(MyService);
|
|
119
|
+
GlobalProviders.delete(NestedService);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should inject the expected class", async () => {
|
|
123
|
+
const providers = new Container();
|
|
124
|
+
providers.add(MyService);
|
|
125
|
+
providers.add(NestedService);
|
|
126
|
+
|
|
127
|
+
await injector().load(providers);
|
|
128
|
+
|
|
129
|
+
expect(injector().get<MyService>(MyService)!.nested).toBeInstanceOf(NestedService);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe("invoke class with a provider", () => {
|
|
133
|
+
it("should invoke class with a another useClass", async () => {
|
|
134
|
+
@Injectable()
|
|
135
|
+
class MyClass {}
|
|
136
|
+
|
|
137
|
+
class FakeMyClass {}
|
|
138
|
+
|
|
139
|
+
injector().addProvider(MyClass, {
|
|
140
|
+
useClass: FakeMyClass
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const instance = inject(MyClass);
|
|
144
|
+
|
|
145
|
+
expect(instance).toBeInstanceOf(FakeMyClass);
|
|
146
|
+
expect(injector().get(MyClass)).toBeInstanceOf(FakeMyClass);
|
|
147
|
+
|
|
148
|
+
await injector().load();
|
|
149
|
+
|
|
150
|
+
expect(injector().get(MyClass)).toBeInstanceOf(FakeMyClass);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {DITest} from "../../node/index.js";
|
|
2
|
+
import {Inject} from "../decorators/inject.js";
|
|
3
|
+
import {Injectable} from "../decorators/injectable.js";
|
|
4
|
+
import {Module} from "../decorators/module.js";
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
class MyService {
|
|
8
|
+
createConnection() {}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@Module()
|
|
12
|
+
class MyModule {
|
|
13
|
+
@Inject()
|
|
14
|
+
myService: MyService;
|
|
15
|
+
|
|
16
|
+
$onInit() {
|
|
17
|
+
this.myService.createConnection();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("DITest", () => {
|
|
22
|
+
beforeEach(() =>
|
|
23
|
+
DITest.create({
|
|
24
|
+
imports: [
|
|
25
|
+
{
|
|
26
|
+
token: MyService,
|
|
27
|
+
use: {
|
|
28
|
+
createConnection: vi.fn()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
it("should create container with stubbed service", () => {
|
|
36
|
+
const service = DITest.get(MyService);
|
|
37
|
+
expect(service.createConnection).toHaveBeenCalledWith();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {beforeEach} from "vitest";
|
|
2
|
+
|
|
3
|
+
import {Scope} from "../decorators/scope.js";
|
|
4
|
+
import {Service} from "../decorators/service.js";
|
|
5
|
+
import {Container} from "../domain/Container.js";
|
|
6
|
+
import {LocalsContainer} from "../domain/LocalsContainer.js";
|
|
7
|
+
import {ProviderScope} from "../domain/ProviderScope.js";
|
|
8
|
+
import {destroyInjector, injector} from "../fn/injector.js";
|
|
9
|
+
import {OnDestroy} from "../interfaces/OnDestroy.js";
|
|
10
|
+
import {GlobalProviders} from "../registries/GlobalProviders.js";
|
|
11
|
+
import {InjectorService} from "../services/InjectorService.js";
|
|
12
|
+
|
|
13
|
+
describe("DI Request", () => {
|
|
14
|
+
beforeEach(() => destroyInjector());
|
|
15
|
+
|
|
16
|
+
@Service()
|
|
17
|
+
@Scope(ProviderScope.INSTANCE)
|
|
18
|
+
class ServiceInstance {
|
|
19
|
+
constructor() {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@Service()
|
|
23
|
+
class ServiceSingleton {
|
|
24
|
+
constructor() {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Service()
|
|
28
|
+
@Scope(ProviderScope.REQUEST)
|
|
29
|
+
class ServiceRequest implements OnDestroy {
|
|
30
|
+
constructor(
|
|
31
|
+
public serviceSingleton: ServiceSingleton,
|
|
32
|
+
public serviceInstance: ServiceInstance
|
|
33
|
+
) {}
|
|
34
|
+
|
|
35
|
+
$onDestroy(): Promise<any> | void {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
afterAll(() => {
|
|
41
|
+
GlobalProviders.delete(ServiceSingleton);
|
|
42
|
+
GlobalProviders.delete(ServiceRequest);
|
|
43
|
+
GlobalProviders.delete(ServiceInstance);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("when invoke a service declared as REQUEST", () => {
|
|
47
|
+
it("should get a new instance of ServiceRequest", async () => {
|
|
48
|
+
// GIVEN
|
|
49
|
+
const container = new Container();
|
|
50
|
+
|
|
51
|
+
container.addProvider(ServiceSingleton);
|
|
52
|
+
container.addProvider(ServiceRequest);
|
|
53
|
+
container.addProvider(ServiceInstance);
|
|
54
|
+
|
|
55
|
+
await injector().load(container);
|
|
56
|
+
|
|
57
|
+
// we use a local container to create a new context
|
|
58
|
+
const locals = new LocalsContainer();
|
|
59
|
+
|
|
60
|
+
// WHEN
|
|
61
|
+
const result1: any = injector().invoke(ServiceRequest, {locals});
|
|
62
|
+
const result2: any = injector().invoke(ServiceRequest, {locals});
|
|
63
|
+
const serviceSingleton1: any = injector().invoke(ServiceSingleton, {locals});
|
|
64
|
+
const serviceSingleton2: any = injector().get(ServiceSingleton);
|
|
65
|
+
|
|
66
|
+
vi.spyOn(result1, "$onDestroy").mockResolvedValue(undefined);
|
|
67
|
+
|
|
68
|
+
await locals.destroy();
|
|
69
|
+
// THEN
|
|
70
|
+
expect(result1).toEqual(result2);
|
|
71
|
+
expect(result1.serviceSingleton).toEqual(serviceSingleton1);
|
|
72
|
+
expect(result1.serviceInstance).toBeInstanceOf(ServiceInstance);
|
|
73
|
+
|
|
74
|
+
expect(serviceSingleton1).toEqual(serviceSingleton2);
|
|
75
|
+
|
|
76
|
+
return expect(result1.$onDestroy).toHaveBeenCalledWith();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {Scope} from "../decorators/scope.js";
|
|
2
|
+
import {Service} from "../decorators/service.js";
|
|
3
|
+
import {Container} from "../domain/Container.js";
|
|
4
|
+
import {ProviderScope} from "../domain/ProviderScope.js";
|
|
5
|
+
import {destroyInjector, injector} from "../fn/injector.js";
|
|
6
|
+
import {GlobalProviders} from "../registries/GlobalProviders.js";
|
|
7
|
+
import {InjectorService} from "../services/InjectorService.js";
|
|
8
|
+
|
|
9
|
+
describe("DI Singleton", () => {
|
|
10
|
+
@Service()
|
|
11
|
+
class ServiceSingleton {
|
|
12
|
+
constructor(public injector: InjectorService) {}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Service()
|
|
16
|
+
@Scope(ProviderScope.REQUEST)
|
|
17
|
+
class ServiceRequest {
|
|
18
|
+
constructor() {}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@Service()
|
|
22
|
+
@Scope(ProviderScope.INSTANCE)
|
|
23
|
+
class ServiceInstance {
|
|
24
|
+
constructor() {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Service()
|
|
28
|
+
class ServiceSingletonWithRequestDep {
|
|
29
|
+
constructor(
|
|
30
|
+
public serviceRequest: ServiceRequest,
|
|
31
|
+
public serviceRequest2: ServiceRequest
|
|
32
|
+
) {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Service()
|
|
36
|
+
class ServiceSingletonWithInstanceDep {
|
|
37
|
+
constructor(
|
|
38
|
+
public serviceInstance: ServiceInstance,
|
|
39
|
+
public serviceInstance2: ServiceInstance
|
|
40
|
+
) {}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
afterEach(() => destroyInjector());
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
GlobalProviders.delete(ServiceSingleton);
|
|
46
|
+
GlobalProviders.delete(ServiceRequest);
|
|
47
|
+
GlobalProviders.delete(ServiceInstance);
|
|
48
|
+
GlobalProviders.delete(ServiceSingletonWithRequestDep);
|
|
49
|
+
GlobalProviders.delete(ServiceSingletonWithInstanceDep);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("when it has a SINGLETON dependency", () => {
|
|
53
|
+
it("should get the service instance", async () => {
|
|
54
|
+
// GIVEN
|
|
55
|
+
const container = new Container();
|
|
56
|
+
|
|
57
|
+
container.addProvider(ServiceSingleton);
|
|
58
|
+
container.addProvider(ServiceRequest);
|
|
59
|
+
container.addProvider(ServiceInstance);
|
|
60
|
+
container.addProvider(ServiceSingletonWithRequestDep);
|
|
61
|
+
container.addProvider(ServiceSingletonWithInstanceDep);
|
|
62
|
+
|
|
63
|
+
// WHEN
|
|
64
|
+
await injector().load(container);
|
|
65
|
+
|
|
66
|
+
// THEN
|
|
67
|
+
expect(injector().get<ServiceSingleton>(ServiceSingleton)!).toBeInstanceOf(ServiceSingleton);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe("when it has a REQUEST dependency", () => {
|
|
71
|
+
it("should get the instance and REQUEST dependency should be considered as local SINGLETON", async () => {
|
|
72
|
+
// GIVEN
|
|
73
|
+
const container = new Container();
|
|
74
|
+
container.addProvider(ServiceSingleton);
|
|
75
|
+
container.addProvider(ServiceRequest);
|
|
76
|
+
container.addProvider(ServiceInstance);
|
|
77
|
+
container.addProvider(ServiceSingletonWithRequestDep);
|
|
78
|
+
container.addProvider(ServiceSingletonWithInstanceDep);
|
|
79
|
+
|
|
80
|
+
// WHEN
|
|
81
|
+
await injector().load(container);
|
|
82
|
+
const serviceSingletonWithReqDep = injector().get<ServiceSingletonWithRequestDep>(ServiceSingletonWithRequestDep)!;
|
|
83
|
+
const serviceRequest = injector().get<ServiceRequest>(ServiceRequest)!;
|
|
84
|
+
|
|
85
|
+
// THEN
|
|
86
|
+
expect(serviceSingletonWithReqDep).toBeInstanceOf(ServiceSingletonWithRequestDep);
|
|
87
|
+
expect(serviceSingletonWithReqDep.serviceRequest).toBeInstanceOf(ServiceRequest);
|
|
88
|
+
expect(serviceSingletonWithReqDep.serviceRequest2).toBeInstanceOf(ServiceRequest);
|
|
89
|
+
|
|
90
|
+
// The same service injected twice or more are considered as a Singleton (REQUEST downgraded to SINGLETON)
|
|
91
|
+
expect(serviceSingletonWithReqDep.serviceRequest).toEqual(serviceSingletonWithReqDep.serviceRequest2);
|
|
92
|
+
|
|
93
|
+
// The service isn't registered in the injectorService
|
|
94
|
+
expect(serviceRequest).toBeDefined();
|
|
95
|
+
expect(injector().has(ServiceRequest)).toEqual(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("when it has a INSTANCE dependency", () => {
|
|
99
|
+
it("should get the service instance", async () => {
|
|
100
|
+
// GIVEN
|
|
101
|
+
const container = new Container();
|
|
102
|
+
container.addProvider(ServiceSingleton);
|
|
103
|
+
container.addProvider(ServiceRequest);
|
|
104
|
+
container.addProvider(ServiceInstance);
|
|
105
|
+
container.addProvider(ServiceSingletonWithRequestDep);
|
|
106
|
+
container.addProvider(ServiceSingletonWithInstanceDep);
|
|
107
|
+
// WHEN
|
|
108
|
+
await injector().load(container);
|
|
109
|
+
const serviceWithInstDep = injector().get<ServiceSingletonWithInstanceDep>(ServiceSingletonWithInstanceDep)!;
|
|
110
|
+
const serviceInstance = injector().get<ServiceInstance>(ServiceInstance)!;
|
|
111
|
+
|
|
112
|
+
// THEN
|
|
113
|
+
expect(serviceWithInstDep).toBeInstanceOf(ServiceSingletonWithInstanceDep);
|
|
114
|
+
expect(serviceWithInstDep.serviceInstance).toBeInstanceOf(ServiceInstance);
|
|
115
|
+
expect(serviceWithInstDep.serviceInstance2).toBeInstanceOf(ServiceInstance);
|
|
116
|
+
|
|
117
|
+
// A same service injected twice or more are considered as a new INSTANCE for each injection
|
|
118
|
+
expect(serviceWithInstDep.serviceInstance === serviceWithInstDep.serviceInstance2).toEqual(false);
|
|
119
|
+
|
|
120
|
+
// The service isn't registered in the injectorService
|
|
121
|
+
expect(serviceInstance).toBeInstanceOf(ServiceInstance);
|
|
122
|
+
expect(injector().has(ServiceInstance)).toEqual(false);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {ProviderScope} from "../domain/ProviderScope.js";
|
|
2
|
+
import type {ImportTokenProviderOpts} from "./ImportTokenProviderOpts.js";
|
|
3
|
+
import type {TokenProvider} from "./TokenProvider.js";
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
namespace TsED {
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
interface Context {}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Here to allow extension on DIConfiguration base service
|
|
12
|
+
*/
|
|
13
|
+
interface DIConfiguration {}
|
|
14
|
+
|
|
15
|
+
interface Configuration extends Record<string, any> {
|
|
16
|
+
scopes: {[key: string]: ProviderScope};
|
|
17
|
+
/**
|
|
18
|
+
* Define dependencies to build the provider
|
|
19
|
+
*/
|
|
20
|
+
imports: (TokenProvider | ImportTokenProviderOpts)[];
|
|
21
|
+
/**
|
|
22
|
+
* Mount controllers
|
|
23
|
+
*/
|
|
24
|
+
mount: Record<string, TokenProvider[]>;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface DIConfigurationOptions extends TsED.Configuration {}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface DILoggerOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Enable debug mode. By default debug is false.
|
|
4
|
+
*/
|
|
5
|
+
debug?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Enable info mode. By default debug is false.
|
|
8
|
+
*/
|
|
9
|
+
level?: "debug" | "info" | "warn" | "error" | "off";
|
|
10
|
+
/**
|
|
11
|
+
* Enable log performance tracker and disable log server.
|
|
12
|
+
*/
|
|
13
|
+
perf?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* List of regexp to ignore log.
|
|
16
|
+
*/
|
|
17
|
+
ignoreUrlPatterns?: (string | RegExp)[];
|
|
18
|
+
/**
|
|
19
|
+
* The number of space characters to use as white space in JSON output. Default is 2 (0 in production).
|
|
20
|
+
*/
|
|
21
|
+
jsonIndentation?: number;
|
|
22
|
+
/**
|
|
23
|
+
* A function called for each incoming request to create a request id.
|
|
24
|
+
* @returns {number}
|
|
25
|
+
*/
|
|
26
|
+
reqIdBuilder?: (req: any) => string;
|
|
27
|
+
/**
|
|
28
|
+
* Disable routes table displayed in the logger. By default debug is `false`.
|
|
29
|
+
*/
|
|
30
|
+
disableRoutesSummary?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Disable bootstrap log displayed in the logger. By default debug is `false`.
|
|
33
|
+
*/
|
|
34
|
+
disableBootstrapLog?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Specify log format. Example: `%[%d{[yyyy-MM-dd hh:mm:ss,SSS}] %p%] %m`. See [@tsed/logger configuration](https://tsedio.github.io/logger/).
|
|
37
|
+
*/
|
|
38
|
+
format?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Specify the log stack size for the context.logger. When the stack.length is reach, the logger is flushed during the request.
|
|
41
|
+
* Default size is set to 30.
|
|
42
|
+
*/
|
|
43
|
+
maxStackSize?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
declare global {
|
|
47
|
+
namespace TsED {
|
|
48
|
+
interface LoggerConfiguration extends DILoggerOptions {}
|
|
49
|
+
|
|
50
|
+
interface Configuration extends Record<string, any> {
|
|
51
|
+
logger?: LoggerConfiguration;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {AbstractType, Type} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
import type {TokenProvider} from "./TokenProvider.js";
|
|
4
|
+
|
|
5
|
+
export type UseImportTokenProviderOpts = {
|
|
6
|
+
token: TokenProvider;
|
|
7
|
+
use: unknown;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type UseClassImportTokenProviderOpts = {
|
|
11
|
+
token: TokenProvider;
|
|
12
|
+
useClass: Type | AbstractType<any>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type UseFactoryImportTokenProviderOpts = {
|
|
16
|
+
token: TokenProvider;
|
|
17
|
+
useFactory: (...args: unknown[]) => unknown;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type UseAsyncFactoryImportTokenProviderOpts = {
|
|
21
|
+
token: TokenProvider;
|
|
22
|
+
useAsyncFactory: (...args: unknown[]) => Promise<unknown>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type ImportTokenProviderOpts =
|
|
26
|
+
| UseImportTokenProviderOpts
|
|
27
|
+
| UseClassImportTokenProviderOpts
|
|
28
|
+
| UseFactoryImportTokenProviderOpts
|
|
29
|
+
| UseAsyncFactoryImportTokenProviderOpts;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type {Type} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
export interface InterceptorNext {
|
|
4
|
+
<T>(err?: Error): T;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface InterceptorContext<Klass = Type, Opts = any> {
|
|
8
|
+
target: Klass;
|
|
9
|
+
propertyKey: string | symbol;
|
|
10
|
+
args: any[];
|
|
11
|
+
next: InterceptorNext;
|
|
12
|
+
options?: Opts;
|
|
13
|
+
}
|