@navios/di 0.3.1 → 0.4.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 (96) hide show
  1. package/README.md +67 -6
  2. package/coverage/base.css +224 -0
  3. package/coverage/block-navigation.js +87 -0
  4. package/coverage/clover.xml +2659 -0
  5. package/coverage/coverage-final.json +46 -0
  6. package/coverage/docs/examples/basic-usage.mts.html +376 -0
  7. package/coverage/docs/examples/factory-pattern.mts.html +1039 -0
  8. package/coverage/docs/examples/index.html +176 -0
  9. package/coverage/docs/examples/injection-tokens.mts.html +760 -0
  10. package/coverage/docs/examples/request-scope-example.mts.html +847 -0
  11. package/coverage/docs/examples/service-lifecycle.mts.html +1162 -0
  12. package/coverage/favicon.png +0 -0
  13. package/coverage/index.html +236 -0
  14. package/coverage/lib/_tsup-dts-rollup.d.mts.html +2806 -0
  15. package/coverage/lib/index.d.mts.html +310 -0
  16. package/coverage/lib/index.html +131 -0
  17. package/coverage/prettify.css +1 -0
  18. package/coverage/prettify.js +2 -0
  19. package/coverage/sort-arrow-sprite.png +0 -0
  20. package/coverage/sorter.js +196 -0
  21. package/coverage/src/container.mts.html +586 -0
  22. package/coverage/src/decorators/factory.decorator.mts.html +322 -0
  23. package/coverage/src/decorators/index.html +146 -0
  24. package/coverage/src/decorators/index.mts.html +91 -0
  25. package/coverage/src/decorators/injectable.decorator.mts.html +394 -0
  26. package/coverage/src/enums/index.html +146 -0
  27. package/coverage/src/enums/index.mts.html +91 -0
  28. package/coverage/src/enums/injectable-scope.enum.mts.html +127 -0
  29. package/coverage/src/enums/injectable-type.enum.mts.html +97 -0
  30. package/coverage/src/errors/errors.enum.mts.html +109 -0
  31. package/coverage/src/errors/factory-not-found.mts.html +109 -0
  32. package/coverage/src/errors/factory-token-not-resolved.mts.html +115 -0
  33. package/coverage/src/errors/index.html +221 -0
  34. package/coverage/src/errors/index.mts.html +106 -0
  35. package/coverage/src/errors/instance-destroying.mts.html +109 -0
  36. package/coverage/src/errors/instance-expired.mts.html +109 -0
  37. package/coverage/src/errors/instance-not-found.mts.html +109 -0
  38. package/coverage/src/errors/unknown-error.mts.html +130 -0
  39. package/coverage/src/event-emitter.mts.html +400 -0
  40. package/coverage/src/factory-context.mts.html +109 -0
  41. package/coverage/src/index.html +296 -0
  42. package/coverage/src/index.mts.html +139 -0
  43. package/coverage/src/injection-token.mts.html +571 -0
  44. package/coverage/src/injector.mts.html +133 -0
  45. package/coverage/src/interfaces/factory.interface.mts.html +121 -0
  46. package/coverage/src/interfaces/index.html +161 -0
  47. package/coverage/src/interfaces/index.mts.html +94 -0
  48. package/coverage/src/interfaces/on-service-destroy.interface.mts.html +94 -0
  49. package/coverage/src/interfaces/on-service-init.interface.mts.html +94 -0
  50. package/coverage/src/registry.mts.html +247 -0
  51. package/coverage/src/request-context-holder.mts.html +607 -0
  52. package/coverage/src/service-instantiator.mts.html +559 -0
  53. package/coverage/src/service-locator-event-bus.mts.html +289 -0
  54. package/coverage/src/service-locator-instance-holder.mts.html +307 -0
  55. package/coverage/src/service-locator-manager.mts.html +604 -0
  56. package/coverage/src/service-locator.mts.html +2911 -0
  57. package/coverage/src/symbols/index.html +131 -0
  58. package/coverage/src/symbols/index.mts.html +88 -0
  59. package/coverage/src/symbols/injectable-token.mts.html +88 -0
  60. package/coverage/src/utils/defer.mts.html +304 -0
  61. package/coverage/src/utils/get-injectable-token.mts.html +142 -0
  62. package/coverage/src/utils/get-injectors.mts.html +691 -0
  63. package/coverage/src/utils/index.html +176 -0
  64. package/coverage/src/utils/index.mts.html +97 -0
  65. package/coverage/src/utils/types.mts.html +241 -0
  66. package/docs/README.md +5 -2
  67. package/docs/api-reference.md +38 -0
  68. package/docs/container.md +75 -0
  69. package/docs/getting-started.md +4 -3
  70. package/docs/injectable.md +4 -3
  71. package/docs/migration.md +177 -0
  72. package/docs/request-contexts.md +364 -0
  73. package/lib/_tsup-dts-rollup.d.mts +177 -36
  74. package/lib/_tsup-dts-rollup.d.ts +177 -36
  75. package/lib/index.d.mts +1 -0
  76. package/lib/index.d.ts +1 -0
  77. package/lib/index.js +480 -294
  78. package/lib/index.js.map +1 -1
  79. package/lib/index.mjs +480 -295
  80. package/lib/index.mjs.map +1 -1
  81. package/package.json +1 -1
  82. package/src/__tests__/defer.spec.mts +166 -0
  83. package/src/__tests__/errors.spec.mts +61 -0
  84. package/src/__tests__/event-emitter.spec.mts +163 -0
  85. package/src/__tests__/get-injectors.spec.mts +70 -0
  86. package/src/__tests__/registry.spec.mts +335 -0
  87. package/src/__tests__/request-scope.spec.mts +34 -35
  88. package/src/__tests__/service-instantiator.spec.mts +408 -0
  89. package/src/__tests__/service-locator-event-bus.spec.mts +242 -0
  90. package/src/__tests__/service-locator-manager.spec.mts +370 -0
  91. package/src/__tests__/unified-api.spec.mts +130 -0
  92. package/src/base-instance-holder-manager.mts +175 -0
  93. package/src/index.mts +1 -0
  94. package/src/request-context-holder.mts +73 -44
  95. package/src/service-locator-manager.mts +12 -70
  96. package/src/service-locator.mts +421 -226
@@ -0,0 +1,335 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest'
2
+
3
+ import { InjectableScope, InjectableType } from '../enums/index.mjs'
4
+ import { InjectionToken } from '../injection-token.mjs'
5
+ import { globalRegistry, Registry } from '../registry.mjs'
6
+
7
+ class TestService {}
8
+ class AnotherService {}
9
+
10
+ describe('Registry', () => {
11
+ let registry: Registry
12
+ let token1: InjectionToken<TestService, undefined>
13
+ let token2: InjectionToken<AnotherService, undefined>
14
+
15
+ beforeEach(() => {
16
+ registry = new Registry()
17
+ token1 = new InjectionToken<TestService, undefined>(
18
+ 'TestService',
19
+ undefined,
20
+ )
21
+ token2 = new InjectionToken<AnotherService, undefined>(
22
+ 'AnotherService',
23
+ undefined,
24
+ )
25
+ })
26
+
27
+ describe('constructor', () => {
28
+ it('should create registry without parent', () => {
29
+ const reg = new Registry()
30
+ expect(reg).toBeDefined()
31
+ })
32
+
33
+ it('should create registry with parent', () => {
34
+ const parentRegistry = new Registry()
35
+ const childRegistry = new Registry(parentRegistry)
36
+ expect(childRegistry).toBeDefined()
37
+ })
38
+ })
39
+
40
+ describe('set', () => {
41
+ it('should set factory record for token', () => {
42
+ registry.set(
43
+ token1,
44
+ InjectableScope.Singleton,
45
+ TestService,
46
+ InjectableType.Class,
47
+ )
48
+
49
+ expect(registry.has(token1)).toBe(true)
50
+ })
51
+
52
+ it('should set multiple factory records', () => {
53
+ registry.set(
54
+ token1,
55
+ InjectableScope.Singleton,
56
+ TestService,
57
+ InjectableType.Class,
58
+ )
59
+ registry.set(
60
+ token2,
61
+ InjectableScope.Transient,
62
+ AnotherService,
63
+ InjectableType.Factory,
64
+ )
65
+
66
+ expect(registry.has(token1)).toBe(true)
67
+ expect(registry.has(token2)).toBe(true)
68
+ })
69
+
70
+ it('should overwrite existing factory record', () => {
71
+ registry.set(
72
+ token1,
73
+ InjectableScope.Singleton,
74
+ TestService,
75
+ InjectableType.Class,
76
+ )
77
+ registry.set(
78
+ token1,
79
+ InjectableScope.Transient,
80
+ TestService,
81
+ InjectableType.Factory,
82
+ )
83
+
84
+ const record = registry.get(token1)
85
+ expect(record.scope).toBe(InjectableScope.Transient)
86
+ expect(record.type).toBe(InjectableType.Factory)
87
+ })
88
+ })
89
+
90
+ describe('has', () => {
91
+ it('should return false for non-existent token', () => {
92
+ expect(registry.has(token1)).toBe(false)
93
+ })
94
+
95
+ it('should return true for existing token', () => {
96
+ registry.set(
97
+ token1,
98
+ InjectableScope.Singleton,
99
+ TestService,
100
+ InjectableType.Class,
101
+ )
102
+ expect(registry.has(token1)).toBe(true)
103
+ })
104
+
105
+ it('should check parent registry when token not found locally', () => {
106
+ const parentRegistry = new Registry()
107
+ const childRegistry = new Registry(parentRegistry)
108
+
109
+ parentRegistry.set(
110
+ token1,
111
+ InjectableScope.Singleton,
112
+ TestService,
113
+ InjectableType.Class,
114
+ )
115
+
116
+ expect(childRegistry.has(token1)).toBe(true)
117
+ })
118
+
119
+ it('should return false when token not found in parent chain', () => {
120
+ const parentRegistry = new Registry()
121
+ const childRegistry = new Registry(parentRegistry)
122
+
123
+ expect(childRegistry.has(token1)).toBe(false)
124
+ })
125
+
126
+ it('should prioritize local registry over parent', () => {
127
+ const parentRegistry = new Registry()
128
+ const childRegistry = new Registry(parentRegistry)
129
+
130
+ parentRegistry.set(
131
+ token1,
132
+ InjectableScope.Singleton,
133
+ TestService,
134
+ InjectableType.Class,
135
+ )
136
+ childRegistry.set(
137
+ token1,
138
+ InjectableScope.Transient,
139
+ TestService,
140
+ InjectableType.Factory,
141
+ )
142
+
143
+ expect(childRegistry.has(token1)).toBe(true)
144
+ const record = childRegistry.get(token1)
145
+ expect(record.scope).toBe(InjectableScope.Transient) // From child registry
146
+ })
147
+ })
148
+
149
+ describe('get', () => {
150
+ it('should return factory record for existing token', () => {
151
+ registry.set(
152
+ token1,
153
+ InjectableScope.Singleton,
154
+ TestService,
155
+ InjectableType.Class,
156
+ )
157
+
158
+ const record = registry.get(token1)
159
+ expect(record.scope).toBe(InjectableScope.Singleton)
160
+ expect(record.target).toBe(TestService)
161
+ expect(record.type).toBe(InjectableType.Class)
162
+ expect(record.originalToken).toBe(token1)
163
+ })
164
+
165
+ it('should throw error for non-existent token', () => {
166
+ expect(() => {
167
+ registry.get(token1)
168
+ }).toThrow(`[Registry] No factory found for ${token1.toString()}`)
169
+ })
170
+
171
+ it('should get from parent registry when not found locally', () => {
172
+ const parentRegistry = new Registry()
173
+ const childRegistry = new Registry(parentRegistry)
174
+
175
+ parentRegistry.set(
176
+ token1,
177
+ InjectableScope.Singleton,
178
+ TestService,
179
+ InjectableType.Class,
180
+ )
181
+
182
+ const record = childRegistry.get(token1)
183
+ expect(record.scope).toBe(InjectableScope.Singleton)
184
+ expect(record.target).toBe(TestService)
185
+ })
186
+
187
+ it('should throw error when token not found in parent chain', () => {
188
+ const parentRegistry = new Registry()
189
+ const childRegistry = new Registry(parentRegistry)
190
+
191
+ expect(() => {
192
+ childRegistry.get(token1)
193
+ }).toThrow(`[Registry] No factory found for ${token1.toString()}`)
194
+ })
195
+
196
+ it('should prioritize local registry over parent', () => {
197
+ const parentRegistry = new Registry()
198
+ const childRegistry = new Registry(parentRegistry)
199
+
200
+ parentRegistry.set(
201
+ token1,
202
+ InjectableScope.Singleton,
203
+ TestService,
204
+ InjectableType.Class,
205
+ )
206
+ childRegistry.set(
207
+ token1,
208
+ InjectableScope.Transient,
209
+ AnotherService,
210
+ InjectableType.Factory,
211
+ )
212
+
213
+ const record = childRegistry.get(token1)
214
+ expect(record.scope).toBe(InjectableScope.Transient)
215
+ expect(record.target).toBe(AnotherService)
216
+ expect(record.type).toBe(InjectableType.Factory)
217
+ })
218
+ })
219
+
220
+ describe('delete', () => {
221
+ it('should delete existing token', () => {
222
+ registry.set(
223
+ token1,
224
+ InjectableScope.Singleton,
225
+ TestService,
226
+ InjectableType.Class,
227
+ )
228
+ expect(registry.has(token1)).toBe(true)
229
+
230
+ registry.delete(token1)
231
+ expect(registry.has(token1)).toBe(false)
232
+ })
233
+
234
+ it('should not affect parent registry when deleting from child', () => {
235
+ const parentRegistry = new Registry()
236
+ const childRegistry = new Registry(parentRegistry)
237
+
238
+ parentRegistry.set(
239
+ token1,
240
+ InjectableScope.Singleton,
241
+ TestService,
242
+ InjectableType.Class,
243
+ )
244
+ childRegistry.set(
245
+ token1,
246
+ InjectableScope.Transient,
247
+ AnotherService,
248
+ InjectableType.Factory,
249
+ )
250
+
251
+ childRegistry.delete(token1)
252
+
253
+ // Child should no longer have it
254
+ expect(childRegistry.has(token1)).toBe(true) // Still true because it exists in parent
255
+ // But getting it should return parent's version
256
+ const record = childRegistry.get(token1)
257
+ expect(record.scope).toBe(InjectableScope.Singleton) // From parent
258
+ })
259
+
260
+ it('should handle delete for non-existent token gracefully', () => {
261
+ expect(() => {
262
+ registry.delete(token1)
263
+ }).not.toThrow()
264
+ })
265
+ })
266
+
267
+ describe('complex parent-child scenarios', () => {
268
+ it('should handle deep hierarchy', () => {
269
+ const grandParent = new Registry()
270
+ const parent = new Registry(grandParent)
271
+ const child = new Registry(parent)
272
+
273
+ grandParent.set(
274
+ token1,
275
+ InjectableScope.Singleton,
276
+ TestService,
277
+ InjectableType.Class,
278
+ )
279
+
280
+ expect(child.has(token1)).toBe(true)
281
+ const record = child.get(token1)
282
+ expect(record.scope).toBe(InjectableScope.Singleton)
283
+ })
284
+
285
+ it('should handle overriding at different levels', () => {
286
+ const grandParent = new Registry()
287
+ const parent = new Registry(grandParent)
288
+ const child = new Registry(parent)
289
+
290
+ grandParent.set(
291
+ token1,
292
+ InjectableScope.Singleton,
293
+ TestService,
294
+ InjectableType.Class,
295
+ )
296
+ parent.set(
297
+ token1,
298
+ InjectableScope.Transient,
299
+ AnotherService,
300
+ InjectableType.Factory,
301
+ )
302
+
303
+ const record = child.get(token1)
304
+ expect(record.scope).toBe(InjectableScope.Transient) // From parent, not grandparent
305
+ expect(record.target).toBe(AnotherService)
306
+ })
307
+ })
308
+ })
309
+
310
+ describe('globalRegistry', () => {
311
+ it('should be a Registry instance', () => {
312
+ expect(globalRegistry).toBeInstanceOf(Registry)
313
+ })
314
+
315
+ it('should be able to store and retrieve tokens', () => {
316
+ const token = new InjectionToken<TestService, undefined>(
317
+ 'GlobalTest',
318
+ undefined,
319
+ )
320
+
321
+ globalRegistry.set(
322
+ token,
323
+ InjectableScope.Singleton,
324
+ TestService,
325
+ InjectableType.Class,
326
+ )
327
+ expect(globalRegistry.has(token)).toBe(true)
328
+
329
+ const record = globalRegistry.get(token)
330
+ expect(record.target).toBe(TestService)
331
+
332
+ // Clean up
333
+ globalRegistry.delete(token)
334
+ })
335
+ })
@@ -238,13 +238,12 @@ describe('Request Scope', () => {
238
238
 
239
239
  holder.addInstance('test-instance', mockInstance, mockHolder)
240
240
 
241
- expect(holder.hasInstance('test-instance')).toBe(true)
242
- expect(holder.getInstance('test-instance')).toBe(mockInstance)
243
- expect(holder.getHolder('test-instance')).toBe(mockHolder)
241
+ expect(holder.has('test-instance')).toBe(true)
242
+ expect(holder.get('test-instance')).toBe(mockHolder)
244
243
 
245
244
  // Clear instances
246
245
  holder.clear()
247
- expect(holder.hasInstance('test-instance')).toBe(false)
246
+ expect(holder.has('test-instance')).toBe(false)
248
247
  })
249
248
 
250
249
  it('should handle metadata correctly', () => {
@@ -270,11 +269,11 @@ describe('Request Scope', () => {
270
269
  holder.addInstance(token, instance)
271
270
 
272
271
  // Verify instance is stored and retrievable
273
- expect(holder.hasInstance(token.toString())).toBe(true)
274
- expect(holder.getInstance(token.toString())).toBe(instance)
272
+ expect(holder.has(token.toString())).toBe(true)
273
+ expect(holder.get(token.toString())?.instance).toBe(instance)
275
274
 
276
275
  // Verify holder is created with correct properties
277
- const holderInfo = holder.getHolder(token.toString())
276
+ const holderInfo = holder.get(token.toString())
278
277
  expect(holderInfo).toBeDefined()
279
278
  expect(holderInfo?.instance).toBe(instance)
280
279
  expect(holderInfo?.name).toBe(token.toString())
@@ -297,18 +296,18 @@ describe('Request Scope', () => {
297
296
  holder.addInstance(token3, instance3)
298
297
 
299
298
  // Verify all instances are stored correctly
300
- expect(holder.hasInstance(token1.toString())).toBe(true)
301
- expect(holder.hasInstance(token2.toString())).toBe(true)
302
- expect(holder.hasInstance(token3.toString())).toBe(true)
299
+ expect(holder.has(token1.toString())).toBe(true)
300
+ expect(holder.has(token2.toString())).toBe(true)
301
+ expect(holder.has(token3.toString())).toBe(true)
303
302
 
304
- expect(holder.getInstance(token1.toString())).toBe(instance1)
305
- expect(holder.getInstance(token2.toString())).toBe(instance2)
306
- expect(holder.getInstance(token3.toString())).toBe(instance3)
303
+ expect(holder.get(token1.toString())?.instance).toBe(instance1)
304
+ expect(holder.get(token2.toString())?.instance).toBe(instance2)
305
+ expect(holder.get(token3.toString())?.instance).toBe(instance3)
307
306
 
308
307
  // Verify each has its own holder
309
- const holder1 = holder.getHolder(token1.toString())
310
- const holder2 = holder.getHolder(token2.toString())
311
- const holder3 = holder.getHolder(token3.toString())
308
+ const holder1 = holder.get(token1.toString())
309
+ const holder2 = holder.get(token2.toString())
310
+ const holder3 = holder.get(token3.toString())
312
311
 
313
312
  expect(holder1?.instance).toBe(instance1)
314
313
  expect(holder2?.instance).toBe(instance2)
@@ -324,15 +323,15 @@ describe('Request Scope', () => {
324
323
 
325
324
  // Store original instance
326
325
  holder.addInstance(token, originalInstance)
327
- expect(holder.getInstance(token.toString())).toBe(originalInstance)
326
+ expect(holder.get(token.toString())?.instance).toBe(originalInstance)
328
327
 
329
328
  // Override with new instance
330
329
  holder.addInstance(token, newInstance)
331
- expect(holder.getInstance(token.toString())).toBe(newInstance)
332
- expect(holder.getInstance(token.toString())).not.toBe(originalInstance)
330
+ expect(holder.get(token.toString())?.instance).toBe(newInstance)
331
+ expect(holder.get(token.toString())?.instance).not.toBe(originalInstance)
333
332
 
334
333
  // Verify holder is updated
335
- const holderInfo = holder.getHolder(token.toString())
334
+ const holderInfo = holder.get(token.toString())
336
335
  expect(holderInfo?.instance).toBe(newInstance)
337
336
  })
338
337
 
@@ -356,9 +355,9 @@ describe('Request Scope', () => {
356
355
  holder.addInstance(symbolToken, symbolInstance)
357
356
  holder.addInstance(classToken, classInstance)
358
357
 
359
- expect(holder.getInstance(stringToken.toString())).toBe(stringInstance)
360
- expect(holder.getInstance(symbolToken.toString())).toBe(symbolInstance)
361
- expect(holder.getInstance(classToken.toString())).toBe(classInstance)
358
+ expect(holder.get(stringToken.toString())?.instance).toBe(stringInstance)
359
+ expect(holder.get(symbolToken.toString())?.instance).toBe(symbolInstance)
360
+ expect(holder.get(classToken.toString())?.instance).toBe(classInstance)
362
361
  })
363
362
 
364
363
  it('should clear instances stored by InjectionToken', () => {
@@ -372,16 +371,16 @@ describe('Request Scope', () => {
372
371
  holder.addInstance(token1, instance1)
373
372
  holder.addInstance(token2, instance2)
374
373
 
375
- expect(holder.hasInstance(token1.toString())).toBe(true)
376
- expect(holder.hasInstance(token2.toString())).toBe(true)
374
+ expect(holder.has(token1.toString())).toBe(true)
375
+ expect(holder.has(token2.toString())).toBe(true)
377
376
 
378
377
  // Clear all instances
379
378
  holder.clear()
380
379
 
381
- expect(holder.hasInstance(token1.toString())).toBe(false)
382
- expect(holder.hasInstance(token2.toString())).toBe(false)
383
- expect(holder.getInstance(token1.toString())).toBeUndefined()
384
- expect(holder.getInstance(token2.toString())).toBeUndefined()
380
+ expect(holder.has(token1.toString())).toBe(false)
381
+ expect(holder.has(token2.toString())).toBe(false)
382
+ expect(holder.get(token1.toString())?.instance).toBeUndefined()
383
+ expect(holder.get(token2.toString())?.instance).toBeUndefined()
385
384
  })
386
385
 
387
386
  it('should handle mixed storage by InjectionToken and string name', () => {
@@ -413,15 +412,15 @@ describe('Request Scope', () => {
413
412
  holder.addInstance(stringName, stringInstance, mockHolder)
414
413
 
415
414
  // Verify both are stored correctly
416
- expect(holder.hasInstance(token.toString())).toBe(true)
417
- expect(holder.hasInstance(stringName)).toBe(true)
415
+ expect(holder.has(token.toString())).toBe(true)
416
+ expect(holder.has(stringName)).toBe(true)
418
417
 
419
- expect(holder.getInstance(token.toString())).toBe(tokenInstance)
420
- expect(holder.getInstance(stringName)).toBe(stringInstance)
418
+ expect(holder.get(token.toString())?.instance).toBe(tokenInstance)
419
+ expect(holder.get(stringName)?.instance).toBe(stringInstance)
421
420
 
422
421
  // Verify holders
423
- expect(holder.getHolder(token.toString())?.instance).toBe(tokenInstance)
424
- expect(holder.getHolder(stringName)?.instance).toBe(stringInstance)
422
+ expect(holder.get(token.toString())?.instance).toBe(tokenInstance)
423
+ expect(holder.get(stringName)?.instance).toBe(stringInstance)
425
424
  })
426
425
  })
427
426
  })