@sustain/core
Version:
Sustain is a Framework that is barely used despedcies to make stable and sustainable apps
83 lines • 3.42 kB
JavaScript
;
// 2018-2019 Darcy Rayner
// 2019 Labidi Aymen (labidi@aymen.co)
Object.defineProperty(exports, "__esModule", { value: true });
exports.Container = void 0;
const provider_1 = require("./provider");
const injectable_1 = require("./injectable");
require("reflect-metadata");
const inject_1 = require("./inject");
const REFLECT_PARAMS = 'design:paramtypes';
class Container {
constructor() {
this.providers = new Map();
}
addProvider(provider) {
this.assertInjectableIfClassProvider(provider);
this.providers.set(provider.provide, provider);
}
inject(type) {
let provider = this.providers.get(type);
if (provider === undefined && !(type instanceof provider_1.InjectionToken)) {
provider = { provide: type, useClass: type };
this.assertInjectableIfClassProvider(provider);
}
return this.injectWithProvider(type, provider);
}
get(type) {
return this.providers.get(type).provide;
}
injectWithProvider(type, provider) {
if (provider === undefined) {
throw new Error(`No provider for type ${this.getTokenName(type)}`);
}
if (provider_1.isClassProvider(provider)) {
return this.injectClass(provider);
}
else if (provider_1.isValueProvider(provider)) {
return this.injectValue(provider);
}
else {
// Factory provider by process of elimination
return this.injectFactory(provider);
}
}
assertInjectableIfClassProvider(provider) {
if (provider_1.isClassProvider(provider) && !injectable_1.isInjectable(provider.useClass)) {
throw new Error(`Cannot provide ${this.getTokenName(provider.provide)} using class ${this.getTokenName(provider.useClass)}, ${this.getTokenName(provider.useClass)} isn't injectable`);
}
}
injectClass(classProvider) {
const target = classProvider.useClass;
const params = this.getInjectedParams(target);
return Reflect.construct(target, params);
}
injectValue(valueProvider) {
return valueProvider.useValue;
}
injectFactory(valueProvider) {
return valueProvider.useFactory();
}
getInjectedParams(target) {
const argTypes = Reflect.getMetadata(REFLECT_PARAMS, target);
if (argTypes === undefined) {
return [];
}
return argTypes.map((argType, index) => {
// The reflect-metadata API fails on circular dependencies, and will return undefined
// for the argument instead.
if (argType === undefined) {
throw new Error(`Injection error. Recursive dependency detected in constructor for type ${target.name} with parameter at index ${index}`);
}
const overrideToken = inject_1.getInjectionToken(target, index);
const actualToken = overrideToken === undefined ? argType : overrideToken;
let provider = this.providers.get(actualToken);
return this.injectWithProvider(actualToken, provider);
});
}
getTokenName(token) {
return token instanceof provider_1.InjectionToken ? token.injectionIdentifier : token.name;
}
}
exports.Container = Container;
//# sourceMappingURL=container.js.map