confidence
Advanced tools
Comparing version 4.0.2 to 5.0.0
@@ -5,3 +5,3 @@ 'use strict'; | ||
const Joi = require('@hapi/joi'); | ||
const Joi = require('joi'); | ||
@@ -12,103 +12,152 @@ // Declare internals | ||
internals.Joi = Joi.extend([ | ||
{ | ||
name: 'object', | ||
base: Joi.object(), | ||
language: { | ||
withPattern: 'fails to match the {{name}} pattern', | ||
notInstanceOf: 'cannot be an instance of {{name}}' | ||
}, | ||
rules: [ | ||
{ | ||
name: 'withPattern', | ||
params: { | ||
key: Joi.string().required(), | ||
pattern: Joi.object().type(RegExp).required(), | ||
options: Joi.object().keys({ | ||
internals.Joi = Joi.extend({ | ||
type: 'object', | ||
base: Joi.object(), | ||
messages: { | ||
'object.withPattern': 'fails to match the {{#name}} pattern', | ||
'object.notInstanceOf': 'cannot be an instance of {{#name}}', | ||
'object.replaceBaseArrayFlag': '{{#desc}}' | ||
}, | ||
rules: { | ||
withPattern: { | ||
multi: true, | ||
method(key, pattern, options) { | ||
return this.$_addRule({ name: 'withPattern', args: { key, pattern, options } }); | ||
}, | ||
args: [ | ||
{ | ||
name: 'key', | ||
assert: Joi.string().required() | ||
}, | ||
{ | ||
name: 'pattern', | ||
assert: Joi.object().instance(RegExp).required() | ||
}, | ||
{ | ||
name: 'options', | ||
assert: Joi.object().keys({ | ||
name: Joi.string().required(), | ||
inverse: Joi.boolean().default(false) | ||
inverse: Joi.boolean() | ||
}).required() | ||
}, | ||
validate(params, value, state, options) { | ||
} | ||
], | ||
validate(value, helpers, args) { | ||
if (Object.prototype.hasOwnProperty.call(value, params.key)) { | ||
let found = false; | ||
for (const key in value) { | ||
if (params.pattern.test(key)) { | ||
found = true; | ||
break; | ||
} | ||
if (Object.prototype.hasOwnProperty.call(value, args.key)) { | ||
let found = false; | ||
for (const key in value) { | ||
if (args.pattern.test(key)) { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (found !== params.options.inverse) { | ||
return this.createError('object.withPattern', { v: value, name: params.options.name }, state, options); | ||
} | ||
if (found !== Boolean(args.options.inverse)) { | ||
return helpers.error('object.withPattern', { v: value, name: args.options.name }); | ||
} | ||
} | ||
return value; | ||
} | ||
return value; | ||
} | ||
}, | ||
notInstanceOf: { | ||
multi: true, | ||
method(fn) { | ||
return this.$_addRule({ name: 'notInstanceOf', args: { fn } }); | ||
}, | ||
{ | ||
name: 'notInstanceOf', | ||
params: { | ||
fn: Joi.func().required() | ||
}, | ||
validate(params, value, state, options) { | ||
args: [{ | ||
name: 'fn', | ||
assert: Joi.func().required() | ||
}], | ||
validate(value, helpers, args) { | ||
if (value instanceof params.fn) { | ||
return this.createError('object.notInstanceOf', { v: value, name: params.fn.name }, state, options); | ||
if (value instanceof args.fn) { | ||
return helpers.error('object.notInstanceOf', { v: value, name: args.fn.name }); | ||
} | ||
return value; | ||
} | ||
}, | ||
replaceBaseArrayFlag: { | ||
validate(value, helpers) { | ||
if (Object.keys(value).includes('$replace')) { | ||
if (!helpers.state.path.includes('$base')) { | ||
return helpers.error('object.replaceBaseArrayFlag', { desc: '$replace only allowed under path $base' }); | ||
} | ||
return value; | ||
if (!Object.keys(value).includes('$value')) { | ||
return helpers.error('object.replaceBaseArrayFlag', { desc: '$replace missing required peer $value' }); | ||
} | ||
if (!Array.isArray(value.$value)) { | ||
return helpers.error('object.replaceBaseArrayFlag', { desc: '$replace requires $value to be an array' }); | ||
} | ||
} | ||
return value; | ||
} | ||
] | ||
} | ||
} | ||
}); | ||
internals.Joi = internals.Joi.extend({ | ||
type: 'array', | ||
base: Joi.array(), | ||
messages: { | ||
'array.sorted': 'entries are not sorted by {{name}}' | ||
}, | ||
{ | ||
name: 'array', | ||
base: Joi.array(), | ||
language: { | ||
sorted: 'entries are not sorted by {{name}}' | ||
}, | ||
rules: [ | ||
{ | ||
name: 'sorted', | ||
params: { | ||
fn: Joi.func().arity(2).required(), | ||
name: Joi.string().required() | ||
rules: { | ||
sorted: { | ||
method(fn, name) { | ||
return this.$_addRule({ name: 'sorted', args: { fn, name } }); | ||
}, | ||
args: [ | ||
{ | ||
name: 'fn', | ||
assert: Joi.func().arity(2).required() | ||
}, | ||
validate(params, value, state, options) { | ||
{ | ||
name: 'name', | ||
assert: Joi.string().required() | ||
} | ||
], | ||
validate(value, helpers, args) { | ||
let sorted = true; | ||
for (let i = 0; i < value.length - 1; ++i) { | ||
sorted = params.fn.call(null, value[i], value[i + 1]); | ||
if (!sorted) { | ||
return this.createError('array.sorted', { v: value, name: params.name }, state, options); | ||
} | ||
let sorted = true; | ||
for (let i = 0; i < value.length - 1; ++i) { | ||
sorted = args.fn.call(null, value[i], value[i + 1]); | ||
if (!sorted) { | ||
return helpers.error('array.sorted', { v: value, name: args.name }); | ||
} | ||
} | ||
return value; | ||
} | ||
return value; | ||
} | ||
] | ||
} | ||
} | ||
}); | ||
internals.alternatives = internals.Joi.alternatives([ | ||
internals.Joi.link('#store'), | ||
internals.Joi.string().allow(''), | ||
internals.Joi.number(), | ||
internals.Joi.boolean(), | ||
internals.Joi.array(), | ||
internals.Joi.func() | ||
]); | ||
internals.alternatives = internals.Joi.lazy(() => { | ||
return internals.Joi.alternatives([ | ||
internals.store, | ||
internals.Joi.string().allow(''), | ||
internals.Joi.number(), | ||
internals.Joi.boolean(), | ||
internals.Joi.array(), | ||
internals.Joi.func() | ||
]); | ||
}); | ||
exports.store = internals.store = internals.Joi.object().keys({ | ||
$param: internals.Joi.string().regex(/^\w+(?:\.\w+)*$/, { name: 'Alphanumeric Characters and "_"' }), | ||
$value: internals.alternatives, | ||
$replace: internals.Joi.boolean().invalid(false), | ||
$env: internals.Joi.string().regex(/^\w+$/, { name: 'Alphanumeric Characters and "_"' }), | ||
$coerce: internals.Joi.string().valid('number'), | ||
$coerce: internals.Joi.string().valid('number', 'array', 'boolean', 'object'), | ||
$splitToken: internals.Joi.alternatives([ | ||
internals.Joi.string(), | ||
internals.Joi.object().instance(RegExp) | ||
]), | ||
$filter: internals.Joi.alternatives([ | ||
@@ -146,5 +195,7 @@ internals.Joi.string().regex(/^\w+(?:\.\w+)*$/, { name: 'Alphanumeric Characters and "_"' }), | ||
.with('$coerce', '$env') | ||
.with('$splitToken', '$coerce') | ||
.withPattern('$filter', /^((\$range)|([^\$].*))$/, { inverse: true, name: '$filter with a valid value OR $range' }) | ||
.withPattern('$range', /^([^\$].*)$/, { name: '$range with non-ranged values' }) | ||
.allow(null); | ||
.replaceBaseArrayFlag() | ||
.allow(null) | ||
.id('store'); |
@@ -12,3 +12,3 @@ 'use strict'; | ||
module.exports = internals.Store = class { | ||
module.exports = internals.Store = class Store { | ||
@@ -112,4 +112,5 @@ constructor(document) { | ||
if (typeof node === 'object' && (Array.isArray(base) === Array.isArray(node))) { | ||
return Hoek.merge(Hoek.clone(base), Hoek.clone(node)); | ||
const filteredBase = internals.filter(base); | ||
if (typeof node === 'object' && (Array.isArray(filteredBase) === Array.isArray(node)) && !base.$replace) { | ||
return Hoek.merge(Hoek.clone(filteredBase), Hoek.clone(node)); | ||
} | ||
@@ -195,3 +196,3 @@ | ||
if (Object.prototype.hasOwnProperty.call(node, '$env')) { | ||
const value = internals.coerce(Hoek.reach(process.env, node.$env, applied), node.$coerce || 'string'); | ||
const value = internals.coerce(Hoek.reach(process.env, node.$env, applied), node.$coerce || 'string', { splitToken: node.$splitToken || ',' }); | ||
@@ -226,3 +227,3 @@ // Falls-through for $default | ||
internals.coerce = function (value, type) { | ||
internals.coerce = function (value, type, options) { | ||
@@ -235,2 +236,38 @@ let result = value; | ||
break; | ||
case 'array': | ||
if (typeof value === 'string') { | ||
result = value.split(options.splitToken); | ||
} | ||
else { | ||
result = undefined; | ||
} | ||
break; | ||
case 'boolean': | ||
result = undefined; | ||
if (typeof value === 'string') { | ||
const string = value.toLowerCase(); | ||
if (string === 'true') { | ||
result = true; | ||
} | ||
else if (string === 'false') { | ||
result = false; | ||
} | ||
} | ||
break; | ||
case 'object': | ||
try { | ||
result = JSON.parse(value); | ||
} | ||
catch (e) { | ||
result = undefined; | ||
} | ||
break; | ||
} | ||
@@ -237,0 +274,0 @@ |
{ | ||
"name": "confidence", | ||
"description": "Configuration API", | ||
"version": "4.0.2", | ||
"version": "5.0.0", | ||
"repository": "git://github.com/hapipal/confidence", | ||
@@ -14,10 +14,11 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@hapi/hoek": "9.x.x", | ||
"alce": "1.x.x", | ||
"@hapi/hoek": "6.x.x", | ||
"@hapi/joi": "15.x.x", | ||
"yargs": "13.x.x" | ||
"joi": "17.x.x", | ||
"yargs": "16.x.x" | ||
}, | ||
"devDependencies": { | ||
"@hapi/code": "5.x.x", | ||
"@hapi/lab": "19.x.x" | ||
"@hapi/code": "8.x.x", | ||
"@hapi/lab": "23.x.x", | ||
"coveralls": "3.x.x" | ||
}, | ||
@@ -29,2 +30,4 @@ "bin": { | ||
"test": "lab -t 100 -a @hapi/code -L", | ||
"coveralls": "lab -r lcov | coveralls", | ||
"lint-fix": "lab -t 100 -a @hapi/code -L --lint-fix", | ||
"test-cov-html": "lab -r html -o coverage.html -a @hapi/code -L" | ||
@@ -31,0 +34,0 @@ }, |
@@ -7,5 +7,5 @@ ![confidence Logo](https://raw.githubusercontent.com/hapipal/confidence/master/images/confidence.png) | ||
Version 4.x only supports node v8.9.0 and over. For older version of node please use version 3.x. | ||
Version 5.x only supports node v12 and over. For older versions of node please use version 4.x. | ||
[![Build Status](https://travis-ci.org/hapipal/confidence.svg?branch=master)](https://travis-ci.org/hapipal/confidence) | ||
[![Build Status](https://travis-ci.org/hapipal/confidence.svg?branch=master)](https://travis-ci.org/hapipal/confidence) [![Coverage Status](https://coveralls.io/repos/hapipal/confidence/badge.svg?branch=master&service=github)](https://coveralls.io/github/hapipal/confidence?branch=master) | ||
@@ -18,2 +18,3 @@ Lead Maintainer: [Sunny Bhanot](https://github.com/augnin) | ||
- [Environment Variables](#environment-variables) | ||
- [Coercing value](#coercing-value) | ||
- [Criteria Parameters](#criteria-parameters) | ||
@@ -217,2 +218,4 @@ - [Filters](#filters) | ||
#### Coercing value | ||
`$coerce` directive allows you to coerce values to different types. In case the coercing fails, it falls back to `$default` directive, if present. Otherwise it return `undefined`. | ||
@@ -236,3 +239,3 @@ | ||
With following Enviornment Variables: | ||
With following Environment Variables: | ||
@@ -260,3 +263,3 @@ ```sh | ||
``` | ||
With following Enviornment Variables: | ||
With following Environment Variables: | ||
@@ -285,2 +288,7 @@ ```sh | ||
Value can be coerced to : | ||
- `number` : applying `Number(value)` | ||
- `boolean` : checking whether the value equal `true` or `false` case insensitive | ||
- `array` : applying a `value.split(token)` with `token` (by default `','`) modifiable by setting the key `$splitToken` to either a string or a regex | ||
- `object` : applying a `JSON.parse(value)` | ||
@@ -539,10 +547,19 @@ ### Criteria Parameters | ||
"$base": { | ||
"logLocation": "/logs" | ||
"logLocation": "/logs", | ||
"flags": ["a", "b"], | ||
"tags": { | ||
"$value": ["DEBUG"], | ||
"$replace": true | ||
} | ||
}, | ||
"production": { | ||
"logLevel": "error" | ||
"logLevel": "error", | ||
"flags": ["c", "d"], | ||
"tags": ["INFO", "ERROR"] | ||
}, | ||
"qa": { | ||
"logLevel": "info", | ||
"logLocation": "/qa/logs" | ||
"logLocation": "/qa/logs", | ||
"flags": ["e", "f"], | ||
"tags": ["DEBUG"] | ||
}, | ||
@@ -563,3 +580,5 @@ "staging": { | ||
"logLevel": "error", | ||
"logLocation": "/logs" | ||
"logLocation": "/logs", | ||
"flags": ["a", "b", "c", "d"], | ||
"tags": ["INFO", "ERROR"] | ||
} | ||
@@ -576,7 +595,11 @@ ``` | ||
"logLevel": "debug", | ||
"logLocation": "/logs" | ||
"logLocation": "/logs", | ||
"flags": ["a", "b"], | ||
"tags": ["DEBUG"], | ||
} | ||
``` | ||
If the same key occurs in `$base` and the `filtered value` then value in `$base` will be overridden. | ||
If the same key occurs in `$base` and the `filtered value`: | ||
- for objects, the value in `$base` will be overridden. | ||
- for arrays, the arrays are merged unless the `$base` array is specified with the `$value` key and the `$replace` flag as shown above. | ||
@@ -583,0 +606,0 @@ In the above sample, when requesting the **key** `/` with: |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
37897
466
677
3
1
+ Addedjoi@17.x.x
+ Added@hapi/hoek@9.3.0(transitive)
+ Added@hapi/topo@5.1.0(transitive)
+ Added@sideway/address@4.1.5(transitive)
+ Added@sideway/formula@3.0.1(transitive)
+ Added@sideway/pinpoint@2.0.0(transitive)
+ Addedansi-regex@5.0.1(transitive)
+ Addedansi-styles@4.3.0(transitive)
+ Addedcliui@7.0.4(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addedemoji-regex@8.0.0(transitive)
+ Addedescalade@3.2.0(transitive)
+ Addedis-fullwidth-code-point@3.0.0(transitive)
+ Addedjoi@17.13.3(transitive)
+ Addedstring-width@4.2.3(transitive)
+ Addedstrip-ansi@6.0.1(transitive)
+ Addedwrap-ansi@7.0.0(transitive)
+ Addedy18n@5.0.8(transitive)
+ Addedyargs@16.2.0(transitive)
+ Addedyargs-parser@20.2.9(transitive)
- Removed@hapi/joi@15.x.x
- Removed@hapi/address@2.1.4(transitive)
- Removed@hapi/bourne@1.3.2(transitive)
- Removed@hapi/hoek@6.2.48.5.1(transitive)
- Removed@hapi/joi@15.1.1(transitive)
- Removed@hapi/topo@3.1.6(transitive)
- Removedansi-regex@4.1.1(transitive)
- Removedansi-styles@3.2.1(transitive)
- Removedcamelcase@5.3.1(transitive)
- Removedcliui@5.0.0(transitive)
- Removedcolor-convert@1.9.3(transitive)
- Removedcolor-name@1.1.3(transitive)
- Removeddecamelize@1.2.0(transitive)
- Removedemoji-regex@7.0.3(transitive)
- Removedfind-up@3.0.0(transitive)
- Removedis-fullwidth-code-point@2.0.0(transitive)
- Removedlocate-path@3.0.0(transitive)
- Removedp-limit@2.3.0(transitive)
- Removedp-locate@3.0.0(transitive)
- Removedp-try@2.2.0(transitive)
- Removedpath-exists@3.0.0(transitive)
- Removedrequire-main-filename@2.0.0(transitive)
- Removedset-blocking@2.0.0(transitive)
- Removedstring-width@3.1.0(transitive)
- Removedstrip-ansi@5.2.0(transitive)
- Removedwhich-module@2.0.1(transitive)
- Removedwrap-ansi@5.1.0(transitive)
- Removedy18n@4.0.3(transitive)
- Removedyargs@13.3.2(transitive)
- Removedyargs-parser@13.1.2(transitive)
Updated@hapi/hoek@9.x.x
Updatedyargs@16.x.x