@foal/core
Version:
Full-featured Node.js framework, with no complexity
195 lines (194 loc) • 6.46 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Config = void 0;
// 3p
const fs_1 = require("fs");
const path_1 = require("path");
// FoalTS
const config_not_found_error_1 = require("./config-not-found.error");
const config_type_error_1 = require("./config-type.error");
const env_1 = require("./env");
/**
* Static class to access environment variables and configuration files.
*
* This class can also be used as a service.
*
* @export
* @class Config
*/
class Config {
static get(key, type, defaultValue) {
const value = this.readConfigValue(key);
if (value === undefined) {
return defaultValue;
}
if (type === 'string' && typeof value !== 'string') {
throw new config_type_error_1.ConfigTypeError(key, 'string', typeof value);
}
if (type === 'boolean' && typeof value !== 'boolean') {
if (value === 'true') {
return true;
}
if (value === 'false') {
return false;
}
throw new config_type_error_1.ConfigTypeError(key, 'boolean', typeof value);
}
if (type === 'number' && typeof value !== 'number') {
if (typeof value === 'string' && value.replace(/ /g, '') !== '') {
const n = Number(value);
if (!isNaN(n)) {
return n;
}
}
throw new config_type_error_1.ConfigTypeError(key, 'number', typeof value);
}
if (type === 'boolean|string' && typeof value !== 'boolean') {
if (value === 'true') {
return true;
}
if (value === 'false') {
return false;
}
if (typeof value !== 'string') {
throw new config_type_error_1.ConfigTypeError(key, 'boolean|string', typeof value);
}
}
if (type === 'number|string' && typeof value !== 'number') {
if (typeof value !== 'string') {
throw new config_type_error_1.ConfigTypeError(key, 'number|string', typeof value);
}
if (value.replace(/ /g, '') !== '') {
const n = Number(value);
if (!isNaN(n)) {
return n;
}
}
}
return value;
}
/**
* Read the configuration value associated with the given key. Optionaly check its type.
*
* Throw an ConfigNotFoundError if no value is found.
*
* @static
* @template T
* @param {string} key - The configuration key.
* @param {T} [type] - The expected type of the returned value.
* @param {string} [msg] - The message of the ConfigNotFoundError if no value is found.
* @returns {ValueType<T>} The configuration value.
* @memberof Config
*/
static getOrThrow(key, type, msg) {
const value = this.get(key, type);
if (value === undefined) {
throw new config_not_found_error_1.ConfigNotFoundError(key, msg);
}
return value;
}
/**
* Clear the cache of the loaded files.
*
* @static
* @memberof Config
*/
static clearCache() {
this.config = null;
this.testConfig.clear();
}
static set(key, value) {
this.testConfig.set(key, value);
}
static remove(key) {
this.testConfig.delete(key);
}
static yaml;
static config = null;
static testConfig = new Map();
static readJSON(path) {
if (!(0, fs_1.existsSync)(path)) {
return {};
}
const fileContent = (0, fs_1.readFileSync)(path, 'utf8');
return JSON.parse(fileContent);
}
static readYAML(path) {
if (!(0, fs_1.existsSync)(path)) {
return {};
}
const yaml = this.getYAMLInstance();
if (!yaml) {
console.log(`Impossible to read ${path}. The package "yamljs" is not installed.`);
return {};
}
const fileContent = (0, fs_1.readFileSync)(path, 'utf8');
return yaml.parse(fileContent);
}
static readJS(path) {
if (!(0, fs_1.existsSync)(path)) {
return {};
}
return require((0, path_1.join)(process.cwd(), path));
}
static readConfigValue(key) {
if (this.testConfig.has(key)) {
return this.testConfig.get(key);
}
if (this.config === null) {
this.config = [
this.readJS('config/default.js'),
this.readYAML('config/default.yml'),
this.readJSON('config/default.json'),
this.readJS(`config/${env_1.Env.getEnvironmentName()}.js`),
this.readYAML(`config/${env_1.Env.getEnvironmentName()}.yml`),
this.readJSON(`config/${env_1.Env.getEnvironmentName()}.json`),
].reduce((config1, config2) => this.mergeDeep(config1, config2));
}
const properties = key.split('.');
let result = this.config;
for (const property of properties) {
result = result[property];
if (result === undefined) {
break;
}
}
if (typeof result === 'string' && result.startsWith('env(') && result.endsWith(')')) {
const envVarName = result.substr(4, result.length - 5);
return env_1.Env.get(envVarName);
}
return result;
}
static mergeDeep(target, source) {
// TODO: improve the tests of this function.
function isObject(o) {
return typeof o === 'object' && o !== null;
}
for (const key in source) {
if (isObject(target[key]) && isObject(source[key])) {
this.mergeDeep(target[key], source[key]);
}
else if (source[key] !== undefined) {
target[key] = source[key];
}
}
return target;
}
static getYAMLInstance() {
// TODO: test this method (hard).
if (this.yaml === false) {
return false;
}
try {
this.yaml = require('yamljs');
}
catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') {
throw err;
}
this.yaml = false;
}
return this.yaml;
}
}
exports.Config = Config;