123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- var __extends = (this && this.__extends) || (function () {
- var extendStatics = function (d, b) {
- extendStatics = Object.setPrototypeOf ||
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
- return extendStatics(d, b);
- };
- return function (d, b) {
- if (typeof b !== "function" && b !== null)
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
- extendStatics(d, b);
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
- };
- })();
- var __assign = (this && this.__assign) || function () {
- __assign = Object.assign || function(t) {
- for (var s, i = 1, n = arguments.length; i < n; i++) {
- s = arguments[i];
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
- t[p] = s[p];
- }
- return t;
- };
- return __assign.apply(this, arguments);
- };
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
- if (ar || !(i in from)) {
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
- ar[i] = from[i];
- }
- }
- return to.concat(ar || Array.prototype.slice.call(from));
- };
- import { getDependencies } from './decorators';
- import { DependencyCollection, DependencyNotFoundError, DependencyNotFoundForModuleError, ResolvedDependencyCollection, clearResolvingStack, popupResolvingStack, pushResolvingStack, } from './dependencyCollection';
- import { normalizeFactoryDeps } from './dependencyDescriptor';
- import { normalizeForwardRef } from './dependencyForwardRef';
- import { isAsyncDependencyItem, isAsyncHook, isClassDependencyItem, isCtor, isFactoryDependencyItem, isValueDependencyItem, prettyPrintIdentifier, AsyncHookSymbol, isExistingDependencyItem, } from './dependencyItem';
- import { RediError } from './error';
- import { IdleValue } from './idleValue';
- import { LookUp, Quantity } from './types';
- var MAX_RESOLUTIONS_QUEUED = 300;
- var NotInstantiatedSymbol = Symbol('$$NOT_INSTANTIATED_SYMBOL');
- var CircularDependencyError = /** @class */ (function (_super) {
- __extends(CircularDependencyError, _super);
- function CircularDependencyError(id) {
- return _super.call(this, "Detecting cyclic dependency. The last identifier is \"".concat(prettyPrintIdentifier(id), "\".")) || this;
- }
- return CircularDependencyError;
- }(RediError));
- var InjectorAlreadyDisposedError = /** @class */ (function (_super) {
- __extends(InjectorAlreadyDisposedError, _super);
- function InjectorAlreadyDisposedError() {
- return _super.call(this, 'Injector cannot be accessed after it was disposed.') || this;
- }
- return InjectorAlreadyDisposedError;
- }(RediError));
- var AsyncItemReturnAsyncItemError = /** @class */ (function (_super) {
- __extends(AsyncItemReturnAsyncItemError, _super);
- function AsyncItemReturnAsyncItemError(id) {
- return _super.call(this, "Async item \"".concat(prettyPrintIdentifier(id), "\" returns another async item.")) || this;
- }
- return AsyncItemReturnAsyncItemError;
- }(RediError));
- var GetAsyncItemFromSyncApiError = /** @class */ (function (_super) {
- __extends(GetAsyncItemFromSyncApiError, _super);
- function GetAsyncItemFromSyncApiError(id) {
- return _super.call(this, "Cannot get async item \"".concat(prettyPrintIdentifier(id), "\" from sync api.")) || this;
- }
- return GetAsyncItemFromSyncApiError;
- }(RediError));
- var AddDependencyAfterResolutionError = /** @class */ (function (_super) {
- __extends(AddDependencyAfterResolutionError, _super);
- function AddDependencyAfterResolutionError(id) {
- return _super.call(this, "Cannot add dependency \"".concat(prettyPrintIdentifier(id), "\" after it is already resolved.")) || this;
- }
- return AddDependencyAfterResolutionError;
- }(RediError));
- var DeleteDependencyAfterResolutionError = /** @class */ (function (_super) {
- __extends(DeleteDependencyAfterResolutionError, _super);
- function DeleteDependencyAfterResolutionError(id) {
- return _super.call(this, "Cannot dependency dependency \"".concat(prettyPrintIdentifier(id), "\" after it is already resolved.")) || this;
- }
- return DeleteDependencyAfterResolutionError;
- }(RediError));
- /**
- *
- */
- var Injector = /** @class */ (function () {
- /**
- * Create a new `Injector` instance
- * @param dependencies Dependencies that should be resolved by this injector instance.
- * @param parent Optional parent injector.
- */
- function Injector(dependencies, parent) {
- if (parent === void 0) { parent = null; }
- this.parent = parent;
- this.children = [];
- this.resolutionOngoing = 0;
- this.disposed = false;
- this.dependencyCollection = new DependencyCollection(dependencies || []);
- this.resolvedDependencyCollection = new ResolvedDependencyCollection();
- if (parent) {
- parent.children.push(this);
- }
- }
- /**
- * Create a child inject with a set of dependencies.
- * @param dependencies Dependencies that should be resolved by the newly created child injector.
- * @returns The child injector.
- */
- Injector.prototype.createChild = function (dependencies) {
- this._ensureInjectorNotDisposed();
- return new Injector(dependencies, this);
- };
- /**
- * Dispose the injector and all dependencies held by this injector. Note that its child injectors will dispose first.
- */
- Injector.prototype.dispose = function () {
- // Dispose child injectors first.
- this.children.forEach(function (c) { return c.dispose(); });
- this.children.length = 0;
- // Call `dispose` method on each instantiated dependencies if they are `IDisposable` and clear collections.
- this.dependencyCollection.dispose();
- this.resolvedDependencyCollection.dispose();
- this.deleteSelfFromParent();
- this.disposed = true;
- };
- Injector.prototype.deleteSelfFromParent = function () {
- if (this.parent) {
- var index = this.parent.children.indexOf(this);
- if (index > -1) {
- this.parent.children.splice(index, 1);
- }
- }
- };
- /**
- * Add a dependency or its instance into injector. It would throw an error if the dependency
- * has already been instantiated.
- *
- * @param dependency The dependency or an instance that would be add in the injector.
- */
- Injector.prototype.add = function (dependency) {
- this._ensureInjectorNotDisposed();
- var identifierOrCtor = dependency[0];
- var item = dependency[1];
- if (this.resolvedDependencyCollection.has(identifierOrCtor)) {
- throw new AddDependencyAfterResolutionError(identifierOrCtor);
- }
- if (typeof item === 'undefined') {
- // Add dependency
- this.dependencyCollection.add(identifierOrCtor);
- }
- else if (isAsyncDependencyItem(item) ||
- isClassDependencyItem(item) ||
- isValueDependencyItem(item) ||
- isFactoryDependencyItem(item)) {
- // Add dependency
- this.dependencyCollection.add(identifierOrCtor, item);
- }
- else {
- // Add instance
- this.resolvedDependencyCollection.add(identifierOrCtor, item);
- }
- };
- /**
- * Replace an injection mapping for interface-based injection. It would throw an error if the dependency
- * has already been instantiated.
- *
- * @param dependency The dependency that will replace the already existed dependency.
- */
- Injector.prototype.replace = function (dependency) {
- this._ensureInjectorNotDisposed();
- var identifier = dependency[0];
- if (this.resolvedDependencyCollection.has(identifier)) {
- throw new AddDependencyAfterResolutionError(identifier);
- }
- this.dependencyCollection.delete(identifier);
- if (dependency.length === 1) {
- this.dependencyCollection.add(identifier);
- }
- else {
- this.dependencyCollection.add(identifier, dependency[1]);
- }
- };
- /**
- * Delete a dependency from an injector. It would throw an error when the deleted dependency
- * has already been instantiated.
- *
- * @param identifier The identifier of the dependency that is supposed to be deleted.
- */
- Injector.prototype.delete = function (identifier) {
- this._ensureInjectorNotDisposed();
- if (this.resolvedDependencyCollection.has(identifier)) {
- throw new DeleteDependencyAfterResolutionError(identifier);
- }
- this.dependencyCollection.delete(identifier);
- };
- /**
- * Invoke a function with dependencies injected. The function could only get dependency from the injector
- * and other methods are not accessible for the function.
- *
- * @param cb the function to be executed
- * @param args arguments to be passed into the function
- * @returns the return value of the function
- */
- Injector.prototype.invoke = function (cb) {
- var _this = this;
- var args = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- args[_i - 1] = arguments[_i];
- }
- this._ensureInjectorNotDisposed();
- var accessor = {
- get: function (id, quantityOrLookup, lookUp) {
- return _this._get(id, quantityOrLookup, lookUp);
- },
- };
- return cb.apply(void 0, __spreadArray([accessor], args, false));
- };
- /**
- * Check if the injector could initialize a dependency.
- *
- * @param id Identifier of the dependency
- */
- Injector.prototype.has = function (id) {
- var _a;
- return this.dependencyCollection.has(id) || ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.has(id)) || false;
- };
- /**
- * Get dependency instance(s).
- *
- * @param id Identifier of the dependency
- * @param quantityOrLookup @link{Quantity} or @link{LookUp}
- * @param lookUp @link{LookUp}
- */
- Injector.prototype.get = function (id, quantityOrLookup, lookUp) {
- this._ensureInjectorNotDisposed();
- try {
- var newResult = this._get(id, quantityOrLookup, lookUp);
- if ((Array.isArray(newResult) && newResult.some(function (r) { return isAsyncHook(r); })) || isAsyncHook(newResult)) {
- throw new GetAsyncItemFromSyncApiError(id);
- }
- return newResult;
- }
- catch (e) {
- if (e instanceof DependencyNotFoundError) {
- clearResolvingStack();
- }
- throw e;
- }
- };
- Injector.prototype._get = function (id, quantityOrLookup, lookUp, toSelf) {
- var quantity = Quantity.REQUIRED;
- if (quantityOrLookup === Quantity.REQUIRED ||
- quantityOrLookup === Quantity.OPTIONAL ||
- quantityOrLookup === Quantity.MANY) {
- quantity = quantityOrLookup;
- }
- else {
- lookUp = quantityOrLookup;
- }
- if (!toSelf) {
- // see if the dependency is already resolved, return it and check quantity
- var cachedResult = this.getValue(id, quantity, lookUp);
- if (cachedResult !== NotInstantiatedSymbol) {
- return cachedResult;
- }
- }
- // see if the dependency can be instantiated by itself or its parent
- return this.createDependency(id, quantity, lookUp, !toSelf);
- };
- /**
- * Get a dependency in the async way.
- */
- Injector.prototype.getAsync = function (id) {
- this._ensureInjectorNotDisposed();
- var cachedResult = this.getValue(id, Quantity.REQUIRED);
- if (cachedResult !== NotInstantiatedSymbol) {
- return Promise.resolve(cachedResult);
- }
- var newResult = this.createDependency(id, Quantity.REQUIRED);
- if (!isAsyncHook(newResult)) {
- return Promise.resolve(newResult);
- }
- return newResult.whenReady();
- };
- /**
- * Instantiate a class. The created instance would not be held by the injector.
- */
- Injector.prototype.createInstance = function (ctor) {
- var customArgs = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- customArgs[_i - 1] = arguments[_i];
- }
- this._ensureInjectorNotDisposed();
- return this._resolveClassImpl.apply(this, __spreadArray([ctor], customArgs, false));
- };
- Injector.prototype._resolveDependency = function (id, item, shouldCache) {
- if (shouldCache === void 0) { shouldCache = true; }
- var result;
- pushResolvingStack(id);
- try {
- if (isValueDependencyItem(item)) {
- result = this._resolveValueDependency(id, item);
- }
- else if (isFactoryDependencyItem(item)) {
- result = this._resolveFactory(id, item, shouldCache);
- }
- else if (isClassDependencyItem(item)) {
- result = this._resolveClass(id, item, shouldCache);
- }
- else if (isExistingDependencyItem(item)) {
- result = this._resolveExisting(id, item);
- }
- else {
- result = this._resolveAsync(id, item);
- }
- popupResolvingStack();
- }
- catch (e) {
- popupResolvingStack();
- throw e;
- }
- return result;
- };
- Injector.prototype._resolveExisting = function (id, item) {
- var thing = this.get(item.useExisting);
- this.resolvedDependencyCollection.add(id, thing);
- return thing;
- };
- Injector.prototype._resolveValueDependency = function (id, item) {
- var thing = item.useValue;
- this.resolvedDependencyCollection.add(id, thing);
- return thing;
- };
- Injector.prototype._resolveClass = function (id, item, shouldCache) {
- var _this = this;
- if (shouldCache === void 0) { shouldCache = true; }
- var ctor = item.useClass;
- var thing;
- if (item.lazy) {
- var idle_1 = new IdleValue(function () {
- _this._ensureInjectorNotDisposed();
- return _this._resolveClassImpl(ctor);
- });
- thing = new Proxy(Object.create(null), {
- get: function (target, key) {
- var _a;
- if (key in target) {
- return target[key]; // such as toString
- }
- // hack checking if it's a async loader
- if (key === 'whenReady') {
- return undefined;
- }
- var hasInstantiated = idle_1.hasRun();
- var thing = idle_1.getValue();
- if (!hasInstantiated) {
- (_a = item.onInstantiation) === null || _a === void 0 ? void 0 : _a.call(item, thing);
- }
- var property = thing[key];
- if (typeof property !== 'function') {
- return property;
- }
- property = property.bind(thing);
- target[key] = property;
- return property;
- },
- set: function (_target, key, value) {
- ;
- idle_1.getValue()[key] = value;
- return true;
- },
- });
- }
- else {
- thing = this._resolveClassImpl(ctor);
- }
- if (id && shouldCache) {
- this.resolvedDependencyCollection.add(id, thing);
- }
- return thing;
- };
- Injector.prototype._resolveClassImpl = function (ctor) {
- var extraParams = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- extraParams[_i - 1] = arguments[_i];
- }
- this.markNewResolution(ctor);
- var declaredDependencies = getDependencies(ctor)
- .sort(function (a, b) { return a.paramIndex - b.paramIndex; })
- .map(function (descriptor) { return (__assign(__assign({}, descriptor), { identifier: normalizeForwardRef(descriptor.identifier) })); });
- var resolvedArgs = [];
- for (var _a = 0, declaredDependencies_1 = declaredDependencies; _a < declaredDependencies_1.length; _a++) {
- var dep = declaredDependencies_1[_a];
- // recursive happens here
- try {
- var thing_1 = this._get(dep.identifier, dep.quantity, dep.lookUp, dep.withNew);
- resolvedArgs.push(thing_1);
- }
- catch (error) {
- if (error instanceof DependencyNotFoundError) {
- throw new DependencyNotFoundForModuleError(ctor, dep.identifier, dep.paramIndex);
- }
- throw error;
- }
- }
- var args = __spreadArray([], extraParams, true);
- var firstDependencyArgIndex = declaredDependencies.length > 0
- ? declaredDependencies[0].paramIndex
- : args.length;
- if (args.length !== firstDependencyArgIndex) {
- console.warn("[redi]: Expect ".concat(firstDependencyArgIndex, " custom parameter(s) of ").concat(ctor.toString(), " but get ").concat(args.length, "."));
- var delta = firstDependencyArgIndex - args.length;
- if (delta > 0) {
- args = __spreadArray(__spreadArray([], args, true), new Array(delta).fill(undefined), true);
- }
- else {
- args = args.slice(0, firstDependencyArgIndex);
- }
- }
- var thing = new (ctor.bind.apply(ctor, __spreadArray(__spreadArray([void 0], args, false), resolvedArgs, false)))();
- this.markResolutionCompleted();
- return thing;
- };
- Injector.prototype._resolveFactory = function (id, item, shouldCache) {
- var _a;
- this.markNewResolution(id);
- var declaredDependencies = normalizeFactoryDeps(item.deps);
- var resolvedArgs = [];
- for (var _i = 0, declaredDependencies_2 = declaredDependencies; _i < declaredDependencies_2.length; _i++) {
- var dep = declaredDependencies_2[_i];
- try {
- var thing_2 = this._get(dep.identifier, dep.quantity, dep.lookUp, dep.withNew);
- resolvedArgs.push(thing_2);
- }
- catch (error) {
- if (error instanceof DependencyNotFoundError) {
- throw new DependencyNotFoundForModuleError(id, dep.identifier, dep.paramIndex);
- }
- throw error;
- }
- }
- var thing = item.useFactory.apply(null, resolvedArgs);
- if (shouldCache) {
- this.resolvedDependencyCollection.add(id, thing);
- }
- this.markResolutionCompleted();
- (_a = item === null || item === void 0 ? void 0 : item.onInstantiation) === null || _a === void 0 ? void 0 : _a.call(item, thing);
- return thing;
- };
- Injector.prototype._resolveAsync = function (id, item) {
- var _this = this;
- var asyncLoader = {
- __symbol: AsyncHookSymbol,
- whenReady: function () { return _this._resolveAsyncImpl(id, item); },
- };
- return asyncLoader;
- };
- Injector.prototype._resolveAsyncImpl = function (id, item) {
- var _this = this;
- return item.useAsync().then(function (thing) {
- // check if another promise has been resolved,
- // do not resolve the async item twice
- var resolvedCheck = _this.getValue(id);
- if (resolvedCheck !== NotInstantiatedSymbol) {
- return resolvedCheck;
- }
- var ret;
- if (Array.isArray(thing)) {
- var item_1 = thing[1];
- if (isAsyncDependencyItem(item_1)) {
- throw new AsyncItemReturnAsyncItemError(id);
- }
- else {
- ret = _this._resolveDependency(id, item_1);
- }
- }
- else if (isCtor(thing)) {
- ret = _this._resolveClassImpl(thing);
- }
- else {
- ret = thing;
- }
- _this.resolvedDependencyCollection.add(id, ret);
- return ret;
- });
- };
- Injector.prototype.getValue = function (id, quantity, lookUp) {
- var _this = this;
- if (quantity === void 0) { quantity = Quantity.REQUIRED; }
- var onSelf = function () {
- if (_this.dependencyCollection.has(id) &&
- !_this.resolvedDependencyCollection.has(id)) {
- return NotInstantiatedSymbol;
- }
- return _this.resolvedDependencyCollection.get(id, quantity);
- };
- var onParent = function () {
- if (_this.parent) {
- return _this.parent.getValue(id, quantity);
- }
- else {
- return NotInstantiatedSymbol;
- }
- };
- if (lookUp === LookUp.SKIP_SELF) {
- return onParent();
- }
- if (lookUp === LookUp.SELF) {
- return onSelf();
- }
- if (this.resolvedDependencyCollection.has(id) ||
- this.dependencyCollection.has(id)) {
- return onSelf();
- }
- return onParent();
- };
- Injector.prototype.createDependency = function (id, quantity, lookUp, shouldCache) {
- var _this = this;
- if (quantity === void 0) { quantity = Quantity.REQUIRED; }
- if (shouldCache === void 0) { shouldCache = true; }
- var onSelf = function () {
- var registrations = _this.dependencyCollection.get(id, quantity);
- var ret = null;
- if (Array.isArray(registrations)) {
- ret = registrations.map(function (dependencyItem) { return _this._resolveDependency(id, dependencyItem, shouldCache); });
- }
- else if (registrations) {
- ret = _this._resolveDependency(id, registrations, shouldCache);
- }
- return ret;
- };
- var onParent = function () {
- if (_this.parent) {
- return _this.parent.createDependency(id, quantity, undefined, shouldCache);
- }
- else {
- if (quantity === Quantity.OPTIONAL) {
- return null;
- }
- pushResolvingStack(id);
- throw new DependencyNotFoundError(id);
- }
- };
- if (lookUp === LookUp.SKIP_SELF) {
- return onParent();
- }
- if (id === Injector) {
- return this;
- }
- if (this.dependencyCollection.has(id)) {
- return onSelf();
- }
- return onParent();
- };
- Injector.prototype.markNewResolution = function (id) {
- this.resolutionOngoing += 1;
- if (this.resolutionOngoing >= MAX_RESOLUTIONS_QUEUED) {
- throw new CircularDependencyError(id);
- }
- };
- Injector.prototype.markResolutionCompleted = function () {
- this.resolutionOngoing -= 1;
- };
- Injector.prototype._ensureInjectorNotDisposed = function () {
- if (this.disposed) {
- throw new InjectorAlreadyDisposedError();
- }
- };
- return Injector;
- }());
- export { Injector };
- //# sourceMappingURL=injector.js.map
|