UNPKG

ts-ioc-container

Version:

Fast, lightweight TypeScript dependency injection container with a clean API, scoped lifecycles, decorators, tokens, hooks, lazy injection, customizable providers, and no global container objects.

77 lines (76 loc) 2.62 kB
import { CannonSingletonApplyTwiceError } from '../errors/CannonSingletonApplyTwiceError'; import { ProviderDisposedError } from '../errors/ProviderDisposedError'; export class Provider { resolveDependency; static fromClass(Target) { return new Provider((container, options) => container.resolve(Target, options)); } static fromValue(value) { return new Provider(() => value); } static fromKey(key) { return new Provider((c) => c.resolve(key)); } argsFnList = []; accessRules = []; mappers = []; isLazy = false; cache = new Map(); getKey; isDisposed = false; constructor(resolveDependency) { this.resolveDependency = resolveDependency; } resolve(scope, options) { ProviderDisposedError.assert(!this.isDisposed, 'Provider is already disposed'); if (!this.getKey) { return this.resolveDep(scope, options); } const key = this.getKey(...(options.args ?? [])); if (!this.cache.has(key)) { this.cache.set(key, this.resolveDep(scope, options)); } return this.cache.get(key); } resolveDep(scope, { args = [], lazy } = {}) { const dependency = this.resolveDependency(scope, { args: this.argsFnList.reduce((acc, current) => current(scope, { args: acc }), args), lazy: lazy ?? this.isLazy, }); return this.mappers.reduce((acc, current) => current(acc, scope), dependency); } map(...mappers) { this.mappers.push(...mappers); return this; } addAccessRule(...rules) { this.accessRules.push(...rules); return this; } lazy() { this.isLazy = true; return this; } addArgsFn(...fns) { this.argsFnList.push(...fns); return this; } hasAccess(options) { ProviderDisposedError.assert(!this.isDisposed, 'Provider is already disposed'); return this.accessRules.reduce((acc, rule) => rule(options, acc), true); } singleton(getCacheKey = () => '1') { CannonSingletonApplyTwiceError.assert(!this.getKey, 'Provider is already singleton'); this.getKey = getCacheKey; return this; } dispose() { ProviderDisposedError.assert(!this.isDisposed, 'Provider is already disposed'); this.isDisposed = true; this.getKey = undefined; this.cache.clear(); this.accessRules.splice(0, this.accessRules.length); this.mappers.splice(0, this.mappers.length); this.argsFnList.splice(0, this.argsFnList.length); } }