@navios/di 0.4.2 → 0.5.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 +211 -1
- package/coverage/clover.xml +1912 -1277
- package/coverage/coverage-final.json +37 -28
- package/coverage/docs/examples/basic-usage.mts.html +1 -1
- package/coverage/docs/examples/factory-pattern.mts.html +1 -1
- package/coverage/docs/examples/index.html +1 -1
- package/coverage/docs/examples/injection-tokens.mts.html +1 -1
- package/coverage/docs/examples/request-scope-example.mts.html +1 -1
- package/coverage/docs/examples/service-lifecycle.mts.html +1 -1
- package/coverage/index.html +71 -41
- package/coverage/lib/_tsup-dts-rollup.d.mts.html +682 -43
- package/coverage/lib/index.d.mts.html +7 -4
- package/coverage/lib/index.html +5 -5
- package/coverage/lib/testing/index.d.mts.html +91 -0
- package/coverage/lib/testing/index.html +116 -0
- package/coverage/src/base-instance-holder-manager.mts.html +589 -0
- package/coverage/src/container.mts.html +257 -74
- package/coverage/src/decorators/factory.decorator.mts.html +1 -1
- package/coverage/src/decorators/index.html +1 -1
- package/coverage/src/decorators/index.mts.html +1 -1
- package/coverage/src/decorators/injectable.decorator.mts.html +20 -20
- package/coverage/src/enums/index.html +1 -1
- package/coverage/src/enums/index.mts.html +1 -1
- package/coverage/src/enums/injectable-scope.enum.mts.html +1 -1
- package/coverage/src/enums/injectable-type.enum.mts.html +1 -1
- package/coverage/src/errors/di-error.mts.html +292 -0
- package/coverage/src/errors/errors.enum.mts.html +30 -21
- package/coverage/src/errors/factory-not-found.mts.html +31 -22
- package/coverage/src/errors/factory-token-not-resolved.mts.html +29 -26
- package/coverage/src/errors/index.html +56 -41
- package/coverage/src/errors/index.mts.html +15 -9
- package/coverage/src/errors/instance-destroying.mts.html +31 -22
- package/coverage/src/errors/instance-expired.mts.html +31 -22
- package/coverage/src/errors/instance-not-found.mts.html +31 -22
- package/coverage/src/errors/unknown-error.mts.html +31 -43
- package/coverage/src/event-emitter.mts.html +14 -14
- package/coverage/src/factory-context.mts.html +1 -1
- package/coverage/src/index.html +121 -46
- package/coverage/src/index.mts.html +7 -4
- package/coverage/src/injection-token.mts.html +28 -28
- package/coverage/src/injector.mts.html +1 -1
- package/coverage/src/instance-resolver.mts.html +1762 -0
- package/coverage/src/interfaces/factory.interface.mts.html +1 -1
- package/coverage/src/interfaces/index.html +1 -1
- package/coverage/src/interfaces/index.mts.html +1 -1
- package/coverage/src/interfaces/on-service-destroy.interface.mts.html +1 -1
- package/coverage/src/interfaces/on-service-init.interface.mts.html +1 -1
- package/coverage/src/registry.mts.html +28 -28
- package/coverage/src/request-context-holder.mts.html +183 -102
- package/coverage/src/request-context-manager.mts.html +532 -0
- package/coverage/src/service-instantiator.mts.html +49 -49
- package/coverage/src/service-invalidator.mts.html +1372 -0
- package/coverage/src/service-locator-event-bus.mts.html +48 -48
- package/coverage/src/service-locator-instance-holder.mts.html +2 -14
- package/coverage/src/service-locator-manager.mts.html +71 -335
- package/coverage/src/service-locator.mts.html +240 -2328
- package/coverage/src/symbols/index.html +1 -1
- package/coverage/src/symbols/index.mts.html +1 -1
- package/coverage/src/symbols/injectable-token.mts.html +1 -1
- package/coverage/src/testing/index.html +131 -0
- package/coverage/src/testing/index.mts.html +88 -0
- package/coverage/src/testing/test-container.mts.html +445 -0
- package/coverage/src/token-processor.mts.html +607 -0
- package/coverage/src/utils/defer.mts.html +28 -214
- package/coverage/src/utils/get-injectable-token.mts.html +7 -7
- package/coverage/src/utils/get-injectors.mts.html +99 -99
- package/coverage/src/utils/index.html +15 -15
- package/coverage/src/utils/index.mts.html +4 -7
- package/coverage/src/utils/types.mts.html +1 -1
- package/docs/injectable.md +51 -11
- package/docs/scopes.md +63 -29
- package/lib/_tsup-dts-rollup.d.mts +376 -213
- package/lib/_tsup-dts-rollup.d.ts +376 -213
- package/lib/{chunk-3NLYPYBY.mjs → chunk-44F3LXW5.mjs} +1021 -605
- package/lib/chunk-44F3LXW5.mjs.map +1 -0
- package/lib/index.d.mts +6 -4
- package/lib/index.d.ts +6 -4
- package/lib/index.js +1192 -776
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +2 -2
- package/lib/testing/index.js +1258 -840
- package/lib/testing/index.js.map +1 -1
- package/lib/testing/index.mjs +1 -1
- package/package.json +1 -1
- package/src/__tests__/container.spec.mts +47 -13
- package/src/__tests__/errors.spec.mts +53 -27
- package/src/__tests__/injectable.spec.mts +73 -0
- package/src/__tests__/request-scope.spec.mts +0 -2
- package/src/__tests__/service-locator-manager.spec.mts +12 -82
- package/src/__tests__/service-locator.spec.mts +1009 -1
- package/src/__type-tests__/inject.spec-d.mts +30 -7
- package/src/__type-tests__/injectable.spec-d.mts +76 -37
- package/src/base-instance-holder-manager.mts +2 -9
- package/src/container.mts +61 -9
- package/src/decorators/injectable.decorator.mts +29 -5
- package/src/errors/di-error.mts +69 -0
- package/src/errors/index.mts +9 -7
- package/src/injection-token.mts +1 -0
- package/src/injector.mts +2 -0
- package/src/instance-resolver.mts +559 -0
- package/src/request-context-holder.mts +0 -2
- package/src/request-context-manager.mts +149 -0
- package/src/service-invalidator.mts +429 -0
- package/src/service-locator-instance-holder.mts +0 -4
- package/src/service-locator-manager.mts +10 -40
- package/src/service-locator.mts +86 -782
- package/src/token-processor.mts +174 -0
- package/src/utils/get-injectors.mts +161 -24
- package/src/utils/index.mts +0 -1
- package/src/utils/types.mts +12 -8
- package/lib/chunk-3NLYPYBY.mjs.map +0 -1
- package/src/__tests__/defer.spec.mts +0 -166
- package/src/errors/errors.enum.mts +0 -8
- package/src/errors/factory-not-found.mts +0 -8
- package/src/errors/factory-token-not-resolved.mts +0 -10
- package/src/errors/instance-destroying.mts +0 -8
- package/src/errors/instance-expired.mts +0 -8
- package/src/errors/instance-not-found.mts +0 -8
- package/src/errors/unknown-error.mts +0 -15
- package/src/utils/defer.mts +0 -73
package/lib/testing/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Injectable, __decoratorStart, __decorateElement, __runInitializers, Container, globalRegistry, getInjectableToken } from '../chunk-
|
|
1
|
+
import { Injectable, __decoratorStart, __decorateElement, __runInitializers, Container, globalRegistry, getInjectableToken } from '../chunk-44F3LXW5.mjs';
|
|
2
2
|
|
|
3
3
|
// src/testing/test-container.mts
|
|
4
4
|
var TestBindingBuilder = class {
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// oxlint-disable no-unused-vars
|
|
1
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
3
|
import { z } from 'zod/v4'
|
|
3
4
|
|
|
@@ -16,7 +17,6 @@ import { InjectionToken } from '../injection-token.mjs'
|
|
|
16
17
|
import { asyncInject, inject } from '../injector.mjs'
|
|
17
18
|
import { Registry } from '../registry.mjs'
|
|
18
19
|
import { ServiceLocator } from '../service-locator.mjs'
|
|
19
|
-
import { createDeferred } from '../utils/defer.mjs'
|
|
20
20
|
|
|
21
21
|
describe('Container', () => {
|
|
22
22
|
let container: Container
|
|
@@ -321,7 +321,6 @@ describe('Container', () => {
|
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
-
@Injectable({ registry })
|
|
325
324
|
class TestService {
|
|
326
325
|
constructor(
|
|
327
326
|
public readonly name: string,
|
|
@@ -359,7 +358,6 @@ describe('Container', () => {
|
|
|
359
358
|
}
|
|
360
359
|
}
|
|
361
360
|
|
|
362
|
-
@Injectable({ registry })
|
|
363
361
|
class TestService {
|
|
364
362
|
constructor(
|
|
365
363
|
public readonly name: string,
|
|
@@ -394,7 +392,6 @@ describe('Container', () => {
|
|
|
394
392
|
}
|
|
395
393
|
}
|
|
396
394
|
|
|
397
|
-
@Injectable({ registry })
|
|
398
395
|
class TestService {
|
|
399
396
|
constructor(public readonly type: string) {}
|
|
400
397
|
}
|
|
@@ -450,7 +447,6 @@ describe('Container', () => {
|
|
|
450
447
|
}
|
|
451
448
|
}
|
|
452
449
|
|
|
453
|
-
@Injectable({ registry })
|
|
454
450
|
class TestService {
|
|
455
451
|
constructor(public readonly factory: string) {}
|
|
456
452
|
}
|
|
@@ -751,7 +747,7 @@ describe('Container', () => {
|
|
|
751
747
|
|
|
752
748
|
describe('Ready method and async operations', () => {
|
|
753
749
|
it('should wait for all pending operations', async () => {
|
|
754
|
-
const deferred =
|
|
750
|
+
const deferred = Promise.withResolvers<string>()
|
|
755
751
|
|
|
756
752
|
@Factory({ registry })
|
|
757
753
|
class AsyncFactory implements Factorable<TestService> {
|
|
@@ -761,7 +757,6 @@ describe('Container', () => {
|
|
|
761
757
|
}
|
|
762
758
|
}
|
|
763
759
|
|
|
764
|
-
@Injectable({ registry })
|
|
765
760
|
class TestService {
|
|
766
761
|
constructor(public readonly value: string) {}
|
|
767
762
|
}
|
|
@@ -779,8 +774,8 @@ describe('Container', () => {
|
|
|
779
774
|
})
|
|
780
775
|
|
|
781
776
|
it('should handle multiple concurrent operations', async () => {
|
|
782
|
-
const deferred1 =
|
|
783
|
-
const deferred2 =
|
|
777
|
+
const deferred1 = Promise.withResolvers<string>()
|
|
778
|
+
const deferred2 = Promise.withResolvers<string>()
|
|
784
779
|
|
|
785
780
|
@Factory({ registry })
|
|
786
781
|
class AsyncFactory1 implements Factorable<TestService> {
|
|
@@ -798,7 +793,6 @@ describe('Container', () => {
|
|
|
798
793
|
}
|
|
799
794
|
}
|
|
800
795
|
|
|
801
|
-
@Injectable({ registry })
|
|
802
796
|
class TestService {
|
|
803
797
|
constructor(public readonly value: string) {}
|
|
804
798
|
}
|
|
@@ -817,7 +811,7 @@ describe('Container', () => {
|
|
|
817
811
|
})
|
|
818
812
|
|
|
819
813
|
it.skip('should handle factory errors in ready state', async () => {
|
|
820
|
-
const deferred =
|
|
814
|
+
const deferred = Promise.withResolvers<string>()
|
|
821
815
|
|
|
822
816
|
@Factory({ registry })
|
|
823
817
|
class ErrorFactory implements Factorable<TestService> {
|
|
@@ -826,13 +820,13 @@ describe('Container', () => {
|
|
|
826
820
|
if (result === 'error') {
|
|
827
821
|
throw new Error('Factory error')
|
|
828
822
|
}
|
|
829
|
-
return new TestService(
|
|
823
|
+
return new TestService()
|
|
830
824
|
}
|
|
831
825
|
}
|
|
832
826
|
|
|
833
827
|
@Injectable({ registry })
|
|
834
828
|
class TestService {
|
|
835
|
-
constructor(
|
|
829
|
+
constructor() {}
|
|
836
830
|
}
|
|
837
831
|
|
|
838
832
|
const promise = container.get(ErrorFactory)
|
|
@@ -1135,6 +1129,46 @@ describe('Container', () => {
|
|
|
1135
1129
|
expect(level1_1.id).not.toBe(level1_2.id)
|
|
1136
1130
|
})
|
|
1137
1131
|
|
|
1132
|
+
it('should invalidate services with nested inject dependencies in request context', async () => {
|
|
1133
|
+
@Injectable({ registry, scope: InjectableScope.Request })
|
|
1134
|
+
class Level1Service {
|
|
1135
|
+
public id = Math.random()
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
@Injectable({ registry })
|
|
1139
|
+
class Level2Service {
|
|
1140
|
+
level1 = inject(Level1Service)
|
|
1141
|
+
public id = Math.random()
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
@Injectable({ registry })
|
|
1145
|
+
class RootService {
|
|
1146
|
+
level2 = inject(Level2Service)
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
container.beginRequest('request-1')
|
|
1150
|
+
|
|
1151
|
+
const root1 = await container.get(RootService)
|
|
1152
|
+
const level2_1 = root1.level2
|
|
1153
|
+
const level1_1 = level2_1.level1
|
|
1154
|
+
|
|
1155
|
+
// Invalidate the root service
|
|
1156
|
+
await container.invalidate(level1_1)
|
|
1157
|
+
|
|
1158
|
+
const root2 = await container.get(RootService)
|
|
1159
|
+
const level2_2 = root2.level2
|
|
1160
|
+
const level1_2 = level2_2.level1
|
|
1161
|
+
|
|
1162
|
+
// All should be new instances
|
|
1163
|
+
expect(root1).not.toBe(root2)
|
|
1164
|
+
expect(level2_1).not.toBe(level2_2)
|
|
1165
|
+
expect(level1_1).not.toBe(level1_2)
|
|
1166
|
+
expect(level2_1.id).not.toBe(level2_2.id)
|
|
1167
|
+
expect(level1_1.id).not.toBe(level1_2.id)
|
|
1168
|
+
|
|
1169
|
+
await container.endRequest('request-1')
|
|
1170
|
+
})
|
|
1171
|
+
|
|
1138
1172
|
it('should handle invalidation of services with mixed inject and asyncInject', async () => {
|
|
1139
1173
|
@Injectable({ registry })
|
|
1140
1174
|
class AsyncService {
|
|
@@ -1,61 +1,87 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
InstanceExpired,
|
|
8
|
-
} from '../errors/index.mjs'
|
|
9
|
-
|
|
10
|
-
describe('Error Classes', () => {
|
|
11
|
-
describe('FactoryNotFound', () => {
|
|
3
|
+
import { DIError, DIErrorCode } from '../errors/index.mjs'
|
|
4
|
+
|
|
5
|
+
describe('DIError', () => {
|
|
6
|
+
describe('factoryNotFound', () => {
|
|
12
7
|
it('should create error with proper message and code', () => {
|
|
13
|
-
const error =
|
|
8
|
+
const error = DIError.factoryNotFound('TestFactory')
|
|
14
9
|
|
|
15
10
|
expect(error.message).toBe('Factory TestFactory not found')
|
|
16
|
-
expect(error.code).toBe(
|
|
17
|
-
expect(error.name).toBe('TestFactory')
|
|
11
|
+
expect(error.code).toBe(DIErrorCode.FactoryNotFound)
|
|
12
|
+
expect(error.context?.name).toBe('TestFactory')
|
|
13
|
+
expect(error).toBeInstanceOf(DIError)
|
|
18
14
|
expect(error).toBeInstanceOf(Error)
|
|
19
15
|
})
|
|
20
16
|
|
|
21
17
|
it('should be throwable', () => {
|
|
22
18
|
expect(() => {
|
|
23
|
-
throw
|
|
19
|
+
throw DIError.factoryNotFound('SomeFactory')
|
|
24
20
|
}).toThrow('Factory SomeFactory not found')
|
|
25
21
|
})
|
|
26
22
|
})
|
|
27
23
|
|
|
28
|
-
describe('
|
|
24
|
+
describe('instanceDestroying', () => {
|
|
29
25
|
it('should create error with proper message and code', () => {
|
|
30
|
-
const error =
|
|
26
|
+
const error = DIError.instanceDestroying('TestInstance')
|
|
31
27
|
|
|
32
28
|
expect(error.message).toBe('Instance TestInstance destroying')
|
|
33
|
-
expect(error.code).toBe(
|
|
34
|
-
expect(error.name).toBe('TestInstance')
|
|
29
|
+
expect(error.code).toBe(DIErrorCode.InstanceDestroying)
|
|
30
|
+
expect(error.context?.name).toBe('TestInstance')
|
|
31
|
+
expect(error).toBeInstanceOf(DIError)
|
|
35
32
|
expect(error).toBeInstanceOf(Error)
|
|
36
33
|
})
|
|
37
34
|
|
|
38
35
|
it('should be throwable', () => {
|
|
39
36
|
expect(() => {
|
|
40
|
-
throw
|
|
37
|
+
throw DIError.instanceDestroying('SomeInstance')
|
|
41
38
|
}).toThrow('Instance SomeInstance destroying')
|
|
42
39
|
})
|
|
43
40
|
})
|
|
44
41
|
|
|
45
|
-
describe('
|
|
42
|
+
describe('instanceNotFound', () => {
|
|
46
43
|
it('should create error with proper message and code', () => {
|
|
47
|
-
const error =
|
|
44
|
+
const error = DIError.instanceNotFound('TestInstance')
|
|
48
45
|
|
|
49
|
-
expect(error.message).toBe('Instance TestInstance
|
|
50
|
-
expect(error.code).toBe(
|
|
51
|
-
expect(error.name).toBe('TestInstance')
|
|
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)
|
|
52
50
|
expect(error).toBeInstanceOf(Error)
|
|
53
51
|
})
|
|
52
|
+
})
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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)
|
|
59
85
|
})
|
|
60
86
|
})
|
|
61
87
|
})
|
|
@@ -170,4 +170,77 @@ describe('Injectable decorator', () => {
|
|
|
170
170
|
expect(value).toBeInstanceOf(TestOuter)
|
|
171
171
|
expect(value.foo).toBeInstanceOf(TestInner)
|
|
172
172
|
})
|
|
173
|
+
|
|
174
|
+
it('should work with inject and Transient services', async () => {
|
|
175
|
+
@Injectable({ scope: InjectableScope.Transient })
|
|
176
|
+
class TransientService {
|
|
177
|
+
value = Math.random()
|
|
178
|
+
|
|
179
|
+
getValue() {
|
|
180
|
+
return this.value
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@Injectable()
|
|
185
|
+
class ConsumerService {
|
|
186
|
+
private readonly transientService = inject(TransientService)
|
|
187
|
+
|
|
188
|
+
async getTransientValue() {
|
|
189
|
+
// Service should be available in async methods after initialization
|
|
190
|
+
return this.transientService.getValue()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Synchronous access should work after initialization
|
|
194
|
+
getTransientValueSync() {
|
|
195
|
+
return this.transientService.getValue()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const consumer1 = await container.get(ConsumerService)
|
|
200
|
+
expect(consumer1).toBeInstanceOf(ConsumerService)
|
|
201
|
+
|
|
202
|
+
const value1 = await consumer1.getTransientValue()
|
|
203
|
+
expect(typeof value1).toBe('number')
|
|
204
|
+
|
|
205
|
+
const value2 = consumer1.getTransientValueSync()
|
|
206
|
+
expect(value2).toBe(value1) // Should be the same instance
|
|
207
|
+
|
|
208
|
+
// Each consumer gets a new transient instance
|
|
209
|
+
const consumer2 = await container.get(ConsumerService)
|
|
210
|
+
expect(consumer2).toBe(consumer1) // Consumer is singleton
|
|
211
|
+
|
|
212
|
+
const value3 = await consumer2.getTransientValue()
|
|
213
|
+
expect(value3).toBe(value1) // Same transient instance for same consumer
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
it('should track async dependencies with inject for Transient services', async () => {
|
|
217
|
+
@Injectable({ scope: InjectableScope.Transient })
|
|
218
|
+
class AsyncTransientService {
|
|
219
|
+
private initialized = false
|
|
220
|
+
|
|
221
|
+
async onServiceInit() {
|
|
222
|
+
await new Promise((resolve) => setTimeout(resolve, 10))
|
|
223
|
+
this.initialized = true
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
isInitialized() {
|
|
227
|
+
return this.initialized
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@Injectable()
|
|
232
|
+
class AsyncConsumerService {
|
|
233
|
+
private readonly transientService = inject(AsyncTransientService)
|
|
234
|
+
|
|
235
|
+
async checkInitialization() {
|
|
236
|
+
return this.transientService.isInitialized()
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const consumer = await container.get(AsyncConsumerService)
|
|
241
|
+
expect(consumer).toBeInstanceOf(AsyncConsumerService)
|
|
242
|
+
|
|
243
|
+
const isInitialized = await consumer.checkInitialization()
|
|
244
|
+
expect(isInitialized).toBe(true) // Should be initialized after container.get()
|
|
245
|
+
})
|
|
173
246
|
})
|
|
@@ -233,7 +233,6 @@ describe('Request Scope', () => {
|
|
|
233
233
|
deps: new Set<string>(),
|
|
234
234
|
destroyListeners: [],
|
|
235
235
|
createdAt: Date.now(),
|
|
236
|
-
ttl: Infinity,
|
|
237
236
|
}
|
|
238
237
|
|
|
239
238
|
holder.addInstance('test-instance', mockInstance, mockHolder)
|
|
@@ -407,7 +406,6 @@ describe('Request Scope', () => {
|
|
|
407
406
|
deps: new Set<string>(),
|
|
408
407
|
destroyListeners: [],
|
|
409
408
|
createdAt: Date.now(),
|
|
410
|
-
ttl: Infinity,
|
|
411
409
|
}
|
|
412
410
|
holder.addInstance(stringName, stringInstance, mockHolder)
|
|
413
411
|
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
2
|
|
|
3
3
|
import { InjectableScope, InjectableType } from '../enums/index.mjs'
|
|
4
|
-
import {
|
|
5
|
-
InstanceDestroying,
|
|
6
|
-
InstanceExpired,
|
|
7
|
-
InstanceNotFound,
|
|
8
|
-
} from '../errors/index.mjs'
|
|
4
|
+
import { DIError } from '../errors/index.mjs'
|
|
9
5
|
import { ServiceLocatorInstanceHolderStatus } from '../service-locator-instance-holder.mjs'
|
|
10
6
|
import { ServiceLocatorManager } from '../service-locator-manager.mjs'
|
|
11
7
|
|
|
@@ -32,11 +28,11 @@ describe('ServiceLocatorManager', () => {
|
|
|
32
28
|
})
|
|
33
29
|
|
|
34
30
|
describe('get', () => {
|
|
35
|
-
it('should return
|
|
31
|
+
it('should return DIError.instanceNotFound for non-existent instance', () => {
|
|
36
32
|
const result = manager.get('non-existent')
|
|
37
33
|
|
|
38
34
|
expect(result).toHaveLength(1)
|
|
39
|
-
expect(result[0]).toBeInstanceOf(
|
|
35
|
+
expect(result[0]).toBeInstanceOf(DIError)
|
|
40
36
|
expect(mockLogger.log).toHaveBeenCalledWith(
|
|
41
37
|
'[ServiceLocatorManager]#getInstanceHolder() Instance non-existent not found',
|
|
42
38
|
)
|
|
@@ -57,30 +53,7 @@ describe('ServiceLocatorManager', () => {
|
|
|
57
53
|
expect(result[1]).toBe(holder)
|
|
58
54
|
})
|
|
59
55
|
|
|
60
|
-
it('should return
|
|
61
|
-
const holder = manager.storeCreatedHolder(
|
|
62
|
-
'expired-instance',
|
|
63
|
-
{ value: 'test' },
|
|
64
|
-
InjectableType.Class,
|
|
65
|
-
InjectableScope.Singleton,
|
|
66
|
-
new Set(),
|
|
67
|
-
100, // 100ms TTL
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
// Manually set creation time to past
|
|
71
|
-
holder.createdAt = Date.now() - 200
|
|
72
|
-
|
|
73
|
-
const result = manager.get('expired-instance')
|
|
74
|
-
|
|
75
|
-
expect(result).toHaveLength(2)
|
|
76
|
-
expect(result[0]).toBeInstanceOf(InstanceExpired)
|
|
77
|
-
expect(result[1]).toBe(holder)
|
|
78
|
-
expect(mockLogger.log).toHaveBeenCalledWith(
|
|
79
|
-
'[ServiceLocatorManager]#getInstanceHolder() TTL expired for expired-instance',
|
|
80
|
-
)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('should return InstanceDestroying for destroying instance', () => {
|
|
56
|
+
it('should return DIError.instanceDestroying for destroying instance', () => {
|
|
84
57
|
const holder = manager.storeCreatedHolder(
|
|
85
58
|
'destroying-instance',
|
|
86
59
|
{ value: 'test' },
|
|
@@ -94,7 +67,7 @@ describe('ServiceLocatorManager', () => {
|
|
|
94
67
|
const result = manager.get('destroying-instance')
|
|
95
68
|
|
|
96
69
|
expect(result).toHaveLength(2)
|
|
97
|
-
expect(result[0]).toBeInstanceOf(
|
|
70
|
+
expect(result[0]).toBeInstanceOf(DIError)
|
|
98
71
|
expect(result[1]).toBe(holder)
|
|
99
72
|
expect(mockLogger.log).toHaveBeenCalledWith(
|
|
100
73
|
'[ServiceLocatorManager]#getInstanceHolder() Instance destroying-instance is destroying',
|
|
@@ -111,35 +84,18 @@ describe('ServiceLocatorManager', () => {
|
|
|
111
84
|
|
|
112
85
|
// Manually set status to error with an error instance
|
|
113
86
|
holder.status = ServiceLocatorInstanceHolderStatus.Error
|
|
114
|
-
const errorInstance =
|
|
87
|
+
const errorInstance = DIError.instanceNotFound('error-instance')
|
|
115
88
|
holder.instance = errorInstance
|
|
116
89
|
|
|
117
90
|
const result = manager.get('error-instance')
|
|
118
91
|
|
|
119
92
|
expect(result).toHaveLength(2)
|
|
120
|
-
expect(result[0]).toBeInstanceOf(
|
|
93
|
+
expect(result[0]).toBeInstanceOf(DIError)
|
|
121
94
|
expect(result[1]).toBe(holder)
|
|
122
95
|
expect(mockLogger.log).toHaveBeenCalledWith(
|
|
123
96
|
'[ServiceLocatorManager]#getInstanceHolder() Instance error-instance is in error state',
|
|
124
97
|
)
|
|
125
98
|
})
|
|
126
|
-
|
|
127
|
-
it('should handle instance with infinite TTL correctly', () => {
|
|
128
|
-
const holder = manager.storeCreatedHolder(
|
|
129
|
-
'infinite-ttl-instance',
|
|
130
|
-
{ value: 'test' },
|
|
131
|
-
InjectableType.Class,
|
|
132
|
-
InjectableScope.Singleton,
|
|
133
|
-
new Set(),
|
|
134
|
-
Infinity,
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
const result = manager.get('infinite-ttl-instance')
|
|
138
|
-
|
|
139
|
-
expect(result).toHaveLength(2)
|
|
140
|
-
expect(result[0]).toBeUndefined()
|
|
141
|
-
expect(result[1]).toBe(holder)
|
|
142
|
-
})
|
|
143
99
|
})
|
|
144
100
|
|
|
145
101
|
describe('set', () => {
|
|
@@ -184,24 +140,6 @@ describe('ServiceLocatorManager', () => {
|
|
|
184
140
|
expect(result[1]).toBe(true)
|
|
185
141
|
})
|
|
186
142
|
|
|
187
|
-
it('should return error for expired instance', () => {
|
|
188
|
-
const holder = manager.storeCreatedHolder(
|
|
189
|
-
'expired-instance',
|
|
190
|
-
{ value: 'test' },
|
|
191
|
-
InjectableType.Class,
|
|
192
|
-
InjectableScope.Singleton,
|
|
193
|
-
new Set(),
|
|
194
|
-
100,
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
holder.createdAt = Date.now() - 200
|
|
198
|
-
|
|
199
|
-
const result = manager.has('expired-instance')
|
|
200
|
-
|
|
201
|
-
expect(result).toHaveLength(1)
|
|
202
|
-
expect(result[0]).toBeInstanceOf(InstanceExpired)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
143
|
it('should return error for destroying instance', () => {
|
|
206
144
|
const holder = manager.storeCreatedHolder(
|
|
207
145
|
'destroying-instance',
|
|
@@ -215,7 +153,7 @@ describe('ServiceLocatorManager', () => {
|
|
|
215
153
|
const result = manager.has('destroying-instance')
|
|
216
154
|
|
|
217
155
|
expect(result).toHaveLength(1)
|
|
218
|
-
expect(result[0]).toBeInstanceOf(
|
|
156
|
+
expect(result[0]).toBeInstanceOf(DIError)
|
|
219
157
|
})
|
|
220
158
|
})
|
|
221
159
|
|
|
@@ -233,7 +171,7 @@ describe('ServiceLocatorManager', () => {
|
|
|
233
171
|
|
|
234
172
|
const getResult = manager.get('test-instance')
|
|
235
173
|
expect(getResult).toHaveLength(1)
|
|
236
|
-
expect(getResult[0]).toBeInstanceOf(
|
|
174
|
+
expect(getResult[0]).toBeInstanceOf(DIError)
|
|
237
175
|
})
|
|
238
176
|
|
|
239
177
|
it('should return false for non-existent instance', () => {
|
|
@@ -299,23 +237,19 @@ describe('ServiceLocatorManager', () => {
|
|
|
299
237
|
expect(holder.type).toBe(InjectableType.Class)
|
|
300
238
|
expect(holder.scope).toBe(InjectableScope.Singleton)
|
|
301
239
|
expect(holder.deps).toEqual(new Set())
|
|
302
|
-
expect(holder.ttl).toBe(Infinity)
|
|
303
240
|
})
|
|
304
241
|
|
|
305
|
-
it('should create holder with custom dependencies
|
|
242
|
+
it('should create holder with custom dependencies', () => {
|
|
306
243
|
const deps = new Set(['dep1', 'dep2'])
|
|
307
|
-
const ttl = 5000
|
|
308
244
|
|
|
309
|
-
const [
|
|
245
|
+
const [, holder] = manager.createCreatingHolder(
|
|
310
246
|
'test-instance',
|
|
311
247
|
InjectableType.Factory,
|
|
312
248
|
InjectableScope.Request,
|
|
313
249
|
deps,
|
|
314
|
-
ttl,
|
|
315
250
|
)
|
|
316
251
|
|
|
317
252
|
expect(holder.deps).toBe(deps)
|
|
318
|
-
expect(holder.ttl).toBe(ttl)
|
|
319
253
|
expect(holder.type).toBe(InjectableType.Factory)
|
|
320
254
|
expect(holder.scope).toBe(InjectableScope.Request)
|
|
321
255
|
})
|
|
@@ -338,7 +272,6 @@ describe('ServiceLocatorManager', () => {
|
|
|
338
272
|
expect(holder.type).toBe(InjectableType.Class)
|
|
339
273
|
expect(holder.scope).toBe(InjectableScope.Singleton)
|
|
340
274
|
expect(holder.deps).toEqual(new Set())
|
|
341
|
-
expect(holder.ttl).toBe(Infinity)
|
|
342
275
|
|
|
343
276
|
// Verify it's stored
|
|
344
277
|
const getResult = manager.get('test-instance')
|
|
@@ -347,9 +280,8 @@ describe('ServiceLocatorManager', () => {
|
|
|
347
280
|
expect(getResult[1]).toBe(holder)
|
|
348
281
|
})
|
|
349
282
|
|
|
350
|
-
it('should create holder with custom dependencies
|
|
283
|
+
it('should create holder with custom dependencies', () => {
|
|
351
284
|
const deps = new Set(['dep1', 'dep2'])
|
|
352
|
-
const ttl = 5000
|
|
353
285
|
const instance = { value: 'test' }
|
|
354
286
|
|
|
355
287
|
const holder = manager.storeCreatedHolder(
|
|
@@ -358,11 +290,9 @@ describe('ServiceLocatorManager', () => {
|
|
|
358
290
|
InjectableType.Factory,
|
|
359
291
|
InjectableScope.Request,
|
|
360
292
|
deps,
|
|
361
|
-
ttl,
|
|
362
293
|
)
|
|
363
294
|
|
|
364
295
|
expect(holder.deps).toBe(deps)
|
|
365
|
-
expect(holder.ttl).toBe(ttl)
|
|
366
296
|
expect(holder.type).toBe(InjectableType.Factory)
|
|
367
297
|
expect(holder.scope).toBe(InjectableScope.Request)
|
|
368
298
|
})
|