actionhero
Version:
actionhero.js is a multi-transport API Server with integrated cluster capabilities and delayed tasks
170 lines (169 loc) • 7.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.config = exports.buildConfig = exports.configPaths = void 0;
const fs = require("fs");
const path = require("path");
const glob = require("glob");
const optimist_1 = require("optimist");
const utils_1 = require("./utils");
const ensureNoTsHeaderFiles_1 = require("./utils/ensureNoTsHeaderFiles");
const env_1 = require("./../classes/process/env");
const id_1 = require("./../classes/process/id");
const actionheroVersion_1 = require("./../classes/process/actionheroVersion");
const typescript_1 = require("./../classes/process/typescript");
const projectRoot_1 = require("./../classes/process/projectRoot");
exports.configPaths = [];
function buildConfig(_startingParams = {}) {
let config = {
process: {
env: env_1.env,
id: id_1.id,
typescript: typescript_1.typescript,
projectRoot: projectRoot_1.projectRoot,
actionheroVersion: actionheroVersion_1.actionheroVersion,
},
};
utils_1.utils.hashMerge(config, _startingParams);
// We support multiple configuration paths as follows:
//
// 1. Use the project 'config' folder, if it exists.
// 2. "actionhero --config=PATH1 --config=PATH2 --config=PATH3,PATH4"
// 3. "ACTIONHERO_CONFIG=PATH1,PATH2 npm start"
//
// Note that if --config or ACTIONHERO_CONFIG are used, they _overwrite_ the use of the default "config" folder. If
// you wish to use both, you need to re-specify "config", e.g. "--config=config,local-config". Also, note that
// specifying multiple --config options on the command line does exactly the same thing as using one parameter with
// comma separators, however the environment variable method only supports the comma-delimited syntax.
function addConfigPath(pathToCheck, alreadySplit) {
if (typeof pathToCheck === "string") {
if (!alreadySplit) {
addConfigPath(pathToCheck.split(","), true);
}
else {
if (pathToCheck.charAt(0) !== "/") {
pathToCheck = path.resolve(projectRoot_1.projectRoot, pathToCheck);
}
if (fs.existsSync(pathToCheck)) {
exports.configPaths.push(pathToCheck);
}
}
}
else if (Array.isArray(pathToCheck)) {
pathToCheck.map((entry) => {
addConfigPath(entry, alreadySplit);
});
}
}
[optimist_1.argv.config, process.env.ACTIONHERO_CONFIG].map((entry) => {
addConfigPath(entry, false);
});
if (exports.configPaths.length < 1 && typescript_1.typescript) {
addConfigPath("src/config", false);
}
if (exports.configPaths.length < 1) {
addConfigPath("dist/config", false);
}
if (exports.configPaths.length < 1) {
throw new Error(exports.configPaths +
"No config directory found in this project. Did you compile your typescript project?");
}
const loadConfigFile = (f) => {
const localConfig = require(f);
if (f.includes("routes.js") || f.includes("routes.ts")) {
let localRoutes = { routes: {} };
if (localConfig.DEFAULT) {
localRoutes = utils_1.utils.hashMerge(localRoutes, localConfig.DEFAULT, config);
}
if (localConfig[env_1.env]) {
localRoutes = utils_1.utils.hashMerge(localRoutes, localConfig[env_1.env], config);
}
Object.keys(localRoutes.routes).forEach((v) => {
if (config.routes && config.routes[v]) {
config.routes[v].push(...localRoutes.routes[v]);
}
else {
if (!config.routes) {
config.routes = {};
}
config.routes[v] = localRoutes.routes[v];
}
});
}
else {
if (localConfig.DEFAULT) {
config = utils_1.utils.hashMerge(config, localConfig.DEFAULT, config);
}
if (localConfig[env_1.env]) {
config = utils_1.utils.hashMerge(config, localConfig[env_1.env], config);
}
}
};
const loadConfigDirectory = (configPath, watch) => {
const configFiles = ensureNoTsHeaderFiles_1.ensureNoTsHeaderFiles(glob.sync(path.join(configPath, "**", "**/*(*.js|*.ts)")));
let loadRetries = 0;
let loadErrors = {};
for (let i = 0, limit = configFiles.length; i < limit; i++) {
const f = configFiles[i];
try {
// attempt configuration file load
loadConfigFile(f);
// configuration file load success: clear retries and
// errors since progress has been made
loadRetries = 0;
loadErrors = {};
}
catch (error) {
// error loading configuration, abort if all remaining
// configuration files have been tried and failed
// indicating inability to progress
loadErrors[f] = { error: error, msg: error.toString() };
if (++loadRetries === limit - i) {
Object.keys(loadErrors).forEach((e) => {
console.log(loadErrors[e].error.stack);
console.log("");
delete loadErrors[e].error;
});
throw new Error("Unable to load configurations, errors: " +
JSON.stringify(loadErrors));
}
// adjust configuration files list: remove and push
// failed configuration to the end of the list and
// continue with next file at same index
configFiles.push(configFiles.splice(i--, 1)[0]);
continue;
}
}
// We load the config twice. Utilize configuration files load order that succeeded on the first pass.
// This is to allow 'literal' values to be loaded whenever possible, and then for references to be resolved
configFiles.forEach(loadConfigFile);
// Remove duplicate routes since we might be loading from multiple config directories, also we load every
// config directory twice.
if (config.routes) {
Object.keys(config.routes).forEach((v) => {
config.routes[v] = config.routes[v].filter((route, index, self) => index ===
self.findIndex((r) => r.path === route.path &&
r.action === route.action &&
r.apiVersion === route.apiVersion &&
r.matchTrailingPathParts === route.matchTrailingPathParts &&
r.dir === route.dir));
});
}
};
// load the default config of actionhero
loadConfigDirectory(path.join(__dirname, "/../config"), false);
// load the project specific config
exports.configPaths.map((p) => loadConfigDirectory(p, false));
// apply any configChanges
if (_startingParams && _startingParams.configChanges) {
config = utils_1.utils.hashMerge(config, _startingParams.configChanges);
}
if (process.env.configChanges) {
config = utils_1.utils.hashMerge(config, JSON.parse(process.env.configChanges));
}
if (optimist_1.argv.configChanges) {
config = utils_1.utils.hashMerge(config, JSON.parse(optimist_1.argv.configChanges));
}
return config;
}
exports.buildConfig = buildConfig;
exports.config = buildConfig();