diff --git a/.eslintrc.js b/.eslintrc.js index a10b5725..023ee16d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,28 +9,102 @@ module.exports = { mocha: true, }, rules: { - strict: ['error', 'global'], + //*** Programming best practices *** - // JavaScript core - 'no-array-constructor': 'error', - 'no-unused-vars': ['error', {'args': 'none'}], + strict: ['error', 'safe'], + semi: ['error', 'never'], + + 'no-unused-vars': ['error', {args: 'none'}], + + // Don't use "var", only use "let" and "const" + 'no-var': 'error', + // Use const if a variable is never reassigned + 'prefer-const': 'error', + + // No redeclaration of existing restricted names and builtins + 'no-shadow-restricted-names': 'error', + // No redeclaration of existing variables in outer scope + //'no-shadow': ['error', {builtinGlobals: true}], + // + // Interesting but produces less readable code … + //'no-shadow': ['error', {builtinGlobals: true, hoist: 'all'}], + + 'no-array-constructor': ['error'], + + // No dead code 'no-unreachable': 'error', - 'no-fallthrough': 'error', + + // Take full advantage of JavaScript flexibility by being able, in a + // function, to return different types (for exemple sometimes a boolean + // and sometimes an object). + 'consistent-return': 'off', + + // Disallow gratuitous parentheses + 'no-extra-parens': ['error', 'all', {conditionalAssign: false}], + + // Error best practices: + // Only throw Error instances + 'no-throw-literal': 'error', + + // Switch-case best practices 'default-case': 'error', + 'no-fallthrough': 'error', 'no-case-declarations': 'error', - 'consistent-return': 'off', - // Node.js specifics + // Enforces return statements in callbacks of array's methods + 'array-callback-return': 'error', + + 'no-console': 'error', + + //*** Presentation style *** + + indent: ['error', 2], + quotes: ['error', 'single', {avoidEscape: true}], + 'quote-props': ['error', 'as-needed'], + + // Use as much as possible snake_case for variable names and camelCase for + // function names. + camelcase: 'off', + + 'new-cap': 'error', + + 'no-multiple-empty-lines': ['error', {max: 2}], + 'no-trailing-spaces': 'error', + 'comma-spacing': ['error', {before: false, after: true}], + 'space-in-parens': ['error', 'never'], + 'keyword-spacing': 'error', + 'space-before-blocks': 'error', + 'space-infix-ops': 'error', + 'space-before-function-paren': ['error', 'never'], + 'no-spaced-func': 'error', + 'no-multi-spaces': 'error', + 'space-unary-ops': 'error', + 'object-curly-spacing': ['error', 'never'], + 'array-bracket-spacing': ['error', 'never'], + 'brace-style': ['error', '1tbs'], + curly: ['error', 'all'], + + //*** Node.js specifics *** + 'no-process-exit': 'error', + + // Use "require" statements in the global scope context (eg. no + // "require" statements inside functions, etc.) + //'global-require': 'error', + + // Use Buffer.from, Buffer.alloc, and Buffer.allocUnsafe instead of the + // Buffer constructor (security vulnerabilities). + 'no-buffer-constructor': 'error', + + // No Sync methods are they degrade perfs 'no-sync': 'error', + + // Disallow string concatenation when using __dirname and __filename 'no-path-concat': 'error', - // Presentation - indent: ['error', 2], - quotes: ['error', 'single', 'avoid-escape'], - 'new-cap': 'error', - camelcase: 'off', - 'no-underscore-dangle': 'off', - 'space-before-function-paren': ['warn', 'never'], + // Enforce Callback Error Handling + 'handle-callback-err': 'error', + + 'no-new-require': 'error', }, }; diff --git a/example/server.js b/example/server.js index e37e94ae..8b36f63f 100644 --- a/example/server.js +++ b/example/server.js @@ -1,12 +1,12 @@ -'use strict'; +'use strict' -const path = require('path'); -const http = require('http'); -const convict = require('../lib/convict.js'); +const path = require('path') +const http = require('http') +const convict = require('../lib/convict.js') -convict.addFormat(require('convict-format-with-validator').ipaddress); +convict.addFormat(require('convict-format-with-validator').ipaddress) -let conf = convict({ +const conf = convict({ ip: { doc: 'The IP Address to bind.', format: 'ipaddress', @@ -19,12 +19,12 @@ let conf = convict({ default: 0, env: 'PORT' } -}).loadFile(path.join(__dirname, 'config.json')).validate(); +}).loadFile(path.join(__dirname, 'config.json')).validate() -let server = http.createServer(function(req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.end('Hello World\n'); +const server = http.createServer(function(req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}) + res.end('Hello World\n') }).listen(conf.get('port'), conf.get('ip'), function() { - let addy = server.address(); - console.log('running on http://%s:%d', addy.address, addy.port); // eslint-disable-line no-console -}); + const addy = server.address() + console.log('running on http://%s:%d', addy.address, addy.port) // eslint-disable-line no-console +}) diff --git a/packages/convict-format-with-moment/.eslintrc.js b/packages/convict-format-with-moment/.eslintrc.js index a10b5725..023ee16d 100644 --- a/packages/convict-format-with-moment/.eslintrc.js +++ b/packages/convict-format-with-moment/.eslintrc.js @@ -9,28 +9,102 @@ module.exports = { mocha: true, }, rules: { - strict: ['error', 'global'], + //*** Programming best practices *** - // JavaScript core - 'no-array-constructor': 'error', - 'no-unused-vars': ['error', {'args': 'none'}], + strict: ['error', 'safe'], + semi: ['error', 'never'], + + 'no-unused-vars': ['error', {args: 'none'}], + + // Don't use "var", only use "let" and "const" + 'no-var': 'error', + // Use const if a variable is never reassigned + 'prefer-const': 'error', + + // No redeclaration of existing restricted names and builtins + 'no-shadow-restricted-names': 'error', + // No redeclaration of existing variables in outer scope + //'no-shadow': ['error', {builtinGlobals: true}], + // + // Interesting but produces less readable code … + //'no-shadow': ['error', {builtinGlobals: true, hoist: 'all'}], + + 'no-array-constructor': ['error'], + + // No dead code 'no-unreachable': 'error', - 'no-fallthrough': 'error', + + // Take full advantage of JavaScript flexibility by being able, in a + // function, to return different types (for exemple sometimes a boolean + // and sometimes an object). + 'consistent-return': 'off', + + // Disallow gratuitous parentheses + 'no-extra-parens': ['error', 'all', {conditionalAssign: false}], + + // Error best practices: + // Only throw Error instances + 'no-throw-literal': 'error', + + // Switch-case best practices 'default-case': 'error', + 'no-fallthrough': 'error', 'no-case-declarations': 'error', - 'consistent-return': 'off', - // Node.js specifics + // Enforces return statements in callbacks of array's methods + 'array-callback-return': 'error', + + 'no-console': 'error', + + //*** Presentation style *** + + indent: ['error', 2], + quotes: ['error', 'single', {avoidEscape: true}], + 'quote-props': ['error', 'as-needed'], + + // Use as much as possible snake_case for variable names and camelCase for + // function names. + camelcase: 'off', + + 'new-cap': 'error', + + 'no-multiple-empty-lines': ['error', {max: 2}], + 'no-trailing-spaces': 'error', + 'comma-spacing': ['error', {before: false, after: true}], + 'space-in-parens': ['error', 'never'], + 'keyword-spacing': 'error', + 'space-before-blocks': 'error', + 'space-infix-ops': 'error', + 'space-before-function-paren': ['error', 'never'], + 'no-spaced-func': 'error', + 'no-multi-spaces': 'error', + 'space-unary-ops': 'error', + 'object-curly-spacing': ['error', 'never'], + 'array-bracket-spacing': ['error', 'never'], + 'brace-style': ['error', '1tbs'], + curly: ['error', 'all'], + + //*** Node.js specifics *** + 'no-process-exit': 'error', + + // Use "require" statements in the global scope context (eg. no + // "require" statements inside functions, etc.) + //'global-require': 'error', + + // Use Buffer.from, Buffer.alloc, and Buffer.allocUnsafe instead of the + // Buffer constructor (security vulnerabilities). + 'no-buffer-constructor': 'error', + + // No Sync methods are they degrade perfs 'no-sync': 'error', + + // Disallow string concatenation when using __dirname and __filename 'no-path-concat': 'error', - // Presentation - indent: ['error', 2], - quotes: ['error', 'single', 'avoid-escape'], - 'new-cap': 'error', - camelcase: 'off', - 'no-underscore-dangle': 'off', - 'space-before-function-paren': ['warn', 'never'], + // Enforce Callback Error Handling + 'handle-callback-err': 'error', + + 'no-new-require': 'error', }, }; diff --git a/packages/convict-format-with-moment/lib/index.js b/packages/convict-format-with-moment/lib/index.js index 2c3329ed..684f508b 100644 --- a/packages/convict-format-with-moment/lib/index.js +++ b/packages/convict-format-with-moment/lib/index.js @@ -15,19 +15,21 @@ function assert(assertion, err_msg) { const duration = { name: 'duration', coerce: (v) => { - let split = v.split(' ') + const split = v.split(' ') if (split.length == 1) { // It must be an integer in string form. v = parseInt(v, 10) } else { // Add an "s" as the unit of measurement used in Moment - if (!split[1].match(/s$/)) split[1] += 's' + if (!split[1].match(/s$/)) { + split[1] += 's' + } v = moment.duration(parseInt(split[0], 10), split[1]).valueOf() } return v }, validate: function(x) { - let err_msg = 'must be a positive integer or human readable string (e.g. 3000, "5 days")' + const err_msg = 'must be a positive integer or human readable string (e.g. 3000, "5 days")' if (Number.isInteger(x)) { assert(x >= 0, err_msg) } else { diff --git a/packages/convict-format-with-moment/test/format-tests.js b/packages/convict-format-with-moment/test/format-tests.js index 6d3aa40f..316ddc2c 100644 --- a/packages/convict-format-with-moment/test/format-tests.js +++ b/packages/convict-format-with-moment/test/format-tests.js @@ -1,17 +1,17 @@ -'use strict'; +'use strict' -require('must'); +require('must') -const moment = require('moment'); +const moment = require('moment') describe('convict formats', function() { - const convict = require('convict'); - let conf; + const convict = require('convict') + let conf it('must add "duration" and "timestamp" format with convict-format-with-moment', function() { - convict.addFormat(require('../').duration); - convict.addFormat(require('../').timestamp); - }); + convict.addFormat(require('../').duration) + convict.addFormat(require('../').timestamp) + }) it('must parse a config specification', function() { conf = convict({ @@ -41,38 +41,44 @@ describe('convict formats', function() { default: '12345' } } - }); + }) - }); + }) it('validates default schema', function() { - (function() { conf.validate(); }).must.not.throw(); - }); + (function() { + conf.validate() + }).must.not.throw() + }) it('successfully fails to validate incorrect values', function() { conf.set('foo.duration4', '-7 days'); - (function() { conf.validate(); }).must.throw(Error, /must be a positive integer or human readable string/); + (function() { + conf.validate() + }).must.throw(Error, /must be a positive integer or human readable string/) conf.set('foo.duration5', 'zz-7zzdays'); - (function() { conf.validate(); }).must.throw(Error, /must be a positive integer or human readable string/); - }); + (function() { + conf.validate() + }).must.throw(Error, /must be a positive integer or human readable string/) + }) describe('predefined formats', function() { it('must handle timestamp', function() { - let val = conf.get('foo.date'); - val.must.be(moment('2013-05-05').valueOf()); - }); + const val = conf.get('foo.date') + val.must.be(moment('2013-05-05').valueOf()) + }) it('must handle duration in milliseconds', function() { - conf.get('foo.duration').must.be(604800000); - }); + conf.get('foo.duration').must.be(604800000) + }) it('must handle duration in a human readable string', function() { - conf.get('foo.duration2').must.be(60 * 5 * 1000); - }); + conf.get('foo.duration2').must.be(60 * 5 * 1000) + }) it('must handle duration in milliseconds as a string', function() { - conf.get('foo.duration3').must.be(12345); - }); - }); -}); + conf.get('foo.duration3').must.be(12345) + }) + }) +}) diff --git a/packages/convict-format-with-validator/.eslintrc.js b/packages/convict-format-with-validator/.eslintrc.js index a10b5725..023ee16d 100644 --- a/packages/convict-format-with-validator/.eslintrc.js +++ b/packages/convict-format-with-validator/.eslintrc.js @@ -9,28 +9,102 @@ module.exports = { mocha: true, }, rules: { - strict: ['error', 'global'], + //*** Programming best practices *** - // JavaScript core - 'no-array-constructor': 'error', - 'no-unused-vars': ['error', {'args': 'none'}], + strict: ['error', 'safe'], + semi: ['error', 'never'], + + 'no-unused-vars': ['error', {args: 'none'}], + + // Don't use "var", only use "let" and "const" + 'no-var': 'error', + // Use const if a variable is never reassigned + 'prefer-const': 'error', + + // No redeclaration of existing restricted names and builtins + 'no-shadow-restricted-names': 'error', + // No redeclaration of existing variables in outer scope + //'no-shadow': ['error', {builtinGlobals: true}], + // + // Interesting but produces less readable code … + //'no-shadow': ['error', {builtinGlobals: true, hoist: 'all'}], + + 'no-array-constructor': ['error'], + + // No dead code 'no-unreachable': 'error', - 'no-fallthrough': 'error', + + // Take full advantage of JavaScript flexibility by being able, in a + // function, to return different types (for exemple sometimes a boolean + // and sometimes an object). + 'consistent-return': 'off', + + // Disallow gratuitous parentheses + 'no-extra-parens': ['error', 'all', {conditionalAssign: false}], + + // Error best practices: + // Only throw Error instances + 'no-throw-literal': 'error', + + // Switch-case best practices 'default-case': 'error', + 'no-fallthrough': 'error', 'no-case-declarations': 'error', - 'consistent-return': 'off', - // Node.js specifics + // Enforces return statements in callbacks of array's methods + 'array-callback-return': 'error', + + 'no-console': 'error', + + //*** Presentation style *** + + indent: ['error', 2], + quotes: ['error', 'single', {avoidEscape: true}], + 'quote-props': ['error', 'as-needed'], + + // Use as much as possible snake_case for variable names and camelCase for + // function names. + camelcase: 'off', + + 'new-cap': 'error', + + 'no-multiple-empty-lines': ['error', {max: 2}], + 'no-trailing-spaces': 'error', + 'comma-spacing': ['error', {before: false, after: true}], + 'space-in-parens': ['error', 'never'], + 'keyword-spacing': 'error', + 'space-before-blocks': 'error', + 'space-infix-ops': 'error', + 'space-before-function-paren': ['error', 'never'], + 'no-spaced-func': 'error', + 'no-multi-spaces': 'error', + 'space-unary-ops': 'error', + 'object-curly-spacing': ['error', 'never'], + 'array-bracket-spacing': ['error', 'never'], + 'brace-style': ['error', '1tbs'], + curly: ['error', 'all'], + + //*** Node.js specifics *** + 'no-process-exit': 'error', + + // Use "require" statements in the global scope context (eg. no + // "require" statements inside functions, etc.) + //'global-require': 'error', + + // Use Buffer.from, Buffer.alloc, and Buffer.allocUnsafe instead of the + // Buffer constructor (security vulnerabilities). + 'no-buffer-constructor': 'error', + + // No Sync methods are they degrade perfs 'no-sync': 'error', + + // Disallow string concatenation when using __dirname and __filename 'no-path-concat': 'error', - // Presentation - indent: ['error', 2], - quotes: ['error', 'single', 'avoid-escape'], - 'new-cap': 'error', - camelcase: 'off', - 'no-underscore-dangle': 'off', - 'space-before-function-paren': ['warn', 'never'], + // Enforce Callback Error Handling + 'handle-callback-err': 'error', + + 'no-new-require': 'error', }, }; diff --git a/packages/convict-format-with-validator/lib/index.js b/packages/convict-format-with-validator/lib/index.js index 7b401a95..81aaf95f 100644 --- a/packages/convict-format-with-validator/lib/index.js +++ b/packages/convict-format-with-validator/lib/index.js @@ -4,9 +4,9 @@ */ 'use strict' -const isEmail = require('validator/lib/isEmail') -const isURL = require('validator/lib/isURL') -const isIP = require('validator/lib/isIP') +const isEmail = require('validator/lib/isEmail') +const isURL = require('validator/lib/isURL') +const isIP = require('validator/lib/isIP') function assert(assertion, err_msg) { if (!assertion) { @@ -18,7 +18,7 @@ const email = { name: 'email', coerce: (v) => v.toString(), validate: function(x) { - assert(isEmail(x), 'must be an email address'); + assert(isEmail(x), 'must be an email address') } } @@ -26,7 +26,7 @@ const ipaddress = { name: 'ipaddress', coerce: (v) => v.toString(), validate: function(x) { - assert(isIP(x), 'must be an IP address'); + assert(isIP(x), 'must be an IP address') } } @@ -34,7 +34,7 @@ const url = { name: 'url', coerce: (v) => v.toString(), validate: function(x) { - assert(isURL(x, {require_tld: false}), 'must be a URL'); + assert(isURL(x, {require_tld: false}), 'must be a URL') } } diff --git a/packages/convict-format-with-validator/test/format-tests.js b/packages/convict-format-with-validator/test/format-tests.js index 1d758840..d1301e28 100644 --- a/packages/convict-format-with-validator/test/format-tests.js +++ b/packages/convict-format-with-validator/test/format-tests.js @@ -1,14 +1,14 @@ -'use strict'; +'use strict' -require('must'); +require('must') describe('convict formats', function() { - const convict = require('convict'); - let conf; + const convict = require('convict') + let conf it('must add formats ("email", "ipaddress" and "url") with convict-format-with-validator', function() { - convict.addFormats(require('../')); - }); + convict.addFormats(require('../')) + }) it('must parse a config specification', function() { conf = convict({ @@ -26,15 +26,19 @@ describe('convict formats', function() { default: 'http://example.com' } } - }); - }); + }) + }) it('validates default schema', function() { - (function() { conf.validate(); }).must.not.throw(); - }); + (function() { + conf.validate() + }).must.not.throw() + }) it('successfully fails to validate incorrect values', function() { conf.set('foo.email', ';aaaa;'); - (function() { conf.validate(); }).must.throw(Error, /must be an email address: value was ";aaaa;"/); - }); -}); + (function() { + conf.validate() + }).must.throw(Error, /must be an email address: value was ";aaaa;"/) + }) +}) diff --git a/packages/convict/.eslintrc.js b/packages/convict/.eslintrc.js index a10b5725..023ee16d 100644 --- a/packages/convict/.eslintrc.js +++ b/packages/convict/.eslintrc.js @@ -9,28 +9,102 @@ module.exports = { mocha: true, }, rules: { - strict: ['error', 'global'], + //*** Programming best practices *** - // JavaScript core - 'no-array-constructor': 'error', - 'no-unused-vars': ['error', {'args': 'none'}], + strict: ['error', 'safe'], + semi: ['error', 'never'], + + 'no-unused-vars': ['error', {args: 'none'}], + + // Don't use "var", only use "let" and "const" + 'no-var': 'error', + // Use const if a variable is never reassigned + 'prefer-const': 'error', + + // No redeclaration of existing restricted names and builtins + 'no-shadow-restricted-names': 'error', + // No redeclaration of existing variables in outer scope + //'no-shadow': ['error', {builtinGlobals: true}], + // + // Interesting but produces less readable code … + //'no-shadow': ['error', {builtinGlobals: true, hoist: 'all'}], + + 'no-array-constructor': ['error'], + + // No dead code 'no-unreachable': 'error', - 'no-fallthrough': 'error', + + // Take full advantage of JavaScript flexibility by being able, in a + // function, to return different types (for exemple sometimes a boolean + // and sometimes an object). + 'consistent-return': 'off', + + // Disallow gratuitous parentheses + 'no-extra-parens': ['error', 'all', {conditionalAssign: false}], + + // Error best practices: + // Only throw Error instances + 'no-throw-literal': 'error', + + // Switch-case best practices 'default-case': 'error', + 'no-fallthrough': 'error', 'no-case-declarations': 'error', - 'consistent-return': 'off', - // Node.js specifics + // Enforces return statements in callbacks of array's methods + 'array-callback-return': 'error', + + 'no-console': 'error', + + //*** Presentation style *** + + indent: ['error', 2], + quotes: ['error', 'single', {avoidEscape: true}], + 'quote-props': ['error', 'as-needed'], + + // Use as much as possible snake_case for variable names and camelCase for + // function names. + camelcase: 'off', + + 'new-cap': 'error', + + 'no-multiple-empty-lines': ['error', {max: 2}], + 'no-trailing-spaces': 'error', + 'comma-spacing': ['error', {before: false, after: true}], + 'space-in-parens': ['error', 'never'], + 'keyword-spacing': 'error', + 'space-before-blocks': 'error', + 'space-infix-ops': 'error', + 'space-before-function-paren': ['error', 'never'], + 'no-spaced-func': 'error', + 'no-multi-spaces': 'error', + 'space-unary-ops': 'error', + 'object-curly-spacing': ['error', 'never'], + 'array-bracket-spacing': ['error', 'never'], + 'brace-style': ['error', '1tbs'], + curly: ['error', 'all'], + + //*** Node.js specifics *** + 'no-process-exit': 'error', + + // Use "require" statements in the global scope context (eg. no + // "require" statements inside functions, etc.) + //'global-require': 'error', + + // Use Buffer.from, Buffer.alloc, and Buffer.allocUnsafe instead of the + // Buffer constructor (security vulnerabilities). + 'no-buffer-constructor': 'error', + + // No Sync methods are they degrade perfs 'no-sync': 'error', + + // Disallow string concatenation when using __dirname and __filename 'no-path-concat': 'error', - // Presentation - indent: ['error', 2], - quotes: ['error', 'single', 'avoid-escape'], - 'new-cap': 'error', - camelcase: 'off', - 'no-underscore-dangle': 'off', - 'space-before-function-paren': ['warn', 'never'], + // Enforce Callback Error Handling + 'handle-callback-err': 'error', + + 'no-new-require': 'error', }, }; diff --git a/packages/convict/lib/convict.js b/packages/convict/lib/convict.js index 3d1db2c9..5aad9325 100644 --- a/packages/convict/lib/convict.js +++ b/packages/convict/lib/convict.js @@ -3,15 +3,15 @@ * Configuration management with support for environmental variables, files, * and validation. */ -'use strict'; +'use strict' -const fs = require('fs'); -const parseArgs = require('yargs-parser'); -const cloneDeep = require('lodash.clonedeep'); +const fs = require('fs') +const parseArgs = require('yargs-parser') +const cloneDeep = require('lodash.clonedeep') function assert(assertion, err_msg) { if (!assertion) { - throw new Error(err_msg); + throw new Error(err_msg) } } @@ -28,7 +28,7 @@ function assert(assertion, err_msg) { * @returns {Boolean} */ function isPort(x) { - return Number.isInteger(x) && x >= 0 && x <= 65535; + return Number.isInteger(x) && x >= 0 && x <= 65535 } /** @@ -39,171 +39,171 @@ function isPort(x) { * @returns {Boolean} */ function isWindowsNamedPipe(x) { - return String(x).includes('\\\\.\\pipe\\'); + return String(x).includes('\\\\.\\pipe\\') } const types = { '*': function() { }, int: function(x) { - assert(Number.isInteger(x), 'must be an integer'); + assert(Number.isInteger(x), 'must be an integer') }, nat: function(x) { - assert(Number.isInteger(x) && x >= 0, 'must be a positive integer'); + assert(Number.isInteger(x) && x >= 0, 'must be a positive integer') }, port: function(x) { - assert(isPort(x), 'ports must be within range 0 - 65535'); + assert(isPort(x), 'ports must be within range 0 - 65535') }, windows_named_pipe: function(x) { - assert(isWindowsNamedPipe(x), 'must be a valid pipe'); + assert(isWindowsNamedPipe(x), 'must be a valid pipe') }, port_or_windows_named_pipe: function(x) { if (!isWindowsNamedPipe(x)) { - assert(isPort(x), 'must be a windows named pipe or a number within range 0 - 65535'); + assert(isPort(x), 'must be a windows named pipe or a number within range 0 - 65535') } } -}; +} // alias -types.integer = types.int; +types.integer = types.int -const converters = new Map(); +const converters = new Map() -const parsers_registry = { '*': JSON.parse }; +const parsers_registry = {'*': JSON.parse} -const ALLOWED_OPTION_STRICT = 'strict'; -const ALLOWED_OPTION_WARN = 'warn'; +const ALLOWED_OPTION_STRICT = 'strict' +const ALLOWED_OPTION_WARN = 'warn' function flatten(obj, useProperties) { - let stack = Object.keys(obj); - let key; + const stack = Object.keys(obj) + let key - let entries = []; + const entries = [] while (stack.length) { - key = stack.shift(); - let val = walk(obj, key); + key = stack.shift() + let val = walk(obj, key) if (typeof val === 'object' && !Array.isArray(val) && val != null) { if (useProperties) { if ('_cvtProperties' in val) { - val = val._cvtProperties; - key = key + '._cvtProperties'; + val = val._cvtProperties + key = key + '._cvtProperties' } else { - entries.push([key, val]); - continue; + entries.push([key, val]) + continue } } - let subkeys = Object.keys(val); + const subkeys = Object.keys(val) // Don't filter out empty objects if (subkeys.length > 0) { subkeys.forEach(function(subkey) { - stack.push(key + '.' + subkey); - }); - continue; + stack.push(key + '.' + subkey) + }) + continue } } - entries.push([key, val]); + entries.push([key, val]) } - let flattened = {}; + const flattened = {} entries.forEach(function(entry) { - let key = entry[0]; + let key = entry[0] if (useProperties) { - key = key.replace(/\._cvtProperties/g, ''); + key = key.replace(/\._cvtProperties/g, '') } - const val = entry[1]; - flattened[key] = val; - }); + const val = entry[1] + flattened[key] = val + }) - return flattened; + return flattened } function validate(instance, schema, strictValidation) { - let errors = { + const errors = { undeclared: [], invalid_type: [], missing: [] - }; + } - const flatInstance = flatten(instance); - const flatSchema = flatten(schema._cvtProperties, true); + const flatInstance = flatten(instance) + const flatSchema = flatten(schema._cvtProperties, true) Object.keys(flatSchema).forEach(function(name) { - const schemaItem = flatSchema[name]; - let instanceItem = flatInstance[name]; + const schemaItem = flatSchema[name] + let instanceItem = flatInstance[name] if (!(name in flatInstance)) { try { if (typeof schemaItem.default === 'object' && !Array.isArray(schemaItem.default)) { // Missing item may be an object with undeclared children, so try to // pull it unflattened from the config instance for type validation - instanceItem = walk(instance, name); + instanceItem = walk(instance, name) } else { - throw new Error('missing'); + throw new Error('missing') } } catch (e) { const err = new Error("configuration param '" + name - + "' missing from config, did you override its parent?"); - errors.missing.push(err); - return; + + "' missing from config, did you override its parent?") + errors.missing.push(err) + return } } - delete flatInstance[name]; + delete flatInstance[name] // ignore nested keys of schema 'object' properties if (schemaItem.format === 'object' || typeof schemaItem.default === 'object') { Object.keys(flatInstance) .filter(function(key) { - return key.lastIndexOf(name + '.', 0) === 0; + return key.lastIndexOf(name + '.', 0) === 0 }).forEach(function(key) { - delete flatInstance[key]; - }); + delete flatInstance[key] + }) } if (!(typeof schemaItem.default === 'undefined' && instanceItem === schemaItem.default)) { try { - schemaItem._format(instanceItem); + schemaItem._format(instanceItem) } catch (err) { - errors.invalid_type.push(err); + errors.invalid_type.push(err) } } - return; - }); + return + }) if (strictValidation) { Object.keys(flatInstance).forEach(function(name) { const err = new Error("configuration param '" + name - + "' not declared in the schema"); - errors.undeclared.push(err); - }); + + "' not declared in the schema") + errors.undeclared.push(err) + }) } - return errors; + return errors } // helper for asserting that a value is in the list of valid options function contains(options, x) { assert(options.indexOf(x) !== -1, 'must be one of the possible values: ' + - JSON.stringify(options)); + JSON.stringify(options)) } const BUILT_INS_BY_NAME = { - 'Object': Object, - 'Array': Array, - 'String': String, - 'Number': Number, - 'Boolean': Boolean, - 'RegExp': RegExp -}; -const BUILT_IN_NAMES = Object.keys(BUILT_INS_BY_NAME); + Object: Object, + Array: Array, + String: String, + Number: Number, + Boolean: Boolean, + RegExp: RegExp +} +const BUILT_IN_NAMES = Object.keys(BUILT_INS_BY_NAME) const BUILT_INS = BUILT_IN_NAMES.map(function(name) { - return BUILT_INS_BY_NAME[name]; -}); + return BUILT_INS_BY_NAME[name] +}) function normalizeSchema(name, node, props, fullName, env, argv, sensitive) { if (name === '_cvtProperties') { - throw new Error("'" + fullName + "': '_cvtProperties' is reserved word of convict."); + throw new Error("'" + fullName + "': '_cvtProperties' is reserved word of convict.") } // If the current schema node is not a config property (has no "default"), recursively normalize it. @@ -211,110 +211,110 @@ function normalizeSchema(name, node, props, fullName, env, argv, sensitive) { Object.keys(node).length > 0 && !('default' in node)) { props[name] = { _cvtProperties: {} - }; + } Object.keys(node).forEach(function(k) { normalizeSchema(k, node[k], props[name]._cvtProperties, fullName + '.' + - k, env, argv, sensitive); - }); - return; + k, env, argv, sensitive) + }) + return } else if (typeof node !== 'object' || Array.isArray(node) || node === null || Object.keys(node).length == 0) { // Normalize shorthand "value" config properties - node = { default: node }; + node = {default: node} } - let o = cloneDeep(node); - props[name] = o; + const o = cloneDeep(node) + props[name] = o // associate this property with an environmental variable if (o.env) { if (!env[o.env]) { - env[o.env] = []; + env[o.env] = [] } - env[o.env].push(fullName); + env[o.env].push(fullName) } // associate this property with a command-line argument if (o.arg) { if (argv[o.arg]) { throw new Error("'" + fullName + "' reuses a command-line argument: " + - o.arg); + o.arg) } - argv[o.arg] = fullName; + argv[o.arg] = fullName } // mark this property as sensitive if (o.sensitive === true) { - sensitive.add(fullName); + sensitive.add(fullName) } // store original format function - let format = o.format; - let newFormat; + const format = o.format + let newFormat if (BUILT_INS.indexOf(format) >= 0 || BUILT_IN_NAMES.indexOf(format) >= 0) { // if the format property is a built-in JavaScript constructor, // assert that the value is of that type - let Format = typeof format === 'string' ? BUILT_INS_BY_NAME[format] : format; + const Format = typeof format === 'string' ? BUILT_INS_BY_NAME[format] : format newFormat = function(x) { assert(Object.prototype.toString.call(x) == Object.prototype.toString.call(new Format()), - 'must be of type ' + Format.name); - }; - o.format = Format.name.toLowerCase(); + 'must be of type ' + Format.name) + } + o.format = Format.name.toLowerCase() } else if (typeof format === 'string') { // store declared type if (!types[format]) { throw new Error("'" + fullName + "' uses an unknown format type: " + - format); + format) } // use a predefined type - newFormat = types[format]; + newFormat = types[format] } else if (Array.isArray(format)) { // assert that the value is a valid option - newFormat = contains.bind(null, format); + newFormat = contains.bind(null, format) } else if (typeof format === 'function') { - newFormat = format; + newFormat = format } else if (format && typeof format !== 'function') { throw new Error("'" + fullName + - "': `format` must be a function or a known format type."); + "': `format` must be a function or a known format type.") } if (!newFormat && !format) { // default format is the typeof the default value - let type = Object.prototype.toString.call(o.default); + const type = Object.prototype.toString.call(o.default) newFormat = function(x) { assert(Object.prototype.toString.call(x) == type, - ' should be of type ' + type.replace(/\[.* |]/g, '')); - }; + ' should be of type ' + type.replace(/\[.* |]/g, '')) + } } o._format = function(x) { try { - newFormat(x, this); + newFormat(x, this) } catch (e) { // attach the value and the property's fullName to the error - e.fullName = fullName; - e.value = x; - throw e; + e.fullName = fullName + e.value = x + throw e } - }; + } } function importEnvironment(o) { - const env = o.getEnv(); + const env = o.getEnv() Object.keys(o._env).forEach(function(envStr) { if (env[envStr] !== undefined) { - let ks = o._env[envStr]; + const ks = o._env[envStr] ks.forEach(function(k) { - o.set(k, env[envStr]); - }); + o.set(k, env[envStr]) + }) } - }); + }) } function importArguments(o) { @@ -322,136 +322,146 @@ function importArguments(o) { configuration: { 'dot-notation': false } - }); + }) Object.keys(o._argv).forEach(function(argStr) { - let k = o._argv[argStr]; + const k = o._argv[argStr] if (argv[argStr] !== undefined) { - o.set(k, String(argv[argStr])); + o.set(k, String(argv[argStr])) } - }); + }) } function addDefaultValues(schema, c, instance) { Object.keys(schema._cvtProperties).forEach(function(name) { - let p = schema._cvtProperties[name]; + const p = schema._cvtProperties[name] if (p._cvtProperties) { - let kids = c[name] || {}; - addDefaultValues(p, kids, instance); - c[name] = kids; + const kids = c[name] || {} + addDefaultValues(p, kids, instance) + c[name] = kids } else { - c[name] = coerce(name, cloneDeep(p.default), schema, instance); + c[name] = coerce(name, cloneDeep(p.default), schema, instance) } - }); + }) } -function isObj(o) { return (typeof o === 'object' && o !== null); } +function isObj(o) { + return typeof o === 'object' && o !== null +} function overlay(from, to, schema) { Object.keys(from).forEach(function(k) { // leaf if (Array.isArray(from[k]) || !isObj(from[k]) || !schema || schema.format === 'object') { - to[k] = coerce(k, from[k], schema); + to[k] = coerce(k, from[k], schema) } else { - if (!isObj(to[k])) to[k] = {}; - overlay(from[k], to[k], schema._cvtProperties[k]); + if (!isObj(to[k])) { + to[k] = {} + } + overlay(from[k], to[k], schema._cvtProperties[k]) } - }); + }) } function traverseSchema(schema, path) { - let ar = path.split('.'); - let o = schema; + const ar = path.split('.') + let o = schema while (ar.length > 0) { - let k = ar.shift(); + const k = ar.shift() if (o && o._cvtProperties && o._cvtProperties[k]) { - o = o._cvtProperties[k]; + o = o._cvtProperties[k] } else { - o = null; - break; + o = null + break } } - return o; + return o } function getFormat(schema, path) { - let o = traverseSchema(schema, path); - if (o == null) return null; - if (typeof o.format === 'string') return o.format; - if (o.default != null) return typeof o.default; - return null; + const o = traverseSchema(schema, path) + if (o == null) { + return null + } + if (typeof o.format === 'string') { + return o.format + } + if (o.default != null) { + return typeof o.default + } + return null } function coerce(k, v, schema, instance) { // magic coerceing - let format = getFormat(schema, k); + const format = getFormat(schema, k) if (typeof v === 'string') { if (converters.has(format)) { - return converters.get(format)(v, instance, k); + return converters.get(format)(v, instance, k) } switch (format) { case 'port': case 'nat': case 'integer': - case 'int': v = parseInt(v, 10); break; - case 'port_or_windows_named_pipe': v = isWindowsNamedPipe(v) ? v : parseInt(v, 10); break; - case 'number': v = parseFloat(v); break; - case 'boolean': v = (String(v).toLowerCase() !== 'false'); break; - case 'array': v = v.split(','); break; - case 'object': v = JSON.parse(v); break; - case 'regexp': v = new RegExp(v); break; + case 'int': v = parseInt(v, 10); break + case 'port_or_windows_named_pipe': v = isWindowsNamedPipe(v) ? v : parseInt(v, 10); break + case 'number': v = parseFloat(v); break + case 'boolean': v = String(v).toLowerCase() !== 'false'; break + case 'array': v = v.split(','); break + case 'object': v = JSON.parse(v); break + case 'regexp': v = new RegExp(v); break default: // TODO: Should we throw an exception here? } } - return v; + return v } function loadFile(path) { - const segments = path.split('.'); - const extension = segments.length > 1 ? segments.pop() : ''; - const parse = parsers_registry[extension] || parsers_registry['*']; + const segments = path.split('.') + const extension = segments.length > 1 ? segments.pop() : '' + const parse = parsers_registry[extension] || parsers_registry['*'] // TODO Get rid of the sync call // eslint-disable-next-line no-sync - return parse(fs.readFileSync(path, 'utf-8')); + return parse(fs.readFileSync(path, 'utf-8')) } function walk(obj, path, initializeMissing) { if (path) { - let ar = path.split('.'); + const ar = path.split('.') while (ar.length) { - let k = ar.shift(); + const k = ar.shift() if (initializeMissing && obj[k] == null) { - obj[k] = {}; - obj = obj[k]; + obj[k] = {} + obj = obj[k] } else if (k in obj) { - obj = obj[k]; + obj = obj[k] } else { - throw new Error("cannot find configuration param '" + path + "'"); + throw new Error("cannot find configuration param '" + path + "'") } } } - return obj; + return obj } /** * @returns a config object */ -let convict = function convict(def, opts) { +const convict = function convict(def, opts) { // TODO: Rename this `rv` variable (supposedly "return value") into something // more meaningful. - let rv = { + const rv = { /** * Gets the array of process arguments, using the override passed to the * convict function or process.argv if no override was passed. */ getArgs: function() { - return (opts && opts.args) || process.argv.slice(2); + return opts && opts.args || process.argv.slice(2) }, /** @@ -459,14 +469,14 @@ let convict = function convict(def, opts) { * convict function or process.env if no override was passed. */ getEnv: function() { - return (opts && opts.env) || process.env; + return opts && opts.env || process.env }, /** * Exports all the properties (that is the keys and their current values) as JSON */ getProperties: function() { - return cloneDeep(this._instance); + return cloneDeep(this._instance) }, /** @@ -475,29 +485,29 @@ let convict = function convict(def, opts) { * even if they aren't set, to avoid revealing any information. */ toString: function() { - let clone = cloneDeep(this._instance); + const clone = cloneDeep(this._instance) this._sensitive.forEach(function(key) { - let path = key.split('.'); - let childKey = path.pop(); - let parentKey = path.join('.'); - let parent = walk(clone, parentKey); - parent[childKey] = '[Sensitive]'; - }); - return JSON.stringify(clone, null, 2); + const path = key.split('.') + const childKey = path.pop() + const parentKey = path.join('.') + const parent = walk(clone, parentKey) + parent[childKey] = '[Sensitive]' + }) + return JSON.stringify(clone, null, 2) }, /** * Exports the schema as JSON. */ getSchema: function() { - return JSON.parse(JSON.stringify(this._schema)); + return JSON.parse(JSON.stringify(this._schema)) }, /** * Exports the schema as a JSON string */ getSchemaString: function() { - return JSON.stringify(this._schema, null, 2); + return JSON.stringify(this._schema, null, 2) }, /** @@ -505,8 +515,8 @@ let convict = function convict(def, opts) { * notation to reference nested values */ get: function(path) { - let o = walk(this._instance, path); - return cloneDeep(o); + const o = walk(this._instance, path) + return cloneDeep(o) }, /** @@ -516,16 +526,16 @@ let convict = function convict(def, opts) { default: function(path) { // The default value for FOO.BAR.BAZ is stored in `_schema._cvtProperties` at: // FOO._cvtProperties.BAR._cvtProperties.BAZ.default - path = (path.split('.').join('._cvtProperties.')) + '.default'; - let o = walk(this._schema._cvtProperties, path); - return cloneDeep(o); + path = path.split('.').join('._cvtProperties.') + '.default' + const o = walk(this._schema._cvtProperties, path) + return cloneDeep(o) }, /** * Resets a property to its default value as defined in the schema */ reset: function(prop_name) { - this.set(prop_name, this.default(prop_name)); + this.set(prop_name, this.default(prop_name)) }, /** @@ -533,11 +543,11 @@ let convict = function convict(def, opts) { */ has: function(path) { try { - let r = this.get(path); + const r = this.get(path) // values that are set but undefined return false - return typeof r !== 'undefined'; + return typeof r !== 'undefined' } catch (e) { - return false; + return false } }, @@ -547,191 +557,213 @@ let convict = function convict(def, opts) { * exist, they will be initialized to empty objects */ set: function(k, v) { - v = coerce(k, v, this._schema, this); - let path = k.split('.'); - let childKey = path.pop(); - let parentKey = path.join('.'); - let parent = walk(this._instance, parentKey, true); - parent[childKey] = v; - return this; + v = coerce(k, v, this._schema, this) + const path = k.split('.') + const childKey = path.pop() + const parentKey = path.join('.') + const parent = walk(this._instance, parentKey, true) + parent[childKey] = v + return this }, /** * Loads and merges a JavaScript object into config */ load: function(conf) { - overlay(conf, this._instance, this._schema); + overlay(conf, this._instance, this._schema) // environment and arguments always overrides config files - importEnvironment(rv); - importArguments(rv); - return this; + importEnvironment(rv) + importArguments(rv) + return this }, /** * Loads and merges one or multiple JSON configuration files into config */ loadFile: function(paths) { - let self = this; - if (!Array.isArray(paths)) paths = [paths]; + const self = this + if (!Array.isArray(paths)) { + paths = [paths] + } paths.forEach(function(path) { // Support empty config files #253 - const result = loadFile(path); + const result = loadFile(path) if (result) { - overlay(result, self._instance, self._schema); + overlay(result, self._instance, self._schema) } - }); + }) // environment and arguments always overrides config files - importEnvironment(rv); - importArguments(rv); - return this; + importEnvironment(rv) + importArguments(rv) + return this }, /** * Validates config against the schema used to initialize it */ validate: function(options) { - options = options || {}; + options = options || {} - options.allowed = options.allowed || ALLOWED_OPTION_WARN; + options.allowed = options.allowed || ALLOWED_OPTION_WARN if (options.output && typeof options.output !== 'function') { - throw new Error('options.output is optionnal and must be a function.'); + throw new Error('options.output is optionnal and must be a function.') } - const output_function = options.output || global.console.log; + const output_function = options.output || global.console.log - let errors = validate(this._instance, this._schema, options.allowed); + const errors = validate(this._instance, this._schema, options.allowed) if (errors.invalid_type.length + errors.undeclared.length + errors.missing.length) { - let sensitive = this._sensitive; + const sensitive = this._sensitive - let fillErrorBuffer = function(errors) { - let err_buf = ''; + const fillErrorBuffer = function(errors) { + let err_buf = '' for (let i = 0; i < errors.length; i++) { - if (err_buf.length) err_buf += '\n'; + if (err_buf.length) { + err_buf += '\n' + } - let e = errors[i]; + const e = errors[i] if (e.fullName) { - err_buf += e.fullName + ': '; + err_buf += e.fullName + ': ' + } + if (e.message) { + err_buf += e.message } - if (e.message) err_buf += e.message; if (e.value && !sensitive.has(e.fullName)) { - err_buf += ': value was ' + JSON.stringify(e.value); + err_buf += ': value was ' + JSON.stringify(e.value) } } - return err_buf; - }; + return err_buf + } - const types_err_buf = fillErrorBuffer(errors.invalid_type); - const params_err_buf = fillErrorBuffer(errors.undeclared); - const missing_err_buf = fillErrorBuffer(errors.missing); + const types_err_buf = fillErrorBuffer(errors.invalid_type) + const params_err_buf = fillErrorBuffer(errors.undeclared) + const missing_err_buf = fillErrorBuffer(errors.missing) - let output_err_bufs = [types_err_buf, missing_err_buf]; + const output_err_bufs = [types_err_buf, missing_err_buf] if (options.allowed === ALLOWED_OPTION_WARN && params_err_buf.length) { - let warning = 'Warning:'; + let warning = 'Warning:' if (process.stdout.isTTY) { // Write 'Warning:' in bold and in yellow - const SET_BOLD_YELLOW_TEXT = '\x1b[33;1m'; - const RESET_ALL_ATTRIBUTES = '\x1b[0m'; - warning = SET_BOLD_YELLOW_TEXT + warning + RESET_ALL_ATTRIBUTES; + const SET_BOLD_YELLOW_TEXT = '\x1b[33;1m' + const RESET_ALL_ATTRIBUTES = '\x1b[0m' + warning = SET_BOLD_YELLOW_TEXT + warning + RESET_ALL_ATTRIBUTES } - output_function(warning + ' ' + params_err_buf); + output_function(warning + ' ' + params_err_buf) } else if (options.allowed === ALLOWED_OPTION_STRICT) { - output_err_bufs.push(params_err_buf); + output_err_bufs.push(params_err_buf) } - let output = output_err_bufs - .filter(function(str) { return str.length; }) - .join('\n'); + const output = output_err_bufs + .filter(function(str) { + return str.length + }) + .join('\n') - if(output.length) { - throw new Error(output); + if (output.length) { + throw new Error(output) } } - return this; + return this } - }; + } // If the definition is a string treat it as an external schema file if (typeof def === 'string') { - rv._def = loadFile(def); + rv._def = loadFile(def) } else { - rv._def = def; + rv._def = def } // build up current config from definition rv._schema = { _cvtProperties: {} - }; + } - rv._env = {}; - rv._argv = {}; - rv._sensitive = new Set(); + rv._env = {} + rv._argv = {} + rv._sensitive = new Set() Object.keys(rv._def).forEach(function(k) { normalizeSchema(k, rv._def[k], rv._schema._cvtProperties, k, rv._env, rv._argv, - rv._sensitive); - }); + rv._sensitive) + }) - rv._instance = {}; - addDefaultValues(rv._schema, rv._instance, rv); - importEnvironment(rv); - importArguments(rv); + rv._instance = {} + addDefaultValues(rv._schema, rv._instance, rv) + importEnvironment(rv) + importArguments(rv) - return rv; -}; + return rv +} /** * Adds a new custom format */ convict.addFormat = function(name, validate, coerce) { if (typeof name === 'object') { - validate = name.validate; - coerce = name.coerce; - name = name.name; + validate = name.validate + coerce = name.coerce + name = name.name } if (typeof validate !== 'function') { - throw new Error('Validation function for ' + name + ' must be a function.'); + throw new Error('Validation function for ' + name + ' must be a function.') } if (coerce && typeof coerce !== 'function') { - throw new Error('Coerce function for ' + name + ' must be a function.'); + throw new Error('Coerce function for ' + name + ' must be a function.') } - types[name] = validate; - if (coerce) converters.set(name, coerce); -}; + types[name] = validate + if (coerce) { + converters.set(name, coerce) + } +} /** * Adds new custom formats */ convict.addFormats = function(formats) { Object.keys(formats).forEach(function(type) { - convict.addFormat(type, formats[type].validate, formats[type].coerce); - }); -}; + convict.addFormat(type, formats[type].validate, formats[type].coerce) + }) +} /** * Adds a new custom file parser */ convict.addParser = function(parsers) { - if (!Array.isArray(parsers)) parsers = [parsers]; + if (!Array.isArray(parsers)) { + parsers = [parsers] + } parsers.forEach(function(parser) { - if (!parser) throw new Error('Invalid parser'); - if (!parser.extension) throw new Error('Missing parser.extension'); - if (!parser.parse) throw new Error('Missing parser.parse function'); + if (!parser) { + throw new Error('Invalid parser') + } + if (!parser.extension) { + throw new Error('Missing parser.extension') + } + if (!parser.parse) { + throw new Error('Missing parser.parse function') + } - if (typeof parser.parse !== 'function') throw new Error('Invalid parser.parse function'); + if (typeof parser.parse !== 'function') { + throw new Error('Invalid parser.parse function') + } - const extensions = !Array.isArray(parser.extension) ? [parser.extension] : parser.extension; + const extensions = !Array.isArray(parser.extension) ? [parser.extension] : parser.extension extensions.forEach(function(extension) { - if (typeof extension !== 'string') throw new Error('Invalid parser.extension'); - parsers_registry[extension] = parser.parse; - }); - }); -}; + if (typeof extension !== 'string') { + throw new Error('Invalid parser.extension') + } + parsers_registry[extension] = parser.parse + }) + }) +} -module.exports = convict; +module.exports = convict diff --git a/packages/convict/test/cases/argv_basic.js b/packages/convict/test/cases/argv_basic.js index 8ceb17c8..4b8329b9 100644 --- a/packages/convict/test/cases/argv_basic.js +++ b/packages/convict/test/cases/argv_basic.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { foo: { @@ -11,6 +11,6 @@ exports.conf = { format: 'port', arg: 'port' } -}; +} -exports.argv = '--foo bar --port 8080'; +exports.argv = '--foo bar --port 8080' diff --git a/packages/convict/test/cases/argv_dot_notation.js b/packages/convict/test/cases/argv_dot_notation.js index 069fab8f..490a09d5 100644 --- a/packages/convict/test/cases/argv_dot_notation.js +++ b/packages/convict/test/cases/argv_dot_notation.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { server: { @@ -15,6 +15,6 @@ exports.conf = { arg: 'ui.port' } } -}; +} -exports.argv = '--server.port 5000 --ui.port 4000'; +exports.argv = '--server.port 5000 --ui.port 4000' diff --git a/packages/convict/test/cases/argv_format_nodefault.js b/packages/convict/test/cases/argv_format_nodefault.js index 30b4a20c..2d2048b4 100644 --- a/packages/convict/test/cases/argv_format_nodefault.js +++ b/packages/convict/test/cases/argv_format_nodefault.js @@ -1,15 +1,15 @@ -'use strict'; +'use strict' exports.conf = { url: { default: null, format: function(value) { if (value == null) { - throw new Error('The url argument must be provided'); + throw new Error('The url argument must be provided') } }, arg: 'url' } -}; +} -exports.argv = '--url www.github.com'; +exports.argv = '--url www.github.com' diff --git a/packages/convict/test/cases/argv_precedent.js b/packages/convict/test/cases/argv_precedent.js index ae389c2e..42cf9526 100644 --- a/packages/convict/test/cases/argv_precedent.js +++ b/packages/convict/test/cases/argv_precedent.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { foo: { @@ -7,10 +7,10 @@ exports.conf = { env: 'FOO', arg: 'foo' } -}; +} exports.env = { FOO: 'c' -}; +} -exports.argv = '--foo d'; +exports.argv = '--foo d' diff --git a/packages/convict/test/cases/argv_types.js b/packages/convict/test/cases/argv_types.js index f52a1510..3234f263 100644 --- a/packages/convict/test/cases/argv_types.js +++ b/packages/convict/test/cases/argv_types.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { boolTrue: { @@ -56,7 +56,7 @@ exports.conf = { format: RegExp, arg: 'regexp' } -}; +} exports.argv = [ '--booltrue', 'true', diff --git a/packages/convict/test/cases/argv_unused.js b/packages/convict/test/cases/argv_unused.js index 50622bd1..a76456f6 100644 --- a/packages/convict/test/cases/argv_unused.js +++ b/packages/convict/test/cases/argv_unused.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { foo: { @@ -6,4 +6,4 @@ exports.conf = { format: String, arg: 'foo' }, -}; +} diff --git a/packages/convict/test/cases/array.js b/packages/convict/test/cases/array.js index cc106050..ca899026 100644 --- a/packages/convict/test/cases/array.js +++ b/packages/convict/test/cases/array.js @@ -1,8 +1,8 @@ -'use strict'; +'use strict' exports.conf = { arr: { default: [], format: Array } -}; +} diff --git a/packages/convict/test/cases/basic.js b/packages/convict/test/cases/basic.js index ea37bd09..05846f32 100644 --- a/packages/convict/test/cases/basic.js +++ b/packages/convict/test/cases/basic.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { env: { @@ -24,4 +24,4 @@ exports.conf = { default: '/home/browserid/var', doc: 'The path the the "var" directory, where logs and such will go' } -}; +} diff --git a/packages/convict/test/cases/boolean.js b/packages/convict/test/cases/boolean.js index 0dfa0a2f..ddc1ed24 100644 --- a/packages/convict/test/cases/boolean.js +++ b/packages/convict/test/cases/boolean.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { true: { @@ -29,4 +29,4 @@ exports.conf = { default: null } } -}; +} diff --git a/packages/convict/test/cases/coerce_aggregate.js b/packages/convict/test/cases/coerce_aggregate.js index 2da9b3b9..2f7f9361 100644 --- a/packages/convict/test/cases/coerce_aggregate.js +++ b/packages/convict/test/cases/coerce_aggregate.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { nested: { @@ -16,16 +16,16 @@ exports.formats = { map: { validate: function(value) { if (typeof value !== 'object') { - throw new Error('must be a map of key/value pairs'); + throw new Error('must be a map of key/value pairs') } }, coerce: function(value, config, path) { - const accum = config.get(path); + const accum = config.get(path) value.split(',').forEach(function(pair) { - const [k, v] = pair.split('='); - accum[k] = v; + const [k, v] = pair.split('=') + accum[k] = v }) - return accum; + return accum } } } diff --git a/packages/convict/test/cases/coerce_placeholder.js b/packages/convict/test/cases/coerce_placeholder.js index 7bd348b6..36ad3ba6 100644 --- a/packages/convict/test/cases/coerce_placeholder.js +++ b/packages/convict/test/cases/coerce_placeholder.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { env: { @@ -29,17 +29,19 @@ exports.conf = { default: '${configPath}/${env}.json', doc: 'Path to configuration file. Defaults to ${configPath}/${env}.json' } -}; +} exports.env = { env: 'local' -}; +} exports.formats = { placeholder: { validate: function() { }, coerce: function(value, config) { - return value.replace(/\$\{([\w.]+)}/g, function(v,m) { return config.get(m); }); + return value.replace(/\$\{([\w.]+)}/g, function(v, m) { + return config.get(m) + }) } } -}; +} diff --git a/packages/convict/test/cases/complex.js b/packages/convict/test/cases/complex.js index 0b305059..6afae54d 100644 --- a/packages/convict/test/cases/complex.js +++ b/packages/convict/test/cases/complex.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { env: { @@ -31,8 +31,8 @@ exports.conf = { }, disable_primary_support: false, enable_code_version: false, - default_lang: [ 'en-US' ], - supported_languages: [ 'en-US' ], + default_lang: ['en-US'], + supported_languages: ['en-US'], locale_directory: 'locale', express_log_format: 'default' -}; +} diff --git a/packages/convict/test/cases/default_shorthand.js b/packages/convict/test/cases/default_shorthand.js index 664ecdcb..6d4707f5 100644 --- a/packages/convict/test/cases/default_shorthand.js +++ b/packages/convict/test/cases/default_shorthand.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { bool: false, @@ -11,4 +11,4 @@ exports.conf = { }, null: null, emptyObject: {} -}; +} diff --git a/packages/convict/test/cases/empty_string_over_default.js b/packages/convict/test/cases/empty_string_over_default.js index 586061f9..3c5caaed 100644 --- a/packages/convict/test/cases/empty_string_over_default.js +++ b/packages/convict/test/cases/empty_string_over_default.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { prefix: { @@ -11,10 +11,10 @@ exports.conf = { format: String, arg: 'suffix' }, -}; +} exports.env = { PREFIX: '', -}; +} exports.argv = ['node', 'index.js', '--suffix='] diff --git a/packages/convict/test/cases/env_basic.js b/packages/convict/test/cases/env_basic.js index aa851971..6ef0f9cc 100644 --- a/packages/convict/test/cases/env_basic.js +++ b/packages/convict/test/cases/env_basic.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { foo: { @@ -11,9 +11,9 @@ exports.conf = { format: 'port', env: 'PORT' } -}; +} exports.env = { FOO: 'Yoyodyne', PORT: 8080 -}; +} diff --git a/packages/convict/test/cases/env_multi.js b/packages/convict/test/cases/env_multi.js index 2ac6c043..4f04cd51 100644 --- a/packages/convict/test/cases/env_multi.js +++ b/packages/convict/test/cases/env_multi.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { foo: { @@ -11,7 +11,7 @@ exports.conf = { format: String, env: 'FOO' }, -}; +} exports.env = { FOO: 'b' -}; +} diff --git a/packages/convict/test/cases/env_precedent.js b/packages/convict/test/cases/env_precedent.js index 958c4e8c..a5c86321 100644 --- a/packages/convict/test/cases/env_precedent.js +++ b/packages/convict/test/cases/env_precedent.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { foo: { @@ -6,8 +6,8 @@ exports.conf = { format: String, env: 'FOO' } -}; +} exports.env = { FOO: 'c' -}; +} diff --git a/packages/convict/test/cases/env_syntax.js b/packages/convict/test/cases/env_syntax.js index c01db4bd..ef382fac 100644 --- a/packages/convict/test/cases/env_syntax.js +++ b/packages/convict/test/cases/env_syntax.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { foo: { @@ -8,8 +8,8 @@ exports.conf = { env: 'BAR' } } -}; +} exports.env = { BAR: 'c' // hey! that's not an allowable value! -}; +} diff --git a/packages/convict/test/cases/env_types.js b/packages/convict/test/cases/env_types.js index cc348f15..e433789d 100644 --- a/packages/convict/test/cases/env_types.js +++ b/packages/convict/test/cases/env_types.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { boolTrue: { @@ -51,7 +51,7 @@ exports.conf = { format: RegExp, env: 'REGEXP' } -}; +} exports.env = { BOOLTRUE: true, @@ -64,4 +64,4 @@ exports.env = { ARRAY: 'a,b,c', OBJECT: '{"foo": "bar"}', REGEXP: '^foo$' -}; +} diff --git a/packages/convict/test/cases/file_basic.js b/packages/convict/test/cases/file_basic.js index 1f212511..b032310d 100644 --- a/packages/convict/test/cases/file_basic.js +++ b/packages/convict/test/cases/file_basic.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { foo: { @@ -18,4 +18,4 @@ exports.conf = { env: 'MAX_COUNT', doc: 'Maximum number of elements allowed.' } -}; +} diff --git a/packages/convict/test/cases/file_object.js b/packages/convict/test/cases/file_object.js index 817fbf5c..723c6b65 100644 --- a/packages/convict/test/cases/file_object.js +++ b/packages/convict/test/cases/file_object.js @@ -1,9 +1,9 @@ -'use strict'; +'use strict' exports.conf = { single: { format: Object, - default: { test: 0 } + default: {test: 0} }, nested: { object: { @@ -12,4 +12,4 @@ exports.conf = { default: {} } } -}; +} diff --git a/packages/convict/test/cases/format_error_nomsg.js b/packages/convict/test/cases/format_error_nomsg.js index 0d0704af..afd44d15 100644 --- a/packages/convict/test/cases/format_error_nomsg.js +++ b/packages/convict/test/cases/format_error_nomsg.js @@ -1,10 +1,10 @@ -'use strict'; +'use strict' exports.conf = { noDefault: { default: null, format: function(value) { - throw new Error(); + throw new Error() } } -}; +} diff --git a/packages/convict/test/cases/formats/out.js b/packages/convict/test/cases/formats/out.js index 6f9e9aca..bbb680d9 100644 --- a/packages/convict/test/cases/formats/out.js +++ b/packages/convict/test/cases/formats/out.js @@ -1,5 +1,5 @@ -'use strict'; +'use strict' module.exports = { data: 'lorem ispum' -}; +} diff --git a/packages/convict/test/cases/formats/schema.js b/packages/convict/test/cases/formats/schema.js index ba977a3a..8c1914d2 100644 --- a/packages/convict/test/cases/formats/schema.js +++ b/packages/convict/test/cases/formats/schema.js @@ -1,8 +1,8 @@ -'use strict'; +'use strict' module.exports = { data: { format: '*', default: undefined }, -}; +} diff --git a/packages/convict/test/cases/invalid_coerce.js b/packages/convict/test/cases/invalid_coerce.js index 003c70a3..46b9e3de 100644 --- a/packages/convict/test/cases/invalid_coerce.js +++ b/packages/convict/test/cases/invalid_coerce.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { invalidCoercer: { @@ -6,11 +6,11 @@ exports.conf = { default: 'invalidCoercer', doc: 'A value with an invalid coercer' } -}; +} exports.formats = { invalidCoercer: { validate: function() {}, coerce: true } -}; +} diff --git a/packages/convict/test/cases/invalid_format.js b/packages/convict/test/cases/invalid_format.js index f492582b..d4d4f37f 100644 --- a/packages/convict/test/cases/invalid_format.js +++ b/packages/convict/test/cases/invalid_format.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { invalidFormat: { @@ -6,4 +6,4 @@ exports.conf = { default: 'invalidFormat', doc: 'A value with an invalid format' } -}; +} diff --git a/packages/convict/test/cases/invalid_validate.js b/packages/convict/test/cases/invalid_validate.js index 945c9118..5d02c9f3 100644 --- a/packages/convict/test/cases/invalid_validate.js +++ b/packages/convict/test/cases/invalid_validate.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { invalidValidator: { @@ -6,10 +6,12 @@ exports.conf = { default: 'invalidValidator', doc: 'A value with an invalid validator' } -}; +} exports.formats = { invalidValidator: { - coerce: function(value) { return value; } + coerce: function(value) { + return value + } } -}; +} diff --git a/packages/convict/test/cases/nested_override.js b/packages/convict/test/cases/nested_override.js index 6d5ba6a2..63835854 100644 --- a/packages/convict/test/cases/nested_override.js +++ b/packages/convict/test/cases/nested_override.js @@ -1,8 +1,8 @@ -'use strict'; +'use strict' exports.conf = { object: { default: null, format: '*' } -}; +} diff --git a/packages/convict/test/cases/nesting.js b/packages/convict/test/cases/nesting.js index efa3b819..ebaea3f1 100644 --- a/packages/convict/test/cases/nesting.js +++ b/packages/convict/test/cases/nesting.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { top: { @@ -11,4 +11,4 @@ exports.conf = { }, internal_leaf: 'baz' } -}; +} diff --git a/packages/convict/test/cases/replace_parent.js b/packages/convict/test/cases/replace_parent.js index 80386d83..e1841cf5 100644 --- a/packages/convict/test/cases/replace_parent.js +++ b/packages/convict/test/cases/replace_parent.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { top: { @@ -6,4 +6,4 @@ exports.conf = { leaf: 'foo', } } -}; +} diff --git a/packages/convict/test/cases/schema-object.js b/packages/convict/test/cases/schema-object.js index 686ca84f..156a9657 100644 --- a/packages/convict/test/cases/schema-object.js +++ b/packages/convict/test/cases/schema-object.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { shorthand: 'value', @@ -40,4 +40,4 @@ exports.conf = { nested: { child: 'ababa' } -}; +} diff --git a/packages/convict/test/cases/sensitive_basic.js b/packages/convict/test/cases/sensitive_basic.js index 91afa493..dda01c07 100644 --- a/packages/convict/test/cases/sensitive_basic.js +++ b/packages/convict/test/cases/sensitive_basic.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { public: { @@ -23,4 +23,4 @@ exports.conf = { doc: 'A sensitive value that defaults to null', sensitive: true } -}; +} diff --git a/packages/convict/test/cases/sensitive_nested.js b/packages/convict/test/cases/sensitive_nested.js index 23fa768a..7d01be29 100644 --- a/packages/convict/test/cases/sensitive_nested.js +++ b/packages/convict/test/cases/sensitive_nested.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { item: { @@ -14,4 +14,4 @@ exports.conf = { sensitive: true } } -}; +} diff --git a/packages/convict/test/cases/sensitive_validation.js b/packages/convict/test/cases/sensitive_validation.js index 55857e58..aaf95c99 100644 --- a/packages/convict/test/cases/sensitive_validation.js +++ b/packages/convict/test/cases/sensitive_validation.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { public: { @@ -12,4 +12,4 @@ exports.conf = { doc: 'A sensitive value', sensitive: true } -}; +} diff --git a/packages/convict/test/cases/unknown_format.js b/packages/convict/test/cases/unknown_format.js index c0fb9633..a41a9703 100644 --- a/packages/convict/test/cases/unknown_format.js +++ b/packages/convict/test/cases/unknown_format.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' exports.conf = { unknownFormat: { @@ -6,4 +6,4 @@ exports.conf = { default: 'unknownFormat', doc: 'A value with an unknown format' } -}; +} diff --git a/packages/convict/test/cli-tests.js b/packages/convict/test/cli-tests.js index d60a4215..1670c1ab 100644 --- a/packages/convict/test/cli-tests.js +++ b/packages/convict/test/cli-tests.js @@ -1,128 +1,132 @@ -'use strict'; +'use strict' /*eslint no-sync: 0*/ -const fs = require('fs'); -const path = require('path'); -const cp = require('child_process'); -const diff = require('deep-object-diff').diff; +const fs = require('fs') +const path = require('path') +const cp = require('child_process') +const diff = require('deep-object-diff').diff // This test finds its cases in /test/cases -const cases_dir_path = path.join(__dirname, 'cases'); -let files = fs.readdirSync(cases_dir_path); +const cases_dir_path = path.join(__dirname, 'cases') +const files = fs.readdirSync(cases_dir_path) -let tests = {}; +const tests = {} files.forEach(function(f) { - let m = /^([a-zA-Z_\-0-9]+)\.js$/.exec(f); - if (m) tests[m[1]] = { - spec: f, - output: m[1] + '.out', - outputString: m[1] + '.string', - outputSchema: m[1] + '.schema', - config_files: [] - }; -}); + const m = /^([a-zA-Z_\-0-9]+)\.js$/.exec(f) + if (m) { + tests[m[1]] = { + spec: f, + output: m[1] + '.out', + outputString: m[1] + '.string', + outputSchema: m[1] + '.schema', + config_files: [] + } + } +}) // now find all configuration files for all tests Object.keys(tests).forEach(function(test) { - let re = new RegExp('^' + test + '.*\\.json$'); + const re = new RegExp('^' + test + '.*\\.json$') files.forEach(function(f) { - if (re.test(f)) tests[test].config_files.push(path.join(cases_dir_path, f)); - }); - tests[test].config_files.sort(); -}); + if (re.test(f)) { + tests[test].config_files.push(path.join(cases_dir_path, f)) + } + }) + tests[test].config_files.sort() +}) function diffObjects(a, b) { - let res = diff(a, b); + const res = diff(a, b) if (Object.keys(res).length) { - return 'mismatch: ' + JSON.stringify(res, null, 4); + return 'mismatch: ' + JSON.stringify(res, null, 4) } - return null; + return null } // time to run! -let toRun = Object.keys(tests); +const toRun = Object.keys(tests) function run(name, done) { - let test = tests[name]; + const test = tests[name] - let kase = require(path.join(cases_dir_path, test.spec)); + const kase = require(path.join(cases_dir_path, test.spec)) - let env = kase.env || {}; - let argv = kase.argv || []; + const env = kase.env || {} + let argv = kase.argv || [] if (!Array.isArray(argv)) { - argv = argv.split(' '); + argv = argv.split(' ') } - let exec = path.join(__dirname, 'lib/runner.js'); + let exec = path.join(__dirname, 'lib/runner.js') if (process.env.running_under_istanbul) { argv = ['cover', '--report', 'none', '--print', 'none', '--include-pid', - exec, '--'].concat(argv); - exec = path.join(__dirname, '..', 'node_modules', '.bin', 'istanbul'); + exec, '--'].concat(argv) + exec = path.join(__dirname, '..', 'node_modules', '.bin', 'istanbul') } - let n = cp.fork(exec, argv, {env: env}); + const n = cp.fork(exec, argv, {env: env}) n.on('message', function(m) { if (m.ready) { - n.send(tests[name]); - return; + n.send(tests[name]) + return } - let expected; - let got; - let errs = []; + let expected + let got + const errs = [] try { if (!m.error) { // let's read the expected output - expected = JSON.parse(fs.readFileSync(path.join(cases_dir_path, test.output))); - got = m.result; + expected = JSON.parse(fs.readFileSync(path.join(cases_dir_path, test.output))) + got = m.result // check that configuration is what we expect - let err = diffObjects(expected, got); + const err = diffObjects(expected, got) if (err) { - errs.push(`get ${err}`); + errs.push(`get ${err}`) } if (fs.existsSync(path.join(cases_dir_path, test.outputString))) { - expected = JSON.parse(fs.readFileSync(path.join(cases_dir_path, test.outputString))); - got = JSON.parse(m.string); - let err = diffObjects(expected, got); + expected = JSON.parse(fs.readFileSync(path.join(cases_dir_path, test.outputString))) + got = JSON.parse(m.string) + const err = diffObjects(expected, got) if (err) { - errs.push(`toString ${err}`); + errs.push(`toString ${err}`) } } if (fs.existsSync(path.join(cases_dir_path, test.outputSchema))) { expected = JSON.parse(fs.readFileSync(path.join(cases_dir_path, - test.outputSchema))); - got = m.schema; - let err = diffObjects(expected, got); + test.outputSchema))) + got = m.schema + const err = diffObjects(expected, got) if (err) { - errs.push(`getSchema ${err}`); + errs.push(`getSchema ${err}`) } } - if(errs.length > 0) { - throw new Error(errs.join('\n')); + if (errs.length > 0) { + throw new Error(errs.join('\n')) } - return done(); + return done() } else { - expected = fs.readFileSync(path.join(cases_dir_path, test.output)).toString().trim(); - got = m.error.trim(); + expected = fs.readFileSync(path.join(cases_dir_path, test.output)).toString().trim() + got = m.error.trim() // EOL for new line and windows support: - expected = expected.split(require('os').EOL).join('\n'); - require('assert').strictEqual(got, expected, `must be pass ${name}`); - return done(); + expected = expected.split(require('os').EOL).join('\n') + require('assert').strictEqual(got, expected, `must be pass ${name}`) + return done() } - } catch(e) { - return done(e); + } catch (e) { + return done(e) } - }); + }) } describe('CLI tests', function() { toRun.forEach(function(name) { it(name, function(done) { - run(name, done); - }); - }); -}); + run(name, done) + }) + }) +}) diff --git a/packages/convict/test/format-tests.js b/packages/convict/test/format-tests.js index 61ef0e30..22b51558 100644 --- a/packages/convict/test/format-tests.js +++ b/packages/convict/test/format-tests.js @@ -1,10 +1,10 @@ -'use strict'; +'use strict' -const expect = require('must'); +const expect = require('must') describe('convict formats', function() { - const convict = require('../'); - let conf; + const convict = require('../') + let conf it('must parse a config specification', function() { @@ -12,38 +12,44 @@ describe('convict formats', function() { name: 'float-percent', validate: function(val) { if (val !== 0 && (!val || val > 1 || val < 0)) { - throw new Error('must be a float between 0 and 1, inclusive'); + throw new Error('must be a float between 0 and 1, inclusive') } }, coerce: function(val) { - return parseFloat(val, 10); + return parseFloat(val, 10) } - }); + }) convict.addFormats({ prime: { validate: function(val) { function isPrime(n) { - if (n <= 1) return false; // zero and one are not prime - for (let i=2; i*i <= n; i++) { - if (n % i === 0) return false; + if (n <= 1) { + return false + } // zero and one are not prime + for (let i = 2; i * i <= n; i++) { + if (n % i === 0) { + return false + } } - return true; + return true + } + if (!isPrime(val)) { + throw new Error('must be a prime number') } - if (!isPrime(val)) throw new Error('must be a prime number'); }, coerce: function(val) { - return parseInt(val, 10); + return parseInt(val, 10) } }, 'hex-string': { validate: function(val) { if (/^[0-9a-fA-F]+$/.test(val)) { - throw new Error('must be a hexidecimal string'); + throw new Error('must be a hexidecimal string') } } } - }); + }) conf = convict({ foo: { @@ -92,32 +98,40 @@ describe('convict formats', function() { default: undefined } } - }); + }) - }); + }) it('validates default schema', function() { - (function() { conf.validate(); }).must.not.throw(); - }); + (function() { + conf.validate() + }).must.not.throw() + }) it('validates non-coerced correct values', function() { conf.set('foo.primeNumber', 7); - (function() { conf.validate(); }).must.not.throw(); - }); + (function() { + conf.validate() + }).must.not.throw() + }) it('validates coerced correct values', function() { conf.set('foo.primeNumber', '11'); - (function() { conf.validate(); }).must.not.throw(); - }); + (function() { + conf.validate() + }).must.not.throw() + }) it('successfully fails to validate incorrect values', function() { conf.set('foo.primeNumber', 16); - (function() { conf.validate(); }).must.throw(); - }); + (function() { + conf.validate() + }).must.throw() + }) describe('predefined formats', function() { describe('port_or_windows_named_pipe', function() { - let conf = convict({ + const conf = convict({ port: { format: 'port_or_windows_named_pipe', default: '1234', @@ -134,50 +148,54 @@ describe('convict formats', function() { format: 'port_or_windows_named_pipe', default: '\\\\.\\pipe\\default', }, - }); + }) it('must coerce ports to integers', function() { - conf.get('port').must.be(1234); - }); + conf.get('port').must.be(1234) + }) it('must not coerce pipes to integers', function() { - conf.get('pipe').must.be('\\\\.\\pipe\\test'); - }); + conf.get('pipe').must.be('\\\\.\\pipe\\test') + }) it('must handle switching from port to pipe', function() { - conf.set('to_pipe', '\\\\.\\pipe\\changed'); - conf.get('to_pipe').must.be('\\\\.\\pipe\\changed'); - }); + conf.set('to_pipe', '\\\\.\\pipe\\changed') + conf.get('to_pipe').must.be('\\\\.\\pipe\\changed') + }) it('must handle switching from pipe to port', function() { - conf.set('to_port', '8080'); - conf.get('to_port').must.be(8080); - }); + conf.set('to_port', '8080') + conf.get('to_port').must.be(8080) + }) it('must throw for invalid ports', function() { - let conf = convict({ + const conf = convict({ invalid: { format: 'port_or_windows_named_pipe', default: '235235452355', }, }); - (function() { conf.validate() }).must.throw(Error, /must be a windows named pipe or a number within range/); - }); + (function() { + conf.validate() + }).must.throw(Error, /must be a windows named pipe or a number within range/) + }) it('must throw for invalid pipes', function() { - let conf = convict({ + const conf = convict({ invalid: { format: 'port_or_windows_named_pipe', default: '\\.pipe\\test', }, }); - (function() { conf.validate() }).must.throw(Error, /must be a windows named pipe or a number within range/); - }); - }); - }); + (function() { + conf.validate() + }).must.throw(Error, /must be a windows named pipe or a number within range/) + }) + }) + }) it('must throw with unknown format', function() { (function() { @@ -186,14 +204,14 @@ describe('convict formats', function() { format: 'unknown', default: 'bar' } - }); - }).must.throw(); - }); + }) + }).must.throw() + }) it('must accept undefined as a default', function() { - let val = conf.get('foo.optional'); - expect(val).to.be(undefined); - }); + const val = conf.get('foo.optional') + expect(val).to.be(undefined) + }) describe('must return schema in second argument', function() { const schema = { @@ -220,59 +238,63 @@ describe('convict formats', function() { }, } } - }; + } const configWithoutErrors = { - 'domains': [ + domains: [ { - 'domain_base': 'mozilla', - 'extension': 'org', - 'bought': true, + domain_base: 'mozilla', + extension: 'org', + bought: true, }, { - 'domain_base': 'gitlab', - 'extension': 'com', - 'bought': true, + domain_base: 'gitlab', + extension: 'com', + bought: true, } ] - }; + } const configWithErrors = { - 'domains': [ + domains: [ { - 'domain_base': 'mozilla', - 'extension': 'org', - 'bought': true, + domain_base: 'mozilla', + extension: 'org', + bought: true, }, { - 'domain_base': 'gitlab', - 'extension': 'com', - 'bought': 8, + domain_base: 'gitlab', + extension: 'com', + bought: 8, } ] - }; + } it('must parse a config specification', function() { convict.addFormat({ name: 'source-array', validate: function(sources, schema) { if (!Array.isArray(sources)) { - throw new Error('must be of type Array'); + throw new Error('must be of type Array') } sources.forEach((source) => { - convict(schema.children).load(source).validate(); + convict(schema.children).load(source).validate() }) } - }); - }); + }) + }) it('must validate children value without throw an Error', function() { - (function() { convict(schema).load(configWithoutErrors).validate() }).must.not.throw(); - }); + (function() { + convict(schema).load(configWithoutErrors).validate() + }).must.not.throw() + }) it('successfully fails to validate incorrect children values', function() { - (function() { convict(schema).load(configWithErrors).validate() }).must.throw(Error, /domains: bought: must be of type Boolean/); - }); - }); -}); + (function() { + convict(schema).load(configWithErrors).validate() + }).must.throw(Error, /domains: bought: must be of type Boolean/) + }) + }) +}) diff --git a/packages/convict/test/get-tests.js b/packages/convict/test/get-tests.js index eb475d61..1bca4b94 100644 --- a/packages/convict/test/get-tests.js +++ b/packages/convict/test/get-tests.js @@ -1,10 +1,10 @@ -'use strict'; +'use strict' -require('must'); +require('must') describe('convict', function() { - const convict = require('../'); - let conf; + const convict = require('../') + let conf it('must parse a config specification', function() { conf = convict({ @@ -22,34 +22,38 @@ describe('convict', function() { } } } - }); - }); + }) + }) it('must be valid', function() { - (function() { conf.validate(); }).must.not.throw(); - }); + (function() { + conf.validate() + }).must.not.throw() + }) describe('.get()', function() { it('must find a nested value', function() { - let val = conf.get('foo.bar'); - val.must.be(7); - }); + const val = conf.get('foo.bar') + val.must.be(7) + }) it('must handle three levels of nesting', function() { - conf.get('foo.baz.bing').must.be('foo'); - }); + conf.get('foo.baz.bing').must.be('foo') + }) it('must handle names with spaces and underscores', function() { - conf.get('foo.baz.name with spaces.name_with_underscores').must.be(true); - }); + conf.get('foo.baz.name with spaces.name_with_underscores').must.be(true) + }) it("must throw if conf doesn't exist", function() { - (function() { conf.get('foo.no'); }).must.throw(); - }); + (function() { + conf.get('foo.no') + }).must.throw() + }) it('must get env', function() { - let val = conf.get('env'); - val.must.be('bar'); - }); - }); -}); + const val = conf.get('env') + val.must.be('bar') + }) + }) +}) diff --git a/packages/convict/test/lib/runner.js b/packages/convict/test/lib/runner.js index df3bf7cb..6eb3cb34 100644 --- a/packages/convict/test/lib/runner.js +++ b/packages/convict/test/lib/runner.js @@ -1,37 +1,37 @@ -'use strict'; +'use strict' const convict = require('../../lib/convict'), - path = require('path'); + path = require('path') /*eslint no-process-exit: 0*/ process.on('message', function(spec) { try { - let s = require(path.join(__dirname, '../cases', spec.spec)); + const s = require(path.join(__dirname, '../cases', spec.spec)) if (s.formats) { if (Array.isArray(s.formats)) { s.formats.forEach(function(formats) { - convict.addFormats(formats); - }); + convict.addFormats(formats) + }) } else { - convict.addFormats(s.formats); + convict.addFormats(s.formats) } } - let conf = convict(s.conf).loadFile(spec.config_files).validate(); + const conf = convict(s.conf).loadFile(spec.config_files).validate() process.send({ result: conf.get(), string: conf.toString(), schema: conf.getSchema() - }); - process.exit(0); - } catch(e) { - console.error(e); // eslint-disable-line no-console - process.send({error: e.message }); - process.exit(1); + }) + process.exit(0) + } catch (e) { + console.error(e) // eslint-disable-line no-console + process.send({error: e.message}) + process.exit(1) } -}); +}) // Tell the parent process that the runner is ready to perform work. This is // necessary because, when run under Istanbul, the runner takes long enough to // start that it misses messages sent immediately post-fork. -process.send({ready: true}); +process.send({ready: true}) diff --git a/packages/convict/test/loadFile-tests.js b/packages/convict/test/loadFile-tests.js index b7df995b..251ee483 100644 --- a/packages/convict/test/loadFile-tests.js +++ b/packages/convict/test/loadFile-tests.js @@ -1,132 +1,166 @@ -'use strict'; +'use strict' -const path = require('path'); -const json5 = require('json5'); -const yaml = require('js-yaml'); -const toml = require('toml'); -require('must'); +const path = require('path') +const json5 = require('json5') +const yaml = require('js-yaml') +const toml = require('toml') +require('must') describe('convict', function() { - const convict = require('../'); - const schema = require('./cases/formats/schema'); - const expected_output = require('./cases/formats/out'); + const convict = require('../') + const schema = require('./cases/formats/schema') + const expected_output = require('./cases/formats/out') describe('.addParser()', function() { it('must not throw on valid parser', function() { - (function() { convict.addParser({ extension: 'json', parse: JSON.parse }); }).must.not.throw(); - (function() { convict.addParser({ extension: ['yml', 'yaml'], parse: yaml.safeLoad }); }).must.not.throw(); - }); + (function() { + convict.addParser({extension: 'json', parse: JSON.parse}) + }).must.not.throw(); + (function() { + convict.addParser({extension: ['yml', 'yaml'], parse: yaml.safeLoad}) + }).must.not.throw() + }) it('must not throw on valid array of parsers', function() { (function() { convict.addParser([ - { extension: 'json', parse: JSON.parse }, - { extension: ['yml', 'yaml'], parse: yaml.safeLoad } - ]); - }).must.not.throw(); - }); + {extension: 'json', parse: JSON.parse}, + {extension: ['yml', 'yaml'], parse: yaml.safeLoad} + ]) + }).must.not.throw() + }) it('must throw on invalid parser', function() { - (function() { convict.addParser(undefined); }).must.throw(); - (function() { convict.addParser(null); }).must.throw(); - }); + (function() { + convict.addParser(undefined) + }).must.throw(); + (function() { + convict.addParser(null) + }).must.throw() + }) it('must throw on invalid parser that is missing extension', function() { - (function() { convict.addParser({ parse: JSON.parse }); }).must.throw(); - }); + (function() { + convict.addParser({parse: JSON.parse}) + }).must.throw() + }) it('must throw on invalid parser that has invalid extension', function() { - (function() { convict.addParser({ extension: 100, parse: JSON.parse }); }).must.throw(); - (function() { convict.addParser({ extension: ['yml', 100], parse: yaml.parse }); }).must.throw(); - }); + (function() { + convict.addParser({extension: 100, parse: JSON.parse}) + }).must.throw(); + (function() { + convict.addParser({extension: ['yml', 100], parse: yaml.parse}) + }).must.throw() + }) it('must throw on invalid parser that is missing parse function', function() { - (function() { convict.addParser({ extension: 'json' }); }).must.throw(); - }); + (function() { + convict.addParser({extension: 'json'}) + }).must.throw() + }) it('must throw on invalid parser that has invalid parse function', function() { - (function() { convict.addParser({ extension: 'json', parse: 100 }); }).must.throw(); - }); + (function() { + convict.addParser({extension: 'json', parse: 100}) + }).must.throw() + }) it('must throw on invalid array of parsers', function() { (function() { convict.addParser([ undefined, null, - { extension: 'json' }, // Missing parse function - { extension: 'json', parse: 100 }, // Invalid parse function - { parse: JSON.parse }, // Missing extension - { extension: 100, parse: JSON.parse }, // Invalid extension - { extension: ['yaml', 200], parse: yaml.parse }, // Invalid extension array - ]); - }).must.throw(); - }); - }); + {extension: 'json'}, // Missing parse function + {extension: 'json', parse: 100}, // Invalid parse function + {parse: JSON.parse}, // Missing extension + {extension: 100, parse: JSON.parse}, // Invalid extension + {extension: ['yaml', 200], parse: yaml.parse}, // Invalid extension array + ]) + }).must.throw() + }) + }) describe('convict().loadFile()', function() { it('must work using default json parser if format isn\'t supported', function() { - const conf = convict(schema); + const conf = convict(schema) conf.loadFile(path.join(__dirname, 'cases/formats/data')); - (function() { conf.validate() }).must.not.throw(); - conf.get().must.eql(expected_output); - }); + (function() { + conf.validate() + }).must.not.throw() + conf.get().must.eql(expected_output) + }) it('must work with custom json parser', function() { - convict.addParser({ extension: 'json', parse: JSON.parse }); + convict.addParser({extension: 'json', parse: JSON.parse}) - const conf = convict(schema); + const conf = convict(schema) conf.loadFile(path.join(__dirname, 'cases/formats/data.json')); - (function() { conf.validate() }).must.not.throw(); - conf.get().must.eql(expected_output); - }); + (function() { + conf.validate() + }).must.not.throw() + conf.get().must.eql(expected_output) + }) it('must work with custom json5 parser', function() { - convict.addParser({ extension: 'json5', parse: json5.parse }); + convict.addParser({extension: 'json5', parse: json5.parse}) - const conf = convict(schema); + const conf = convict(schema) conf.loadFile(path.join(__dirname, 'cases/formats/data.json5')); - (function() { conf.validate() }).must.not.throw(); - conf.get().must.eql(expected_output); - }); + (function() { + conf.validate() + }).must.not.throw() + conf.get().must.eql(expected_output) + }) it('must work with custom yaml parser', function() { - convict.addParser({ extension: ['yml', 'yaml'], parse: yaml.safeLoad }); + convict.addParser({extension: ['yml', 'yaml'], parse: yaml.safeLoad}) - const conf = convict(schema); + const conf = convict(schema) conf.loadFile(path.join(__dirname, 'cases/formats/data.yaml')); - (function() { conf.validate() }).must.not.throw(); - conf.get().must.eql(expected_output); - }); + (function() { + conf.validate() + }).must.not.throw() + conf.get().must.eql(expected_output) + }) it('must work with custom toml parser', function() { - convict.addParser({ extension: 'toml', parse: toml.parse }); + convict.addParser({extension: 'toml', parse: toml.parse}) - const conf = convict(schema); + const conf = convict(schema) conf.loadFile(path.join(__dirname, 'cases/formats/data.toml')); - (function() { conf.validate() }).must.not.throw(); - conf.get().must.eql(expected_output); - }); + (function() { + conf.validate() + }).must.not.throw() + conf.get().must.eql(expected_output) + }) it('must use wildcard parser if no parser is registered for extension', function() { const message = 'Unsupported file type' - convict.addParser({ extension: '*', parse: function() { throw new Error(message) } }); + convict.addParser({extension: '*', parse: function() { + throw new Error(message) + }}) const conf = convict(schema); - (function() { conf.loadFile(path.join(__dirname, 'cases/formats/data.xml')) }).must.throw(message); - }); - + (function() { + conf.loadFile(path.join(__dirname, 'cases/formats/data.xml')) + }).must.throw(message) + }) + it('must not break when parsing an empty file', function() { - convict.addParser({ extension: ['yml', 'yaml'], parse: yaml.safeLoad }); - - const conf = convict(schema); + convict.addParser({extension: ['yml', 'yaml'], parse: yaml.safeLoad}) + + const conf = convict(schema) conf.loadFile(path.join(__dirname, 'cases/formats/data.empty.yaml')); - - (function() { conf.validate() }).must.not.throw(); - }); - }); -}); + + (function() { + conf.validate() + }).must.not.throw() + }) + }) +}) diff --git a/packages/convict/test/nesting-tests.js b/packages/convict/test/nesting-tests.js index d952bd36..bfc231a3 100644 --- a/packages/convict/test/nesting-tests.js +++ b/packages/convict/test/nesting-tests.js @@ -1,8 +1,8 @@ 'use strict' describe('deep nested tree structure', function() { - const convict = require('../'); - let conf; + const convict = require('../') + let conf it('must parse a deep nested config specification', function() { conf = convict({ @@ -22,8 +22,8 @@ describe('deep nested tree structure', function() { } } } - }); - }); + }) + }) it('instance must be valid', function() { conf.load({ @@ -38,93 +38,93 @@ describe('deep nested tree structure', function() { (function() { conf.validate({ allowed: 'strict' - }); - }).must.not.throw(); - }); + }) + }).must.not.throw() + }) describe('get nested fields value', function() { it('must find a value', function() { (function() { - conf.get('db'); - }).must.not.throw(); - }); + conf.get('db') + }).must.not.throw() + }) it('must handle two levels of nesting', function() { - conf.get('db.name').must.be('some_db'); - }); + conf.get('db.name').must.be('some_db') + }) it('must handle three levels of nesting', function() { - conf.get('db.synchro.active').must.be(true); - }); + conf.get('db.synchro.active').must.be(true) + }) it('must handle three levels of side by side nesting', function() { - conf.get('db.synchro.foo').must.be('xyz'); - }); - }); + conf.get('db.synchro.foo').must.be('xyz') + }) + }) describe('alter nested fields value', function() { - let synchro; + let synchro it('must find a nested value', function() { (function() { - synchro = conf.get('db.synchro'); - }).must.not.throw(); - }); + synchro = conf.get('db.synchro') + }).must.not.throw() + }) it('modify a nested value and must be valid', function() { - synchro.active = false; + synchro.active = false conf.set('db.synchro', synchro); (function() { conf.validate({ allowed: 'strict' - }); - }).must.not.throw(); - conf.get('db.synchro.active').must.be(false); - }); + }) + }).must.not.throw() + conf.get('db.synchro.active').must.be(false) + }) - }); + }) describe('alter deep nested fields value', function() { - let db; + let db it('must find a deep nested value', function() { (function() { - db = conf.get('db'); - }).must.not.throw(); - }); + db = conf.get('db') + }).must.not.throw() + }) it('modify a deep nested value and must be valid', function() { - db.synchro.foo = 'mnopq'; + db.synchro.foo = 'mnopq' conf.set('db', db); (function() { conf.validate({ allowed: 'strict' - }); - }).must.not.throw(); - conf.get('db.synchro.foo').must.be('mnopq'); - }); + }) + }).must.not.throw() + conf.get('db.synchro.foo').must.be('mnopq') + }) - }); + }) describe('missing chains', function() { it('must error when attempting to access a missing chain', function() { (function() { - conf.get('invalid'); + conf.get('invalid') }).must.throw(); (function() { - conf.get('invalid.child'); - }).must.throw(); - }); + conf.get('invalid.child') + }).must.throw() + }) it('must initialize an empty chain', function() { (function() { - conf.set('invalid.child', 'value'); - }).must.not.throw(); - }); + conf.set('invalid.child', 'value') + }).must.not.throw() + }) it('must retrieve an initialized empty chain', function() { - conf.get('invalid.child').must.be('value'); - conf.get('invalid').must.be.eql({child: 'value'}); - }); - }); + conf.get('invalid.child').must.be('value') + conf.get('invalid').must.be.eql({child: 'value'}) + }) + }) }) diff --git a/packages/convict/test/schema-tests.js b/packages/convict/test/schema-tests.js index 17c600cd..d5da32d9 100644 --- a/packages/convict/test/schema-tests.js +++ b/packages/convict/test/schema-tests.js @@ -1,34 +1,36 @@ -'use strict'; +'use strict' -const path = require('path'); -require('must'); +const path = require('path') +require('must') describe('convict schema', function() { - const convict = require('../'); - let conf; - let conf2 = convict({ + const convict = require('../') + let conf + const conf2 = convict({ foo: { none: { format: String, default: undefined } } - }); + }) it('must parse a config specification from a file', function() { - conf = convict(path.join(__dirname, 'schema.json')); - }); + conf = convict(path.join(__dirname, 'schema.json')) + }) it('must parse a specification with built-in formats', function() { - conf = convict(path.join(__dirname, 'cases/schema-built-in-formats.json')); - }); + conf = convict(path.join(__dirname, 'cases/schema-built-in-formats.json')) + }) it('must throw when parsing a specification that reuses a command-line argument', function() { - (function() { convict({ - foo: {default: 'a', arg: 'BAZ'}, - bar: {default: 'a', arg: 'BAZ'} - })}).must.throw(); - }); + (function() { + convict({ + foo: {default: 'a', arg: 'BAZ'}, + bar: {default: 'a', arg: 'BAZ'} + }) + }).must.throw() + }) it('must accept process arguments and environment variables as parameters', function() { conf = convict({ @@ -44,56 +46,60 @@ describe('convict schema', function() { env: 'BAR', arg: 'bar' } - }, { args: ['--bar', 'baz'], env: { FOO: 'foz' } }); + }, {args: ['--bar', 'baz'], env: {FOO: 'foz'}}) conf.getArgs().must.eql(['--bar', 'baz']) - conf.getEnv().must.eql({ FOO: 'foz' }) - conf.get('bar').must.be('baz'); - conf.get('foo').must.be('foz'); - }); + conf.getEnv().must.eql({FOO: 'foz'}) + conf.get('bar').must.be('baz') + conf.get('foo').must.be('foz') + }) describe('after being parsed', function() { beforeEach(function() { - conf = convict(path.join(__dirname, 'schema.json')); - }); + conf = convict(path.join(__dirname, 'schema.json')) + }) it('must be valid', function() { - (function() { conf.validate(); }).must.not.throw(); - }); + (function() { + conf.validate() + }).must.not.throw() + }) it('must be valid again', function() { - (function() { conf2.validate(); }).must.not.throw(); - }); + (function() { + conf2.validate() + }).must.not.throw() + }) it('must export all its properties as JSON', function() { - let res = conf.getProperties(); + const res = conf.getProperties() res.must.eql({ - 'foo': { - 'bar': 7, - 'baz': { - 'bing': 'foo', + foo: { + bar: 7, + baz: { + bing: 'foo', 'name with spaces': { - 'name_with_underscores': true + name_with_underscores: true } } } - }); - }); + }) + }) it('must export all its properties as a string', function() { - let res = conf.toString(); + const res = conf.toString() res.must.eql(JSON.stringify({ - 'foo': { - 'bar': 7, - 'baz': { - 'bing': 'foo', + foo: { + bar: 7, + baz: { + bing: 'foo', 'name with spaces': { - 'name_with_underscores': true + name_with_underscores: true } } } - }, null, 2)); - }); + }, null, 2)) + }) it('must throw if `_cvtProperties` (reserved keyword) is used', function() { (function() { @@ -102,28 +108,28 @@ describe('convict schema', function() { format: String, default: 'DEFAULT' } - }); - }).must.throw(); - }); + }) + }).must.throw() + }) it('must export the schema as JSON', function() { - let res = conf.getSchema(); + const res = conf.getSchema() res.must.eql({ - '_cvtProperties': { - 'foo': { - '_cvtProperties': { - 'bar': { - 'default': 7 + _cvtProperties: { + foo: { + _cvtProperties: { + bar: { + default: 7 }, - 'baz': { - '_cvtProperties': { - 'bing': { - 'default': 'foo' + baz: { + _cvtProperties: { + bing: { + default: 'foo' }, 'name with spaces': { - '_cvtProperties': { - 'name_with_underscores': { - 'default': true + _cvtProperties: { + name_with_underscores: { + default: true } } } @@ -132,27 +138,27 @@ describe('convict schema', function() { } } } - }); - }); + }) + }) it('must export the schema as a JSON string', function() { - let res = conf.getSchemaString(); + const res = conf.getSchemaString() res.must.eql(JSON.stringify({ - '_cvtProperties': { - 'foo': { - '_cvtProperties': { - 'bar': { - 'default': 7 + _cvtProperties: { + foo: { + _cvtProperties: { + bar: { + default: 7 }, - 'baz': { - '_cvtProperties': { - 'bing': { - 'default': 'foo' + baz: { + _cvtProperties: { + bing: { + default: 'foo' }, 'name with spaces': { - '_cvtProperties': { - 'name_with_underscores': { - 'default': true + _cvtProperties: { + name_with_underscores: { + default: true } } } @@ -161,101 +167,119 @@ describe('convict schema', function() { } } } - }, null, 2)); - }); + }, null, 2)) + }) describe('.has()', function() { it('must not have undefined properties', function() { - let val = conf.has('foo.bar.madeup'); - val.must.be(false); - }); + const val = conf.has('foo.bar.madeup') + val.must.be(false) + }) it('must not have properties specified with a default of undefined', function() { - let val = conf2.has('foo.none'); - val.must.be(false); - }); - }); + const val = conf2.has('foo.none') + val.must.be(false) + }) + }) describe('.get()', function() { it('must find a nested value', function() { - let val = conf.get('foo.bar'); - val.must.be(7); - }); + const val = conf.get('foo.bar') + val.must.be(7) + }) it('must handle three levels of nesting', function() { - conf.get('foo.baz.bing').must.be('foo'); - }); + conf.get('foo.baz.bing').must.be('foo') + }) it('must handle names with spaces and underscores', function() { - conf.get('foo.baz.name with spaces.name_with_underscores').must.be(true); - }); + conf.get('foo.baz.name with spaces.name_with_underscores').must.be(true) + }) it('must throw if conf doesn\'t exist', function() { - (function() { conf.get('foo.no'); }).must.throw(); - }); - }); + (function() { + conf.get('foo.no') + }).must.throw() + }) + }) describe('.default()', function() { // Temporarily modify a property while testing default() - beforeEach(function() { conf.set('foo.bar', 8); }); - afterEach(function() { conf.set('foo.bar', 7); }); + beforeEach(function() { + conf.set('foo.bar', 8) + }) + afterEach(function() { + conf.set('foo.bar', 7) + }) it('must report the default value of a property', function() { - conf.get('foo.bar').must.be(8); // Modified - conf.default('foo.bar').must.be(7); - conf.get('foo.bar').must.be(8); - }); + conf.get('foo.bar').must.be(8) // Modified + conf.default('foo.bar').must.be(7) + conf.get('foo.bar').must.be(8) + }) it('must throw if key doesn\'t exist', function() { - (function() { conf.default('foo.no'); }).must.throw(); - }); + (function() { + conf.default('foo.no') + }).must.throw() + }) describe('when acting on an Object property', function() { beforeEach(function() { - conf = convict(path.join(__dirname, 'cases/schema-built-in-formats.json')); - }); + conf = convict(path.join(__dirname, 'cases/schema-built-in-formats.json')) + }) it('must report the default value of the property', function() { - conf.get('someObject').must.eql({}); - conf.default('someObject').must.eql({}); - }); + conf.get('someObject').must.eql({}) + conf.default('someObject').must.eql({}) + }) it('must not be altered by calls to .set()', function() { - conf.set('someObject.five', 5); + conf.set('someObject.five', 5) conf.default('someObject').must.eql({}); - (function() { conf.default('someObject.five'); }).must.throw(); - }); + (function() { + conf.default('someObject.five') + }).must.throw() + }) it('must not be altered by calls to .load()', function() { - conf.load({someObject: {five: 5}}); + conf.load({someObject: {five: 5}}) conf.default('someObject').must.eql({}); - (function() { conf.default('someObject.five'); }).must.throw(); - }); - }); - }); + (function() { + conf.default('someObject.five') + }).must.throw() + }) + }) + }) describe('.reset()', function() { // Temporarily modify a property while testing default() - beforeEach(function() { conf.set('foo.bar', 8); }); - afterEach(function() { conf.set('foo.bar', 7); }); + beforeEach(function() { + conf.set('foo.bar', 8) + }) + afterEach(function() { + conf.set('foo.bar', 7) + }) it('must reset the property to its default value', function() { - conf.get('foo.bar').must.be(8); // Modified - conf.reset('foo.bar'); - conf.get('foo.bar').must.be(7); - }); + conf.get('foo.bar').must.be(8) // Modified + conf.reset('foo.bar') + conf.get('foo.bar').must.be(7) + }) it('must throw if key doesn\'t exist', function() { - (function() { conf.reset('foo.no'); }).must.throw(); - }); - }); + (function() { + conf.reset('foo.no') + }).must.throw() + }) + }) - }); -}); + }) +}) describe('convict used multiple times on one schema', function() { - const convict = require('../'); - let schema = { + const convict = require('../') + const schema = { publicServerAddress: { doc: 'The public-facing server address', format: String, @@ -263,7 +287,7 @@ describe('convict used multiple times on one schema', function() { } }; (function() { - convict(schema); - convict(schema); - }).must.not.throw(); -}); + convict(schema) + convict(schema) + }).must.not.throw() +}) diff --git a/packages/convict/test/validation-tests.js b/packages/convict/test/validation-tests.js index d89f743b..52518398 100644 --- a/packages/convict/test/validation-tests.js +++ b/packages/convict/test/validation-tests.js @@ -1,11 +1,11 @@ -'use strict'; +'use strict' -const path = require('path'); -require('must'); +const path = require('path') +require('must') describe('configuration files contain properties not declared in the schema', function() { - const convict = require('../'); - let config = convict({ + const convict = require('../') + const config = convict({ foo: { doc: 'testing', format: String, @@ -30,136 +30,138 @@ describe('configuration files contain properties not declared in the schema', fu } } } - }); + }) it('must not throw, if properties in config file match with the schema', function() { config.loadFile(path.join(__dirname, 'cases/validation_correct.json')); (function() { config.validate({ allowed: 'strict' - }); - }).must.not.throw(); - }); + }) + }).must.not.throw() + }) it('must not throw, if the option to check for non schema properties is set by default but must display warnings', function() { config.loadFile(path.join(__dirname, 'cases/validation_incorrect.json')); (function() { - config.validate(); - }).must.not.throw(); - }); + config.validate() + }).must.not.throw() + }) it('must not throw, if the option to check for non schema properties is not specified and must display warnings', function() { config.loadFile(path.join(__dirname, 'cases/validation_incorrect.json')); (function() { - config.validate(); - }).must.not.throw(); - }); + config.validate() + }).must.not.throw() + }) it('must throw, if properties in config file do not match the properties declared in the schema', function() { config.loadFile(path.join(__dirname, 'cases/validation_incorrect.json')); (function() { config.validate({ allowed: 'strict' - }); - }).must.throw(/not declared/); - }); + }) + }).must.throw(/not declared/) + }) it('must display warning, if properties in config file do not match the properties declared in the schema', function() { config.loadFile(path.join(__dirname, 'cases/validation_incorrect.json')); (function() { config.validate({ allowed: 'warn' - }); - }).must.not.throw(); - }); + }) + }).must.not.throw() + }) it('must throw, if properties in instance do not match the properties declared in the schema and there are incorrect values', function() { (function() { config.load({ - 'foo': 58, - 'bar': 98, - 'nested': { - 'level1_1': 'undeclared' + foo: 58, + bar: 98, + nested: { + level1_1: 'undeclared' }, - 'undeclared': 'this property is not declared in the schema' - }); + undeclared: 'this property is not declared in the schema' + }) config.validate({ allowed: 'strict' - }); - }).must.throw(); - }); - let message = ''; + }) + }).must.throw() + }) + let message = '' function myOutput(str) { - message += str; + message += str } it('must not break when a failed validation follows an undeclared property and must display warnings, and call the user output function', function() { (function() { convict.addFormat('foo', function(val) { - if (val !== 0) { throw new Error('Validation error'); } - }); + if (val !== 0) { + throw new Error('Validation error') + } + }) - let config = convict({ + const config = convict({ test2: { - one: { default: 0 }, + one: {default: 0}, two: { format: 'foo', default: 0 } } - }); + }) // if this key is a number, the error occurs; if it is a string, it does not // i don't know why. the deep nesting is also required. - config.load({'0': true}); - config.load({ test2: { two: 'two' } }); + config.load({0: true}) + config.load({test2: {two: 'two'}}) config.validate({ output: myOutput - }); - }).must.throw(/Validation error/); - }); + }) + }).must.throw(/Validation error/) + }) it('must use the user output function when it was declared', function() { - message.must.eql("\u001b[33;1mWarning:\u001b[0m configuration param '0' not declared in the schema"); - }); + message.must.eql("\u001b[33;1mWarning:\u001b[0m configuration param '0' not declared in the schema") + }) it('must only accept function when user set an output function', function() { config.loadFile(path.join(__dirname, 'cases/validation_incorrect.json')); (function() { config.validate({ output: 312 - }); - }).must.throw(/options\.output is optionnal and must be a function\./); - }); + }) + }).must.throw(/options\.output is optionnal and must be a function\./) + }) it('must not break on consecutive overrides', function() { (function() { - let config = convict({ + const config = convict({ object: { doc: 'testing', format: Object, default: {} } - }); + }) config.loadFile([ path.join(__dirname, 'cases/object_override1.json'), path.join(__dirname, 'cases/object_override2.json') - ]); - config.validate(); - }).must.not.throw(); + ]) + config.validate() + }).must.not.throw() }) -}); +}) describe('setting specific values', function() { - const convict = require('../'); + const convict = require('../') it('must not show warning for undeclared nested object values', function() { (function() { - let config = convict({ + const config = convict({ object: { doc: 'testing', format: Object, default: {} } - }); - config.set('object', { foo: 'bar' }); - config.validate({ allowed: 'strict' }); - }).must.not.throw(); - }); + }) + config.set('object', {foo: 'bar'}) + config.validate({allowed: 'strict'}) + }).must.not.throw() + }) it('must show warning for undeclared property names similar to nested declared property name', function() { (function() { - let config = convict({ + const config = convict({ parent: { object: { doc: 'testing', @@ -167,30 +169,30 @@ describe('setting specific values', function() { default: {} } }, - }); - config.set('parent.object', { foo: 'bar' }); - config.set('parent_object', { foo: 'bar' }); - config.validate({ allowed: 'strict' }); - }).must.throw(); - }); + }) + config.set('parent.object', {foo: 'bar'}) + config.set('parent_object', {foo: 'bar'}) + config.validate({allowed: 'strict'}) + }).must.throw() + }) it('must show warning for undeclared property names starting with declared object properties', function() { (function() { - let config = convict({ + const config = convict({ object: { doc: 'testing', format: Object, default: {} } - }); - config.set('object', { foo: 'bar' }); - config.set('objectfoo', { foo: 'bar' }); - config.validate({ allowed: 'strict' }); - }).must.throw(); - }); -}); + }) + config.set('object', {foo: 'bar'}) + config.set('objectfoo', {foo: 'bar'}) + config.validate({allowed: 'strict'}) + }).must.throw() + }) +}) describe('schema contains an object property with a custom format', function() { - const convict = require('../'); + const convict = require('../') it('must throw if a nested object property has an undeclared format', function() { (function() { const config = convict({ @@ -201,14 +203,14 @@ describe('schema contains an object property with a custom format', function() { bar: 'baz', }, }, - }); + }) - config.validate({ allowed: 'strict' }); - }).must.throw(); - }); + config.validate({allowed: 'strict'}) + }).must.throw() + }) it('must not throw if an object property has a nested value and a custom format', function() { (function() { - convict.addFormat('foo', function() {}); + convict.addFormat('foo', function() {}) const config = convict({ object: { doc: 'testing', @@ -217,14 +219,14 @@ describe('schema contains an object property with a custom format', function() { bar: 'baz', }, }, - }); + }) - config.validate({ allowed: 'strict' }); - }).must.not.throw(); - }); + config.validate({allowed: 'strict'}) + }).must.not.throw() + }) it('must not throw if a declared object property with a custom format and with nested values is set', function() { (function() { - convict.addFormat('foo', function() {}); + convict.addFormat('foo', function() {}) const config = convict({ object: { doc: 'testing', @@ -233,12 +235,12 @@ describe('schema contains an object property with a custom format', function() { bar: 'baz', }, }, - }); + }) - config.set('object', { bar: '', baz: 'blah' }); - config.validate({ allowed: 'strict' }); - }).must.not.throw(); - }); + config.set('object', {bar: '', baz: 'blah'}) + config.validate({allowed: 'strict'}) + }).must.not.throw() + }) it.skip("must not throw if an object's default value property name contains a period", function() { (function() { @@ -250,10 +252,10 @@ describe('schema contains an object property with a custom format', function() { 'foo.bar': '' } } - }); + }) - config.validate(); - }).must.not.throw(); - }); + config.validate() + }).must.not.throw() + }) -}); +})