UNPKG

@launchtray/tsyringe-async

Version:

Lightweight dependency injection container for JavaScript/TypeScript, with asynchronous resolution

397 lines (396 loc) 18.1 kB
import { __awaiter, __generator, __read, __spread, __values } from "tslib"; import { isClassProvider, isFactoryProvider, isNormalToken, isTokenProvider, isValueProvider } from "./providers"; import { isProvider } from "./providers/provider"; import { isTokenDescriptor } from "./providers/injection-token"; import Registry from "./registry"; import Lifecycle from "./types/lifecycle"; import ResolutionContext from "./resolution-context"; import { formatErrorCtor } from "./error-helpers"; import { callInitializers } from "./decorators/initializer"; export var typeInfo = new Map(); var InternalDependencyContainer = (function () { function InternalDependencyContainer(parent) { this.parent = parent; this._registry = new Registry(); } InternalDependencyContainer.prototype.register = function (token, providerOrConstructor, options) { if (options === void 0) { options = { lifecycle: Lifecycle.Transient }; } var provider; if (!isProvider(providerOrConstructor)) { provider = { useClass: providerOrConstructor }; } else { provider = providerOrConstructor; } if (options.lifecycle === Lifecycle.Singleton || options.lifecycle == Lifecycle.ContainerScoped || options.lifecycle == Lifecycle.ResolutionScoped) { if (isValueProvider(provider) || isFactoryProvider(provider)) { throw new Error("Cannot use lifecycle \"" + Lifecycle[options.lifecycle] + "\" with ValueProviders or FactoryProviders"); } } this._registry.set(token, { provider: provider, options: options }); return this; }; InternalDependencyContainer.prototype.registerType = function (from, to) { if (isNormalToken(to)) { return this.register(from, { useToken: to }); } return this.register(from, { useClass: to }); }; InternalDependencyContainer.prototype.registerInstance = function (token, instance) { return this.register(token, { useValue: instance }); }; InternalDependencyContainer.prototype.registerSingleton = function (from, to) { if (isNormalToken(from)) { if (isNormalToken(to)) { return this.register(from, { useToken: to }, { lifecycle: Lifecycle.Singleton }); } else if (to) { return this.register(from, { useClass: to }, { lifecycle: Lifecycle.Singleton }); } throw new Error('Cannot register a type name as a singleton without a "to" token'); } var useClass = from; if (to && !isNormalToken(to)) { useClass = to; } return this.register(from, { useClass: useClass }, { lifecycle: Lifecycle.Singleton }); }; InternalDependencyContainer.prototype.resolve = function (token, context) { if (context === void 0) { context = new ResolutionContext(); } return __awaiter(this, void 0, void 0, function () { var registration, resolved; return __generator(this, function (_a) { switch (_a.label) { case 0: registration = this.getRegistration(token); if (!registration && isNormalToken(token)) { throw new Error("Attempted to resolve unregistered dependency token: \"" + token.toString() + "\""); } if (!registration) return [3, 2]; return [4, this.resolveRegistration(registration, context)]; case 1: return [2, _a.sent()]; case 2: return [4, this.construct(token, context)]; case 3: resolved = _a.sent(); return [4, callInitializers(this, resolved)]; case 4: _a.sent(); return [2, resolved]; } }); }); }; InternalDependencyContainer.prototype.resolveRegistration = function (registration, context) { if (registration.options.lifecycle === Lifecycle.ResolutionScoped && context.scopedResolutions.has(registration)) { return context.scopedResolutions.get(registration); } var resolutionPromise = this.resolveRegistrationHelper(registration, context); if (registration.options.lifecycle === Lifecycle.ResolutionScoped) { context.scopedResolutions.set(registration, resolutionPromise); } return resolutionPromise; }; InternalDependencyContainer.prototype.resolveRegistrationHelper = function (registration, context) { return __awaiter(this, void 0, void 0, function () { var isSingleton, isContainerScoped, returnInstance, resolved, _a, _b, _c, _d, _e, _f; return __generator(this, function (_g) { switch (_g.label) { case 0: isSingleton = registration.options.lifecycle === Lifecycle.Singleton; isContainerScoped = registration.options.lifecycle === Lifecycle.ContainerScoped; returnInstance = isSingleton || isContainerScoped; if (!isValueProvider(registration.provider)) return [3, 1]; resolved = registration.provider.useValue; return [3, 17]; case 1: if (!isTokenProvider(registration.provider)) return [3, 7]; if (!returnInstance) return [3, 4]; _b = registration.instance; if (_b) return [3, 3]; _c = registration; return [4, this.resolve(registration.provider.useToken, context)]; case 2: _b = (_c.instance = _g.sent()); _g.label = 3; case 3: _a = _b; return [3, 6]; case 4: return [4, this.resolve(registration.provider.useToken, context)]; case 5: _a = _g.sent(); _g.label = 6; case 6: resolved = _a; return [3, 17]; case 7: if (!isClassProvider(registration.provider)) return [3, 13]; if (!returnInstance) return [3, 10]; _e = registration.instance; if (_e) return [3, 9]; _f = registration; return [4, this.construct(registration.provider.useClass, context)]; case 8: _e = (_f.instance = _g.sent()); _g.label = 9; case 9: _d = _e; return [3, 12]; case 10: return [4, this.construct(registration.provider.useClass, context)]; case 11: _d = _g.sent(); _g.label = 12; case 12: resolved = _d; return [3, 17]; case 13: if (!isFactoryProvider(registration.provider)) return [3, 15]; return [4, registration.provider.useFactory(this)]; case 14: resolved = _g.sent(); return [3, 17]; case 15: return [4, this.construct(registration.provider, context)]; case 16: resolved = _g.sent(); _g.label = 17; case 17: return [4, callInitializers(this, resolved)]; case 18: _g.sent(); return [2, resolved]; } }); }); }; InternalDependencyContainer.prototype.resolveAll = function (token, context) { if (context === void 0) { context = new ResolutionContext(); } return __awaiter(this, void 0, void 0, function () { var registrations, instances, registrations_1, registrations_1_1, item, _a, _b, e_1_1, resolved; var e_1, _c; return __generator(this, function (_d) { switch (_d.label) { case 0: registrations = this.getAllRegistrations(token); if (!registrations && isNormalToken(token)) { registrations = []; } if (!registrations) return [3, 9]; instances = []; _d.label = 1; case 1: _d.trys.push([1, 6, 7, 8]); registrations_1 = __values(registrations), registrations_1_1 = registrations_1.next(); _d.label = 2; case 2: if (!!registrations_1_1.done) return [3, 5]; item = registrations_1_1.value; _b = (_a = instances).push; return [4, this.resolveRegistration(item, context)]; case 3: _b.apply(_a, [_d.sent()]); _d.label = 4; case 4: registrations_1_1 = registrations_1.next(); return [3, 2]; case 5: return [3, 8]; case 6: e_1_1 = _d.sent(); e_1 = { error: e_1_1 }; return [3, 8]; case 7: try { if (registrations_1_1 && !registrations_1_1.done && (_c = registrations_1.return)) _c.call(registrations_1); } finally { if (e_1) throw e_1.error; } return [7]; case 8: return [2, instances]; case 9: return [4, this.construct(token, context)]; case 10: resolved = _d.sent(); return [4, callInitializers(this, resolved)]; case 11: _d.sent(); return [2, [resolved]]; } }); }); }; InternalDependencyContainer.prototype.isRegistered = function (token, recursive) { if (recursive === void 0) { recursive = false; } return (this._registry.has(token) || (recursive && (this.parent || false) && this.parent.isRegistered(token, true))); }; InternalDependencyContainer.prototype.reset = function () { this._registry.clear(); }; InternalDependencyContainer.prototype.clearInstances = function () { var e_2, _a; try { for (var _b = __values(this._registry.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), token = _d[0], registrations = _d[1]; this._registry.setAll(token, registrations .filter(function (registration) { return !isValueProvider(registration.provider); }) .map(function (registration) { registration.instance = undefined; return registration; })); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_2) throw e_2.error; } } }; InternalDependencyContainer.prototype.createChildContainer = function () { var e_3, _a; var childContainer = new InternalDependencyContainer(this); try { for (var _b = __values(this._registry.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), token = _d[0], registrations = _d[1]; if (registrations.some(function (_a) { var options = _a.options; return options.lifecycle === Lifecycle.ContainerScoped; })) { childContainer._registry.setAll(token, registrations.map(function (registration) { if (registration.options.lifecycle === Lifecycle.ContainerScoped) { return { provider: registration.provider, options: registration.options }; } return registration; })); } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_3) throw e_3.error; } } return childContainer; }; InternalDependencyContainer.prototype.getRegistration = function (token) { if (this.isRegistered(token)) { return this._registry.get(token); } if (this.parent) { return this.parent.getRegistration(token); } return null; }; InternalDependencyContainer.prototype.getAllRegistrations = function (token) { if (this.isRegistered(token)) { return this._registry.getAll(token); } if (this.parent) { return this.parent.getAllRegistrations(token); } return null; }; InternalDependencyContainer.prototype.construct = function (ctor, context) { return __awaiter(this, void 0, void 0, function () { var paramInfo, idx, params, paramInfo_1, paramInfo_1_1, param, resolver, _a, _b, e_4_1; var e_4, _c; return __generator(this, function (_d) { switch (_d.label) { case 0: if (typeof ctor === "undefined") { throw new Error("Attempted to construct an undefined constructor. Could mean a circular dependency problem."); } if (ctor.length === 0) { return [2, new ctor()]; } paramInfo = typeInfo.get(ctor); if (!paramInfo || paramInfo.length === 0) { throw new Error("TypeInfo not known for \"" + ctor.name + "\""); } idx = 0; params = []; _d.label = 1; case 1: _d.trys.push([1, 6, 7, 8]); paramInfo_1 = __values(paramInfo), paramInfo_1_1 = paramInfo_1.next(); _d.label = 2; case 2: if (!!paramInfo_1_1.done) return [3, 5]; param = paramInfo_1_1.value; resolver = this.resolveParams(context, ctor); _b = (_a = params).push; return [4, resolver(param, idx)]; case 3: _b.apply(_a, [_d.sent()]); idx++; _d.label = 4; case 4: paramInfo_1_1 = paramInfo_1.next(); return [3, 2]; case 5: return [3, 8]; case 6: e_4_1 = _d.sent(); e_4 = { error: e_4_1 }; return [3, 8]; case 7: try { if (paramInfo_1_1 && !paramInfo_1_1.done && (_c = paramInfo_1.return)) _c.call(paramInfo_1); } finally { if (e_4) throw e_4.error; } return [7]; case 8: return [2, new (ctor.bind.apply(ctor, __spread([void 0], params)))()]; } }); }); }; InternalDependencyContainer.prototype.resolveParams = function (context, ctor) { var _this = this; return function (param, idx) { return __awaiter(_this, void 0, void 0, function () { var _a, e_5; return __generator(this, function (_b) { switch (_b.label) { case 0: _b.trys.push([0, 7, , 8]); if (!isTokenDescriptor(param)) return [3, 5]; if (!param.multiple) return [3, 2]; return [4, this.resolveAll(param.token)]; case 1: _a = _b.sent(); return [3, 4]; case 2: return [4, this.resolve(param.token, context)]; case 3: _a = _b.sent(); _b.label = 4; case 4: return [2, _a]; case 5: return [4, this.resolve(param, context)]; case 6: return [2, _b.sent()]; case 7: e_5 = _b.sent(); throw new Error(formatErrorCtor(ctor, idx, e_5)); case 8: return [2]; } }); }); }; }; return InternalDependencyContainer; }()); export var instance = new InternalDependencyContainer(); export default instance;