@navios/di 0.3.0 → 0.3.1

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.
@@ -4,6 +4,7 @@ import { Container } from '../container.mjs'
4
4
  import { Injectable } from '../decorators/injectable.decorator.mjs'
5
5
  import { InjectableScope } from '../enums/index.mjs'
6
6
  import { inject } from '../index.mjs'
7
+ import { InjectionToken } from '../injection-token.mjs'
7
8
  import { Registry } from '../registry.mjs'
8
9
  import { createRequestContextHolder } from '../request-context-holder.mjs'
9
10
 
@@ -259,5 +260,168 @@ describe('Request Scope', () => {
259
260
  holder.clear()
260
261
  expect(holder.getMetadata('key1')).toBeUndefined()
261
262
  })
263
+
264
+ it('should store instances by InjectionToken', () => {
265
+ const holder = createRequestContextHolder('test-request')
266
+ const token = InjectionToken.create<string>('TestService')
267
+ const instance = { id: 'test-instance', data: 'test-data' }
268
+
269
+ // Store instance by InjectionToken
270
+ holder.addInstance(token, instance)
271
+
272
+ // Verify instance is stored and retrievable
273
+ expect(holder.hasInstance(token.toString())).toBe(true)
274
+ expect(holder.getInstance(token.toString())).toBe(instance)
275
+
276
+ // Verify holder is created with correct properties
277
+ const holderInfo = holder.getHolder(token.toString())
278
+ expect(holderInfo).toBeDefined()
279
+ expect(holderInfo?.instance).toBe(instance)
280
+ expect(holderInfo?.name).toBe(token.toString())
281
+ })
282
+
283
+ it('should store multiple instances by different InjectionTokens', () => {
284
+ const holder = createRequestContextHolder('test-request')
285
+
286
+ const token1 = InjectionToken.create<string>('Service1')
287
+ const token2 = InjectionToken.create<number>('Service2')
288
+ const token3 = InjectionToken.create<boolean>('Service3')
289
+
290
+ const instance1 = { id: 'instance1', type: 'string' }
291
+ const instance2 = { id: 'instance2', type: 'number' }
292
+ const instance3 = { id: 'instance3', type: 'boolean' }
293
+
294
+ // Store multiple instances
295
+ holder.addInstance(token1, instance1)
296
+ holder.addInstance(token2, instance2)
297
+ holder.addInstance(token3, instance3)
298
+
299
+ // 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)
303
+
304
+ expect(holder.getInstance(token1.toString())).toBe(instance1)
305
+ expect(holder.getInstance(token2.toString())).toBe(instance2)
306
+ expect(holder.getInstance(token3.toString())).toBe(instance3)
307
+
308
+ // 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())
312
+
313
+ expect(holder1?.instance).toBe(instance1)
314
+ expect(holder2?.instance).toBe(instance2)
315
+ expect(holder3?.instance).toBe(instance3)
316
+ })
317
+
318
+ it('should override instances stored by InjectionToken', () => {
319
+ const holder = createRequestContextHolder('test-request')
320
+ const token = InjectionToken.create<string>('TestService')
321
+
322
+ const originalInstance = { id: 'original', data: 'original-data' }
323
+ const newInstance = { id: 'new', data: 'new-data' }
324
+
325
+ // Store original instance
326
+ holder.addInstance(token, originalInstance)
327
+ expect(holder.getInstance(token.toString())).toBe(originalInstance)
328
+
329
+ // Override with new instance
330
+ holder.addInstance(token, newInstance)
331
+ expect(holder.getInstance(token.toString())).toBe(newInstance)
332
+ expect(holder.getInstance(token.toString())).not.toBe(originalInstance)
333
+
334
+ // Verify holder is updated
335
+ const holderInfo = holder.getHolder(token.toString())
336
+ expect(holderInfo?.instance).toBe(newInstance)
337
+ })
338
+
339
+ it('should handle InjectionToken with different name types', () => {
340
+ const holder = createRequestContextHolder('test-request')
341
+
342
+ // Test with string name
343
+ const stringToken = InjectionToken.create<string>('StringService')
344
+ const stringInstance = { type: 'string' }
345
+
346
+ // Test with symbol name
347
+ const symbolToken = InjectionToken.create<number>(Symbol('SymbolService'))
348
+ const symbolInstance = { type: 'symbol' }
349
+
350
+ // Test with class name
351
+ class TestClass {}
352
+ const classToken = InjectionToken.create(TestClass)
353
+ const classInstance = { type: 'class' }
354
+
355
+ holder.addInstance(stringToken, stringInstance)
356
+ holder.addInstance(symbolToken, symbolInstance)
357
+ holder.addInstance(classToken, classInstance)
358
+
359
+ expect(holder.getInstance(stringToken.toString())).toBe(stringInstance)
360
+ expect(holder.getInstance(symbolToken.toString())).toBe(symbolInstance)
361
+ expect(holder.getInstance(classToken.toString())).toBe(classInstance)
362
+ })
363
+
364
+ it('should clear instances stored by InjectionToken', () => {
365
+ const holder = createRequestContextHolder('test-request')
366
+ const token1 = InjectionToken.create<string>('Service1')
367
+ const token2 = InjectionToken.create<number>('Service2')
368
+
369
+ const instance1 = { id: 'instance1' }
370
+ const instance2 = { id: 'instance2' }
371
+
372
+ holder.addInstance(token1, instance1)
373
+ holder.addInstance(token2, instance2)
374
+
375
+ expect(holder.hasInstance(token1.toString())).toBe(true)
376
+ expect(holder.hasInstance(token2.toString())).toBe(true)
377
+
378
+ // Clear all instances
379
+ holder.clear()
380
+
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()
385
+ })
386
+
387
+ it('should handle mixed storage by InjectionToken and string name', () => {
388
+ const holder = createRequestContextHolder('test-request')
389
+
390
+ const token = InjectionToken.create<string>('TokenService')
391
+ const tokenInstance = { id: 'token-instance' }
392
+
393
+ const stringName = 'string-service'
394
+ const stringInstance = { id: 'string-instance' }
395
+
396
+ // Store by InjectionToken
397
+ holder.addInstance(token, tokenInstance)
398
+
399
+ // Store by string name (requires holder)
400
+ const mockHolder = {
401
+ status: 'Created' as any,
402
+ name: stringName,
403
+ instance: stringInstance,
404
+ creationPromise: null,
405
+ destroyPromise: null,
406
+ type: 'Class' as any,
407
+ scope: 'Singleton' as any,
408
+ deps: new Set<string>(),
409
+ destroyListeners: [],
410
+ createdAt: Date.now(),
411
+ ttl: Infinity,
412
+ }
413
+ holder.addInstance(stringName, stringInstance, mockHolder)
414
+
415
+ // Verify both are stored correctly
416
+ expect(holder.hasInstance(token.toString())).toBe(true)
417
+ expect(holder.hasInstance(stringName)).toBe(true)
418
+
419
+ expect(holder.getInstance(token.toString())).toBe(tokenInstance)
420
+ expect(holder.getInstance(stringName)).toBe(stringInstance)
421
+
422
+ // Verify holders
423
+ expect(holder.getHolder(token.toString())?.instance).toBe(tokenInstance)
424
+ expect(holder.getHolder(stringName)?.instance).toBe(stringInstance)
425
+ })
262
426
  })
263
427
  })
@@ -1,5 +1,9 @@
1
1
  import type { ServiceLocatorInstanceHolder } from './service-locator-instance-holder.mjs'
2
2
 
3
+ import { InjectableScope, InjectableType } from './enums/index.mjs'
4
+ import { InjectionToken } from './injection-token.mjs'
5
+ import { ServiceLocatorInstanceHolderStatus } from './service-locator-instance-holder.mjs'
6
+
3
7
  /**
4
8
  * Request context holder that manages pre-prepared instances for a specific request.
5
9
  * This allows for efficient instantiation of request-scoped services.
@@ -45,6 +49,11 @@ export interface RequestContextHolder {
45
49
  holder: ServiceLocatorInstanceHolder,
46
50
  ): void
47
51
 
52
+ /**
53
+ * Adds a pre-prepared instance to this context.
54
+ */
55
+ addInstance(token: InjectionToken<any, undefined>, instance: any): void
56
+
48
57
  /**
49
58
  * Gets a pre-prepared instance from this context.
50
59
  */
@@ -98,12 +107,32 @@ export class DefaultRequestContextHolder implements RequestContextHolder {
98
107
  }
99
108
 
100
109
  addInstance(
101
- instanceName: string,
110
+ instanceName: string | InjectionToken<any, undefined>,
102
111
  instance: any,
103
- holder: ServiceLocatorInstanceHolder,
112
+ holder?: ServiceLocatorInstanceHolder,
104
113
  ): void {
105
- this.instances.set(instanceName, instance)
106
- this.holders.set(instanceName, holder)
114
+ if (instanceName instanceof InjectionToken) {
115
+ this.instances.set(instanceName.toString(), instance)
116
+ this.holders.set(instanceName.toString(), {
117
+ instance,
118
+ status: ServiceLocatorInstanceHolderStatus.Created,
119
+ creationPromise: null,
120
+ destroyPromise: null,
121
+ destroyListeners: [],
122
+ deps: new Set(),
123
+ name: instanceName.toString(),
124
+ type: InjectableType.Class,
125
+ scope: InjectableScope.Singleton,
126
+ createdAt: Date.now(),
127
+ ttl: Infinity,
128
+ })
129
+ } else {
130
+ if (!holder) {
131
+ throw new Error('Holder is required when adding an instance by name')
132
+ }
133
+ this.instances.set(instanceName, instance)
134
+ this.holders.set(instanceName, holder)
135
+ }
107
136
  }
108
137
 
109
138
  getInstance(instanceName: string): any | undefined {