Socket
Socket
Sign inDemoInstall

yup

Package Overview
Dependencies
Maintainers
1
Versions
127
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

yup - npm Package Compare versions

Comparing version 0.8.3 to 0.9.0

karma.conf.js

16

CHANGELOG.md

@@ -0,3 +1,17 @@

## 0.9.0
__breaking__
- `test` functions are no longer passed `path` and `context` as arguments, Instead they are now values on `this` inside the test function.
- test functions are longer called with the schema as their `this` value, use `this.schema` instead.
__other changes__
- test functions are call with with a new context object, including, options, parent and `createError` for dynamically altering validation errors.
## 0.8.3
- document `stripUnknown`
- add `recursive` option
- add `noUnknown()` test to objects
## 0.8.2
- the default, default for objects now adds keys for all fields, not just fields with non empty defaults
- default for objects now adds keys for all fields, not just fields with non empty defaults

@@ -4,0 +18,0 @@ ## 0.8.1

19

gulpfile.js

@@ -9,13 +9,3 @@ 'use strict';

gulp.task('test-runner', function(){
gulp.watch(['./src/**/*.js'], ['compile'])
gulp.watch('./test/**/*.js', function(e){
gulp.src(e.path)
.pipe(plumber())
.pipe(mocha({ reporter: 'spec' }))
})
})
gulp.task('clean', function(cb){

@@ -34,12 +24,3 @@ del('./lib', cb);

gulp.task('watch', function(){
gulp.watch(['./src/**/*.js', './test/**/*.js'], ['build'])
})
gulp.task('mocha', function () {
return gulp.src('test.js', { read: false })
.pipe(mocha({ reporter: 'spec' }));
})
gulp.task('publish', ['compile'], require('jq-release'))

@@ -8,6 +8,6 @@ 'use strict';

ValidationError = require('./util/validation-error'),
getter = require('property-expr').getter,
locale = require('./locale.js').mixed,
_ = require('./util/_'),
cloneDeep = require('./util/clone'),
createValidation = require('./util/createValidation'),
BadSet = require('./util/set');

@@ -89,8 +89,7 @@

_resolve: function _resolve(context) {
_resolve: function _resolve(context, parent) {
var schema = this;
return this._conditions.reduce(function (schema, match) {
if (!context) throw new Error('missing the context necessary to cast this value');
return match.resolve(schema, getter(match.key)(context));
return match.resolve(schema, match.getValue(parent, context));
}, schema);

@@ -100,15 +99,17 @@ },

//-- tests
_validate: function _validate(value, _opts, _state) {
_validate: function _validate(value) {
var options = arguments[1] === undefined ? {} : arguments[1];
var state = arguments[2] === undefined ? {} : arguments[2];
var valids = this._whitelist,
invalids = this._blacklist,
context = (_opts || {}).context || _state.parent,
context = options.context,
parent = state.parent,
schema = undefined,
state = undefined,
endEarly = undefined,
isStrict = undefined;
state = _state;
schema = this._resolve(context);
isStrict = schema._option('strict', _opts);
endEarly = schema._option('abortEarly', _opts);
schema = this._resolve(context, parent);
isStrict = schema._option('strict', options);
endEarly = schema._option('abortEarly', options);

@@ -122,3 +123,3 @@ var path = state.path;

if (!state.isCast && !isStrict) value = schema._cast(value, _opts);
if (!state.isCast && !isStrict) value = schema._cast(value, options);

@@ -147,3 +148,3 @@ // value is cast, we can check if it meets type requirements

var result = schema.tests.map(function (fn) {
return fn.call(schema, value, path, context);
return fn({ value: value, path: path, state: state, schema: schema, options: options });
});

@@ -248,3 +249,3 @@

errorMsg = formatError(opts.message || locale['default']);
var validate = createValidation(opts);

@@ -266,15 +267,20 @@ isExclusive = opts.name && next._exclusive[opts.name] === true;

return next;
return next
function validate(value, path, context) {
var _this2 = this;
// function validate(value, path, context) {
return new Promise(function (resolve, reject) {
!opts.useCallback ? resolve(opts.test.call(_this2, value, path, context)) : opts.test.call(_this2, value, path, context, function (err, valid) {
return err ? reject(err) : resolve(valid);
});
}).then(function (valid) {
if (!valid) throw new ValidationError(errorMsg(babelHelpers._extends({ path: path }, opts.params)), value, path);
});
}
// return new Promise((resolve, reject) => {
// !opts.useCallback
// ? resolve(opts.test.call(this, value, path, context))
// : opts.test.call(this, value, path, context, (err, valid) => err ? reject(err) : resolve(valid))
// })
// .then(validOrError => {
// if ( ValidationError.isError(validOrError) )
// throw normalizeError(validOrError, errorMsg, opts.params, path, value)
// else if (!validOrError)
// throw new ValidationError(errorMsg({ path, ...opts.params }), path, value)
// })
// }
;
}),

@@ -336,2 +342,15 @@

function normalizeError(error, msg, params, path, value) {
if (error.path === undefined) error.path = path;
if (error.value === undefined) error.value = value;
error.errors = error.errors.length ? error.errors.map(function (msg) {
return formatError(msg, babelHelpers._extends({ path: error.path }, error.path));
}) : [msg(babelHelpers._extends({ path: error.path }, error.path))];
return new ValidationError(error.errors, error.path, error.value);
}
function nodeify(promise, cb) {

@@ -338,0 +357,0 @@ if (typeof cb !== 'function') return promise;

@@ -90,3 +90,3 @@ 'use strict';

}).test('integer', msg, function (val) {
return value == null || val === (val | 0);
return val == null || val === (val | 0);
});

@@ -93,0 +93,0 @@ },

@@ -203,3 +203,3 @@ 'use strict';

test: function test(value) {
return value == null || !noAllow || unknown(this, value).length === 0;
return value == null || !noAllow || unknown(this.schema, value).length === 0;
}

@@ -206,0 +206,0 @@ });

@@ -9,2 +9,3 @@ 'use strict';

var isSchema = _require.isSchema;
var getter = require('property-expr').getter;

@@ -19,4 +20,7 @@ module.exports = Conditional;

var otherwise = options.otherwise;
var prefix = options.contextPrefix || '$';
this.prefix = prefix;
this.key = key;
this.isContext = key.indexOf(prefix) === 0;

@@ -40,2 +44,10 @@ if (typeof options === 'function') this.fn = options;else {

Conditional.prototype.getValue = function getValue(parent, context) {
var path = this.isContext ? this.key.slice(this.prefix.length) : this.key;
if (this.isContext && !context || !this.isContext && !context && !parent) throw new Error('missing the context necessary to cast this value');
return getter(path)(this.isContext ? context : parent || context);
};
Conditional.prototype.resolve = function resolve(ctx, value) {

@@ -42,0 +54,0 @@ var schema = this.fn.call(ctx, value, ctx);

@@ -17,7 +17,5 @@ 'use strict';

function ValidationError(errors, value) {
function ValidationError(errors, value, field) {
var _this = this;
var field = arguments[2] === undefined ? '' : arguments[2];
this.name = 'ValidationError';

@@ -29,3 +27,3 @@ this.value = value;

[].concat(errors).forEach(function (err) {
if (errors) [].concat(errors).forEach(function (err) {
_this.errors = _this.errors.concat(err.errors || err);

@@ -44,2 +42,6 @@

ValidationError.isError = function (err) {
return err && err.name === 'ValidationError';
};
ValidationError.formatError = function (message, params) {

@@ -52,3 +54,3 @@ if (typeof message === 'string') message = replace(message);

params.path = 'this' + (path ? path.charAt(0) === '[' ? path : '.' + path : '');
params.path = path || 'this';

@@ -55,0 +57,0 @@ return message(params);

{
"name": "yup",
"version": "0.8.3",
"version": "0.9.0",
"description": "Dead simple Object schema validation",
"main": "lib/index.js",
"scripts": {
"test": "gulp compile && mocha -R spec ./test/*.js"
"test": "karma start --single-run",
"build": "gulp compile"
},

@@ -20,2 +21,4 @@ "repository": {

"devDependencies": {
"babel-core": "^5.7.4",
"babel-loader": "^5.3.2",
"chai": "^1.9.1",

@@ -29,6 +32,15 @@ "chai-as-promised": "^4.1.1",

"gulp-rename": "^1.2.2",
"jq-release": "*",
"karma": "^0.12.2",
"karma-mocha": "^0.2.0",
"karma-mocha-reporter": "^1.0.2",
"karma-phantomjs-launcher": "^0.2.0",
"karma-sourcemap-loader": "^0.3.5",
"karma-webpack": "^1.6.0",
"mocha": "^1.21.4",
"jq-release": "*",
"node-libs-browser": "^0.5.2",
"phantomjs": "^1.9.17",
"sinon": "^1.10.3",
"sinon-chai": "^2.5.0"
"sinon-chai": "^2.5.0",
"webpack": "^1.10.1"
},

@@ -35,0 +47,0 @@ "dependencies": {

@@ -113,3 +113,3 @@ Yup

### `ValidationError`
### `ValidationError(String|Array<String> errors, String path, Any value)`

@@ -138,7 +138,7 @@ Thrown on failed validations, with the following properties

#### `mixed.concat(schema)`
#### `mixed.concat(Schema schema)`
Creates a new instance of the schema by combining two schemas. Only schemas of the same type can be concatenated.
#### `mixed.validate(value, [options, callback])`
#### `mixed.validate(Any value, [Object options, Function callback])`

@@ -148,2 +148,11 @@ Returns the value (a cast value if `isStrict` is `false`) if the value is valid, and returns the errors otherwise. This method is __asynchronous__ and returns a Promise object, that is fulfilled with the value, or rejected with a `ValidationError`. If you are more comfortable with Node style callbacks, then you can provide one to be called when the validation is complete (called with the Error as the first argument, and value

The `options` argument is an object hash containing any schema options you may want to override (or specify for the first time).
- `strict` -> boolean: default `false`, only validate the input, and skip and coercion or transformation
- `abortEarly` -> boolean: default `true`, return from validation methods on the first error rather than after all validations run.
- `stripUnknown` -> boolean: default `false` remove unspecified keys from objects.
- `recursive` -> boolean: default `true` when `false` validations will not descend into sub schemas (relavant for objects or arrays).
- `context` -> an `object` containing any context for validating schema conditions (see: `when()`)
```javascript

@@ -175,20 +184,13 @@ schema.validate({ name: 'jimmy',age: 24 })

#### `mixed.isValid(value, [options, callback])`
#### `mixed.isValid(Any value, [Object options, Function callback]) -> Promise`
Returns `true` when the passed in value matches the schema. if `false` then the schema also has a `.errors` field which is an array of validation error messages (strings), thrown by the schema. `isValid` is __asynchronous__ and returns a Promise object. If you are more comfortable with
Node style callbacks, then you can provide one to be called when the validation is complete.
Returns `true` when the passed in value matches the schema. if `false` then the schema also has a `.errors` field which is an array of validation error messages (strings), thrown by the schema. `isValid` is __asynchronous__ and returns a Promise object. If you are more comfortable with Node style callbacks, providing a function as teh last argument will opt into that interface.
The `options` argument is an object hash containing any schema options you may want to override (or specify for the first time).
Takes the same options as `validate()`.
- `strict` -> boolean: default `false`, only validate the input, and skip and coercion or transformation
- `abortEarly` -> boolean: default `true`, return from validation methods on the first error rather than after all validations run.
- `stripUnknown` -> boolean: default `false` remove unspecified keys from objects.
- `recursive` -> boolean: default `true` when `false` validations will not descend into sub schemas (relavant for objects or arrays).
- `context` -> an `object` containing any context for validating schema conditions (see: `when()`)
#### `mixed.cast(value) -> Any`
#### `mixed.cast(value)`
Attempts to coerce the passed in value to a value that matches the schema. For example: `'5'` will cast to `5` when using the `number()` type. Failed casts generally return `null`, but may also return results like `NaN` and unexpected strings.
#### `mixed.isType(value)`
#### `mixed.isType(Any value) -> Boolean`

@@ -201,3 +203,3 @@ Runs a type check against the passed in `value`. It returns true if it matches, it does not cast the value. When `nullable()` is set `null` is considered a valid value of the type. You should use `isType` for all Schema type checks.

#### `mixed.default(value)`
#### `mixed.default(Any value)`

@@ -217,7 +219,12 @@ Sets a default value to use when the value is `undefined` (or `null` when the schema is not nullable). Defaults are created after transformations are executed, but before validations, to help ensure that safe defaults are specified. The default value will be cloned on each use wich can incur performance penalty for objects and arrays. To avoid this overhead you can also pass a function that returns an new default.

#### `mixed.typeError(message)` (default: '${path} (value: \`${value}\`) must be a \`${type}\` type')
#### `mixed.default() -> Any`
Calling `default` with no arguments will return the current default value
#### `mixed.typeError(String message)` (default: '${path} (value: \`${value}\`) must be a \`${type}\` type')
Define an error message for failed type checks. The `${value}` and `${type}` interpolation can be used in the `message` argument.
#### `mixed.nullable(isNullable)` (default: `false`)
#### `mixed.nullable(Bool isNullable)` (default: `false`)

@@ -227,7 +234,7 @@ Indicates that `null` is a valid value for the schema. Without `nullable()`

#### `mixed.required([message])`
#### `mixed.required([String message])`
Mark the schema as required. All field values apart from `undefined` meet this requirement.
#### `mixed.oneOf(arrayOfValues, [message])` Alias: `equals`
#### `mixed.oneOf(Array<Any> arrayOfValues, [String message])` Alias: `equals`

@@ -243,3 +250,3 @@ Whitelist a set of values. Values added are automatically removed from any blacklist if they are in it. The `${values}` interpolation can be used in the `message` argument.

#### `mixed.notOneOf(arrayOfValues, [message])`
#### `mixed.notOneOf(Array<Any> arrayOfValues, [String message])`

@@ -254,3 +261,3 @@ Blacklist a set of values. Values added are automatically removed from any whitelist if they are in it. The `${values}` interpolation can be used in the `message` argument.

#### `mixed.when(key, options | function)`
#### `mixed.when(String key, Object options | Function func)`

@@ -263,6 +270,7 @@ Adjust the schema based on a sibling or sibling children fields. You can provide an object literal where the key `is` is value or a matcher function, `then` provides the true schema and/or `otherwise` for the failure condition.

Like Joi you can also prefix properties with `$` to specify a property that is dependent on `context` passed in by `validate()` or `isValid`.
```javascript
var inst = yup.object({
isBig: yup.boolean(),
other: yup.number(),
count: yup.number()

@@ -274,15 +282,16 @@ .when('isBig', {

})
.when('other', (other, schema) => other === 4
.when('$other', (other, schema) => other === 4
? schema.max(6)
: schema)
})
inst.validate(value, { context: { other: 4 }})
```
__note: because `when` conditions must be resolved during `cast()`, a synchronous api, `is` cannot be a schema object as checking schema validity it is asynchronous__
#### `mixed.test(name, message, fn, [callbackStyleAsync])`
#### `mixed.test(String name, String message, Function fn, [Bool callbackStyleAsync])`
Adds a test function to the validation chain. Tests are run after any object is cast. Many types have some tests built in, but you can create custom ones easily. In order to allow asynchronous custom validations _all_ tests are run asynchronously. A consequence of this is that test execution order cannot be guaranteed.
All tests must provide a `name`, an error `message` and a validation function that must return `true` or `false`. To make a test async return a promise that resolves `true` or `false`. If you perfer the Node callback style, you can pass `true` for `callbackStyleAsync` and the validation function will pass in an additional `done` function as the last parameter to be called with the validity.
All tests must provide a `name`, an error `message` and a validation function that must return `true` or `false` or a `ValidationError`. To make a test async return a promise that resolves `true` or `false` or a `ValidationError`. If you perfer the Node callback style, you can pass `true` for `callbackStyleAsync` and the validation function will pass in an additional `done` function as the last parameter to be called with the validity.

@@ -299,3 +308,3 @@ for the `message` argument you can provide a string which is will interpolate certain values if specified using the `${param}` syntax. By default all test messages are passed a `path` value which is valuable in nested schemas.

var asyncJimmySchema = yup.string()
.test('is-jimmy', '${path} is not Jimmy', function (value, path, context){
.test('is-jimmy', '${path} is not Jimmy', function (value){
return fetch('/is-jimmy/' + value)

@@ -309,3 +318,3 @@ .then(response => response.responseText === 'true')

function test(value, path, context, done){
function test(value, done){
// error argument is for exceptions, not an failed tests

@@ -322,5 +331,13 @@ done(null, value === 'jimmy')

test functions are called with a special context, or `this` value, that exposes some useful metadata and functions.
#### `mixed.test(options)`
- `this.path`: the string path of the current validation
- `this.schema`: the resolved schema object that the test is running against.
- `this.options`: the `options` object that validate() or isValid() was called with
- `this.parent`: in the case of nested schema, this is the value of the parent object
- `this.createError(Object: { path: String, message: String })`: create and return a validation error. Useful for dynamically setting the `path`, or more likely, the error `message`. If either option is omitted it will use the current path, or default message.
#### `mixed.test(Object options)`
Alternative `test(..)` signature. `options` is an object containing some of the following options:

@@ -345,3 +362,3 @@

#### `mixed.transform(fn)`
#### `mixed.transform(Function fn)`

@@ -386,15 +403,15 @@ Adds a transformation to the transform chain. Transformations are central to the casting process, default transforms for each type coerce values to the specific type (as verified by [`isType()`](mixedistypevalue)). transforms are run before validations and only applied when `strict` is `true`. Some types have built in transformations.

#### `string.required([message])`
#### `string.required([String message])`
The same as the `mixed()` schema required, except that empty strings are also considered 'missing' values. To allow empty strings but fail on `undefined` values use: `string().required().min(0)`
#### `string.min(limit, [message])`
#### `string.min(Number limit, [String message])`
Set an minimum length limit for the string value. The `${min}` interpolation can be used in the `message` argument
#### `string.max(limit, [message])`
#### `string.max(Number limit, [String message])`
Set an maximum length limit for the string value. The `${max}` interpolation can be used in the `message` argument
#### `string.matches(regex, [message])`
#### `string.matches(Regex regex, [String message])`

@@ -409,7 +426,7 @@ Provide an arbitrary `regex` to match the value against.

#### `string.email([message])`
#### `string.email([String message])`
Validates the value as an email address via a regex.
#### `string.url(message)`
#### `string.url([String message])`

@@ -419,3 +436,3 @@ Validates the value as a valid URL via a regex.

#### `string.trim([message])`
#### `string.trim([String message])`

@@ -425,7 +442,7 @@ Transforms string values by removing leading and trailing whitespace. If

#### `string.lowercase([message])`
#### `string.lowercase([String message])`
Transforms the string value to lowercase. If `strict()` is set it will only validate that the value is lowercase.
#### `string.uppercase([message])`
#### `string.uppercase([String message])`

@@ -443,3 +460,3 @@ Transforms the string value to uppercase. If `strict()` is set it will only validate that the value is uppercase.

#### `number.min(limit, [message])`
#### `number.min(Number limit, [String message])`

@@ -449,3 +466,3 @@ Set the minimum value allowed. The `${min}` interpolation can be used in the

#### `number.max(limit, [message])`
#### `number.max(Number limit, [String message])`

@@ -455,11 +472,11 @@ Set the maximum value allowed. The `${max}` interpolation can be used in the

#### `number.positive([message])`
#### `number.positive([String message])`
Value must be a positive number.
#### `number.negative([message])`
#### `number.negative([String message])`
Value mut be a negative number.
#### `number.integer([message])`
#### `number.integer([String message])`

@@ -469,3 +486,3 @@ Transformation that coerces the value into an integer via truncation

#### `round(type)` - 'floor', 'ceil', 'round'
#### `round(String type)` - 'floor', 'ceil', 'round'

@@ -493,7 +510,7 @@ Rounds the value by the specified method (defaults to 'round').

#### `date.min(limit, [message])`
#### `date.min(Date|String limit, [String message])`
Set the minimum date allowed.
#### `date.max(limit, [message])`
#### `date.max(Date|String limit, [String message])`

@@ -514,19 +531,19 @@ Set the maximum date allowed.

### `array.of(type)`
### `array.of(Schema type)`
Specify the schema of array elements. `of()` is optional and when ommited the array schema will not validate its contents.
#### `array.required([message])`
#### `array.required([String message])`
The same as the `mixed()` schema required, except that empty arrays are also considered 'missing' values. To allow empty arrays but fail on `undefined` values use: `array().required().min(0)`
#### `array.min(limit, [message])`
#### `array.min(Number limit, [String message])`
Set an minimum length limit for the array. The `${min}` interpolation can be used in the `message` argument.
#### `array.max(limit, [message])`
#### `array.max(Number limit, [String message])`
Set an maximum length limit for the array. The `${max}` interpolation can be used in the `message` argument.
### `array.compact(rejector)`
### `array.compact(Function rejector)`

@@ -560,7 +577,7 @@ Removes falsey values from the array. Providing a rejector function lets you specify the rejection criteria yourself.

#### `object.shape(schemaHash, [noSortEdges])`
#### `object.shape(Object schemaHash, [noSortEdges])`
Define the keys of the object and the schemas for said keys.
#### `object.from(fromKey, toKey, alias)`
#### `object.from(String fromKey, String toKey, Bool alias)`

@@ -581,2 +598,7 @@ Transforms the specified key to a new key. If `alias` is `true` then the old key will be left.

#### `object.noUnknown([Bool onlyKnownKeys, String msg])`
Validate that teh object value only contains keys specified in `shape`, pass `false` as the first argument to disable the check. Restricting keys to known, also enables `stripUnknown` option, when not in strict mode.
#### `object.camelcase()`

@@ -583,0 +605,0 @@

@@ -18,3 +18,3 @@ 'use strict';

reach: require('./util/reach'),
ValidationError: require('./util/validation-error'),

@@ -25,3 +25,3 @@

addMethod(schemaType, name, fn) {
if ( !schemaType || !isSchema(schemaType.prototype))
if ( !schemaType || !isSchema(schemaType.prototype))
throw new TypeError('You must provide a yup schema constructor function')

@@ -31,5 +31,5 @@

if ( typeof fn !== 'function') throw new TypeError('Method function must be provided')
schemaType.prototype[name] = fn
}
}

@@ -6,6 +6,6 @@ 'use strict';

, ValidationError = require('./util/validation-error')
, getter = require('property-expr').getter
, locale = require('./locale.js').mixed
, _ = require('./util/_')
, cloneDeep = require('./util/clone')
, createValidation = require('./util/createValidation')
, BadSet = require('./util/set');

@@ -48,3 +48,3 @@

concat(schema){
if (!schema)
if (!schema)
return this

@@ -62,3 +62,3 @@

// trim exclusive tests, take the most recent ones
next.tests = _.uniq(next.tests.reverse(),
next.tests = _.uniq(next.tests.reverse(),
(fn, idx) => next[fn.VALIDATION_KEY] ? fn.VALIDATION_KEY : idx).reverse()

@@ -91,8 +91,7 @@

_resolve(context){
_resolve(context, parent){
var schema = this;
return this._conditions.reduce(function(schema, match){
if(!context) throw new Error('missing the context necessary to cast this value')
return match.resolve(schema, getter(match.key)(context))
return match.resolve(schema, match.getValue(parent, context))
}, schema)

@@ -102,12 +101,12 @@ },

//-- tests
_validate(value, _opts, _state) {
_validate(value, options = {}, state = {}) {
let valids = this._whitelist
, invalids = this._blacklist
, context = (_opts || {}).context || _state.parent
, schema, state, endEarly, isStrict;
, context = options.context
, parent = state.parent
, schema, endEarly, isStrict;
state = _state
schema = this._resolve(context)
isStrict = schema._option('strict', _opts)
endEarly = schema._option('abortEarly', _opts)
schema = this._resolve(context, parent)
isStrict = schema._option('strict', options)
endEarly = schema._option('abortEarly', options)

@@ -120,3 +119,3 @@ let path = state.path

if ( !state.isCast && !isStrict )
value = schema._cast(value, _opts)
value = schema._cast(value, options)

@@ -140,3 +139,3 @@ // value is cast, we can check if it meets type requirements

}
// It makes no sense to validate further at this point if their are errors

@@ -146,3 +145,3 @@ if ( errors.length )

let result = schema.tests.map(fn => fn.call(schema, value, path, context))
let result = schema.tests.map(fn => fn({ value, path, state, schema, options }))

@@ -171,3 +170,3 @@ result = endEarly

.catch(err => {
if ( err.name === 'ValidationError')
if ( err.name === 'ValidationError')
return false

@@ -182,3 +181,3 @@

var dflt = _.has(this, '_default') ? this._default : this._defaultDefault
return typeof dflt === 'function'
return typeof dflt === 'function'
? dflt.call(this) : cloneDeep(dflt)

@@ -199,7 +198,7 @@ }

required(msg) {
return this.test({
name: 'required',
exclusive: true,
return this.test({
name: 'required',
exclusive: true,
message: msg || locale.required,
test: value => value != null
test: value => value != null
})

@@ -232,3 +231,3 @@ },

if( typeof name === 'string' ) {
if( typeof message === 'function')
if( typeof message === 'function')
test = message, message = name, name = null

@@ -245,3 +244,3 @@

errorMsg = formatError(opts.message || locale.default)
var validate = createValidation(opts)

@@ -253,3 +252,3 @@ isExclusive = opts.name && next._exclusive[opts.name] === true

throw new TypeError('You cannot have an exclusive validation without a `name`')
next._exclusive[opts.name] = true

@@ -266,13 +265,17 @@ validate.VALIDATION_KEY = opts.name

function validate(value, path, context) {
return new Promise((resolve, reject) => {
!opts.useCallback
? resolve(opts.test.call(this, value, path, context))
: opts.test.call(this, value, path, context, (err, valid) => err ? reject(err) : resolve(valid))
})
.then(valid => {
if (!valid)
throw new ValidationError(errorMsg({ path, ...opts.params }), value, path)
})
}
// function validate(value, path, context) {
// return new Promise((resolve, reject) => {
// !opts.useCallback
// ? resolve(opts.test.call(this, value, path, context))
// : opts.test.call(this, value, path, context, (err, valid) => err ? reject(err) : resolve(valid))
// })
// .then(validOrError => {
// if ( ValidationError.isError(validOrError) )
// throw normalizeError(validOrError, errorMsg, opts.params, path, value)
// else if (!validOrError)
// throw new ValidationError(errorMsg({ path, ...opts.params }), path, value)
// })
// }
},

@@ -294,3 +297,3 @@

next._whitelistError = (valids, path) =>
next._whitelistError = (valids, path) =>
formatError(msg || locale.oneOf, { values: valids.join(', '), path })

@@ -309,3 +312,3 @@

next._blacklistError = (invalids, path) =>
next._blacklistError = (invalids, path) =>
formatError(msg || locale.notOneOf, { values: invalids.join(', '), path })

@@ -333,6 +336,22 @@

for( var method in aliases ) if ( _.has(aliases, method) )
aliases[method].forEach(
for( var method in aliases ) if ( _.has(aliases, method) )
aliases[method].forEach(
alias => SchemaType.prototype[alias] = SchemaType.prototype[method]) //eslint-disable-line no-loop-func
function normalizeError(error, msg, params, path, value){
if (error.path === undefined)
error.path = path
if (error.value === undefined)
error.value = value
error.errors = error.errors.length
? error.errors.map( msg => formatError(msg, { path: error.path, ...error.path }))
: [ msg({ path: error.path, ...error.path }) ]
return new ValidationError(error.errors, error.path, error.value)
}
function nodeify(promise, cb){

@@ -339,0 +358,0 @@ if(typeof cb !== 'function') return promise

@@ -61,3 +61,3 @@ 'use strict';

.transform( v => v != null ? (v | 0) : v)
.test('integer', msg, val => value == null || val === (val | 0))
.test('integer', msg, val => val == null || val === (val | 0))
},

@@ -74,2 +74,2 @@

}
})
})

@@ -10,3 +10,3 @@ 'use strict';

, c = require('case')
, {
, {
isObject

@@ -43,3 +43,3 @@ , transform

value = JSON.parse(value)
}
}
catch (err){ value = null }

@@ -84,3 +84,3 @@ }

var fieldSchema = fields[prop] === '$this' ? schema.default(undefined) : fields[prop]
obj[prop] = fieldSchema.cast(value[prop], { context: obj })

@@ -120,3 +120,3 @@ }

errors.push(err)
return err.value
return err.value
})

@@ -132,3 +132,3 @@ .then(value => {

, path = (_state.path ? (_state.path + '.') : '') + key;
return field._validate(value[key]

@@ -139,10 +139,10 @@ , _opts

result = endEarly
result = endEarly
? Promise.all(result).catch(scopeError(value))
: collectErrors(result, value, _state.path, errors)
return result.then(() => value)
})
},

@@ -152,3 +152,3 @@

var next = MixedSchema.prototype.concat.call(this, schema)
next._nodes = sortFields(next.fields, next._excludedEdges)

@@ -179,5 +179,5 @@

return this.transform( obj => {
if ( obj == null)
if ( obj == null)
return obj
var newObj = transform(obj, (o, val, key) => key !== from && (o[key] = val), {})

@@ -196,12 +196,12 @@

var next = this.test({
name: 'noUnknown',
exclusive: true,
var next = this.test({
name: 'noUnknown',
exclusive: true,
message: message || locale.noUnknown,
test(value) {
return value == null || !noAllow || unknown(this, value).length === 0
test(value) {
return value == null || !noAllow || unknown(this.schema, value).length === 0
}
})
if ( noAllow )
if ( noAllow )
this._options.stripUnknown = true

@@ -238,12 +238,12 @@

node = split(node)[0]
if ( !~nodes.indexOf(node) )
if ( !~nodes.indexOf(node) )
nodes.push(node)
if ( !~excludes.indexOf(`${key}-${node}`) )
if ( !~excludes.indexOf(`${key}-${node}`) )
edges.push([key, node])
})
})
}
return toposort.array(nodes, edges).reverse()
}

@@ -16,4 +16,4 @@ var Promise = require('promise/lib/es6-extensions')

function settled(promises){
let settle = promise => promise.then(
value => ({ fulfilled: true, value }),
let settle = promise => promise.then(
value => ({ fulfilled: true, value }),
value => ({ fulfilled: false, value }))

@@ -26,3 +26,3 @@

// unwrap aggregate errors
errors = errors.inner && errors.inner.length
errors = errors.inner && errors.inner.length
? errors.inner : [].concat(errors)

@@ -34,3 +34,3 @@

if ( errors.length )
if ( errors.length )
throw new ValidationError(errors, value, path)

@@ -44,3 +44,3 @@ })

for (var key in source) if ( has(source, key))
for (var key in source) if ( has(source, key))
target[key] = source[key];

@@ -54,3 +54,3 @@ }

var seen = {}
return arr.filter( (item, idx) => {

@@ -67,6 +67,6 @@ var key = iter(item, idx)

if( Array.isArray(obj))
if( Array.isArray(obj))
obj.forEach(cb)
else
for(var key in obj) if( has(obj, key) )
for(var key in obj) if( has(obj, key) )
cb(obj[key], key, obj)

@@ -103,3 +103,3 @@

}
return target;

@@ -126,3 +126,3 @@ }

module.exports = {
inherits, uniq, has,
inherits, uniq, has,
assign, merge, transform,

@@ -129,0 +129,0 @@ isSchema, isObject, isPlainObject, isDate,

'use strict';
var { has, isSchema } = require('./_')
, getter = require('property-expr').getter

@@ -9,5 +10,8 @@ module.exports = Conditional

constructor(key, type, options){
let { is, then, otherwise } = options;
let { is, then, otherwise } = options
, prefix = options.contextPrefix || '$';
this.prefix = prefix;
this.key = key
this.isContext = key.indexOf(prefix) === 0

@@ -18,6 +22,6 @@ if ( typeof options === 'function')

{
if( !has(options, 'is') )
if( !has(options, 'is') )
throw new TypeError('`is:` is required for `when()` conditions')
if( !options.then && !options.otherwise )
if( !options.then && !options.otherwise )
throw new TypeError('either `then:` or `otherwise:` is required for `when()` conditions')

@@ -35,2 +39,11 @@

getValue(parent, context){
var path = this.isContext ? this.key.slice(this.prefix.length) : this.key
if ( (this.isContext && !context) || (!this.isContext && !context && !parent))
throw new Error('missing the context necessary to cast this value')
return getter(path)(this.isContext ? context : (parent || context) )
}
resolve(ctx, value) {

@@ -37,0 +50,0 @@ let schema = this.fn.call(ctx, value, ctx)

'use strict';
var strReg = /\$\{\s*(\w+)\s*\}/g;
let replace = str =>
let replace = str =>
params => str.replace(strReg, (_, key) => params[key] || '')

@@ -9,3 +9,3 @@

function ValidationError(errors, value, field = '') {
function ValidationError(errors, value, field) {
this.name = 'ValidationError'

@@ -16,12 +16,13 @@ this.value = value

this.inner = [];
[].concat(errors).forEach(err => {
this.errors = this.errors.concat(err.errors || err)
if ( err.inner )
this.inner = this.inner.concat(err.inner.length ? err.inner : err)
})
if ( errors )
[].concat(errors).forEach(err => {
this.errors = this.errors.concat(err.errors || err)
this.message = this.errors.length > 1
? `${this.errors.length } errors occurred`
if ( err.inner )
this.inner = this.inner.concat(err.inner.length ? err.inner : err)
})
this.message = this.errors.length > 1
? `${this.errors.length } errors occurred`
: this.errors[0]

@@ -36,2 +37,6 @@

ValidationError.isError = function(err){
return err && err.name === 'ValidationError'
}
ValidationError.formatError = function(message, params) {

@@ -42,6 +47,4 @@ if ( typeof message === 'string')

let fn = ({ path, ...params }) => {
params.path = 'this' + (path
? (path.charAt(0) === '[' ? path : '.' + path)
: '')
params.path = path || 'this'
return message(params)

@@ -51,2 +54,2 @@ }

return arguments.length === 1 ? fn : fn(params)
}
}

@@ -5,7 +5,7 @@ 'use strict';

, chaiAsPromised = require('chai-as-promised')
, Promise = require('promise/lib/es6-extensions')
, string = require('../lib/string')
, number = require('../lib/number')
, object = require('../lib/object')
, array = require('../lib/array');
, Promise = require('promise/src/es6-extensions')
, string = require('../src/string')
, number = require('../src/number')
, object = require('../src/object')
, array = require('../src/array');

@@ -69,3 +69,3 @@ chai.use(chaiAsPromised);

inst.isValid(['gg', 3]).should.eventually.equal(false),
inst.isValid(['4', 3]).should.eventually.equal(true),

@@ -84,3 +84,3 @@

])
})

@@ -106,3 +106,3 @@

err.errors.length.should.equal(2)
err.errors.should.eql(['oops', 'this[0].str is a required field'])
err.errors.should.eql(['oops', '[0].str is a required field'])
})

@@ -109,0 +109,0 @@ ])

@@ -5,4 +5,4 @@ 'use strict';

, chaiAsPromised = require('chai-as-promised')
, Promise = require('promise/lib/es6-extensions')
, bool = require('../lib/boolean');
, Promise = require('promise/src/es6-extensions')
, bool = require('../src/boolean');

@@ -9,0 +9,0 @@ chai.use(chaiAsPromised);

'use strict';
var chai = require('chai')
, chaiAsPromised = require('chai-as-promised')
, Promise = require('promise/lib/es6-extensions')
, date = require('../lib/date');
, Promise = require('promise/src/es6-extensions')
, date = require('../src/date');

@@ -17,3 +17,3 @@ chai.use(chaiAsPromised);

it('should CAST correctly', function(){
var inst = date()

@@ -20,0 +20,0 @@

@@ -5,8 +5,8 @@ 'use strict';

, chaiAsPromised = require('chai-as-promised')
, ValidationError = require('../lib/util/validation-error')
, Promise = require('promise/lib/es6-extensions')
, mixed = require('../lib/mixed')
, object = require('../lib/object')
, string = require('../lib/string')
, reach = require('../lib/util/reach');
, ValidationError = require('../src/util/validation-error')
, Promise = require('promise/src/es6-extensions')
, mixed = require('../src/mixed')
, object = require('../src/object')
, string = require('../src/string')
, reach = require('../src/util/reach');

@@ -63,3 +63,3 @@ chai.use(chaiAsPromised);

}),
inst.oneOf([5]).isValid(5).should.eventually.equal(true)

@@ -106,14 +106,14 @@ ])

inst.tests.length.should.equal(2)
inst.tests.length.should.equal(2)
})
it('exclusive tests should throw without a name', function(){
;(function(){
;(function(){
mixed().test({ message: 'invalid', exclusive: true, test: function(){} })
}).should.throw()
}).should.throw()
})
it('exclusive tests should replace previous ones', function(){
var inst = mixed().test({ message: 'invalid', exclusive: true, name: 'max', test: function(v){
return v < 5
var inst = mixed().test({ message: 'invalid', exclusive: true, name: 'max', test: function(v){
return v < 5
}})

@@ -125,19 +125,20 @@

inst.test({ message: 'invalid', exclusive: true, name: 'max', test: function(v){
return v < 10
inst.test({ message: 'invalid', exclusive: true, name: 'max', test: function(v){
return v < 10
}})
.isValid(8).should.eventually.become(true)
])
])
})
it('tests should receive path and context', function(done){
it('tests should be called with the correct `this`', function(done){
var inst = object({
other: mixed(),
test: mixed().test({
message: 'invalid',
exclusive: true,
name: 'max',
test: function(v, path, context){
path.should.equal('test')
context.should.eql({ other: 5, test : 'hi' })
message: 'invalid',
exclusive: true,
name: 'max',
test: function(v, path, context){
this.path.should.equal('test')
this.parent.should.eql({ other: 5, test : 'hi' })
this.options.context.should.eql({ user: 'jason' })
done()

@@ -148,6 +149,39 @@ }

inst.validate({ other: 5, test : 'hi' })
inst.validate({ other: 5, test : 'hi' }, { context: { user: 'jason' } })
})
it('tests can return an error', function(){
var inst = mixed().test({
message: 'invalid ${path}',
name: 'max',
test: function(v){
return this.createError({ path: 'my.path' })
}
})
return inst.validate('')
.should.be.rejected
.then(function(e){
e.path.should.equal('my.path')
e.errors[0].should.equal('invalid my.path')
})
})
it('should use returned error path and message', function(){
var inst = mixed().test({
message: 'invalid ${path}',
name: 'max',
test: function(v){
return this.createError({ message: '${path} nope!', path: 'my.path' })
}
})
return inst.validate({ other: 5, test : 'hi' })
.should.be.rejected
.then(function(e){
e.path.should.equal('my.path')
e.errors[0].should.equal('my.path nope!')
})
})
it('should allow custom validation of either style', function(){

@@ -158,6 +192,6 @@ var inst = string()

})
.test('name', 'test b', function(val, path, context, done){
.test('name', 'test b', function(val, done){
process.nextTick(function(){
done(null, val !== 'jim')
})
})
}, true)

@@ -218,7 +252,7 @@

next.validate({ str: 'hi', str2: 'hi', obj: {} }).should.be.rejected.then(function(err){
err.message.should.contain('this.obj.str is a required field')
err.message.should.contain('obj.str is a required field')
}),
next.validate({ str2: 'hi', obj: { str: 'hi'} }).should.be.rejected.then(function(err){
err.message.should.contain('this.str is a required field')
err.message.should.contain('str is a required field')
})

@@ -254,8 +288,10 @@ ])

it('should handle conditionals', function(){
var inst = mixed().when('prop', { is: 5, then: mixed().required() })
var inst = mixed()
.when('prop', { is: 5, then: mixed().required('from parent') })
return Promise.all([
//parent
inst._validate(undefined, {}, { parent: { prop: 5 }}).should.be.rejected,
inst._validate(undefined, {}, { parent: { prop: 1 }}).should.be.fulfilled,
inst._validate('hello', {}, { parent: { prop: 5 }}).should.be.fulfilled
inst._validate('hello', {}, { parent: { prop: 5 }}).should.be.fulfilled,
])

@@ -278,2 +314,27 @@ .then(function(){

it('should require context when needed', function(){
var inst = mixed()
.when('$prop', { is: 5, then: mixed().required('from context') })
return Promise.all([
inst._validate(undefined, { context: { prop: 5 }}, {}).should.be.rejected,
inst._validate(undefined, { context: { prop: 1 }}, {}).should.be.fulfilled,
inst._validate('hello', { context: { prop: 5 }}, {}).should.be.fulfilled
])
.then(function(){
inst = string().when('prop', {
is: function(val) { return val === 5 },
then: string().required(),
otherwise: string().min(4)
})
return Promise.all([
inst._validate(undefined, { context: { prop: 5 }}, {}).should.be.rejected,
inst._validate('hello', { context: { prop: 1 }}, {}).should.be.fulfilled,
inst._validate('hel', { context: { prop: 1 }}, {}).should.be.rejected
])
})
})
})

@@ -280,0 +341,0 @@

@@ -5,4 +5,4 @@ 'use strict';

, chaiAsPromised = require('chai-as-promised')
, Promise = require('promise/lib/es6-extensions')
, number = require('../lib/number');
, Promise = require('promise/src/es6-extensions')
, number = require('../src/number');

@@ -17,3 +17,3 @@ chai.use(chaiAsPromised);

var inst = number(), date = new Date()
chai.expect(

@@ -74,3 +74,3 @@ inst.cast(null)).to.eql(NaN)

})
])
])
})

@@ -77,0 +77,0 @@

@@ -5,10 +5,10 @@ 'use strict';

, chaiAsPromised = require('chai-as-promised')
, Promise = require('promise/lib/es6-extensions')
, mixed = require('../lib/mixed')
, string = require('../lib/string')
, date = require('../lib/date')
, number = require('../lib/number')
, bool = require('../lib/boolean')
, array = require('../lib/array')
, object = require('../lib/object');
, Promise = require('promise/src/es6-extensions')
, mixed = require('../src/mixed')
, string = require('../src/string')
, date = require('../src/date')
, number = require('../src/number')
, bool = require('../src/boolean')
, array = require('../src/array')
, object = require('../src/object');

@@ -95,3 +95,3 @@ chai.use(chaiAsPromised);

err.errors.length.should.equal(1)
err.errors[0].should.contain('this.nested.str')
err.errors[0].should.contain('nested.str')
})

@@ -106,3 +106,3 @@ .then(function(){

inst.validate(obj).should.be.rejected.then(function(err){
err.errors[0].should.contain('this.arr[1]')
err.errors[0].should.contain('arr[1]')
})

@@ -169,4 +169,4 @@ ])

return inst.validate({ extra: 'field' }).should.be.rejected
return inst.validate({ extra: 'field' })
.should.be.rejected
.then(function(err){

@@ -213,3 +213,3 @@ err.errors[0].should.equal('hi')

var inst = object({
nest: object({
nest: object({
str: string().required()

@@ -236,3 +236,3 @@ })

err.errors.length.should.equal(2)
err.errors.should.eql(['oops', 'this.nest.str is a required field'])
err.errors.should.eql(['oops', 'nest.str is a required field'])
})

@@ -245,3 +245,3 @@ ])

var inst = object({
nest: object({
nest: object({
str: string().required()

@@ -343,3 +343,3 @@ })

other: bool(),
stats: object({
stats: object({
isBig: bool(),

@@ -346,0 +346,0 @@ count: countSchema

'use strict';
/* global describe, it */
var chai = require('chai')
, Promise = require('promise/lib/es6-extensions')
, Promise = require('promise/src/es6-extensions')
, sinonChai = require('sinon-chai')
, chaiAsPromised = require('chai-as-promised')
, string = require('../lib/string');
, string = require('../src/string');

@@ -76,3 +76,3 @@ chai.use(chaiAsPromised);

})
])
])
})

@@ -79,0 +79,0 @@

'use strict';
/*global describe, it */
var Promise = require('promise/lib/es6-extensions')
var Promise = require('promise/src/es6-extensions')
, chai = require('chai')
, chaiAsPromised = require('chai-as-promised')
, reach = require('../lib/util/reach')
, number = require('../lib/number')
, array = require('../lib/array')
, object = require('../lib/object')
, _ = require('../lib/util/_');
, reach = require('../src/util/reach')
, number = require('../src/number')
, array = require('../src/array')
, object = require('../src/object')
, _ = require('../src/util/_');

@@ -49,7 +49,7 @@ chai.use(chaiAsPromised);

_.merge(a, b).should.deep.eql({
a: 4,
b: 'hello',
c: [1, 2, 3, 4, 5, 3],
d: {
_.merge(a, b).should.deep.eql({
a: 4,
b: 'hello',
c: [1, 2, 3, 4, 5, 3],
d: {
a: /hi/,

@@ -70,6 +70,6 @@ b: 'hello'

nested: object()
.shape({
.shape({
arr: array().of(
object().shape({ num: num })
)
)
})

@@ -93,5 +93,5 @@ })

// var num = number()
// var altShape = {
// var altShape = {
// next: object().shape({
// greet: bool(),
// greet: bool(),
// prop: number().when('greet', { is: true, then: number().max(5) })

@@ -105,3 +105,3 @@ // })

// .when('num', { is: number().min(3), then: object(altShape) })
// .shape({
// .shape({
// next: object().shape({ prop: bool() })

@@ -121,3 +121,3 @@ // })

// })
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc