First pass at transform functions (#279)
This commit is contained in:
parent
b9c345bf96
commit
856fdf8dff
5 changed files with 167 additions and 5 deletions
78
README.md
78
README.md
|
@ -193,6 +193,32 @@ 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 `yargs` into the configuration hierarchy. See the [yargs option docs](https://github.com/bcoe/yargs#optionskey-opt) for more on the option format.
|
||||
|
||||
#### Options
|
||||
|
||||
##### `parseValues: {true|false}` (default: `false`)
|
||||
Attempt to parse well-known values (e.g. 'false', 'true', 'null', 'undefined', '3', '5.1' and JSON values)
|
||||
into their proper types. If a value cannot be parsed, it will remain a string.
|
||||
|
||||
##### `transform: function(obj)`
|
||||
Pass each key/value pair to the specified function for transformation.
|
||||
|
||||
The input `obj` contains two properties passed in the following format:
|
||||
```
|
||||
{
|
||||
key: '<string>',
|
||||
value: '<string>'
|
||||
}
|
||||
```
|
||||
|
||||
The transformation function may alter both the key and the value.
|
||||
|
||||
The function may return either an object in the asme format as the input or a value that evaluates to false.
|
||||
If the return value is falsey, the entry will be dropped from the store, otherwise it will replace the original key/value.
|
||||
|
||||
*Note: If the return value doesn't adhere to the above rules, an exception will be thrown.*
|
||||
|
||||
#### Examples
|
||||
|
||||
``` js
|
||||
//
|
||||
// Can optionally also be an object literal to pass to `yargs`.
|
||||
|
@ -202,16 +228,52 @@ Responsible for loading the values parsed from `process.argv` by `yargs` into th
|
|||
alias: 'example',
|
||||
describe: 'Example description for usage generation',
|
||||
demand: true,
|
||||
default: 'some-value'
|
||||
default: 'some-value',
|
||||
parseValues: true,
|
||||
transform: function(obj) {
|
||||
if (obj.key === 'foo') {
|
||||
obj.value = 'baz';
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Env
|
||||
Responsible for loading the values parsed from `process.env` into the configuration hierarchy.
|
||||
Usually the env variables values are loaded into the configuration as strings.
|
||||
To ensure well-known strings ('false', 'true', 'null', 'undefined', '3', '5.1') and JSON values
|
||||
are properly parsed, the `parseValues` boolean option is available.
|
||||
By default, the env variables values are loaded into the configuration as strings.
|
||||
|
||||
#### Options
|
||||
|
||||
##### `lowerCase: {true|false}` (default: `false`)
|
||||
Convert all input keys to lower case. Values are not modified.
|
||||
|
||||
If this option is enabled, all calls to `nconf.get()` must pass in a lowercase string (e.g. `nconf.get('port')`)
|
||||
|
||||
##### `parseValues: {true|false}` (default: `false`)
|
||||
Attempt to parse well-known values (e.g. 'false', 'true', 'null', 'undefined', '3', '5.1' and JSON values)
|
||||
into their proper types. If a value cannot be parsed, it will remain a string.
|
||||
|
||||
##### `transform: function(obj)`
|
||||
Pass each key/value pair to the specified function for transformation.
|
||||
|
||||
The input `obj` contains two properties passed in the following format:
|
||||
```
|
||||
{
|
||||
key: '<string>',
|
||||
value: '<string>'
|
||||
}
|
||||
```
|
||||
|
||||
The transformation function may alter both the key and the value.
|
||||
|
||||
The function may return either an object in the asme format as the input or a value that evaluates to false.
|
||||
If the return value is falsey, the entry will be dropped from the store, otherwise it will replace the original key/value.
|
||||
|
||||
*Note: If the return value doesn't adhere to the above rules, an exception will be thrown.*
|
||||
|
||||
#### Examples
|
||||
|
||||
``` js
|
||||
//
|
||||
|
@ -247,7 +309,13 @@ are properly parsed, the `parseValues` boolean option is available.
|
|||
match: /^whatever_matches_this_will_be_whitelisted/
|
||||
whitelist: ['database__host', 'only', 'load', 'these', 'values', 'if', 'whatever_doesnt_match_but_is_whitelisted_gets_loaded_too'],
|
||||
lowerCase: true,
|
||||
parseValues: true
|
||||
parseValues: true,
|
||||
transform: function(obj) {
|
||||
if (obj.key === 'foo') {
|
||||
obj.value = 'baz';
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
var dbHost = nconf.get('database:host');
|
||||
```
|
||||
|
|
|
@ -141,3 +141,31 @@ common.parseValues = function (value) {
|
|||
|
||||
return val;
|
||||
};
|
||||
|
||||
//
|
||||
// ### function transform(map, fn)
|
||||
// #### @map {object} Object of key/value pairs to apply `fn` to
|
||||
// #### @fn {function} Transformation function that will be applied to every key/value pair
|
||||
// transform a set of key/value pairs and return the transformed result
|
||||
common.transform = function(map, fn) {
|
||||
var pairs = Object.keys(map).map(function(key) {
|
||||
var obj = { key: key, value: map[key]};
|
||||
var result = fn.call(null, obj);
|
||||
|
||||
if (!result) {
|
||||
return null;
|
||||
} else if (result.key && typeof result.value !== 'undefined') {
|
||||
return result;
|
||||
}
|
||||
|
||||
var error = new Error('Transform function passed to store returned an invalid format: ' + JSON.stringify(result));
|
||||
error.name = 'RuntimeError';
|
||||
throw error;
|
||||
});
|
||||
|
||||
|
||||
return pairs.reduce(function(accumulator, pair) {
|
||||
accumulator[pair.key] = pair.value;
|
||||
return accumulator;
|
||||
}, {});
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ var Argv = exports.Argv = function (options, usage) {
|
|||
this.options = options;
|
||||
this.usage = usage;
|
||||
this.parseValues = options.parseValues || false;
|
||||
this.transform = options.transform || false;
|
||||
};
|
||||
|
||||
// Inherit from the Memory store
|
||||
|
@ -59,6 +60,10 @@ Argv.prototype.loadArgv = function () {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.transform) {
|
||||
argv = common.transform(argv, this.transform);
|
||||
}
|
||||
|
||||
this.readOnly = false;
|
||||
Object.keys(argv).forEach(function (key) {
|
||||
var val = argv[key];
|
||||
|
|
|
@ -25,6 +25,7 @@ var Env = exports.Env = function (options) {
|
|||
this.separator = options.separator || '';
|
||||
this.lowerCase = options.lowerCase || false;
|
||||
this.parseValues = options.parseValues || false;
|
||||
this.transform = options.transform || false;
|
||||
|
||||
if (({}).toString.call(options.match) === '[object RegExp]'
|
||||
&& typeof options !== 'string') {
|
||||
|
@ -67,6 +68,10 @@ Env.prototype.loadEnv = function () {
|
|||
});
|
||||
}
|
||||
|
||||
if (this.transform) {
|
||||
env = common.transform(env, this.transform);
|
||||
}
|
||||
|
||||
this.readOnly = false;
|
||||
Object.keys(env).filter(function (key) {
|
||||
if (self.match && self.whitelist.length) {
|
||||
|
|
|
@ -184,5 +184,61 @@ vows.describe('nconf/multiple-stores').addBatch({
|
|||
teardown: function () {
|
||||
nconf.remove('env');
|
||||
}
|
||||
},
|
||||
}).addBatch({
|
||||
// Threw this in it's own batch to make sure it's run separately from the
|
||||
// sync check
|
||||
"When using env with transform:fn": {
|
||||
topic: function () {
|
||||
|
||||
function testTransform(obj) {
|
||||
if (obj.key === 'FOO') {
|
||||
obj.key = 'FOOD';
|
||||
obj.value = 'BARFOO';
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
var that = this;
|
||||
helpers.cp(complete, completeTest, function () {
|
||||
nconf.env({ transform: testTransform })
|
||||
that.callback();
|
||||
});
|
||||
}, "env vars": {
|
||||
"port key/value properly transformed": function() {
|
||||
assert.equal(nconf.get('FOOD'), 'BARFOO');
|
||||
}
|
||||
}
|
||||
},
|
||||
teardown: function () {
|
||||
nconf.remove('env');
|
||||
}
|
||||
}).addBatch({
|
||||
// Threw this in it's own batch to make sure it's run separately from the
|
||||
// sync check
|
||||
"When using env with a bad transform:fn": {
|
||||
topic: function () {
|
||||
function testTransform() {
|
||||
return {foo: 'bar'};
|
||||
}
|
||||
|
||||
var that = this;
|
||||
helpers.cp(complete, completeTest, function () {
|
||||
try {
|
||||
nconf.env({ transform: testTransform });
|
||||
that.callback();
|
||||
} catch (err) {
|
||||
that.callback(null, err);
|
||||
}
|
||||
});
|
||||
}, "env vars": {
|
||||
"port key/value throws transformation error": function(err) {
|
||||
assert.equal(err.name, 'RuntimeError');
|
||||
}
|
||||
}
|
||||
},
|
||||
teardown: function () {
|
||||
nconf.remove('env');
|
||||
}
|
||||
}).export(module);
|
Loading…
Reference in a new issue