DescriptorImpl.ts
89 lines
| 2.9 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r15 | import { Descriptor, ILifetime, IActivationContext, DescriptorMap, DescriptorDepsMap } from "../typings/interfaces"; | ||
| import { ActivationError, ActivationItem } from "./ActivationError"; | ||||
|
|
r9 | import { each, key } from "./traits"; | ||
|
|
r1 | |||
|
|
r9 | export interface DescriptorImplArgs<S, T> { | ||
|
|
r0 | |||
|
|
r15 | readonly lifetime: ILifetime<T>; | ||
|
|
r14 | |||
| readonly factory: (refs: Record<key, unknown>) => NonNullable<T>; | ||||
|
|
r0 | |||
|
|
r14 | readonly cleanup?: (item: NonNullable<T>) => void; | ||
|
|
r0 | |||
|
|
r14 | readonly overrides?: DescriptorMap<S>; | ||
|
|
r4 | |||
|
|
r15 | readonly dependencies?: DescriptorDepsMap<S>; | ||
|
|
r0 | } | ||
|
|
r9 | export class DescriptorImpl<S, T> implements Descriptor<S, T> { | ||
|
|
r0 | |||
|
|
r15 | private readonly _overrides: DescriptorMap<S> | undefined; | ||
|
|
r0 | |||
|
|
r15 | private readonly _lifetime: ILifetime<T>; | ||
|
|
r0 | |||
|
|
r9 | private readonly _factory: (refs: Record<key, unknown>) => NonNullable<T>; | ||
|
|
r15 | private readonly _cleanup: (item: NonNullable<T>) => void; | ||
|
|
r0 | |||
|
|
r15 | private readonly _dependencies: DescriptorDepsMap<S> | undefined; | ||
|
|
r4 | |||
| constructor({ lifetime, factory, cleanup, overrides, dependencies }: DescriptorImplArgs<S, T>) { | ||||
| this._lifetime = lifetime; | ||||
| this._factory = factory; | ||||
|
|
r15 | this._cleanup = cleanup ? cleanup : () => { }; | ||
| this._overrides = overrides; | ||||
| this._dependencies = dependencies; | ||||
|
|
r0 | } | ||
|
|
r15 | activate(context: IActivationContext<S>, stack: ActivationItem[]): NonNullable<T> { | ||
|
|
r0 | |||
|
|
r15 | const slot = this._lifetime(context); | ||
| if (slot.has()) | ||||
| return slot.get(); | ||||
| if (!slot.initialize()) | ||||
| throw new Error("Cyclic reference detected"); | ||||
|
|
r0 | |||
|
|
r15 | const instance = this._overrides ? | ||
| context.withOverrides(this._overrides, () => this._activate(context, stack)) : | ||||
| this._activate(context, stack); | ||||
|
|
r14 | |||
|
|
r15 | slot.store(instance, this._cleanup); | ||
|
|
r0 | |||
|
|
r15 | return instance; | ||
| } | ||||
|
|
r0 | |||
|
|
r15 | private _activate(context: IActivationContext<S>, stack: ActivationItem[]) { | ||
| const refs: Record<key, unknown> = {}; | ||||
| if (this._dependencies) { | ||||
| const resolve = <K extends keyof S>({ name, lazy, ...opts }: { name: K; lazy?: boolean; default?: S[K]; }) => { | ||||
| if (lazy) { | ||||
| return "default" in opts ? | ||||
| () => context.resolve(name, stack, opts.default) : | ||||
| () => context.resolve(name, stack); | ||||
| } else { | ||||
| return "default" in opts ? | ||||
| context.resolve(name, stack, opts.default) : | ||||
| context.resolve(name, stack); | ||||
| } | ||||
| }; | ||||
|
|
r0 | |||
|
|
r15 | // can throw activation exception | ||
| each(this._dependencies, (v, k) => { | ||||
| refs[k] = resolve(v); | ||||
| }); | ||||
| } | ||||
|
|
r1 | |||
|
|
r11 | try { | ||
|
|
r12 | // call the factory method | ||
|
|
r15 | return (0, this._factory)(refs); | ||
| } catch (e) { | ||||
| throw new ActivationError("Error creating instance", stack, e); | ||||
|
|
r11 | } | ||
|
|
r0 | } | ||
|
|
r1 | |||
|
|
r0 | toString() { | ||
|
|
r1 | return `[object DescriptorImpl, lifetime=${String(this._lifetime)}]`; | ||
|
|
r0 | } | ||
| } | ||||
