diff --git a/src/container.ts b/src/container.ts index f7a95df..b7f953d 100644 --- a/src/container.ts +++ b/src/container.ts @@ -1,5 +1,5 @@ import {type InjectionConfig, isConfigLike} from './config' -import {assert, ErrorMessage, expectNever, invariant} from './errors' +import {assert, ErrorMessage, expectNever} from './errors' import type {Injections} from './injection' import {useInjectionContext, withInjectionContext} from './injection-context' import {getMetadata} from './metadata' @@ -179,59 +179,41 @@ export class Container { } #resolveScopedInstance({token, scope = this.defaultScope}: InjectionConfig, instantiate: () => T): T { - let resolvedScope = scope - let context = useInjectionContext() - if (context) { - if (context.container != this) { - return withInjectionContext({ - container: this, - resolution: { - ...context.resolution, - instances: new Map(), - }, - }, () => this.#resolveScopedInstance({token, scope}, instantiate)) - } - const resolution = context.resolution - if (resolution.stack.has(token)) { - if (resolution.dependents.has(token)) { - return resolution.dependents.get(token) - } - assert(false, ErrorMessage.CircularDependency, token.name) - } - if (resolvedScope == InjectionScope.Inherited) { - const dependentFrame = resolution.stack.peek() - invariant(dependentFrame) - resolvedScope = dependentFrame.scope - } - } - else { - if (resolvedScope == InjectionScope.Inherited) { - resolvedScope = InjectionScope.Transient - } - context = { + const context = useInjectionContext() + + if (!context || context.container != this) { + return withInjectionContext({ container: this, resolution: { stack: new Stack(), instances: new Map(), dependents: new Map(), }, - } + }, () => this.#resolveScopedInstance({token, scope}, instantiate)) } - const instantiateWithContext = () => { - const hasContext = !!useInjectionContext() - if (hasContext) { - return instantiate() + + const resolution = context.resolution + + if (resolution.stack.has(token)) { + if (resolution.dependents.has(token)) { + return resolution.dependents.get(token) } - return withInjectionContext(context, instantiate) + assert(false, ErrorMessage.CircularDependency, token.name) } - const resolution = context.resolution + + let resolvedScope = scope + if (resolvedScope == InjectionScope.Inherited) { + const dependentFrame = resolution.stack.peek() + resolvedScope = dependentFrame?.scope || InjectionScope.Transient + } + resolution.stack.push(token, {token, scope: resolvedScope}) try { if (resolvedScope == InjectionScope.Container) { if (this.#instanceCache.has(token)) { return this.#instanceCache.get(token) } - const instance = instantiateWithContext() + const instance = instantiate() this.#instanceCache.set(token, instance) return instance } @@ -239,17 +221,17 @@ export class Container { if (resolution.instances.has(token)) { return resolution.instances.get(token) } - const instance = instantiateWithContext() + const instance = instantiate() resolution.instances.set(token, instance) return instance } else if (resolvedScope == InjectionScope.Transient) { - return instantiateWithContext() + return instantiate() } + expectNever(resolvedScope) } finally { resolution.stack.pop() } - expectNever(resolvedScope) } } diff --git a/src/errors.ts b/src/errors.ts index 5dbde59..90bdd65 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -2,6 +2,7 @@ export const ErrorMessage = { ReservedToken: 'reserved token:', UnresolvableToken: 'unresolvable token:', CircularDependency: 'circular dependency:', + InvariantViolation: 'invariant violation', InjectOutsideOfContext: 'inject outside of context', } as const @@ -11,12 +12,6 @@ export function assert(condition: unknown, ...args: any[]): asserts condition { } } -export function invariant(condition: unknown): asserts condition { - if (!condition) { - throw new Error('invariant violation') - } -} - export function expectNever(value: never): never { throw new TypeError('unexpected value: ' + value) } diff --git a/src/inject.ts b/src/inject.ts index de2bd84..4688469 100644 --- a/src/inject.ts +++ b/src/inject.ts @@ -1,4 +1,4 @@ -import {assert, ErrorMessage, invariant} from './errors' +import {assert, ErrorMessage} from './errors' import type {Injections} from './injection' import {useInjectionContext} from './injection-context' @@ -15,7 +15,7 @@ export namespace inject { assert(context, ErrorMessage.InjectOutsideOfContext) const resolution = context.resolution const currentFrame = resolution.stack.peek() - invariant(currentFrame) + assert(currentFrame, ErrorMessage.InvariantViolation) resolution.dependents.set(currentFrame.token, thisArg) try { return inject(...injections)