wires-domain
Version:
Restfull service with dependency injection
276 lines (256 loc) • 8.87 kB
JavaScript
(function(isNode, $storage, Exports) {
var domain = {};
var global;
var _, Promise;
var logger = {};
if (isNode) {
global = $storage;
Promise = require("promise");
_ = require('lodash');
var log4js = require('log4js').getLogger("domain");
logger.fatal = function(msg) {
log4js.fatal(msg)
};
logger.log = function(msg) {
log4js.log(msg)
}
logger.warn = function() {
log4js.warn(msg)
};
} else {
if (!Exports._) {
console.warn("Lodash is required for wires-domain!");
}
_ = Exports._;
global = {};
Promise = Exports.Promise;
logger = {
fatal: function(msg) {
console.error(msg);
},
log: function(msg) {
console.log(msg)
},
warn: function(msg) {
console.warn(msg);
}
}
}
global.__wires_services_cached__ = global.__wires_services_cached__ || {};
function getParamNames(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;
};
var isPromise = function(v) {
return v && _.isFunction(v.then) && _.isFunction(v.catch);
};
// Extracts arguments and defined target for the require function
function getInputArguments(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;
};
var domainEach = function(argv, cb) {
return new Promise(function(resolve, reject) {
var callbacks = [];
var results = [];
var isObject = _.isPlainObject(argv);
var index = -1;
var iterate = function() {
index++;
if (index < _.size(argv)) {
var key;
var value;
if (isObject) {
key = _.keys(argv)[index];
value = argv[key];
} else {
key = index;
value = argv[index];
}
if (isPromise(value)) {
value.then(function(data) {
results.push(data);
iterate();
}).catch(reject);
} else {
var res = cb.call(cb, value, key);
if (isPromise(res)) {
res.then(function(a) {
results.push(a);
iterate();
}).catch(reject);
} else {
results.push(res);
iterate();
}
}
} else {
return resolve(results);
}
};
iterate();
});
}
var domain = {
each: domainEach,
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]) {
console.log(logger)
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;
}
}
Exports.domain = domain;
})(typeof module !== 'undefined' && module.exports,
typeof module !== 'undefined' && module.exports ? global : this, this);