Skip to content

Commit

Permalink
refactor: simply instance resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
exuanbo committed Oct 14, 2024
1 parent bf503dc commit 5c473db
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 50 deletions.
66 changes: 24 additions & 42 deletions src/container.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -179,77 +179,59 @@ export class Container {
}

#resolveScopedInstance<T>({token, scope = this.defaultScope}: InjectionConfig<T>, 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
}
else if (resolvedScope == InjectionScope.Resolution) {
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)
}
}
7 changes: 1 addition & 6 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
}
4 changes: 2 additions & 2 deletions src/inject.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -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)
Expand Down

0 comments on commit 5c473db

Please sign in to comment.