gofigure
Version:
Configuration library for node
130 lines (119 loc) • 3.84 kB
JavaScript
/**
* @projectName gofigure
* @github http://github.com/C2FO/gofigure
* @header [../README.md]
* @includeDoc [Change Log] ../History.md
*/
const _ = require('lodash');
const PatternEventEmitter = require('./PatternEventEmitter');
const loader = require('./loader');
const processor = require('./processor');
class ConfigLocation extends PatternEventEmitter {
/**
* Aggregate class for a single entry in the `locations` array.
*
* Locations will load all the config files specified within their list
* and then merge them together.
*
* @param {{ file: string }} locationName the location that this instance should own
* @param opts @see ConfigLoader
*/
constructor(locationName, opts) {
super({});
if (!locationName) {
throw new Error('A locationName is required');
}
const options = opts || {};
this.environment = options.environment || process.env.NODE_ENV || null;
this.nodeType = options.nodeType || process.env.NODE_TYPE || null;
this.environmentVariables = options.environmentVariables || process.env || {};
this.defaultEnvironment = options.defaultEnvironment || '*';
this.config = {};
this.monitor = !!options.monitor;
this.locationName = locationName;
this.loaded = false;
}
/**
* Stops monitoring confgurations for changes.
*
* @return {Config} this config object.
*/
stop() {
this.__loaders.forEach((l) => l.unWatch());
return this;
}
/**
* Asynchronously loads configs.
*
* @example
* configLoader.load().then((config) => {
* // use the config.
* })
*
* @return {Promise<any>|Promise<any[] | never>} resolves with the merged configuration from all locations.s
*/
load() {
if (this.__loaded) {
return Promise.resolve(this.config);
}
return loader.createLoadersAsync(this.locationName, { monitor: this.monitor }).then((loaders) => {
this.__loaders = loaders;
const loads = loaders.map((l) => l.load());
return Promise.all(loads).then((configs) => this.__postLoad(configs));
});
}
/**
* Synchronously loads configurations.
*
* @example
* const config = configLoader.loadSync()
* //use your config.
*
* @return {Object} the merged configuration from all locations.
*/
loadSync() {
if (this.__loaded) {
return this.config;
}
this.__loaders = loader.createLoadersSync(this.locationName, { monitor: this.monitor });
return this.__postLoad(this.__loaders.map((l) => l.loadSync()));
}
__mergeConfigs(configs) {
return processor(_.cloneDeep(this.config), configs, {
environment: this.environment,
defaultEnvironment: this.defaultEnvironment,
nodeType: this.nodeType,
eventEmitter: this,
environmentVariables: this.environmentVariables,
});
}
/**
* Merges configs and starts monitoring of configs if `monitor` is true.
* @param configs {Array<Object>} an array of configurations to merge into a single object.
* @return {Object} the merged config
* @private
*/
__postLoad(configs) {
this.config = this.__mergeConfigs(configs);
this.__listenToChanges();
this.__loaded = true;
return this.config;
}
__listenToChanges() {
this.__loaders.forEach((l) =>
l.on('change', (path, config) => {
/**
* Whenever one of our loaders reports that their file was changed,
* we forward that event onward.
*
* The `config` object here is just the raw contents of the file. Our "parent"
* listener expects us to forward them the resolved config, so we process it before
* forwarding it.
*/
this.config = this.__mergeConfigs([config]);
this.emit('change', this.config);
}),
);
}
}
module.exports = ConfigLocation;