Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 18x 1425x 11x 1425x 484x 928x 13x | import type { InstanceHolder } from '../holder/instance-holder.mjs'
import type { IAsyncLocalStorage } from './async-local-storage.types.mjs'
import { createAsyncLocalStorage } from './async-local-storage.mjs'
/**
* Data stored in the resolution context during service instantiation.
*/
export interface ResolutionContextData {
/** The holder that is currently being instantiated */
waiterHolder: InstanceHolder
/** Function to get a holder by name (for cycle detection) */
getHolder: (name: string) => InstanceHolder | undefined
}
/**
* AsyncLocalStorage for tracking the current resolution context.
*
* This allows tracking which service is being instantiated even across
* async boundaries (like when inject() is called inside a constructor).
* Essential for circular dependency detection.
*
* The actual implementation varies by environment:
* - Production: No-op (returns undefined, run() just calls fn directly)
* - Development: Real AsyncLocalStorage with full async tracking
* - Browser: SyncLocalStorage for synchronous-only tracking
*/
let resolutionContext: IAsyncLocalStorage<ResolutionContextData> | null = null
function getResolutionContext(): IAsyncLocalStorage<ResolutionContextData> {
if (!resolutionContext) {
resolutionContext = createAsyncLocalStorage<ResolutionContextData>()
}
return resolutionContext
}
/**
* Runs a function within a resolution context.
*
* The context tracks which holder is currently being instantiated,
* allowing circular dependency detection to work correctly.
*
* @param waiterHolder The holder being instantiated
* @param getHolder Function to retrieve holders by name
* @param fn The function to run within the context
*/
export function withResolutionContext<T>(
waiterHolder: InstanceHolder,
getHolder: (name: string) => InstanceHolder | undefined,
fn: () => T,
): T {
return getResolutionContext().run({ waiterHolder, getHolder }, fn)
}
/**
* Gets the current resolution context, if any.
*
* Returns undefined if we're not inside a resolution context
* (e.g., when resolving a top-level service that has no parent).
*/
export function getCurrentResolutionContext():
| ResolutionContextData
| undefined {
return getResolutionContext().getStore()
}
/**
* Runs a function outside any resolution context.
*
* This is useful for async injections that should not participate
* in circular dependency detection since they don't block.
*
* @param fn The function to run without resolution context
*/
export function withoutResolutionContext<T>(fn: () => T): T {
// Run with undefined context to clear any current context
return getResolutionContext().run(
undefined as unknown as ResolutionContextData,
fn,
)
}
|