tiny-di
Version:
A tini tiny dependency injection container for node/io.js applications
241 lines (207 loc) • 7.12 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _generic = require("./binder/generic");
var _path = require("./binder/path");
var _provider = require("./binder/provider");
var _abstract = require("./binding/abstract");
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
/**
* tiny-di
* @module tiny-di
* @copyright Dennis Saenger <tiny-di-15@mail.ds82.de>
*/
var path = require('path');
var _require = require('../package.json'),
version = _require.version;
// https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
var TinyDi =
/*#__PURE__*/
function () {
function TinyDi() {
(0, _classCallCheck2["default"])(this, TinyDi);
this.version = version;
this.logger = console.log;
this.resolving = [];
this.bindings = {};
this.nsBindings = [];
this.resolverFn = this.getDefaultResolver();
} //
// PUBLIC DI API
//
(0, _createClass2["default"])(TinyDi, [{
key: "setLogger",
value: function setLogger(logger) {
this.logger = logger;
}
}, {
key: "bind",
value: function bind(key) {
return new _generic.GenericBinder(this, key);
}
}, {
key: "ns",
value: function ns(space) {
return new _path.PathBinder(this, space);
}
}, {
key: "get",
value: function get(key, env) {
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var _bindings = opts.bindings || {};
var bindings = _objectSpread({}, this.bindings, {}, _bindings);
if (Array.isArray(key)) {
return key.map(function (_key) {
return this.get(_key, env, opts);
}, this);
}
return bindings[key] !== undefined ? this.getBinding(key, env, bindings) : this.lazy(key);
}
}, {
key: "provide",
value: function provide(key) {
return new _provider.ProviderBinder(this, key);
}
}, {
key: "setResolver",
value: function setResolver(resolverFn) {
this.resolverFn = resolverFn;
}
}, {
key: "set",
value: function set(key, object) {
this.bindings[key] = object;
return object;
} //
// HELPER
//
}, {
key: "getDefaultResolver",
value: function getDefaultResolver(req) {
req = req || require;
var APP_ROOT = path.dirname(require.main.filename);
return function (file) {
var filePath = path.join(APP_ROOT, file);
try {
return req(filePath);
} catch (error1) {
try {
return req(file);
} catch (error2) {
this.logger('ERROR: Cannot load module', file);
this.logger('tried to require `' + filePath + '` and `' + file + '`');
this.logger(error1, error2, error1.stack.split('\n'), error2.stack.split('\n'));
}
}
};
}
}, {
key: "resolveKey",
value: function resolveKey(key) {
if (this.hasBinding(key)) {
return key;
}
var prefix = this.nsBindings.find(function (prefix) {
var re = new RegExp('^' + escapeRegExp(prefix.ns) + '/');
return key === prefix.ns || !!key.match(re);
});
if (prefix) {
var re = new RegExp('^' + escapeRegExp(prefix.ns));
return key.replace(re, prefix.path);
}
return key;
}
}, {
key: "hasBinding",
value: function hasBinding(key) {
return !!this.bindings[key];
}
}, {
key: "setNsBinding",
value: function setNsBinding(ns, dir) {
this.nsBindings.push({
ns: ns,
path: dir
});
}
}, {
key: "load",
value: function load(key, what, opts) {
what = what || key;
what = this.resolveKey(what);
var resolved = typeof what === 'function' ? what : this.resolverFn(what);
if (resolved) {
this.markResolving(key);
var object = this.apply(resolved, {
key: key,
binding: what
}, null, opts);
this.set(key, object);
this.markResolved(key);
return object;
}
}
}, {
key: "lazy",
value: function lazy(key, opts) {
if (this.isCircularDep(key)) {
throw new Error('Circular dependency found; abort loading');
}
return this.load(key, key, opts);
}
}, {
key: "getBinding",
value: function getBinding(key, env) {
var bindings = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.bindings;
var binding = bindings[key];
if (binding instanceof _abstract.AbstractBinding) {
return binding.$get(env);
}
return binding;
}
}, {
key: "apply",
value: function apply(fn, env, that, opts) {
var self = this; // support es6 default exports
fn = fn["default"] ? fn["default"] : fn;
if (fn && fn.$inject && typeof fn === 'function') {
var isArray = Array.isArray(fn.$inject);
var rawArgs = isArray ? fn.$inject : fn.$inject.deps || [];
var returnAsClass = !isArray && fn.$inject.callAs === 'class';
var argumentList = rawArgs.map(function (arg) {
return self.get(arg, env, opts);
}, this);
return returnAsClass ? new (Function.prototype.bind.apply(fn, [null].concat(argumentList)))() : fn.apply(that, argumentList);
}
return fn;
}
}, {
key: "markResolving",
value: function markResolving(key) {
this.resolving.push(key);
}
}, {
key: "markResolved",
value: function markResolved(key) {
var index = this.resolving.indexOf(key);
if (index > -1) {
this.resolving.splice(index, 1);
}
}
}, {
key: "isCircularDep",
value: function isCircularDep(key) {
return this.resolving.indexOf(key) > -1;
}
}]);
return TinyDi;
}();
module.exports = function () {
return new TinyDi();
};