confit
Version:
Environment-aware configuration.
100 lines (86 loc) • 4.3 kB
JavaScript
/*───────────────────────────────────────────────────────────────────────────*\
│ Copyright (C) 2016 PayPal │
│ │
│ Licensed under the Apache License, Version 2.0 (the "License"); │
│ you may not use this file except in compliance with the License. │
│ You may obtain a copy of the License at │
│ │
│ http://www.apache.org/licenses/LICENSE-2.0 │
│ │
│ Unless required by applicable law or agreed to in writing, software │
│ distributed under the License is distributed on an "AS IS" BASIS, │
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
│ See the License for the specific language governing permissions and │
│ limitations under the License. │
\*───────────────────────────────────────────────────────────────────────────*/
;
const Path = require('path');
const shush = require('shush');
const { debuglog } = require('util');
const Config = require('./config');
const Common = require('./common');
const Handlers = require('./handlers');
const Provider = require('./provider');
const debug = debuglog('confit');
class Factory {
constructor({ basedir, protocols = {}, defaults = 'config.json', envignore = []}) {
this.envignore = envignore.push('env');
this.basedir = basedir;
this.protocols = protocols;
this.promise = Promise.resolve({})
.then(store => Common.merge(Provider.convenience(), store))
.then(Factory.conditional(store => {
let file = Path.join(this.basedir, defaults);
return Handlers.resolveImport(shush(file), this.basedir)
.then(data => Common.merge(data, store));
}))
.then(Factory.conditional(store => {
let file = Path.join(this.basedir, `${store.env.env}.json`);
return Handlers.resolveImport(shush(file), this.basedir)
.then(data => Common.merge(shush(file), store));
}))
.then(store => Common.merge(Provider.env(envignore), store))
.then(store => Common.merge(Provider.argv(), store));
}
addDefault(obj) {
this._add(obj, (store, data) => Common.merge(store, data));
return this;
}
addOverride(obj) {
this._add(obj, (store, data) => Common.merge(data, store));
return this;
}
create(cb) {
this.promise
.then(store => Handlers.resolveImport(store, this.basedir))
.then(store => Handlers.resolveCustom(store, this.protocols))
.then(store => Handlers.resolveConfig(store))
.then(store => cb(null, new Config(store))).catch(cb);
}
_add(obj, fn) {
let data = this._resolveFile(obj);
let handler = Handlers.resolveImport(data, this.basedir);
this.promise = Promise.all([this.promise, handler]).then(([store, data]) => fn(store, data));
}
_resolveFile(path) {
if (typeof path === 'string') {
let file = Common.isAbsolute(path) ? path : Path.join(this.basedir, path);
return shush(file);
}
return path;
}
static conditional(fn) {
return function (store) {
try {
return fn(store);
} catch (err) {
if (err.code && err.code === 'MODULE_NOT_FOUND') {
debug(`WARNING: ${err.message}`);
return store;
}
throw err;
}
}
}
}
module.exports = Factory;