@orchestrated-io/cqrs-domain
Version:
Node-cqrs-domain is a node.js module based on node-eventstore. It can be very useful as domain component if you work with (d)ddd, cqrs, eventdenormalizer, host, etc.
211 lines (175 loc) • 4.9 kB
JavaScript
var debug = require('debug')('domain:structureParser'),
_ = require('lodash'),
fs = require('fs'),
path = require('path');
var validFileTypes = ['js', 'json'];
function isValidFileType(fileName) {
var index = fileName.lastIndexOf('.');
if (index < 0) {
return false;
}
var fileType = fileName.substring(index + 1);
var index = validFileTypes.indexOf(fileType);
if (index < 0) {
return false;
}
return validFileTypes[index];
}
function loadPaths (dir, callback) {
dir = path.resolve(dir);
var results = [];
fs.readdir(dir, function (err, list) {
if (err) {
debug(err);
return callback(err);
}
var pending = list.length;
if (pending === 0) return callback(null, results);
list.forEach(function (file) {
var pathFull = path.join(dir, file);
fs.stat(pathFull, function(err, stat) {
if (err) {
return debug(err);
}
// if directory, go deep...
if (stat && stat.isDirectory()) {
loadPaths(pathFull, function (err, res) {
results = results.concat(res);
if (!--pending) callback(null, results);
});
return;
}
// if a file we are looking for
if (isValidFileType(pathFull)) {
results.push(pathFull);
}
// of just an other file, skip...
if (!--pending) callback(null, results);
});
});
});
}
function pathToJson (root, paths, addWarning) {
root = path.resolve(root);
var res = [];
paths.forEach(function (p) {
if (p.indexOf(root) >= 0) {
var part = p.substring(root.length);
if (part.indexOf(path.sep) === 0) {
part = part.substring(path.sep.length);
}
var splits = part.split(path.sep);
var withoutFileName = splits;
withoutFileName.splice(splits.length - 1);
var fileName = path.basename(part);
var dottiedBase = '';
withoutFileName.forEach(function (s, i) {
if (i + 1 < withoutFileName.length) {
dottiedBase += s + '.';
} else {
dottiedBase += s;
}
});
try {
var required = require(p);
// // clean cache, fixes multiple loading of same aggregates, commands, etc...
// if (require.cache[require.resolve(p)]) {
// delete require.cache[require.resolve(p)];
// }
if (!required || _.isEmpty(required)) {
return;
}
if (typeof required === 'object' && typeof required.default !== 'undefined') {
required = required.default;
}
if (_.isArray(required)) {
_.each(required, function (req) {
res.push({
path: p,
dottiedBase: dottiedBase,
fileName: fileName,
value: req,
fileType: path.extname(p).substring(1)
});
});
} else {
res.push({
path: p,
dottiedBase: dottiedBase,
fileName: fileName,
value: required,
fileType: path.extname(p).substring(1)
});
}
} catch (err) {
debug(err);
if (addWarning) {
addWarning(err);
}
}
} else {
debug('path is not a subpath from root');
}
});
return res;
}
function parse (dir, useLoaderExtensions, filter, callback) {
if (!callback) {
callback = filter;
filter = function (r) {
return r;
};
}
if (useLoaderExtensions) {
validFileTypes = Object.keys(require.extensions)
.map(function (ext) {
return ext.substr(1);
});
debug('Using valid file types from loader extensions');
}
dir = path.resolve(dir);
loadPaths(dir, function (err, paths) {
if (err) {
return callback(err);
}
var warns = [];
function addWarning (e) {
warns.push(e);
}
var res = filter(pathToJson(dir, paths, addWarning));
var dottiesParts = [];
res.forEach(function (r) {
var parts = r.dottiedBase.split('.');
parts.forEach(function (p, i) {
if (!dottiesParts[i]) {
return dottiesParts[i] = [p];
}
if (dottiesParts[i].indexOf(p) < 0) {
dottiesParts[i].push(p);
}
});
});
var toRemove = '';
for (var pi = 0, plen = dottiesParts.length; pi < plen; pi++) {
if (dottiesParts[pi].length === 1) {
toRemove += dottiesParts[pi][0];
} else {
break;
}
}
if (toRemove.length > 0) {
res.forEach(function (r) {
if (r.dottiedBase === toRemove) {
r.dottiedBase = '';
} else {
r.dottiedBase = r.dottiedBase.substring(toRemove.length + 1);
}
});
}
if (warns.length === 0) {
warns = null;
}
callback(null, res, warns);
});
}
module.exports = parse;