Compare commits

...

353 Commits

Author SHA1 Message Date
Jonatan Nilsson 296a65dfe1 2.1.0 2021-10-14 09:53:17 +00:00
Jonatan Nilsson 2ee285e1c4 argv: Add support for boolean flags when equal sign is used 2021-10-14 09:52:56 +00:00
Jonatan Nilsson 129e50367d circleci: Switch to alpine and add more versions 2021-06-23 09:41:27 +00:00
Jonatan Nilsson f43d81a2cd Merge branch 'master' of https://github.com/nfp-projects/nconf-lite 2021-06-23 09:39:42 +00:00
Jonatan Nilsson fa46b3b043 Fix ci and update engine in package 2021-06-23 09:39:40 +00:00
Jonatan Nilsson 863fec827d Add .circleci/config.yml 2021-06-23 09:36:46 +00:00
Jonatan Nilsson 98980c3453
Update README.md 2021-06-22 19:25:39 +00:00
Jonatan Nilsson 1014cdec86 Finished completely rewriting both library and unit tests 2021-06-22 19:25:00 +00:00
Jonatan Nilsson 1104c0d3ad Migrating a bunch of tests to ecmamodule 2021-06-07 08:58:26 +00:00
Jonatan Nilsson 44a22ce6dd Move async to main dependancy 2020-06-02 10:36:58 +00:00
Jonatan Nilsson b824493aa6 Updated version to 1.0.0, updated changelog 2020-06-02 10:23:51 +00:00
Jonatan Nilsson 2f66137a81 Update package and readme 2020-06-02 10:21:30 +00:00
Jonatan Nilsson c8a8d29d63 Add package-lock to ignore 2020-06-02 10:15:21 +00:00
Jonatan Nilsson 455103a330 Remove argv and its huge yargs dependancy 2020-06-02 10:15:06 +00:00
renovate[bot] aad2c1e449 [dist] Update dependency yargs to v14 (#334) 2019-11-14 14:56:06 -05:00
renovate[bot] ee8e89c1b0 [dist] Update dependency eslint to v6 (#330) 2019-06-23 21:33:55 -04:00
renovate[bot] 0ee6938568 [dist] Update dependency yargs to v13 (#321) 2019-06-14 22:33:09 -04:00
Eric Bickle 7d625086ca Fix saveToFile tests on Windows. indexzero#325 (#329) 2019-06-14 22:11:34 -04:00
Eric Bickle 85edc9afad [fix] Jest as devDependency indexzero/nconf#327 (#328) 2019-06-14 22:03:35 -04:00
Indospace.io 20e00efd6c Change require fs (#313)
what is there now is bad, everyone will think they need the fs library, when they only need it for the last example.
2019-05-16 17:05:20 -04:00
renovate[bot] e6f27f5d2c [dist] Update dependency jest to v24 (#320) 2019-05-16 17:03:06 -04:00
Matt Hamann d582066743
Upgraded encryption using CipherIV (#322)
* Remove package-lock.json from gitignore

* Update dependencies and fix repo url

* Fix test

* Update to cipheriv

* Bump version

* Sync package-lock

* Revert extraneous package changes

* Revert minor doc change
2019-05-15 23:27:38 -04:00
renovate[bot] 10318c0098 Configure Renovate (#319)
* Add renovate.json

* [dist] Update renovate.json
2019-05-14 14:09:08 -04:00
indexzero 48c92ce989 [dist tiny] Remove unused CircleCI configs. 2019-05-13 23:23:50 -04:00
indexzero 52afef5218 [tiny dist] Regenerate package-lock.json file. 2019-05-13 23:14:22 -04:00
Charlie Robbins 75641ffaee
[dist] Drop unsupported versions of Node. No automated publishing just yet. (#318) 2019-05-13 23:10:23 -04:00
Matt Hamann 1bb9d091f1 Switch to circleci (#317) 2019-05-13 22:56:47 -04:00
Adrien Becchis b8686aeff0 Migrating test to jest (#292)
* set up jest dependencies

* add parser option to eslint to support es6

* migrate first test to jest

* migrate the argv test to shpec

* convert the env and literal store tests

* convert the file-store tests

* convert the memory-store tests

* convert the hierarchy tests

* convert the provider-save test

* convert the complete test

* convert the provider test

* convert the conf test

* tweak a test that was no longer working (context changed)

* replace in place the helpers file

* remove vows dependency

* update the test invocation to rely on jest

* update the argv test to be able to use the jest --verbose option

* Some tweaks to the test to have them working

* Update node version tested (+10 +12 -9)

* Replace const by var until we drop 0.10/0.12/4 node

* Replace let by var until we drop 0.10/0.12/4 node
2019-04-29 22:26:02 -04:00
Matt Hamann 17376d4d17
Update packages to resolve security vulnerabilities (#306) 2018-09-27 13:03:17 -04:00
louis-murray 391665cc38 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
2017-11-12 23:11:01 -05:00
Austin Burdine 6c5ba64db6 whitelist npm published files (#236)
- reduces files published to npm and downloaded with every install
2017-11-11 10:48:49 -05:00
Adrien Becchis c1e15681db Upgrading dependencies (#280)
* upgrade yargs and async dependencies.

were breaking change, but no impact according the tests

* upgrade yargs and package-lock.json

* add node 8 to the tested versions

* add node 8 to the allowed failures as requested

* add node 9 to travis build as acceptable failure and remove node 7
2017-11-06 11:15:12 -05:00
bryce-gibson b6699aba2d Don't do array lookups on strings. (#188)
`hasOwnProperty(number)` can return true for strings.

This is unlikely to be the desired usage, and can mean that odd
responses are returned by nconf.

Disable trying to check `hasOwnProperty` of strings.
2017-11-04 21:39:00 -04:00
Adrien Becchis 467ab753c8 Regex as env separator (#288)
* use regexp as env separator (support shorthand specification)

* add test to cover the env separator
2017-11-04 21:30:56 -04:00
Adrien Becchis e5db2ef6d7 Argv store separator (#291)
* argv store now accept a separator argument to create nested values

* remove stub file that shouldnt have been commited

* write a test to ensure separator is working well and use delete rather than undefined assign
2017-11-04 21:30:14 -04:00
Ahmed Ayoub 3607767f90 fixes #258 chainable .required() (#259)
* fixes #258 chainable .required()

* fixes #258 use var instead of let for travis builds
2017-11-04 00:34:27 -04:00
Matt Hamann bac910a6df 0.9.1 2017-11-03 23:52:19 -04:00
Adrien Becchis 2bdf7e1a32 Clean Argv Store options (#290)
* unset parse/transform from options and ensure they are not yargs options

* use delete rather than undefined assignement
2017-11-03 23:41:23 -04:00
Adrien Becchis b9321b200a transformer can now return an undefined key (#289) 2017-11-03 23:22:13 -04:00
Matt Hamann 81ce0be01e Update changelog 2017-10-31 20:20:27 -04:00
Augusto Franzoia b1ee63cfa4 fix error in transform function when dealing with dropped entries (#287) 2017-10-31 17:12:31 -04:00
Matt Hamann 9f70ba148f [doc] Update changelog 2017-10-30 11:27:11 -04:00
Matt Hamann 8afcf991eb [dist] Version bump. 0.9.0 2017-10-30 10:26:30 -04:00
Adrien Becchis b41c505c6e Save conf to dedicated file (#283)
* Added support for saving configuration to a specific file

Added support for saving configuration to a specific file

* add test to cover the save to file feature

* add posibility to specify a format to save to file

* add a test with nconf-yaml to ensure specifying a format works
2017-10-30 10:01:55 -04:00
Matt Hamann 52e0a3566e Update changelog 2017-10-28 21:16:03 -04:00
AdrieanKhisbe fa215a44f1 add tests for the normal configuration of yargs via argv 2017-10-28 17:13:38 -04:00
AdrieanKhisbe 802a8d623f test for yargs custom instance (more flexible check isYargs) 2017-10-28 17:13:38 -04:00
Nicolas Deveaud 3e26bb2756 Add posibility to pass a yargs instance to argv() method 2017-10-28 17:13:38 -04:00
Matt Hamann 856fdf8dff First pass at transform functions (#279) 2017-10-25 22:57:58 -04:00
Matt Hamann b9c345bf96 Fix `parseValues` option name 2017-10-21 21:58:30 -04:00
Matt Hamann 35088a3313 Added nconf.any method (#278)
* Added nconf.any method

Fixes #126
Implemented on the Provider class
Takes an array of keys, or a variable argument list
Supports both callback and non-callback invocations

* Use an explicit search base in file store test

Fixes #224
Test file was created under process.env.HOME, but test was searching in
the current working directory. If the cwd was not on the same drive as
the home directory, the test would fail.

* Added some API documentation to README for 'any'

* Tweak `.any` documentation
2017-10-21 16:42:24 -04:00
Matt Hamann ca10d0eaf8 Add basic linting rules 2017-10-21 16:01:06 -04:00
Brian Harrington bfb0220fe1 Remove unused module (#277)
crypto is no longer used in file.js
2017-10-21 15:47:41 -04:00
Matt Hamann 532ac9cc57 Support parsing simple values from env/argv strings (#273)
* simple parse, indexzero/nconf#72

* documentation for tryParse option

* Combine JSON parsing and simple parsing
2017-10-21 15:39:16 -04:00
Matt Hamann b8402d4eab Enable support for parsing JSON environment variables (#272)
* Add support for applying JSON string

* only take JSON Object or JSON Array into consideration

* Add tests and make JSON-parsing opt-in
2017-09-27 16:32:26 -04:00
Matt Hamann f46c449a9e 0.8.5 2017-08-15 23:59:31 -04:00
Matt Hamann 552300a687 [doc] Document lowerCase option in .env(options) (#268)
- Add missing documentation about the lowerCase option
2017-08-15 23:58:13 -04:00
evoye 5e8a34d6cf enable use with webpack by removing unnecessary fs call (#252) 2017-08-15 23:39:34 -04:00
Chris Manson 608b607782 Add test for merging with defaults (#255)
* implementing a test for merging with defaults

* bypassing strange common tests

* trying to fix travis build in node 7

* adding node 8 to tests

* removing node 8
2017-08-15 23:37:19 -04:00
Charlie Robbins 0c5774fec7 Merge pull request #211 from vanjan/fix-env-ignore-case
Copy `process.env` before lower-casing the keys
2016-08-25 12:48:47 -04:00
Charlie Robbins 011be49a5c Merge pull request #222 from katacarbix/patch-1
Fixed some issues with code escaping in README.md
2016-06-15 05:52:32 -04:00
Charter Jacobson d70b6a0335 Fixed some issues with code escaping 2016-05-14 14:55:23 -05:00
Jan Klosinski 392c6022c9 Copy `process.env` before lower-casing the keys
`process.env` is read-only in GitBash (and potentially other consoles),
so the `lowerCase` flag had no effect.
2016-03-01 17:08:35 +00:00
Jarrett Cruger 3d4e589578 [dist] Version bump. 0.8.4 2016-02-03 00:39:12 -08:00
Charlie Robbins b065c4ccd9 Merge pull request #209 from indexzero/better-DX
[fix] handle buffers
2016-02-02 21:46:14 -08:00
Jarrett Cruger 4431c33162 [fix] handle buffers so we dont get ambiguous errors when we dont strictly read the file as utf8 2016-02-02 16:38:48 -08:00
Jarrett Cruger 54cab2059a [dist] Version bump. 0.8.3 2016-02-01 22:26:12 -08:00
Charlie Robbins f554382435 Merge pull request #208 from indexzero/clean-secure
[fix] cleanup secure with new module
2016-02-02 01:24:49 -05:00
Jarrett Cruger b447268097 [fix] cleanup secure with new module 2016-02-01 22:21:15 -08:00
Jarrett Cruger 3d4682a62f Merge pull request #207 from moberemk/patch-1
Update README.md
2016-01-27 12:32:26 -05:00
Mark Oberemk de551d42ec Update README.md
Add basic documentation explaining the `nconf.required` method
2016-01-27 12:29:26 -05:00
Charlie Robbins 4a59c9b577 Merge pull request #191 from wturyn/feature-mandatory-keys
Feature: mandatory keys - required() method
2016-01-27 09:20:20 -08:00
Charlie Robbins e58d55429d Merge pull request #195 from AdrieanKhisbe/features/improved-ci
Improved CI
2015-12-22 14:21:07 -05:00
AdrieanKhisbe c242f777a6 [travis test] setup coveralls config + update README badges 2015-12-03 08:18:44 +01:00
AdrieanKhisbe c8dbede0ca [test] setup istanbul coverage 2015-12-03 08:03:12 +01:00
AdrieanKhisbe bdecdc29cf [travis] add v5 to node version tested 2015-12-03 07:48:52 +01:00
Wojtek Turyn 5d6e236b73 fixed 2015-10-15 10:44:26 +02:00
Wojtek Turyn 37a84ae8df required() method 2015-10-15 10:16:33 +02:00
indexzero ddee9bc8f5 [dist] Version bump. 0.8.2 2015-10-07 15:32:55 -04:00
indexzero 86bfd7c5bc [fix] Do not trim `\n` from files read in. 2015-10-07 15:31:53 -04:00
indexzero ff0f174520 [dist] Version bump. 0.8.1 2015-10-02 01:01:20 -07:00
indexzero 11b2448471 [fix] Correct property path. Trim read secret keys from disk. 2015-10-02 01:00:55 -07:00
indexzero 438a2c8ef5 [doc] Remove `node@0.8.0` from travis. Drop `nodeci` because it is 503 atm`. 2015-09-21 17:11:52 -07:00
indexzero ebd8e48342 [dist] Version bump. 0.8.0 2015-09-20 01:39:50 -07:00
indexzero be085c9ad5 [doc] Update CHANGELOG.md. 2015-09-20 01:39:41 -07:00
indexzero 0922563593 [doc fix] Remove unused and outdated literate coding documentation. 2015-09-20 01:37:09 -07:00
Charlie Robbins e503718468 Merge pull request #186 from indexzero/fix-redis
Fix some minor consistency issues in Redis
2015-09-20 01:14:43 -07:00
Charlie Robbins d4ebf49908 Merge pull request #185 from indexzero/crypto
[wip] Allow for "secure" option to be passed to `nconf.stores.File`
2015-09-20 01:13:26 -07:00
indexzero 4b5030dbc2 [fix] Only merge actual objects, not `null` values. Fixes #150. 2015-09-20 01:10:37 -07:00
Rob Rodriguez a3589fab95 Fixing provider issue in source 2015-09-20 01:08:45 -07:00
Rob Rodriguez 51653e6486 Passing the value parameter to the providers
The nconf-redis provider needs the value for some reason, if its absent
this call will fail. It should be there anyway.
2015-09-20 01:07:21 -07:00
indexzero 2030144d88 [test dist] Add `test/fixtures/secure.json`. 2015-09-20 00:36:49 -07:00
indexzero 9dbed2d2cd [doc minor] Update docs for secure information. 2015-09-20 00:34:44 -07:00
indexzero 0358545ae5 [test api] Make the format capable of sub-objects. 2015-09-20 00:26:34 -07:00
indexzero 04c0f3a001 [api test] Encrypt individual keys instead of entire stringified contents. Added basic unit tests. 2015-09-19 00:12:50 -07:00
indexzero d2b3561e09 [dist] Update `.travis.yml`. 2015-09-18 20:55:39 -07:00
indexzero 442d2b4233 [api] Allow for `secure` to be simply a secret string. 2015-09-18 20:52:16 -07:00
indexzero 2de2bc0b66 [api] Allow for "secure" option to be passed to `nconf.stores.File` to perform content encryption / decryption with `crypto.createCipher`. 2015-09-18 20:52:16 -07:00
Jarrett Cruger 4c07028e40 Merge pull request #173 from NickHeiner/patch-2
Quick grammar fix
2015-09-17 18:49:48 -07:00
Jarrett Cruger 75cea11f62 Merge pull request #163 from pgilad/patch-1
Add license attribute
2015-09-17 18:47:11 -07:00
Jarrett Cruger 394286cd16 Merge pull request #172 from Oza94/fix-child-process-tests
fix random fails on tests that use child process
2015-09-17 18:46:57 -07:00
Jarrett Cruger 54f2287dd8 Merge pull request #177 from olalonde/master
env({lowerCase:true}) option to make it possible to get() keys in lower case
2015-09-17 18:46:27 -07:00
Jarrett Cruger 38cade0fc2 Merge pull request #167 from josephpage/patch-1
Add tests for node 0.12 and io.js
2015-08-19 23:13:21 -04:00
Jarrett Cruger 32aabcab69 Merge pull request #171 from ChristianMurphy/update-async
Update Async.js
2015-08-19 12:31:23 -04:00
Jarrett Cruger 8332f5a343 Merge pull request #183 from ChristianMurphy/filter-undefined
filter out undefined values
2015-08-19 12:30:27 -04:00
Christian Murphy 5d95f13eb0 filter out undefined values 2015-08-19 09:16:16 -07:00
Joseph Page 7d6be3265b [travis] fix yaml syntax (supposed to solve nvm bugs #182) 2015-08-19 17:52:09 +02:00
Joseph Page abeeca0d5f [travis] fix npm bugs for node 0.8 (recommended way) 2015-08-19 17:47:01 +02:00
Joseph Page d252288dae Merge commit '80195744af4929731ff1c87e9b29e37a2c48e464' into patch-1 2015-08-19 17:45:38 +02:00
Christian Murphy be0ee00b2a Merge branch 'master' of https://github.com/indexzero/nconf into update-async 2015-08-19 08:03:38 -07:00
Christian Murphy 59056fe364 Update Async and ini 2015-08-19 07:58:50 -07:00
Joseph Page a2b812f704 Add travis tests for iojs 2015-08-13 20:45:57 +02:00
Joseph Page 32d560c95d Add tests for node 0.12 2015-08-13 20:45:57 +02:00
Christian Murphy 80195744af Merge branch 'master' of https://github.com/indexzero/nconf into update-travis 2015-08-04 11:51:26 -07:00
indexzero c2b8b97778 [dist] Version bump. 0.7.2 2015-08-04 10:31:48 -07:00
Remy Sharp 3c11ef50e5 fix: env.match test
The previous test was expecting the .match value to be a function rather than a regexp which is what the README shows. So I've fixed the code to match against a real regexp, and test if the stringified version of the regexp function is [object RegExp].

I've also updated the tests to prime the process.env with values that are specifically tested for to ensure it's correctly loading the env values.

Fixex indexzero/nconf#178
2015-08-04 10:30:33 -07:00
Olivier Lalonde 8a21ef36d5 env({lowerCase:true}) option to make it possible to get() keys in lower case 2015-08-04 18:56:43 +08:00
indexzero 372521b124 [doc] Add the badges!. 2015-07-29 17:16:12 -07:00
Jarrett Cruger 8afdf63497 Merge pull request #168 from ChristianMurphy/replace-optimist-with-yargs
Replace optimist with yargs
2015-07-12 19:34:18 -04:00
Nick Heiner 89dff39d55 Quick grammar fix 2015-07-09 14:07:35 -04:00
Pierre Beaujeu 339e59afd5 fix random fails on tests that use child process
Listen to 'close' event rather than 'exit' event which can be fired before
stdio is closed.
2015-07-09 17:33:52 +02:00
Christian Murphy a65e1a3317 update async 2015-07-07 16:01:08 -07:00
Christian Murphy a82b53941d update badge and use container build 2015-07-07 13:36:21 -07:00
Christian Murphy 80ec01b91d replace optimist with yargs 2015-07-07 13:06:41 -07:00
Gilad Peleg e5b33ceb05 Add license attribute
https://docs.npmjs.com/files/package.json#license
http://npm1k.org/
2015-05-19 12:56:17 +03:00
Jarrett Cruger d335b5a0f5 Merge pull request #141 from NickHeiner/patch-1
Grammar nit
2015-01-20 14:23:27 -05:00
Nick Heiner 6d86950914 Grammar nit 2015-01-20 13:41:46 -05:00
Jarrett Cruger dc6aed2050 [dist] Version bump. 0.7.1 2014-11-26 12:52:01 -05:00
Jarrett Cruger 87a3b82418 [fix] we shouldnt be reversing here fixes #127 2014-11-26 12:51:33 -05:00
Jarrett Cruger 6271cdb35d Revert "fixing the tests"
This reverts commit f69e43a423.
2014-11-26 12:49:50 -05:00
indexzero f0d5b6eb30 [dist] Fix travis. 2014-11-26 01:34:28 -05:00
indexzero a2a132181a [dist] Version bump. 0.7.0 2014-11-26 01:32:16 -05:00
indexzero 352f07559a [dist] "Real" CHANGELOG.md again. 2014-11-26 01:32:00 -05:00
indexzero af0e9fb7e7 [dist fix] Cleanup some whitespace. 2014-11-26 01:31:48 -05:00
indexzero 09342555ba [fix] Fixed regression introduced by #98. 2014-11-26 01:28:31 -05:00
indexzero 8d5fb25701 [fix] Fix my own sloppy coding fixing the sloppy coding from #76. 2014-11-26 01:14:44 -05:00
Charlie Robbins 5502f2cf98 Merge pull request #111 from martinheidegger/patch-1
Adding helpful information in case parsing failed.
2014-11-26 01:08:02 -05:00
Charlie Robbins 2496f59994 Merge pull request #100 from tommystanton/doc_improve
Add some documentation about File and Literal
2014-11-26 01:07:03 -05:00
indexzero f07bc40d64 [fix] Fix inconsistent style from #98. 2014-11-26 01:06:44 -05:00
Charlie Robbins d5bd26c0b6 Merge pull request #98 from joaoafrmartins/master
filter process.env by regexp
2014-11-26 01:06:11 -05:00
indexzero 0b8aa903c7 [fix test] Remove leftover `console.log()` from #79. 2014-11-26 01:05:06 -05:00
Charlie Robbins c6d8f5d140 Merge pull request #79 from jfromaniello/master
Use optionally a different separator for memorystore
2014-11-26 01:04:35 -05:00
indexzero f771500266 [dist] Semantic cleanup from sloppy coding in #76. 2014-11-26 01:02:59 -05:00
indexzero ffce2cbec1 [dist] Update package.json versions. 2014-11-26 01:02:42 -05:00
Charlie Robbins a3404b4062 Merge pull request #76 from jmonster/usage
Resolves #64, usage and help
2014-11-26 00:59:36 -05:00
Charlie Robbins 7b01b46313 Merge pull request #117 from MitchellMcKenna/master
Update Readme to note additional nconf.file() calls require using a custom key
2014-11-11 03:12:44 -05:00
Charlie Robbins 51a4fea561 Merge pull request #99 from meritt/patch-1
Delete CHANGELOG.md
2014-09-24 23:00:38 -04:00
Charlie Robbins ddd4b616ee Merge pull request #102 from gabegorelick/tilde-versions
Use ~ for dependencies
2014-09-24 23:00:23 -04:00
Charlie Robbins 1602a9e1a3 Merge pull request #116 from Blooie/master
fixing the tests
2014-09-24 23:00:07 -04:00
Mitchell McKenna 6301d7d9c6 Update Readme; multiple file() needs custom key
- Update the Readme with notes that when using multiple config files,
  the user must use a custom key as the first parameter in additional
  nconf.file() calls in order for config heirarchy/inheritance to work
  properly.

Fixes #97, Fixes #109, Fixes #110
2014-06-17 17:56:42 -07:00
Chris Manson f69e43a423 fixing the tests 2014-05-27 17:43:24 +01:00
Martin Heidegger c8b6c98c7a Adding helpful information in case parsing failed.
I stumbled over 2 slight problems of broken configuration files:

1) It said that a error in my JSON file existed (even though it was a yaml file, parsed by libyaml)
2) It didn't tell me which error occured.

both should be fixed with this PR
2014-03-09 21:40:10 +09:00
Christopher Jeffrey 8105c761ad [fix] only reverse keys for "get" action to be safe. 2014-02-12 12:32:34 -06:00
Jarrett Cruger 999c6fbc6e Merge pull request #104 from flatiron/precedence_fix
[fix] have latter stores precede the former stores again.
2014-02-12 13:33:29 -05:00
Christopher Jeffrey 2241a36789 [fix] have latter stores precede the former stores again. 2014-02-12 12:26:38 -06:00
Jarrett Cruger 1bd1561cdd Merge pull request #103 from flatiron/precedence_fix
[fix] have latter stores precede the former stores.
2014-02-12 13:16:58 -05:00
Christopher Jeffrey 0bb89ee2b4 [fix] have latter stores precede the former stores. 2014-02-11 12:40:41 -06:00
Gabe Gorelick 43505a53ae Use ~ for dependencies 2014-02-05 10:42:15 -05:00
Jarrett Cruger 05d73de3d0 [fix] No need to test 0.6 anymore 2014-01-27 15:52:42 -05:00
Tommy Stanton 79b9b84300 [doc] Add a Literal example to add() 2014-01-16 14:15:35 -08:00
Tommy Stanton 3a7b788e35 [doc] The store for File is empty if non-existent 2014-01-16 14:05:05 -08:00
Alexey Simonenko 9891814b27 Delete CHANGELOG.md
Changelog not updated for more than 2 years, it is better to remove it so as not to mislead.
2014-01-12 21:23:15 +03:00
joaoafrmartins 120f5f0a4b added documentation 2014-01-10 00:26:07 +00:00
joaoafrmartins 681fd2f6b4 added regexp filtering to nconf env store 2014-01-10 00:17:52 +00:00
Jarrett Cruger 022b9bc507 [dist] Version bump. 0.6.9 2013-12-01 22:23:41 -08:00
Jarrett Cruger 9aa33b565a [dist] bump optimist version, fixes #89 2013-12-01 22:22:24 -08:00
Jarrett Cruger 92311c81c3 [rm] kill pkginfo 2013-12-01 22:21:21 -08:00
Jarrett Cruger c713936e8d [dist] bump async 2013-12-01 22:20:34 -08:00
Jarrett Cruger cd81efac7e [dist] Version bump. 0.6.8 2013-10-29 14:50:10 -04:00
Jarrett Cruger 5f148d5aa5 Merge pull request #90 from midknight41/master
added support for BOM in load() and loadSync(), fixed travis build too.
2013-10-26 17:05:16 -07:00
midknight41 6c1eb5e917 fixed white spacing and added (embarrassing absent) variable declarations 2013-10-26 20:40:12 +01:00
midknight41 ccd609c1c3 updated version of vows as v0.6 didn't work with node 0.10 2013-10-10 21:27:25 +01:00
midknight41 5546469061 updated .travis.yml as travis doesn't support node 0.4 or 0.9 2013-10-04 08:10:53 +01:00
midknight41 6641ed234a made bom tests more meaningful 2013-10-03 15:58:13 +01:00
midknight41 2ce8aea8fc made bom tests more meaningful 2013-10-03 15:53:02 +01:00
midknight41 f7733c1719 included bom test fixtures 2013-10-03 14:37:39 +01:00
midknight41 24f77a0edd included bom test fixtures 2013-10-03 14:37:07 +01:00
midknight41 29f1ca281b added support for BOM in load() and loadSync() 2013-10-03 09:17:36 +01:00
Charlie Robbins 62589145f3 Merge pull request #82 from mfloryan/fileinfo
Fileinfo
2013-06-21 23:14:20 -07:00
Marcin Floryan ada15db9e3 Test that invalid file name is indicated 2013-04-29 21:36:26 +01:00
Marcin Floryan 0135d95a06 Additional error information when JSON config file cannot be read 2013-04-29 16:34:48 +01:00
José F. Romaniello 039057c730 allow different separator for memorystore 2013-04-05 15:07:33 -03:00
Johnny Domino b73b0e1a37 attach help and showHelp arguments to the argv store 2013-02-23 12:33:23 -05:00
Johnny Domino 4894c8fcf7 resolves #64 passing usage string to optimist 2013-02-23 12:32:42 -05:00
Charlie Robbins 818526ca62 Merge pull request #63 from SchoonologyRRL/patch-1
Updated Memory.merge to handle null values
2012-12-20 22:56:54 -08:00
Michael Schoonmaker 5d2ebfbe9f Added test to confirm merging an Object and null behaves as expected. 2012-12-20 19:02:36 -08:00
indexzero d77c55d4ba [dist] Version bump. 0.6.7 2012-12-20 18:13:50 -05:00
Michael Hart bb57c497d3 Prefer this fix for #65 to 6045618 2012-12-20 18:12:42 -05:00
indexzero aec2b4eb46 [dist] Version bump. 0.6.6 2012-12-20 18:07:16 -05:00
Charlie Robbins e26f1af48c Merge pull request #67 from flatiron/gh-65
Fix for #65
2012-12-20 15:06:38 -08:00
indexzero 60456186d7 [fix] Fix for #65 2012-12-20 18:03:37 -05:00
indexzero 0d795ecf81 [test] Better tests to show #65 2012-12-20 14:08:36 -05:00
indexzero f19f0b6c39 [test] Added failing test to illustrate #65 2012-12-20 14:01:04 -05:00
Maciej Małecki bcbaf3a133 [dist] Bump version to 0.6.5 2012-11-02 18:17:08 +01:00
Maciej Małecki 8b65e195eb [test] Test on newer node versions 2012-11-02 18:09:17 +01:00
Michael Schoonmaker ed41c51850 Updated Memory.merge to handle null values
Previously, if the Memory store was merged with an object containing a null value, the following Error occurred:

TypeError: Object.keys called on non-object
    at Function.keys (native)
    at Memory.merge (/.../node_modules/nconf/lib/nconf/stores/memory.js:199:17)
    at Memory.merge (/.../node_modules/nconf/lib/nconf/stores/memory.js:200:17)
    at Array.every (native)
    at Memory.merge (/.../node_modules/nconf/lib/nconf/stores/memory.js:199:29)
    at common.merge (/.../node_modules/nconf/lib/nconf/common.js:99:13)
    at Array.forEach (native)
    at common.merge (/.../node_modules/nconf/lib/nconf/common.js:98:22)
    at Array.forEach (native)
    at Object.common.merge (/.../node_modules/nconf/lib/nconf/common.js:97:8)

This commit prevents that.
2012-09-27 11:26:56 -07:00
Pavan Kumar Sunkara 2ba437807a Merge pull request #62 from tellnes/loadFrom
Fix ini files for memory loadFrom option
2012-09-16 19:32:47 -07:00
Christian Tellnes 8e987b8d3d make it possible to use other formats than json in common.loadFiles and common.loadFilesSync 2012-09-16 17:45:00 +02:00
Bradley Meck f9b24f1aa6 Merge pull request #61 from flatiron/merge-null
[fix] null values should merge properly instead of throwing errors
2012-09-08 18:11:54 -07:00
Bradley Meck da39d3cac3 [fix] null values should merge properly instead of throwing errors 2012-09-08 20:10:58 -05:00
Bradley Meck f21557e783 Merge pull request #60 from flatiron/root-actions
[fix] #59 root get/set should work via null/undefined as key
2012-09-07 12:10:56 -07:00
Bradley Meck 7421836387 [fix] heirarchy fixture file path wrong in tests 2012-09-07 09:40:15 -05:00
Bradley Meck 683f78918c [fix] #59 root get/set should work via null/undefined as key 2012-09-07 09:29:30 -05:00
Joshua Holbrook ec9a13e901 Merge pull request #54 from eethann/master
Add docs for optimist options hash
2012-08-06 23:24:22 -07:00
Ethan Winn 0f092ab5a4 Added docs for options hash to optimist.
I had to dig a bit to figure out how to get options working on argv,
thought I'd save others the time.
2012-08-07 01:52:29 -04:00
indexzero 7279bc11b3 [dist] Version bump. 0.6.4 2012-07-10 03:21:06 -04:00
indexzero d96d2544bc [fix] Fix regression introduced by 36e061c4bd 2012-07-10 03:16:54 -04:00
indexzero 7e8d9d6bce [test] Added failing test for `.save()` regression introduced by @russfrank in 36e061c4bd 2012-07-10 03:16:04 -04:00
indexzero 04e22303bd [minor doc] Update file header in test/provider-test.js 2012-07-10 03:14:00 -04:00
indexzero c7c6b6f6ef [dist] Version bump. 0.6.3 2012-07-10 01:50:31 -04:00
indexzero 30734301e7 [api test doc] Make options to `Provider.prototype.file` take more flexible options 2012-07-10 01:50:18 -04:00
indexzero 8b53c12729 [minor] Use locally scoped `path` variable 2012-07-10 01:47:28 -04:00
indexzero 80a79733d3 [dist] Version bump. 0.6.2 2012-07-10 01:29:58 -04:00
indexzero 7515f66572 [fix] Ensure that all options are passed to `Provider.prototype.add` in `Provider.prototype.file`. Fixes #51
[doc] Update README.md and method documentation
[dist] Remove vim comments
2012-07-10 01:27:28 -04:00
indexzero eeddb70f20 [dist] Version bump. 0.6.1 2012-07-08 01:40:33 -04:00
Pavan Kumar Sunkara 6dd2351991 Merge pull request #49 from mhart/nested-env-configs
Add support for nested configs via env
2012-06-21 01:44:16 -07:00
Michael Hart 9aaafc5a22 Ugh, fixed whitespace 2012-06-21 18:05:52 +10:00
Michael Hart 3c08fad1c9 Changed to as it's more accurate 2012-06-21 18:04:37 +10:00
Michael Hart e15f787940 Updated README and allowed a simpley syntax 2012-06-21 17:18:22 +10:00
Michael Hart 92d4e9ea14 Added test and updated docs 2012-06-21 17:04:06 +10:00
Michael Hart 8921d0502e Added support for nested configs via env 2012-06-21 16:46:10 +10:00
Michael Hart 6cbc323005 Add reset to the list of destructive commands 2012-06-14 19:40:28 +05:30
Michael Hart 26d81e8dca Merge objects if necessary when traversing stores on get() 2012-06-13 18:28:54 +05:30
Joshua Holbrook 6b1b019353 Merge pull request #40 from tellnes/master
[fix] Fix spelling in error message
2012-05-23 22:29:56 -07:00
Christian Tellnes 83440f9956 fix spelling in error message 2012-05-24 07:27:19 +02:00
Maciej Małecki 87b0dd01c9 [minor] Use `fs.exists` when available
`path.exists*` was moved to `fs` module in
joyent/node@e10ed097cb.
2012-05-15 11:02:46 +02:00
Christian Howe 1f67d35305 [dist] Fix maintainers field 2012-05-07 03:56:46 +00:00
Jonathan Stewmon 6353d028f7 api and doc change for flatiron/nconf#28 (`.file` may now take a string instead of an object)
Conflicts:

	lib/nconf/provider.js
2012-05-03 17:10:19 -07:00
Russell Frank d3e68976c8 Proper teardowns in `complete-test.js` 2012-05-03 00:16:13 -04:00
Russell Frank 94bdb7dbd8 Added `complete-test.js` & fixture.
`complete-test.js` correctly tests the modified `save()` method.  It is
an attempt at a more complete functional test of nconf.
2012-05-01 23:27:00 -04:00
Russell Frank 36e061c4bd Fixes to `Provider.save()` and tests.
Fixed `Provider.save()` to properly ignore stores which do not provide
a saveSync method.  Also, fixed `save()` to properly save asynchronously
when an async `save()` method on a store is provided.

Removed the tests from `nconf-test.js` which expected `save()` to throw
or return an error when a store without `save()` methods was
encountered. Also removed a `console.log` from `provider-test.js`.
2012-05-01 22:44:15 -04:00
Pavan Kumar Sunkara 29eb5f905d [minor] Fix whitespaces 2012-04-15 00:58:55 +05:30
Jordan Harband 6ce0b7aef3 Surfacing additional JSON.stringify arguments in formats.json.stringify, and adding the json_spacing option to the File constructor. 2012-04-13 13:22:42 -07:00
Maciej Małecki b3699314cf [minor] Use `fs.existsSync` when available
`path.exists*` was moved to `fs` module in
joyent/node@e10ed097cb.
2012-03-29 13:13:16 +02:00
Maciej Małecki d8c4749335 [test] Test on `node@0.7` 2012-01-17 19:29:43 +01:00
indexzero 464af417fe [fix test] Fix bad test assertion 2012-01-02 17:27:09 -05:00
indexzero 6a6e092062 [dist] Version bump. 0.5.1 2012-01-02 17:20:17 -05:00
indexzero 6242caafda [api minor] Add `.loadSync()` to Memory store. Fixes #24 2012-01-02 17:20:06 -05:00
indexzero d0a91219ec [test dist] Remove unused `eyes` dependency 2012-01-02 17:14:17 -05:00
indexzero 9e9e37bb84 [minor] Update whitespace 2012-01-02 17:14:03 -05:00
Jonathan Stewmon fdb73f007b updated tests to verify that Provider.load respects hierarchy 2012-01-02 17:12:08 -05:00
Jonathan Stewmon a216336290 updated Provider.load to respect sources hierarchy 2012-01-02 17:11:51 -05:00
Jonathan Stewmon 6b6bf85802 updated optimist to version 0.3.x 2012-01-02 17:11:36 -05:00
Jonathan Stewmon 5c43d546d1 fixed merge issue in Provider.load by reversing store keys in getStores 2012-01-02 17:11:31 -05:00
Jonathan Stewmon 2804b1fb37 fixed issue caused by using same name for defaults and overrides 2012-01-02 17:11:24 -05:00
Maciej Małecki e0e070ab28 [test] Test if `File.saveSync()` returns store content
Tests #27.
2011-12-25 15:38:39 +01:00
Maciej Małecki 963387cfd4 [api] `File.saveSync()` should return store content
Fixes #27.
2011-12-25 15:30:48 +01:00
Maciej Małecki d5ce1ed68f [test] Test `saveSync()` method of file store 2011-12-25 15:26:04 +01:00
Pavan Kumar Sunkara cf9889ea81 [dist] Upgrade vows to 0.6.x 2011-12-08 11:27:48 +05:30
indexzero 62cb7fb3d9 [dist] Version bump. 0.5.0 2011-11-24 00:33:22 -05:00
indexzero 6c720ee109 [dist] Update Copyright and Author to Nodejitsu Inc. 2011-11-24 00:33:08 -05:00
indexzero 4643a14a5c [doc] Updated README and added CHANGELOG.md 2011-11-24 00:30:34 -05:00
indexzero 90b029782e [test] Update tests to use optional options API 2011-11-24 00:30:31 -05:00
indexzero 53d854a789 [api] Default to `options` if `options.store` is not available in nconf.Literal 2011-11-24 00:30:27 -05:00
indexzero b658f68a89 [test] Add additional test coverage for hierarchical configuration 2011-11-24 00:30:24 -05:00
indexzero a9c354032b [fix test] Fix overwritten tests in file-store-test.js 2011-11-24 00:30:19 -05:00
indexzero f4f1fdf464 [fix test] Update to respected `.sources` option correctly 2011-11-24 00:30:14 -05:00
indexzero bbcb2712f1 [api fix] Dont eagerly create config files in `.load()` and `.loadSync()` 2011-11-24 00:30:11 -05:00
indexzero 021850a14d [test] Move around test .json files 2011-11-24 00:29:51 -05:00
indexzero 0fbc9a2722 [test] Added tests (which are now passing) for #15 2011-11-24 00:29:47 -05:00
indexzero 16a18bffe6 [refactor] Expose all store prototypes on `nconf.*`. Expose store instances on Provider.stores and Provider.sources 2011-11-24 00:29:43 -05:00
indexzero c3cebe7cb4 [refactor] Rename `.sources` to `._stores` and bring back `._sources` 2011-11-24 00:29:39 -05:00
indexzero 78ce55602f [minor] Dont allow `.set()` calls to change values in readOnly stores: argv, env, and literal 2011-11-24 00:29:35 -05:00
indexzero 1aa2f1f315 [doc] Updated README.md 2011-11-24 00:29:31 -05:00
Sander Tolsma 47a56ccb5a [test] Test for hierarchical argv options get() 2011-11-24 00:29:27 -05:00
indexzero c3c315d648 [refactor] Refactor to make using nconf more fluent. 2011-11-24 00:29:15 -05:00
Marak Squires 2c1ef7118c [dist] Bump to v0.4.6 2011-11-21 17:17:01 -08:00
Marak Squires 223ad35ae2 Merge pull request #19 from flatiron/fix-option-reparsing
[fix] Fix option parsing
2011-11-21 17:10:57 -08:00
Maciej Małecki 1b258bf5b3 [fix] Fix option parsing
See nodejitsu/forever#165.
2011-11-22 02:06:09 +01:00
Maciej Małecki ef3222e7ab [dist] Make `repository` point to `flatiron/nconf` 2011-11-22 01:39:49 +01:00
indexzero f4723e9654 [dist] Version bump. 0.4.5 2011-11-20 14:34:16 -05:00
Maciej Małecki 2475d06cb2 [test] Test command line arguments reparsing 2011-11-19 02:02:22 +01:00
Maciej Małecki bbc5885fc1 [api] Reparse argv arguments on `system.loadArgv()`
It allows manipulating `process.argv` on the fly while still being able
to use nconf `System` store.
2011-11-19 01:58:08 +01:00
Maciej Małecki 51700cae88 [test minor] Use `process.argv[0]` when spawning processes
Previous implementation used `node`.
2011-11-19 01:29:01 +01:00
Maciej Małecki 07f8c3e558 [doc] Add Travis build status image 2011-11-18 22:29:32 +01:00
Maciej Małecki bab96b045a [test] Add `.travis.yml` for testing on Travis CI 2011-11-18 22:29:05 +01:00
indexzero b96151e617 [dist] Version bump. 0.4.4 2011-10-22 02:38:24 -04:00
Joshua Holbrook d8a30203ce [fix] filename --> file in a few file transport examples 2011-10-22 02:38:05 -04:00
indexzero 2e33082f0b [api] Automatically search for a file if `options.search` is true in File store 2011-10-22 02:36:45 -04:00
indexzero 86e22cb927 [dist] Version bump. 0.4.3 2011-09-25 00:46:40 -04:00
indexzero a2464d244b [api] Load sources into the default system store so they are permenantly cached 2011-09-25 00:46:28 -04:00
indexzero e243b0befe [dist] Version bump. 0.4.2 2011-09-25 00:21:42 -04:00
indexzero d0aee0d451 [api test] Added `.sources` option for `nconf.Provider` for readonly configuration data 2011-09-25 00:01:44 -04:00
indexzero 0234e17804 [fix] Update bad variable reference 2011-09-24 23:40:57 -04:00
indexzero d334d07b6e [dist] Version bump. 0.4.1 2011-09-19 13:51:31 -07:00
indexzero a490c7729b [fix] Match case in `require` statements 2011-09-19 13:51:17 -07:00
indexzero 0addce424d [dist] Version bump. 0.4.0 2011-09-18 21:41:00 -04:00
indexzero c4c8d7b76f [doc] Updated docco docs 2011-09-18 21:39:13 -04:00
indexzero f867e749b9 [dist] Remove unused test fixtures 2011-09-18 21:38:44 -04:00
indexzero 1ef5797e83 [api test] Finished API and tests for hierarchical configuration storage. 2011-09-18 21:37:01 -04:00
indexzero 7ef9b11d33 [doc] Minor update to library `title` 2011-09-18 21:35:55 -04:00
indexzero a0638805ce [doc] Updated usage.js and README.md for the next hierarchical syntax. 2011-09-18 21:34:45 -04:00
indexzero da2da7aea8 [api test breaking refactor] Significant refactor to how nconf works. Now a fully hierarchical configuration storage mechanism capable of multiple levels of stores of the same type. 2011-09-16 06:49:47 -04:00
indexzero 2bda7b6216 [api] Added `nconf.stores.System` 2011-09-13 07:38:41 -04:00
indexzero 54ea0950c2 [dist] Version bump. 0.3.1 2011-08-29 15:20:54 -04:00
indexzero e631d239d5 [fix] Lazy-load any CLI arguments from `optimist` 2011-08-29 15:19:55 -04:00
indexzero 8a3172868e [dist] Version bump. 0.3.0 2011-08-28 10:46:12 -04:00
indexzero 2e47d027ce [doc] Updated README.md 2011-08-28 10:43:44 -04:00
indexzero 954b5fdc2e [doc] Updated docco docs 2011-08-28 10:43:34 -04:00
indexzero fb392ddc51 [api test] Updated test/provider-test.js and associated merge implementation 2011-08-28 08:50:26 -04:00
indexzero e8904e95c6 [api] Added `nconf.loadFiles()` method 2011-08-23 06:53:05 -04:00
indexzero a6533aa7bf [dist api test] Finished integrating features from reconf and updating associated tests 2011-08-23 06:38:51 -04:00
indexzero add8922c04 [api dist] Begin to integrate features from reconf 2011-08-22 20:17:28 -04:00
indexzero 57f0742455 [doc] Update README.md for nconf-redis 2011-07-08 17:01:22 -04:00
indexzero b6adab2825 [dist] Version bump. 0.2.0 2011-07-08 15:37:15 -04:00
indexzero 8620e6ba91 [api test] Remove Redis store in preparation for nconf-redis 2011-07-08 15:33:33 -04:00
indexzero 49a1a6dea3 [dist] Added LICENSE (MIT ftw) 2011-07-01 14:00:30 -04:00
indexzero d485f5edde [dist] Version bump. 0.1.14 2011-06-25 00:34:19 -04:00
indexzero 7e4623ec46 [api test] Update `nconf.Provider` to create a new instance of the store if the options are different 2011-06-25 00:34:07 -04:00
indexzero 1b0f34793b [dist] Version bump. 0.1.13 2011-06-24 03:31:44 -04:00
indexzero d8b5a80280 [minor] Small style updates to the File store 2011-06-24 03:31:26 -04:00
Marak Squires c43685160d [refactor]: Cleaned up error handling on File.loadSync and File.load
[refactor]: Using path module to determine if file exists instead of throwing error
[api]: File.load and File.loadSync will now automatically create the requested JSON file path if no file is found.
2011-06-23 18:06:26 -07:00
Charlie Robbins d8627a9475 Merge pull request #6 from dominictarr/master
callback inside of try block can obscure errors
2011-06-12 16:38:17 -07:00
Dominic Tarr 6c6887a850 move callback outside of try / catch
it's dangerous to callback inside try, because you may catch unexpected throws in callback.
2011-06-12 15:45:02 -07:00
indexzero ae5aec6830 [dist] Version bump. 0.1.12 2011-06-08 00:07:12 -04:00
indexzero 76db254740 [fix test] Update nconf.stores.File to respond with an error when loading malformed JSON async 2011-06-08 00:06:58 -04:00
indexzero d7495f8373 [dist] Version bump. 0.1.11 2011-06-07 23:45:39 -04:00
indexzero 4c7aea99d3 [doc] Update docco docs 2011-06-07 23:45:23 -04:00
indexzero f611066b60 [dist] Update to pkginfo 0.2.0 2011-06-07 23:45:01 -04:00
indexzero be7688782a [dist] Version bump. 0.1.10 2011-06-05 01:40:11 -04:00
indexzero 7ffbf0a4ab [doc] Regenerate docco docs 2011-06-05 01:39:58 -04:00
indexzero 13f5753405 [minor] Update `nconf.version` to use pkginfo 2011-06-05 01:39:39 -04:00
indexzero c9e60d96b5 [doc] Update code docs 2011-06-05 01:35:54 -04:00
indexzero 4459ba54a1 [api] Added `.merge()` to stores.Memory and stores.Redis 2011-06-05 01:29:14 -04:00
indexzero a4f00be991 [dist] Update package.json and .gitignore 2011-05-24 23:45:57 -06:00
indexzero c21ab02f44 Merge branch 'master' of https://github.com/samsonjs/nconf 2011-05-23 16:58:12 -04:00
indexzero 1b47f58343 Merge branch 'master' of https://github.com/AvianFlu/nconf 2011-05-23 16:54:54 -04:00
Sami Samhuri 8a79ef04fd test retrieving non-existent keys and drilling into non-objects 2011-05-22 13:01:49 -07:00
Sami Samhuri 6acc1fc533 allow storing null in redis 2011-05-22 12:40:57 -07:00
Sami Samhuri faa8ab9486 correctly retrieve falsy values from memory (hence file) 2011-05-22 12:40:57 -07:00
avian bdf2fc8cd7 [fix] Fixed spelling error 2011-05-20 01:21:46 -07:00
avian e7c216e970 [minor] Clarified error message returned when a config file contains invalid JSON. 2011-05-20 01:16:22 -07:00
indexzero e26bbe25f2 [doc] Updated code samples for GitHub flavored markdown with Javascript 2011-05-19 23:12:56 -04:00
indexzero 78202ecb6c [dist] Version bump. 0.1.9 2011-05-16 22:44:53 -04:00
indexzero 87351caac8 [fix] Use the memory engine by default 2011-05-16 22:44:46 -04:00
indexzero badbb59e3f [dist] Version bump. 0.1.8 2011-05-16 14:08:30 -04:00
indexzero 9da37dff2a [dist api test] Refactor pluggable nconf-level logic into nconf.Provider. Update .gitignore for npm 1.0. Update pathing in source and tests to be more `require.paths` future-proof 2011-05-14 01:47:26 -04:00
indexzero 4a61560671 [dist] Version bump. 0.1.7 2011-04-20 01:58:46 -04:00
indexzero 3b104f2026 [doc] Update docco docs 2011-04-20 01:58:12 -04:00
indexzero d65922dc7a [api] Add `.saveSync()` and `.loadSync()` methods to File store 2011-04-20 01:57:56 -04:00
indexzero b9951b44c1 [dist] Version bump. 0.1.6. 2011-04-19 17:34:42 -04:00
indexzero da8559427f [doc] Update docco docs 2011-04-19 17:34:27 -04:00
indexzero 067d58a99d [minor test] Add tests for File store `save()`. Improve default file format to pretty print the JSON output 2011-04-19 17:32:13 -04:00
indexzero 96859f913c [dist] Version bump. 0.1.5 2011-04-13 18:49:54 -04:00
indexzero d99ab32cc5 [fix] Dont allow `async.forEach` to be called on undefined or null arrays 2011-04-13 18:49:38 -04:00
indexzero 7484fdb7a0 [dist] Version bump. 0.1.4 2011-04-05 03:53:50 -04:00
indexzero 04a59e93d6 [fix] Supress errors from Redis 2011-04-05 03:53:17 -04:00
indexzero 9bd6e266a7 [dist] Version bump. 0.1.3 2011-04-05 00:10:24 -04:00
indexzero 4094125b30 [api] Add support for Redis auth and optional callbacks. 2011-04-05 00:09:46 -04:00
indexzero 81e1883df5 [dist] Version bump. 0.1.2 2011-04-03 14:19:33 -04:00
indexzero b850ae2dd0 [fix] Update path to require statement in Redis store 2011-04-03 14:19:02 -04:00
indexzero 6f16bc71d6 [dist] Version bump. 0.1.1 2011-04-02 19:17:26 -04:00
indexzero 752bb980ac [api] Improve the `.use()` method. Use the memory engine by default 2011-04-02 19:17:04 -04:00
53 changed files with 3588 additions and 1834 deletions

33
.circleci/config.yml Normal file
View File

@ -0,0 +1,33 @@
version: 2.1
commands:
test-nodejs:
steps:
- run:
name: Versions
command: npm version
- checkout
- run:
name: Install dependencies
command: npm install
- run:
name: Test
command: npm test
jobs:
node-v14:
docker:
- image: node:14-alpine
steps:
- test-nodejs
node-v16:
docker:
- image: node:16-alpine
steps:
- test-nodejs
workflows:
version: 2
node-multi-build:
jobs:
- node-v14
- node-v16

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
.DS_Store
config.json
test/fixtures/store.json
node_modules
npm-debug.log

1
.npmrc Normal file
View File

@ -0,0 +1 @@
package-lock=false

12
CHANGELOG.md Normal file
View File

@ -0,0 +1,12 @@
v2.0.0 / Tue, 2 Jun 2020
========================
Completely redesigned and re-written with zero dependencies among other things.
v1.0.0 / Tue, 2 Jun 2020
========================
This is quite the change as master had been updated over the years since the v.0.9.1 release. However it should be smaller and lighter.
* Major change: Removed all dependancies to yargs and removed argv support

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (C) 2011 Charlie Robbins and the Contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

335
README.md
View File

@ -1,84 +1,321 @@
# nconf
# nconf-lite
A hybrid local / remote configuration storage library for node.js.
Nconf-lite is a complete re-written design of original nconf with zero dependancy, tiny and fast while maintaining most if not all of the documented features of the old nconf.
## Installation
It is a hierarchical node.js configuration with files, environment variables, and atomic object merging.
### Installing npm (node package manager)
<pre>
curl http://npmjs.org/install.sh | sh
</pre>
Compared to nconf running at 952KB with over 220 files *installed*, nconf-lite is clocking at measly 42KB with only 11 files of easily reviewable code and a ton more unit test, testing almost every micro functionality.
### Installing nconf
<pre>
[sudo] npm install nconf
</pre>
## Example
Using nconf is easy; it is designed to be a simple key-value store with support for both local and remote storage. Keys are namespaced and delimited by `:`. Let's dive right into sample usage:
## Usage
Using nconf is easy; it is designed to be a simple key-value store with support for both local and remote storage. Keys are namespaced and delimited by `:`. Lets dive right into sample usage:
``` js
import Nconf from 'nconf-lite'
const nconf = new Nconf()
<pre>
var fs = require('fs'),
nconf = require('nconf');
//
// Setup nconf to user the 'file' store and set a couple of values;
// Setup nconf to use (in-order):
// 2. Environment variables
// 3. A file located at 'path/to/config.json'
//
nconf.env()
.file({ file: 'path/to/config.json' });
//
// Set a few variables on `nconf`.
//
nconf.use('file', { file: 'path/to/your/config.json' });
nconf.set('database:host', '127.0.0.1');
nconf.set('database:port', 5984);
//
// Get the entire database object from nconf
// Get the entire database object from nconf. This will output
// { host: '127.0.0.1', port: 5984 }
//
var database = nconf.get('database');
console.log('foo: ' + nconf.get('foo'));
console.log('NODE_ENV: ' + nconf.get('NODE_ENV'));
console.log('database: ' + nconf.get('database'));
//
// Save the configuration object to disk
//
nconf.save(function (err) {
fs.readFile('path/to/your/config.json', function (err, data) {
console.dir(JSON.parse(data.toString()))
});
nconf.save()
```
If you run the above script:
``` bash
$ NODE_ENV=production sample.js
```
The output will be:
```
NODE_ENV: production
database: { host: '127.0.0.1', port: 5984 }
```
## Hierarchical configuration
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.** Let's take a look at the options available to you
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.
5. **nconf.overrides(options)** Loads the data in options.store into the hierarchy.
A sane default for this could be:
``` js
import Nconf from 'nconf-lite'
const nconf = new Nconf()
//
// 1. any overrides
//
nconf.overrides({
'always': 'be this value'
});
</pre>
//
// 2. `process.env`
//
nconf.env();
//
// 4. Values in `config.json`
//
nconf.file('/path/to/config.json');
//
// Or with a custom name
// Note: A custom key must be supplied for hierarchy to work if multiple files are used.
//
nconf.file('custom', '/path/to/config.json');
//
// 5. Any default values
//
nconf.defaults({
'if nothing else': 'use this value'
});
```
## API Documentation
### 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
or as an array. If the last argument is a function, it will be called with the result; otherwise, the value is returned.
``` js
//
// Get one of 'NODEJS_PORT' and 'PORT' as a return value
//
let port = nconf.any('NODEJS_PORT', 'PORT');
```
### nconf.use(name)
Fetch a specific store with the specified name.
``` js
//
// Load a file store onto nconf with the specified settings
//
nconf.file('custom', '/path/to/config.json');
//
// Grab the instance and set it to be readonly
//
nconf.use('custom').readOnly = true
```
### nconf.required(keys)
Declares a set of string keys to be mandatory, and throw an error if any are missing.
``` js
nconf.defaults({
keya: 'a',
});
nconf.required(['keya', 'keyb']);
// Error: Missing required keys: keyb
```
You can also chain `.required()` calls when needed. for example when a configuration depends on another configuration store
```js
config
.env()
.required([ 'STAGE']) //here you should have STAGE otherwise throw an error
.file( 'stage', path.resolve( 'configs', 'stages', config.get( 'STAGE' ) + '.json' ) )
.required([ 'OAUTH:redirectURL']) // here you should have OAUTH:redirectURL, otherwise throw an error
.file( 'oauth', path.resolve( 'configs', 'oauth', config.get( 'OAUTH:MODE' ) + '.json' ) )
.file( 'app', path.resolve( 'configs', 'app.json' ) )
.required([ 'LOGS_MODE']) // here you should haveLOGS_MODE, otherwise throw an error
.literal( 'logs', require( path.resolve( 'configs', 'logs', config.get( 'LOGS_MODE' ) + '.js') ))
.defaults( defaults );
```
## Storage Engines
### Memory
A simple in-memory storage engine that stores a nested JSON representation of the configuration. To use this engine, just call `.use()` with the appropriate arguments. All calls to `.get()`, `.set()`, `.clear()`, `.reset()` methods are synchronous since we are only dealing with an in-memory object.
<pre>
``` js
nconf.use('memory');
</pre>
```
### Env
Responsible for loading the values parsed from `process.env` into the configuration hierarchy.
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
//
// Can optionally also be an Array of values to limit process.env to.
//
nconf.env(['only', 'load', 'these', 'values', 'from', 'process.env']);
//
// Can also specify a separator for nested keys (instead of the default ':')
//
nconf.env({ separator: '__' });
// Get the value of the env variable 'database__host'
let dbHost = nconf.get('database:host');
//
// Can also lowerCase keys.
// Especially handy when dealing with environment variables which are usually
// uppercased.
//
// Given an environment variable PORT=3001
nconf.env();
let port = nconf.get('port') // undefined
nconf.env({ lowerCase: true });
let port = nconf.get('port') // 3001
//
// Or use all options
//
nconf.env({
separator: '__',
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,
transform: function(obj) {
if (obj.key === 'foo') {
obj.value = 'baz';
}
return obj;
}
});
let dbHost = nconf.get('database:host');
```
### Literal
Loads a given object literal into the configuration hierarchy. Both `nconf.defaults()` and `nconf.overrides()` use the Literal store.
``` js
nconf.defaults({
'some': 'default value'
});
```
### File
Based on the Memory engine, but provides additional methods `.save()` and `.load()` which allow you to read your configuration to and from file. As with the Memory store, all method calls are synchronous with the exception of `.save()` and `.load()` which take callback functions. It is important to note that setting keys in the File engine will not be persisted to disk until a call to `.save()` is made.
Based on the Memory store, but provides additional methods `.save()` and `.load()` which allow you to read your configuration to and from file. As with the Memory store, all method calls are synchronous includ `.save()` and `.load()`.
<pre>
nconf.use('file', { file: 'path/to/your/config.json' });
</pre>
It is important to note that setting keys in the File engine will not be persisted to disk until a call to `.save()` is made. Note a custom key must be supplied as the first parameter for hierarchy to work if multiple files are used.
``` js
nconf.file('path/to/your/config.json');
// add multiple files, hierarchically. notice the unique key for each file
nconf.file('user', 'path/to/your/user.json');
nconf.file('global', 'path/to/your/global.json');
// Set a variable in the user store and save it
nconf.user('user').set('some:variable', true)
nconf.user('user').save()
```
The file store is also extensible for multiple file formats, defaulting to `JSON`. To use a custom format, simply pass a format object to the `.use()` method. This object must have `.parse()` and `.stringify()` methods just like the native `JSON` object.
### Redis
The Redis engine will persist all of your configuration settings to a Redis server. All calls to `.get()`, `.set()`, `.clear()`, `.reset()` are asynchronous taking an additional callback parameter.
If the file does not exist at the provided path, the store will simply be empty.
<pre>
nconf.use('redis', { host: 'localhost', port: 6379, ttl: 60 * 60 * 1000 });
</pre>
#### Encrypting file contents
The Redis engine also has an in-memory cache with a default TTL of one hour. To change this, just pass the `ttl` option to `.use()`.
Encryption and decrypting file contents using the `secure` option:
## More Documentation
There is more documentation available through docco. I haven't gotten around to making a gh-pages branch so in the meantime if you clone the repository you can view the docs:
<pre>
open docs/nconf.html
</pre>
``` js
nconf.file('secure-file', {
file: 'path/to/secure-file.json',
secure: {
secret: 'super-secretzzz-keyzz',
alg: 'aes-256-ctr'
}
})
```
This will encrypt each key using [`crypto.createCipheriv`](https://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options), defaulting to `aes-256-ctr`. The encrypted file contents will look like this:
```
{
"config-key-name": {
"alg": "aes-256-ctr", // cipher used
"value": "af07fbcf", // encrypted contents
"iv": "49e7803a2a5ef98c7a51a8902b76dd10" // initialization vector
},
"another-config-key": {
"alg": "aes-256-ctr", // cipher used
"value": "e310f6d94f13", // encrypted contents
"iv": "b654e01aed262f37d0acf200be193985" // initialization vector
},
}
```
## Installation
``` bash
npm install nconf-lite --save
```
## Run Tests
Tests are written in vows and give complete coverage of all APIs and storage engines.
<pre>
vows test/*-test.js --spec
</pre>
#### Author: [Charlie Robbins](http://nodejitsu.com)
``` bash
$ npm test
```
#### Original author: [Charlie Robbins](http://nodejitsu.com)
#### Rewriter of all that garbage: TheThing
#### License: MIT
[0]: http://github.com/nfp-projects/nconf-lite

View File

@ -1,194 +0,0 @@
/*--------------------- Layout and Typography ----------------------------*/
body {
font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
font-size: 15px;
line-height: 22px;
color: #252519;
margin: 0; padding: 0;
}
a {
color: #261a3b;
}
a:visited {
color: #261a3b;
}
p {
margin: 0 0 15px 0;
}
h4, h5, h6 {
color: #333;
margin: 6px 0 6px 0;
font-size: 13px;
}
h2, h3 {
margin-bottom: 0;
color: #000;
}
h1 {
margin-top: 40px;
margin-bottom: 15px;
color: #000;
}
#container {
position: relative;
}
#background {
position: fixed;
top: 0; left: 525px; right: 0; bottom: 0;
background: #f5f5ff;
border-left: 1px solid #e5e5ee;
z-index: -1;
}
#jump_to, #jump_page {
background: white;
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
font: 10px Arial;
text-transform: uppercase;
cursor: pointer;
text-align: right;
}
#jump_to, #jump_wrapper {
position: fixed;
right: 0; top: 0;
padding: 5px 10px;
}
#jump_wrapper {
padding: 0;
display: none;
}
#jump_to:hover #jump_wrapper {
display: block;
}
#jump_page {
padding: 5px 0 3px;
margin: 0 0 25px 25px;
}
#jump_page .source {
display: block;
padding: 5px 10px;
text-decoration: none;
border-top: 1px solid #eee;
}
#jump_page .source:hover {
background: #f5f5ff;
}
#jump_page .source:first-child {
}
table td {
border: 0;
outline: 0;
}
td.docs, th.docs {
max-width: 450px;
min-width: 450px;
min-height: 5px;
padding: 10px 25px 1px 50px;
overflow-x: hidden;
vertical-align: top;
text-align: left;
}
.docs pre {
margin: 15px 0 15px;
padding-left: 15px;
}
.docs p tt, .docs p code {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 12px;
padding: 0 0.2em;
}
.pilwrap {
position: relative;
}
.pilcrow {
font: 12px Arial;
text-decoration: none;
color: #454545;
position: absolute;
top: 3px; left: -20px;
padding: 1px 2px;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
}
td.docs:hover .pilcrow {
opacity: 1;
}
td.code, th.code {
padding: 14px 15px 16px 25px;
width: 100%;
vertical-align: top;
background: #f5f5ff;
border-left: 1px solid #e5e5ee;
}
pre, tt, code {
font-size: 12px; line-height: 18px;
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
/*---------------------- Syntax Highlighting -----------------------------*/
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
body .hll { background-color: #ffffcc }
body .c { color: #408080; font-style: italic } /* Comment */
body .err { border: 1px solid #FF0000 } /* Error */
body .k { color: #954121 } /* Keyword */
body .o { color: #666666 } /* Operator */
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
body .cp { color: #BC7A00 } /* Comment.Preproc */
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
body .cs { color: #408080; font-style: italic } /* Comment.Special */
body .gd { color: #A00000 } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #FF0000 } /* Generic.Error */
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
body .gi { color: #00A000 } /* Generic.Inserted */
body .go { color: #808080 } /* Generic.Output */
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
body .gt { color: #0040D0 } /* Generic.Traceback */
body .kc { color: #954121 } /* Keyword.Constant */
body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
body .kp { color: #954121 } /* Keyword.Pseudo */
body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
body .kt { color: #B00040 } /* Keyword.Type */
body .m { color: #666666 } /* Literal.Number */
body .s { color: #219161 } /* Literal.String */
body .na { color: #7D9029 } /* Name.Attribute */
body .nb { color: #954121 } /* Name.Builtin */
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
body .no { color: #880000 } /* Name.Constant */
body .nd { color: #AA22FF } /* Name.Decorator */
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
body .nf { color: #0000FF } /* Name.Function */
body .nl { color: #A0A000 } /* Name.Label */
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
body .nt { color: #954121; font-weight: bold } /* Name.Tag */
body .nv { color: #19469D } /* Name.Variable */
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #666666 } /* Literal.Number.Float */
body .mh { color: #666666 } /* Literal.Number.Hex */
body .mi { color: #666666 } /* Literal.Number.Integer */
body .mo { color: #666666 } /* Literal.Number.Oct */
body .sb { color: #219161 } /* Literal.String.Backtick */
body .sc { color: #219161 } /* Literal.String.Char */
body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
body .s2 { color: #219161 } /* Literal.String.Double */
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
body .sh { color: #219161 } /* Literal.String.Heredoc */
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
body .sx { color: #954121 } /* Literal.String.Other */
body .sr { color: #BB6688 } /* Literal.String.Regex */
body .s1 { color: #219161 } /* Literal.String.Single */
body .ss { color: #19469D } /* Literal.String.Symbol */
body .bp { color: #954121 } /* Name.Builtin.Pseudo */
body .vc { color: #19469D } /* Name.Variable.Class */
body .vg { color: #19469D } /* Name.Variable.Global */
body .vi { color: #19469D } /* Name.Variable.Instance */
body .il { color: #666666 } /* Literal.Number.Integer.Long */

View File

@ -1,103 +0,0 @@
<!DOCTYPE html> <html> <head> <title>nconf.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="nconf/stores/file.html"> nconf/stores/file.html </a> <a class="source" href="nconf/stores/memory.html"> nconf/stores/memory.html </a> <a class="source" href="nconf/stores/redis.html"> nconf/stores/redis.html </a> <a class="source" href="nconf/stores.html"> nconf/stores.html </a> <a class="source" href="nconf.html"> nconf.html </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> nconf.js </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> </td> <td class="code"> <div class="highlight"><pre><span class="cm">/*</span>
<span class="cm"> * nconf.js: Top-level include for the nconf module</span>
<span class="cm"> *</span>
<span class="cm"> * (C) 2011, Charlie Robbins</span>
<span class="cm"> *</span>
<span class="cm"> */</span>
<span class="nx">require</span><span class="p">.</span><span class="nx">paths</span><span class="p">.</span><span class="nx">unshift</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">nconf</span> <span class="o">=</span> <span class="nx">exports</span><span class="p">;</span>
<span class="nx">nconf</span><span class="p">.</span><span class="nx">stores</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;nconf/stores&#39;</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <h3>function use (type, options)</h3>
<h4>@type {string} Type of the nconf store to use.</h4>
<h4>@options {Object} Options for the store instance.</h4>
<p>Sets the active <code>nconf.store</code> to a new instance of the
specified <code>type</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">use</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">type</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">stores</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">type</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h3>function get (key, callback)</h3>
<h4>@key {string} Key to retrieve for this instance.</h4>
<h4>@callback {function} <strong>Optional</strong> Continuation to respond to when complete.</h4>
<p>Retrieves the value for the specified key (if any).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">get</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <h3>function set (key, value, callback)</h3>
<h4>@key {string} Key to set in this instance</h4>
<h4>@value {literal|Object} Value for the specified key</h4>
<h4>@callback {function} <strong>Optional</strong> Continuation to respond to when complete.</h4>
<p>Sets the <code>value</code> for the specified <code>key</code> in this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">set</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <h3>function clear (key, callback)</h3>
<h4>@key {string} Key to remove from this instance</h4>
<h4>@callback {function} <strong>Optional</strong> Continuation to respond to when complete.</h4>
<p>Removes the value for the specified <code>key</code> from this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">clear</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">clear</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <h3>function load (callback)</h3>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Responds with an Object representing all keys associated in this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">load</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">load</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">error</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s1">&#39;nconf store &#39;</span> <span class="o">+</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">type</span> <span class="o">+</span> <span class="s1">&#39; has no load() method&#39;</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span> <span class="p">(</span><span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">callback</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <h3>function save (value, callback)</h3>
<h4>@value {Object} <strong>Optional</strong> Config object to set for this instance</h4>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Removes any existing configuration settings that may exist in this
instance and then adds all key-value pairs in <code>value</code>. </p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">save</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">callback</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="nx">value</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">save</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">error</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s1">&#39;nconf store &#39;</span> <span class="o">+</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">type</span> <span class="o">+</span> <span class="s1">&#39; has no save() method&#39;</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span> <span class="p">(</span><span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">save</span><span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <h3>function reset (callback)</h3>
<h4>@callback {function} <strong>Optional</strong> Continuation to respond to when complete.</h4>
<p>Clears all keys associated with this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">reset</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">reset</span><span class="p">(</span><span class="nx">callback</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <h3>function key (arguments)</h3>
<p>Returns a <code>:</code> joined string from the <code>arguments</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;:&#39;</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <h3>function path (key)</h3>
<h4>@key {string} The ':' delimited key to split</h4>
<p>Returns a fully-qualified path to a nested nconf key. </p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">nconf</span><span class="p">.</span><span class="nx">path</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">key</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;:&#39;</span><span class="p">);</span>
<span class="p">};</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@ -1,27 +0,0 @@
<!DOCTYPE html> <html> <head> <title>stores.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="../docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="..//nconf/stores/file.html"> nconf/stores/file.html </a> <a class="source" href="..//nconf/stores/memory.html"> nconf/stores/memory.html </a> <a class="source" href="..//nconf/stores/redis.html"> nconf/stores/redis.html </a> <a class="source" href="..//nconf/stores.html"> nconf/stores.html </a> <a class="source" href="..//nconf.html"> nconf.html </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> stores.js </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> </td> <td class="code"> <div class="highlight"><pre><span class="cm">/*</span>
<span class="cm"> * stores.js: Top-level include for all nconf stores</span>
<span class="cm"> *</span>
<span class="cm"> * (C) 2011, Charlie Robbins</span>
<span class="cm"> *</span>
<span class="cm"> */</span>
<span class="kd">var</span> <span class="nx">stores</span> <span class="o">=</span> <span class="nx">exports</span><span class="p">;</span>
<span class="kd">function</span> <span class="nx">capitalize</span> <span class="p">(</span><span class="nx">str</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">str</span> <span class="o">&amp;&amp;</span> <span class="nx">str</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">toUpperCase</span><span class="p">()</span> <span class="o">+</span> <span class="nx">str</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="p">};</span>
<span class="nx">stores</span><span class="p">.</span><span class="nx">Memory</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;nconf/stores/memory&#39;</span><span class="p">).</span><span class="nx">Memory</span><span class="p">;</span>
<span class="nx">stores</span><span class="p">.</span><span class="nx">File</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;nconf/stores/file&#39;</span><span class="p">).</span><span class="nx">File</span><span class="p">;</span>
<span class="nx">stores</span><span class="p">.</span><span class="nx">Redis</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;nconf/stores/redis&#39;</span><span class="p">).</span><span class="nx">Redis</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <h3>function create (type, options)</h3>
<h4>@type {string} Type of the nconf store to use.</h4>
<h4>@options {Object} Options for the store instance.</h4>
<p>Creates a store of the specified <code>type</code> using the
specified <code>options</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">stores</span><span class="p">.</span><span class="nx">create</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">type</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">stores</span><span class="p">[</span><span class="nx">capitalize</span><span class="p">(</span><span class="nx">type</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">())](</span><span class="nx">options</span><span class="p">);</span>
<span class="p">};</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@ -1,58 +0,0 @@
<!DOCTYPE html> <html> <head> <title>file.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="../../docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="../..//nconf/stores/file.html"> nconf/stores/file.html </a> <a class="source" href="../..//nconf/stores/memory.html"> nconf/stores/memory.html </a> <a class="source" href="../..//nconf/stores/redis.html"> nconf/stores/redis.html </a> <a class="source" href="../..//nconf/stores.html"> nconf/stores.html </a> <a class="source" href="../..//nconf.html"> nconf.html </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> file.js </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> </td> <td class="code"> <div class="highlight"><pre><span class="cm">/*</span>
<span class="cm"> * file.js: Simple file storage engine for nconf files</span>
<span class="cm"> *</span>
<span class="cm"> * (C) 2011, Charlie Robbins</span>
<span class="cm"> *</span>
<span class="cm"> */</span>
<span class="kd">var</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;fs&#39;</span><span class="p">),</span>
<span class="nx">util</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;util&#39;</span><span class="p">),</span>
<span class="nx">Memory</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./memory&#39;</span><span class="p">).</span><span class="nx">Memory</span><span class="p">;</span>
</pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <h3>function File (options)</h3>
<h4>@options {Object} Options for this instance</h4>
<p>Constructor function for the File nconf store, a simple abstraction
around the Memory store that can persist configuration to disk.</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">File</span> <span class="o">=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">File</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">options</span><span class="p">.</span><span class="nx">file</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="p">(</span><span class="s1">&#39;Missing required option `files`&#39;</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">Memory</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">file</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">file</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">format</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">format</span> <span class="o">||</span> <span class="nx">JSON</span><span class="p">;</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>Inherit from the Memory store</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">util</span><span class="p">.</span><span class="nx">inherits</span><span class="p">(</span><span class="nx">File</span><span class="p">,</span> <span class="nx">Memory</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <h3>function save (value, callback)</h3>
<h4>@value {Object} <em>Ignored</em> Left here for consistency</h4>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Saves the current configuration object to disk at <code>this.file</code>
using the format specified by <code>this.format</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">File</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">save</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">callback</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="nx">value</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">format</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">store</span><span class="p">),</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">err</span> <span class="o">?</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">:</span> <span class="nx">callback</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <h3>function load (callback)</h3>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Responds with an Object representing all keys associated in this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">File</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">load</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">data</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">format</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">store</span> <span class="o">=</span> <span class="nx">data</span><span class="p">;</span>
<span class="nx">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">self</span><span class="p">.</span><span class="nx">store</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">};</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@ -1,83 +0,0 @@
<!DOCTYPE html> <html> <head> <title>memory.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="../../docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="../..//nconf/stores/file.html"> nconf/stores/file.html </a> <a class="source" href="../..//nconf/stores/memory.html"> nconf/stores/memory.html </a> <a class="source" href="../..//nconf/stores/redis.html"> nconf/stores/redis.html </a> <a class="source" href="../..//nconf/stores.html"> nconf/stores.html </a> <a class="source" href="../..//nconf.html"> nconf.html </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> memory.js </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> </td> <td class="code"> <div class="highlight"><pre><span class="cm">/*</span>
<span class="cm"> * memory.js: Simple memory storage engine for nconf configuration(s)</span>
<span class="cm"> *</span>
<span class="cm"> * (C) 2011, Charlie Robbins</span>
<span class="cm"> *</span>
<span class="cm"> */</span>
<span class="kd">var</span> <span class="nx">nconf</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;nconf&#39;</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <h3>function Memory (options)</h3>
<h4>@options {Object} Options for this instance</h4>
<p>Constructor function for the Memory nconf store which maintains
a nested json structure based on key delimiters <code>:</code>.</p>
<p>e.g. <code>my:nested:key</code> ==> <code>{ my: { nested: { key: } } }</code> </p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">Memory</span> <span class="o">=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">Memory</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">options</span> <span class="o">=</span> <span class="nx">options</span> <span class="o">||</span> <span class="p">{};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">store</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">mtimes</span> <span class="o">=</span> <span class="p">{};</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h3>function get (key)</h3>
<h4>@key {string} Key to retrieve for this instance.</h4>
<p>Retrieves the value for the specified key (if any).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Memory</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">get</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">target</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">store</span><span class="p">,</span>
<span class="nx">path</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">path</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>Scope into the object to get the appropriate nested context</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">while</span> <span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">key</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">shift</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">])</span> <span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">target</span> <span class="o">=</span> <span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">target</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <h3>function set (key, value)</h3>
<h4>@key {string} Key to set in this instance</h4>
<h4>@value {literal|Object} Value for the specified key</h4>
<p>Sets the <code>value</code> for the specified <code>key</code> in this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Memory</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">set</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">target</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">store</span><span class="p">,</span>
<span class="nx">path</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">path</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>Update the <code>mtime</code> (modified time) of the key</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">this</span><span class="p">.</span><span class="nx">mtimes</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">();</span>
</pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>Scope into the object to get the appropriate nested context</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">while</span> <span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">key</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">shift</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">])</span> <span class="p">{</span>
<span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{};</span>
<span class="p">}</span>
<span class="nx">target</span> <span class="o">=</span> <span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">];</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>Set the specified value in the nested JSON structure</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">key</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">shift</span><span class="p">();</span>
<span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <h3>function clear (key)</h3>
<h4>@key {string} Key to remove from this instance</h4>
<p>Removes the value for the specified <code>key</code> from this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Memory</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">clear</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">target</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">store</span><span class="p">,</span>
<span class="nx">path</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">path</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Remove the key from the set of <code>mtimes</code> (modified times)</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">delete</span> <span class="k">this</span><span class="p">.</span><span class="nx">mtimes</span><span class="p">[</span><span class="nx">key</span><span class="p">];</span>
</pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>Scope into the object to get the appropriate nested context</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">while</span> <span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">key</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">shift</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">])</span> <span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">target</span> <span class="o">=</span> <span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">];</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Delete the key from the nested JSON structure</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">key</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">shift</span><span class="p">();</span>
<span class="k">delete</span> <span class="nx">target</span><span class="p">[</span><span class="nx">key</span><span class="p">];</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <h3>function reset (callback)</h3>
<p>Clears all keys associated with this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Memory</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">reset</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">mtimes</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">store</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@ -1,250 +0,0 @@
<!DOCTYPE html> <html> <head> <title>redis.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="../../docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="../..//nconf/stores/file.html"> nconf/stores/file.html </a> <a class="source" href="../..//nconf/stores/memory.html"> nconf/stores/memory.html </a> <a class="source" href="../..//nconf/stores/redis.html"> nconf/stores/redis.html </a> <a class="source" href="../..//nconf/stores.html"> nconf/stores.html </a> <a class="source" href="../..//nconf.html"> nconf.html </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> redis.js </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> </td> <td class="code"> <div class="highlight"><pre><span class="cm">/*</span>
<span class="cm"> * redis.js: Redis storage engine for nconf configuration(s)</span>
<span class="cm"> *</span>
<span class="cm"> * (C) 2011, Charlie Robbins</span>
<span class="cm"> *</span>
<span class="cm"> */</span>
<span class="kd">var</span> <span class="nx">async</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;async&#39;</span><span class="p">),</span>
<span class="nx">eyes</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;eyes&#39;</span><span class="p">),</span>
<span class="nx">redis</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;redis&#39;</span><span class="p">),</span>
<span class="nx">nconf</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;nconf&#39;</span><span class="p">),</span>
<span class="nx">Memory</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./Memory&#39;</span><span class="p">).</span><span class="nx">Memory</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <h3>function Redis (options)</h3>
<h4>@options {Object} Options for this instance</h4>
<p>Constructor function for the Redis nconf store which maintains
a nested Redis key structure based on key delimiters <code>:</code>.</p>
<p>e.g.
my:nested:key, 'value'
namespace:keys ==> ['my']
namespace:nested:keys ==> ['key']
namespace:nested:key ==> 'value'</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">Redis</span> <span class="o">=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">Redis</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">options</span> <span class="o">=</span> <span class="nx">options</span> <span class="o">||</span> <span class="p">{}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">namespace</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">namespace</span> <span class="o">||</span> <span class="s1">&#39;nconf&#39;</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">host</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">host</span> <span class="o">||</span> <span class="s1">&#39;localhost&#39;</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">port</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">port</span> <span class="o">||</span> <span class="mi">6379</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">ttl</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">ttl</span> <span class="o">||</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">cache</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Memory</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">redis</span> <span class="o">=</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">createClient</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">host</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h3>function get (key, callback)</h3>
<h4>@key {string} Key to retrieve for this instance.</h4>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Retrieves the value for the specified key (if any).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Redis</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">get</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span>
<span class="nx">result</span> <span class="o">=</span> <span class="p">{},</span>
<span class="nx">now</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">(),</span>
<span class="nx">mtime</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">mtimes</span><span class="p">[</span><span class="nx">key</span><span class="p">],</span>
<span class="nx">fullKey</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">namespace</span><span class="p">,</span> <span class="nx">key</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>If the key exists in the cache and the ttl is less than
the value set for this instance, return from the cache.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">mtime</span> <span class="o">&amp;&amp;</span> <span class="nx">now</span> <span class="o">-</span> <span class="nx">mtime</span> <span class="o">&lt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">ttl</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">key</span><span class="p">));</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Get the set of all children keys for the <code>key</code> supplied. If the value
to be returned is an Object, this list will not be empty.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">this</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">smembers</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="nx">fullKey</span><span class="p">,</span> <span class="s1">&#39;keys&#39;</span><span class="p">),</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">keys</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">function</span> <span class="nx">addValue</span> <span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">source</span><span class="p">),</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">result</span><span class="p">[</span><span class="nx">source</span><span class="p">]</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">keys</span> <span class="o">&amp;&amp;</span> <span class="nx">keys</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>If the value to be retrieved is an Object, recursively attempt
to get the value from redis. Here we use a recursive call to <code>this.get</code>
to support nested Object keys.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">async</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">keys</span><span class="p">,</span> <span class="nx">addValue</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">result</span><span class="p">);</span>
<span class="nx">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">result</span><span class="p">);</span>
<span class="p">})</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>If there are no keys, then the value to be retrieved is a literal
and we can simply return the value from redis directly. </p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">self</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">fullKey</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">result</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">result</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">result</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <h3>function set (key, value, callback)</h3>
<h4>@key {string} Key to set in this instance</h4>
<h4>@value {literal|Object} Value for the specified key</h4>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Sets the <code>value</code> for the specified <code>key</code> in this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Redis</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">set</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span>
<span class="nx">path</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">path</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span>
<span class="kd">function</span> <span class="nx">addKey</span> <span class="p">(</span><span class="nx">partial</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">index</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">partial</span><span class="p">),</span>
<span class="nx">base</span> <span class="o">=</span> <span class="p">[</span><span class="nx">self</span><span class="p">.</span><span class="nx">namespace</span><span class="p">].</span><span class="nx">concat</span><span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">index</span><span class="p">)),</span>
<span class="nx">parent</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">base</span><span class="p">.</span><span class="nx">concat</span><span class="p">([</span><span class="s1">&#39;keys&#39;</span><span class="p">]));</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">sadd</span><span class="p">(</span><span class="nx">parent</span><span class="p">,</span> <span class="nx">partial</span><span class="p">,</span> <span class="nx">next</span><span class="p">);</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>Iterate over the entire key path and add each key to the
parent key-set if it doesn't exist already.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">async</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">path</span><span class="p">,</span> <span class="nx">addKey</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">fullKey</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="nx">self</span><span class="p">.</span><span class="nx">namespace</span><span class="p">,</span> <span class="nx">key</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="k">typeof</span> <span class="nx">value</span> <span class="o">===</span> <span class="s1">&#39;object&#39;</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>If the value is an <code>Object</code> (and not an <code>Array</code>) then
nest into the value and set the child keys appropriately.
This is done for efficient lookup when setting Object keys.
(i.e. If you set and Object then wish to later retrieve only a
member of that Object, the entire Object need not be retrieved). </p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">self</span><span class="p">.</span><span class="nx">_setObject</span><span class="p">(</span><span class="nx">fullKey</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>If the value is a simple literal (or an <code>Array</code>) then JSON
stringify it and put it into Redis.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">value</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">fullKey</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <h3>function clear (key, callback)</h3>
<h4>@key {string} Key to remove from this instance</h4>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Removes the value for the specified <code>key</code> from this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Redis</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">clear</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span>
<span class="nx">result</span> <span class="o">=</span> <span class="p">{},</span>
<span class="nx">path</span> <span class="o">=</span> <span class="p">[</span><span class="k">this</span><span class="p">.</span><span class="nx">namespace</span><span class="p">].</span><span class="nx">concat</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">path</span><span class="p">(</span><span class="nx">key</span><span class="p">)),</span>
<span class="nx">last</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">pop</span><span class="p">(),</span>
<span class="nx">fullKey</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">namespace</span><span class="p">,</span> <span class="nx">key</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Clear the key from the cache for this instance</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">this</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">clear</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Remove the <code>key</code> from the parent set of keys.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">this</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">srem</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">path</span><span class="p">.</span><span class="nx">concat</span><span class="p">([</span><span class="s1">&#39;keys&#39;</span><span class="p">])),</span> <span class="nx">last</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>Remove the value from redis by iterating over the set of keys (if any)
and deleting each value. If no keys, then just delete the simple literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">self</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">smembers</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="nx">fullKey</span><span class="p">,</span> <span class="s1">&#39;keys&#39;</span><span class="p">),</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">keys</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">function</span> <span class="nx">removeValue</span> <span class="p">(</span><span class="nx">child</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Recursively call <code>self.clear</code> here to ensure we remove any
nested Objects completely from this instance.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">self</span><span class="p">.</span><span class="nx">clear</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">child</span><span class="p">),</span> <span class="nx">next</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">keys</span> <span class="o">&amp;&amp;</span> <span class="nx">keys</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>If there are child keys then iterate over them,
removing each child along the way.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">async</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">keys</span><span class="p">,</span> <span class="nx">removeValue</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>Otherwise if this is just a simple literal, then
simply remove it from Redis directly.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">self</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">del</span><span class="p">(</span><span class="nx">fullKey</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <h3>function save (value, callback)</h3>
<h4>@value {Object} Config object to set for this instance</h4>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Removes any existing configuration settings that may exist in this
instance and then adds all key-value pairs in <code>value</code>. </p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Redis</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">save</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="o">||</span> <span class="k">typeof</span> <span class="nx">value</span> <span class="o">!==</span> <span class="s1">&#39;object&#39;</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s1">&#39;`value` to be saved must be an object.&#39;</span><span class="p">));</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span>
<span class="nx">keys</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>Clear all existing keys associated with this instance.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">this</span><span class="p">.</span><span class="nx">reset</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>Iterate over the keys in the new value, setting each of them.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">async</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">keys</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">[</span><span class="nx">key</span><span class="p">],</span> <span class="nx">next</span><span class="p">);</span>
<span class="p">},</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">&#182;</a> </div> <h3>function load (callback)</h3>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Responds with an Object representing all keys associated in this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Redis</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">load</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span>
<span class="nx">result</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">smembers</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">namespace</span><span class="p">,</span> <span class="s1">&#39;keys&#39;</span><span class="p">),</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">keys</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">addValue</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">result</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="nx">next</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nx">async</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">keys</span><span class="p">,</span> <span class="nx">addValue</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">err</span> <span class="o">?</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">:</span> <span class="nx">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">result</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">&#182;</a> </div> <h3>function reset (callback)</h3>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Clears all keys associated with this instance.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Redis</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">reset</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
</pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">&#182;</a> </div> <p>Get the list of of top-level keys, then clear each of them</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">this</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">smembers</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">namespace</span><span class="p">,</span> <span class="s1">&#39;keys&#39;</span><span class="p">),</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">existing</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">async</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">existing</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">clear</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">next</span><span class="p">);</span>
<span class="p">},</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</a> </div> <h3>@private function _setObject (key, value, callback)</h3>
<h4>@key {string} Key to set in this instance</h4>
<h4>@value {Object} Value for the specified key</h4>
<h4>@callback {function} Continuation to respond to when complete.</h4>
<p>Internal helper function for setting all keys of a nested object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">Redis</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">_setObject</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span>
<span class="nx">keys</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
<span class="kd">function</span> <span class="nx">addValue</span> <span class="p">(</span><span class="nx">child</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p>Add the child key to the parent key-set, then set the value.
Recursively call <code>_setObject</code> in the event of nested Object(s).</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">self</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">sadd</span><span class="p">(</span><span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="s1">&#39;keys&#39;</span><span class="p">),</span> <span class="nx">child</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">fullKey</span> <span class="o">=</span> <span class="nx">nconf</span><span class="p">.</span><span class="nx">key</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">child</span><span class="p">),</span>
<span class="nx">childValue</span> <span class="o">=</span> <span class="nx">value</span><span class="p">[</span><span class="nx">child</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">childValue</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="k">typeof</span> <span class="nx">childValue</span> <span class="o">===</span> <span class="s1">&#39;object&#39;</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">_setObject</span><span class="p">(</span><span class="nx">fullKey</span><span class="p">,</span> <span class="nx">childValue</span><span class="p">,</span> <span class="nx">next</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="nx">childValue</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">childValue</span><span class="p">);</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">redis</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">fullKey</span><span class="p">,</span> <span class="nx">childValue</span><span class="p">,</span> <span class="nx">next</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>Iterate over the keys of the Object and set the appropriate values.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">async</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">keys</span><span class="p">,</span> <span class="nx">addValue</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">err</span> <span class="o">?</span> <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">:</span> <span class="nx">callback</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">};</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

177
lib/common.mjs Normal file
View File

@ -0,0 +1,177 @@
import fs from 'fs'
import Memory from './stores/memory.mjs'
//
// ### function validkeyvalue(key)
// #### @key {any} key to check
// Return string of key if valid string type key,
// otherwise transform into new key containing
// the error message
export function validkeyvalue(key) {
let type = typeof(key)
if (key && type !== 'string' && type !== 'number') {
return '__invalid_valuetype_of_' + type + '__'
}
return null
}
//
// ### function path (key)
// #### @key {string} The ':' delimited key to split
// Returns a fully-qualified path to a nested nconf key.
// If given null or undefined it should return an empty path.
// '' should still be respected as a path.
//
export function path(key, separator) {
let invalidType = validkeyvalue(key)
if (invalidType) {
return [invalidType]
}
separator = separator || ':'
return key == null
|| key === ''
? []
: key.toString().split(separator)
}
//
// ### function key (arguments)
// Returns a `:` joined string from the `arguments`.
//
export function key(...path) {
return path.map(function(item) {
return validkeyvalue(item) || ('' + item)
}).join(':')
}
//
// ### function key (arguments)
// Returns a joined string from the `arguments`,
// first argument is the join delimiter.
//
export function keyed(separator, ...path) {
return path.map(function(item) {
return validkeyvalue(item) || ('' + item)
}).join(separator)
}
// taken from isobject npm library
export function isObject(val) {
return val != null && typeof val === 'object' && Array.isArray(val) === false
}
// Return a new recursive deep instance of array of objects
// or values to make sure no original object ever get touched
export function mergeRecursiveArray(arr) {
return arr.map(function(item) {
if (isObject(item)) return mergeRecursive({}, item)
if (Array.isArray(item)) return mergeRecursiveArray(item)
return item
})
}
// Recursively merges the child into the parent.
export function mergeRecursive(parent, child) {
Object.keys(child).forEach(key => {
// Arrays will always overwrite for now
if (Array.isArray(child[key])) {
parent[key] = mergeRecursiveArray(child[key])
} else if (child[key] && typeof child[key] === 'object') {
// We don't wanna support cross merging between array and objects
// so we overwrite the old value (at least for now).
if (parent[key] && Array.isArray(parent[key])) {
parent[key] = mergeRecursive({}, child[key])
} else {
parent[key] = mergeRecursive(parent[key] || {}, child[key])
}
} else {
parent[key] = child[key]
}
})
return parent
}
//
// ### function merge (objs)
// #### @objs {Array} Array of object literals to merge
// Merges the specified `objs` together into a new object.
// This differs from the old logic as it does not affect or chagne
// any of the objects being merged.
//
export function merge(orgOut, orgObjs) {
let out = orgOut
let objs = orgObjs
if (objs === undefined) {
out = {}
objs = orgOut
}
if (!Array.isArray(objs)) {
throw new Error('merge called with non-array of objects')
}
for (let x = 0; x < objs.length; x++) {
out = mergeRecursive(out, objs[x])
}
return out
}
//
// ### function capitalize (str)
// #### @str {string} String to capitalize
// Capitalizes the specified `str` if string, otherwise
// returns the original object
//
export function capitalize(str) {
if (typeof(str) !== 'string' && typeof(str) !== 'number') {
return str
}
let out = str.toString()
return out && (out[0].toString()).toUpperCase() + out.slice(1)
}
//
// ### function parseValues (any)
// #### @any {string} String to parse as json or return as is
// try to parse `any` as a json stringified
//
export function parseValues(value) {
if (value === 'undefined') {
return undefined
}
try {
return JSON.parse(value)
} catch (ignore) {
return value
}
}
//
// ### 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
export function transform(map, fn) {
var pairs = Object.keys(map).map(function(key) {
var result = fn(key, map[key])
if (!result) {
return null
} else if (result.key) {
return result
}
throw new Error('Transform function passed to store returned an invalid format: ' + JSON.stringify(result))
})
return pairs
.filter(function(pair) {
return pair !== null
})
.reduce(function(accumulator, pair) {
accumulator[pair.key] = pair.value
return accumulator
}, {})
}

View File

@ -1,123 +0,0 @@
/*
* nconf.js: Top-level include for the nconf module
*
* (C) 2011, Charlie Robbins
*
*/
require.paths.unshift(__dirname);
var nconf = exports;
nconf.stores = require('nconf/stores');
//
// ### function use (type, options)
// #### @type {string} Type of the nconf store to use.
// #### @options {Object} Options for the store instance.
// Sets the active `nconf.store` to a new instance of the
// specified `type`.
//
nconf.use = function (type, options) {
nconf.store = new nconf.stores.create(type, options);
};
//
// ### function get (key, callback)
// #### @key {string} Key to retrieve for this instance.
// #### @callback {function} **Optional** Continuation to respond to when complete.
// Retrieves the value for the specified key (if any).
//
nconf.get = function (key, callback) {
return nconf.store.get(key, callback);
};
//
// ### function set (key, value, callback)
// #### @key {string} Key to set in this instance
// #### @value {literal|Object} Value for the specified key
// #### @callback {function} **Optional** Continuation to respond to when complete.
// Sets the `value` for the specified `key` in this instance.
//
nconf.set = function (key, value, callback) {
return nconf.store.set(key, value, callback);
};
//
// ### function clear (key, callback)
// #### @key {string} Key to remove from this instance
// #### @callback {function} **Optional** Continuation to respond to when complete.
// Removes the value for the specified `key` from this instance.
//
nconf.clear = function (key, callback) {
return nconf.store.clear(key, callback);
};
//
// ### function load (callback)
// #### @callback {function} Continuation to respond to when complete.
// Responds with an Object representing all keys associated in this instance.
//
nconf.load = function (callback) {
if (!nconf.store.load) {
var error = new Error('nconf store ' + nconf.store.type + ' has no load() method');
if (callback) {
return callback (error);
}
throw error;
}
return nconf.store.load(callback);
};
//
// ### function save (value, callback)
// #### @value {Object} **Optional** Config object to set for this instance
// #### @callback {function} Continuation to respond to when complete.
// Removes any existing configuration settings that may exist in this
// instance and then adds all key-value pairs in `value`.
//
nconf.save = function (value, callback) {
if (!callback) {
callback = value;
value = null;
}
if (!nconf.store.save) {
var error = new Error('nconf store ' + nconf.store.type + ' has no save() method');
if (callback) {
return callback (error);
}
throw error;
}
return nconf.store.save(value, callback);
};
//
// ### function reset (callback)
// #### @callback {function} **Optional** Continuation to respond to when complete.
// Clears all keys associated with this instance.
//
nconf.reset = function (callback) {
return nconf.store.reset(callback);
};
//
// ### function key (arguments)
// Returns a `:` joined string from the `arguments`.
//
nconf.key = function () {
return Array.prototype.slice.call(arguments).join(':');
};
//
// ### function path (key)
// #### @key {string} The ':' delimited key to split
// Returns a fully-qualified path to a nested nconf key.
//
nconf.path = function (key) {
return key.split(':');
};

181
lib/nconf.mjs Normal file
View File

@ -0,0 +1,181 @@
import fs from 'fs'
import { fileURLToPath } from 'url'
import path from 'path'
import * as common from './common.mjs'
import Literal from './stores/literal.mjs'
import Memory from './stores/memory.mjs'
import File from './stores/file.mjs'
import Env from './stores/env.mjs'
import Argv from './stores/argv.mjs'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const pckg = JSON.parse(fs.readFileSync(path.resolve(path.join(__dirname, '../package.json'))))
const AvailableStores = [
['memory', Memory],
['file', File],
['defaults', Literal],
['overrides', Literal],
['literal', Literal],
['env', Env],
['argv', Argv],
]
function Nconf(options) {
let opts = options || {}
this.sources = []
this.using = new Map()
this.version = pckg.version
this.init()
}
Nconf.prototype.key = common.key
Nconf.prototype.path = common.path
Nconf.prototype.init = function() {
AvailableStores.forEach((storeType) => {
let nameCapital = common.capitalize(storeType[0])
let nameLower = storeType[0].toLowerCase()
Object.defineProperty(this, nameCapital, {
value: storeType[1],
writable: false,
enumerable: true,
})
Object.defineProperty(this, nameLower, {
value: function(leName, leOpts) {
let name = leName
let options = leOpts || {}
if (typeof(name) !== 'string') {
name = nameLower
options = leName || {}
}
this.add(name, new this[nameCapital](options))
return this
},
writable: false,
enumerable: true,
})
})
}
Nconf.prototype.any = function(...items) {
let check = items
if (items.length === 1 && Array.isArray(items[0])) {
check = items[0]
}
for (let i = 0; i < check.length; i++) {
let found = this.get(check[i])
if (found) return found
}
return undefined
}
Nconf.prototype.get = function(key) {
let out = []
for (let i = 0; i < this.sources.length; i++) {
let found = this.sources[i].get(key)
if (found && !out.length && (Array.isArray(found) || typeof(found) !== 'object')) {
return found
}
if (found) {
out.push(found)
}
}
if (!out.length) return undefined
return common.merge(out.reverse())
}
Nconf.prototype.set = function(key, value) {
for (let i = 0; i < this.sources.length; i++) {
if (!this.sources[i].readOnly) {
if (this.sources[i].set(key, value))
return this
}
}
return false
}
Nconf.prototype.clear = function(key) {
for (let i = 0; i < this.sources.length; i++) {
this.sources[i].clear(key)
}
if (this.get(key)) {
return false
}
return this
}
Nconf.prototype.load = function() {
for (let i = 0; i < this.sources.length; i++) {
if (typeof(this.sources[i].load) === 'function') {
this.sources[i].load()
}
}
}
Nconf.prototype.save = function() {
for (let i = 0; i < this.sources.length; i++) {
if (typeof(this.sources[i].save) === 'function') {
this.sources[i].save()
}
}
}
Nconf.prototype.reset = function() {
throw new Error('Deprecated, create new instance instead')
}
Nconf.prototype.required = function(...items) {
let check = items
if (items.length === 1 && Array.isArray(items[0])) {
check = items[0]
}
let missing = []
for (let i = 0; i < check.length; i++) {
if (!this.get(check[i])) {
missing.push(check[i])
}
}
if (missing.length) {
throw new Error('Missing required keys: ' + missing.join(', '));
}
return this
}
Nconf.prototype.add = function(name, store) {
let oldStore = this.using.get(name)
if (typeof(store.load) === 'function') {
store.load()
}
if (oldStore) {
this.sources.splice(this.sources.indexOf(oldStore), 1)
this.using.delete(name)
}
this.using.set(name, store)
this.sources.push(store)
}
Nconf.prototype.use = function(name) {
return this.using.get(name)
}
Nconf.register = function(name, val) {
AvailableStores.push([name, val])
let nameCapital = common.capitalize(name)
Object.defineProperty(Nconf, nameCapital, {
value: val,
writable: false,
enumerable: true,
})
}
AvailableStores.forEach((storeType) => {
let nameCapital = common.capitalize(storeType[0])
Object.defineProperty(Nconf, nameCapital, {
value: storeType[1],
writable: false,
enumerable: true,
})
})
export default Nconf

View File

@ -1,27 +0,0 @@
/*
* stores.js: Top-level include for all nconf stores
*
* (C) 2011, Charlie Robbins
*
*/
var stores = exports;
function capitalize (str) {
return str && str[0].toUpperCase() + str.slice(1);
};
stores.Memory = require('nconf/stores/memory').Memory;
stores.File = require('nconf/stores/file').File;
stores.Redis = require('nconf/stores/redis').Redis;
//
// ### function create (type, options)
// #### @type {string} Type of the nconf store to use.
// #### @options {Object} Options for the store instance.
// Creates a store of the specified `type` using the
// specified `options`.
//
stores.create = function (type, options) {
return new stores[capitalize(type.toLowerCase())](options);
};

View File

@ -1,66 +0,0 @@
/*
* file.js: Simple file storage engine for nconf files
*
* (C) 2011, Charlie Robbins
*
*/
var fs = require('fs'),
util = require('util'),
Memory = require('./memory').Memory;
//
// ### function File (options)
// #### @options {Object} Options for this instance
// Constructor function for the File nconf store, a simple abstraction
// around the Memory store that can persist configuration to disk.
//
var File = exports.File = function (options) {
if (!options.file) {
throw new Error ('Missing required option `files`');
}
Memory.call(this, options);
this.file = options.file;
this.format = options.format || JSON;
};
// Inherit from the Memory store
util.inherits(File, Memory);
//
// ### function save (value, callback)
// #### @value {Object} _Ignored_ Left here for consistency
// #### @callback {function} Continuation to respond to when complete.
// Saves the current configuration object to disk at `this.file`
// using the format specified by `this.format`.
//
File.prototype.save = function (value, callback) {
if (!callback) {
callback = value;
value = null;
}
fs.writeFile(this.file, this.format.stringify(this.store), function (err) {
return err ? callback(err) : callback();
});
};
//
// ### function load (callback)
// #### @callback {function} Continuation to respond to when complete.
// Responds with an Object representing all keys associated in this instance.
//
File.prototype.load = function (callback) {
var self = this;
fs.readFile(this.file, function (err, data) {
if (err) {
return callback(err);
}
data = self.format.parse(data.toString());
self.store = data;
callback(null, self.store);
});
};

View File

@ -1,122 +0,0 @@
/*
* memory.js: Simple memory storage engine for nconf configuration(s)
*
* (C) 2011, Charlie Robbins
*
*/
var nconf = require('nconf');
//
// ### function Memory (options)
// #### @options {Object} Options for this instance
// Constructor function for the Memory nconf store which maintains
// a nested json structure based on key delimiters `:`.
//
// e.g. `my:nested:key` ==> `{ my: { nested: { key: } } }`
//
var Memory = exports.Memory = function (options) {
options = options || {};
this.store = {};
this.mtimes = {};
};
//
// ### function get (key)
// #### @key {string} Key to retrieve for this instance.
// Retrieves the value for the specified key (if any).
//
Memory.prototype.get = function (key) {
var target = this.store,
path = nconf.path(key);
//
// Scope into the object to get the appropriate nested context
//
while (path.length > 0) {
key = path.shift();
if (!target[key]) {
return;
}
target = target[key];
if (path.length === 0) {
return target;
}
}
};
//
// ### function set (key, value)
// #### @key {string} Key to set in this instance
// #### @value {literal|Object} Value for the specified key
// Sets the `value` for the specified `key` in this instance.
//
Memory.prototype.set = function (key, value) {
var target = this.store,
path = nconf.path(key);
//
// Update the `mtime` (modified time) of the key
//
this.mtimes[key] = Date.now();
//
// Scope into the object to get the appropriate nested context
//
while (path.length > 1) {
key = path.shift();
if (!target[key]) {
target[key] = {};
}
target = target[key];
}
// Set the specified value in the nested JSON structure
key = path.shift();
target[key] = value;
return true;
};
//
// ### function clear (key)
// #### @key {string} Key to remove from this instance
// Removes the value for the specified `key` from this instance.
//
Memory.prototype.clear = function (key) {
var target = this.store,
path = nconf.path(key);
//
// Remove the key from the set of `mtimes` (modified times)
//
delete this.mtimes[key];
//
// Scope into the object to get the appropriate nested context
//
while (path.length > 1) {
key = path.shift();
if (!target[key]) {
return;
}
target = target[key];
}
// Delete the key from the nested JSON structure
key = path.shift();
delete target[key];
return true;
};
//
// ### function reset (callback)
// Clears all keys associated with this instance.
//
Memory.prototype.reset = function () {
this.mtimes = {};
this.store = {};
return true;
}

View File

@ -1,338 +0,0 @@
/*
* redis.js: Redis storage engine for nconf configuration(s)
*
* (C) 2011, Charlie Robbins
*
*/
var async = require('async'),
redis = require('redis'),
nconf = require('nconf'),
Memory = require('./Memory').Memory;
//
// ### function Redis (options)
// #### @options {Object} Options for this instance
// Constructor function for the Redis nconf store which maintains
// a nested Redis key structure based on key delimiters `:`.
//
// e.g.
// my:nested:key, 'value'
// namespace:keys ==> ['my']
// namespace:nested:keys ==> ['key']
// namespace:nested:key ==> 'value'
//
var Redis = exports.Redis = function (options) {
options = options || {}
this.namespace = options.namespace || 'nconf';
this.host = options.host || 'localhost';
this.port = options.port || 6379;
this.ttl = options.ttl || 60 * 60 * 1000;
this.cache = new Memory();
this.redis = redis.createClient(options.port, options.host);
};
//
// ### function get (key, callback)
// #### @key {string} Key to retrieve for this instance.
// #### @callback {function} Continuation to respond to when complete.
// Retrieves the value for the specified key (if any).
//
Redis.prototype.get = function (key, callback) {
var self = this,
result = {},
now = Date.now(),
mtime = this.cache.mtimes[key],
fullKey = nconf.key(this.namespace, key);
//
// If the key exists in the cache and the ttl is less than
// the value set for this instance, return from the cache.
//
if (mtime && now - mtime < this.ttl) {
return callback(null, this.cache.get(key));
}
//
// Get the set of all children keys for the `key` supplied. If the value
// to be returned is an Object, this list will not be empty.
//
this.redis.smembers(nconf.key(fullKey, 'keys'), function (err, keys) {
function addValue (source, next) {
self.get(nconf.key(key, source), function (err, value) {
if (err) {
return next(err);
}
result[source] = value;
next();
});
}
if (keys && keys.length > 0) {
//
// If the value to be retrieved is an Object, recursively attempt
// to get the value from redis. Here we use a recursive call to `this.get`
// to support nested Object keys.
//
async.forEach(keys, addValue, function (err) {
if (err) {
return callback(err);
}
self.cache.set(key, result);
callback(null, result);
})
}
else {
//
// If there are no keys, then the value to be retrieved is a literal
// and we can simply return the value from redis directly.
//
self.redis.get(fullKey, function (err, value) {
if (err) {
return callback(err);
}
result = JSON.parse(value);
if (result) {
self.cache.set(key, result);
}
callback(null, result);
});
}
});
};
//
// ### function set (key, value, callback)
// #### @key {string} Key to set in this instance
// #### @value {literal|Object} Value for the specified key
// #### @callback {function} Continuation to respond to when complete.
// Sets the `value` for the specified `key` in this instance.
//
Redis.prototype.set = function (key, value, callback) {
var self = this,
path = nconf.path(key);
function addKey (partial, next) {
var index = path.indexOf(partial),
base = [self.namespace].concat(path.slice(0, index)),
parent = nconf.key.apply(null, base.concat(['keys']));
self.redis.sadd(parent, partial, next);
};
//
// Iterate over the entire key path and add each key to the
// parent key-set if it doesn't exist already.
//
async.forEach(path, addKey, function (err) {
if (err) {
return callback(err);
}
var fullKey = nconf.key(self.namespace, key);
if (!Array.isArray(value) && typeof value === 'object') {
//
// If the value is an `Object` (and not an `Array`) then
// nest into the value and set the child keys appropriately.
// This is done for efficient lookup when setting Object keys.
// (i.e. If you set and Object then wish to later retrieve only a
// member of that Object, the entire Object need not be retrieved).
//
self._setObject(fullKey, value, callback);
}
else {
//
// If the value is a simple literal (or an `Array`) then JSON
// stringify it and put it into Redis.
//
value = JSON.stringify(value);
self.cache.set(key, value);
self.redis.set(fullKey, value, callback);
}
});
};
//
// ### function clear (key, callback)
// #### @key {string} Key to remove from this instance
// #### @callback {function} Continuation to respond to when complete.
// Removes the value for the specified `key` from this instance.
//
Redis.prototype.clear = function (key, callback) {
var self = this,
result = {},
path = [this.namespace].concat(nconf.path(key)),
last = path.pop(),
fullKey = nconf.key(this.namespace, key);
//
// Clear the key from the cache for this instance
//
this.cache.clear(key);
//
// Remove the `key` from the parent set of keys.
//
this.redis.srem(nconf.key.apply(null, path.concat(['keys'])), last, function (err) {
//
// Remove the value from redis by iterating over the set of keys (if any)
// and deleting each value. If no keys, then just delete the simple literal.
//
self.redis.smembers(nconf.key(fullKey, 'keys'), function (err, keys) {
function removeValue (child, next) {
//
// Recursively call `self.clear` here to ensure we remove any
// nested Objects completely from this instance.
//
self.clear(nconf.key(key, child), next);
}
if (keys && keys.length > 0) {
//
// If there are child keys then iterate over them,
// removing each child along the way.
//
async.forEach(keys, removeValue, callback);
}
else {
//
// Otherwise if this is just a simple literal, then
// simply remove it from Redis directly.
//
self.redis.del(fullKey, callback);
}
});
});
};
//
// ### function save (value, callback)
// #### @value {Object} Config object to set for this instance
// #### @callback {function} Continuation to respond to when complete.
// Removes any existing configuration settings that may exist in this
// instance and then adds all key-value pairs in `value`.
//
Redis.prototype.save = function (value, callback) {
if (Array.isArray(value) || typeof value !== 'object') {
return callback(new Error('`value` to be saved must be an object.'));
}
var self = this,
keys = Object.keys(value);
//
// Clear all existing keys associated with this instance.
//
this.reset(function (err) {
if (err) {
return callback(err);
}
//
// Iterate over the keys in the new value, setting each of them.
//
async.forEach(keys, function (key, next) {
self.set(key, value[key], next);
}, callback);
});
};
//
// ### function load (callback)
// #### @callback {function} Continuation to respond to when complete.
// Responds with an Object representing all keys associated in this instance.
//
Redis.prototype.load = function (callback) {
var self = this,
result = {};
this.redis.smembers(nconf.key(this.namespace, 'keys'), function (err, keys) {
if (err) {
return callback(err);
}
function addValue (key, next) {
self.get(key, function (err, value) {
if (err) {
return next(err);
}
result[key] = value;
next();
});
}
async.forEach(keys, addValue, function (err) {
return err ? callback(err) : callback(null, result);
});
});
};
//
// ### function reset (callback)
// #### @callback {function} Continuation to respond to when complete.
// Clears all keys associated with this instance.
//
Redis.prototype.reset = function (callback) {
var self = this;
//
// Get the list of of top-level keys, then clear each of them
//
this.redis.smembers(nconf.key(this.namespace, 'keys'), function (err, existing) {
if (err) {
return callback(err);
}
async.forEach(existing, function (key, next) {
self.clear(key, next);
}, callback);
});
};
//
// ### @private function _setObject (key, value, callback)
// #### @key {string} Key to set in this instance
// #### @value {Object} Value for the specified key
// #### @callback {function} Continuation to respond to when complete.
// Internal helper function for setting all keys of a nested object.
//
Redis.prototype._setObject = function (key, value, callback) {
var self = this,
keys = Object.keys(value);
function addValue (child, next) {
//
// Add the child key to the parent key-set, then set the value.
// Recursively call `_setObject` in the event of nested Object(s).
//
self.redis.sadd(nconf.key(key, 'keys'), child, function (err) {
if (err) {
return next(err);
}
var fullKey = nconf.key(key, child),
childValue = value[child];
if (!Array.isArray(childValue) && typeof childValue === 'object') {
self._setObject(fullKey, childValue, next);
}
else {
childValue = JSON.stringify(childValue);
self.redis.set(fullKey, childValue, next);
}
});
}
//
// Iterate over the keys of the Object and set the appropriate values.
//
async.forEach(keys, addValue, function (err) {
return err ? callback(err) : callback();
});
};

72
lib/stores/argv.mjs Normal file
View File

@ -0,0 +1,72 @@
import util from 'util'
import Memory from './memory.mjs'
import * as common from '../common.mjs'
//
// ### function Argv (options)
// #### @options {Object} Options for this instance.
// Constructor function for the Argv nconf store, a simple abstraction
// around the Memory store that can read basic arguments.
//
const Argv = function(orgOpts) {
let options = orgOpts || {}
Memory.call(this, options)
this.readOnly = true
this.separator = options.separator || ''
this.lowerCase = options.lowerCase || false
this.parseValues = options.parseValues || false
this.transform = options.transform || false
this.prefix = options.prefix || '--'
this.useEqualsign = options.useEqualsign || false
if (!this.prefix) {
throw new Error('')
}
}
// Inherit from the Memory store
util.inherits(Argv, Memory)
//
// ### function load ()
// Loads the data passed in from `process.env` into this instance.
//
Argv.prototype.load = function () {
this.store = {}
let args = process.argv.slice(2)
this.readOnly = false
for (let i = 0; i < args.length; i++) {
if (args[i].startsWith(this.prefix)) {
let key = args[i].slice(this.prefix.length)
if (this.lowerCase) {
key = key.toLowerCase()
}
if (this.separator) {
key = common.key(...key.split(this.separator))
}
if (this.useEqualsign) {
let equalSignIndex = key.indexOf('=')
if (equalSignIndex > 0) {
this.set(key.slice(0, equalSignIndex), key.slice(equalSignIndex + 1))
} else {
this.set(key, true)
}
} else if (args[i + 1] && !args[i + 1].startsWith(this.prefix)) {
this.set(key, args[i + 1])
i++
} else {
this.set(key, true)
}
}
}
this.readOnly = true
return this.store
}
export default Argv

102
lib/stores/env.mjs Normal file
View File

@ -0,0 +1,102 @@
import util from 'util'
import Memory from './memory.mjs'
import * as common from '../common.mjs'
//
// ### function Env (options)
// #### @options {Object} Options for this instance.
// Constructor function for the Env nconf store, a simple abstraction
// around the Memory store that can read process environment variables.
//
const Env = function(orgOpts) {
let options = orgOpts || {}
if (Array.isArray(options)) {
options = { whitelist: options }
}
Memory.call(this, options)
this.readOnly = true
this.whitelist = options.whitelist || []
this.separator = options.separator || ''
this.lowerCase = options.lowerCase || false
this.parseValues = options.parseValues || false
this.transform = options.transform || false
if (!Array.isArray(this.whitelist)) {
throw new Error('Env parameter whitelist was not an array or contained non-string elements')
}
for (let i = 0; i < this.whitelist.length; i++) {
if (typeof(this.whitelist[i]) !== 'string') {
throw new Error('Env parameter whitelist was not an array or contained non-string elements')
}
this.whitelist[i] = this.whitelist[i].toLowerCase()
}
if (options.match) {
if (typeof(options.match) === 'string') {
options.match = new RegExp(options.match)
}
if (typeof(options.match.test) !== 'function') {
throw new Error('Env parameter match was not a valid RegExp')
}
this.match = options.match
}
}
// Inherit from the Memory store
util.inherits(Env, Memory)
//
// ### function load ()
// Loads the data passed in from `process.env` into this instance.
//
Env.prototype.load = function () {
let env = {}
if (this.lowerCase) {
Object.keys(process.env).forEach(function (key) {
env[key.toLowerCase()] = process.env[key]
})
} else {
env = process.env
}
if (this.transform) {
env = common.transform(env, this.transform)
}
this.readOnly = false
Object.keys(env).filter((key) => {
if (this.match && this.whitelist.length) {
return key.match(this.match) || this.whitelist.indexOf(key.toLowerCase()) !== -1
}
else if (this.match) {
return key.match(this.match)
}
else {
return !this.whitelist.length || this.whitelist.indexOf(key.toLowerCase()) !== -1
}
}).forEach((key) => {
var val = env[key]
if (this.parseValues) {
val = common.parseValues(val)
}
if (this.separator) {
this.set(common.key(...key.split(this.separator)), val)
}
else {
this.set(key, val)
}
})
this.readOnly = true
return this.store
}
export default Env

386
lib/stores/file.mjs Normal file
View File

@ -0,0 +1,386 @@
import fs from 'fs'
import path from 'path'
import util from 'util'
import crypto from 'crypto'
import Memory from './memory.mjs'
const fsPromise = fs.promises
//
// ### function File (options)
// #### @options {Object} Options for this instance
// Constructor function for the File nconf store, a simple abstraction
// around the Memory store that can persist configuration to disk.
//
const File = function (orgOpts) {
let options = orgOpts
if (typeof(options) === 'string') {
options = { file: options }
}
if (!options || !options.file) {
throw new Error('Missing required option `file`')
}
Memory.call(this, options)
this.file = options.file
// this.dir = options.dir || process.cwd()
this.format = options.format || JSON
this.secure = options.secure
// this.spacing = options.json_spacing || options.spacing || 2
if (this.secure) {
this.secure = typeof(this.secure === 'string')
? { secret: this.secure.toString() }
: this.secure
this.secure.alg = this.secure.alg || 'aes-256-ctr'
// if (this.secure.secretPath) {
// this.secure.secret = fs.readFileSync(this.secure.secretPath, 'utf8')
// }
if (!this.secure.secret) {
throw new Error('secure.secret option is required')
}
}
// if (options.search) {
// this.search(this.dir)
// }
}
// Inherit from the Memory store
util.inherits(File, Memory)
File.prototype.load = function () {
this.store = {}
let fileData
try {
fileData = fs.readFileSync(this.file, 'utf8')
}
catch (ex) {
throw new Error('Error opening ' + this.file + ': ' + ex.message)
}
// Deals with file that include BOM
if (fileData.charAt(0) === '\uFEFF') {
fileData = fileData.substr(1)
}
try {
this.store = this.parse(fileData)
}
catch (ex) {
throw new Error("Error parsing your configuration file: [" + this.file + ']: ' + ex.message)
}
return this.store
}
File.prototype.loadAsync = function () {
this.store = {}
return fsPromise.readFile(this.file, 'utf8')
.then(fileData => {
let data = fileData
if (data.charAt(0) === '\uFEFF') {
data = data.substr(1)
}
try {
this.store = this.parse(data)
} catch (err) {
return Promise.reject(new Error("Error parsing your configuration file: [" + this.file + ']: ' + err.message))
}
return this.store
}, err => {
return Promise.reject(new Error('Error opening ' + this.file + ': ' + err.message))
})
}
//
// ### function parse (contents)
// Returns a decrypted version of the contents IFF
// `this.secure` is enabled.
//
File.prototype.parse = function (contents) {
let parsed = this.format.parse(contents)
if (this.secure) {
parsed = Object.keys(parsed).reduce((acc, key) => {
let value = parsed[key]
if (!value.iv) {
throw new Error(`Encrypted file ${this.file} is outdated (encrypted without iv). Please re-encrypt your file.`)
}
let decipher = crypto.createDecipheriv(value.alg, this.secure.secret, Buffer.from(value.iv, 'hex'))
let plaintext = decipher.update(value.value, 'hex', 'utf8')
plaintext += decipher.final('utf8')
acc[key] = this.format.parse(plaintext)
return acc
}, {})
}
return parsed
}
//
// ### function save (path)
// #### @path {string} The path to the file where we save the configuration to
// Saves the current configuration object to disk at `this.file`
//
File.prototype.save = function (orgPath) {
let path = orgPath
if (!path) {
path = this.file
}
fs.writeFileSync(path, this.stringify())
return this
}
//
// ### function save (path)
// #### @path {string} The path to the file where we save the configuration to
// Saves the current configuration object to disk at `this.file`
//
File.prototype.saveAsync = function(orgPath) {
let path = orgPath
if (!path) {
path = this.file
}
return fsPromise.writeFile(path, this.stringify()).then(() => {
return this
})
}
//
// ### function stringify ()
// Returns an encrypted version of the contents IIF
// `this.secure` is enabled
//
File.prototype.stringify = function () {
let data = this.store
if (this.secure) {
data = Object.keys(data).reduce((acc, key) => {
let value = this.format.stringify(data[key])
let iv = crypto.randomBytes(16)
let cipher = crypto.createCipheriv(this.secure.alg, this.secure.secret, iv)
let ciphertext = cipher.update(value, 'utf8', 'hex')
ciphertext += cipher.final('hex')
acc[key] = { alg: this.secure.alg, value: ciphertext, iv: iv.toString('hex') }
return acc
}, {})
}
return this.format.stringify(data, null, this.spacing)
}
/*
//
// ### function save (value, callback)
// #### @value {Object} _Ignored_ Left here for consistency
// #### @callback {function} Continuation to respond to when complete.
// Saves the current configuration object to disk at `this.file`
// using the format specified by `this.format`.
//
File.prototype.save = function (value, callback) {
this.saveToFile(this.file, value, callback)
}
//
// ### function saveToFile (path, value, callback)
// #### @path {string} The path to the file where we save the configuration to
// #### @format {Object} Optional formatter, default behing the one of the store
// #### @callback {function} Continuation to respond to when complete.
// Saves the current configuration object to disk at `this.file`
// using the format specified by `this.format`.
//
File.prototype.saveToFile = function (path, format, callback) {
if (!callback) {
callback = format
format = this.format
}
fs.writeFile(path, this.stringify(format), callback)
}
//
// ### function saveSync (value, callback)
// Saves the current configuration object to disk at `this.file`
// using the format specified by `this.format` synchronously.
//
File.prototype.saveSync = function () {
fs.writeFileSync(this.file, this.stringify())
return this.store
}
//
// ### function load (callback)
// #### @callback {function} Continuation to respond to when complete.
// Responds with an Object representing all keys associated in this instance.
//
File.prototype.load = function (callback) {
let self = this
exists(self.file, function (exists) {
if (!exists) {
return callback(null, {})
}
//
// Else, the path exists, read it from disk
//
fs.readFile(self.file, function (err, data) {
if (err) {
return callback(err)
}
try {
// Deals with string that include BOM
let stringData = data.toString()
if (stringData.charAt(0) === '\uFEFF') {
stringData = stringData.substr(1)
}
self.store = self.parse(stringData)
}
catch (ex) {
return callback(new Error("Error parsing your configuration file: [" + self.file + ']: ' + ex.message))
}
callback(null, self.store)
})
})
}
//
// ### function loadSync (callback)
// Attempts to load the data stored in `this.file` synchronously
// and responds appropriately.
//
File.prototype.loadSync = function () {
if (!existsSync(this.file)) {
this.store = {}
return this.store
}
//
// Else, the path exists, read it from disk
//
try {
// Deals with file that include BOM
let fileData = fs.readFileSync(this.file, 'utf8')
if (fileData.charAt(0) === '\uFEFF') {
fileData = fileData.substr(1)
}
this.store = this.parse(fileData)
}
catch (ex) {
throw new Error("Error parsing your configuration file: [" + this.file + ']: ' + ex.message)
}
return this.store
}
//
// ### function search (base)
// #### @base {string} Base directory (or file) to begin searching for the target file.
// Attempts to find `this.file` by iteratively searching up the
// directory structure
//
File.prototype.search = function (base) {
let looking = true,
fullpath,
previous,
stats
base = base || process.cwd()
if (this.file[0] === '/') {
//
// If filename for this instance is a fully qualified path
// (i.e. it starts with a `'/'`) then check if it exists
//
try {
stats = fs.statSync(fs.realpathSync(this.file))
if (stats.isFile()) {
fullpath = this.file
looking = false
}
}
catch (ex) {
//
// Ignore errors
//
}
}
if (looking && base) {
//
// Attempt to stat the realpath located at `base`
// if the directory does not exist then return false.
//
try {
let stat = fs.statSync(fs.realpathSync(base))
looking = stat.isDirectory()
}
catch (ex) {
return false
}
}
while (looking) {
//
// Iteratively look up the directory structure from `base`
//
try {
stats = fs.statSync(fs.realpathSync(fullpath = path.join(base, this.file)))
looking = stats.isDirectory()
}
catch (ex) {
previous = base
base = path.dirname(base)
if (previous === base) {
//
// If we've reached the top of the directory structure then simply use
// the default file path.
//
try {
stats = fs.statSync(fs.realpathSync(fullpath = path.join(this.dir, this.file)))
if (stats.isDirectory()) {
fullpath = undefined
}
}
catch (ex) {
//
// Ignore errors
//
}
looking = false
}
}
}
//
// Set the file for this instance to the fullpath
// that we have found during the search. In the event that
// the search was unsuccessful use the original value for `this.file`.
//
this.file = fullpath || this.file
return fullpath
}
*/
export default File

15
lib/stores/literal.mjs Normal file
View File

@ -0,0 +1,15 @@
import { inherits } from 'util'
import Memory from './memory.mjs'
function Literal (options) {
Memory.call(this, options)
this.type = 'literal'
this.readOnly = true
this.store = options
}
// Inherit from Memory store.
inherits(Literal, Memory)
export default Literal

212
lib/stores/memory.mjs Normal file
View File

@ -0,0 +1,212 @@
import * as common from '../common.mjs'
//
// ### function Memory (options)
// #### @options {Object} Options for this instance
// Constructor function for the Memory nconf store which maintains
// a nested json structure based on key delimiters `:`.
//
// e.g. `my:nested:key` ==> `{ my: { nested: { key: } } }`
//
function Memory(orgOpts) {
let options = orgOpts || {}
this.type = 'memory'
this.store = {}
this.readOnly = options.readOnly || false
this.logicalSeparator = options.logicalSeparator || ':'
this.parseValues = options.parseValues || false
}
//
// ### function get (key)
// #### @key {string} Key to retrieve for this instance.
// Retrieves the value for the specified key (if any).
//
Memory.prototype.get = function (key) {
var target = this.store,
path = common.path(key, this.logicalSeparator)
//
// Scope into the object to get the appropriate nested context
//
while (path.length > 0) {
key = path.shift()
if (target && typeof target !== 'string' && target.hasOwnProperty(key)) {
target = target[key]
continue
}
return undefined
}
return target
}
//
// ### function set (key, value)
// #### @key {string} Key to set in this instance
// #### @value {literal|Object} Value for the specified key
// Sets the `value` for the specified `key` in this instance.
//
Memory.prototype.set = function (orgKey, orgValue) {
if (this.readOnly) {
return false
}
let key = orgKey
let value = orgValue
if (value === undefined && typeof(key) === 'object') {
key = null
value = orgKey
}
let target = this.store
let path = common.path(key, this.logicalSeparator)
if (path.length === 0) {
//
// Root must be an object
//
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return false
}
this.store = value
return true
}
key = path.shift()
//
// Scope into the object to get the appropriate nested context
//
while (path.length) {
if (!target[key]) {
target[key] = {}
}
target = target[key]
key = path.shift()
}
if (this.parseValues) {
value = common.parseValues(value)
}
if (value) {
if (Array.isArray(value)) {
value = common.mergeRecursiveArray(value)
} else if (typeof(value) === 'object') {
value = common.merge([value])
}
}
target[key] = value
return true
}
//
// ### function clear (key)
// #### @key {string} Key to remove from this instance
// Removes the value for the specified `key` from this instance.
//
Memory.prototype.clear = function (key) {
if (this.readOnly) {
return false
}
let target = this.store
let value = target
let path = common.path(key, this.logicalSeparator)
//
// Scope into the object to get the appropriate nested context
//
let i = 0
for (; i < path.length - 1; i++) {
key = path[i]
value = target[key]
if (typeof value !== 'function' && typeof value !== 'object') {
return false
}
target = value
}
// Delete the key from the nested JSON structure
key = path[i]
delete target[key]
return true
}
//
// ### function merge (key, value)
// #### @key {string} Key to merge the value into
// #### @value {literal|Object} Value to merge into the key
// Merges the properties in `value` into the existing object value
// at `key`.
//
Memory.prototype.merge = function (orgFullKey, orgValue) {
if (this.readOnly) {
return false
}
let fullKey = orgFullKey
let value = orgValue
// If fullkey is an object, do basic merge on root
if (typeof(fullKey) === 'object') {
this.store = common.merge(this.store, [fullKey])
return true
}
if (typeof(fullKey) === 'number') {
fullKey = fullKey.toString()
}
let target = this.store
let path = common.path(fullKey, this.logicalSeparator)
let key = path.shift()
//
// Scope into the object to get the appropriate nested context
//
while (path.length) {
if (!target[key]) {
target[key] = {}
}
target = target[key]
key = path.shift()
}
// Check if we actually need to do any merging. Sometimes a simple assign or "set"
// is all that is needed. This might be instances where the value is "null" (which
// would mean no merging is required) or if we're dealing with arrays on either side.
if (!value || typeof(value) !== 'object' || Array.isArray(value) || !target[key] || typeof(target[key]) !== 'object' || Array.isArray(target[key])) {
return this.set(fullKey, value)
}
target[key] = common.merge(target[key], [value])
return true
}
//
// ### function reset (callback)
// Clears all keys associated with this instance.
//
Memory.prototype.reset = function () {
if (this.readOnly) {
return false
}
this.store = {}
return true
}
//
// ### function loadSync
// Returns the store managed by this instance
//
Memory.prototype.loadSync = function () {
return this.store || {}
}
export default Memory

View File

@ -1,19 +1,42 @@
{
"name": "nconf",
"description": "A hybrid local / remote configuration storage library for node.js.",
"version": "0.1.0",
"author": "Charlie Robbins <charlie.robbins@gmail.com>",
"name": "nconf-lite",
"description": "Zero dependency hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging.",
"version": "2.1.0",
"author": "Jonatan Nilsson <jonatan@nilsson.is>",
"repository": {
"type": "git",
"url": "http://github.com/indexzero/nconf.git"
"url": "http://github.com/nfp-projects/nconf-lite.git"
},
"keywords": ["configuration", "key value store", "redis"],
"dependencies": {
"async": ">= 0.1.8",
"redis": ">= 0.5.9",
"vows": ">= 0.5.8"
"keywords": [
"configuration",
"key value store",
"plugabble"
],
"watch": {
"test": {
"patterns": [
"{lib,test}/*"
],
"extensions": "js,mjs",
"quiet": true,
"inherit": true
}
},
"main": "./lib/nconf",
"scripts": { "test": "vows test/*-test.js --spec" },
"engines": { "node": ">= 0.4.5" }
"dependencies": {},
"devDependencies": {
"eltro": "^1.0.2"
},
"main": "./lib/nconf.mjs",
"scripts": {
"test": "eltro test/**/*.test.mjs -r dot",
"test:watch": "npm-watch test",
"lint": "eslint ."
},
"files": [
"lib"
],
"engines": {
"node": ">= 13.0.0"
},
"license": "MIT"
}

258
test/common.test.mjs Normal file
View File

@ -0,0 +1,258 @@
import { Eltro as t, assert} from 'eltro'
import * as common from '../lib/common.mjs'
t.describe('#validkeyvalue', function() {
t.test('should return key if valid key', function() {
assert.strictEqual(common.validkeyvalue('asdf'), null)
assert.strictEqual(common.validkeyvalue(''), null)
assert.strictEqual(common.validkeyvalue(), null)
assert.strictEqual(common.validkeyvalue(null), null)
assert.strictEqual(common.validkeyvalue(undefined), null)
})
t.test('should return invalid valuetype in result', function() {
assert.strictEqual(common.validkeyvalue([]), '__invalid_valuetype_of_object__')
assert.strictEqual(common.validkeyvalue({}), '__invalid_valuetype_of_object__')
assert.strictEqual(common.validkeyvalue([]), '__invalid_valuetype_of_object__')
assert.strictEqual(common.validkeyvalue({}), '__invalid_valuetype_of_object__')
assert.strictEqual(common.validkeyvalue(() => {}), '__invalid_valuetype_of_function__')
assert.strictEqual(common.validkeyvalue(function() {}), '__invalid_valuetype_of_function__')
})
})
t.describe('#path()', function() {
t.test('it should support normal operation', function() {
assert.deepStrictEqual(common.path('a:b:c'), ['a','b','c'])
assert.deepStrictEqual(common.path('a'), ['a'])
})
t.test('it should support different separator', function() {
assert.deepStrictEqual(common.path('a:b:c', '__'), ['a:b:c'])
assert.deepStrictEqual(common.path('a__b__c', '__'), ['a','b','c'])
assert.deepStrictEqual(common.path('a', '__'), ['a'])
})
t.test('it should work with non-string keys', function() {
assert.deepStrictEqual(common.path(1, '__'), ['1'])
assert.deepStrictEqual(common.path(4.3, '__'), ['4.3'])
})
t.test('it should return invalid value on non-supported keys', function() {
assert.deepStrictEqual(common.path([], '__'), ['__invalid_valuetype_of_object__'])
assert.strictEqual(common.path([], '__').length, 1)
assert.deepStrictEqual(common.path({}, '__'), ['__invalid_valuetype_of_object__'])
assert.strictEqual(common.path({}, '__').length, 1)
assert.deepStrictEqual(common.path([]), ['__invalid_valuetype_of_object__'])
assert.strictEqual(common.path([]).length, 1)
assert.deepStrictEqual(common.path({}), ['__invalid_valuetype_of_object__'])
assert.strictEqual(common.path({}).length, 1)
assert.deepStrictEqual(common.path(() => {}), ['__invalid_valuetype_of_function__'])
assert.strictEqual(common.path(() => {}).length, 1)
assert.deepStrictEqual(common.path(function() {}), ['__invalid_valuetype_of_function__'])
assert.strictEqual(common.path(function() {}).length, 1)
})
t.test('it should support empty values and return empty path', function() {
assert.deepStrictEqual(common.path(null, '__'), [])
assert.strictEqual(common.path(null, '__').length, 0)
assert.deepStrictEqual(common.path(undefined, '__'), [])
assert.strictEqual(common.path(undefined, '__').length, 0)
assert.deepStrictEqual(common.path('', '__'), [])
assert.strictEqual(common.path('', '__').length, 0)
assert.deepStrictEqual(common.path(null), [])
assert.strictEqual(common.path(null).length, 0)
assert.deepStrictEqual(common.path(undefined), [])
assert.strictEqual(common.path(undefined).length, 0)
assert.deepStrictEqual(common.path(''), [])
assert.strictEqual(common.path('').length, 0)
assert.deepStrictEqual(common.path(), [])
assert.strictEqual(common.path().length, 0)
})
})
t.describe('#key()', function() {
t.test('it should work with common values', function() {
assert.strictEqual(common.key('a'), 'a')
assert.strictEqual(common.key('a', 'b'), 'a:b')
assert.strictEqual(common.key('a', 'b', 'c'), 'a:b:c')
assert.strictEqual(common.key(123), '123')
assert.strictEqual(common.key(5.4), '5.4')
assert.strictEqual(common.key('a', 123, 'b'), 'a:123:b')
assert.strictEqual(common.key('a', 5.4, 'b'), 'a:5.4:b')
assert.strictEqual(common.key('a', 123, 456), 'a:123:456')
assert.strictEqual(common.key('a', 5.4, 456), 'a:5.4:456')
})
t.test('it should text replace invalid keys with the invalid value string', function() {
assert.strictEqual(common.key([]), '__invalid_valuetype_of_object__')
assert.strictEqual(common.key({}), '__invalid_valuetype_of_object__')
assert.strictEqual(common.key([]), '__invalid_valuetype_of_object__')
assert.strictEqual(common.key({}), '__invalid_valuetype_of_object__')
assert.strictEqual(common.key(() => {}), '__invalid_valuetype_of_function__')
assert.strictEqual(common.key(function() {}), '__invalid_valuetype_of_function__')
assert.strictEqual(common.key('a', [], 'b'), 'a:__invalid_valuetype_of_object__:b')
assert.strictEqual(common.key('a', {}, 'b'), 'a:__invalid_valuetype_of_object__:b')
assert.strictEqual(common.key('a', [], 'b'), 'a:__invalid_valuetype_of_object__:b')
assert.strictEqual(common.key('a', {}, 'b'), 'a:__invalid_valuetype_of_object__:b')
assert.strictEqual(common.key('a', () => {}, 'b'), 'a:__invalid_valuetype_of_function__:b')
assert.strictEqual(common.key('a', function() {}, 'b'), 'a:__invalid_valuetype_of_function__:b')
})
})
t.describe('#keyed()', function() {
t.test('it should work with common values', function() {
assert.strictEqual(common.keyed('__', 'a'), 'a')
assert.strictEqual(common.keyed('__', 'a', 'b'), 'a__b')
assert.strictEqual(common.keyed('__', 'a', 'b', 'c'), 'a__b__c')
assert.strictEqual(common.keyed('__', 123), '123')
assert.strictEqual(common.keyed('__', 5.4), '5.4')
assert.strictEqual(common.keyed('__', 'a', 123, 'b'), 'a__123__b')
assert.strictEqual(common.keyed('__', 'a', 5.4, 'b'), 'a__5.4__b')
assert.strictEqual(common.keyed('__', 'a', 123, 456), 'a__123__456')
assert.strictEqual(common.keyed('__', 'a', 5.4, 456), 'a__5.4__456')
})
t.test('it should text replace invalid keys with the invalid value string', function() {
assert.strictEqual(common.keyed('__', []), '__invalid_valuetype_of_object__')
assert.strictEqual(common.keyed('__', {}), '__invalid_valuetype_of_object__')
assert.strictEqual(common.keyed('__', []), '__invalid_valuetype_of_object__')
assert.strictEqual(common.keyed('__', {}), '__invalid_valuetype_of_object__')
assert.strictEqual(common.keyed('__', () => {}), '__invalid_valuetype_of_function__')
assert.strictEqual(common.keyed('__', function() {}), '__invalid_valuetype_of_function__')
assert.strictEqual(common.keyed('__', 'a', [], 'b'), 'a____invalid_valuetype_of_object____b')
assert.strictEqual(common.keyed('__', 'a', {}, 'b'), 'a____invalid_valuetype_of_object____b')
assert.strictEqual(common.keyed('__', 'a', [], 'b'), 'a____invalid_valuetype_of_object____b')
assert.strictEqual(common.keyed('__', 'a', {}, 'b'), 'a____invalid_valuetype_of_object____b')
assert.strictEqual(common.keyed('__', 'a', () => {}, 'b'), 'a____invalid_valuetype_of_function____b')
assert.strictEqual(common.keyed('__', 'a', function() {}, 'b'), 'a____invalid_valuetype_of_function____b')
})
})
t.describe('#merge()', function() {
t.test('should throw if not sent an array', function() {
assert.throws(function() { common.merge({}) })
assert.throws(function() { common.merge('asdf') })
assert.throws(function() { common.merge(12412) })
assert.throws(function() { common.merge(null) })
assert.throws(function() { common.merge(undefined) })
assert.throws(function() { common.merge() })
})
t.test('it should be able to merge properly', function() {
// Test individual check and then re-check that the original are untouched
let fn = function() { return true }
let a = null
let b = null
let c = null
a = { a: 1 }
b = { b: 2 }
assert.deepStrictEqual(common.merge([a, b]), { a: 1, b: 2 })
assert.deepStrictEqual(a, { a: 1 })
assert.deepStrictEqual(b, { b: 2 })
a = { a: 1 }
b = { b: 2 }
c = { a: 3 }
assert.deepStrictEqual(common.merge([a, b, c]), { a: 3, b: 2 })
assert.deepStrictEqual(a, { a: 1 })
assert.deepStrictEqual(b, { b: 2 })
assert.deepStrictEqual(c, { a: 3 })
a = { a: [1, 2] }
b = { a: [2, 3] }
assert.deepStrictEqual(common.merge([a, b]), { a: [2, 3] })
assert.deepStrictEqual(b, { a: [2, 3] })
assert.deepStrictEqual(a, { a: [1, 2] })
a = { a: [1, 2] }
b = { a: [2, [3, 4]] }
assert.deepStrictEqual(common.merge([a, b]), { a: [2, [3, 4]] })
assert.deepStrictEqual(a, { a: [1, 2] })
assert.deepStrictEqual(b, { a: [2, [3, 4]] })
a = { a: fn }
b = { b: 2 }
assert.deepStrictEqual(common.merge([a, b]), { a: fn, b: 2 })
assert.deepStrictEqual(a, { a: fn })
assert.deepStrictEqual(b, { b: 2 })
a = { a: fn }
b = { b: 2 }
c = { a: 3 }
assert.deepStrictEqual(common.merge([a, b, c]), { a: 3, b: 2 })
assert.deepStrictEqual(a, { a: fn })
assert.deepStrictEqual(b, { b: 2 })
assert.deepStrictEqual(c, { a: 3 })
a = { apples: true, bananas: true, foo: { bar: "boo" }, candy: { something: "file1", something1: true, something2: true, something5: { first: 1, second: 2 } }, unicorn: { exists: true }}
b = { candy: { something: "file2", something3: true, something4: true }, dates: true, elderberries: true, unicorn: null }
assert.deepStrictEqual(common.merge([a, b]), { apples: true, bananas: true, foo: { bar: "boo" }, candy: { something: "file2", something1: true, something2: true, something3: true, something4: true, something5: { first: 1, second: 2 } }, dates: true, elderberries: true, unicorn: null })
assert.deepStrictEqual(a, { apples: true, bananas: true, foo: { bar: "boo" }, candy: { something: "file1", something1: true, something2: true, something5: { first: 1, second: 2 } }, unicorn: { exists: true }})
assert.deepStrictEqual(b, { candy: { something: "file2", something3: true, something4: true }, dates: true, elderberries: true, unicorn: null })
// weird behavior from old merge but I have no better idea to turn arrays
// into object so this is "good enough" for now
a = { a: 1 }
b = { a: 2 }
c = ['test']
assert.deepStrictEqual(common.merge([a, b, c]), { '0': 'test', a: 2 })
assert.deepStrictEqual(a, { a: 1 })
assert.deepStrictEqual(b, { a: 2 })
assert.deepStrictEqual(c, ['test'])
})
t.test('it should support edge cases properly', function() {
let a = { a: { b: 1 } }
let b = { a: ['test'] }
let out = common.merge([a, b])
assert.deepStrictEqual(out, { a: ['test'] })
b = { a: { b: 1 } }
out = common.merge(out, [b])
assert.deepStrictEqual(out, { a: { b: 1 } })
})
})
t.describe('#capitalize()', function() {
t.test('should return original if not string', function() {
const assertObject = {}
const assertArray = []
assert.strictEqual(common.capitalize(assertObject), assertObject)
assert.strictEqual(common.capitalize(assertArray), assertArray)
assert.strictEqual(common.capitalize(null), null)
assert.strictEqual(common.capitalize(undefined), undefined)
assert.strictEqual(common.capitalize(), undefined)
})
t.test('should adapt value to string if value type', function() {
assert.strictEqual(common.capitalize(12412), '12412')
assert.strictEqual(common.capitalize(123.4), '123.4')
})
t.test('should otherwise capitalize', function() {
assert.strictEqual(common.capitalize('asdf'), 'Asdf')
assert.strictEqual(common.capitalize('test test'), 'Test test')
assert.strictEqual(common.capitalize('FOO'), 'FOO')
assert.strictEqual(common.capitalize('f'), 'F')
assert.strictEqual(common.capitalize('F'), 'F')
assert.strictEqual(common.capitalize(''), '')
})
})
t.describe('#parseValues()', function() {
t.test('should special handle undefined', function() {
assert.strictEqual(common.parseValues('undefined'), undefined)
})
t.test('should normally json parse string', function() {
assert.strictEqual(common.parseValues('null'), null)
assert.deepStrictEqual(common.parseValues('{"a": 1}'), { a: 1 })
assert.deepStrictEqual(common.parseValues('["a", 1]'), [ 'a', 1 ])
assert.strictEqual(common.parseValues('123'), 123)
assert.strictEqual(common.parseValues('"{\\"a\\": 1}"'), '{"a": 1}')
})
t.test('should otherwise return original string if errors are found', function() {
assert.strictEqual(common.parseValues('anull'), 'anull')
assert.deepStrictEqual(common.parseValues('a{"a": 1}'), 'a{"a": 1}')
assert.deepStrictEqual(common.parseValues('a["a", 1]'), 'a["a", 1]')
assert.strictEqual(common.parseValues('a123'), 'a123')
assert.strictEqual(common.parseValues('a"{\\"a\\": 1}"'), 'a"{\\"a\\": 1}"')
})
})

View File

@ -1,56 +0,0 @@
/*
* file-store-test.js: Tests for the nconf File store.
*
* (C) 2011, Charlie Robbins
*
*/
require.paths.unshift(require('path').join(__dirname, '..', 'lib'));
var fs = require('fs'),
path = require('path'),
vows = require('vows'),
assert = require('assert'),
nconf = require('nconf'),
data = require('./fixtures/data').data,
store;
vows.describe('nconf/stores/file').addBatch({
"When using the nconf file store": {
topic: function () {
var filePath = path.join(__dirname, 'fixtures', 'store.json');
fs.writeFileSync(filePath, JSON.stringify(data));
store = new nconf.stores.File({ file: filePath });
return null;
},
"the load() method": {
topic: function () {
store.load(this.callback);
},
"should load the data correctly": function (err, data) {
assert.isNull(err);
assert.deepEqual(data, store.store);
}
}
}
}).addBatch({
"When using the nconf file store": {
"the set() method": {
"should respond with true": function () {
assert.isTrue(store.set('foo:bar:bazz', 'buzz'));
}
},
"the get() method": {
"should respond with the correct value": function () {
assert.equal(store.get('foo:bar:bazz'), 'buzz');
}
},
"the clear() method": {
"should respond with the true": function () {
assert.equal(store.get('foo:bar:bazz'), 'buzz');
assert.isTrue(store.clear('foo:bar:bazz'));
assert.isTrue(typeof store.get('foo:bar:bazz') === 'undefined');
}
}
}
}).export(module);

19
test/fixtures/bom.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"I've seen things": {
"like": [
"carrots",
"handbags",
"cheese",
"toilets",
"russians",
"planets",
"hampsters",
"weddings",
"poets",
"stalin",
"kuala lumpur"
]
},
"host": "weebls-stuff.com",
"port": 78304
}

19
test/fixtures/complete.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"I've seen things": {
"like": [
"carrots",
"handbags",
"cheese",
"toilets",
"russians",
"planets",
"hampsters",
"weddings",
"poets",
"stalin",
"kuala lumpur"
]
},
"host": "weebls-stuff.com",
"port": 78304
}

View File

@ -1,12 +1,6 @@
/*
* data.js: Simple data fixture for configuration test.
*
* (C) 2011, Charlie Robbins
*
*/
exports.data = {
literal: 'bazz',
export const data = {
isNull: null,
literal: 'bazz',
arr: ['one', 2, true, { value: 'foo' }],
obj: {
host: 'localhost',
@ -17,4 +11,13 @@ exports.data = {
password: 'password'
}
}
}
};
export const merge = {
prop1: 1,
prop2: [1, 2, 3],
prop3: {
foo: 'bar',
bar: 'foo'
}
};

5
test/fixtures/hierarchy/global.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"title": "My generic title",
"color": "red",
"movie": "Kill Bill"
}

4
test/fixtures/hierarchy/user.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"title": "My specific title",
"color": "green"
}

3
test/fixtures/malformed.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"literal": "bazz",
}

19
test/fixtures/merge/file1.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"apples": true,
"bananas": true,
"foo": {
"bar": "boo"
},
"candy": {
"something": "file1",
"something1": true,
"something2": true,
"something5": {
"first": 1,
"second": 2
}
},
"unicorn": {
"exists": true
}
}

10
test/fixtures/merge/file2.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
"candy": {
"something": "file2",
"something3": true,
"something4": true
},
"dates": true,
"elderberries": true,
"unicorn": null
}

9
test/fixtures/merge/file3.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
"candy": {
"something": "much better something for you",
"something18": "completely unique",
"something5": {
"second": 99
}
}
}

19
test/fixtures/no-bom.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"I've seen things": {
"like": [
"carrots",
"handbags",
"cheese",
"toilets",
"russians",
"planets",
"hampsters",
"weddings",
"poets",
"stalin",
"kuala lumpur"
]
},
"host": "weebls-stuff.com",
"port": 78304
}

22
test/fixtures/secure-iv.json vendored Normal file
View File

@ -0,0 +1,22 @@
{
"isNull": {
"alg": "aes-256-ctr",
"value": "16f39325",
"iv": "49e7803a2a5ef98c7a51a8902b76dd10"
},
"literal": {
"alg": "aes-256-ctr",
"value": "647965c22605",
"iv": "b654e01aed262f37d0acf200be193985"
},
"arr": {
"alg": "aes-256-ctr",
"value": "70c6d3b2ec3820e4d4fa3d7834fcf7fd51190a9e580944583ca7b30f42d230b7f271e72287f6c2ab4624685c779936aa2ed19b90",
"iv": "b5263665331158c2165fe623a895870f"
},
"obj": {
"alg": "aes-256-ctr",
"value": "521f1995698896d2fe7d76d16bec9e86b9b5b25bcfae3a4f3c52ad6f0425c3fd059793b9dec7927c616f4c4c57f2b9ee833f8c865d9aa42bbb37203763703755a0c79afd13f8c0e96e9ac47f490a12105583e31ff628104e6b216265b849cdf6642eb8a4b5bd6f532339a5f5737bd6a7ae6e7bb22148cbcfa549802336cb1322fb701151b25b5863c5c6d5047875aed9806350ae0e292c259e82d5a561eb672402d20230a0c3107ff2b1e6259ccb1bbbe7a25ce965ce56cb32f679",
"iv": "355f307363d69ed58345ae395744f5f0"
}
}

18
test/fixtures/secure.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"isNull": {
"alg": "aes-256-ctr",
"value": "af07fbcf"
},
"literal": {
"alg": "aes-256-ctr",
"value": "e310f6d94f13"
},
"arr": {
"alg": "aes-256-ctr",
"value": "9a78b783175e69bb8f3458042b1c098d8ed9613410fac185b3735099224f8fe4ece0f0da8decfddbbf0eab3b7c391c47772b5441"
},
"obj": {
"alg": "aes-256-ctr",
"value": "ba78b783175968add93a680429424ae4cf957d2916ebcfa399730bb17200ddb0ecacb183c1b1ebcd950ced76726964062e74643c995c47372bfb1311bee8f65bbeb5a1d9426537a6d83635220ec7934e1d7cc187f7218cd4afadfa2f107fb42c232d80d95c160ee704fa8e922998b0b3e47ec579dd0baef7cae6d7dbaa203d732adb5cff22b80d810d7191237999cd8dc528d8f2201ae128a9f9e2df96d1a816aa73e3e6b8e6246cd98b454e453b36f43f9117cb4af8fa85429a92"
}
}

28
test/fixtures/store.json vendored Normal file
View File

@ -0,0 +1,28 @@
{
"isNull": null,
"literal": "bazz",
"arr": [
"one",
2,
true,
{
"value": "foo"
}
],
"obj": {
"host": "localhost",
"port": 5984,
"array": [
"one",
2,
true,
{
"foo": "bar"
}
],
"auth": {
"username": "admin",
"password": "password"
}
}
}

64
test/helpers.mjs Normal file
View File

@ -0,0 +1,64 @@
import { assert } from 'eltro'
import fs from 'fs'
import path from 'path'
import { exec as ex } from 'child_process'
import { fileURLToPath } from 'url'
import Nconf from '../lib/nconf.mjs'
let __dirname = path.dirname(fileURLToPath(import.meta.url))
export function assertMerged(err, merged) {
merged = merged instanceof Nconf
? merged.store.store
: merged;
assert.strictEqual(err, null)
assert.strictEqual(typeof(merged), 'object')
assert.ok(merged.apples)
assert.ok(merged.bananas)
assert.strictEqual(typeof(merged.candy), 'object')
assert.ok(merged.candy.something1)
assert.ok(merged.candy.something2)
assert.ok(merged.candy.something3)
assert.ok(merged.candy.something4)
assert.ok(merged.dates)
assert.ok(merged.elderberries)
};
// copy a file
export function cp(from, to) {
return new Promise(function(res, rej) {
fs.readFile(from, function (err, data) {
if (err) return rej(err);
fs.writeFile(to, data, function(err, data) {
if (err) return rej(err)
res(data)
});
});
})
};
/*export function exec(script, prefix = 'node') {
let command = `${prefix} ${script}`
return new Promise(function(res, rej) {
ex(command,
function (err, stdout, stderr) {
if (err) {
err.stdout = stdout
err.stderr = stderr
return rej(err)
}
res({
stdout,
stderr,
})
}
)
})
}*/
export function fixture(file) {
return path.resolve(path.join(__dirname, 'fixtures', file));
};

56
test/hierarchy.test.mjs Normal file
View File

@ -0,0 +1,56 @@
import { Eltro as t, assert} from 'eltro'
import * as helpers from './helpers.mjs'
import Nconf from '../lib/nconf.mjs'
var globalConfig = helpers.fixture('hierarchy/global.json')
var userConfig = helpers.fixture('hierarchy/user.json')
var file3 = helpers.fixture('merge/file3.json')
t.test('configured with two file stores should work', function() {
let nconf = new Nconf()
nconf.file('user', {type: 'file', file: userConfig})
nconf.file('global', {type: 'file', file: globalConfig})
nconf.load()
assert.strictEqual(nconf.get('title'), 'My specific title')
assert.strictEqual(nconf.get('color'), 'green')
assert.strictEqual(nconf.get('movie'), 'Kill Bill')
})
t.test('configured with two file stores with just filenames should work', function() {
let nconf = new Nconf()
nconf.file('user', userConfig)
nconf.file('global', globalConfig)
nconf.load()
assert.strictEqual(nconf.get('title'), 'My specific title')
assert.strictEqual(nconf.get('color'), 'green')
assert.strictEqual(nconf.get('movie'), 'Kill Bill')
})
t.test('configured with .file(), .defaults() should deep merge objects correctly', async function() {
let nconf = new Nconf()
.file('localOverrides', file3)
.defaults({
"candy": {
"something": "a nice default",
"something1": true,
"something2": true,
"something5": {
"first": 1,
"second": 2
}
}
})
assert.deepStrictEqual(nconf.get('candy'), {
something: 'much better something for you',
something1: true,
something2: true,
something18: 'completely unique',
something5: {
first: 1,
second: 99
}
})
})

View File

@ -1,35 +0,0 @@
/*
* memory-store-test.js: Tests for the nconf Memory store.
*
* (C) 2011, Charlie Robbins
*
*/
require.paths.unshift(require('path').join(__dirname, '..', 'lib'));
var vows = require('vows'),
assert = require('assert'),
nconf = require('nconf');
vows.describe('nconf/stores/memory').addBatch({
"When using the nconf memory store": {
topic: new nconf.stores.Memory(),
"the set() method": {
"should respond with true": function (store) {
assert.isTrue(store.set('foo:bar:bazz', 'buzz'));
}
},
"the get() method": {
"should respond with the correct value": function (store) {
assert.equal(store.get('foo:bar:bazz'), 'buzz');
}
},
"the clear() method": {
"should respond with the true": function (store) {
assert.equal(store.get('foo:bar:bazz'), 'buzz');
assert.isTrue(store.clear('foo:bar:bazz'));
assert.isTrue(typeof store.get('foo:bar:bazz') === 'undefined');
}
}
}
}).export(module);

View File

@ -1,93 +0,0 @@
/*
* file-store-test.js: Tests for the nconf File store.
*
* (C) 2011, Charlie Robbins
*
*/
require.paths.unshift(require('path').join(__dirname, '..', 'lib'));
var fs = require('fs'),
path = require('path'),
vows = require('vows'),
assert = require('assert'),
nconf = require('nconf'),
data = require('./fixtures/data').data;
vows.describe('nconf').addBatch({
"When using the nconf": {
"should have the correct methods set": function () {
assert.isFunction(nconf.key);
assert.isFunction(nconf.path);
assert.isFunction(nconf.use);
assert.isFunction(nconf.get);
assert.isFunction(nconf.set);
assert.isFunction(nconf.clear);
assert.isFunction(nconf.load);
assert.isFunction(nconf.save);
assert.isFunction(nconf.reset);
},
"the use() method": {
"should instaniate the correct store": function () {
nconf.use('memory');
assert.instanceOf(nconf.store, nconf.stores.Memory);
}
}
}
}).addBatch({
"When using the nconf": {
"with the memory store": {
"the set() method": {
"should respond with true": function () {
assert.isTrue(nconf.set('foo:bar:bazz', 'buzz'));
}
},
"the get() method": {
"should respond with the correct value": function () {
assert.equal(nconf.get('foo:bar:bazz'), 'buzz');
}
},
"the clear() method": {
"should respond with the true": function () {
assert.equal(nconf.get('foo:bar:bazz'), 'buzz');
assert.isTrue(nconf.clear('foo:bar:bazz'));
assert.isTrue(typeof nconf.get('foo:bar:bazz') === 'undefined');
}
},
"the load() method": {
"without a callback": {
"should throw an exception": function () {
assert.throws(function () {
nconf.load();
})
}
},
"with a callback": {
topic: function () {
nconf.load(this.callback.bind(null, null));
},
"should respond with an error": function (ign, err) {
assert.isNotNull(err);
}
}
},
"the save() method": {
"without a callback": {
"should throw an exception": function () {
assert.throws(function () {
nconf.save();
})
}
},
"with a callback": {
topic: function () {
nconf.save(this.callback.bind(null, null));
},
"should respond with an error": function (ign, err) {
assert.isNotNull(err);
}
}
}
}
}
}).export(module);

194
test/nconf.test.mjs Normal file
View File

@ -0,0 +1,194 @@
import fs from 'fs'
import path from 'path'
import { Eltro as t, assert} from 'eltro'
import Nconf from '../lib/nconf.mjs'
import * as helpers from './helpers.mjs'
t.describe('nconf', function() {
t.test('should have the correct methods set', function() {
let nconf = new Nconf()
assert.strictEqual(typeof(nconf.key), 'function')
assert.strictEqual(typeof(nconf.path), 'function')
assert.strictEqual(typeof(nconf.use), 'function')
assert.strictEqual(typeof(nconf.any), 'function')
assert.strictEqual(typeof(nconf.get), 'function')
assert.strictEqual(typeof(nconf.set), 'function')
assert.strictEqual(typeof(nconf.clear), 'function')
assert.strictEqual(typeof(nconf.load), 'function')
assert.strictEqual(typeof(nconf.save), 'function')
assert.strictEqual(typeof(nconf.reset), 'function')
assert.strictEqual(typeof(nconf.required), 'function')
})
t.test('memory() should instaniate the correct store', function() {
let nconf = new Nconf()
nconf.memory()
assert.ok(nconf.use('memory') instanceof Nconf.Memory)
})
t.test('should have the correct version set', function () {
let nconf = new Nconf()
let pckg = JSON.parse(fs.readFileSync(helpers.fixture('../../package.json')))
assert.ok(pckg.version)
assert.strictEqual(nconf.version, pckg.version)
})
})
t.describe('#required()', function() {
let nconf = new Nconf()
nconf.memory()
nconf.set('foo:bar:bazz', 'buzz')
t.test('should throw error with missing keys', function() {
assert.throws(function() {
nconf.required(['missingtest', 'foo:bar:bazz'])
}, /missingtest/)
})
t.test('should throw error with missing keys with non-array parameter', function() {
assert.throws(function() {
nconf.required(['missingtest', 'foo:bar:bazz'])
}, /missingtest/)
})
t.test('should return the provider if all keys exist', function() {
assert.strictEqual(nconf.required(['foo:bar:bazz']), nconf)
})
})
t.describe('#any()', function() {
let nconf = new Nconf()
nconf.memory()
nconf.set('foo:bar:bazz', 'buzz')
t.test('should return if found', function() {
assert.strictEqual(nconf.any(['missingtest', 'nope', 'foo:bar:bazz']), 'buzz')
})
t.test('should return first item found', function() {
assert.deepStrictEqual(nconf.any(['missingtest', 'foo', 'nope', 'foo:bar:bazz']), {
bar: {
bazz: 'buzz',
},
})
})
t.test('should return if found as paramaters', function() {
assert.strictEqual(nconf.any('missingtest', 'nope', 'foo:bar:bazz'), 'buzz')
})
t.test('should return undefined otherwise', function() {
assert.strictEqual(nconf.any(['missingtest', 'nope']), undefined)
})
})
t.describe('#set()', function() {
t.test('should respond with self if success', function() {
let nconf = new Nconf()
nconf.memory()
assert.strictEqual(nconf.set('foo:bar:bazz', 'buzz'), nconf)
})
t.test('should respond with false if not successful', function() {
let nconf = new Nconf()
nconf.memory({ readOnly: true })
assert.strictEqual(nconf.set('foo:bar:bazz', 'buzz'), false)
})
t.test('should always set the first writeable store', function() {
let nconf = new Nconf()
nconf.memory('first')
nconf.memory('second')
nconf.use('second').set('foo:bar:bazz', 'buzz')
assert.strictEqual(nconf.get('foo:bar:bazz'), 'buzz')
nconf.set('foo:bar:bazz', 'overwritten')
assert.strictEqual(nconf.get('foo:bar:bazz'), 'overwritten')
assert.strictEqual(nconf.use('second').get('foo:bar:bazz'), 'buzz')
})
t.test('should respond allow access to the root and complain about non-objects', function() {
let nconf = new Nconf()
nconf.memory()
assert.notOk(nconf.set(null, null))
assert.notOk(nconf.set(null, undefined))
assert.notOk(nconf.set(null))
assert.notOk(nconf.set(null, ''))
assert.notOk(nconf.set(null, 1))
var original = nconf.get()
assert.ok(nconf.set(null, nconf.get()))
assert.notStrictEqual(nconf.get(), original)
assert.deepStrictEqual(nconf.get(), original)
})
})
t.describe('#get()', function() {
let nconf = new Nconf()
nconf.memory()
nconf.set('foo:bar:bazz', 'buzz')
t.test('should respond with the correct value', function() {
assert.strictEqual(nconf.get('foo:bar:bazz'), 'buzz')
})
t.test('unknown keys should return undefined', function() {
assert.strictEqual(nconf.get('foo:bar:bazz:toString'), undefined)
})
t.test('should not step inside strings', function() {
assert.strictEqual(nconf.get('foo:bar:bazz:0'), undefined)
})
t.test('should respond allow access to the root', function() {
assert.ok(nconf.get(null))
assert.ok(nconf.get(undefined))
assert.ok(nconf.get())
assert.deepStrictEqual(nconf.get(), { foo: { bar: { bazz: 'buzz' } } })
})
t.test('should merge stores correctly', function() {
let testMerge = new Nconf()
testMerge.memory('higherpriority')
testMerge.set('foo:bar', {
bazz: 'overwritten',
test: 1
})
testMerge.memory('lowerdefaults')
testMerge.use('lowerdefaults').set('foo:bar:bazz', 'buzz')
testMerge.use('lowerdefaults').set('foo:bar:buzz', 'buzz')
assert.strictEqual(testMerge.get('foo:bar:bazz'), 'overwritten')
assert.strictEqual(testMerge.get('foo:bar:buzz'), 'buzz')
assert.deepStrictEqual(testMerge.get('foo:bar'), {
bazz: 'overwritten',
buzz: 'buzz',
test: 1,
})
})
})
t.describe('#clear()', function() {
t.test('should respond with self if success', function() {
let nconf = new Nconf()
nconf.memory().set('foo:bar:bazz', 'buzz')
assert.strictEqual(nconf.get('foo:bar:bazz'), 'buzz')
assert.strictEqual(nconf.clear('foo:bar:bazz'), nconf)
assert.strictEqual(nconf.get('foo:bar:bazz'), undefined)
})
t.test('should respond with self if success even with readOnly store', function() {
let nconf = new Nconf()
nconf
.literal({ testetytest: 'buzz' })
.memory()
.set('foo:bar:bazz', 'buzz')
assert.strictEqual(nconf.get('foo:bar:bazz'), 'buzz')
assert.strictEqual(nconf.get('testetytest'), 'buzz')
assert.strictEqual(nconf.clear('foo:bar:bazz'), nconf)
assert.strictEqual(nconf.get('foo:bar:bazz'), undefined)
assert.strictEqual(nconf.use('literal').get('foo:bar:bazz'), undefined)
})
t.test('should respond with false if clearing readonly value', function() {
let nconf = new Nconf()
nconf.literal({ testetytest: 'buzz' })
assert.strictEqual(nconf.get('testetytest'), 'buzz')
assert.notOk(nconf.clear('testetytest'))
assert.strictEqual(nconf.get('testetytest'), 'buzz')
})
})

225
test/provider.test.mjs Normal file
View File

@ -0,0 +1,225 @@
import fs from 'fs'
import path from 'path'
import { spawn } from 'child_process'
import { Eltro as t, assert} from 'eltro'
import * as helpers from './helpers.mjs'
// import nconf from '../lib/nconf-o.mjs'
import Nconf from '../lib/nconf.mjs'
let files = [
helpers.fixture('merge/file1.json'),
helpers.fixture('merge/file2.json'),
];
let override = JSON.parse(fs.readFileSync(files[0]), 'utf8');
function assertSystemConf(options) {
return new Promise(function(res, rej) {
let env = null;
if (options.env) {
env = {}
Object.keys(process.env).forEach(function (key) {
env[key] = process.env[key];
});
Object.keys(options.env).forEach(function (key) {
env[key] = options.env[key];
});
}
let child = spawn('node', [options.script].concat(options.argv), {env: env});
child.stdout.once('data', data => {
res(data.toString())
});
})
}
t.describe('When using nconf', function() {
t.test("calling add with the same store type and different options should use the new instance", function() {
let nconf = new Nconf()
nconf.file({ file: files[0] })
let old = nconf.using.get('file');
assert.ok(old)
assert.strictEqual(old.file, files[0]);
nconf.file({ file: files[1] });
let newOne = nconf.using.get('file');
assert.notStrictEqual(old, newOne);
assert.strictEqual(newOne.file, files[1]);
})
/*
t.test("respond with correct arg when 'env' is true", async function() {
let result = await assertSystemConf({
script: helpers.fixture('scripts/provider-env.mjs'),
env: {SOMETHING: 'foobar'}
})
assert.strictEqual(result.toString(), 'foobar')
});
t.test("respond with correct arg when 'env' is true and 'parseValues' option is true", function() {
let env = {
SOMETHING: 'foobar',
SOMEBOOL: 'true',
SOMENULL: 'null',
SOMEUNDEF: 'undefined',
SOMEINT: '3600',
SOMEFLOAT: '0.5',
SOMEBAD: '5.1a'
};
let oenv = {};
Object.keys(env).forEach(function (key) {
if (process.env[key]) oenv[key] = process.env[key];
process.env[key] = env[key];
});
let provider = new nconf.Provider().use('env', {parseValues: true});
Object.keys(env).forEach(function (key) {
delete process.env[key];
if (oenv[key]) process.env[key] = oenv[key];
});
assert.strictEqual(provider.get('SOMETHING'), 'foobar');
assert.strictEqual(provider.get('SOMEBOOL'), true);
assert.notStrictEqual(provider.get('SOMEBOOL'), 'true');
assert.strictEqual(provider.get('SOMENULL'), null);
assert.strictEqual(provider.get('SOMEUNDEF'), undefined);
assert.strictEqual(provider.get('SOMEINT'), 3600);
assert.strictEqual(provider.get('SOMEFLOAT'), .5);
assert.strictEqual(provider.get('SOMEBAD'), '5.1a');
});
t.describe("an instance of 'nconf.Provider'", function() {
t.describe("the merge() method", function() {
t.test("should have the result merged in", function() {
let provider = new nconf.Provider().use('file', {file: files[1]});
provider.load();
provider.merge(override);
helpers.assertMerged(null, provider.stores.file.store);
assert.strictEqual(provider.stores.file.store.candy.something, 'file1');
});
t.test("should merge Objects over null", function() {
let provider = new nconf.Provider().use('file', {file: files[1]});
provider.load();
provider.merge(override);
assert.strictEqual(provider.stores.file.store.unicorn.exists, true);
});
})
t.describe("the load() method", function() {
t.test("should respect the hierarchy when sources are passed in", function() {
let provider = new nconf.Provider({
sources: {
user: {
type: 'file',
file: files[0]
},
global: {
type: 'file',
file: files[1]
}
}
});
let merged = provider.load();
helpers.assertMerged(null, merged);
assert.strictEqual(merged.candy.something, 'file1');
})
t.test("should respect the hierarchy when multiple stores are used", function() {
let provider = new nconf.Provider().overrides({foo: {bar: 'baz'}})
.add('file1', {type: 'file', file: files[0]})
.add('file2', {type: 'file', file: files[1]});
let merged = provider.load();
helpers.assertMerged(null, merged);
assert.strictEqual(merged.foo.bar, 'baz');
assert.strictEqual(merged.candy.something, 'file1');
})
})
})
t.describe("the .file() method", function() {
t.test("should use the correct File store with a single filepath", function() {
let provider = new nconf.Provider();
provider.file(helpers.fixture('store.json'));
assert.strictEqual(typeof(provider.stores.file), 'object');
});
t.test("should use the correct File store with a name and a filepath", function() {
let provider = new nconf.Provider();
provider.file('custom', helpers.fixture('store.json'));
assert.strictEqual(typeof(provider.stores.custom), 'object');
});
t.test("should use the correct File store with a single object", function() {
let provider = new nconf.Provider();
provider.file({
dir: helpers.fixture(''),
file: 'store.json',
search: true
});
assert.strictEqual(typeof(provider.stores.file), 'object');
assert.strictEqual(provider.stores.file.file, helpers.fixture('store.json'));
});
t.test("should use the correct File store with a name and an object", function() {
let provider = new nconf.Provider();
provider.file('custom', {
dir: helpers.fixture(''),
file: 'store.json',
search: true
});
assert.strictEqual(typeof(provider.stores.custom), 'object');
assert.strictEqual(provider.stores.custom.file, helpers.fixture('store.json'));
})*/
/*t.describe("the any() method", function() {
let provider = new nconf.Provider({
type: 'literal',
store: {
key: "getThisValue"
}
})
t.describe("without a callback", function() {
t.test("should respond with the correct value given an array of keys with one matching", function() {
assert.strictEqual(provider.any(["notthis", "orthis", "key"]), 'getThisValue');
})
t.test("should respond with null given an array of keys with no match", function() {
assert.strictEqual(provider.any(["notthis", "orthis"]), null);
});
t.test("should respond with the correct value given a variable argument list of keys with one matching", function() {
assert.strictEqual(provider.any("notthis", "orthis", "key"), 'getThisValue');
});
t.test("should respond with null given no arguments", function() {
assert.strictEqual(provider.any(), null);
});
})
t.describe("with a callback", function() {
t.test("should respond with the correct value given an array of keys with one matching", function(done) {
provider.any(["notthis", "orthis", "key"], (err, value) => {
assert.strictEqual(value, 'getThisValue');
done();
});
});
t.test("should respond with an undefined value given an array of keys with no match", function(done) {
provider.any(["notthis", "orthis"], (err, value) => {
assert.strictEqual(value, undefined)
done();
});
});
t.test("should respond with the correct value given a variable argument list of keys with one matching", function(done) {
provider.any("notthis", "orthis", "key", (err, value) => {
assert.strictEqual(value, 'getThisValue');
done();
});
});
t.test("should respond with an undefined value given no keys", function(done) {
provider.any((err, value) => {
assert.strictEqual(value, undefined)
done();
});
});
})
})
})*/
});

View File

@ -1,159 +0,0 @@
/*
* redis-store-test.js: Tests for the redis nconf storage engine.
*
* (C) 2011, Charlie Robbins
*
*/
require.paths.unshift(require('path').join(__dirname, '..', 'lib'));
var vows = require('vows'),
assert = require('assert'),
nconf = require('nconf'),
data = require('./fixtures/data').data;
vows.describe('nconf/stores/redis').addBatch({
"When using the nconf redis store": {
topic: new nconf.stores.Redis(),
"the set() method": {
"with a literal": {
topic: function (store) {
store.set('foo:literal', 'bazz', this.callback)
},
"should respond without an error": function (err, ok) {
assert.isNull(err);
}
},
"with an Array": {
topic: function (store) {
store.set('foo:array', data.arr, this.callback)
},
"should respond without an": function (err, ok) {
assert.isNull(err);
}
},
"with an Object": {
topic: function (store) {
store.set('foo:object', data.obj, this.callback)
},
"should respond without an error": function (err, ok) {
assert.isNull(err);
}
}
}
}
}).addBatch({
"When using the nconf redis store": {
topic: new nconf.stores.Redis(),
"the get() method": {
"with a literal value": {
topic: function (store) {
store.get('foo:literal', this.callback);
},
"should respond with the correct value": function (err, value) {
assert.equal(value, data.literal);
}
},
"with an Array value": {
topic: function (store) {
store.get('foo:array', this.callback);
},
"should respond with the correct value": function (err, value) {
assert.deepEqual(value, data.arr);
}
},
"with an Object value": {
topic: function (store) {
store.get('foo:object', this.callback);
},
"should respond with the correct value": function (err, value) {
assert.deepEqual(value, data.obj);
}
},
"with a nested Object value": {
topic: function (store) {
store.get('foo:object:auth', this.callback);
},
"should respond with the correct value": function (err, value) {
assert.deepEqual(value, data.obj.auth);
}
}
}
}
}).addBatch({
"When using the nconf redis store": {
topic: new nconf.stores.Redis(),
"the clear() method": {
topic: function (store) {
var that = this;
store.clear('foo', function (err) {
if (err) {
return that.callback(err);
}
store.get('foo', that.callback);
});
},
"should actually remove the value from Redis": function (err, value) {
assert.isNull(err);
assert.isNull(value);
}
}
}
}).addBatch({
"When using the nconf redis store": {
topic: new nconf.stores.Redis(),
"the save() method": {
topic: function (store) {
var that = this;
store.save(data, function (err) {
if (err) {
return that.callback(err);
}
store.get('obj', that.callback);
});
},
"should set all values correctly": function (err, value) {
assert.isNull(err);
assert.deepEqual(value, data.obj);
}
}
}
}).addBatch({
"When using the nconf redis store": {
topic: new nconf.stores.Redis(),
"the load() method": {
topic: function (store) {
store.load(this.callback);
},
"should respond with the correct object": function (err, value) {
assert.isNull(err);
assert.deepEqual(value, data);
}
}
}
}).addBatch({
"When using the nconf redis store": {
topic: new nconf.stores.Redis(),
"the reset() method": {
topic: function (store) {
var that = this;
this.store = store;
store.reset(function (err) {
if (err) {
return that.callback(err);
}
store.get('obj', that.callback);
});
},
"should remove all keys from redis": function (err, value) {
assert.isNull(err);
assert.isNull(value);
assert.length(Object.keys(this.store.cache.store), 0);
}
}
}
}).export(module);

171
test/stores/argv.test.mjs Normal file
View File

@ -0,0 +1,171 @@
import { Eltro as t, assert} from 'eltro'
import Nconf from '../../lib/nconf.mjs'
t.describe('#load()', () => {
t.test('should support pairs of arguments together as strings', function() {
process.argv = ['bla', 'bla',
'--foobar', '123',
'--testety', 'hello',
]
let store = new Nconf.Argv()
store.load()
assert.strictEqual(store.get('foobar'), '123')
assert.strictEqual(store.get('testety'), 'hello')
assert.deepStrictEqual(store.get(), {
foobar: '123',
testety: 'hello',
})
})
t.test('should support custom prefix argument', function() {
process.argv = ['bla', 'bla',
'-foobar', '123',
'-testety', 'hello',
]
let store = new Nconf.Argv({ prefix: '-' })
store.load()
assert.strictEqual(store.get('foobar'), '123')
assert.strictEqual(store.get('testety'), 'hello')
assert.deepStrictEqual(store.get(), {
foobar: '123',
testety: 'hello',
})
})
t.test('should support individual options as boolean', function() {
process.argv = ['bla', 'bla',
'--booleanone',
'--foobar', '123',
'--testety', 'hello',
'--booleantwo',
]
let store = new Nconf.Argv()
store.load()
assert.strictEqual(store.get('foobar'), '123')
assert.strictEqual(store.get('testety'), 'hello')
assert.strictEqual(store.get('booleanone'), true)
assert.strictEqual(store.get('booleantwo'), true)
assert.deepStrictEqual(store.get(), {
foobar: '123',
testety: 'hello',
booleanone: true,
booleantwo: true,
})
})
t.test('should support forcing everything as lowercase', function() {
process.argv = ['bla', 'bla',
'--FOOBAR', '123',
'--TESTETY', 'hello',
]
let store = new Nconf.Argv({ lowerCase: true })
store.load()
assert.strictEqual(store.get('foobar'), '123')
assert.strictEqual(store.get('testety'), 'hello')
assert.deepStrictEqual(store.get(), {
foobar: '123',
testety: 'hello',
})
})
t.test('should support making objects', function() {
process.argv = ['bla', 'bla',
'--foo:bar:baz', '123',
'--foo:bar:testety', 'hello',
]
let store = new Nconf.Argv()
store.load()
assert.strictEqual(store.get('foo:bar:baz'), '123')
assert.strictEqual(store.get('foo:bar:testety'), 'hello')
assert.deepStrictEqual(store.get(), {
foo: {
bar: {
baz: '123',
testety: 'hello',
}
}
})
})
t.test('should support custom seperator', function() {
process.argv = ['bla', 'bla',
'--foo__bar__baz', '123',
'--foo__bar__testety', 'hello',
]
let store = new Nconf.Argv({ separator: '__' })
store.load()
assert.strictEqual(store.get('foo:bar:baz'), '123')
assert.strictEqual(store.get('foo:bar:testety'), 'hello')
assert.deepStrictEqual(store.get(), {
foo: {
bar: {
baz: '123',
testety: 'hello',
}
}
})
})
t.test('should support parse values', function() {
process.argv = ['bla', 'bla',
'--foo', '123',
'--bar', '0.123',
'--asdf', '{"hello":"world"}',
'--testety', 'hello',
]
let store = new Nconf.Argv({ parseValues: true })
store.load()
assert.deepStrictEqual(store.get(), {
foo: 123,
bar: 0.123,
asdf: {
hello: 'world',
},
testety: 'hello',
})
})
t.test('should support usage of equal sign instead', function() {
process.argv = ['bla', 'bla',
'--foo=123',
'--testety=hello',
]
let store = new Nconf.Argv({ useEqualsign: true })
store.load()
assert.deepStrictEqual(store.get(), {
foo: '123',
testety: 'hello',
})
})
t.test('equal sign should support boolean values', function() {
process.argv = ['bla', 'bla',
'--booleanone',
'--foobar=123',
'--testety=hello',
'--booleantwo',
]
let store = new Nconf.Argv({ useEqualsign: true })
store.load()
assert.strictEqual(store.get('booleanone'), true)
assert.strictEqual(store.get('booleantwo'), true)
assert.deepStrictEqual(store.get(), {
foobar: '123',
testety: 'hello',
booleanone: true,
booleantwo: true,
})
})
t.test('should be smart with the usage of equal sign', function() {
process.argv = ['bla', 'bla',
'--foo=hello=world',
]
let store = new Nconf.Argv({ useEqualsign: true })
store.load()
assert.strictEqual(store.get('foo'), 'hello=world')
})
})

245
test/stores/env.test.mjs Normal file
View File

@ -0,0 +1,245 @@
import { Eltro as t, assert} from 'eltro'
import Nconf from '../../lib/nconf.mjs'
t.describe('#load()', () => {
let backupEnv = {}
let testEnv = {
SOMETHING: 'foobar',
SOMEBOOL: 'true',
SOMENULL: 'null',
SOMEUNDEF: 'undefined',
SOMEINT: '3600',
SOMEFLOAT: '0.5',
SOMEBAD: '5.1a',
ANOTHER__TEST__THIS: 'foobar',
}
t.before(function() {
Object.keys(testEnv).forEach(function (key) {
if (process.env[key]) backupEnv[key] = process.env[key]
process.env[key] = testEnv[key]
})
})
t.test("should default read everything as string", function() {
let store = new Nconf.Env()
store.load()
assert.strictEqual(store.get('SOMETHING'), 'foobar')
assert.strictEqual(store.get('SOMEBOOL'), 'true')
assert.strictEqual(store.get('SOMENULL'), 'null')
assert.strictEqual(store.get('SOMEUNDEF'), 'undefined')
assert.strictEqual(store.get('SOMEINT'), '3600')
assert.strictEqual(store.get('SOMEFLOAT'), '0.5')
assert.strictEqual(store.get('SOMEBAD'), '5.1a')
assert.strictEqual(store.get('ANOTHER__TEST__THIS'), 'foobar')
})
t.test("should support parseValues correctly", function() {
let store = new Nconf.Env({parseValues: true})
store.load()
assert.strictEqual(store.get('SOMETHING'), 'foobar')
assert.strictEqual(store.get('SOMEBOOL'), true)
assert.notStrictEqual(store.get('SOMEBOOL'), 'true')
assert.strictEqual(store.get('SOMENULL'), null)
assert.strictEqual(store.get('SOMEUNDEF'), undefined)
assert.strictEqual(store.get('SOMEINT'), 3600)
assert.strictEqual(store.get('SOMEFLOAT'), .5)
assert.strictEqual(store.get('SOMEBAD'), '5.1a')
assert.strictEqual(store.get('ANOTHER__TEST__THIS'), 'foobar')
})
t.test("should support lowercase", function() {
let store = new Nconf.Env({lowerCase: true})
store.load()
assert.notOk(store.get('SOMETHING'))
assert.notOk(store.get('SOMEBOOL'))
assert.notOk(store.get('SOMENULL'))
assert.notOk(store.get('SOMEUNDEF'))
assert.notOk(store.get('SOMEINT'))
assert.notOk(store.get('SOMEFLOAT'))
assert.notOk(store.get('SOMEBAD'))
assert.notOk(store.get('ANOTHER__TEST__THIS'))
assert.strictEqual(store.get('something'), 'foobar')
assert.strictEqual(store.get('somebool'), 'true')
assert.strictEqual(store.get('somenull'), 'null')
assert.strictEqual(store.get('someundef'), 'undefined')
assert.strictEqual(store.get('someint'), '3600')
assert.strictEqual(store.get('somefloat'), '0.5')
assert.strictEqual(store.get('somebad'), '5.1a')
assert.strictEqual(store.get('another__test__this'), 'foobar')
})
t.test("should support transform", function() {
let store = new Nconf.Env({transform: function(key, value) {
if (!testEnv[key]) return null
return {
key: key[0].toUpperCase() + key.slice(1).toLowerCase(),
value: 1,
}
}})
store.load()
assert.strictEqual(store.get('Something'), 1)
assert.strictEqual(store.get('Somebool'), 1)
assert.strictEqual(store.get('Somenull'), 1)
assert.strictEqual(store.get('Someundef'), 1)
assert.strictEqual(store.get('Someint'), 1)
assert.strictEqual(store.get('Somefloat'), 1)
assert.strictEqual(store.get('Somebad'), 1)
assert.strictEqual(store.get('Another__test__this'), 1)
assert.deepStrictEqual(store.get(), {
Something: 1,
Somebool: 1,
Somenull: 1,
Someundef: 1,
Someint: 1,
Somefloat: 1,
Somebad: 1,
Another__test__this: 1,
})
})
t.test("should support matches", function() {
let store = new Nconf.Env({match: /^SOME/})
store.load()
assert.strictEqual(store.get('SOMETHING'), 'foobar')
assert.strictEqual(store.get('SOMEBOOL'), 'true')
assert.strictEqual(store.get('SOMENULL'), 'null')
assert.strictEqual(store.get('SOMEUNDEF'), 'undefined')
assert.strictEqual(store.get('SOMEINT'), '3600')
assert.strictEqual(store.get('SOMEFLOAT'), '0.5')
assert.strictEqual(store.get('SOMEBAD'), '5.1a')
assert.notOk(store.get('Another__test__this'))
assert.deepStrictEqual(store.get(), {
SOMETHING: 'foobar',
SOMEBOOL: 'true',
SOMENULL: 'null',
SOMEUNDEF: 'undefined',
SOMEINT: '3600',
SOMEFLOAT: '0.5',
SOMEBAD: '5.1a',
})
})
t.test("should support whitelist", function() {
let store = new Nconf.Env({whitelist: ['ANOTHER__TEST__THIS']})
store.load()
assert.notOk(store.get('SOMETHING'), 'foobar')
assert.notOk(store.get('SOMEBOOL'), 'true')
assert.notOk(store.get('SOMENULL'), 'null')
assert.notOk(store.get('SOMEUNDEF'), 'undefined')
assert.notOk(store.get('SOMEINT'), '3600')
assert.notOk(store.get('SOMEFLOAT'), '0.5')
assert.notOk(store.get('SOMEBAD'), '5.1a')
assert.strictEqual(store.get('ANOTHER__TEST__THIS'), 'foobar')
assert.deepStrictEqual(store.get(), {
ANOTHER__TEST__THIS: 'foobar',
})
})
t.test("whitelist should be case insensitive", function() {
let store = new Nconf.Env({whitelist: ['another__test__this']})
store.load()
assert.strictEqual(store.get('ANOTHER__TEST__THIS'), 'foobar')
assert.deepStrictEqual(store.get(), {
ANOTHER__TEST__THIS: 'foobar',
})
})
t.test("should support whitelist with match", function() {
let store = new Nconf.Env({
whitelist: ['another__test__this'],
match: /^SOMEBOOL/,
})
store.load()
assert.strictEqual(store.get('ANOTHER__TEST__THIS'), 'foobar')
assert.strictEqual(store.get('SOMEBOOL'), 'true')
assert.deepStrictEqual(store.get(), {
ANOTHER__TEST__THIS: 'foobar',
SOMEBOOL: 'true',
})
})
t.test("should support custom seperator", function() {
let store = new Nconf.Env({
whitelist: ['another__test__this', 'somebool'],
separator: '__',
})
store.load()
assert.strictEqual(store.get('ANOTHER:TEST:THIS'), 'foobar')
assert.strictEqual(store.get('SOMEBOOL'), 'true')
assert.deepStrictEqual(store.get(), {
ANOTHER: {
TEST: {
THIS: 'foobar',
},
},
SOMEBOOL: 'true',
})
})
t.test("should stay readOnly always", function() {
let store = new Nconf.Env({whitelist: ['another__test__this']})
assert.strictEqual(store.readOnly, true)
store.load()
assert.strictEqual(store.readOnly, true)
})
t.test("should throw if whitelist is invalid", function() {
assert.throws(function() {
new Nconf.Env({whitelist: 'another__test__this'})
}, /[Ww]hitelist.+[Aa]rray/)
assert.throws(function() {
new Nconf.Env({whitelist: ['another__test__this', 123]})
}, /[Ww]hitelist.+[Aa]rray/)
})
t.test("should throw if match is invalid", function() {
assert.throws(function() {
new Nconf.Env({match: 1234})
}, /[Mm]atch.+[Rr]eg[Ee]xp/)
assert.throws(function() {
new Nconf.Env({match: {}})
}, /[Mm]atch.+[Rr]eg[Ee]xp/)
})
t.test("should automatically convert string match to RegExp", function() {
let store = new Nconf.Env({match: 'asdf'})
assert.ok(store.match)
assert.ok(store.match.test('asdf'))
assert.notOk(store.match.test('test'))
})
t.test("should support whitelist directly in parameter", function() {
let store = new Nconf.Env(['another__test__this'])
store.load()
assert.strictEqual(store.get('ANOTHER__TEST__THIS'), 'foobar')
assert.deepStrictEqual(store.get(), {
ANOTHER__TEST__THIS: 'foobar',
})
})
t.after(function() {
Object.keys(backupEnv).forEach(function (key) {
process.env[key] = backupEnv[key]
})
})
})

250
test/stores/file.test.mjs Normal file
View File

@ -0,0 +1,250 @@
import fs from 'fs'
import { Eltro as t, assert} from 'eltro'
import * as helpers from '../helpers.mjs'
import { data } from '../fixtures/data.mjs'
import Nconf from '../../lib/nconf.mjs'
const fsPromise = fs.promises
// let yamlFormat = require('nconf-yaml')
t.describe('#load()', function() {
let validFile = helpers.fixture('store.json')
fs.writeFileSync(validFile, JSON.stringify(data, null, 2))
let malformedFile = helpers.fixture('malformed.json')
let bomFile = helpers.fixture('bom.json')
let noBomPath = helpers.fixture('no-bom.json')
t.test('with valid json should load correctly', function() {
let store = new Nconf.File({file: validFile})
store.load()
assert.deepStrictEqual(store.store, data)
})
t.test('with only file string as option', function() {
let store = new Nconf.File(validFile)
store.load()
assert.deepStrictEqual(store.store, data)
})
t.test('malformed JSON should respond with an error and indicate file name', function() {
let store = new Nconf.File({file: malformedFile})
assert.throws(() => {
store.load()
}, /malformed\.json/)
})
t.test('with a valid UTF8 JSON file that contains a BOM', function() {
let store = new Nconf.File(bomFile)
store.load()
assert.strictEqual(store.get('port'), 78304)
assert.strictEqual(store.get('host'), 'weebls-stuff.com')
})
t.test('with a valid UTF8 JSON file that contains no BOM', function() {
let store = new Nconf.File(noBomPath)
store.load()
assert.strictEqual(store.get('port'), 78304)
assert.strictEqual(store.get('host'), 'weebls-stuff.com')
})
})
t.describe('#loadAsync()', function() {
let validFile = helpers.fixture('store.json')
fs.writeFileSync(validFile, JSON.stringify(data, null, 2))
let malformedFile = helpers.fixture('malformed.json')
let bomFile = helpers.fixture('bom.json')
let noBomPath = helpers.fixture('no-bom.json')
t.test('with valid json should load correctly', function() {
let store = new Nconf.File({file: validFile})
return store.loadAsync().then(function(newData) {
assert.strictEqual(newData, store.store)
assert.deepStrictEqual(store.store, data)
})
})
t.test('with only file string as option', function() {
let store = new Nconf.File(validFile)
return store.loadAsync().then(function() {
assert.deepStrictEqual(store.store, data)
})
})
t.test('malformed JSON should respond with an error and indicate file name', function() {
let store = new Nconf.File({file: malformedFile})
assert.isRejected(store.loadAsync()).then(function(err) {
assert.match(err.message, /malformed\.json/)
})
})
t.test('with a valid UTF8 JSON file that contains a BOM', function() {
let store = new Nconf.File(bomFile)
return store.loadAsync().then(function() {
assert.strictEqual(store.get('port'), 78304)
assert.strictEqual(store.get('host'), 'weebls-stuff.com')
})
})
t.test('with a valid UTF8 JSON file that contains no BOM', function() {
let store = new Nconf.File(noBomPath)
return store.loadAsync().then(function() {
assert.strictEqual(store.get('port'), 78304)
assert.strictEqual(store.get('host'), 'weebls-stuff.com')
})
})
})
t.describe('#save()', function() {
let testPath = helpers.fixture('tmp.json')
let testSecondPath = helpers.fixture('tmp2.json')
t.test('should save the data correctly to original file specified', function() {
let store = new Nconf.File({file: testPath})
Object.keys(data).forEach(function (key) {
store.set(key, data[key])
})
assert.strictEqual(store.save(), store)
let readData = JSON.parse(fs.readFileSync(store.file))
assert.deepStrictEqual(readData, data)
})
t.test('should save the data to specified file', function() {
let store = new Nconf.File({file: testPath})
Object.keys(data).forEach(function (key) {
store.set(key, data[key])
})
store.save(testSecondPath)
let readData = JSON.parse(fs.readFileSync(testSecondPath))
assert.deepStrictEqual(readData, data)
})
t.after(function() {
return Promise.all([
fsPromise.unlink(testPath),
fsPromise.unlink(testSecondPath),
]).catch(function() {})
})
})
t.describe('#saveAsync()', function() {
let testPath = helpers.fixture('tmp.json')
let testSecondPath = helpers.fixture('tmp2.json')
t.test('should save the data correctly to original file specified', function() {
let store = new Nconf.File({file: testPath})
Object.keys(data).forEach(function (key) {
store.set(key, data[key])
})
return store.saveAsync().then(function(checkStore) {
assert.strictEqual(checkStore, store)
return fsPromise.readFile(store.file)
}).then(function(readData) {
assert.deepStrictEqual(JSON.parse(readData), data)
})
})
t.test('should save the data to specified file', function() {
let store = new Nconf.File({file: testPath})
Object.keys(data).forEach(function (key) {
store.set(key, data[key])
})
return store.saveAsync(testSecondPath).then(function() {
return fsPromise.readFile(testSecondPath)
}).then(function(readData) {
assert.deepStrictEqual(JSON.parse(readData), data)
})
})
t.after(function() {
return Promise.all([
fsPromise.unlink(testPath),
fsPromise.unlink(testSecondPath),
]).catch(function() {})
})
})
t.describe('#secure', function() {
t.test('the stringify() method should encrypt properly', function() {
let secureStore = new Nconf.File({
file: helpers.fixture('secure-iv.json'),
secure: 'super-secret-key-32-characterszz'
})
secureStore.store = data
let contents = JSON.parse(secureStore.stringify())
Object.keys(data).forEach(key => {
assert.strictEqual(typeof(contents[key]), 'object')
assert.strictEqual(typeof(contents[key].value), 'string')
assert.strictEqual(contents[key].alg, 'aes-256-ctr')
assert.strictEqual(typeof(contents[key].iv), 'string')
})
})
t.test('the parse() method should decrypt properly', function() {
let secureStore = new Nconf.File({
file: helpers.fixture('secure-iv.json'),
secure: 'super-secret-key-32-characterszz'
})
secureStore.store = data
let contents = secureStore.stringify()
let parsed = secureStore.parse(contents)
assert.deepStrictEqual(parsed, data)
})
t.test('the load() method should decrypt properly', function() {
let secureStore = new Nconf.File({
file: helpers.fixture('secure-iv.json'),
secure: 'super-secret-key-32-characterszz'
})
secureStore.load()
assert.deepStrictEqual(secureStore.store, data)
})
t.test('it should throw error on legacy encrypted files', function() {
let secureStore = new Nconf.File({
file: helpers.fixture('secure.json'),
secure: 'super-secretzzz'
})
assert.throws(function() {
secureStore.load()
}, /[Oo]utdated/)
})
})
/*
t.test('the search() method when the target file exists higher in the directory tree should update the file appropriately', function() {
let searchBase = require('os').homedir()
let filePath = path.join(searchBase, '.nconf')
fs.writeFileSync(filePath, JSON.stringify(data, null, 2))
let store = new Nconf.File({
file: '.nconf'
})
store.search(store.searchBase)
expect(store.file).toEqual(filePath)
fs.unlinkSync(filePath)
})
t.test('the search() method when the target file doesn't exist higher in the directory tree should update the file appropriately', function() {
let filePath = helpers.fixture('search-store.json')
let store = new Nconf.File({
dir: path.dirname(filePath),
file: 'search-store.json'
})
store.search()
expect(store.file).toEqual(filePath)
})
*/

View File

@ -0,0 +1,24 @@
import { Eltro as t, assert} from 'eltro'
import Nconf from '../../lib/nconf.mjs'
t.describe('nconf/stores/literal, An instance of nconf.Literal', function () {
var envOptions = {foo: 'bar', one: 2}
t.test("should have the correct methods defined", function () {
var literal = new Nconf.Literal()
assert.ok(literal.readOnly)
assert.strictEqual(literal.type, 'literal')
assert.strictEqual(typeof(literal.get), 'function')
assert.strictEqual(typeof(literal.set), 'function')
assert.strictEqual(typeof(literal.merge), 'function')
assert.strictEqual(typeof(literal.loadSync), 'function')
})
t.test("should have the correct values in the store", function () {
var literal = new Nconf.Literal(envOptions)
assert.strictEqual(literal.store.foo, 'bar')
assert.strictEqual(literal.store.one, 2)
assert.notOk(literal.set('foo', 'foo'))
assert.strictEqual(literal.store.foo, 'bar')
})
})

379
test/stores/memory.test.mjs Normal file
View File

@ -0,0 +1,379 @@
import { Eltro as t, assert} from 'eltro'
import Nconf from '../../lib/nconf.mjs'
import { merge } from '../fixtures/data.mjs'
t.describe('Memory Store', function () {
let store = new Nconf.Memory()
t.describe('#set()', function() {
t.test('should return true', function () {
assert.ok(store.set('foo:bar:bazz', 'buzz'))
assert.ok(store.set('falsy:number', 0))
assert.ok(store.set('falsy:string:empty', ''))
assert.ok(store.set('falsy:string:value', 'value'))
assert.ok(store.set('falsy:boolean', false))
assert.ok(store.set('falsy:object', null))
})
t.test('should support numbers as key', function() {
assert.notOk(store.get('523453'))
assert.ok(store.set(523453, true))
assert.ok(store.get('523453'))
})
t.test('should always make sure not store direct references to objects', function() {
const assertArray = [ 1, 2 ]
const assertObject = { a: 1 }
assert.ok(store.set('reference:test:arraydirect', assertArray))
assert.notStrictEqual(store.get('reference:test:arraydirect'), assertArray)
assert.ok(store.set('reference:test:objectdirect', assertObject))
assert.notStrictEqual(store.get('reference:test:objectdirect'), assertObject)
assert.ok(store.set('reference:test:objectchild', { x: assertArray, y: assertObject }))
assert.notStrictEqual(store.get('reference:test:objectchild:x'), assertArray)
assert.notStrictEqual(store.get('reference:test:objectchild:y'), assertObject)
})
t.test('should support numbers as key', function() {
let inStore = new Nconf.Memory()
inStore.set({ version: 1 })
assert.ok(inStore.set('version', 2))
assert.strictEqual(inStore.get('version'), 2)
inStore.readOnly = true
assert.notOk(inStore.set('version', 3))
assert.strictEqual(inStore.get('version'), 2)
})
t.test('should support numbers as key', function() {
let inStore = new Nconf.Memory({ parseValues: true })
inStore.set('test', '{"a":1}')
assert.ok(inStore.get('test'))
assert.deepStrictEqual(inStore.get('test'), { a: 1 })
inStore.set('test', 'undefined')
assert.notOk(inStore.get('test'))
})
t.test('should not do anything if given invalid set root', function() {
let inStore = new Nconf.Memory()
inStore.set({ version: 1 })
assert.deepStrictEqual(inStore.get(), { version: 1 })
assert.notOk(inStore.set(null))
assert.deepStrictEqual(inStore.get(), { version: 1 })
assert.notOk(inStore.set())
assert.deepStrictEqual(inStore.get(), { version: 1 })
assert.notOk(inStore.set([1, 2]))
assert.deepStrictEqual(inStore.get(), { version: 1 })
})
})
t.describe('#get()', function() {
t.test('should respond with the correct value', function () {
store.set('foo:bar:bazz', 'buzz')
store.set('falsy:number', 0)
store.set('falsy:string:empty', '')
store.set('falsy:string:value', 'value')
store.set('falsy:boolean', false)
store.set('falsy:object', null)
assert.strictEqual(store.get('foo:bar:bazz'), 'buzz')
assert.strictEqual(store.get('falsy:number'), 0)
assert.strictEqual(store.get('falsy:string:empty'), '')
assert.strictEqual(store.get('falsy:string:value'), 'value')
assert.strictEqual(store.get('falsy:boolean'), false)
assert.strictEqual(store.get('falsy:object'), null)
})
t.describe('should not at non-existent keys', function () {
t.test('at the root level', function () {
assert.strictEqual(store.get('this:key:does:not:exist'), undefined)
})
t.test('within numbers', function () {
assert.strictEqual(store.get('falsy:number:not:exist'), undefined)
})
t.test('within booleans', function () {
assert.strictEqual(store.get('falsy:boolean:not:exist'), undefined)
})
t.test('within objects', function () {
assert.strictEqual(store.get('falsy:object:not:exist'), undefined)
})
t.test('within empty strings', function () {
assert.strictEqual(store.get('falsy:string:empty:not:exist'), undefined)
})
t.test('within non-empty strings', function () {
assert.strictEqual(store.get('falsy:string:value:not:exist'), undefined)
})
})
})
t.describe('#clear()', function() {
t.test('should return false if readonly', function() {
let inStore = new Nconf.Memory()
inStore.set({ version: 1 })
inStore.readOnly = true
assert.notOk(inStore.clear('version'))
assert.strictEqual(inStore.get('version'), 1)
})
t.test('the clear() should return true if success', function () {
store.set('foo:bar:bazz', 'buzz')
assert.strictEqual(store.get('foo:bar:bazz'), 'buzz')
assert.ok(store.clear('foo:bar:bazz'))
assert.strictEqual(typeof store.get('foo:bar:bazz'), 'undefined')
})
t.test('should return false if not found', function() {
store.set('this:exists', 'fornow')
assert.strictEqual(store.get('this:exists'), 'fornow')
assert.notOk(store.clear('this:exists:but:not:this'))
assert.strictEqual(store.get('this:exists'), 'fornow')
})
})
t.describe('#merge()', function () {
t.test('should return false if readonly', function() {
let inStore = new Nconf.Memory()
inStore.set({ version: 1 })
inStore.readOnly = true
assert.notOk(inStore.merge({ version: 2 }))
assert.strictEqual(inStore.get('version'), 1)
})
t.test('when overriding an existing literal value', function () {
store.set('merge:literal', 'string-value')
store.merge('merge:literal', merge)
assert.deepStrictEqual(store.get('merge:literal'), merge)
})
t.test('when overriding an existing Array value', function () {
store.set('merge:array', [1, 2, 3, 4])
store.merge('merge:array', merge)
assert.deepStrictEqual(store.get('merge:literal'), merge)
})
t.test('when merging into an existing Object value', function () {
store.set('merge:object', {
prop1: 2,
prop2: 'prop2',
prop3: {
bazz: 'bazz'
},
prop4: ['foo', 'bar']
})
assert.strictEqual(store.get('merge:object:prop1'), 2)
assert.strictEqual(store.get('merge:object:prop2'), 'prop2')
assert.deepStrictEqual(store.get('merge:object:prop3'), {
bazz: 'bazz'
})
assert.strictEqual(store.get('merge:object:prop4').length, 2)
store.merge('merge:object', merge)
assert.strictEqual(store.get('merge:object:prop1'), 1)
assert.strictEqual(store.get('merge:object:prop2').length, 3)
assert.deepStrictEqual(store.get('merge:object:prop3'), {
foo: 'bar',
bar: 'foo',
bazz: 'bazz'
})
assert.strictEqual(store.get('merge:object:prop4').length, 2)
})
t.test('when merging at root level with an object', function() {
const assertFirst = 'herp'
const assertAfter = 'derp'
const newItem = { asdf: assertAfter }
let inStore = new Nconf.Memory()
inStore.set({
version: 1,
asdf: assertFirst,
})
assert.strictEqual(inStore.get('asdf'), assertFirst)
assert.strictEqual(inStore.get('version'), 1)
assert.ok(inStore.merge(newItem))
assert.notStrictEqual(inStore.get(), newItem)
assert.strictEqual(inStore.get('asdf'), assertAfter)
assert.strictEqual(inStore.get('version'), 1)
})
t.test('when merging at root level with an object with null after', function() {
const assertFirst = 'herp'
const assertAfter = 'derp'
const newItem = { asdf: assertAfter }
let inStore = new Nconf.Memory()
inStore.set({
version: 1,
asdf: assertFirst,
})
assert.strictEqual(inStore.get('asdf'), assertFirst)
assert.strictEqual(inStore.get('version'), 1)
assert.ok(inStore.merge(newItem), null)
assert.notStrictEqual(inStore.get(), newItem)
assert.strictEqual(inStore.get('asdf'), assertAfter)
assert.strictEqual(inStore.get('version'), 1)
})
t.test('when merging at root level with array', function() {
const newItem = 'herp'
let inStore = new Nconf.Memory()
inStore.set({
version: 1,
})
assert.strictEqual(inStore.get('version'), 1)
assert.notOk(inStore.get('0'))
assert.ok(inStore.merge([newItem]))
assert.ok(inStore.get('0'))
assert.strictEqual(inStore.get('0'), newItem)
assert.strictEqual(inStore.get('version'), 1)
})
t.test('when merging at root level with array and null after', function() {
const newItem = 'herp'
let inStore = new Nconf.Memory()
inStore.set({
version: 1,
})
assert.strictEqual(inStore.get('version'), 1)
assert.notOk(inStore.get('0'))
assert.ok(inStore.merge([newItem], null))
assert.ok(inStore.get('0'))
assert.strictEqual(inStore.get('0'), newItem)
assert.strictEqual(inStore.get('version'), 1)
})
t.test('it should always merge at root level if key is object regardless of what comes after', function() {
let inStore = new Nconf.Memory()
inStore.set({ herp: 1 })
assert.deepStrictEqual(inStore.get(), { herp: 1 })
assert.ok(inStore.merge({ version: 2 }, null))
assert.deepStrictEqual(inStore.get(), { herp: 1, version: 2 })
assert.ok(inStore.merge({ test: 3 }, 1235))
assert.deepStrictEqual(inStore.get(), { herp: 1, version: 2, test: 3 })
assert.ok(inStore.merge({ foo: 4 }, 'sadfsadfs'))
assert.deepStrictEqual(inStore.get(), { herp: 1, version: 2, test: 3, foo: 4 })
assert.ok(inStore.merge({ bar: 5 }, { asdf: 1 }))
assert.deepStrictEqual(inStore.get(), { herp: 1, version: 2, test: 3, foo: 4, bar: 5 })
})
t.test('it should be robust about key type and overwriting', function() {
let inStore = new Nconf.Memory()
inStore.set({ herp: 1 })
assert.deepStrictEqual(inStore.get(), { herp: 1 })
assert.ok(inStore.merge(123, null))
assert.deepStrictEqual(inStore.get(), { herp: 1, '123': null })
assert.ok(inStore.merge(123, { a: 1 }))
assert.deepStrictEqual(inStore.get(), { herp: 1, '123': { a: 1 } })
assert.ok(inStore.merge(123, ['a', 1]))
assert.deepStrictEqual(inStore.get(), { herp: 1, '123': ['a', 1] })
})
t.test('it be able to handle basic value types with basic values', function() {
let inStore = new Nconf.Memory()
inStore.set({ herp: 1 })
assert.deepStrictEqual(inStore.get(), { herp: 1 })
assert.ok(inStore.merge({ version: 2 }, null))
assert.deepStrictEqual(inStore.get(), { herp: 1, version: 2 })
assert.ok(inStore.merge({ test: 3 }, 1235))
assert.deepStrictEqual(inStore.get(), { herp: 1, version: 2, test: 3 })
assert.ok(inStore.merge({ foo: 4 }, 'sadfsadfs'))
assert.deepStrictEqual(inStore.get(), { herp: 1, version: 2, test: 3, foo: 4 })
assert.ok(inStore.merge({ bar: 5 }, { asdf: 1 }))
assert.deepStrictEqual(inStore.get(), { herp: 1, version: 2, test: 3, foo: 4, bar: 5 })
})
t.test('when sending a single path with null, string or number value should overwrite', function() {
const assertString = 'Beginning'
const assertNumber = 358792
let inStore = new Nconf.Memory()
inStore.set({
herp: {
derp: 123,
},
})
assert.strictEqual(inStore.get('herp:derp'), 123)
assert.ok(inStore.merge('herp:derp', null))
assert.strictEqual(inStore.get('herp:derp'), null)
assert.ok(inStore.merge('herp:derp', assertString))
assert.strictEqual(inStore.get('herp:derp'), assertString)
assert.ok(inStore.merge('herp:derp', assertNumber))
assert.strictEqual(inStore.get('herp:derp'), assertNumber)
})
t.test('when merging at nonexisting path', function() {
const assertNewItem = { a: 1, b: 2 }
const assertPath = 'new:path:for:item'
let inStore = new Nconf.Memory()
inStore.set({
version: 1,
})
assert.strictEqual(inStore.get('version'), 1)
assert.notOk(inStore.get(assertPath))
assert.ok(inStore.merge(assertPath, assertNewItem))
assert.ok(inStore.get(assertPath))
assert.notStrictEqual(inStore.get(assertPath), assertNewItem)
assert.deepStrictEqual(inStore.get(assertPath), assertNewItem)
assert.deepStrictEqual(inStore.get().new.path.for.item, assertNewItem)
})
})
t.describe('#reset()', function() {
t.test('should remove everything', function() {
const assertRoot = {
version: 1,
asdf: 'test',
}
let inStore = new Nconf.Memory()
inStore.set(assertRoot)
assert.deepStrictEqual(inStore.get(), assertRoot)
inStore.reset()
assert.deepStrictEqual(inStore.get(), {})
})
t.test('should do nothing if readonly', function() {
const assertRoot = {
version: 1,
asdf: 'test',
}
let inStore = new Nconf.Memory()
inStore.set(assertRoot)
assert.deepStrictEqual(inStore.get(), assertRoot)
inStore.readOnly = true
assert.notOk(inStore.reset())
assert.deepStrictEqual(inStore.get(), assertRoot)
})
})
t.describe('options', function () {
t.describe('logicalSeparator', function () {
var store = new Nconf.Memory({logicalSeparator: '||'})
t.test('when storing with : (colon), should store the config atomicly', function () {
store.set('foo:bar:bazz', 'buzz')
assert.strictEqual(typeof store.get('foo:bar'), 'undefined')
assert.strictEqual(store.get('foo:bar:bazz'), 'buzz')
})
t.test('when storing with separator, should be able to read the object', function () {
store.set('foo||bar||bazz', 'buzz')
assert.strictEqual(store.get('foo||bar').bazz, 'buzz')
assert.strictEqual(store.get('foo').bar.bazz, 'buzz')
})
})
t.test('should allow specifying readonly', function () {
var store = new Nconf.Memory({ readOnly: true })
assert.strictEqual(store.readOnly, true)
})
})
})

View File

@ -1,27 +0,0 @@
require.paths.unshift(require('path').join(__dirname, 'lib'));
var fs = require('fs'),
path = require('path'),
nconf = require('nconf');
//
// Setup nconf to user the 'file' store and set a couple of values;
//
nconf.use('file', { file: path.join(__dirname, 'config.json') });
nconf.set('database:host', '127.0.0.1');
nconf.set('database:port', 5984);
//
// Get the entire database object from nconf
//
var database = nconf.get('database');
console.dir(database);
//
// Save the configuration object to disk
//
nconf.save(function (err) {
fs.readFile(path.join(__dirname, 'config.json'), function (err, data) {
console.dir(JSON.parse(data.toString()))
});
});