/**
* Create a index.js for the given directory.
* Exports files in directory with camelized name.
* @example
*
* //This is an index file generate by ci worker.
* exports.fooBar = require('./foo_bar.js');
*
* @function task.worker.generateIndex
* @param {object} config - Configuration object.
* @param {string} config.dir - Directory to create index.
* @param {boolean}[config.capitalize=false] - Exports with capitalize name or not.
* @param {string} [config.pattern='*'] - Pattern to collect modules within the directory.
* @param {string} [config.dest=config.dir+'/index.js'] - Index file path to generate.
* @param {function} callback - Callback when done.
* @author Taka Okunishi
*
*/
var fs = require('fs'),
path = require('path'),
string = require('../../lib/string'),
file = require('../../lib/file'),
object = require('../../lib/object'),
camelize = string.camelize,
debug = require('./_debug'),
matchesGlob = file.matchesGlob,
writeReadonlyFile = file.writeReadonlyFile,
fallbackCopy = object.fallbackCopy,
copy = object.copy,
_loadLocalTmpl = require('./_load_local_tmpl');
exports = module.exports = function (config, callback) {
var dirname = config.dir,
pattern = config.pattern || '*',
capitalize = config.capitalize || false,
dest = path.resolve(config.dest || path.join(dirname, 'index.js'));
exports._modulesData(dirname, pattern, capitalize, function (err, modulesData) {
if (err) {
callback(err);
return;
}
var exportsNames = modulesData && modulesData.map(function (data) {
return data.exportsName;
}) || [];
exports._prototypeData(dirname, exportsNames, function (err, prototypeData) {
if (err) {
callback(err);
return;
}
var docData = exports._docData(config.doc);
exports._loadIndexJsTmpl(function (err, tmpl) {
if (err) {
callback(err);
return;
}
var modules = modulesData && modulesData.map(function (data, i) {
data.hasNext = i < modulesData.length - 1;
return data;
});
var data = exports._renderData({
prototype: prototypeData,
doc: docData,
modules: modules,
hasModules: !!modules.length
}),
content = tmpl(data);
writeReadonlyFile(dest, content, function (err) {
if (!err) {
debug.didCreateFile(dest);
}
callback();
});
});
});
});
};
exports._renderData = function (data) {
var result = {};
fallbackCopy(global.apemandata || {}, result);
copy(data, result);
return result;
};
exports._docData = function (data) {
if (!data) return null;
return {
overview: data.overview,
namespace: data.namespace
}
};
/**
* Get module data.
* @param {string} dirname - Name of directory which contains all modules.
* @param {string} pattern - Model file name pattern.
* @param {string[]} capitalize - Module names to be exported with capitalized names.
* @param {function} callback - Callback when done.
* @private
*/
exports._modulesData = function (dirname, pattern, capitalize, callback) {
/**
* Should be capitalized or not
* @param name - Name to judge.
* @returns {boolean} Capitalized or not
* @private
*/
function shouldCapitalize(name) {
if (typeof(capitalize) === 'string') {
capitalize = [capitalize];
}
if (Array.isArray(capitalize)) {
if (~capitalize.indexOf(name)) {
return true;
} else {
for (var i = 0; i < capitalize.length; i++) {
var hit = matchesGlob(name, capitalize[i]);
if (hit) return true;
}
}
return false;
} else {
return !!capitalize;
}
}
fs.exists(dirname, function (exists) {
if (!exists) {
callback(null);
return;
}
fs.readdir(dirname, function (err, filenames) {
if (err) {
callback(err);
return;
}
var data = filenames
.filter(function (filename) {
return matchesGlob(filename, pattern);
})
.filter(function (filename) {
return filename != 'index.js';
})
.filter(function (filename) {
return !filename.match(/^\./);
})
.filter(function (filename) {
return filename != exports._prototypeFileName;
})
.map(function (filename) {
var name = path.basename(filename, path.extname(filename));
return {
exportsName: camelize(name.replace(/\-/g, '_'), shouldCapitalize(name)),
requireName: './' + name
};
});
callback(null, data);
});
});
};
/**
* Get the prototype module data.
* @param {string} dirname - Directory name to look up.
* @param {string[]|boolean} overridden - Overridden or not.
* @param {function} callback - Callback when done.
* @protected
* @ignore
*/
exports._prototypeData = function (dirname, overridden, callback) {
var filename = path.resolve(dirname, exports._prototypeFileName);
fs.exists(filename, function (exists) {
if (!exists) {
callback(null);
return;
}
var prototype = require(path.resolve(dirname, filename)),
modules = Object.keys(prototype)
.filter(function (name) {
if (!overridden) return true;
return overridden.indexOf(name) === -1;
})
.map(function (name) {
return {exportsName: name}
});
var data = prototype && {
path: './' + path.basename(filename),
modules: modules.map(function (data, i) {
data.hasNext = i < modules.length - 1;
return data;
})
};
callback(null, data);
});
};
/**
* Load the index js template.
* @param {function} callback - Callback when done.
* @protected
* @ignore
*/
exports._loadIndexJsTmpl = function (callback) {
_loadLocalTmpl('js/index.js.hbs', callback);
};
exports._prototypeFileName = '_prototype.js';