@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.
- package/CHANGELOG.md +110 -0
- package/README.md +117 -17
- package/lib/browser/container/abstract-container.d.mts +112 -0
- package/lib/browser/container/abstract-container.d.mts.map +1 -0
- package/lib/browser/container/abstract-container.mjs +100 -0
- package/lib/browser/container/abstract-container.mjs.map +1 -0
- package/lib/browser/container/container.d.mts +100 -0
- package/lib/browser/container/container.d.mts.map +1 -0
- package/lib/browser/container/container.mjs +424 -0
- package/lib/browser/container/container.mjs.map +1 -0
- package/lib/browser/container/scoped-container.d.mts +93 -0
- package/lib/browser/container/scoped-container.d.mts.map +1 -0
- package/lib/browser/container/scoped-container.mjs +119 -0
- package/lib/browser/container/scoped-container.mjs.map +1 -0
- package/lib/browser/decorators/factory.decorator.d.mts +26 -0
- package/lib/browser/decorators/factory.decorator.d.mts.map +1 -0
- package/lib/browser/decorators/factory.decorator.mjs +20 -0
- package/lib/browser/decorators/factory.decorator.mjs.map +1 -0
- package/lib/browser/decorators/injectable.decorator.d.mts +38 -0
- package/lib/browser/decorators/injectable.decorator.d.mts.map +1 -0
- package/lib/browser/decorators/injectable.decorator.mjs +21 -0
- package/lib/browser/decorators/injectable.decorator.mjs.map +1 -0
- package/lib/browser/enums/injectable-scope.enum.d.mts +18 -0
- package/lib/browser/enums/injectable-scope.enum.d.mts.map +1 -0
- package/lib/browser/enums/injectable-scope.enum.mjs +20 -0
- package/lib/browser/enums/injectable-scope.enum.mjs.map +1 -0
- package/lib/browser/enums/injectable-type.enum.d.mts +8 -0
- package/lib/browser/enums/injectable-type.enum.d.mts.map +1 -0
- package/lib/browser/enums/injectable-type.enum.mjs +10 -0
- package/lib/browser/enums/injectable-type.enum.mjs.map +1 -0
- package/lib/browser/errors/di-error.d.mts +43 -0
- package/lib/browser/errors/di-error.d.mts.map +1 -0
- package/lib/browser/errors/di-error.mjs +98 -0
- package/lib/browser/errors/di-error.mjs.map +1 -0
- package/lib/browser/event-emitter.d.mts +16 -0
- package/lib/browser/event-emitter.d.mts.map +1 -0
- package/lib/browser/event-emitter.mjs +320 -0
- package/lib/browser/event-emitter.mjs.map +1 -0
- package/lib/browser/index.d.mts +37 -1508
- package/lib/browser/index.mjs +29 -2650
- package/lib/browser/interfaces/container.interface.d.mts +59 -0
- package/lib/browser/interfaces/container.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/factory.interface.d.mts +14 -0
- package/lib/browser/interfaces/factory.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/on-service-destroy.interface.d.mts +7 -0
- package/lib/browser/interfaces/on-service-destroy.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/on-service-init.interface.d.mts +7 -0
- package/lib/browser/interfaces/on-service-init.interface.d.mts.map +1 -0
- package/lib/browser/internal/context/async-local-storage.browser.mjs +20 -0
- package/lib/browser/internal/context/async-local-storage.browser.mjs.map +1 -0
- package/lib/browser/internal/context/async-local-storage.d.mts +9 -0
- package/lib/browser/internal/context/async-local-storage.d.mts.map +1 -0
- package/lib/browser/internal/context/async-local-storage.types.d.mts +11 -0
- package/lib/browser/internal/context/async-local-storage.types.d.mts.map +1 -0
- package/lib/browser/internal/context/factory-context.d.mts +23 -0
- package/lib/browser/internal/context/factory-context.d.mts.map +1 -0
- package/lib/browser/internal/context/resolution-context.d.mts +43 -0
- package/lib/browser/internal/context/resolution-context.d.mts.map +1 -0
- package/lib/browser/internal/context/resolution-context.mjs +56 -0
- package/lib/browser/internal/context/resolution-context.mjs.map +1 -0
- package/lib/browser/internal/context/service-initialization-context.d.mts +48 -0
- package/lib/browser/internal/context/service-initialization-context.d.mts.map +1 -0
- package/lib/browser/internal/context/sync-local-storage.mjs +53 -0
- package/lib/browser/internal/context/sync-local-storage.mjs.map +1 -0
- package/lib/browser/internal/core/instance-resolver.d.mts +119 -0
- package/lib/browser/internal/core/instance-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/instance-resolver.mjs +306 -0
- package/lib/browser/internal/core/instance-resolver.mjs.map +1 -0
- package/lib/browser/internal/core/name-resolver.d.mts +52 -0
- package/lib/browser/internal/core/name-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/name-resolver.mjs +118 -0
- package/lib/browser/internal/core/name-resolver.mjs.map +1 -0
- package/lib/browser/internal/core/scope-tracker.d.mts +65 -0
- package/lib/browser/internal/core/scope-tracker.d.mts.map +1 -0
- package/lib/browser/internal/core/scope-tracker.mjs +120 -0
- package/lib/browser/internal/core/scope-tracker.mjs.map +1 -0
- package/lib/browser/internal/core/service-initializer.d.mts +44 -0
- package/lib/browser/internal/core/service-initializer.d.mts.map +1 -0
- package/lib/browser/internal/core/service-initializer.mjs +109 -0
- package/lib/browser/internal/core/service-initializer.mjs.map +1 -0
- package/lib/browser/internal/core/service-invalidator.d.mts +81 -0
- package/lib/browser/internal/core/service-invalidator.d.mts.map +1 -0
- package/lib/browser/internal/core/service-invalidator.mjs +142 -0
- package/lib/browser/internal/core/service-invalidator.mjs.map +1 -0
- package/lib/browser/internal/core/token-resolver.d.mts +54 -0
- package/lib/browser/internal/core/token-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/token-resolver.mjs +77 -0
- package/lib/browser/internal/core/token-resolver.mjs.map +1 -0
- package/lib/browser/internal/holder/holder-storage.interface.d.mts +99 -0
- package/lib/browser/internal/holder/holder-storage.interface.d.mts.map +1 -0
- package/lib/browser/internal/holder/instance-holder.d.mts +101 -0
- package/lib/browser/internal/holder/instance-holder.d.mts.map +1 -0
- package/lib/browser/internal/holder/instance-holder.mjs +19 -0
- package/lib/browser/internal/holder/instance-holder.mjs.map +1 -0
- package/lib/browser/internal/holder/unified-storage.d.mts +53 -0
- package/lib/browser/internal/holder/unified-storage.d.mts.map +1 -0
- package/lib/browser/internal/holder/unified-storage.mjs +144 -0
- package/lib/browser/internal/holder/unified-storage.mjs.map +1 -0
- package/lib/browser/internal/lifecycle/circular-detector.d.mts +39 -0
- package/lib/browser/internal/lifecycle/circular-detector.d.mts.map +1 -0
- package/lib/browser/internal/lifecycle/circular-detector.mjs +55 -0
- package/lib/browser/internal/lifecycle/circular-detector.mjs.map +1 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts +18 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts.map +1 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs +43 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs.map +1 -0
- package/lib/browser/internal/stub-factory-class.d.mts +14 -0
- package/lib/browser/internal/stub-factory-class.d.mts.map +1 -0
- package/lib/browser/internal/stub-factory-class.mjs +18 -0
- package/lib/browser/internal/stub-factory-class.mjs.map +1 -0
- package/lib/browser/symbols/injectable-token.d.mts +5 -0
- package/lib/browser/symbols/injectable-token.d.mts.map +1 -0
- package/lib/browser/symbols/injectable-token.mjs +6 -0
- package/lib/browser/symbols/injectable-token.mjs.map +1 -0
- package/lib/browser/token/injection-token.d.mts +55 -0
- package/lib/browser/token/injection-token.d.mts.map +1 -0
- package/lib/browser/token/injection-token.mjs +100 -0
- package/lib/browser/token/injection-token.mjs.map +1 -0
- package/lib/browser/token/registry.d.mts +37 -0
- package/lib/browser/token/registry.d.mts.map +1 -0
- package/lib/browser/token/registry.mjs +86 -0
- package/lib/browser/token/registry.mjs.map +1 -0
- package/lib/browser/utils/default-injectors.d.mts +12 -0
- package/lib/browser/utils/default-injectors.d.mts.map +1 -0
- package/lib/browser/utils/default-injectors.mjs +13 -0
- package/lib/browser/utils/default-injectors.mjs.map +1 -0
- package/lib/browser/utils/get-injectable-token.d.mts +9 -0
- package/lib/browser/utils/get-injectable-token.d.mts.map +1 -0
- package/lib/browser/utils/get-injectable-token.mjs +13 -0
- package/lib/browser/utils/get-injectable-token.mjs.map +1 -0
- package/lib/browser/utils/get-injectors.d.mts +55 -0
- package/lib/browser/utils/get-injectors.d.mts.map +1 -0
- package/lib/browser/utils/get-injectors.mjs +121 -0
- package/lib/browser/utils/get-injectors.mjs.map +1 -0
- package/lib/browser/utils/types.d.mts +23 -0
- package/lib/browser/utils/types.d.mts.map +1 -0
- package/lib/{container-Pb_Y4Z4x.mjs → container-8-z89TyQ.mjs} +1269 -1305
- package/lib/container-8-z89TyQ.mjs.map +1 -0
- package/lib/{container-BuAutHGg.d.mts → container-CNiqesCL.d.mts} +600 -569
- package/lib/container-CNiqesCL.d.mts.map +1 -0
- package/lib/{container-DnzgpfBe.cjs → container-CaY2fDuk.cjs} +1287 -1329
- package/lib/container-CaY2fDuk.cjs.map +1 -0
- package/lib/{container-oGTgX2iX.d.cts → container-D-0Ho3qL.d.cts} +601 -565
- package/lib/container-D-0Ho3qL.d.cts.map +1 -0
- package/lib/index.cjs +13 -15
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +58 -223
- package/lib/index.d.cts.map +1 -1
- package/lib/index.d.mts +62 -222
- package/lib/index.d.mts.map +1 -1
- package/lib/index.mjs +5 -6
- package/lib/index.mjs.map +1 -1
- package/lib/testing/index.cjs +569 -311
- package/lib/testing/index.cjs.map +1 -1
- package/lib/testing/index.d.cts +370 -41
- package/lib/testing/index.d.cts.map +1 -1
- package/lib/testing/index.d.mts +370 -41
- package/lib/testing/index.d.mts.map +1 -1
- package/lib/testing/index.mjs +568 -305
- package/lib/testing/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/__tests__/circular-detector.spec.mts +193 -0
- package/src/__tests__/concurrent.spec.mts +368 -0
- package/src/__tests__/container.spec.mts +32 -30
- package/src/__tests__/di-error.spec.mts +351 -0
- package/src/__tests__/e2e.browser.spec.mts +0 -4
- package/src/__tests__/e2e.spec.mts +10 -19
- package/src/__tests__/event-emitter.spec.mts +232 -109
- package/src/__tests__/get-injectors.spec.mts +250 -39
- package/src/__tests__/injection-token.spec.mts +293 -349
- package/src/__tests__/library-findings.spec.mts +8 -8
- package/src/__tests__/registry.spec.mts +358 -210
- package/src/__tests__/resolution-context.spec.mts +255 -0
- package/src/__tests__/scope-tracker.spec.mts +598 -0
- package/src/__tests__/scope-upgrade.spec.mts +808 -0
- package/src/__tests__/scoped-container.spec.mts +595 -0
- package/src/__tests__/test-container.spec.mts +293 -0
- package/src/__tests__/token-resolver.spec.mts +207 -0
- package/src/__tests__/unified-storage.spec.mts +535 -0
- package/src/__tests__/unit-test-container.spec.mts +405 -0
- package/src/__type-tests__/container.spec-d.mts +180 -0
- package/src/__type-tests__/factory.spec-d.mts +15 -3
- package/src/__type-tests__/inject.spec-d.mts +115 -20
- package/src/__type-tests__/injectable.spec-d.mts +69 -52
- package/src/__type-tests__/injection-token.spec-d.mts +176 -0
- package/src/__type-tests__/scoped-container.spec-d.mts +212 -0
- package/src/container/abstract-container.mts +327 -0
- package/src/container/container.mts +142 -170
- package/src/container/scoped-container.mts +126 -208
- package/src/decorators/factory.decorator.mts +16 -11
- package/src/decorators/injectable.decorator.mts +20 -16
- package/src/enums/index.mts +2 -2
- package/src/enums/injectable-scope.enum.mts +1 -0
- package/src/enums/injectable-type.enum.mts +1 -0
- package/src/errors/di-error.mts +96 -0
- package/src/event-emitter.mts +3 -27
- package/src/index.mts +6 -153
- package/src/interfaces/container.interface.mts +13 -0
- package/src/interfaces/factory.interface.mts +1 -1
- package/src/interfaces/index.mts +1 -1
- package/src/internal/context/async-local-storage.mts +3 -2
- package/src/internal/context/async-local-storage.types.mts +1 -0
- package/src/internal/context/factory-context.mts +1 -0
- package/src/internal/context/index.mts +3 -1
- package/src/internal/context/resolution-context.mts +1 -0
- package/src/internal/context/service-initialization-context.mts +43 -0
- package/src/internal/core/index.mts +5 -4
- package/src/internal/core/instance-resolver.mts +461 -292
- package/src/internal/core/name-resolver.mts +196 -0
- package/src/internal/core/scope-tracker.mts +242 -0
- package/src/internal/core/{instantiator.mts → service-initializer.mts} +51 -29
- package/src/internal/core/service-invalidator.mts +290 -0
- package/src/internal/core/{token-processor.mts → token-resolver.mts} +17 -88
- package/src/internal/holder/holder-storage.interface.mts +11 -5
- package/src/internal/holder/index.mts +2 -5
- package/src/internal/holder/instance-holder.mts +1 -3
- package/src/internal/holder/unified-storage.mts +245 -0
- package/src/internal/index.mts +2 -1
- package/src/internal/lifecycle/circular-detector.mts +1 -0
- package/src/internal/lifecycle/index.mts +1 -1
- package/src/internal/lifecycle/lifecycle-event-bus.mts +1 -0
- package/src/internal/stub-factory-class.mts +16 -0
- package/src/symbols/injectable-token.mts +3 -1
- package/src/testing/index.mts +2 -0
- package/src/testing/test-container.mts +546 -85
- package/src/testing/types.mts +117 -0
- package/src/testing/unit-test-container.mts +509 -0
- package/src/token/injection-token.mts +41 -4
- package/src/token/registry.mts +75 -9
- package/src/utils/default-injectors.mts +16 -0
- package/src/utils/get-injectable-token.mts +2 -3
- package/src/utils/get-injectors.mts +26 -15
- package/src/utils/index.mts +3 -1
- package/src/utils/types.mts +1 -0
- package/tsdown.config.mts +11 -1
- package/lib/browser/index.d.mts.map +0 -1
- package/lib/browser/index.mjs.map +0 -1
- package/lib/container-BuAutHGg.d.mts.map +0 -1
- package/lib/container-DnzgpfBe.cjs.map +0 -1
- package/lib/container-Pb_Y4Z4x.mjs.map +0 -1
- package/lib/container-oGTgX2iX.d.cts.map +0 -1
- package/src/__tests__/async-local-storage.browser.spec.mts +0 -166
- package/src/__tests__/async-local-storage.spec.mts +0 -333
- package/src/__tests__/errors.spec.mts +0 -87
- package/src/__tests__/factory.spec.mts +0 -137
- package/src/__tests__/injectable.spec.mts +0 -246
- package/src/__tests__/request-scope.spec.mts +0 -416
- package/src/__tests__/service-instantiator.spec.mts +0 -410
- package/src/__tests__/service-locator-event-bus.spec.mts +0 -242
- package/src/__tests__/service-locator-manager.spec.mts +0 -300
- package/src/__tests__/service-locator.spec.mts +0 -966
- package/src/__tests__/unified-api.spec.mts +0 -130
- package/src/browser.mts +0 -11
- package/src/injectors.mts +0 -18
- package/src/internal/context/request-context.mts +0 -214
- package/src/internal/core/invalidator.mts +0 -437
- package/src/internal/core/service-locator.mts +0 -202
- package/src/internal/holder/base-holder-manager.mts +0 -238
- package/src/internal/holder/holder-manager.mts +0 -85
- package/src/internal/holder/request-storage.mts +0 -134
- package/src/internal/holder/singleton-storage.mts +0 -105
- package/src/testing/README.md +0 -80
- 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
|
-
})
|