botpress
Version:
The world's first CMS for bots. Easily create, manage and extend chatbots.
203 lines (157 loc) • 8.82 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _joi = require('joi');
var _joi2 = _interopRequireDefault(_joi);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _yn = require('yn');
var _yn2 = _interopRequireDefault(_yn);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _json = require('json5');
var _json2 = _interopRequireDefault(_json);
var _module = require('./module');
var _module2 = _interopRequireDefault(_module);
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /**
* The Configuration Manager is in charge of the configuration
* for all the modules. It knows how to provision and load configuration
* from the right places (env variables, files, botfile).
* @namespace ConfigurationManager
* @private
*/
const validations = {
any: (value, validation) => validation(value),
string: (value, validation) => typeof value === 'string' && validation(value),
choice: (value, validation) => _lodash2.default.includes(validation, value),
bool: (value, validation) => ((0, _yn2.default)(value) === true || (0, _yn2.default)(value) === false) && validation(value)
};
const transformers = {
bool: value => (0, _yn2.default)(value)
};
const defaultValues = {
any: null,
string: '',
bool: false
};
const amendOption = (option, name) => {
const validTypes = _lodash2.default.keys(validations);
if (!option.type || !_lodash2.default.includes(validTypes, option.type)) {
throw new Error(`Invalid type (${option.type || ''}) for config key (${name})`);
}
const validation = option.validation || (() => true);
if (typeof option.default !== 'undefined' && !validations[option.type](option.default, validation)) {
throw new Error(`Invalid default value (${option.default}) for (${name})`);
}
if (!option.default && !_lodash2.default.includes(_lodash2.default.keys(defaultValues), option.type)) {
throw new Error(`Default value is mandatory for type ${option.type} (${name})`);
}
return {
type: option.type,
required: option.required || false,
env: option.env || null,
default: option.default || defaultValues[option.type],
validation: validation
};
};
const amendOptions = options => {
return _lodash2.default.mapValues(options, amendOption);
};
class ConfigurationManager {
constructor(options) {
if (_util.isDeveloping) {
const schema = _joi2.default.object().keys({
configLocation: _joi2.default.string().min(1).required(),
botfile: _joi2.default.object().required(),
logger: _joi2.default.object().required()
});
_joi2.default.assert(options, schema, 'Invalid constructor elements for Configuration Manager');
}
this.configLocation = options.configLocation;
this.botfile = options.botfile;
this.logger = options.logger;
this._memoizedLoadAll = _lodash2.default.memoize(this._loadAll.bind(this));
}
_loadFromDefaultValues(options) {
return _lodash2.default.mapValues(options, value => value.default);
}
_loadFromConfigFile(file, options) {
const filePath = _path2.default.resolve(this.configLocation, file);
if (_fs2.default.existsSync(filePath)) {
const content = _fs2.default.readFileSync(filePath, 'utf8');
return _json2.default.parse(content);
}
return {};
}
_loadFromEnvVariables(options) {
const obj = {};
_lodash2.default.mapValues(process.env, (value, key) => {
if (_lodash2.default.isNil(value)) {
return;
}
const entry = _lodash2.default.findKey(options, { env: key });
if (entry) {
obj[entry] = value;
}
});
return obj;
}
_loadAll(file, options = {}) {
options = amendOptions(options);
let config = this._loadFromDefaultValues(options);
Object.assign(config, this._loadFromConfigFile(file, options));
Object.assign(config, this._loadFromEnvVariables(options));
// Transform the values if there's a transformer for this type of value
config = _lodash2.default.mapValues(config, (value, key) => {
const { type } = options[key];
if (transformers[type]) {
return transformers[type](value);
} else {
return value;
}
});
return config;
}
/**
* Returns a Configuration for a specific module
* @param {Object} module A module object
* @private
* @return {ModuleConfiguration} A module-specific configuration
*/
getModuleConfiguration(module) {
return new _module2.default({
manager: this,
module: module,
configLocation: this.configLocation,
logger: this.logger
});
}
/**
* Loads configuration from the right module
* @param {String} file The name of the configuration file
* @param {Object} options
* @private
* @return {Object} The full configuration object, assembled from various sources
*/
loadAll(file, options, caching = true) {
var _this = this;
return _asyncToGenerator(function* () {
const getter = caching ? _this._memoizedLoadAll : _this._loadAll;
return getter(file, options);
})();
}
get(file, key, options, caching = true) {
var _this2 = this;
return _asyncToGenerator(function* () {
const config = yield _this2.loadAll(file, options, caching);
return config[key];
})();
}
}
exports.default = ConfigurationManager;
//# sourceMappingURL=index.js.map