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.
82 lines (81 loc) • 2.7 kB
JavaScript
import { isDependencyKey } from '../container/IContainer';
import { Provider } from '../provider/Provider';
import { DependencyMissingKeyError } from '../errors/DependencyMissingKeyError';
import { isProviderPipe } from './IRegistration';
import { getTransformers } from './IRegistration';
import { SingleToken } from '../token/SingleToken';
import { pipe } from '../utils/fp';
import { Is } from '../utils/basic';
export class Registration {
createProvider;
key;
scopeRules;
static fromClass(Target, { name } = {}) {
const transform = pipe(...getTransformers(Target));
return transform(new Registration(() => Provider.fromClass(Target), name ?? Target.name));
}
static fromValue(value) {
if (Is.constructor(value)) {
const transform = pipe(...getTransformers(value));
return transform(new Registration(() => Provider.fromValue(value), value.name));
}
return new Registration(() => Provider.fromValue(value));
}
static fromFn(fn) {
return new Registration(() => new Provider(fn));
}
static fromKey(key) {
return new Registration(() => Provider.fromKey(key));
}
mappers = [];
aliases = new Set();
constructor(createProvider, key, scopeRules = []) {
this.createProvider = createProvider;
this.key = key;
this.scopeRules = scopeRules;
}
bindToKey(key) {
this.key = key;
return this;
}
bindToAlias(alias) {
this.aliases.add(alias);
return this;
}
pipe(...mappers) {
const fns = mappers.map((m) => (isProviderPipe(m) ? m.mapProvider.bind(m) : m));
this.mappers.push(...fns);
return this;
}
when(...predicates) {
this.scopeRules.push(...predicates);
return this;
}
bindTo(key) {
if (isDependencyKey(key)) {
new SingleToken(key).bindTo(this);
return this;
}
key.bindTo(this);
return this;
}
matchScope(container) {
return this.scopeRules.reduce((prev, curr) => curr(container, prev), true);
}
applyTo(container) {
if (!this.matchScope(container)) {
return;
}
if (!this.key) {
throw new DependencyMissingKeyError('No key provided for registration');
}
const provider = this.mappers.reduce((p, m) => m(p), this.createProvider());
container.register(this.key, provider, { aliases: [...this.aliases] });
}
getKeyOrFail() {
if (!this.key) {
throw new DependencyMissingKeyError('No key provided for registration');
}
return this.key;
}
}