@navios/di 0.7.1 → 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 (263) hide show
  1. package/CHANGELOG.md +110 -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 -1508
  40. package/lib/browser/index.mjs +29 -2650
  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-Pb_Y4Z4x.mjs → container-8-z89TyQ.mjs} +1269 -1305
  138. package/lib/container-8-z89TyQ.mjs.map +1 -0
  139. package/lib/{container-BuAutHGg.d.mts → container-CNiqesCL.d.mts} +600 -569
  140. package/lib/container-CNiqesCL.d.mts.map +1 -0
  141. package/lib/{container-DnzgpfBe.cjs → container-CaY2fDuk.cjs} +1287 -1329
  142. package/lib/container-CaY2fDuk.cjs.map +1 -0
  143. package/lib/{container-oGTgX2iX.d.cts → container-D-0Ho3qL.d.cts} +601 -565
  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 +461 -292
  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-processor.mts → token-resolver.mts} +17 -88
  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-BuAutHGg.d.mts.map +0 -1
  239. package/lib/container-DnzgpfBe.cjs.map +0 -1
  240. package/lib/container-Pb_Y4Z4x.mjs.map +0 -1
  241. package/lib/container-oGTgX2iX.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 -214
  256. package/src/internal/core/invalidator.mts +0 -437
  257. package/src/internal/core/service-locator.mts +0 -202
  258. package/src/internal/holder/base-holder-manager.mts +0 -238
  259. package/src/internal/holder/holder-manager.mts +0 -85
  260. package/src/internal/holder/request-storage.mts +0 -134
  261. package/src/internal/holder/singleton-storage.mts +0 -105
  262. package/src/testing/README.md +0 -80
  263. package/src/testing/__tests__/test-container.spec.mts +0 -173
@@ -1,166 +0,0 @@
1
- /**
2
- * Browser environment tests for AsyncLocalStorage.
3
- *
4
- * These tests verify that:
5
- * 1. The SyncLocalStorage polyfill works correctly
6
- * 2. All DI functionality works correctly with the polyfill
7
- * 3. The resolution context pattern works for synchronous operations
8
- *
9
- * Note: We directly import the browser implementation to test it
10
- * in isolation, simulating how it would work in a browser bundle.
11
- */
12
-
13
- import { describe, expect, it } from 'vitest'
14
-
15
- import {
16
- createAsyncLocalStorage,
17
- isUsingNativeAsyncLocalStorage,
18
- } from '../internal/context/async-local-storage.browser.mjs'
19
- import {
20
- getCurrentResolutionContext,
21
- withResolutionContext,
22
- } from '../internal/context/resolution-context.mjs'
23
- import { SyncLocalStorage } from '../internal/context/sync-local-storage.mjs'
24
-
25
- // ============================================================================
26
- // SECTION 1: Environment Detection
27
- // ============================================================================
28
-
29
- describe('Browser Environment Detection', () => {
30
- it('should use sync polyfill in browser build', () => {
31
- expect(isUsingNativeAsyncLocalStorage()).toBe(false)
32
- })
33
-
34
- it('should create a SyncLocalStorage instance', () => {
35
- const storage = createAsyncLocalStorage<{ value: number }>()
36
- expect(storage).toBeInstanceOf(SyncLocalStorage)
37
- })
38
-
39
- it('should create a working storage instance', () => {
40
- const storage = createAsyncLocalStorage<{ value: number }>()
41
- expect(storage).toBeDefined()
42
- expect(typeof storage.run).toBe('function')
43
- expect(typeof storage.getStore).toBe('function')
44
- })
45
-
46
- it('should create a resolution context instance', () => {
47
- const resolutionContext = getCurrentResolutionContext()
48
- expect(resolutionContext).toBeUndefined()
49
- })
50
- })
51
-
52
- // ============================================================================
53
- // SECTION 2: SyncLocalStorage Behavior in Browser
54
- // ============================================================================
55
-
56
- describe('SyncLocalStorage in Browser', () => {
57
- it('should store and retrieve context synchronously', () => {
58
- const storage = createAsyncLocalStorage<{ name: string }>()
59
-
60
- expect(storage.getStore()).toBeUndefined()
61
-
62
- storage.run({ name: 'test' }, () => {
63
- expect(storage.getStore()?.name).toBe('test')
64
- })
65
-
66
- expect(storage.getStore()).toBeUndefined()
67
- })
68
-
69
- it('should handle nested contexts', () => {
70
- const storage = createAsyncLocalStorage<{ depth: number }>()
71
-
72
- storage.run({ depth: 1 }, () => {
73
- expect(storage.getStore()?.depth).toBe(1)
74
-
75
- storage.run({ depth: 2 }, () => {
76
- expect(storage.getStore()?.depth).toBe(2)
77
-
78
- storage.run({ depth: 3 }, () => {
79
- expect(storage.getStore()?.depth).toBe(3)
80
- })
81
-
82
- expect(storage.getStore()?.depth).toBe(2)
83
- })
84
-
85
- expect(storage.getStore()?.depth).toBe(1)
86
- })
87
-
88
- expect(storage.getStore()).toBeUndefined()
89
- })
90
-
91
- it('should restore context after exceptions', () => {
92
- const storage = createAsyncLocalStorage<{ value: number }>()
93
-
94
- storage.run({ value: 1 }, () => {
95
- try {
96
- storage.run({ value: 2 }, () => {
97
- throw new Error('test error')
98
- })
99
- } catch {
100
- // Expected
101
- }
102
-
103
- // Should be back to outer context
104
- expect(storage.getStore()?.value).toBe(1)
105
- })
106
- })
107
- })
108
-
109
- // ============================================================================
110
- // SECTION 3: Async Limitations in Browser
111
- // ============================================================================
112
-
113
- describe('Async Limitations in Browser (expected behavior)', () => {
114
- it('should NOT propagate context across microtasks', async () => {
115
- const storage = createAsyncLocalStorage<{ value: number }>()
116
-
117
- let valueInMicrotask: number | undefined
118
-
119
- storage.run({ value: 42 }, () => {
120
- // Queue a microtask
121
- Promise.resolve().then(() => {
122
- // In browser with SyncLocalStorage, context is lost
123
- valueInMicrotask = storage.getStore()?.value
124
- })
125
- })
126
-
127
- // Wait for microtask to complete
128
- await Promise.resolve()
129
- await Promise.resolve()
130
-
131
- // Context should be undefined because SyncLocalStorage doesn't propagate
132
- expect(valueInMicrotask).toBeUndefined()
133
- })
134
-
135
- it('should NOT propagate context across setTimeout', async () => {
136
- const storage = createAsyncLocalStorage<{ value: number }>()
137
-
138
- const valuePromise = new Promise<number | undefined>((resolve) => {
139
- storage.run({ value: 42 }, () => {
140
- setTimeout(() => {
141
- resolve(storage.getStore()?.value)
142
- }, 0)
143
- })
144
- })
145
-
146
- const value = await valuePromise
147
- // Context should be undefined
148
- expect(value).toBeUndefined()
149
- })
150
-
151
- it('should still work for synchronous code in async functions', () => {
152
- const storage = createAsyncLocalStorage<{ value: number }>()
153
-
154
- // This is the key behavior: even in browser, synchronous access works
155
- storage.run({ value: 42 }, () => {
156
- // Synchronous access within the run callback works
157
- expect(storage.getStore()?.value).toBe(42)
158
-
159
- // Nested synchronous calls work
160
- function nestedCall() {
161
- return storage.getStore()?.value
162
- }
163
- expect(nestedCall()).toBe(42)
164
- })
165
- })
166
- })
@@ -1,333 +0,0 @@
1
- /**
2
- * Tests for the cross-platform AsyncLocalStorage implementation.
3
- *
4
- * These tests verify:
5
- * 1. SyncLocalStorage polyfill works correctly for synchronous code
6
- * 2. The runtime detection correctly identifies the environment
7
- * 3. Both implementations provide consistent behavior for sync use cases
8
- */
9
-
10
- import { describe, expect, it } from 'vitest'
11
-
12
- import { SyncLocalStorage } from '../internal/context/sync-local-storage.mjs'
13
- import {
14
- createAsyncLocalStorage,
15
- isUsingNativeAsyncLocalStorage,
16
- } from '../internal/context/async-local-storage.mjs'
17
-
18
- // ============================================================================
19
- // SECTION 1: SyncLocalStorage Unit Tests
20
- // ============================================================================
21
-
22
- describe('SyncLocalStorage', () => {
23
- it('should return undefined when no context is active', () => {
24
- const storage = new SyncLocalStorage<{ value: number }>()
25
- expect(storage.getStore()).toBeUndefined()
26
- })
27
-
28
- it('should return the store within a run() call', () => {
29
- const storage = new SyncLocalStorage<{ value: number }>()
30
- const store = { value: 42 }
31
-
32
- storage.run(store, () => {
33
- expect(storage.getStore()).toBe(store)
34
- })
35
- })
36
-
37
- it('should return undefined after run() completes', () => {
38
- const storage = new SyncLocalStorage<{ value: number }>()
39
- const store = { value: 42 }
40
-
41
- storage.run(store, () => {
42
- // Inside context
43
- })
44
-
45
- expect(storage.getStore()).toBeUndefined()
46
- })
47
-
48
- it('should handle nested run() calls correctly', () => {
49
- const storage = new SyncLocalStorage<{ value: number }>()
50
- const outer = { value: 1 }
51
- const inner = { value: 2 }
52
-
53
- storage.run(outer, () => {
54
- expect(storage.getStore()).toBe(outer)
55
-
56
- storage.run(inner, () => {
57
- expect(storage.getStore()).toBe(inner)
58
- })
59
-
60
- // After inner run completes, should be back to outer
61
- expect(storage.getStore()).toBe(outer)
62
- })
63
-
64
- // After all runs complete
65
- expect(storage.getStore()).toBeUndefined()
66
- })
67
-
68
- it('should handle deeply nested run() calls', () => {
69
- const storage = new SyncLocalStorage<{ depth: number }>()
70
- const stores = Array.from({ length: 5 }, (_, i) => ({ depth: i }))
71
-
72
- function nest(depth: number): void {
73
- if (depth >= stores.length) return
74
-
75
- storage.run(stores[depth], () => {
76
- expect(storage.getStore()).toBe(stores[depth])
77
- nest(depth + 1)
78
- expect(storage.getStore()).toBe(stores[depth])
79
- })
80
- }
81
-
82
- nest(0)
83
- expect(storage.getStore()).toBeUndefined()
84
- })
85
-
86
- it('should return the value from run()', () => {
87
- const storage = new SyncLocalStorage<{ value: number }>()
88
- const store = { value: 42 }
89
-
90
- const result = storage.run(store, () => {
91
- return 'hello'
92
- })
93
-
94
- expect(result).toBe('hello')
95
- })
96
-
97
- it('should propagate errors and still restore context', () => {
98
- const storage = new SyncLocalStorage<{ value: number }>()
99
- const store = { value: 42 }
100
-
101
- expect(() => {
102
- storage.run(store, () => {
103
- throw new Error('test error')
104
- })
105
- }).toThrow('test error')
106
-
107
- // Context should be restored even after error
108
- expect(storage.getStore()).toBeUndefined()
109
- })
110
-
111
- it('should restore context after error in nested run()', () => {
112
- const storage = new SyncLocalStorage<{ value: number }>()
113
- const outer = { value: 1 }
114
- const inner = { value: 2 }
115
-
116
- storage.run(outer, () => {
117
- try {
118
- storage.run(inner, () => {
119
- throw new Error('inner error')
120
- })
121
- } catch {
122
- // Catch the error
123
- }
124
-
125
- // Should be back to outer context
126
- expect(storage.getStore()).toBe(outer)
127
- })
128
- })
129
-
130
- it('exit() should clear the context temporarily', () => {
131
- const storage = new SyncLocalStorage<{ value: number }>()
132
- const store = { value: 42 }
133
-
134
- storage.run(store, () => {
135
- expect(storage.getStore()).toBe(store)
136
-
137
- storage.exit(() => {
138
- expect(storage.getStore()).toBeUndefined()
139
- })
140
-
141
- // After exit, should be back to the original context
142
- expect(storage.getStore()).toBe(store)
143
- })
144
- })
145
-
146
- it('exit() should restore context after error', () => {
147
- const storage = new SyncLocalStorage<{ value: number }>()
148
- const store = { value: 42 }
149
-
150
- storage.run(store, () => {
151
- try {
152
- storage.exit(() => {
153
- throw new Error('exit error')
154
- })
155
- } catch {
156
- // Catch the error
157
- }
158
-
159
- // Context should be restored
160
- expect(storage.getStore()).toBe(store)
161
- })
162
- })
163
- })
164
-
165
- // ============================================================================
166
- // SECTION 2: createAsyncLocalStorage Tests
167
- // ============================================================================
168
-
169
- describe('createAsyncLocalStorage', () => {
170
- it('should create a storage instance', () => {
171
- const storage = createAsyncLocalStorage<{ value: number }>()
172
- expect(storage).toBeDefined()
173
- expect(typeof storage.run).toBe('function')
174
- expect(typeof storage.getStore).toBe('function')
175
- })
176
-
177
- it('should work with run() and getStore()', () => {
178
- const storage = createAsyncLocalStorage<{ value: number }>()
179
- const store = { value: 42 }
180
-
181
- storage.run(store, () => {
182
- expect(storage.getStore()).toBe(store)
183
- })
184
-
185
- expect(storage.getStore()).toBeUndefined()
186
- })
187
-
188
- it('should handle nested contexts', () => {
189
- const storage = createAsyncLocalStorage<{ name: string }>()
190
-
191
- storage.run({ name: 'outer' }, () => {
192
- expect(storage.getStore()?.name).toBe('outer')
193
-
194
- storage.run({ name: 'inner' }, () => {
195
- expect(storage.getStore()?.name).toBe('inner')
196
- })
197
-
198
- expect(storage.getStore()?.name).toBe('outer')
199
- })
200
- })
201
- })
202
-
203
- // ============================================================================
204
- // SECTION 3: Environment Detection Tests
205
- // ============================================================================
206
-
207
- describe('isUsingNativeAsyncLocalStorage', () => {
208
- it('should return a boolean', () => {
209
- const result = isUsingNativeAsyncLocalStorage()
210
- expect(typeof result).toBe('boolean')
211
- })
212
-
213
- it('should return true in Node.js environment', () => {
214
- // Since we're running in Node.js (vitest), this should be true
215
- expect(isUsingNativeAsyncLocalStorage()).toBe(true)
216
- })
217
- })
218
-
219
- // ============================================================================
220
- // SECTION 4: Integration with resolution context pattern
221
- // ============================================================================
222
-
223
- describe('Resolution Context Pattern', () => {
224
- interface ResolutionContextData {
225
- waiterName: string
226
- depth: number
227
- }
228
-
229
- it('should work with the resolution context pattern', () => {
230
- const resolutionContext = createAsyncLocalStorage<ResolutionContextData>()
231
-
232
- function withResolutionContext<T>(
233
- waiterName: string,
234
- depth: number,
235
- fn: () => T,
236
- ): T {
237
- return resolutionContext.run({ waiterName, depth }, fn)
238
- }
239
-
240
- function getCurrentContext(): ResolutionContextData | undefined {
241
- return resolutionContext.getStore()
242
- }
243
-
244
- // Simulate nested service resolution
245
- withResolutionContext('ServiceA', 0, () => {
246
- const ctxA = getCurrentContext()
247
- expect(ctxA?.waiterName).toBe('ServiceA')
248
- expect(ctxA?.depth).toBe(0)
249
-
250
- withResolutionContext('ServiceB', 1, () => {
251
- const ctxB = getCurrentContext()
252
- expect(ctxB?.waiterName).toBe('ServiceB')
253
- expect(ctxB?.depth).toBe(1)
254
- })
255
-
256
- // Back to ServiceA context
257
- const ctxAfter = getCurrentContext()
258
- expect(ctxAfter?.waiterName).toBe('ServiceA')
259
- })
260
-
261
- // Outside all contexts
262
- expect(getCurrentContext()).toBeUndefined()
263
- })
264
-
265
- it('should handle withoutResolutionContext pattern', () => {
266
- const resolutionContext = createAsyncLocalStorage<ResolutionContextData>()
267
-
268
- function withoutResolutionContext<T>(fn: () => T): T {
269
- return resolutionContext.run(undefined as any, fn)
270
- }
271
-
272
- resolutionContext.run({ waiterName: 'Service', depth: 0 }, () => {
273
- expect(resolutionContext.getStore()?.waiterName).toBe('Service')
274
-
275
- withoutResolutionContext(() => {
276
- // Context should be cleared (undefined-ish)
277
- const store = resolutionContext.getStore()
278
- expect(store === undefined || store === null).toBe(true)
279
- })
280
-
281
- // Context should be restored
282
- expect(resolutionContext.getStore()?.waiterName).toBe('Service')
283
- })
284
- })
285
- })
286
-
287
- // ============================================================================
288
- // SECTION 5: Async behavior tests (Node.js native only)
289
- // ============================================================================
290
-
291
- describe('Async behavior (native AsyncLocalStorage)', () => {
292
- it('should propagate context through async/await in Node.js', async () => {
293
- // Skip if not using native (though in Node.js vitest, it should be native)
294
- if (!isUsingNativeAsyncLocalStorage()) {
295
- return
296
- }
297
-
298
- const storage = createAsyncLocalStorage<{ value: number }>()
299
- const store = { value: 42 }
300
-
301
- await storage.run(store, async () => {
302
- // Sync check
303
- expect(storage.getStore()).toBe(store)
304
-
305
- // After await
306
- await Promise.resolve()
307
- expect(storage.getStore()).toBe(store)
308
-
309
- // After setTimeout wrapped in promise
310
- await new Promise((resolve) => setTimeout(resolve, 10))
311
- expect(storage.getStore()).toBe(store)
312
- })
313
- })
314
-
315
- it('should propagate context through Promise.all in Node.js', async () => {
316
- if (!isUsingNativeAsyncLocalStorage()) {
317
- return
318
- }
319
-
320
- const storage = createAsyncLocalStorage<{ value: number }>()
321
- const store = { value: 42 }
322
-
323
- await storage.run(store, async () => {
324
- const results = await Promise.all([
325
- Promise.resolve().then(() => storage.getStore()?.value),
326
- Promise.resolve().then(() => storage.getStore()?.value),
327
- Promise.resolve().then(() => storage.getStore()?.value),
328
- ])
329
-
330
- expect(results).toEqual([42, 42, 42])
331
- })
332
- })
333
- })
@@ -1,87 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { DIError, DIErrorCode } from '../errors/index.mjs'
4
-
5
- describe('DIError', () => {
6
- describe('factoryNotFound', () => {
7
- it('should create error with proper message and code', () => {
8
- const error = DIError.factoryNotFound('TestFactory')
9
-
10
- expect(error.message).toBe('Factory TestFactory not found')
11
- expect(error.code).toBe(DIErrorCode.FactoryNotFound)
12
- expect(error.context?.name).toBe('TestFactory')
13
- expect(error).toBeInstanceOf(DIError)
14
- expect(error).toBeInstanceOf(Error)
15
- })
16
-
17
- it('should be throwable', () => {
18
- expect(() => {
19
- throw DIError.factoryNotFound('SomeFactory')
20
- }).toThrow('Factory SomeFactory not found')
21
- })
22
- })
23
-
24
- describe('instanceDestroying', () => {
25
- it('should create error with proper message and code', () => {
26
- const error = DIError.instanceDestroying('TestInstance')
27
-
28
- expect(error.message).toBe('Instance TestInstance destroying')
29
- expect(error.code).toBe(DIErrorCode.InstanceDestroying)
30
- expect(error.context?.name).toBe('TestInstance')
31
- expect(error).toBeInstanceOf(DIError)
32
- expect(error).toBeInstanceOf(Error)
33
- })
34
-
35
- it('should be throwable', () => {
36
- expect(() => {
37
- throw DIError.instanceDestroying('SomeInstance')
38
- }).toThrow('Instance SomeInstance destroying')
39
- })
40
- })
41
-
42
- describe('instanceNotFound', () => {
43
- it('should create error with proper message and code', () => {
44
- const error = DIError.instanceNotFound('TestInstance')
45
-
46
- expect(error.message).toBe('Instance TestInstance not found')
47
- expect(error.code).toBe(DIErrorCode.InstanceNotFound)
48
- expect(error.context?.name).toBe('TestInstance')
49
- expect(error).toBeInstanceOf(DIError)
50
- expect(error).toBeInstanceOf(Error)
51
- })
52
- })
53
-
54
- describe('factoryTokenNotResolved', () => {
55
- it('should create error with proper message and code', () => {
56
- const error = DIError.factoryTokenNotResolved('TestToken')
57
-
58
- expect(error.message).toBe('Factory token not resolved: TestToken')
59
- expect(error.code).toBe(DIErrorCode.FactoryTokenNotResolved)
60
- expect(error.context?.token).toBe('TestToken')
61
- expect(error).toBeInstanceOf(DIError)
62
- expect(error).toBeInstanceOf(Error)
63
- })
64
- })
65
-
66
- describe('unknown', () => {
67
- it('should create error with string message', () => {
68
- const error = DIError.unknown('Test error message')
69
-
70
- expect(error.message).toBe('Test error message')
71
- expect(error.code).toBe(DIErrorCode.UnknownError)
72
- expect(error).toBeInstanceOf(DIError)
73
- expect(error).toBeInstanceOf(Error)
74
- })
75
-
76
- it('should create error with Error object', () => {
77
- const originalError = new Error('Original error')
78
- const error = DIError.unknown(originalError)
79
-
80
- expect(error.message).toBe('Original error')
81
- expect(error.code).toBe(DIErrorCode.UnknownError)
82
- expect(error.context?.parent).toBe(originalError)
83
- expect(error).toBeInstanceOf(DIError)
84
- expect(error).toBeInstanceOf(Error)
85
- })
86
- })
87
- })