@navios/di 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +117 -17
  3. package/lib/browser/container/abstract-container.d.mts +112 -0
  4. package/lib/browser/container/abstract-container.d.mts.map +1 -0
  5. package/lib/browser/container/abstract-container.mjs +100 -0
  6. package/lib/browser/container/abstract-container.mjs.map +1 -0
  7. package/lib/browser/container/container.d.mts +100 -0
  8. package/lib/browser/container/container.d.mts.map +1 -0
  9. package/lib/browser/container/container.mjs +424 -0
  10. package/lib/browser/container/container.mjs.map +1 -0
  11. package/lib/browser/container/scoped-container.d.mts +93 -0
  12. package/lib/browser/container/scoped-container.d.mts.map +1 -0
  13. package/lib/browser/container/scoped-container.mjs +119 -0
  14. package/lib/browser/container/scoped-container.mjs.map +1 -0
  15. package/lib/browser/decorators/factory.decorator.d.mts +26 -0
  16. package/lib/browser/decorators/factory.decorator.d.mts.map +1 -0
  17. package/lib/browser/decorators/factory.decorator.mjs +20 -0
  18. package/lib/browser/decorators/factory.decorator.mjs.map +1 -0
  19. package/lib/browser/decorators/injectable.decorator.d.mts +38 -0
  20. package/lib/browser/decorators/injectable.decorator.d.mts.map +1 -0
  21. package/lib/browser/decorators/injectable.decorator.mjs +21 -0
  22. package/lib/browser/decorators/injectable.decorator.mjs.map +1 -0
  23. package/lib/browser/enums/injectable-scope.enum.d.mts +18 -0
  24. package/lib/browser/enums/injectable-scope.enum.d.mts.map +1 -0
  25. package/lib/browser/enums/injectable-scope.enum.mjs +20 -0
  26. package/lib/browser/enums/injectable-scope.enum.mjs.map +1 -0
  27. package/lib/browser/enums/injectable-type.enum.d.mts +8 -0
  28. package/lib/browser/enums/injectable-type.enum.d.mts.map +1 -0
  29. package/lib/browser/enums/injectable-type.enum.mjs +10 -0
  30. package/lib/browser/enums/injectable-type.enum.mjs.map +1 -0
  31. package/lib/browser/errors/di-error.d.mts +43 -0
  32. package/lib/browser/errors/di-error.d.mts.map +1 -0
  33. package/lib/browser/errors/di-error.mjs +98 -0
  34. package/lib/browser/errors/di-error.mjs.map +1 -0
  35. package/lib/browser/event-emitter.d.mts +16 -0
  36. package/lib/browser/event-emitter.d.mts.map +1 -0
  37. package/lib/browser/event-emitter.mjs +320 -0
  38. package/lib/browser/event-emitter.mjs.map +1 -0
  39. package/lib/browser/index.d.mts +37 -1558
  40. package/lib/browser/index.mjs +29 -2749
  41. package/lib/browser/interfaces/container.interface.d.mts +59 -0
  42. package/lib/browser/interfaces/container.interface.d.mts.map +1 -0
  43. package/lib/browser/interfaces/factory.interface.d.mts +14 -0
  44. package/lib/browser/interfaces/factory.interface.d.mts.map +1 -0
  45. package/lib/browser/interfaces/on-service-destroy.interface.d.mts +7 -0
  46. package/lib/browser/interfaces/on-service-destroy.interface.d.mts.map +1 -0
  47. package/lib/browser/interfaces/on-service-init.interface.d.mts +7 -0
  48. package/lib/browser/interfaces/on-service-init.interface.d.mts.map +1 -0
  49. package/lib/browser/internal/context/async-local-storage.browser.mjs +20 -0
  50. package/lib/browser/internal/context/async-local-storage.browser.mjs.map +1 -0
  51. package/lib/browser/internal/context/async-local-storage.d.mts +9 -0
  52. package/lib/browser/internal/context/async-local-storage.d.mts.map +1 -0
  53. package/lib/browser/internal/context/async-local-storage.types.d.mts +11 -0
  54. package/lib/browser/internal/context/async-local-storage.types.d.mts.map +1 -0
  55. package/lib/browser/internal/context/factory-context.d.mts +23 -0
  56. package/lib/browser/internal/context/factory-context.d.mts.map +1 -0
  57. package/lib/browser/internal/context/resolution-context.d.mts +43 -0
  58. package/lib/browser/internal/context/resolution-context.d.mts.map +1 -0
  59. package/lib/browser/internal/context/resolution-context.mjs +56 -0
  60. package/lib/browser/internal/context/resolution-context.mjs.map +1 -0
  61. package/lib/browser/internal/context/service-initialization-context.d.mts +48 -0
  62. package/lib/browser/internal/context/service-initialization-context.d.mts.map +1 -0
  63. package/lib/browser/internal/context/sync-local-storage.mjs +53 -0
  64. package/lib/browser/internal/context/sync-local-storage.mjs.map +1 -0
  65. package/lib/browser/internal/core/instance-resolver.d.mts +119 -0
  66. package/lib/browser/internal/core/instance-resolver.d.mts.map +1 -0
  67. package/lib/browser/internal/core/instance-resolver.mjs +306 -0
  68. package/lib/browser/internal/core/instance-resolver.mjs.map +1 -0
  69. package/lib/browser/internal/core/name-resolver.d.mts +52 -0
  70. package/lib/browser/internal/core/name-resolver.d.mts.map +1 -0
  71. package/lib/browser/internal/core/name-resolver.mjs +118 -0
  72. package/lib/browser/internal/core/name-resolver.mjs.map +1 -0
  73. package/lib/browser/internal/core/scope-tracker.d.mts +65 -0
  74. package/lib/browser/internal/core/scope-tracker.d.mts.map +1 -0
  75. package/lib/browser/internal/core/scope-tracker.mjs +120 -0
  76. package/lib/browser/internal/core/scope-tracker.mjs.map +1 -0
  77. package/lib/browser/internal/core/service-initializer.d.mts +44 -0
  78. package/lib/browser/internal/core/service-initializer.d.mts.map +1 -0
  79. package/lib/browser/internal/core/service-initializer.mjs +109 -0
  80. package/lib/browser/internal/core/service-initializer.mjs.map +1 -0
  81. package/lib/browser/internal/core/service-invalidator.d.mts +81 -0
  82. package/lib/browser/internal/core/service-invalidator.d.mts.map +1 -0
  83. package/lib/browser/internal/core/service-invalidator.mjs +142 -0
  84. package/lib/browser/internal/core/service-invalidator.mjs.map +1 -0
  85. package/lib/browser/internal/core/token-resolver.d.mts +54 -0
  86. package/lib/browser/internal/core/token-resolver.d.mts.map +1 -0
  87. package/lib/browser/internal/core/token-resolver.mjs +77 -0
  88. package/lib/browser/internal/core/token-resolver.mjs.map +1 -0
  89. package/lib/browser/internal/holder/holder-storage.interface.d.mts +99 -0
  90. package/lib/browser/internal/holder/holder-storage.interface.d.mts.map +1 -0
  91. package/lib/browser/internal/holder/instance-holder.d.mts +101 -0
  92. package/lib/browser/internal/holder/instance-holder.d.mts.map +1 -0
  93. package/lib/browser/internal/holder/instance-holder.mjs +19 -0
  94. package/lib/browser/internal/holder/instance-holder.mjs.map +1 -0
  95. package/lib/browser/internal/holder/unified-storage.d.mts +53 -0
  96. package/lib/browser/internal/holder/unified-storage.d.mts.map +1 -0
  97. package/lib/browser/internal/holder/unified-storage.mjs +144 -0
  98. package/lib/browser/internal/holder/unified-storage.mjs.map +1 -0
  99. package/lib/browser/internal/lifecycle/circular-detector.d.mts +39 -0
  100. package/lib/browser/internal/lifecycle/circular-detector.d.mts.map +1 -0
  101. package/lib/browser/internal/lifecycle/circular-detector.mjs +55 -0
  102. package/lib/browser/internal/lifecycle/circular-detector.mjs.map +1 -0
  103. package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts +18 -0
  104. package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts.map +1 -0
  105. package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs +43 -0
  106. package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs.map +1 -0
  107. package/lib/browser/internal/stub-factory-class.d.mts +14 -0
  108. package/lib/browser/internal/stub-factory-class.d.mts.map +1 -0
  109. package/lib/browser/internal/stub-factory-class.mjs +18 -0
  110. package/lib/browser/internal/stub-factory-class.mjs.map +1 -0
  111. package/lib/browser/symbols/injectable-token.d.mts +5 -0
  112. package/lib/browser/symbols/injectable-token.d.mts.map +1 -0
  113. package/lib/browser/symbols/injectable-token.mjs +6 -0
  114. package/lib/browser/symbols/injectable-token.mjs.map +1 -0
  115. package/lib/browser/token/injection-token.d.mts +55 -0
  116. package/lib/browser/token/injection-token.d.mts.map +1 -0
  117. package/lib/browser/token/injection-token.mjs +100 -0
  118. package/lib/browser/token/injection-token.mjs.map +1 -0
  119. package/lib/browser/token/registry.d.mts +37 -0
  120. package/lib/browser/token/registry.d.mts.map +1 -0
  121. package/lib/browser/token/registry.mjs +86 -0
  122. package/lib/browser/token/registry.mjs.map +1 -0
  123. package/lib/browser/utils/default-injectors.d.mts +12 -0
  124. package/lib/browser/utils/default-injectors.d.mts.map +1 -0
  125. package/lib/browser/utils/default-injectors.mjs +13 -0
  126. package/lib/browser/utils/default-injectors.mjs.map +1 -0
  127. package/lib/browser/utils/get-injectable-token.d.mts +9 -0
  128. package/lib/browser/utils/get-injectable-token.d.mts.map +1 -0
  129. package/lib/browser/utils/get-injectable-token.mjs +13 -0
  130. package/lib/browser/utils/get-injectable-token.mjs.map +1 -0
  131. package/lib/browser/utils/get-injectors.d.mts +55 -0
  132. package/lib/browser/utils/get-injectors.d.mts.map +1 -0
  133. package/lib/browser/utils/get-injectors.mjs +121 -0
  134. package/lib/browser/utils/get-injectors.mjs.map +1 -0
  135. package/lib/browser/utils/types.d.mts +23 -0
  136. package/lib/browser/utils/types.d.mts.map +1 -0
  137. package/lib/{container-DAKOvAgr.mjs → container-8-z89TyQ.mjs} +1325 -1462
  138. package/lib/container-8-z89TyQ.mjs.map +1 -0
  139. package/lib/{container-Bp1W-pWJ.d.mts → container-CNiqesCL.d.mts} +598 -617
  140. package/lib/container-CNiqesCL.d.mts.map +1 -0
  141. package/lib/{container-DENMeJ87.cjs → container-CaY2fDuk.cjs} +1369 -1512
  142. package/lib/container-CaY2fDuk.cjs.map +1 -0
  143. package/lib/{container-YPwvmlK2.d.cts → container-D-0Ho3qL.d.cts} +598 -612
  144. package/lib/container-D-0Ho3qL.d.cts.map +1 -0
  145. package/lib/index.cjs +13 -15
  146. package/lib/index.cjs.map +1 -1
  147. package/lib/index.d.cts +58 -223
  148. package/lib/index.d.cts.map +1 -1
  149. package/lib/index.d.mts +62 -222
  150. package/lib/index.d.mts.map +1 -1
  151. package/lib/index.mjs +5 -6
  152. package/lib/index.mjs.map +1 -1
  153. package/lib/testing/index.cjs +569 -311
  154. package/lib/testing/index.cjs.map +1 -1
  155. package/lib/testing/index.d.cts +370 -41
  156. package/lib/testing/index.d.cts.map +1 -1
  157. package/lib/testing/index.d.mts +370 -41
  158. package/lib/testing/index.d.mts.map +1 -1
  159. package/lib/testing/index.mjs +568 -305
  160. package/lib/testing/index.mjs.map +1 -1
  161. package/package.json +2 -1
  162. package/src/__tests__/circular-detector.spec.mts +193 -0
  163. package/src/__tests__/concurrent.spec.mts +368 -0
  164. package/src/__tests__/container.spec.mts +32 -30
  165. package/src/__tests__/di-error.spec.mts +351 -0
  166. package/src/__tests__/e2e.browser.spec.mts +0 -4
  167. package/src/__tests__/e2e.spec.mts +10 -19
  168. package/src/__tests__/event-emitter.spec.mts +232 -109
  169. package/src/__tests__/get-injectors.spec.mts +250 -39
  170. package/src/__tests__/injection-token.spec.mts +293 -349
  171. package/src/__tests__/library-findings.spec.mts +8 -8
  172. package/src/__tests__/registry.spec.mts +358 -210
  173. package/src/__tests__/resolution-context.spec.mts +255 -0
  174. package/src/__tests__/scope-tracker.spec.mts +598 -0
  175. package/src/__tests__/scope-upgrade.spec.mts +808 -0
  176. package/src/__tests__/scoped-container.spec.mts +595 -0
  177. package/src/__tests__/test-container.spec.mts +293 -0
  178. package/src/__tests__/token-resolver.spec.mts +207 -0
  179. package/src/__tests__/unified-storage.spec.mts +535 -0
  180. package/src/__tests__/unit-test-container.spec.mts +405 -0
  181. package/src/__type-tests__/container.spec-d.mts +180 -0
  182. package/src/__type-tests__/factory.spec-d.mts +15 -3
  183. package/src/__type-tests__/inject.spec-d.mts +115 -20
  184. package/src/__type-tests__/injectable.spec-d.mts +69 -52
  185. package/src/__type-tests__/injection-token.spec-d.mts +176 -0
  186. package/src/__type-tests__/scoped-container.spec-d.mts +212 -0
  187. package/src/container/abstract-container.mts +327 -0
  188. package/src/container/container.mts +142 -170
  189. package/src/container/scoped-container.mts +126 -208
  190. package/src/decorators/factory.decorator.mts +16 -11
  191. package/src/decorators/injectable.decorator.mts +20 -16
  192. package/src/enums/index.mts +2 -2
  193. package/src/enums/injectable-scope.enum.mts +1 -0
  194. package/src/enums/injectable-type.enum.mts +1 -0
  195. package/src/errors/di-error.mts +96 -0
  196. package/src/event-emitter.mts +3 -27
  197. package/src/index.mts +6 -153
  198. package/src/interfaces/container.interface.mts +13 -0
  199. package/src/interfaces/factory.interface.mts +1 -1
  200. package/src/interfaces/index.mts +1 -1
  201. package/src/internal/context/async-local-storage.mts +3 -2
  202. package/src/internal/context/async-local-storage.types.mts +1 -0
  203. package/src/internal/context/factory-context.mts +1 -0
  204. package/src/internal/context/index.mts +3 -1
  205. package/src/internal/context/resolution-context.mts +1 -0
  206. package/src/internal/context/service-initialization-context.mts +43 -0
  207. package/src/internal/core/index.mts +5 -4
  208. package/src/internal/core/instance-resolver.mts +460 -302
  209. package/src/internal/core/name-resolver.mts +196 -0
  210. package/src/internal/core/scope-tracker.mts +242 -0
  211. package/src/internal/core/{instantiator.mts → service-initializer.mts} +51 -29
  212. package/src/internal/core/service-invalidator.mts +290 -0
  213. package/src/internal/core/token-resolver.mts +122 -0
  214. package/src/internal/holder/holder-storage.interface.mts +11 -5
  215. package/src/internal/holder/index.mts +2 -5
  216. package/src/internal/holder/instance-holder.mts +1 -3
  217. package/src/internal/holder/unified-storage.mts +245 -0
  218. package/src/internal/index.mts +2 -1
  219. package/src/internal/lifecycle/circular-detector.mts +1 -0
  220. package/src/internal/lifecycle/index.mts +1 -1
  221. package/src/internal/lifecycle/lifecycle-event-bus.mts +1 -0
  222. package/src/internal/stub-factory-class.mts +16 -0
  223. package/src/symbols/injectable-token.mts +3 -1
  224. package/src/testing/index.mts +2 -0
  225. package/src/testing/test-container.mts +546 -85
  226. package/src/testing/types.mts +117 -0
  227. package/src/testing/unit-test-container.mts +509 -0
  228. package/src/token/injection-token.mts +41 -4
  229. package/src/token/registry.mts +75 -9
  230. package/src/utils/default-injectors.mts +16 -0
  231. package/src/utils/get-injectable-token.mts +2 -3
  232. package/src/utils/get-injectors.mts +26 -15
  233. package/src/utils/index.mts +3 -1
  234. package/src/utils/types.mts +1 -0
  235. package/tsdown.config.mts +11 -1
  236. package/lib/browser/index.d.mts.map +0 -1
  237. package/lib/browser/index.mjs.map +0 -1
  238. package/lib/container-Bp1W-pWJ.d.mts.map +0 -1
  239. package/lib/container-DAKOvAgr.mjs.map +0 -1
  240. package/lib/container-DENMeJ87.cjs.map +0 -1
  241. package/lib/container-YPwvmlK2.d.cts.map +0 -1
  242. package/src/__tests__/async-local-storage.browser.spec.mts +0 -166
  243. package/src/__tests__/async-local-storage.spec.mts +0 -333
  244. package/src/__tests__/errors.spec.mts +0 -87
  245. package/src/__tests__/factory.spec.mts +0 -137
  246. package/src/__tests__/injectable.spec.mts +0 -246
  247. package/src/__tests__/request-scope.spec.mts +0 -416
  248. package/src/__tests__/service-instantiator.spec.mts +0 -410
  249. package/src/__tests__/service-locator-event-bus.spec.mts +0 -242
  250. package/src/__tests__/service-locator-manager.spec.mts +0 -300
  251. package/src/__tests__/service-locator.spec.mts +0 -966
  252. package/src/__tests__/unified-api.spec.mts +0 -130
  253. package/src/browser.mts +0 -11
  254. package/src/injectors.mts +0 -18
  255. package/src/internal/context/request-context.mts +0 -225
  256. package/src/internal/core/invalidator.mts +0 -437
  257. package/src/internal/core/service-locator.mts +0 -202
  258. package/src/internal/core/token-processor.mts +0 -252
  259. package/src/internal/holder/base-holder-manager.mts +0 -334
  260. package/src/internal/holder/holder-manager.mts +0 -85
  261. package/src/internal/holder/request-storage.mts +0 -127
  262. package/src/internal/holder/singleton-storage.mts +0 -92
  263. package/src/testing/README.md +0 -80
  264. package/src/testing/__tests__/test-container.spec.mts +0 -173
@@ -1,410 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest'
2
-
3
- import type { FactoryContext } from '../internal/context/factory-context.mjs'
4
- import type { FactoryRecord } from '../token/registry.mjs'
5
- import type { Injectors } from '../utils/get-injectors.mjs'
6
-
7
- import { InjectableScope, InjectableType } from '../enums/index.mjs'
8
- import { DIError } from '../errors/index.mjs'
9
- import { Instantiator } from '../internal/core/instantiator.mjs'
10
- import { InjectionToken } from '../token/injection-token.mjs'
11
-
12
- // Mock classes for testing
13
- class TestService {
14
- constructor(public name: string = 'default') {}
15
- }
16
-
17
- class TestServiceWithLifecycle {
18
- public initCalled = false
19
- public destroyCalled = false
20
-
21
- async onServiceInit() {
22
- this.initCalled = true
23
- }
24
-
25
- async onServiceDestroy() {
26
- this.destroyCalled = true
27
- }
28
- }
29
-
30
- class TestFactory {
31
- async create(ctx: FactoryContext, args?: any) {
32
- return { factoryResult: args?.value || 'default' }
33
- }
34
- }
35
-
36
- class TestFactoryWithoutCreate {
37
- // Missing create method
38
- }
39
-
40
- describe('Instantiator', () => {
41
- let instantiator: Instantiator
42
- let mockInjectors: Injectors
43
- let mockContext: FactoryContext
44
- let mockAddDestroyListener: ReturnType<typeof vi.fn>
45
-
46
- beforeEach(() => {
47
- mockAddDestroyListener = vi.fn()
48
-
49
- mockInjectors = {
50
- wrapSyncInit: vi.fn((fn) => {
51
- // Simple mock implementation that just calls the function
52
- return () => [fn(), [], null]
53
- }),
54
- provideFactoryContext: vi.fn((ctx) => ctx),
55
- } as any
56
-
57
- mockContext = {
58
- inject: vi.fn(),
59
- locator: {} as any,
60
- // @ts-expect-error Test
61
- addDestroyListener: mockAddDestroyListener,
62
- }
63
-
64
- instantiator = new Instantiator(mockInjectors)
65
- })
66
-
67
- function createFactoryRecord<T>(
68
- target: any,
69
- type: InjectableType,
70
- scope: InjectableScope = InjectableScope.Singleton,
71
- ): FactoryRecord<T, any> {
72
- const token = new InjectionToken<T, any>('test-token', undefined)
73
- return {
74
- type,
75
- target,
76
- scope,
77
- originalToken: token,
78
- }
79
- }
80
-
81
- describe('instantiateService', () => {
82
- it('should instantiate class-based service', async () => {
83
- const record = createFactoryRecord<TestService>(
84
- TestService,
85
- InjectableType.Class,
86
- )
87
-
88
- const result = await instantiator.instantiateService(
89
- mockContext,
90
- record,
91
- 'test-name',
92
- )
93
-
94
- expect(result).toHaveLength(2)
95
- expect(result[0]).toBeUndefined()
96
- expect(result[1]).toBeInstanceOf(TestService)
97
- expect((result[1] as TestService).name).toBe('test-name')
98
- })
99
-
100
- it('should instantiate factory-based service', async () => {
101
- const record: FactoryRecord<any, any> = {
102
- type: InjectableType.Factory,
103
- target: TestFactory,
104
- scope: InjectableScope.Singleton,
105
- originalToken: 'test' as any,
106
- }
107
-
108
- const result = await instantiator.instantiateService(
109
- mockContext,
110
- record,
111
- { value: 'test' },
112
- )
113
-
114
- expect(result).toHaveLength(2)
115
- expect(result[0]).toBeUndefined()
116
- expect(result[1]).toEqual({ factoryResult: 'test' })
117
- })
118
-
119
- it('should handle unknown service type', async () => {
120
- const record: FactoryRecord<any, any> = {
121
- type: 'Unknown' as any,
122
- target: TestService,
123
- scope: InjectableScope.Singleton,
124
- originalToken: 'test' as any,
125
- }
126
-
127
- const result = await instantiator.instantiateService(mockContext, record)
128
-
129
- expect(result).toHaveLength(1)
130
- expect(result[0]).toBeInstanceOf(DIError)
131
- expect(result[0]!.message).toContain('Unknown service type: Unknown')
132
- })
133
-
134
- it('should handle errors during instantiation', async () => {
135
- const ThrowingService = class {
136
- constructor() {
137
- throw new Error('Constructor error')
138
- }
139
- }
140
-
141
- const record: FactoryRecord<any, any> = {
142
- type: InjectableType.Class,
143
- target: ThrowingService,
144
- scope: InjectableScope.Singleton,
145
- originalToken: 'test' as any,
146
- }
147
-
148
- const result = await instantiator.instantiateService(mockContext, record)
149
-
150
- expect(result).toHaveLength(1)
151
- expect(result[0]).toBeInstanceOf(DIError)
152
- expect(result[0]!.message).toBe('Error: Constructor error')
153
- })
154
- })
155
-
156
- describe('instantiateClass', () => {
157
- it('should handle class with no arguments', async () => {
158
- const record: FactoryRecord<TestService, any> = {
159
- type: InjectableType.Class,
160
- target: TestService,
161
- scope: InjectableScope.Singleton,
162
- originalToken: 'test' as any,
163
- }
164
-
165
- const result = await instantiator.instantiateService(mockContext, record)
166
-
167
- expect(result).toHaveLength(2)
168
- expect(result[0]).toBeUndefined()
169
- expect(result[1]).toBeInstanceOf(TestService)
170
- expect((result[1] as TestService).name).toBe('default')
171
- })
172
-
173
- it('should handle class with lifecycle hooks', async () => {
174
- const record: FactoryRecord<TestServiceWithLifecycle, any> = {
175
- type: InjectableType.Class,
176
- target: TestServiceWithLifecycle,
177
- scope: InjectableScope.Singleton,
178
- originalToken: 'test' as any,
179
- }
180
-
181
- const result = await instantiator.instantiateService(mockContext, record)
182
-
183
- expect(result).toHaveLength(2)
184
- expect(result[0]).toBeUndefined()
185
-
186
- const instance = result[1] as TestServiceWithLifecycle
187
- expect(instance.initCalled).toBe(true)
188
- expect(mockAddDestroyListener).toHaveBeenCalled()
189
-
190
- // Test destroy listener
191
- const destroyListener = mockAddDestroyListener.mock.calls[0][0]
192
- await destroyListener()
193
- expect(instance.destroyCalled).toBe(true)
194
- })
195
-
196
- it('should handle wrapSyncInit with promises', async () => {
197
- // Mock wrapSyncInit to simulate async dependencies
198
- // @ts-expect-error Test
199
- mockInjectors.wrapSyncInit = vi.fn((fn) => {
200
- return (injectState?: any) => {
201
- if (!injectState) {
202
- // First call - return promises
203
- return [fn(), [Promise.resolve('async-dep')], 'inject-state']
204
- } else {
205
- // Second call - no more promises
206
- return [fn(), [], null]
207
- }
208
- }
209
- })
210
-
211
- const record: FactoryRecord<TestService, any> = {
212
- type: InjectableType.Class,
213
- target: TestService,
214
- scope: InjectableScope.Singleton,
215
- originalToken: 'test' as any,
216
- }
217
-
218
- const result = await instantiator.instantiateService(mockContext, record)
219
-
220
- expect(result).toHaveLength(2)
221
- expect(result[0]).toBeUndefined()
222
- expect(result[1]).toBeInstanceOf(TestService)
223
- })
224
-
225
- it('should handle failed async dependencies', async () => {
226
- // @ts-expect-error Test
227
- mockInjectors.wrapSyncInit = vi.fn((fn) => {
228
- return () => [fn(), [Promise.reject(new Error('Async error'))], null]
229
- })
230
-
231
- const record: FactoryRecord<TestService, any> = {
232
- type: InjectableType.Class,
233
- target: TestService,
234
- scope: InjectableScope.Singleton,
235
- originalToken: 'test' as any,
236
- }
237
-
238
- const result = await instantiator.instantiateService(mockContext, record)
239
-
240
- expect(result).toHaveLength(1)
241
- expect(result[0]).toBeInstanceOf(DIError)
242
- expect(result[0]!.message).toContain('cannot be instantiated')
243
- })
244
-
245
- it('should handle persistent promises after retry', async () => {
246
- let callCount = 0
247
- // Always return promises to simulate problematic definition
248
- // @ts-expect-error Test
249
- mockInjectors.wrapSyncInit = vi.fn((fn) => {
250
- return (injectState?: any) => {
251
- callCount++
252
- // Always return promises to simulate problematic definition
253
- return [fn(), [Promise.resolve('persistent-promise')], 'state']
254
- }
255
- })
256
-
257
- // Mock console.error to capture the warning
258
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
259
-
260
- const record: FactoryRecord<TestService, any> = {
261
- type: InjectableType.Class,
262
- target: TestService,
263
- scope: InjectableScope.Singleton,
264
- originalToken: 'test' as any,
265
- }
266
-
267
- const result = await instantiator.instantiateService(mockContext, record)
268
-
269
- expect(result).toHaveLength(1)
270
- expect(result[0]).toBeInstanceOf(DIError)
271
- expect(result[0]!.message).toContain('cannot be instantiated')
272
- expect(consoleSpy).toHaveBeenCalledWith(
273
- expect.stringContaining("has problem with it's definition"),
274
- )
275
-
276
- consoleSpy.mockRestore()
277
- })
278
- })
279
-
280
- describe('instantiateFactory', () => {
281
- it('should handle factory with no arguments', async () => {
282
- const record: FactoryRecord<any, any> = {
283
- type: InjectableType.Factory,
284
- target: TestFactory,
285
- scope: InjectableScope.Singleton,
286
- originalToken: 'test' as any,
287
- }
288
-
289
- const result = await instantiator.instantiateService(mockContext, record)
290
-
291
- expect(result).toHaveLength(2)
292
- expect(result[0]).toBeUndefined()
293
- expect(result[1]).toEqual({ factoryResult: 'default' })
294
- })
295
-
296
- it('should handle factory without create method', async () => {
297
- const record: FactoryRecord<any, any> = {
298
- type: InjectableType.Factory,
299
- target: TestFactoryWithoutCreate,
300
- scope: InjectableScope.Singleton,
301
- originalToken: 'test' as any,
302
- }
303
-
304
- const result = await instantiator.instantiateService(mockContext, record)
305
-
306
- expect(result).toHaveLength(1)
307
- expect(result[0]).toBeInstanceOf(DIError)
308
- expect(result[0]!.message).toContain(
309
- 'does not implement the create method',
310
- )
311
- })
312
-
313
- it('should handle factory with promises', async () => {
314
- // @ts-expect-error Test
315
- mockInjectors.wrapSyncInit = vi.fn((fn) => {
316
- return (injectState?: any) => {
317
- if (!injectState) {
318
- return [fn(), [Promise.resolve('async-dep')], 'inject-state']
319
- } else {
320
- return [fn(), [], null]
321
- }
322
- }
323
- })
324
-
325
- const record: FactoryRecord<any, any> = {
326
- type: InjectableType.Factory,
327
- target: TestFactory,
328
- scope: InjectableScope.Singleton,
329
- originalToken: 'test' as any,
330
- }
331
-
332
- const result = await instantiator.instantiateService(mockContext, record)
333
-
334
- expect(result).toHaveLength(2)
335
- expect(result[0]).toBeUndefined()
336
- expect(result[1]).toEqual({ factoryResult: 'default' })
337
- })
338
-
339
- it('should handle failed async dependencies in factory', async () => {
340
- // @ts-expect-error Test
341
- mockInjectors.wrapSyncInit = vi.fn((fn) => {
342
- return () => [
343
- fn(),
344
- [Promise.reject(new Error('Factory async error'))],
345
- null,
346
- ]
347
- })
348
-
349
- const record: FactoryRecord<any, any> = {
350
- type: InjectableType.Factory,
351
- target: TestFactory,
352
- scope: InjectableScope.Singleton,
353
- originalToken: 'test' as any,
354
- }
355
-
356
- const result = await instantiator.instantiateService(mockContext, record)
357
-
358
- expect(result).toHaveLength(1)
359
- expect(result[0]).toBeInstanceOf(DIError)
360
- expect(result[0]!.message).toContain('cannot be instantiated')
361
- })
362
-
363
- it('should handle persistent promises in factory', async () => {
364
- // @ts-expect-error
365
- mockInjectors.wrapSyncInit = vi.fn((fn) => {
366
- return () => [fn(), [Promise.resolve('persistent')], 'state']
367
- })
368
-
369
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
370
-
371
- const record: FactoryRecord<any, any> = {
372
- type: InjectableType.Factory,
373
- target: TestFactory,
374
- scope: InjectableScope.Singleton,
375
- originalToken: 'test' as any,
376
- }
377
-
378
- const result = await instantiator.instantiateService(mockContext, record)
379
-
380
- expect(result).toHaveLength(1)
381
- expect(result[0]).toBeInstanceOf(DIError)
382
- expect(consoleSpy).toHaveBeenCalledWith(
383
- expect.stringContaining('asyncInject instead of inject'),
384
- )
385
-
386
- consoleSpy.mockRestore()
387
- })
388
-
389
- it('should handle factory create method that throws', async () => {
390
- class ThrowingFactory {
391
- async create() {
392
- throw new Error('Factory create error')
393
- }
394
- }
395
-
396
- const record: FactoryRecord<any, any> = {
397
- type: InjectableType.Factory,
398
- target: ThrowingFactory,
399
- scope: InjectableScope.Singleton,
400
- originalToken: 'test' as any,
401
- }
402
-
403
- const result = await instantiator.instantiateService(mockContext, record)
404
-
405
- expect(result).toHaveLength(1)
406
- expect(result[0]).toBeInstanceOf(DIError)
407
- expect(result[0]!.message).toBe('Error: Factory create error')
408
- })
409
- })
410
- })
@@ -1,242 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest'
2
-
3
- import { LifecycleEventBus } from '../internal/lifecycle/lifecycle-event-bus.mjs'
4
-
5
- describe('LifecycleEventBus', () => {
6
- let eventBus: LifecycleEventBus
7
- let mockLogger: Console
8
-
9
- beforeEach(() => {
10
- mockLogger = {
11
- debug: vi.fn(),
12
- warn: vi.fn(),
13
- } as any as Console
14
- eventBus = new LifecycleEventBus(mockLogger)
15
- })
16
-
17
- describe('constructor', () => {
18
- it('should create event bus without logger', () => {
19
- const eventBusWithoutLogger = new LifecycleEventBus()
20
- expect(eventBusWithoutLogger).toBeDefined()
21
- })
22
-
23
- it('should create event bus with logger', () => {
24
- expect(eventBus).toBeDefined()
25
- })
26
- })
27
-
28
- describe('on', () => {
29
- it('should register event listener', () => {
30
- const listener = vi.fn()
31
-
32
- eventBus.on('test-ns', 'create', listener)
33
-
34
- expect(mockLogger.debug).toHaveBeenCalledWith(
35
- '[LifecycleEventBus]#on(): ns:test-ns event:create',
36
- )
37
- })
38
-
39
- it('should register multiple listeners for same namespace and event', () => {
40
- const listener1 = vi.fn()
41
- const listener2 = vi.fn()
42
-
43
- eventBus.on('test-ns', 'create', listener1)
44
- eventBus.on('test-ns', 'create', listener2)
45
-
46
- expect(mockLogger.debug).toHaveBeenCalledTimes(2)
47
- })
48
-
49
- it('should register listeners for different events in same namespace', () => {
50
- const listener1 = vi.fn()
51
- const listener2 = vi.fn()
52
-
53
- eventBus.on('test-ns', 'create', listener1)
54
- eventBus.on('test-ns', 'destroy', listener2)
55
-
56
- expect(mockLogger.debug).toHaveBeenCalledWith(
57
- '[LifecycleEventBus]#on(): ns:test-ns event:create',
58
- )
59
- expect(mockLogger.debug).toHaveBeenCalledWith(
60
- '[LifecycleEventBus]#on(): ns:test-ns event:destroy',
61
- )
62
- })
63
-
64
- it('should return unsubscribe function', async () => {
65
- const listener = vi.fn()
66
-
67
- const unsubscribe = eventBus.on('test-ns', 'create', listener)
68
- await eventBus.emit('test-ns', 'create')
69
-
70
- expect(listener).toHaveBeenCalledWith('create')
71
-
72
- unsubscribe()
73
- await eventBus.emit('test-ns', 'create')
74
-
75
- // Should only be called once (before unsubscribe)
76
- expect(listener).toHaveBeenCalledTimes(1)
77
- })
78
- })
79
-
80
- describe('emit', () => {
81
- it('should emit event to registered listeners', async () => {
82
- const listener = vi.fn()
83
-
84
- eventBus.on('test-ns', 'create', listener)
85
- await eventBus.emit('test-ns', 'create')
86
-
87
- expect(listener).toHaveBeenCalledWith('create')
88
- expect(mockLogger.debug).toHaveBeenCalledWith(
89
- '[LifecycleEventBus]#emit(): test-ns:create',
90
- )
91
- })
92
-
93
- it('should emit event to multiple listeners', async () => {
94
- const listener1 = vi.fn()
95
- const listener2 = vi.fn()
96
-
97
- eventBus.on('test-ns', 'create', listener1)
98
- eventBus.on('test-ns', 'create', listener2)
99
- await eventBus.emit('test-ns', 'create')
100
-
101
- expect(listener1).toHaveBeenCalledWith('create')
102
- expect(listener2).toHaveBeenCalledWith('create')
103
- })
104
-
105
- it('should handle emit for non-existent namespace', async () => {
106
- await expect(
107
- eventBus.emit('non-existent-ns', 'create'),
108
- ).resolves.not.toThrow()
109
- })
110
-
111
- it('should handle emit for non-existent event in existing namespace', async () => {
112
- const listener = vi.fn()
113
-
114
- eventBus.on('test-ns', 'create', listener)
115
- await eventBus.emit('test-ns', 'destroy') // Different event
116
-
117
- expect(listener).not.toHaveBeenCalled()
118
- })
119
-
120
- it('should handle async listeners', async () => {
121
- const asyncListener = vi.fn().mockResolvedValue('async result')
122
-
123
- eventBus.on('test-ns', 'create', asyncListener)
124
- await eventBus.emit('test-ns', 'create')
125
-
126
- expect(asyncListener).toHaveBeenCalledWith('create')
127
- })
128
-
129
- it('should handle listeners that throw errors and warn about them', async () => {
130
- const throwingListener = vi.fn().mockImplementation(() => {
131
- throw new Error('Listener error')
132
- })
133
- const goodListener = vi.fn()
134
-
135
- eventBus.on('test-ns', 'create', throwingListener)
136
- eventBus.on('test-ns', 'create', goodListener)
137
-
138
- // Let's test what actually happens - the implementation appears to be buggy
139
- // It should use Promise.allSettled to handle errors but seems to throw directly
140
- await expect(eventBus.emit('test-ns', 'create')).rejects.toThrow(
141
- 'Listener error',
142
- )
143
-
144
- // Due to the synchronous error, the second listener may not be called
145
- expect(throwingListener).toHaveBeenCalledWith('create')
146
- // The good listener might not be called if error is thrown synchronously
147
- // This seems to be a bug in the implementation
148
- })
149
-
150
- it('should handle promises from async listeners', async () => {
151
- const asyncListener1 = vi.fn().mockResolvedValue('result1')
152
- const asyncListener2 = vi.fn().mockResolvedValue('result2')
153
-
154
- eventBus.on('test-ns', 'create', asyncListener1)
155
- eventBus.on('test-ns', 'create', asyncListener2)
156
-
157
- const results = await eventBus.emit('test-ns', 'create')
158
-
159
- expect(asyncListener1).toHaveBeenCalledWith('create')
160
- expect(asyncListener2).toHaveBeenCalledWith('create')
161
- expect(results).toHaveLength(2)
162
- })
163
- })
164
-
165
- describe('unsubscribe functionality', () => {
166
- it('should remove specific listener when unsubscribe is called', async () => {
167
- const listener1 = vi.fn()
168
- const listener2 = vi.fn()
169
-
170
- const unsubscribe1 = eventBus.on('test-ns', 'create', listener1)
171
- eventBus.on('test-ns', 'create', listener2)
172
-
173
- unsubscribe1()
174
-
175
- await eventBus.emit('test-ns', 'create')
176
-
177
- expect(listener1).not.toHaveBeenCalled()
178
- expect(listener2).toHaveBeenCalledWith('create')
179
- })
180
-
181
- it('should clean up empty listener sets after removing all listeners', async () => {
182
- const listener1 = vi.fn()
183
- const listener2 = vi.fn()
184
-
185
- const unsubscribe1 = eventBus.on('test-ns', 'create', listener1)
186
- const unsubscribe2 = eventBus.on('test-ns', 'create', listener2)
187
-
188
- unsubscribe1()
189
- unsubscribe2()
190
-
191
- // After removing all listeners, emitting should not call anything
192
- await eventBus.emit('test-ns', 'create')
193
-
194
- expect(listener1).not.toHaveBeenCalled()
195
- expect(listener2).not.toHaveBeenCalled()
196
- })
197
- })
198
-
199
- describe('complex scenarios', () => {
200
- it('should handle multiple namespaces', async () => {
201
- const listener1 = vi.fn()
202
- const listener2 = vi.fn()
203
-
204
- eventBus.on('ns1', 'create', listener1)
205
- eventBus.on('ns2', 'create', listener2)
206
-
207
- await eventBus.emit('ns1', 'create')
208
- await eventBus.emit('ns2', 'create')
209
-
210
- expect(listener1).toHaveBeenCalledWith('create')
211
- expect(listener2).toHaveBeenCalledWith('create')
212
- })
213
-
214
- it('should handle multiple events in same namespace', async () => {
215
- const createListener = vi.fn()
216
- const destroyListener = vi.fn()
217
-
218
- eventBus.on('test-ns', 'create', createListener)
219
- eventBus.on('test-ns', 'destroy', destroyListener)
220
-
221
- await eventBus.emit('test-ns', 'create')
222
- await eventBus.emit('test-ns', 'destroy')
223
-
224
- expect(createListener).toHaveBeenCalledWith('create')
225
- expect(destroyListener).toHaveBeenCalledWith('destroy')
226
- })
227
-
228
- it('should handle prefixed events', async () => {
229
- const preListener = vi.fn()
230
- const postListener = vi.fn()
231
-
232
- eventBus.on('test-ns', 'pre:action', preListener)
233
- eventBus.on('test-ns', 'post:action', postListener)
234
-
235
- await eventBus.emit('test-ns', 'pre:action')
236
- await eventBus.emit('test-ns', 'post:action')
237
-
238
- expect(preListener).toHaveBeenCalledWith('pre:action')
239
- expect(postListener).toHaveBeenCalledWith('post:action')
240
- })
241
- })
242
- })