UNPKG

injection-js

Version:

Dependency Injection library for JavaScript and TypeScript

328 lines 11.7 kB
/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { Injector, THROW_IF_NOT_FOUND } from './injector'; import { Self, SkipSelf } from './metadata'; import { cyclicDependencyError, instantiationError, noProviderError, outOfBoundsError } from './reflective_errors'; import { ReflectiveKey } from './reflective_key'; import { resolveReflectiveProviders, } from './reflective_provider'; // Threshold for the dynamic version var UNDEFINED = new Object(); /** * A ReflectiveDependency injection container used for instantiating objects and resolving * dependencies. * * An `Injector` is a replacement for a `new` operator, which can automatically resolve the * constructor dependencies. * * In typical use, application code asks for the dependencies in the constructor and they are * resolved by the `Injector`. * * ### Example ([live demo](http://plnkr.co/edit/jzjec0?p=preview)) * * The following example creates an `Injector` configured to create `Engine` and `Car`. * * ```typescript * @Injectable() * class Engine { * } * * @Injectable() * class Car { * constructor(public engine:Engine) {} * } * * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]); * var car = injector.get(Car); * expect(car instanceof Car).toBe(true); * expect(car.engine instanceof Engine).toBe(true); * ``` * * Notice, we don't use the `new` operator because we explicitly want to have the `Injector` * resolve all of the object's dependencies automatically. * * @stable */ var ReflectiveInjector = /** @class */ (function () { function ReflectiveInjector() { } /** * Turns an array of provider definitions into an array of resolved providers. * * A resolution is a process of flattening multiple nested arrays and converting individual * providers into an array of {@link ResolvedReflectiveProvider}s. * * ### Example ([live demo](http://plnkr.co/edit/AiXTHi?p=preview)) * * ```typescript * @Injectable() * class Engine { * } * * @Injectable() * class Car { * constructor(public engine:Engine) {} * } * * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]); * * expect(providers.length).toEqual(2); * * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true); * expect(providers[0].key.displayName).toBe("Car"); * expect(providers[0].dependencies.length).toEqual(1); * expect(providers[0].factory).toBeDefined(); * * expect(providers[1].key.displayName).toBe("Engine"); * }); * ``` * * See {@link ReflectiveInjector#fromResolvedProviders} for more info. */ ReflectiveInjector.resolve = function (providers) { return resolveReflectiveProviders(providers); }; /** * Resolves an array of providers and creates an injector from those providers. * * The passed-in providers can be an array of `Type`, {@link Provider}, * or a recursive array of more providers. * * ### Example ([live demo](http://plnkr.co/edit/ePOccA?p=preview)) * * ```typescript * @Injectable() * class Engine { * } * * @Injectable() * class Car { * constructor(public engine:Engine) {} * } * * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]); * expect(injector.get(Car) instanceof Car).toBe(true); * ``` * * This function is slower than the corresponding `fromResolvedProviders` * because it needs to resolve the passed-in providers first. * See {@link Injector#resolve} and {@link Injector#fromResolvedProviders}. */ ReflectiveInjector.resolveAndCreate = function (providers, parent) { var ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers); return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent); }; /** * Creates an injector from previously resolved providers. * * This API is the recommended way to construct injectors in performance-sensitive parts. * * ### Example ([live demo](http://plnkr.co/edit/KrSMci?p=preview)) * * ```typescript * @Injectable() * class Engine { * } * * @Injectable() * class Car { * constructor(public engine:Engine) {} * } * * var providers = ReflectiveInjector.resolve([Car, Engine]); * var injector = ReflectiveInjector.fromResolvedProviders(providers); * expect(injector.get(Car) instanceof Car).toBe(true); * ``` * @experimental */ ReflectiveInjector.fromResolvedProviders = function (providers, parent) { // tslint:disable-next-line:no-use-before-declare return new ReflectiveInjector_(providers, parent); }; return ReflectiveInjector; }()); export { ReflectiveInjector }; // tslint:disable-next-line:class-name var ReflectiveInjector_ = /** @class */ (function () { /** * Private */ function ReflectiveInjector_(_providers, _parent) { /** @internal */ this._constructionCounter = 0; this._providers = _providers; this._parent = _parent || null; var len = _providers.length; this.keyIds = new Array(len); this.objs = new Array(len); for (var i = 0; i < len; i++) { this.keyIds[i] = _providers[i].key.id; this.objs[i] = UNDEFINED; } } ReflectiveInjector_.prototype.get = function (token, notFoundValue) { if (notFoundValue === void 0) { notFoundValue = THROW_IF_NOT_FOUND; } return this._getByKey(ReflectiveKey.get(token), null, notFoundValue); }; Object.defineProperty(ReflectiveInjector_.prototype, "parent", { get: function () { return this._parent; }, enumerable: false, configurable: true }); ReflectiveInjector_.prototype.resolveAndCreateChild = function (providers) { var ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers); return this.createChildFromResolved(ResolvedReflectiveProviders); }; ReflectiveInjector_.prototype.createChildFromResolved = function (providers) { var inj = new ReflectiveInjector_(providers); inj._parent = this; return inj; }; ReflectiveInjector_.prototype.resolveAndInstantiate = function (provider) { return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]); }; ReflectiveInjector_.prototype.instantiateResolved = function (provider) { return this._instantiateProvider(provider); }; ReflectiveInjector_.prototype.getProviderAtIndex = function (index) { if (index < 0 || index >= this._providers.length) { throw outOfBoundsError(index); } return this._providers[index]; }; /** @internal */ ReflectiveInjector_.prototype._new = function (provider) { if (this._constructionCounter++ > this._getMaxNumberOfObjects()) { throw cyclicDependencyError(this, provider.key); } return this._instantiateProvider(provider); }; ReflectiveInjector_.prototype._getMaxNumberOfObjects = function () { return this.objs.length; }; ReflectiveInjector_.prototype._instantiateProvider = function (provider) { if (provider.multiProvider) { var res = new Array(provider.resolvedFactories.length); for (var i = 0; i < provider.resolvedFactories.length; ++i) { res[i] = this._instantiate(provider, provider.resolvedFactories[i]); } return res; } else { return this._instantiate(provider, provider.resolvedFactories[0]); } }; ReflectiveInjector_.prototype._instantiate = function (provider, ResolvedReflectiveFactory) { var _this = this; var factory = ResolvedReflectiveFactory.factory; var deps; try { deps = ResolvedReflectiveFactory.dependencies.map(function (dep) { return _this._getByReflectiveDependency(dep); }); } catch (e) { if (e.addKey) { e.addKey(this, provider.key); } throw e; } var obj; try { obj = factory.apply(void 0, deps); } catch (e) { throw instantiationError(this, e, e.stack, provider.key); } return obj; }; ReflectiveInjector_.prototype._getByReflectiveDependency = function (dep) { return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND); }; ReflectiveInjector_.prototype._getByKey = function (key, visibility, notFoundValue) { // tslint:disable-next-line:no-use-before-declare if (key === INJECTOR_KEY) { return this; } if (visibility instanceof Self) { return this._getByKeySelf(key, notFoundValue); } else { return this._getByKeyDefault(key, notFoundValue, visibility); } }; ReflectiveInjector_.prototype._getObjByKeyId = function (keyId) { for (var i = 0; i < this.keyIds.length; i++) { if (this.keyIds[i] === keyId) { if (this.objs[i] === UNDEFINED) { this.objs[i] = this._new(this._providers[i]); } return this.objs[i]; } } return UNDEFINED; }; /** @internal */ ReflectiveInjector_.prototype._throwOrNull = function (key, notFoundValue) { if (notFoundValue !== THROW_IF_NOT_FOUND) { return notFoundValue; } else { throw noProviderError(this, key); } }; /** @internal */ ReflectiveInjector_.prototype._getByKeySelf = function (key, notFoundValue) { var obj = this._getObjByKeyId(key.id); return obj !== UNDEFINED ? obj : this._throwOrNull(key, notFoundValue); }; /** @internal */ ReflectiveInjector_.prototype._getByKeyDefault = function (key, notFoundValue, visibility) { var inj; if (visibility instanceof SkipSelf) { inj = this._parent; } else { inj = this; } while (inj instanceof ReflectiveInjector_) { var inj_ = inj; var obj = inj_._getObjByKeyId(key.id); if (obj !== UNDEFINED) return obj; inj = inj_._parent; } if (inj !== null) { return inj.get(key.token, notFoundValue); } else { return this._throwOrNull(key, notFoundValue); } }; Object.defineProperty(ReflectiveInjector_.prototype, "displayName", { get: function () { var providers = _mapProviders(this, function (b) { return ' "' + b.key.displayName + '" '; }).join(', '); return "ReflectiveInjector(providers: [" + providers + "])"; }, enumerable: false, configurable: true }); ReflectiveInjector_.prototype.toString = function () { return this.displayName; }; return ReflectiveInjector_; }()); export { ReflectiveInjector_ }; var INJECTOR_KEY = ReflectiveKey.get(Injector); function _mapProviders(injector, fn) { var res = new Array(injector._providers.length); for (var i = 0; i < injector._providers.length; ++i) { res[i] = fn(injector.getProviderAtIndex(i)); } return res; } //# sourceMappingURL=reflective_injector.js.map