diff --git a/README.md b/README.md index aa395d1..fcc7776 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -# nconf [![Build Status](https://secure.travis-ci.org/flatiron/nconf.png)](http://travis-ci.org/flatiron/nconf) +# nconf + +[![Version npm](https://img.shields.io/npm/v/nconf.svg?style=flat-square)](https://www.npmjs.com/package/nconf)[![npm Downloads](https://img.shields.io/npm/dm/nconf.svg?style=flat-square)](https://www.npmjs.com/package/nconf)[![Build Status](https://img.shields.io/travis/indexzero/nconf/master.svg?style=flat-square)](https://travis-ci.org/indexzero/nconf)[![Dependencies](https://img.shields.io/david/indexzero/nconf.svg?style=flat-square)](https://david-dm.org/indexzero/nconf) + +[![NPM](https://nodei.co/npm/nconf.png?downloads=true&downloadRank=true)](https://nodei.co/npm/nconf/) Hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging. @@ -61,7 +65,7 @@ The output will be: Configuration management can get complicated very quickly for even trivial applications running in production. `nconf` addresses this problem by enabling you to setup a hierarchy for different sources of configuration with no defaults. **The order in which you attach these configuration sources determines their priority in the hierarchy.** Lets take a look at the options available to you - 1. **nconf.argv(options)** Loads `process.argv` using optimist. If `options` is supplied it is passed along to optimist. + 1. **nconf.argv(options)** Loads `process.argv` using yargs. If `options` is supplied it is passed along to yargs. 2. **nconf.env(options)** Loads `process.env` into the hierarchy. 3. **nconf.file(options)** Loads the configuration data at options.file into the hierarchy. 4. **nconf.defaults(options)** Loads the data in options.store into the hierarchy. @@ -159,11 +163,11 @@ A simple in-memory storage engine that stores a nested JSON representation of th ``` ### Argv -Responsible for loading the values parsed from `process.argv` by `optimist` into the configuration hierarchy. See the [optimist option docs](https://github.com/substack/node-optimist/#optionskey-opt) for more on the option format. +Responsible for loading the values parsed from `process.argv` by `yargs` into the configuration hierarchy. See the [yargs option docs](https://github.com/bcoe/yargs#optionskey-opt) for more on the option format. ``` js // - // Can optionally also be an object literal to pass to `optimist`. + // Can optionally also be an object literal to pass to `yargs`. // nconf.argv({ "x": { diff --git a/docs/nconf/provider.html b/docs/nconf/provider.html index 66c6718..b349626 100644 --- a/docs/nconf/provider.html +++ b/docs/nconf/provider.html @@ -13,7 +13,7 @@

Constructor function for the Provider object responsible for exposing the pluggable storage features of nconf.

var Provider = exports.Provider = function (options) {
-  var self = this;  
+  var self = this;
   

Setup default options for working with stores, overrides, process.env and process.argv.

  options         = options           || {};
   this._overrides = options.overrides || null;
@@ -24,7 +24,7 @@ for exposing the pluggable storage features of nconf.

Add the default system store for working with overrides, process.env, process.argv and a simple in-memory objects.

  this.add('system', options);
-  
+
   if (options.type) {
     this.add(options.type, options);
   }
@@ -42,8 +42,8 @@ a simple in-memory objects.

@options {Object} Options for the store instance.

-

Adds (or replaces) a new store with the specified name -and options. If options.type is not set, then name +

Adds (or replaces) a new store with the specified name +and options. If options.type is not set, then name will be used instead:

provider.use('file'); @@ -54,7 +54,7 @@ will be used instead:

else if (this._reserved.indexOf(name) !== -1) { throw new Error('Cannot use reserved name: ' + name); } - + options = options || {}; var type = options.type || name; @@ -63,18 +63,18 @@ will be used instead:

return options[key] === store[key]; }); } - + var store = this[name], update = store && !sameOptions(store); - + if (!store || update) { if (update) { this.remove(name); } - + this.add(name, options); } - + return this; };

function add (name, options)

@@ -90,17 +90,17 @@ is not set, then name will be used instead:

if (this._reserved.indexOf(name) !== -1) { throw new Error('Cannot use reserved name: ' + name); } - + options = options || {}; var type = options.type || name; - + if (Object.keys(stores).indexOf(common.capitalize(type)) === -1) { throw new Error('Cannot add store with unknown type: ' + type); } - + this[name] = this.create(type, options); this._stores.push(name); - + if (this[name].loadSync) { this[name].loadSync(); } @@ -117,7 +117,7 @@ this was used in the call to .add().

else if (!this[name]) { throw new Error('Cannot remove store that does not exist: ' + name); } - + delete this[name]; this._stores.splice(this._stores.indexOf(name), 1); };

function create (type, options)

@@ -126,7 +126,7 @@ this was used in the call to .add().

@options {Object} Options for the store instance.

-

Creates a store of the specified type using the +

Creates a store of the specified type using the specified options.

Provider.prototype.create = function (type, options) {
   return new stores[common.capitalize(type.toLowerCase())](options);
 };

function get (key, callback)

@@ -139,29 +139,29 @@ specified options.

  if (!callback) {
     return this._execute('get', 1, key, callback);
   }
-  

Otherwise the asynchronous, hierarchical get is +

Otherwise the asynchronous, hierarchical get is slightly more complicated because we do not need to traverse the entire set of stores, but up until there is a defined value.

  var current = 0,
       self = this,
       response;
-      
+
   async.whilst(function () {
     return typeof response === 'undefined' && current < self._stores.length;
   }, function (next) {
     var store = self[self._stores[current]];
     current++;
-    
+
     if (store.get.length >= 2) {
       return store.get(key, function (err, value) {
         if (err) {
           return next(err);
         }
-        
+
         response = value;
         next();
       });
     }
-    
+
     response = store.get(key);
     next();
   }, function (err) {
@@ -182,7 +182,7 @@ the entire set of stores, but up until there is a defined value.

@callback {function} Optional Continuation to respond to when complete.

Clears all keys associated with this instance.

Provider.prototype.reset = function (callback) {
-  return this._execute('reset', 0, callback);  
+  return this._execute('reset', 0, callback);
 };

function clear (key, callback)

@key {string} Key to remove from this instance

@@ -210,19 +210,19 @@ the entire set of stores, but up until there is a defined value.

callback = typeof args[args.length - 1] === 'function' && args.pop(), value = args.pop(), key = args.pop(); - + function mergeProperty (prop, next) { return self._execute('merge', 2, prop, value[prop], next); } - + if (!key) { if (Array.isArray(value) || typeof value !== 'object') { return onError(new Error('Cannot merge non-Object into top-level.'), callback); } - + return async.forEach(Object.keys(value), mergeProperty, callback || function () { }) } - + return this._execute('merge', 2, key, value, callback); };

function load (callback)

@@ -230,34 +230,34 @@ the entire set of stores, but up until there is a defined value.

Responds with an Object representing all keys associated in this instance.

Provider.prototype.load = function (callback) {
   var self = this;
-  
+
   function loadStoreSync(name) {
     var store = self[name];
-    
+
     if (!store.loadSync) {
       throw new Error('nconf store ' + store.type + ' has no loadSync() method');
     }
-    
+
     return store.loadSync();
   }
-  
+
   function loadStore(name, next) {
     var store = self[name];
-    
+
     if (!store.load && !store.loadSync) {
       return next(new Error('nconf store ' + store.type + ' has no load() method'));
     }
-    
+
     return store.loadSync
       ? next(null, store.loadSync())
       : store.load(next);
   }
-  

If we don't have a callback and the current +

If we don't have a callback and the current store is capable of loading synchronously then do so.

  if (!callback) {
     return common.merge(this._stores.map(loadStoreSync));
   }
-  
+
   async.map(this._stores, loadStore, function (err, objs) {
     return err ? callback(err) : callback(null, common.merge(objs));
   });
@@ -273,39 +273,39 @@ instance and then adds all key-value pairs in value. 

callback = value; value = null; } - + var self = this; - + function saveStoreSync(name) { var store = self[name]; - + if (!store.saveSync) { throw new Error('nconf store ' + store.type + ' has no saveSync() method'); } - + return store.saveSync(); } - + function saveStore(name, next) { var store = self[name]; - + if (!store.save && !store.saveSync) { return next(new Error('nconf store ' + store.type + ' has no save() method')); } - + return store.saveSync ? next(null, store.saveSync()) : store.save(next); } -

If we don't have a callback and the current +

If we don't have a callback and the current store is capable of saving synchronously then do so.

  if (!callback) {
     return common.merge(this._stores.map(saveStoreSync));
   }
-  
+
   async.map(this._stores, saveStore, function (err, objs) {
     return err ? callback(err) : callback();
-  });  
+  });
 };

@private function _execute (action, syncLength, [arguments])

@action {string} Action to execute on this.store.

@@ -320,15 +320,15 @@ to a synchronous store function is still invoked.

callback = typeof args[args.length - 1] === 'function' && args.pop(), self = this, response; - + function runAction (name, next) { var store = self[name] - + return store[action].length > syncLength ? store[action].apply(store, args.concat(next)) : next(null, store[action].apply(store, args)); } - + if (callback) { return async.forEach(self._stores, runAction, function (err) { return err ? callback(err) : callback(); @@ -339,40 +339,40 @@ to a synchronous store function is still invoked.

var store = self[name]; response = store[action].apply(store, args); }); - + return response; }

@argv {boolean}

-

Gets or sets a property representing overrides which supercede all +

Gets or sets a property representing overrides which supercede all other values for this instance.

Provider.prototype.__defineSetter__('overrides', function (val) { updateSystem.call(this, 'overrides', val) });
 Provider.prototype.__defineGetter__('overrides', function () { return this._argv });

@argv {boolean}

-

Gets or sets a property indicating if we should wrap calls to .get -by checking optimist.argv. Can be a boolean or the pass-thru -options for optimist.

Provider.prototype.__defineSetter__('argv', function (val) { updateSystem.call(this, 'argv', val) });
+

Gets or sets a property indicating if we should wrap calls to .get +by checking yargs.argv. Can be a boolean or the pass-thru +options for yargs.

Provider.prototype.__defineSetter__('argv', function (val) { updateSystem.call(this, 'argv', val) });
 Provider.prototype.__defineGetter__('argv', function () { return this._argv });

@env {boolean}

-

Gets or sets a property indicating if we should wrap calls to .get -by checking process.env. Can be a boolean or an Array of +

Gets or sets a property indicating if we should wrap calls to .get +by checking process.env. Can be a boolean or an Array of environment variables to extract.

Provider.prototype.__defineSetter__('env', function (val) { updateSystem.call(this, 'env', val) });
 Provider.prototype.__defineGetter__('env', function () { return this._env });

Throw the err if a callback is not supplied

function onError(err, callback) {
   if (callback) {
     return callback(err);
   }
-  
+
   throw err;
 }

Helper function for working with the default system store for providers.

function updateSystem(prop, value) {
   var system = this['system'];
-  
+
   if (system[prop] === value) {
     return;
   }
-  
+
   value = value || false;
   this['_' + prop] = value;
   system[prop] = value;
   system.loadSync();
 }
 
-
\ No newline at end of file + diff --git a/docs/nconf/stores/system.html b/docs/nconf/stores/system.html index 9e89544..6a10015 100644 --- a/docs/nconf/stores/system.html +++ b/docs/nconf/stores/system.html @@ -5,7 +5,7 @@ * (C) 2011, Charlie Robbins * */ - + var util = require('util'), Memory = require('./memory').Memory;

function System (options)

@@ -28,15 +28,15 @@ and command-line arguments.

if (this.env) { this.loadEnv(); } - + if (this.argv) { this.loadArgv(); } - + if (this.overrides) { this.loadOverrides(); } - + return this.store; };

function loadOverrides ()

@@ -45,54 +45,54 @@ the underlying managed Memory store.

if (!this.overrides) { return; } - + var self = this, keys = Object.keys(this.overrides); - + keys.forEach(function (key) { self.set(key, self.overrides[key]); }); - + return this.store; };

function loadArgv ()

-

Loads the data passed in from the command-line arguments +

Loads the data passed in from the command-line arguments into this instance.

System.prototype.loadArgv = function () {
-  var self = this, 
+  var self = this,
       argv;
-  
+
   if (typeof this.argv === 'object') {
-    argv = require('optimist').options(this.argv).argv;
+    argv = require('yargs').options(this.argv).argv;
   }
   else if (this.argv) {
-    argv = require('optimist').argv;
+    argv = require('yargs').argv;
   }
-  
+
   if (!argv) {
     return;
   }
-  
+
   Object.keys(argv).forEach(function (key) {
     self.set(key, argv[key]);
   });
-  
+
   return this.store;
 };

function loadEnv ()

Loads the data passed in from process.env into this instance.

System.prototype.loadEnv = function () {
   var self = this;
-  
+
   if (!this.env) {
     return;
   }
-  
+
   Object.keys(process.env).filter(function (key) {
     return !self.env.length || self.env.indexOf(key) !== -1;
   }).forEach(function (key) {
     self.set(key, process.env[key]);
   });
-    
+
   return this.store;
 };
 
-
\ No newline at end of file + diff --git a/lib/nconf/stores/argv.js b/lib/nconf/stores/argv.js index 359cb8d..04e1fd4 100644 --- a/lib/nconf/stores/argv.js +++ b/lib/nconf/stores/argv.js @@ -42,15 +42,15 @@ Argv.prototype.loadSync = function () { // Argv.prototype.loadArgv = function () { var self = this, - optimist, argv; + yargs, argv; - optimist = typeof this.options === 'object' - ? require('optimist')(process.argv.slice(2)).options(this.options) - : require('optimist')(process.argv.slice(2)); + yargs = typeof this.options === 'object' + ? require('yargs')(process.argv.slice(2)).options(this.options) + : require('yargs')(process.argv.slice(2)); - if (typeof this.usage === 'string') { optimist.usage(this.usage) } + if (typeof this.usage === 'string') { yargs.usage(this.usage) } - argv = optimist.argv + argv = yargs.argv if (!argv) { return; @@ -61,9 +61,9 @@ Argv.prototype.loadArgv = function () { self.set(key, argv[key]); }); - this.showHelp = optimist.showHelp - this.help = optimist.help + this.showHelp = yargs.showHelp + this.help = yargs.help this.readOnly = true; return this.store; -}; \ No newline at end of file +}; diff --git a/lib/nconf/stores/env.js b/lib/nconf/stores/env.js index aa775f3..2d921de 100644 --- a/lib/nconf/stores/env.js +++ b/lib/nconf/stores/env.js @@ -24,7 +24,7 @@ var Env = exports.Env = function (options) { this.whitelist = options.whitelist || []; this.separator = options.separator || ''; - if (typeof options.match === 'function' + if (({}).toString.call(options.match) === '[object RegExp]' && typeof options !== 'string') { this.match = options.match; } diff --git a/package.json b/package.json index 889ffb2..ca792a7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nconf", "description": "Hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging.", - "version": "0.7.1", + "version": "0.7.2", "author": "Charlie Robbins ", "repository": { "type": "git", @@ -15,7 +15,7 @@ "dependencies": { "async": "^1.4.0", "ini": "^1.3.0", - "optimist": "~0.6.0" + "yargs": "^3.19.0" }, "devDependencies": { "vows": "0.8.x" diff --git a/test/complete-test.js b/test/complete-test.js index 70ad31c..8a90092 100644 --- a/test/complete-test.js +++ b/test/complete-test.js @@ -16,12 +16,23 @@ var fs = require('fs'), var completeTest = helpers.fixture('complete-test.json'), complete = helpers.fixture('complete.json'); +// prime the process.env +process.env['NCONF_foo'] = 'bar'; +process.env.FOO = 'bar'; +process.env.BAR = 'zalgo'; +process.env.NODE_ENV = 'debug'; +process.env.FOOBAR = 'should not load'; + vows.describe('nconf/multiple-stores').addBatch({ "When using the nconf with multiple providers": { topic: function () { var that = this; helpers.cp(complete, completeTest, function () { - nconf.env(); + nconf.env({ + // separator: '__', + match: /^NCONF_/, + whitelist: ['NODE_ENV', 'FOO', 'BAR'] + }); nconf.file({ file: completeTest }); nconf.use('argv', { type: 'literal', store: data }); that.callback(); @@ -34,7 +45,7 @@ vows.describe('nconf/multiple-stores').addBatch({ }, "env vars": { "are present": function () { - Object.keys(process.env).forEach(function (key) { + ['NODE_ENV', 'FOO', 'BAR', 'NCONF_foo'].forEach(function (key) { assert.equal(nconf.get(key), process.env[key]); }); } diff --git a/test/fixtures/scripts/nconf-argv.js b/test/fixtures/scripts/nconf-argv.js index 1689031..98a803c 100644 --- a/test/fixtures/scripts/nconf-argv.js +++ b/test/fixtures/scripts/nconf-argv.js @@ -1,5 +1,5 @@ /* - * default-argv.js: Test fixture for using optimist defaults with nconf. + * default-argv.js: Test fixture for using yargs defaults with nconf. * * (C) 2011, Charlie Robbins and the Contributors. * @@ -7,4 +7,4 @@ var nconf = require('../../../lib/nconf').argv().env(); -process.stdout.write(nconf.get('something')); \ No newline at end of file +process.stdout.write(nconf.get('something')); diff --git a/test/fixtures/scripts/nconf-hierarchical-file-argv.js b/test/fixtures/scripts/nconf-hierarchical-file-argv.js index 3c6b293..417995c 100644 --- a/test/fixtures/scripts/nconf-hierarchical-file-argv.js +++ b/test/fixtures/scripts/nconf-hierarchical-file-argv.js @@ -1,5 +1,5 @@ /* - * nconf-hierarchical-file-argv.js: Test fixture for using optimist defaults and a file store with nconf. + * nconf-hierarchical-file-argv.js: Test fixture for using yargs defaults and a file store with nconf. * * (C) 2011, Charlie Robbins and the Contributors. * (C) 2011, Sander Tolsma @@ -14,4 +14,4 @@ nconf.add('file', { file: path.join(__dirname, '../hierarchy/hierarchical.json') }); -process.stdout.write(nconf.get('something') || 'undefined'); \ No newline at end of file +process.stdout.write(nconf.get('something') || 'undefined'); diff --git a/test/fixtures/scripts/nconf-hierarchical-load-save.js b/test/fixtures/scripts/nconf-hierarchical-load-save.js index cedc4b1..8b86847 100644 --- a/test/fixtures/scripts/nconf-hierarchical-load-save.js +++ b/test/fixtures/scripts/nconf-hierarchical-load-save.js @@ -1,5 +1,5 @@ /* - * nconf-hierarchical-load-save.js: Test fixture for using optimist, envvars and a file store with nconf. + * nconf-hierarchical-load-save.js: Test fixture for using yargs, envvars and a file store with nconf. * * (C) 2011, Charlie Robbins and the Contributors. * @@ -29,4 +29,4 @@ process.stdout.write(nconf.get('foo')); // // Save the configuration object to disk // -nconf.save(); \ No newline at end of file +nconf.save(); diff --git a/test/fixtures/scripts/provider-argv.js b/test/fixtures/scripts/provider-argv.js index 42eb277..0e2e1fa 100644 --- a/test/fixtures/scripts/provider-argv.js +++ b/test/fixtures/scripts/provider-argv.js @@ -1,5 +1,5 @@ /* - * provider-argv.js: Test fixture for using optimist defaults with nconf. + * provider-argv.js: Test fixture for using yargs defaults with nconf. * * (C) 2011, Charlie Robbins and the Contributors. * @@ -9,4 +9,4 @@ var nconf = require('../../../lib/nconf'); var provider = new (nconf.Provider)().argv(); -process.stdout.write(provider.get('something')); \ No newline at end of file +process.stdout.write(provider.get('something'));