DescriptorImpl.ts
105 lines
| 3.0 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r9 | import { Descriptor, ILifetime, DepsMap, IActivationContext, DescriptorMap } from "./interfaces"; | ||
| import { each, key } from "./traits"; | ||||
|
|
r1 | |||
|
|
r9 | export interface DescriptorImplArgs<S, T> { | ||
|
|
r0 | |||
|
|
r14 | readonly lifetime: ILifetime<NonNullable<T>>; | ||
| readonly factory: (refs: Record<key, unknown>) => NonNullable<T>; | ||||
|
|
r0 | |||
|
|
r14 | readonly cleanup?: (item: NonNullable<T>) => void; | ||
|
|
r0 | |||
|
|
r14 | readonly overrides?: DescriptorMap<S>; | ||
|
|
r4 | |||
|
|
r14 | readonly dependencies?: DepsMap<S>; | ||
|
|
r0 | } | ||
|
|
r13 | export const containerSelfDescriptor = <S>() => Object.freeze({ | ||
| level: 0, | ||||
| activate(context: IActivationContext<S>) { | ||||
| return context.createChildContainer(); | ||||
| } | ||||
| }); | ||||
|
|
r1 | |||
|
|
r9 | export class DescriptorImpl<S, T> implements Descriptor<S, T> { | ||
|
|
r0 | |||
|
|
r9 | private readonly _overrides?: DescriptorMap<S>; | ||
|
|
r0 | |||
|
|
r14 | private readonly _lifetime: ILifetime<NonNullable<T>>; | ||
|
|
r0 | |||
|
|
r9 | private readonly _factory: (refs: Record<key, unknown>) => NonNullable<T>; | ||
| private readonly _cleanup?: (item: NonNullable<T>) => void; | ||||
|
|
r0 | |||
|
|
r9 | private readonly _deps?: DepsMap<S>; | ||
|
|
r0 | |||
|
|
r9 | readonly hasOverrides: boolean; | ||
|
|
r4 | |||
| constructor({ lifetime, factory, cleanup, overrides, dependencies }: DescriptorImplArgs<S, T>) { | ||||
| this._lifetime = lifetime; | ||||
| this._factory = factory; | ||||
| if (cleanup) | ||||
| this._cleanup = cleanup; | ||||
| if (overrides) | ||||
| this._overrides = overrides; | ||||
| if (dependencies) | ||||
| this._deps = dependencies; | ||||
|
|
r9 | |||
| this.hasOverrides = !!overrides; | ||||
|
|
r0 | } | ||
|
|
r9 | activate(context: IActivationContext<S>): NonNullable<T> { | ||
|
|
r0 | |||
|
|
r12 | const { has, get, initialize, store } = this._lifetime(context); | ||
|
|
r0 | |||
|
|
r12 | if (has()) | ||
| return get(); | ||||
|
|
r14 | |||
|
|
r12 | initialize(); | ||
|
|
r0 | |||
| if (this._overrides) | ||||
| each(this._overrides, (v, k) => context.register(k, v)); | ||||
|
|
r9 | const resolve = <K extends keyof S>({ name, lazy, ...opts }: { name: K; lazy?: boolean; default?: S[K] | null; }) => { | ||
|
|
r4 | if (lazy) { | ||
|
|
r11 | return "default" in opts ? | ||
| () => context.resolve(name, opts.default) : | ||||
| () => context.resolve(name); | ||||
|
|
r4 | } else { | ||
|
|
r11 | return "default" in opts ? | ||
| context.resolve(name, opts.default) : | ||||
| context.resolve(name); | ||||
|
|
r4 | } | ||
| }; | ||||
|
|
r0 | |||
|
|
r11 | const deps = this._deps; | ||
| const refs = deps ? | ||||
|
|
r4 | Object.keys(deps) | ||
| .map(k => { | ||||
| const ref = deps[k]; | ||||
|
|
r9 | return typeof ref !== "object" ? | ||
|
|
r4 | { [k]: resolve({ name: ref }) } : | ||
| { [k]: resolve(ref) }; | ||||
| }) | ||||
|
|
r11 | .reduce((a, p) => ({ ...a, ...p }), {}) : | ||
|
|
r9 | {}; | ||
|
|
r1 | |||
|
|
r11 | try { | ||
|
|
r12 | // call the factory method | ||
|
|
r14 | const instance = (0, this._factory)(refs); | ||
|
|
r12 | // store the instance | ||
| store(instance, this._cleanup); | ||||
|
|
r11 | return instance; | ||
|
|
r14 | } catch (err) { | ||
|
|
r11 | context.fail(err); | ||
| } | ||||
|
|
r0 | } | ||
|
|
r1 | |||
|
|
r0 | toString() { | ||
|
|
r1 | return `[object DescriptorImpl, lifetime=${String(this._lifetime)}]`; | ||
|
|
r0 | } | ||
| } | ||||
