UNPKG

@travetto/di

Version:

Dependency registration/management and injection support.

79 lines (67 loc) 2.66 kB
import type { RegistryAdapter } from '@travetto/registry'; import { type Class, classConstruct, describeFunction, safeAssign } from '@travetto/runtime'; import { CONSTRUCTOR_PROPERTY, SchemaRegistryIndex } from '@travetto/schema'; import { type InjectableConfig, getDefaultQualifier, type InjectableCandidate } from '../types.ts'; function combineInjectableCandidates<T extends InjectableCandidate>(base: T, ...overrides: Partial<T>[]): typeof base { for (const override of overrides) { safeAssign(base, override); } return base; } function combineClasses<T extends InjectableConfig>(base: T, ...overrides: Partial<T>[]): typeof base { for (const override of overrides) { Object.assign(base, { ...base, ...override, candidates: { ...base.candidates, ...override.candidates, } }); } return base; } export class DependencyRegistryAdapter implements RegistryAdapter<InjectableConfig> { #cls: Class; #config: InjectableConfig; constructor(cls: Class) { this.#cls = cls; } register(...data: Partial<InjectableConfig<unknown>>[]): InjectableConfig<unknown> { this.#config ??= { class: this.#cls, candidates: {} }; return combineClasses(this.#config, ...data); } registerFactory(method: string, ...data: Partial<InjectableCandidate<unknown>>[]): InjectableCandidate { const { candidates } = this.register(); candidates[method] ??= { class: this.#cls, method, enabled: true, factory: undefined!, candidateType: undefined!, }; return combineInjectableCandidates(candidates[method], ...data); } registerClass(...data: Partial<InjectableCandidate<unknown>>[]): InjectableCandidate { return this.registerFactory(CONSTRUCTOR_PROPERTY, ...data, { factory: (...args: unknown[]) => classConstruct(this.#cls, args), candidateType: this.#cls, }); } get(): InjectableConfig<unknown> { return this.#config; } finalize(): void { for (const method of Object.keys(this.#config.candidates)) { const candidate = this.#config.candidates[method]; const candidateType = SchemaRegistryIndex.get(candidate.class).getMethodReturnType(method); candidate.candidateType = candidateType; candidate.qualifier ??= getDefaultQualifier(candidateType); } } getCandidateConfigs(): InjectableCandidate[] { return Object.values(this.#config.candidates) .filter(item => (item.enabled ?? true) === true || (typeof item.enabled === 'function' && item.enabled())) .filter(item => item.method !== CONSTRUCTOR_PROPERTY || !describeFunction(item.candidateType)?.abstract); } }