UNPKG

aurelia-dependency-injection

Version:

A lightweight, extensible dependency injection container for JavaScript.

696 lines (681 loc) 25.2 kB
import { metadata, protocol } from 'aurelia-metadata'; import { AggregateError } from 'aurelia-pal'; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol */ function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function __metadata(metadataKey, metadataValue) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); } function __spreadArray(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)); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; function isInjectable(potentialTarget) { return !!potentialTarget; } function autoinject(potentialTarget) { var deco = function (target) { if (!target.hasOwnProperty('inject')) { target.inject = (metadata.getOwn(metadata.paramTypes, target) || _emptyParameters).slice(); if (target.inject && target.inject.length > 0) { if (target.inject[target.inject.length - 1] === Object) { target.inject.splice(-1, 1); } } } }; if (isInjectable(potentialTarget)) { return deco(potentialTarget); } return deco; } function inject() { var rest = []; for (var _i = 0; _i < arguments.length; _i++) { rest[_i] = arguments[_i]; } return function (target, _key, descriptor) { if (typeof descriptor === 'number') { autoinject(target); if (rest.length === 1) { target.inject[descriptor] = rest[0]; } return; } if (descriptor) { var fn = descriptor.value; fn.inject = rest; } else { target.inject = rest; } }; } var resolver = protocol.create('aurelia:resolver', function (target) { if (!(typeof target.get === 'function')) { return 'Resolvers must implement: get(container: Container, key: any): any'; } return true; }); var Strategy; (function (Strategy) { Strategy[Strategy["instance"] = 0] = "instance"; Strategy[Strategy["singleton"] = 1] = "singleton"; Strategy[Strategy["transient"] = 2] = "transient"; Strategy[Strategy["function"] = 3] = "function"; Strategy[Strategy["array"] = 4] = "array"; Strategy[Strategy["alias"] = 5] = "alias"; })(Strategy || (Strategy = {})); function isStrategy(actual, expected, state) { return actual === expected; } var StrategyResolver = (function () { function StrategyResolver(strategy, state) { this.strategy = strategy; this.state = state; } StrategyResolver.prototype.get = function (container, key) { if (isStrategy(this.strategy, Strategy.instance, this.state)) { return this.state; } if (isStrategy(this.strategy, Strategy.singleton, this.state)) { var singleton = container.invoke(this.state); this.state = singleton; this.strategy = 0; return singleton; } if (isStrategy(this.strategy, Strategy.transient, this.state)) { return container.invoke(this.state); } if (isStrategy(this.strategy, Strategy.function, this.state)) { return this.state(container, key, this); } if (isStrategy(this.strategy, Strategy.array, this.state)) { return this.state[0].get(container, key); } if (isStrategy(this.strategy, Strategy.alias, this.state)) { return container.get(this.state); } throw new Error('Invalid strategy: ' + this.strategy); }; StrategyResolver = __decorate([ resolver(), __metadata("design:paramtypes", [Number, Object]) ], StrategyResolver); return StrategyResolver; }()); var Lazy = (function () { function Lazy(key) { this._key = key; } Lazy_1 = Lazy; Lazy.prototype.get = function (container) { var _this = this; return function () { return container.get(_this._key); }; }; Lazy.of = function (key) { return new Lazy_1(key); }; var Lazy_1; Lazy = Lazy_1 = __decorate([ resolver(), __metadata("design:paramtypes", [Object]) ], Lazy); return Lazy; }()); var All = (function () { function All(key) { this._key = key; } All_1 = All; All.prototype.get = function (container) { return container.getAll(this._key); }; All.of = function (key) { return new All_1(key); }; var All_1; All = All_1 = __decorate([ resolver(), __metadata("design:paramtypes", [Object]) ], All); return All; }()); var Optional = (function () { function Optional(key, checkParent) { if (checkParent === void 0) { checkParent = true; } this._key = key; this._checkParent = checkParent; } Optional_1 = Optional; Optional.prototype.get = function (container) { if (container.hasResolver(this._key, this._checkParent)) { return container.get(this._key); } return null; }; Optional.of = function (key, checkParent) { if (checkParent === void 0) { checkParent = true; } return new Optional_1(key, checkParent); }; var Optional_1; Optional = Optional_1 = __decorate([ resolver(), __metadata("design:paramtypes", [Object, Boolean]) ], Optional); return Optional; }()); var Parent = (function () { function Parent(key) { this._key = key; } Parent_1 = Parent; Parent.prototype.get = function (container) { return container.parent ? container.parent.get(this._key) : null; }; Parent.of = function (key) { return new Parent_1(key); }; var Parent_1; Parent = Parent_1 = __decorate([ resolver(), __metadata("design:paramtypes", [Object]) ], Parent); return Parent; }()); var Factory = (function () { function Factory(key) { this._key = key; } Factory_1 = Factory; Factory.prototype.get = function (container) { var fn = this._key; var resolver = container.getResolver(fn); if (resolver && resolver.strategy === Strategy.function) { fn = resolver.state; } return function () { var rest = []; for (var _i = 0; _i < arguments.length; _i++) { rest[_i] = arguments[_i]; } return container.invoke(fn, rest); }; }; Factory.of = function (key) { return new Factory_1(key); }; var Factory_1; Factory = Factory_1 = __decorate([ resolver(), __metadata("design:paramtypes", [Object]) ], Factory); return Factory; }()); var NewInstance = (function () { function NewInstance(key) { var dynamicDependencies = []; for (var _i = 1; _i < arguments.length; _i++) { dynamicDependencies[_i - 1] = arguments[_i]; } this.key = key; this.asKey = key; this.dynamicDependencies = dynamicDependencies; } NewInstance_1 = NewInstance; NewInstance.prototype.get = function (container) { var dynamicDependencies = this.dynamicDependencies.length > 0 ? this.dynamicDependencies.map(function (dependency) { return dependency['protocol:aurelia:resolver'] ? dependency.get(container) : container.get(dependency); }) : undefined; var fn = this.key; var resolver = container.getResolver(fn); if (resolver && resolver.strategy === 3) { fn = resolver.state; } var instance = container.invoke(fn, dynamicDependencies); container.registerInstance(this.asKey, instance); return instance; }; NewInstance.prototype.as = function (key) { this.asKey = key; return this; }; NewInstance.of = function (key) { var dynamicDependencies = []; for (var _i = 1; _i < arguments.length; _i++) { dynamicDependencies[_i - 1] = arguments[_i]; } return new (NewInstance_1.bind.apply(NewInstance_1, __spreadArray([void 0, key], dynamicDependencies, false)))(); }; var NewInstance_1; NewInstance = NewInstance_1 = __decorate([ resolver(), __metadata("design:paramtypes", [Object, Object]) ], NewInstance); return NewInstance; }()); function getDecoratorDependencies(target) { autoinject(target); return target.inject; } function lazy(keyValue) { return function (target, _key, index) { var inject = getDecoratorDependencies(target); inject[index] = Lazy.of(keyValue); }; } function all(keyValue) { return function (target, _key, index) { var inject = getDecoratorDependencies(target); inject[index] = All.of(keyValue); }; } function optional(checkParentOrTarget) { if (checkParentOrTarget === void 0) { checkParentOrTarget = true; } var deco = function (checkParent) { return function (target, _key, index) { var inject = getDecoratorDependencies(target); inject[index] = Optional.of(inject[index], checkParent); }; }; if (typeof checkParentOrTarget === 'boolean') { return deco(checkParentOrTarget); } return deco(true); } function parent(target, _key, index) { var inject = getDecoratorDependencies(target); inject[index] = Parent.of(inject[index]); } function factory(keyValue) { return function (target, _key, index) { var inject = getDecoratorDependencies(target); inject[index] = Factory.of(keyValue); }; } function newInstance(asKeyOrTarget) { var dynamicDependencies = []; for (var _i = 1; _i < arguments.length; _i++) { dynamicDependencies[_i - 1] = arguments[_i]; } var deco = function (asKey) { return function (target, _key, index) { var inject = getDecoratorDependencies(target); inject[index] = NewInstance.of.apply(NewInstance, __spreadArray([inject[index]], dynamicDependencies, false)); if (!!asKey) { inject[index].as(asKey); } }; }; if (arguments.length >= 1) { return deco(asKeyOrTarget); } return deco(); } var currentContainer = null; function validateKey(key) { if (key === null || key === undefined) { throw new Error('key/value cannot be null or undefined. Are you trying to inject/register something that doesn\'t exist with DI?'); } } var _emptyParameters = Object.freeze([]); metadata.registration = 'aurelia:registration'; metadata.invoker = 'aurelia:invoker'; var resolverDecorates = resolver.decorates; var InvocationHandler = (function () { function InvocationHandler(fn, invoker, dependencies) { this.fn = fn; this.invoker = invoker; this.dependencies = dependencies; } InvocationHandler.prototype.invoke = function (container, dynamicDependencies) { var previousContainer = currentContainer; currentContainer = container; try { return dynamicDependencies !== undefined ? this.invoker.invokeWithDynamicDependencies(container, this.fn, this.dependencies, dynamicDependencies) : this.invoker.invoke(container, this.fn, this.dependencies); } finally { currentContainer = previousContainer; } }; return InvocationHandler; }()); function invokeWithDynamicDependencies(container, fn, staticDependencies, dynamicDependencies) { var i = staticDependencies.length; var args = new Array(i); var lookup; while (i--) { lookup = staticDependencies[i]; if (lookup === null || lookup === undefined) { throw new Error('Constructor Parameter with index ' + i + ' cannot be null or undefined. Are you trying to inject/register something that doesn\'t exist with DI?'); } else { args[i] = container.get(lookup); } } if (dynamicDependencies !== undefined) { args = args.concat(dynamicDependencies); } return Reflect.construct(fn, args); } var classInvoker = { invoke: function (container, Type, deps) { var instances = deps.map(function (dep) { return container.get(dep); }); return Reflect.construct(Type, instances); }, invokeWithDynamicDependencies: invokeWithDynamicDependencies }; function getDependencies(f) { if (!f.hasOwnProperty('inject')) { return []; } if (typeof f.inject === 'function') { return f.inject(); } return f.inject; } var Container = (function () { function Container(configuration) { if (configuration === undefined) { configuration = {}; } this._configuration = configuration; this._onHandlerCreated = configuration.onHandlerCreated; this._handlers = configuration.handlers || (configuration.handlers = new Map()); this._resolvers = new Map(); this.root = this; this.parent = null; } Container.prototype.makeGlobal = function () { Container.instance = this; return this; }; Container.prototype.setHandlerCreatedCallback = function (onHandlerCreated) { this._onHandlerCreated = onHandlerCreated; this._configuration.onHandlerCreated = onHandlerCreated; }; Container.prototype.registerInstance = function (key, instance) { return this.registerResolver(key, new StrategyResolver(0, instance === undefined ? key : instance)); }; Container.prototype.registerSingleton = function (key, fn) { return this.registerResolver(key, new StrategyResolver(Strategy.singleton, fn === undefined ? key : fn)); }; Container.prototype.registerTransient = function (key, fn) { return this.registerResolver(key, new StrategyResolver(2, fn === undefined ? key : fn)); }; Container.prototype.registerHandler = function (key, handler) { return this.registerResolver(key, new StrategyResolver(Strategy.function, handler)); }; Container.prototype.registerAlias = function (originalKey, aliasKey) { return this.registerResolver(aliasKey, new StrategyResolver(5, originalKey)); }; Container.prototype.registerResolver = function (key, resolver) { validateKey(key); var allResolvers = this._resolvers; var result = allResolvers.get(key); if (result === undefined) { allResolvers.set(key, resolver); } else if (result.strategy === 4) { result.state.push(resolver); } else { allResolvers.set(key, new StrategyResolver(4, [result, resolver])); } return resolver; }; Container.prototype.autoRegister = function (key, fn) { fn = fn === undefined ? key : fn; if (typeof fn === 'function') { var registration = metadata.get(metadata.registration, fn); if (registration === undefined) { return this.registerResolver(key, new StrategyResolver(1, fn)); } return registration.registerResolver(this, key, fn); } return this.registerResolver(key, new StrategyResolver(0, fn)); }; Container.prototype.autoRegisterAll = function (fns) { var i = fns.length; while (i--) { this.autoRegister(fns[i]); } }; Container.prototype.unregister = function (key) { this._resolvers.delete(key); }; Container.prototype.hasResolver = function (key, checkParent) { if (checkParent === void 0) { checkParent = false; } validateKey(key); return (this._resolvers.has(key) || (checkParent && this.parent !== null && this.parent.hasResolver(key, checkParent))); }; Container.prototype.getResolver = function (key) { return this._resolvers.get(key); }; Container.prototype.get = function (key) { validateKey(key); if (key === Container) { return this; } if (resolverDecorates(key)) { return key.get(this, key); } var resolver = this._resolvers.get(key); if (resolver === undefined) { if (this.parent === null) { return this.autoRegister(key).get(this, key); } var registration = metadata.get(metadata.registration, key); if (registration === undefined) { return this.parent._get(key); } return registration.registerResolver(this, key, key).get(this, key); } return resolver.get(this, key); }; Container.prototype._get = function (key) { var resolver = this._resolvers.get(key); if (resolver === undefined) { if (this.parent === null) { return this.autoRegister(key).get(this, key); } return this.parent._get(key); } return resolver.get(this, key); }; Container.prototype.getAll = function (key) { validateKey(key); var resolver = this._resolvers.get(key); if (resolver === undefined) { if (this.parent === null) { return _emptyParameters; } return this.parent.getAll(key); } if (resolver.strategy === 4) { var state = resolver.state; var i = state.length; var results = new Array(i); while (i--) { results[i] = state[i].get(this, key); } return results; } return [resolver.get(this, key)]; }; Container.prototype.createChild = function () { var child = new Container(this._configuration); child.root = this.root; child.parent = this; return child; }; Container.prototype.invoke = function (fn, dynamicDependencies) { try { var handler = this._handlers.get(fn); if (handler === undefined) { handler = this._createInvocationHandler(fn); this._handlers.set(fn, handler); } return handler.invoke(this, dynamicDependencies); } catch (e) { throw new AggregateError("Error invoking ".concat(fn.name, ". Check the inner error for details."), e, true); } }; Container.prototype._createInvocationHandler = function (fn) { var dependencies; if (fn.inject === undefined) { dependencies = metadata.getOwn(metadata.paramTypes, fn) || _emptyParameters; } else { dependencies = []; var ctor = fn; while (typeof ctor === 'function') { dependencies.push.apply(dependencies, getDependencies(ctor)); ctor = Object.getPrototypeOf(ctor); } } var invoker = metadata.getOwn(metadata.invoker, fn) || classInvoker; var handler = new InvocationHandler(fn, invoker, dependencies); return this._onHandlerCreated !== undefined ? this._onHandlerCreated(handler) : handler; }; return Container; }()); function resolve() { var keys = []; for (var _i = 0; _i < arguments.length; _i++) { keys[_i] = arguments[_i]; } if (currentContainer == null) { throw new Error("There is not a currently active container to resolve \"".concat(String(keys), "\". Are you trying to \"new SomeClass(...)\" that has a resolve(...) call?")); } return keys.length === 1 ? currentContainer.get(keys[0]) : keys.map(containerGetKey, currentContainer); } function containerGetKey(key) { return this.get(key); } function invoker(value) { return function (target) { metadata.define(metadata.invoker, value, target); }; } function invokeAsFactory(potentialTarget) { var deco = function (target) { metadata.define(metadata.invoker, FactoryInvoker.instance, target); }; return potentialTarget ? deco(potentialTarget) : deco; } var FactoryInvoker = (function () { function FactoryInvoker() { } FactoryInvoker.prototype.invoke = function (container, fn, dependencies) { var i = dependencies.length; var args = new Array(i); while (i--) { args[i] = container.get(dependencies[i]); } return (fn.apply(undefined, args)); }; FactoryInvoker.prototype.invokeWithDynamicDependencies = function (container, fn, staticDependencies, dynamicDependencies) { var i = staticDependencies.length; var args = new Array(i); while (i--) { args[i] = container.get(staticDependencies[i]); } if (dynamicDependencies !== undefined) { args = args.concat(dynamicDependencies); } return fn.apply(undefined, args); }; return FactoryInvoker; }()); FactoryInvoker.instance = new FactoryInvoker(); function registration(value) { return function (target) { metadata.define(metadata.registration, value, target); }; } function transient(key) { return registration(new TransientRegistration(key)); } function singleton(keyOrRegisterInChild, registerInChild) { if (registerInChild === void 0) { registerInChild = false; } return registration(new SingletonRegistration(keyOrRegisterInChild, registerInChild)); } var TransientRegistration = (function () { function TransientRegistration(key) { this._key = key; } TransientRegistration.prototype.registerResolver = function (container, key, fn) { var existingResolver = container.getResolver(this._key || key); return existingResolver === undefined ? container.registerTransient((this._key || key), fn) : existingResolver; }; return TransientRegistration; }()); var SingletonRegistration = (function () { function SingletonRegistration(keyOrRegisterInChild, registerInChild) { if (registerInChild === void 0) { registerInChild = false; } if (typeof keyOrRegisterInChild === 'boolean') { this._registerInChild = keyOrRegisterInChild; } else { this._key = keyOrRegisterInChild; this._registerInChild = registerInChild; } } SingletonRegistration.prototype.registerResolver = function (container, key, fn) { var targetContainer = this._registerInChild ? container : container.root; var existingResolver = targetContainer.getResolver(this._key || key); return existingResolver === undefined ? targetContainer.registerSingleton(this._key || key, fn) : existingResolver; }; return SingletonRegistration; }()); export { All, Container, Factory, FactoryInvoker, InvocationHandler, Lazy, NewInstance, Optional, Parent, SingletonRegistration, Strategy, StrategyResolver, TransientRegistration, _emptyParameters, all, autoinject, factory, getDecoratorDependencies, inject, invokeAsFactory, invoker, lazy, newInstance, optional, parent, registration, resolve, resolver, singleton, transient }; //# sourceMappingURL=aurelia-dependency-injection.js.map