'use strict';
var fs = require('fs');
var ini = require('ini');
var merge = require('recursive-merge');
var _ = require('lodash');
/**
* @private
* @function readConfig
*
* @description Reads file and parses ini
*
* @param {string} filename
* @param {boolean} mustExist throws exception on missing
*
* @returns {object}
*/
function readConfig(filename, mustExist) {
try {
return ini.parse(fs.readFileSync(filename, 'utf8'));
} catch(e) {
Iif (mustExist) {
throw e;
}
return {};
}
}
/**
* @public
* @function configReader
*
* @description Reads and merge multiple configuration files
* Files passed in first take the highest presidence.
*
* @example: configReader(['a.ini', 'b.ini'])
* if a.ini and b.ini have same config var, a.ini is used
*
* if mustPass is true and no files exist, returns empty object {}
*
* @param {array|string} filenames
* @param {boolean} mustExist raises error if filename is missing
*
* @returns {object}
*/
const ConfigReader = function(filenames, mustExist) {
const _this = this;
Iif (!filenames) {
throw new Error('no config filenames specified');
}
Iif (!_.isArray(filenames)) {
filenames = [filenames];
}
var configs = _(filenames).map(function(filename) {
return readConfig(filename, mustExist);
}).value();
var configData = {};
_.each(configs, function(c) {
merge(configData, c);
});
_.each(configData, function(values, key) {
_this[key] = values;
});
return _this;
};
ConfigReader.prototype.getString = function (section, option, def_val) {
const _this = this;
try {
const sec = _this[section];
if (sec === undefined) {
throw new Error('no section: [' + section + '] for: ' + option);
}
const val = sec[option];
if (val === undefined) {
throw new Error('config not found: [' + section + '].' + option);
}
return String(val).trim();
} catch(e) {
if (typeof def_val === 'undefined') {
throw e;
}
return def_val;
}
};
ConfigReader.prototype.getNumber = function (section, option, def_val) {
const _this = this;
const val = _this.getString(section, option, def_val);
if (isNaN(val)) {
throw new Error('config [' + section + '].' + option + ' NaN: ' + val);
}
return Number(val);
};
ConfigReader.prototype.getBoolean = function (section, option, def_val) {
const _this = this;
const val = _this.getString(section, option, def_val);
switch (String(val).toLowerCase()) {
case 'true':
case 'yes':
case 'on':
case '1':
return true;
case 'false':
case 'no':
case 'off':
case '0':
return false;
default:
throw new Error('config [' + section + '].' + option + ' not bool: ' + val);
}
};
module.exports = function(filenames, mustExist) {
return new ConfigReader(filenames, mustExist);
};
|