UNPKG

simple-ioc-container

Version:
270 lines (223 loc) 9.88 kB
"use strict"; var _typeof2 = require("babel-runtime/helpers/typeof"); var _typeof3 = _interopRequireDefault(_typeof2); var _toConsumableArray2 = require("babel-runtime/helpers/toConsumableArray"); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require("babel-runtime/helpers/createClass"); var _createClass3 = _interopRequireDefault(_createClass2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _require = require("./constants"), CONTAINER_TYPE_VALUE = _require.CONTAINER_TYPE_VALUE, CONTAINER_TYPE_FACTORY = _require.CONTAINER_TYPE_FACTORY, CONTAINER_TYPE_SERVICE = _require.CONTAINER_TYPE_SERVICE; var checkableTypes = [CONTAINER_TYPE_VALUE, CONTAINER_TYPE_FACTORY, CONTAINER_TYPE_SERVICE]; /** * Creates a new Injector. * @class * @property {object} proxy - Proxy of an Injector instance for simple access to * dependencies via properties. */ module.exports = function () { /** * Initializes the Injector with a container. * @constructs * * @param {Map|Object} container - Container for dependencies. * @param {...Object} dependencies - See {@link Injector#register}. * (optional) */ function Injector(container) { (0, _classCallCheck3.default)(this, Injector); /** * @protected * @property {object} __container - contains a container of * dependencies. */ Object.defineProperty(this, "__container", { value: container, __proto__: null }); this.proxy = new Proxy(this, { get: function get(target, prop) { return target.get(prop); } }); for (var _len = arguments.length, dependencies = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { dependencies[_key - 1] = arguments[_key]; } this.register.apply(this, dependencies); } /** * Registers dependence(ies) in a container with specified params. * * @param {...Object} dependencies - Params of a dependence. Description: * { * key(required): {string} dependence key; * type(required): {enum} ["class", "value", "singleton"]; * value(required): {*}; * args(optional): {Array} arguments to bind to a constructor. * force(optional): {bool} registers forcefully if true, otherwise * doesn't. Default false; * onRegister(optional): {callback} Invokes if dependence is * successfully registered. * } * * @returns {Injector} Injector instance. * @throws Error */ (0, _createClass3.default)(Injector, [{ key: "register", value: function register() { var _this = this; for (var _len2 = arguments.length, dependencies = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { dependencies[_key2] = arguments[_key2]; } dependencies.forEach(function (params) { var key = params.key, type = params.type, force = params.force, onRegister = params.onRegister; if (!key) { throw new Error("Key is not specified."); } else if (!checkableTypes.includes(type)) { throw new Error("Type is invalidated."); } else if (!("value" in params)) { throw new Error("Value is not specified."); } if (force) { _this.__container.delete(key); _this.__container.set(key, params); } else { if (!_this.__container.has(key)) { _this.__container.set(key, params); } else { return console.warn("Dependence key '" + key + "' has already registered. " + "You should specify flag 'force'."); } } if (onRegister && typeof onRegister == "function") { onRegister(); } }); return this; } /** * Resolves all dependencies before invoke one of them by a key. * @protected * * @param {Object} dependence - Dependence params. * See {@link Injector#register}. * @param {Array} args - Arguments to bind to a constructor. * @param {Boolean} needConstructor - Returns constructor if true * otherwise instance. Default false. * * @returns {*} Dependence. */ }, { key: "__resolve", value: function __resolve(dependence) { var args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var needConstructor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; switch (dependence.type) { case CONTAINER_TYPE_VALUE: return dependence.value; case CONTAINER_TYPE_FACTORY: return needConstructor ? this.getConstructor(null, dependence.value) : new (Function.prototype.bind.apply(this.__issueProxyConstructor(dependence), [null].concat((0, _toConsumableArray3.default)(args))))(); case CONTAINER_TYPE_SERVICE: if ((0, _typeof3.default)(dependence.value) == "object") { return needConstructor ? dependence.value.constructor : dependence.value; } else if (needConstructor) { return this.getConstructor(null, dependence.value); } this.register({ key: dependence.key, type: CONTAINER_TYPE_SERVICE, value: new (Function.prototype.bind.apply(this.__issueProxyConstructor(dependence), [null].concat((0, _toConsumableArray3.default)(args))))(), force: true }); return this.__container.get(dependence.key).value; } } /** * Issues a constructor for a dependence. * @protected * * @param {Object} dependence - Dependence params. * See {@link Injector#register}. * @returns {*} Constructor with bound args. */ }, { key: "__issueProxyConstructor", value: function __issueProxyConstructor(dependence) { var Constructor = this.getConstructor(null, dependence.value); var proxy = this.proxy; return new Proxy(Constructor, { construct: function construct(target, args) { target.prototype._di = proxy; return new (Function.prototype.bind.apply(target, [null].concat((0, _toConsumableArray3.default)(args))))(); } }); } /** * Returns a dependence by a key. * * @param {*} key - Key to get a dependence for. * @param {...*} args - Arguments to bind to a constructor. * * @returns {*} Dependence. */ }, { key: "get", value: function get(key) { try { for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { args[_key3 - 1] = arguments[_key3]; } return this.__resolve(this.__container.get(key), args); } catch (e) { console.error("Undefined key \"" + key + "\""); console.error(e); } } /** * Returns a dependence constructor. * Note: a dependence has to have a constructor. * * @param {*} key - Key to get a dependence for. * @param {*} value - Custom constructor or path to a constructor. (inner) * * @returns {Function} Dependence constructor. * @throws Error */ }, { key: "getConstructor", value: function getConstructor(key) { var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; try { var target = value ? value : this.__resolve(this.__container.get(key), [], true); if (typeof target == "function") { return target; } else if (typeof target == "string") { var _constructor = require(target); if (_constructor && _constructor.__esModule) { _constructor = target.default; } if (typeof _constructor == "function") { return _constructor; } } else if ((typeof target === "undefined" ? "undefined" : (0, _typeof3.default)(target)) == "object") { if (value.__esModule) { return value.default; } return target.constructor; } throw new Error("This is not a constructor."); } catch (e) { console.error("Undefined key \"" + key + "\""); console.error(e); } } }]); return Injector; }();