@navios/di 0.3.0 → 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.
- package/README.md +67 -6
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +2659 -0
- package/coverage/coverage-final.json +46 -0
- package/coverage/docs/examples/basic-usage.mts.html +376 -0
- package/coverage/docs/examples/factory-pattern.mts.html +1039 -0
- package/coverage/docs/examples/index.html +176 -0
- package/coverage/docs/examples/injection-tokens.mts.html +760 -0
- package/coverage/docs/examples/request-scope-example.mts.html +847 -0
- package/coverage/docs/examples/service-lifecycle.mts.html +1162 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +236 -0
- package/coverage/lib/_tsup-dts-rollup.d.mts.html +2806 -0
- package/coverage/lib/index.d.mts.html +310 -0
- package/coverage/lib/index.html +131 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/coverage/src/container.mts.html +586 -0
- package/coverage/src/decorators/factory.decorator.mts.html +322 -0
- package/coverage/src/decorators/index.html +146 -0
- package/coverage/src/decorators/index.mts.html +91 -0
- package/coverage/src/decorators/injectable.decorator.mts.html +394 -0
- package/coverage/src/enums/index.html +146 -0
- package/coverage/src/enums/index.mts.html +91 -0
- package/coverage/src/enums/injectable-scope.enum.mts.html +127 -0
- package/coverage/src/enums/injectable-type.enum.mts.html +97 -0
- package/coverage/src/errors/errors.enum.mts.html +109 -0
- package/coverage/src/errors/factory-not-found.mts.html +109 -0
- package/coverage/src/errors/factory-token-not-resolved.mts.html +115 -0
- package/coverage/src/errors/index.html +221 -0
- package/coverage/src/errors/index.mts.html +106 -0
- package/coverage/src/errors/instance-destroying.mts.html +109 -0
- package/coverage/src/errors/instance-expired.mts.html +109 -0
- package/coverage/src/errors/instance-not-found.mts.html +109 -0
- package/coverage/src/errors/unknown-error.mts.html +130 -0
- package/coverage/src/event-emitter.mts.html +400 -0
- package/coverage/src/factory-context.mts.html +109 -0
- package/coverage/src/index.html +296 -0
- package/coverage/src/index.mts.html +139 -0
- package/coverage/src/injection-token.mts.html +571 -0
- package/coverage/src/injector.mts.html +133 -0
- package/coverage/src/interfaces/factory.interface.mts.html +121 -0
- package/coverage/src/interfaces/index.html +161 -0
- package/coverage/src/interfaces/index.mts.html +94 -0
- package/coverage/src/interfaces/on-service-destroy.interface.mts.html +94 -0
- package/coverage/src/interfaces/on-service-init.interface.mts.html +94 -0
- package/coverage/src/registry.mts.html +247 -0
- package/coverage/src/request-context-holder.mts.html +607 -0
- package/coverage/src/service-instantiator.mts.html +559 -0
- package/coverage/src/service-locator-event-bus.mts.html +289 -0
- package/coverage/src/service-locator-instance-holder.mts.html +307 -0
- package/coverage/src/service-locator-manager.mts.html +604 -0
- package/coverage/src/service-locator.mts.html +2911 -0
- package/coverage/src/symbols/index.html +131 -0
- package/coverage/src/symbols/index.mts.html +88 -0
- package/coverage/src/symbols/injectable-token.mts.html +88 -0
- package/coverage/src/utils/defer.mts.html +304 -0
- package/coverage/src/utils/get-injectable-token.mts.html +142 -0
- package/coverage/src/utils/get-injectors.mts.html +691 -0
- package/coverage/src/utils/index.html +176 -0
- package/coverage/src/utils/index.mts.html +97 -0
- package/coverage/src/utils/types.mts.html +241 -0
- package/docs/README.md +5 -2
- package/docs/api-reference.md +38 -0
- package/docs/container.md +75 -0
- package/docs/getting-started.md +4 -3
- package/docs/injectable.md +4 -3
- package/docs/migration.md +177 -0
- package/docs/request-contexts.md +364 -0
- package/lib/_tsup-dts-rollup.d.mts +180 -35
- package/lib/_tsup-dts-rollup.d.ts +180 -35
- package/lib/index.d.mts +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +485 -279
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +485 -280
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/defer.spec.mts +166 -0
- package/src/__tests__/errors.spec.mts +61 -0
- package/src/__tests__/event-emitter.spec.mts +163 -0
- package/src/__tests__/get-injectors.spec.mts +70 -0
- package/src/__tests__/registry.spec.mts +335 -0
- package/src/__tests__/request-scope.spec.mts +167 -4
- package/src/__tests__/service-instantiator.spec.mts +408 -0
- package/src/__tests__/service-locator-event-bus.spec.mts +242 -0
- package/src/__tests__/service-locator-manager.spec.mts +370 -0
- package/src/__tests__/unified-api.spec.mts +130 -0
- package/src/base-instance-holder-manager.mts +175 -0
- package/src/index.mts +1 -0
- package/src/request-context-holder.mts +85 -27
- package/src/service-locator-manager.mts +12 -70
- 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
|
+
})
|
|
@@ -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
|
|
|
@@ -237,13 +238,12 @@ describe('Request Scope', () => {
|
|
|
237
238
|
|
|
238
239
|
holder.addInstance('test-instance', mockInstance, mockHolder)
|
|
239
240
|
|
|
240
|
-
expect(holder.
|
|
241
|
-
expect(holder.
|
|
242
|
-
expect(holder.getHolder('test-instance')).toBe(mockHolder)
|
|
241
|
+
expect(holder.has('test-instance')).toBe(true)
|
|
242
|
+
expect(holder.get('test-instance')).toBe(mockHolder)
|
|
243
243
|
|
|
244
244
|
// Clear instances
|
|
245
245
|
holder.clear()
|
|
246
|
-
expect(holder.
|
|
246
|
+
expect(holder.has('test-instance')).toBe(false)
|
|
247
247
|
})
|
|
248
248
|
|
|
249
249
|
it('should handle metadata correctly', () => {
|
|
@@ -259,5 +259,168 @@ describe('Request Scope', () => {
|
|
|
259
259
|
holder.clear()
|
|
260
260
|
expect(holder.getMetadata('key1')).toBeUndefined()
|
|
261
261
|
})
|
|
262
|
+
|
|
263
|
+
it('should store instances by InjectionToken', () => {
|
|
264
|
+
const holder = createRequestContextHolder('test-request')
|
|
265
|
+
const token = InjectionToken.create<string>('TestService')
|
|
266
|
+
const instance = { id: 'test-instance', data: 'test-data' }
|
|
267
|
+
|
|
268
|
+
// Store instance by InjectionToken
|
|
269
|
+
holder.addInstance(token, instance)
|
|
270
|
+
|
|
271
|
+
// Verify instance is stored and retrievable
|
|
272
|
+
expect(holder.has(token.toString())).toBe(true)
|
|
273
|
+
expect(holder.get(token.toString())?.instance).toBe(instance)
|
|
274
|
+
|
|
275
|
+
// Verify holder is created with correct properties
|
|
276
|
+
const holderInfo = holder.get(token.toString())
|
|
277
|
+
expect(holderInfo).toBeDefined()
|
|
278
|
+
expect(holderInfo?.instance).toBe(instance)
|
|
279
|
+
expect(holderInfo?.name).toBe(token.toString())
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it('should store multiple instances by different InjectionTokens', () => {
|
|
283
|
+
const holder = createRequestContextHolder('test-request')
|
|
284
|
+
|
|
285
|
+
const token1 = InjectionToken.create<string>('Service1')
|
|
286
|
+
const token2 = InjectionToken.create<number>('Service2')
|
|
287
|
+
const token3 = InjectionToken.create<boolean>('Service3')
|
|
288
|
+
|
|
289
|
+
const instance1 = { id: 'instance1', type: 'string' }
|
|
290
|
+
const instance2 = { id: 'instance2', type: 'number' }
|
|
291
|
+
const instance3 = { id: 'instance3', type: 'boolean' }
|
|
292
|
+
|
|
293
|
+
// Store multiple instances
|
|
294
|
+
holder.addInstance(token1, instance1)
|
|
295
|
+
holder.addInstance(token2, instance2)
|
|
296
|
+
holder.addInstance(token3, instance3)
|
|
297
|
+
|
|
298
|
+
// Verify all instances are stored correctly
|
|
299
|
+
expect(holder.has(token1.toString())).toBe(true)
|
|
300
|
+
expect(holder.has(token2.toString())).toBe(true)
|
|
301
|
+
expect(holder.has(token3.toString())).toBe(true)
|
|
302
|
+
|
|
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)
|
|
306
|
+
|
|
307
|
+
// Verify each has its own holder
|
|
308
|
+
const holder1 = holder.get(token1.toString())
|
|
309
|
+
const holder2 = holder.get(token2.toString())
|
|
310
|
+
const holder3 = holder.get(token3.toString())
|
|
311
|
+
|
|
312
|
+
expect(holder1?.instance).toBe(instance1)
|
|
313
|
+
expect(holder2?.instance).toBe(instance2)
|
|
314
|
+
expect(holder3?.instance).toBe(instance3)
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('should override instances stored by InjectionToken', () => {
|
|
318
|
+
const holder = createRequestContextHolder('test-request')
|
|
319
|
+
const token = InjectionToken.create<string>('TestService')
|
|
320
|
+
|
|
321
|
+
const originalInstance = { id: 'original', data: 'original-data' }
|
|
322
|
+
const newInstance = { id: 'new', data: 'new-data' }
|
|
323
|
+
|
|
324
|
+
// Store original instance
|
|
325
|
+
holder.addInstance(token, originalInstance)
|
|
326
|
+
expect(holder.get(token.toString())?.instance).toBe(originalInstance)
|
|
327
|
+
|
|
328
|
+
// Override with new instance
|
|
329
|
+
holder.addInstance(token, newInstance)
|
|
330
|
+
expect(holder.get(token.toString())?.instance).toBe(newInstance)
|
|
331
|
+
expect(holder.get(token.toString())?.instance).not.toBe(originalInstance)
|
|
332
|
+
|
|
333
|
+
// Verify holder is updated
|
|
334
|
+
const holderInfo = holder.get(token.toString())
|
|
335
|
+
expect(holderInfo?.instance).toBe(newInstance)
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
it('should handle InjectionToken with different name types', () => {
|
|
339
|
+
const holder = createRequestContextHolder('test-request')
|
|
340
|
+
|
|
341
|
+
// Test with string name
|
|
342
|
+
const stringToken = InjectionToken.create<string>('StringService')
|
|
343
|
+
const stringInstance = { type: 'string' }
|
|
344
|
+
|
|
345
|
+
// Test with symbol name
|
|
346
|
+
const symbolToken = InjectionToken.create<number>(Symbol('SymbolService'))
|
|
347
|
+
const symbolInstance = { type: 'symbol' }
|
|
348
|
+
|
|
349
|
+
// Test with class name
|
|
350
|
+
class TestClass {}
|
|
351
|
+
const classToken = InjectionToken.create(TestClass)
|
|
352
|
+
const classInstance = { type: 'class' }
|
|
353
|
+
|
|
354
|
+
holder.addInstance(stringToken, stringInstance)
|
|
355
|
+
holder.addInstance(symbolToken, symbolInstance)
|
|
356
|
+
holder.addInstance(classToken, classInstance)
|
|
357
|
+
|
|
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)
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it('should clear instances stored by InjectionToken', () => {
|
|
364
|
+
const holder = createRequestContextHolder('test-request')
|
|
365
|
+
const token1 = InjectionToken.create<string>('Service1')
|
|
366
|
+
const token2 = InjectionToken.create<number>('Service2')
|
|
367
|
+
|
|
368
|
+
const instance1 = { id: 'instance1' }
|
|
369
|
+
const instance2 = { id: 'instance2' }
|
|
370
|
+
|
|
371
|
+
holder.addInstance(token1, instance1)
|
|
372
|
+
holder.addInstance(token2, instance2)
|
|
373
|
+
|
|
374
|
+
expect(holder.has(token1.toString())).toBe(true)
|
|
375
|
+
expect(holder.has(token2.toString())).toBe(true)
|
|
376
|
+
|
|
377
|
+
// Clear all instances
|
|
378
|
+
holder.clear()
|
|
379
|
+
|
|
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()
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it('should handle mixed storage by InjectionToken and string name', () => {
|
|
387
|
+
const holder = createRequestContextHolder('test-request')
|
|
388
|
+
|
|
389
|
+
const token = InjectionToken.create<string>('TokenService')
|
|
390
|
+
const tokenInstance = { id: 'token-instance' }
|
|
391
|
+
|
|
392
|
+
const stringName = 'string-service'
|
|
393
|
+
const stringInstance = { id: 'string-instance' }
|
|
394
|
+
|
|
395
|
+
// Store by InjectionToken
|
|
396
|
+
holder.addInstance(token, tokenInstance)
|
|
397
|
+
|
|
398
|
+
// Store by string name (requires holder)
|
|
399
|
+
const mockHolder = {
|
|
400
|
+
status: 'Created' as any,
|
|
401
|
+
name: stringName,
|
|
402
|
+
instance: stringInstance,
|
|
403
|
+
creationPromise: null,
|
|
404
|
+
destroyPromise: null,
|
|
405
|
+
type: 'Class' as any,
|
|
406
|
+
scope: 'Singleton' as any,
|
|
407
|
+
deps: new Set<string>(),
|
|
408
|
+
destroyListeners: [],
|
|
409
|
+
createdAt: Date.now(),
|
|
410
|
+
ttl: Infinity,
|
|
411
|
+
}
|
|
412
|
+
holder.addInstance(stringName, stringInstance, mockHolder)
|
|
413
|
+
|
|
414
|
+
// Verify both are stored correctly
|
|
415
|
+
expect(holder.has(token.toString())).toBe(true)
|
|
416
|
+
expect(holder.has(stringName)).toBe(true)
|
|
417
|
+
|
|
418
|
+
expect(holder.get(token.toString())?.instance).toBe(tokenInstance)
|
|
419
|
+
expect(holder.get(stringName)?.instance).toBe(stringInstance)
|
|
420
|
+
|
|
421
|
+
// Verify holders
|
|
422
|
+
expect(holder.get(token.toString())?.instance).toBe(tokenInstance)
|
|
423
|
+
expect(holder.get(stringName)?.instance).toBe(stringInstance)
|
|
424
|
+
})
|
|
262
425
|
})
|
|
263
426
|
})
|