From 391665cc38412ce47c31c9f0eea8da6e76fe2663 Mon Sep 17 00:00:00 2001 From: louis-murray Date: Sun, 12 Nov 2017 23:11:01 -0500 Subject: [PATCH] Enable writes env and argv stores with a flag (#285) * added fucntionality to toggle readonly for env store * fixed issue with using lint * updated readme to reflect env options change * updated tests to better test readOnly property * added fucntionality to toggle readonly for env store * fixed issue with using lint * updated readme to reflect env options change * updated tests to better test readOnly property * updated tests to fix issues. * updated argv to have readOnly toggle-able * added tests for argv toggle-able readonly --- README.md | 9 ++++++--- lib/nconf/stores/argv.js | 21 ++++++++++++++++++--- lib/nconf/stores/env.js | 18 +++++++++++++----- test/complete-test.js | 37 ++++++++++++++++++++++++++++++++++--- test/stores/argv-test.js | 21 ++++++++++++++++++++- test/stores/env-test.js | 14 +++++++++++++- 6 files changed, 104 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e7f4e03..eabc7f3 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Adds a new store with the specified `name` and `options`. If `options.type` is n ``` ### nconf.any(names, callback) -Given a set of key names, gets the value of the first key found to be truthy. The key names can be given as separate arguments +Given a set of key names, gets the value of the first key found to be truthy. The key names can be given as separate arguments or as an array. If the last argument is a function, it will be called with the result; otherwise, the value is returned. ``` js @@ -308,6 +308,9 @@ If the return value is falsey, the entry will be dropped from the store, otherwi *Note: If the return value doesn't adhere to the above rules, an exception will be thrown.* +#### `readOnly: {true|false}` (defaultL `true`) +Allow values in the env store to be updated in the future. The default is to not allow items in the env store to be updated. + #### Examples ``` js @@ -324,8 +327,8 @@ If the return value is falsey, the entry will be dropped from the store, otherwi var dbHost = nconf.get('database:host'); // - // Can also lowerCase keys. - // Especially handy when dealing with environment variables which are usually + // Can also lowerCase keys. + // Especially handy when dealing with environment variables which are usually // uppercased while argv are lowercased. // diff --git a/lib/nconf/stores/argv.js b/lib/nconf/stores/argv.js index ac00613..bc65168 100644 --- a/lib/nconf/stores/argv.js +++ b/lib/nconf/stores/argv.js @@ -20,9 +20,17 @@ var Argv = exports.Argv = function (options, usage) { options = options || {}; this.type = 'argv'; - this.readOnly = true; + this.readOnly = options.readOnly !== undefined? options.readOnly : true; this.options = options; this.usage = usage; + + if(typeof options.readOnly === 'boolean') { + this.readOnly = options.readOnly; + delete options.readOnly; + } else { + this.readOnly = true; + } + if(typeof options.parseValues === 'boolean') { this.parseValues = options.parseValues; delete options.parseValues; @@ -82,7 +90,12 @@ Argv.prototype.loadArgv = function () { argv = common.transform(argv, this.transform); } - this.readOnly = false; + var tempWrite = false; + + if(this.readOnly) { + this.readOnly = false; + tempWrite = true; + } Object.keys(argv).forEach(function (key) { var val = argv[key]; @@ -103,7 +116,9 @@ Argv.prototype.loadArgv = function () { this.showHelp = yargs.showHelp this.help = yargs.help - this.readOnly = true; + if (tempWrite) { + this.readOnly = true; + } return this.store; }; diff --git a/lib/nconf/stores/env.js b/lib/nconf/stores/env.js index 12dd3b4..37b2c81 100644 --- a/lib/nconf/stores/env.js +++ b/lib/nconf/stores/env.js @@ -20,7 +20,7 @@ var Env = exports.Env = function (options) { options = options || {}; this.type = 'env'; - this.readOnly = true; + this.readOnly = options.readOnly !== undefined? options.readOnly : true; this.whitelist = options.whitelist || []; this.separator = options.separator || ''; this.lowerCase = options.lowerCase || false; @@ -72,7 +72,13 @@ Env.prototype.loadEnv = function () { env = common.transform(env, this.transform); } - this.readOnly = false; + var tempWrite = false; + + if(this.readOnly) { + this.readOnly = false; + tempWrite = true; + } + Object.keys(env).filter(function (key) { if (self.match && self.whitelist.length) { return key.match(self.match) || self.whitelist.indexOf(key) !== -1 @@ -84,7 +90,7 @@ Env.prototype.loadEnv = function () { return !self.whitelist.length || self.whitelist.indexOf(key) !== -1 } }).forEach(function (key) { - + var val = env[key]; if (self.parseValues) { @@ -99,7 +105,9 @@ Env.prototype.loadEnv = function () { } }); - this.readOnly = true; + if (tempWrite) { + this.readOnly = true; + } + return this.store; }; - diff --git a/test/complete-test.js b/test/complete-test.js index 3125388..0780528 100644 --- a/test/complete-test.js +++ b/test/complete-test.js @@ -21,6 +21,7 @@ process.env.FOO = 'bar'; process.env.BAR = 'zalgo'; process.env.NODE_ENV = 'debug'; process.env.FOOBAR = 'should not load'; +process.env.TES = 'TING'; process.env.json_array = JSON.stringify(['foo', 'bar', 'baz']); process.env.json_obj = JSON.stringify({foo: 'bar', baz: 'foo'}); process.env.NESTED__VALUE = 'nested'; @@ -34,7 +35,7 @@ vows.describe('nconf/multiple-stores').addBatch({ nconf.env({ // separator: '__', match: /^NCONF_/, - whitelist: ['NODE_ENV', 'FOO', 'BAR'] + whitelist: ['NODE_ENV', 'FOO', 'BAR', 'TES'] }); nconf.file({ file: completeTest }); nconf.use('argv', { type: 'literal', store: data }); @@ -51,6 +52,10 @@ vows.describe('nconf/multiple-stores').addBatch({ ['NODE_ENV', 'FOO', 'BAR', 'NCONF_foo'].forEach(function (key) { assert.equal(nconf.get(key), process.env[key]); }); + }, + "are readOnly": function () { + nconf.set('tes', 'broken'); + assert(nconf.get('tes'), 'TING'); } }, "json vars": { @@ -174,7 +179,7 @@ vows.describe('nconf/multiple-stores').addBatch({ "JSON keys properly parsed": function () { Object.keys(process.env).forEach(function (key) { var val = process.env[key]; - + try { val = JSON.parse(val); } catch (err) {} @@ -323,4 +328,30 @@ vows.describe('nconf/multiple-stores').addBatch({ teardown: function () { nconf.remove('env'); } -}).export(module); \ No newline at end of file +}).addBatch({ + // Threw this in it's own batch to make sure it's run separately from the + // sync check + "When using env with a readOnly:false": { + topic: function () { + + var that = this; + helpers.cp(complete, completeTest, function () { + try { + nconf.env({ readOnly: false }); + that.callback(); + } catch (err) { + that.callback(null, err); + } + }); + }, "env vars": { + "can be changed when readOnly is false": function() { + assert.equal(nconf.get('TES'), 'TING'); + nconf.set('TES', 'changed'); + assert.equal(nconf.get('TES'), 'changed'); + } + } + }, + teardown: function () { + nconf.remove('env'); + } +}).export(module); diff --git a/test/stores/argv-test.js b/test/stores/argv-test.js index fb2b457..265ea41 100644 --- a/test/stores/argv-test.js +++ b/test/stores/argv-test.js @@ -47,7 +47,26 @@ vows.describe('nconf/stores/argv').addBatch({ argv.loadSync() assert.equal(argv.get('verbose'), 'false'); assert.equal(argv.get('v'), 'false'); + }, + "values cannot be altered with set when readOnly:true": function (argv) { + argv.set('verbose', 'true'); + assert.equal(argv.get('verbose'), 'false'); + } + }, + "can be created with readOnly set to be false":{ + topic: function(){ + var options = {verbose: {alias: 'v', default: 'false'}, readOnly: false}; + return new nconf.Argv(options); + }, + "readOnly is actually false": function (argv) { + assert.equal(argv.readOnly, false); + }, + "values can be changed by calling .set": function (argv) { + argv.loadSync() + assert.equal(argv.get('verbose'), 'false'); + argv.set('verbose', 'true'); + assert.equal(argv.get('verbose'), 'true'); } } } -}).export(module); \ No newline at end of file +}).export(module); diff --git a/test/stores/env-test.js b/test/stores/env-test.js index 88c5f4e..05cdc40 100644 --- a/test/stores/env-test.js +++ b/test/stores/env-test.js @@ -9,6 +9,8 @@ var vows = require('vows'), assert = require('assert'), nconf = require('../../lib/nconf'); +process.env.TES = 'TING'; + vows.describe('nconf/stores/env').addBatch({ "An instance of nconf.Env": { topic: new nconf.Env(), @@ -19,5 +21,15 @@ vows.describe('nconf/stores/env').addBatch({ assert.lengthOf(env.whitelist, 0); assert.equal(env.separator, ''); } - } + }, + "An instance of nconf.Env with readOnly option set to false": { + topic: new nconf.Env({readOnly: false}), + "should have it's readOnly property set to false": function (env) { + assert.isFunction(env.loadSync); + assert.isFunction(env.loadEnv); + assert.isArray(env.whitelist); + assert.lengthOf(env.whitelist, 0); + assert.ok(!env.readOnly); + } +} }).export(module);