@tsed/di 8.0.0 → 8.0.2

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 (125) hide show
  1. package/package.json +10 -9
  2. package/src/common/constants/constants.ts +5 -0
  3. package/src/common/decorators/autoInjectable.spec.ts +135 -0
  4. package/src/common/decorators/autoInjectable.ts +59 -0
  5. package/src/common/decorators/configuration.spec.ts +45 -0
  6. package/src/common/decorators/configuration.ts +34 -0
  7. package/src/common/decorators/constant.spec.ts +67 -0
  8. package/src/common/decorators/constant.ts +72 -0
  9. package/src/common/decorators/controller.spec.ts +43 -0
  10. package/src/common/decorators/controller.ts +64 -0
  11. package/src/common/decorators/inject.spec.ts +298 -0
  12. package/src/common/decorators/inject.ts +144 -0
  13. package/src/common/decorators/injectable.spec.ts +43 -0
  14. package/src/common/decorators/injectable.ts +30 -0
  15. package/src/common/decorators/intercept.spec.ts +103 -0
  16. package/src/common/decorators/intercept.ts +77 -0
  17. package/src/common/decorators/interceptor.ts +17 -0
  18. package/src/common/decorators/lazyInject.spec.ts +53 -0
  19. package/src/common/decorators/lazyInject.ts +91 -0
  20. package/src/common/decorators/module.ts +52 -0
  21. package/src/common/decorators/opts.ts +51 -0
  22. package/src/common/decorators/overrideProvider.spec.ts +30 -0
  23. package/src/common/decorators/overrideProvider.ts +15 -0
  24. package/src/common/decorators/scope.spec.ts +25 -0
  25. package/src/common/decorators/scope.ts +13 -0
  26. package/src/common/decorators/service.ts +14 -0
  27. package/src/common/decorators/useOpts.spec.ts +90 -0
  28. package/src/common/decorators/useOpts.ts +61 -0
  29. package/src/common/decorators/value.spec.ts +59 -0
  30. package/src/common/decorators/value.ts +60 -0
  31. package/src/common/domain/Container.spec.ts +85 -0
  32. package/src/common/domain/Container.ts +80 -0
  33. package/src/common/domain/ControllerProvider.spec.ts +55 -0
  34. package/src/common/domain/ControllerProvider.ts +48 -0
  35. package/src/common/domain/InjectablePropertyType.ts +7 -0
  36. package/src/common/domain/LocalsContainer.spec.ts +20 -0
  37. package/src/common/domain/LocalsContainer.ts +11 -0
  38. package/src/common/domain/Provider.spec.ts +107 -0
  39. package/src/common/domain/Provider.ts +205 -0
  40. package/src/common/domain/ProviderScope.ts +5 -0
  41. package/src/common/domain/ProviderType.ts +8 -0
  42. package/src/common/errors/InjectionError.spec.ts +17 -0
  43. package/src/common/errors/InjectionError.ts +68 -0
  44. package/src/common/errors/InvalidPropertyTokenError.ts +13 -0
  45. package/src/common/fn/configuration.spec.ts +42 -0
  46. package/src/common/fn/configuration.ts +22 -0
  47. package/src/common/fn/constant.spec.ts +37 -0
  48. package/src/common/fn/constant.ts +7 -0
  49. package/src/common/fn/inject.spec.ts +54 -0
  50. package/src/common/fn/inject.ts +29 -0
  51. package/src/common/fn/injectMany.ts +16 -0
  52. package/src/common/fn/injectable.spec.ts +87 -0
  53. package/src/common/fn/injectable.ts +15 -0
  54. package/src/common/fn/injector.ts +26 -0
  55. package/src/common/fn/lazyInject.spec.ts +22 -0
  56. package/src/common/fn/lazyInject.ts +36 -0
  57. package/src/common/fn/localsContainer.ts +55 -0
  58. package/src/common/fn/refValue.spec.ts +47 -0
  59. package/src/common/fn/refValue.ts +33 -0
  60. package/src/common/index.ts +63 -0
  61. package/src/common/integration/async-factory.spec.ts +60 -0
  62. package/src/common/integration/di.spec.ts +153 -0
  63. package/src/common/integration/imports.spec.ts +39 -0
  64. package/src/common/integration/request.spec.ts +79 -0
  65. package/src/common/integration/singleton.spec.ts +125 -0
  66. package/src/common/interfaces/DIConfigurationOptions.ts +29 -0
  67. package/src/common/interfaces/DILogger.ts +13 -0
  68. package/src/common/interfaces/DILoggerOptions.ts +54 -0
  69. package/src/common/interfaces/ImportTokenProviderOpts.ts +29 -0
  70. package/src/common/interfaces/InterceptorContext.ts +13 -0
  71. package/src/common/interfaces/InterceptorMethods.ts +5 -0
  72. package/src/common/interfaces/InvokeOptions.ts +28 -0
  73. package/src/common/interfaces/OnDestroy.ts +3 -0
  74. package/src/common/interfaces/OnInit.ts +3 -0
  75. package/src/common/interfaces/ProviderOpts.ts +57 -0
  76. package/src/common/interfaces/RegistrySettings.ts +11 -0
  77. package/src/common/interfaces/ResolvedInvokeOptions.ts +14 -0
  78. package/src/common/interfaces/TokenProvider.ts +3 -0
  79. package/src/common/interfaces/TokenRoute.ts +6 -0
  80. package/src/common/registries/GlobalProviders.spec.ts +94 -0
  81. package/src/common/registries/GlobalProviders.ts +131 -0
  82. package/src/common/registries/ProviderRegistry.spec.ts +36 -0
  83. package/src/common/registries/ProviderRegistry.ts +32 -0
  84. package/src/common/services/DIConfiguration.spec.ts +60 -0
  85. package/src/common/services/DIConfiguration.ts +140 -0
  86. package/src/common/services/DILogger.spec.ts +22 -0
  87. package/src/common/services/DILogger.ts +8 -0
  88. package/src/common/services/InjectorService.spec.ts +793 -0
  89. package/src/common/services/InjectorService.ts +601 -0
  90. package/src/common/utils/colors.spec.ts +9 -0
  91. package/src/common/utils/colors.ts +11 -0
  92. package/src/common/utils/createContainer.spec.ts +18 -0
  93. package/src/common/utils/createContainer.ts +14 -0
  94. package/src/common/utils/discoverHooks.ts +15 -0
  95. package/src/common/utils/getConfiguration.spec.ts +40 -0
  96. package/src/common/utils/getConfiguration.ts +20 -0
  97. package/src/common/utils/getConstructorDependencies.ts +9 -0
  98. package/src/common/utils/providerBuilder.ts +81 -0
  99. package/src/index.ts +2 -0
  100. package/src/node/decorators/injectContext.spec.ts +60 -0
  101. package/src/node/decorators/injectContext.ts +29 -0
  102. package/src/node/domain/ContextLogger.spec.ts +277 -0
  103. package/src/node/domain/ContextLogger.ts +137 -0
  104. package/src/node/domain/DIContext.spec.ts +103 -0
  105. package/src/node/domain/DIContext.ts +115 -0
  106. package/src/node/fn/context.ts +24 -0
  107. package/src/node/fn/logger.spec.ts +46 -0
  108. package/src/node/fn/logger.ts +17 -0
  109. package/src/node/index.ts +16 -0
  110. package/src/node/integration/async-factory-invoke.spec.ts +58 -0
  111. package/src/node/integration/inject-context.spec.ts +29 -0
  112. package/src/node/integration/invoke-oninit.spec.ts +25 -0
  113. package/src/node/interfaces/AlterRunInContext.ts +3 -0
  114. package/src/node/services/DILogger.spec.ts +24 -0
  115. package/src/node/services/DILogger.ts +6 -0
  116. package/src/node/services/DITest.spec.ts +109 -0
  117. package/src/node/services/DITest.ts +119 -0
  118. package/src/node/utils/asyncHookContext.spec.ts +147 -0
  119. package/src/node/utils/asyncHookContext.ts +48 -0
  120. package/src/node/utils/attachLogger.spec.ts +14 -0
  121. package/src/node/utils/attachLogger.ts +7 -0
  122. package/src/node/utils/setLoggerConfiguration.spec.ts +43 -0
  123. package/src/node/utils/setLoggerConfiguration.ts +7 -0
  124. package/src/node/utils/setLoggerFormat.ts +33 -0
  125. package/src/node/utils/setLoggerLevel.ts +12 -0
@@ -0,0 +1,119 @@
1
+ import {Env, getValue, isClass, isObject} from "@tsed/core";
2
+ import {$log} from "@tsed/logger";
3
+
4
+ import {cleanAllLocalsContainer, detachLocalsContainer, localsContainer} from "../../common/fn/localsContainer.js";
5
+ import {
6
+ createContainer,
7
+ destroyInjector,
8
+ DI_INJECTABLE_PROPS,
9
+ inject,
10
+ injector,
11
+ InjectorService,
12
+ type OnInit,
13
+ TokenProvider,
14
+ type UseImportTokenProviderOpts
15
+ } from "../../common/index.js";
16
+ import {DIContext} from "../domain/DIContext.js";
17
+ import {logger} from "../fn/logger.js";
18
+ import {setLoggerConfiguration} from "../utils/setLoggerConfiguration.js";
19
+
20
+ /**
21
+ * Tool to run test with lightweight DI sandbox.
22
+ */
23
+ export class DITest {
24
+ static get injector() {
25
+ return injector();
26
+ }
27
+
28
+ static async create(settings: Partial<TsED.Configuration> = {}) {
29
+ DITest.createInjector(settings);
30
+ await DITest.createContainer();
31
+ }
32
+
33
+ static async createContainer() {
34
+ await injector().load(createContainer());
35
+ }
36
+
37
+ /**
38
+ * Create a new injector with the right default services
39
+ */
40
+ static createInjector(settings: any = {}): InjectorService {
41
+ const inj = injector();
42
+ injector().logger = $log;
43
+ inj.settings.set(DITest.configure(settings));
44
+
45
+ setLoggerConfiguration();
46
+
47
+ return inj;
48
+ }
49
+
50
+ /**
51
+ * Resets the test injector of the test context, so it won't pollute your next test. Call this in your `tearDown` logic.
52
+ */
53
+ static async reset() {
54
+ await destroyInjector();
55
+ cleanAllLocalsContainer();
56
+ }
57
+
58
+ /**
59
+ * Invoke a provider and return a fresh instance
60
+ * @param target
61
+ * @param providers
62
+ */
63
+ static async invoke<T = any>(target: TokenProvider<T>, providers: UseImportTokenProviderOpts[] = []): Promise<T> {
64
+ const locals = localsContainer({providers, rebuild: true});
65
+
66
+ const instance: T & OnInit = inject<T & OnInit>(target, {locals, rebuild: true});
67
+
68
+ if (instance && isObject(instance) && "$onInit" in instance) {
69
+ const result = instance.$onInit();
70
+
71
+ if (result instanceof Promise) {
72
+ return result
73
+ .then(() => {
74
+ return;
75
+ })
76
+ .then(() => instance as any);
77
+ }
78
+ }
79
+
80
+ if (isClass(instance)) {
81
+ const keys = (instance as any)[DI_INJECTABLE_PROPS];
82
+
83
+ if (keys) {
84
+ await Promise.all([...keys.keys()].map((key: string) => (instance as any)[key]));
85
+ }
86
+ }
87
+
88
+ detachLocalsContainer();
89
+
90
+ return instance as any;
91
+ }
92
+
93
+ /**
94
+ * Return the instance from injector registry
95
+ * @param target
96
+ */
97
+ static get<T = any>(target: TokenProvider): T {
98
+ return injector().get<T>(target)!;
99
+ }
100
+
101
+ static createDIContext() {
102
+ return new DIContext({
103
+ id: "id",
104
+ injector: injector(),
105
+ logger: logger()
106
+ });
107
+ }
108
+
109
+ protected static configure(settings: Partial<TsED.Configuration> = {}): Partial<TsED.Configuration> {
110
+ return {
111
+ ...settings,
112
+ env: getValue(settings, "env", Env.TEST),
113
+ logger: {
114
+ ...getValue(settings, "logger", {}),
115
+ level: getValue(settings, "logger.level", "off")
116
+ }
117
+ };
118
+ }
119
+ }
@@ -0,0 +1,147 @@
1
+ import {DITest} from "../services/DITest.js";
2
+ import {getContext, runInContext, setContext} from "./asyncHookContext.js";
3
+
4
+ describe("asyncHookContext", () => {
5
+ beforeEach(() => DITest.create());
6
+ afterEach(() => DITest.reset());
7
+ it("should initiate the async hook context - promise", async () => {
8
+ const req = {type: "req"};
9
+ const res = {type: "res"};
10
+
11
+ function next(res: any, req: any) {
12
+ return Promise.resolve(getContext());
13
+ }
14
+
15
+ function nextContext(res: any, req: any, next: any) {
16
+ const $ctx: any = {
17
+ id: "id",
18
+ req,
19
+ res
20
+ };
21
+
22
+ setContext($ctx);
23
+
24
+ return next();
25
+ }
26
+
27
+ function app(req: any, res: any) {
28
+ return runInContext(undefined, () => nextContext(req, res, () => next(req, res)), DITest.injector);
29
+ }
30
+
31
+ const result = await app(req, res);
32
+
33
+ expect(result).toEqual({
34
+ id: "id",
35
+ req: {
36
+ type: "res"
37
+ },
38
+ res: {
39
+ type: "req"
40
+ }
41
+ });
42
+ });
43
+ it("should initiate the async hook context - promise - runInContext x2", async () => {
44
+ const req = {type: "req"};
45
+ const res = {type: "res"};
46
+
47
+ function next(res: any, req: any) {
48
+ return Promise.resolve(getContext());
49
+ }
50
+
51
+ function nextContext(res: any, req: any, next: any) {
52
+ const $ctx: any = {
53
+ id: "id",
54
+ req,
55
+ res
56
+ };
57
+
58
+ return runInContext($ctx, next);
59
+ }
60
+
61
+ function app(req: any, res: any) {
62
+ return runInContext(undefined, () => nextContext(req, res, () => next(req, res)), DITest.injector);
63
+ }
64
+
65
+ const result = await app(req, res);
66
+
67
+ expect(result).toEqual({
68
+ id: "id",
69
+ req: {
70
+ type: "res"
71
+ },
72
+ res: {
73
+ type: "req"
74
+ }
75
+ });
76
+ });
77
+ it("should initiate the async hook context - promise (initialValue)", async () => {
78
+ const req = {type: "req"};
79
+ const res = {type: "res"};
80
+
81
+ function next(res: any, req: any) {
82
+ return Promise.resolve(getContext({id: "id2"} as never));
83
+ }
84
+
85
+ function nextContext(res: any, req: any, next: any) {
86
+ const $ctx: any = {
87
+ id: "id",
88
+ req,
89
+ res
90
+ };
91
+
92
+ setContext($ctx);
93
+
94
+ return next();
95
+ }
96
+
97
+ function app(req: any, res: any) {
98
+ return runInContext(undefined, () => nextContext(req, res, () => next(req, res)), DITest.injector);
99
+ }
100
+
101
+ const result = await app(req, res);
102
+
103
+ expect(result).toEqual({
104
+ id: "id2"
105
+ });
106
+ });
107
+ it("should initiate the async hook context - promise + setTimeout", async () => {
108
+ const req = {type: "req"};
109
+ const res = {type: "res"};
110
+
111
+ function next(res: any, req: any) {
112
+ return new Promise((resolve) => {
113
+ setTimeout(() => {
114
+ resolve(getContext());
115
+ }, 100);
116
+ });
117
+ }
118
+
119
+ function nextContext(res: any, req: any, next: any) {
120
+ const $ctx: any = {
121
+ id: "id",
122
+ req,
123
+ res
124
+ };
125
+
126
+ setContext($ctx);
127
+
128
+ return next();
129
+ }
130
+
131
+ function app(req: any, res: any) {
132
+ return runInContext(undefined, () => nextContext(req, res, () => next(req, res)), DITest.injector);
133
+ }
134
+
135
+ const result = await app(req, res);
136
+
137
+ expect(result).toEqual({
138
+ id: "id",
139
+ req: {
140
+ type: "res"
141
+ },
142
+ res: {
143
+ type: "req"
144
+ }
145
+ });
146
+ });
147
+ });
@@ -0,0 +1,48 @@
1
+ import {AsyncLocalStorage, AsyncResource} from "async_hooks";
2
+
3
+ import {InjectorService} from "../../common/index.js";
4
+ import type {DIContext} from "../domain/DIContext.js";
5
+
6
+ const storage: AsyncLocalStorage<{current: DIContext | undefined}> = new AsyncLocalStorage();
7
+
8
+ export function getAsyncStore() {
9
+ return storage;
10
+ }
11
+
12
+ export function useContextRef() {
13
+ return getAsyncStore().getStore();
14
+ }
15
+
16
+ export function getContext<Context = DIContext>(initialValue?: DIContext): Context | undefined {
17
+ return initialValue || (useContextRef()?.current as any);
18
+ }
19
+
20
+ export async function runInContext<Result = unknown>(
21
+ ctx: DIContext | undefined,
22
+ cb: (...args: unknown[]) => Result,
23
+ injector?: InjectorService
24
+ ): Promise<Result> {
25
+ const ref = useContextRef();
26
+
27
+ if (ref) {
28
+ ctx && setContext(ctx);
29
+ return cb();
30
+ } else {
31
+ injector = ctx?.injector || injector;
32
+ cb = (await injector?.alterAsync("$alterRunInContext", cb)) || cb;
33
+
34
+ return storage.run({current: ctx}, cb);
35
+ }
36
+ }
37
+
38
+ export function setContext(ctx: DIContext) {
39
+ const ref = useContextRef();
40
+
41
+ if (ref && !ref.current) {
42
+ ref.current = ctx;
43
+ }
44
+ }
45
+
46
+ export function bindContext(cb: any) {
47
+ return AsyncResource.bind(cb);
48
+ }
@@ -0,0 +1,14 @@
1
+ import {Logger} from "@tsed/logger";
2
+
3
+ import {injector} from "../../common/index.js";
4
+ import {attachLogger} from "./attachLogger.js";
5
+
6
+ describe("attachLogger", () => {
7
+ it("should attach logger", () => {
8
+ const $log = new Logger("test");
9
+
10
+ attachLogger($log);
11
+
12
+ expect(injector().logger).toEqual($log);
13
+ });
14
+ });
@@ -0,0 +1,7 @@
1
+ import {DILogger, injector, InjectorService} from "../../common/index.js";
2
+ import {setLoggerConfiguration} from "./setLoggerConfiguration.js";
3
+
4
+ export function attachLogger($log: DILogger) {
5
+ injector().logger = $log;
6
+ setLoggerConfiguration();
7
+ }
@@ -0,0 +1,43 @@
1
+ import {Logger} from "@tsed/logger";
2
+ import {afterEach} from "vitest";
3
+
4
+ import {destroyInjector, injector} from "../../common/index.js";
5
+ import {setLoggerConfiguration} from "./setLoggerConfiguration.js";
6
+
7
+ describe("setLoggerConfiguration", () => {
8
+ afterEach(() => destroyInjector());
9
+ it("should change the logger level depending on the configuration", () => {
10
+ injector().settings.set("logger.level", "info");
11
+
12
+ setLoggerConfiguration();
13
+
14
+ expect(injector().logger.level).toEqual("info");
15
+ });
16
+ it("should call $log.appenders.set()", () => {
17
+ injector().logger = new Logger();
18
+
19
+ vi.spyOn(injector().logger.appenders, "set").mockResolvedValue(undefined);
20
+
21
+ injector().settings.set("logger.format", "format");
22
+
23
+ setLoggerConfiguration();
24
+
25
+ expect(injector().logger.appenders.set).toHaveBeenCalledWith("stdout", {
26
+ type: "stdout",
27
+ levels: ["info", "debug"],
28
+ layout: {
29
+ type: "pattern",
30
+ pattern: "format"
31
+ }
32
+ });
33
+
34
+ expect(injector().logger.appenders.set).toHaveBeenCalledWith("stderr", {
35
+ levels: ["trace", "fatal", "error", "warn"],
36
+ type: "stderr",
37
+ layout: {
38
+ type: "pattern",
39
+ pattern: "format"
40
+ }
41
+ });
42
+ });
43
+ });
@@ -0,0 +1,7 @@
1
+ import {setLoggerFormat} from "./setLoggerFormat.js";
2
+ import {setLoggerLevel} from "./setLoggerLevel.js";
3
+
4
+ export function setLoggerConfiguration() {
5
+ setLoggerLevel();
6
+ setLoggerFormat();
7
+ }
@@ -0,0 +1,33 @@
1
+ import {injector} from "../../common/index.js";
2
+ import {logger} from "../fn/logger.js";
3
+
4
+ /**
5
+ * @ignore
6
+ */
7
+ export function setLoggerFormat() {
8
+ const {level, format} = injector().settings.logger;
9
+
10
+ if (level) {
11
+ injector().logger.level = level;
12
+ }
13
+
14
+ if (format && injector().logger.appenders) {
15
+ logger().appenders.set("stdout", {
16
+ type: "stdout",
17
+ levels: ["info", "debug"],
18
+ layout: {
19
+ type: "pattern",
20
+ pattern: format
21
+ }
22
+ });
23
+
24
+ logger().appenders.set("stderr", {
25
+ levels: ["trace", "fatal", "error", "warn"],
26
+ type: "stderr",
27
+ layout: {
28
+ type: "pattern",
29
+ pattern: format
30
+ }
31
+ });
32
+ }
33
+ }
@@ -0,0 +1,12 @@
1
+ import {injector} from "../../common/index.js";
2
+
3
+ /**
4
+ * @ignore
5
+ */
6
+ export function setLoggerLevel() {
7
+ const {level} = injector().settings.logger;
8
+
9
+ if (level) {
10
+ injector().logger.level = level;
11
+ }
12
+ }