@kitmi/config
Version:
JavaScript env-aware config system
233 lines (232 loc) • 8.85 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
EnvAwareJsonConfigProvider: function() {
return EnvAwareJsonConfigProvider;
},
EnvAwareYamlConfigProvider: function() {
return EnvAwareYamlConfigProvider;
},
default: function() {
return _default;
}
});
const _utils = require("@kitmi/utils");
const _JsonConfigProvider = /*#__PURE__*/ _interop_require_default(require("./JsonConfigProvider.js"));
const _YamlConfigProvider = /*#__PURE__*/ _interop_require_default(require("./YamlConfigProvider.js"));
const _EnvAwareConfigProviderF = /*#__PURE__*/ _interop_require_default(require("./EnvAwareConfigProviderF.js"));
const _defaultSyntax = /*#__PURE__*/ _interop_require_wildcard(require("./defaultSyntax.js"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
const EnvAwareJsonConfigProvider = (0, _EnvAwareConfigProviderF.default)('.json', _JsonConfigProvider.default);
const EnvAwareYamlConfigProvider = (0, _EnvAwareConfigProviderF.default)('.yaml', _YamlConfigProvider.default);
class ConfigLoader {
/**
* Create an environment aware JSON config loader
* @param {string} configDir
* @param {string} baseName
* @param {string} envFlag
* @param {Logger} logger
* @param {function} overrider
* @param {object} postProcessors
*/ static createEnvAwareJsonLoader(configDir, baseName, envFlag, logger, overrider, postProcessors) {
return new ConfigLoader(new EnvAwareJsonConfigProvider(configDir, baseName, envFlag, overrider), logger, postProcessors);
}
/**
* Create an environment aware YAML config loader
* @param {string} configDir
* @param {string} baseName
* @param {string} envFlag
* @param {Logger} logger
* @param {function} overrider
* @param {object} postProcessors
*/ static createEnvAwareYamlLoader(configDir, baseName, envFlag, logger, overrider, postProcessors) {
return new ConfigLoader(new EnvAwareYamlConfigProvider(configDir, baseName, envFlag, overrider), logger, postProcessors);
}
/**
* Start loading the config files and override existing
* @param {object} variables - variables
* @returns {Promise.<object>}
*/ async load_(variables) {
const oldData = this.data;
await this.reload_(variables);
if (oldData) {
this.data = _utils._.defaults(this.data, oldData);
}
return this.data;
}
/**
* Reload config
* @returns {Promise.<object>}
*/ async reload_(variables) {
this.data = await this.provider.load_(this.logger, true);
if (this.autoPostProcess) this.postProcess(variables);
return this.data;
}
/**
* PostProcess the loaded config
* @param {object} variables - variables
*/ postProcess(variables) {
const queue = [
this.data
];
this._l = this.postProcessors.prefix.length;
variables = {
...variables,
$this: this.data
};
const interpolateElement = (coll, key, val)=>{
// Process the value
if (typeof val === 'string') {
coll[key] = this._tryProcessStringValue(val, variables);
} else if (_utils._.isPlainObject(val) || _utils._.isArray(val)) {
queue.push(val);
}
// Process the key if it's wrapped in brackets
if (typeof key === 'string' && key.startsWith('[') && key.endsWith(']')) {
const keyContent = key.substring(1, key.length - 1);
const processedKey = this._tryProcessStringValue(keyContent, variables);
if (key !== `[${processedKey}]`) {
// Create new entry with processed key and delete the old one
coll[processedKey] = coll[key];
delete coll[key];
}
}
};
let offset = 0;
while(queue.length > offset){
const node = queue[offset];
if (_utils._.isPlainObject(node)) {
_utils._.forOwn(node, (value, key)=>{
interpolateElement(node, key, value);
});
} else {
const l = node.length;
for(let i = 0; i < l; i++){
interpolateElement(node, i, node[i]);
}
}
offset++;
}
}
_tryProcessStringValue(strVal, variables) {
if (strVal.startsWith(this.postProcessors.prefix)) {
const colonPos = strVal.indexOf(':');
if (colonPos > this._l) {
const token = strVal.substring(this._l, colonPos);
const operator = this.postProcessors.processors[token];
if (operator) {
return operator(strVal.substring(colonPos + 1), variables);
}
throw new Error('Unsupported post processor: ' + token);
}
throw new Error('Invalid post processor syntax: ' + strVal);
} else if (strVal.startsWith('${') && strVal.endsWith('}')) {
const operator = this.postProcessors.processors[_defaultSyntax.ES6_TEMPLATE_TOKEN];
return operator(strVal, variables);
}
return strVal;
}
/**
* The config loader
* @constructs ConfigLoader
* @extends EventEmitter
* @example
* let fileSource = new JsonConfigProvider('path/to/config.json');
* let config = new ConfigLoader(fileSource);
* await config.load_()...;
*
* let dbSource = new DbConfigProvider(config.data.dbConnection);
* config.provider = dbSource;
* await config.reload_()...;
*
* // same as: let envAwareLoader = new ConfigLoader(
* // new (EnvAwareConfigProviderF('.json', JsonConfigProvider, 'default'))('config/dir', 'app', 'production')
* // );
* let envAwareLoader = ConfigLoader.createEnvAwareJsonLoader('config/dir', 'app', 'production');
*
* // Loader will load config/dir/app.default.json first,
* // and then load config/dir/app.production.json,
* // and finally override the default.
* let cfg = await envAwareLoader.load_();
*/ constructor(configProvider, logger, postProcessors){
/**
* The config data source provider
* @type {object}
* @public
**/ this.provider = configProvider;
/**
* The config data
* @type {object}
* @public
**/ this.data = undefined;
/**
* Whether to do string post process automatically after loading
* @type {boolean}
* @public
*/ this.autoPostProcess = true;
/**
* Logger with log(level, message, meta) function.
* @type {Logger}
* @public
*/ this.logger = logger;
/**
* Post processors
* @private
*/ this.postProcessors = postProcessors != null ? _utils._.defaultsDeep(postProcessors, _defaultSyntax.default) : _defaultSyntax.default;
}
}
const _default = ConfigLoader;
//# sourceMappingURL=ConfigLoader.js.map