'use strict'; const container = require('../Container'); const path = container.get('path'); // Load environment file require('dotenv').config({ path: path.resolve(__dirname, '../../.env'), }); const fs = require('fs'); const glob = require('glob'); const configSslPath = path.resolve(__dirname, '../config/ssl'); const configPath = path.resolve(__dirname, '../config'); const defaultConfig = new Map([ ['host', 'localhost'], ['http', true], ['http-port', 80], ['https', false], ['https-port', 443], ['node-env', 'development'], ]); const configFiles = glob.sync(`${configPath}/**/*.js`); /** * Config management class * * Hierarchy of config options * 1. Directly defined config options * 2. Environment variables * 3. Default values */ class Config { constructor() { let _configMap = new Map(); // Load files in config folder under their // own respective namespaces configFiles.forEach((fullPath) => { let key = path.basename(fullPath, '.js'); _configMap.set(key, require(fullPath)); }); this._config = _configMap; } /** * Returns the list of available configuration keys * * @return {array} - the list of configuration keys */ keys() { let keys = []; for (let key of this._config.keys()) { keys.push(key); } return keys; } /** * Determine if a config value exists * * @param {string|symbol} key - the config value key * @return {boolean} - whether the config value exists */ has(key) { return this._config.has(key); } /** * Determine whether an environment variable is currently defined * * @param {string} key - the environment varaible to look for * @return {boolean} - whether the environment variable is defined */ hasEnv(key) { return process.env[this._envName(key)] != null; } /** * Retrieve a config value * * @param {string|symbol} key - the name of the config value * @return {*} - the configuration value */ get(key) { if (! this.has(key)) { // Fallback to environment variables let envKey = key.toUpperCase().replace('-', '_'); if (this.hasEnv(envKey)) { let envValue = this.getEnv(envKey); this._config.set(key, envValue); return envValue; } // Fallback to default values if (defaultConfig.has(key)) { let defaultValue = defaultConfig.get(key); this._config.set(key, defaultValue); return defaultValue; } } return this._config.get(key); } /** * Get the value of an environment variable * * @param {string} key - the environment variable to get * @return {string|undefined} - the value of the environment variable */ getEnv(key) { let raw = process.env[this._envName(key)]; return this._normalizeValue(raw); } /** * Get equivalent environment variable for config key * * @private * @param {string} key - the config key * @return {string} - the environment variable name */ _envName(key) { return key.toUpperCase().replace('-', '_'); } /** * Attempt to parse javascript types from strings * * @private * @param {string} val - the string value * @return {string|number|boolean} - the 'parsed' value */ _normalizeValue(val) { let bool = /^true|false$/; let integer = /^([0-9]+)$/; if (String(val).search(integer) !== -1) { return parseInt(val, 10); } if (String(val).search(bool) !== -1) { switch (val) { case 'true': return true; // return overrides break case 'false': return false; // return overrides break } } return val; } /** * Set a config variable (mainly for testing) * * @private * @param {mixed} key - the key to set * @param {mixed} val - the value for the key * @return {Config} - the config instance */ _set(key, val) { this._config.set(key, val); return this; } } module.exports = new Config();