UNPKG

wires-domain

Version:

Restfull service with dependency injection

198 lines (183 loc) 6.37 kB
var logger = require("log4js").getLogger("domain"); var _ = require("lodash"); var Promise = require('promise'); var Class = require('wires-class'); var Promise = require("promise"); var domainEach = require("./_each.js"); var isPromise = function(v) { return _.isFunction(v.then) && _.isFunction(v.catch); }; global.__wires_services_cached__ = global.__wires_services_cached__ || {}; //Extract parameter names from a function var getParamNames = function(func) { var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var ARGUMENT_NAMES = /([^\s,]+)/g; var fnStr = func.toString().replace(STRIP_COMMENTS, ''); var result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES); if (result === null) result = []; return result; }; // Extracts arguments and defined target for the require function var getInputArguments = function(args) { var out = {}; out.localServices = {}; if (args.length > 0) { out.source = args[0]; out.target = args[0]; if (_.isPlainObject(args[0])) { var opts = args[0]; out.target = opts.target; out.source = opts.source; out.instance = opts.instance; } // call(func, callback) if (args.length > 1) { var argsDefined = _.isString(args[0]) || _.isArray(args[0]); if (argsDefined) { if (_.isArray(args[0])) { out.source = args[0]; } else { out.source = _.isString(args[0]) ? [args[0]] : args[0]; } if (_.isFunction(args[1])) { out.target = args[1]; } if (_.isFunction(args[2])) { out.target = args[2]; } } else { if (_.isFunction(args[1])) { out.callReady = args[1]; } if (_.isPlainObject(args[1])) { out.localServices = args[1]; } } } if (args.length === 3) { if (_.isPlainObject(args[1])) { out.localServices = args[1]; } if (_.isFunction(args[2])) { out.callReady = args[2]; } } } out.target = out.target || function() {}; out.source = out.source ? out.source : out.target; out.callReady = out.callReady || function() {}; return out; }; // Register local services // Will be available only on rest service construct var Require = { // Factory constructor // Class is used for creating an instance with following resolution service: function() { this.register.apply(this, arguments); }, module: function(name, func, opts) { opts = opts || {}; opts.cache = true; this.register.apply(this, [name, func, opts]); }, register: function(name, arg1, arg2) { var localArgs = null; var target = arg1; if (_.isArray(arg1)) { localArgs = arg1; target = arg2; } var cache = false; if (_.isPlainObject(arg2)) { cache = arg2.cache === true; } global.__wires_services__ = global.__wires_services__ || {}; global.__wires_services__[name] = { name: name, target: target, args: localArgs, cache: cache }; }, isServiceRegistered: function(name) { return global.__wires_services__ && global.__wires_services__[name] !== undefined; }, requirePackage: function(name) { var _packageServices = {} var self = this; return domainEach(global.__wires_services__, function(service, serviceName) { var _package = serviceName.split(".")[0]; if (_package === name) { return self.require([serviceName], function(serviceInstance) { _packageServices[serviceName] = serviceInstance }) } }).then(function() { return _packageServices; }); }, promise: function(cb) { return new Promise(cb); }, storeModule: function(name, inst) { global.__wires_services_cached__[name] = inst; }, require: function() { var data = getInputArguments(arguments); var self = this; var localServices = data.localServices; var variables = _.isArray(data.source) ? data.source : getParamNames(data.source); var target = data.target; var callReady = data.callReady; var instance = data.instance; var globalServices = global.__wires_services__; var resultPromise = new Promise(function(resolve, reject) { var args = []; var avialableServices = _.merge(localServices, globalServices); for (var i in variables) { var v = variables[i]; var variableName = variables[i]; if (!avialableServices[variableName]) { logger.fatal("Error while injecting variable '" + variableName + "' into function \n" + data.source.toString()); return reject({ status: 500, message: "Service with name '" + variableName + "' was not found " }); } args.push(avialableServices[variableName]); } var results = []; return domainEach(args, function(item) { if (item.cache && global.__wires_services_cached__[item.name]) { return global.__wires_services_cached__[item.name]; } var argService = item.target; var requiredArgs = item.args; if (_.isFunction(argService)) { var promised; var currentArgs = []; if (requiredArgs) { currentArgs = [requiredArgs, localServices, argService]; } else { currentArgs = [argService, localServices]; } return self.require.apply(self, currentArgs).then(function(dest) { if (item.cache) { self.storeModule(item.name, dest); } return dest; }); } else { return argService || item; } }).then(function(results) { return target.apply(instance || results, results); }).then(resolve).catch(reject); }); return resultPromise; } }; module.exports = Require;