mmir-tooling
Version:
Build tools for MMIR projects
220 lines (219 loc) • 11.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const lodash_1 = __importDefault(require("lodash"));
const filepath_utils_1 = __importDefault(require("../utils/filepath-utils"));
const module_config_init_1 = __importDefault(require("../utils/module-config-init"));
const directories_utils_1 = __importDefault(require("../tools/directories-utils"));
const option_utils_1 = __importDefault(require("../tools/option-utils"));
const log_utils_1 = __importDefault(require("../utils/log-utils"));
const log = log_utils_1.default.log;
const warn = log_utils_1.default.warn;
//mode: 'controller' | 'helper' | 'model'
function readDir(mode, dir, list, options, generalOptions) {
var files = fs_extra_1.default.readdirSync(dir);
var dirs = [];
// log('read dir "'+dir+'" -> ', files);
files.forEach(function (p) {
var absPath = path_1.default.join(dir, p);
if (filepath_utils_1.default.isDirectory(absPath)) {
dirs.push(absPath);
return false;
}
else {
var normalized = filepath_utils_1.default.normalizePath(absPath);
var id = path_1.default.basename(absPath, '.js');
switch (mode) {
case 'helper':
if (!/Helper$/.test(id)) {
warn('impl-utils.addFromDirectory(): invalid file-name for helper ' + id + ' (must have suffix "Helper"): "' + normalized + '"!');
id += 'Helper';
}
break;
case 'controller': // intentional fall through
case 'model': // intentional fall through
default:
break;
}
log('impl-utils.addFromDirectory(): parsing ' + mode + ' implemenation ' + id + ' at "' + normalized + '"'); //DEBUG
var opt = options && options[id];
if ((opt && (opt.exclude || opt.file) || opt === false)) {
//-> ignore/exclude this impl. file!
log('impl-utils.addFromDirectory(): excluding ' + mode + ' implemenation ' + id + ' at "' + normalized + '"!');
return; //////////////////// EARLY EXIT //////////////////
}
var modExport = opt && opt.addModuleExport;
if (typeof modExport === 'undefined') {
modExport = generalOptions.addModuleExport || false;
}
list.push({
id: id,
name: toImplName(id),
type: mode,
file: normalized,
addModuleExport: modExport
});
}
});
// log('read sub-dirs -> ', dirs);
var size = dirs.length;
if (size > 0) {
for (var i = 0; i < size; ++i) {
readDir(mode, dirs[i], list, options, generalOptions);
}
}
}
function addFromOptions(implMap, list, appRootDir, _generalOptions) {
var impl, entry;
for (var id in implMap) {
impl = implMap[id];
if (impl && impl.file && !impl.exclude) {
entry = lodash_1.default.cloneDeep(impl);
if (!path_1.default.isAbsolute(entry.file)) {
entry.file = path_1.default.resolve(appRootDir, entry.file);
}
entry.file = filepath_utils_1.default.normalizePath(entry.file);
if (entry.id && entry.id !== id) {
warn('impl-utils.addFromOptions(): entry from implOptions for ID "' + id + '" has differing field id with value "' + entry.id + '", overwritting the id field with "' + id + '"!'); //FIXME proper webpack error/warning
}
entry.id = id;
if (!entry.name) {
entry.name = toImplName(id);
}
if (!/^(controller|helper|model)$/.test(entry.type)) {
warn('impl-utils.addFromOptions(): entry from implOptions for ID "' + id + '" has invalid type ' + JSON.stringify(entry.type) + ', overwritting the type field with "controller"!'); //FIXME proper webpack error/warning
entry.type = 'controller';
}
//TODO verify existence of entry.file?
if (!contains(list, id, entry.type)) {
log('impl-utils.addFromOptions(): adding ', entry); //DEBUG
list.push(entry);
}
else {
warn('impl-utils.addFromOptions(): entry from implOptions for ID ' + id + ' already exists in implementation-list, ignoring entry!'); //FIXME proper webpack error/warning
}
}
else { //DEBUG
log('impl-utils.addFromOptions(): entry for ' + id + ' has no file set -> ignore ', impl); //DEBU
}
}
}
function contains(implList, id, type) {
return implList.findIndex(function (item) {
return item.id === id && item.type === type;
}) !== -1;
}
function toImplName(id) {
return id[0].toUpperCase() + id.substring(1);
}
function toAliasPath(impl) {
return path_1.default.normalize(impl.file).replace(/\.js$/i, '');
}
function toAliasId(impl) {
return 'mmirf/' + impl.type + '/' + impl.id; //FIXME formalize IDs for loading views in webpack (?)
}
module.exports = {
/**
* [description]
* @param {"controller" | "helper" | "model"} mode the kind of implementation (modules) that the directory contains
* @param {ImplOptions} options the implementation options where
* options.path: REQUIRED the directory from which to add the implementations, and has the following structure:
* <directory>/<module-id-1>.js
* <directory>/<module-id-2>.js
* ...
* options["controllers" | "helpers" | "models"]: OPTIONAL a map of impl. IDs, i.e. {[implID: string]: ImplOption} with specific options for processing the corresponding implementation:
* options[types][id].exclude {Boolean}: OPTIONAL if <code>true</code>, the corresponding implementation will be excluded
* options[types][id].addModuleExport {Boolean|String}: OPTIONAL if <code>true</code>, the implementation will be exported,
* i.e. will be made a "requireable module"; the exported variable will be the impl. name,
* or, if addModuleExport is a String, this String will be used.
* @param {String} appRootDir the root directory of the app (against which relative paths will be resolved)
* @param {Array<ImplEntry>} [implList] OPTIONAL list of ImplEntry objects, to which the new entries (read from the options.directory) will be added
* if omitted, a new list will be created and returned.
* ImplEntry.id {String}: the implementation ID
* ImplEntry.name {String}: the implementation's name (usually the ID with capitalized first letter)
* ImplEntry.type {"controller" | "helper" | "model"}: the implementation's type
* ImplEntry.file {String}: the path to the implementation's file
* ImplEntry.addModuleExport {Boolean|String}: OPTIONAL if <code>true</code>, the implementation will be exported,
* i.e. will be made a "requireable module"; the exported variable will be the impl. name,
* or, if addModuleExport is a String, this String will be used.
* @return {Array<ImplEntry>} the list of ImplEntry objects
*/
implFromDir: function (mode, options, appRootDir, implList) {
var dir = options.path;
if (!path_1.default.isAbsolute(dir)) {
dir = path_1.default.resolve(appRootDir, dir);
}
var list = implList || [];
readDir(mode, dir, list, options[mode + 's'], options);
return list;
},
/**
* add implementations form options[mode+'s'] map {[implID: string]: ImplOption}, if the ImplOption has a <code>file</code> field set.
* @param {"controller" | "helper" | "model"} mode the kind of implementation (modules) that the directory contains
* @param {ImplOptions} options the implementation options with field options[mode+'s'], e.g. option.controllers for mode "controller"
* @param {String} appRootDir the root directory of the app (against which relative paths will be resolved)
* @param {{Array<ImplEntry>}} [implList] OPTIONAL
* @return {{Array<ImplEntry>}}
*/
implFromOptions: function (mode, options, appRootDir, implList) {
var list = implList || [];
addFromOptions(options[mode + 's'], list, appRootDir, options);
return list;
},
/**
* apply the "global" options from `options` or default values to the entries
* from `implList` if its corresponding options-field is not explicitly specified.
*
* @param {ImplOptions} options the implementation options
* @param {{Array<ImplEntry>}} implList
* @return {{Array<ImplEntry>}}
*/
applyDefaultOptions: function (options, implList) {
implList.forEach(function (impl) {
[
{ name: 'addModuleExport', defaultValue: false }
].forEach(function (fieldInfo) {
option_utils_1.default.applySetting(fieldInfo.name, impl, options, fieldInfo.defaultValue);
});
});
return implList;
},
/**
* add implementations to (webpack) app build configuration
*
* @param {Array<ImplEntry>} implList list of ImplEntry objects:
* impl.id {String}: the impl id (usually the language code, e.g. "en" or "de")
* impl.file {String}: the path to the JSON impl (from which the executable impl will be created)
* @param {[type]} appConfig the app configuration to which the implementations will be added
* @param {[type]} directories the directories.json representation
* @param {ResourcesConfig} _resources the resources configuration
* @param {[type]} runtimeConfiguration the configuration.json representation
*/
addImplementationsToAppConfig: function (implList, appConfig, directories, _resources, _runtimeConfiguration) {
if (!implList || implList.length < 1) {
return;
}
implList.forEach(function (impl) {
var aliasId = toAliasId(impl);
module_config_init_1.default.addIncludeModule(appConfig, aliasId, toAliasPath(impl));
log('impl-utils.addImplementationsToAppConfig(): adding ' + impl.type + ' implemenation ' + impl.id + ': [' + aliasId + '] -> "' + toAliasPath(impl) + '"!');
switch (impl.type) {
case 'controller':
directories_utils_1.default.addCtrl(directories, aliasId);
break;
case 'helper':
directories_utils_1.default.addHelper(directories, aliasId);
break;
case 'model':
directories_utils_1.default.addModel(directories, aliasId);
break;
default:
warn('impl-utils.addImplementationsToAppConfig(): unknown type ' + impl.type + ' for implemenation ' + impl.id + ' at "' + impl.file + '"!');
break;
}
});
}
};