diff --git a/lib/array.js b/lib/array.js index 6aa551bdb..aa5e6bad4 100644 --- a/lib/array.js +++ b/lib/array.js @@ -93,7 +93,7 @@ inherits(ArraySchema, MixedSchema, { return value; } - var result = value.map(function (item, key) { + var validations = value.map(function (item, key) { var path = (options.path || '') + '[' + key + ']'; // object._validate note for isStrict explanation @@ -104,9 +104,9 @@ inherits(ArraySchema, MixedSchema, { return true; }); - result = endEarly ? Promise.all(result).catch(scopeError(value)) : collectErrors(result, value, options.path, errors); + validations = endEarly ? Promise.all(validations).catch(scopeError(value)) : collectErrors({ validations: validations, value: value, errors: errors, path: options.path }); - return result.then(function () { + return validations.then(function () { return value; }); }); diff --git a/lib/mixed.js b/lib/mixed.js index 55bf90b32..b1cd8ff1c 100644 --- a/lib/mixed.js +++ b/lib/mixed.js @@ -17,13 +17,15 @@ var notEmpty = function notEmpty(value) { }; function runValidations(validations, endEarly, value, path) { - return endEarly ? Promise.all(validations) : _.collectErrors(validations, value, path); + return endEarly ? Promise.all(validations) : _.collectErrors({ validations: validations, value: value, path: path }); } function extractTestParams(name, message, test, useCallback) { var opts = name; - if (typeof message === 'function') test = message, message = locale.default; + if (typeof message === 'function') test = message, message = locale.default, name = null; + + if (typeof name === 'function') test = name, message = locale.default, name = null; if (typeof name === 'string' || name === null) opts = { name: name, test: test, message: message, useCallback: useCallback, exclusive: false }; diff --git a/lib/object.js b/lib/object.js index a0b4fc495..c8029b090 100644 --- a/lib/object.js +++ b/lib/object.js @@ -9,6 +9,7 @@ var locale = require('./locale.js').object; var split = require('property-expr').split; var Ref = require('./util/reference'); var c = require('case'); +var sortByFields = require('./util/sortByFields'); var _require = require('./util/_'); @@ -141,7 +142,7 @@ inherits(ObjectSchema, MixedSchema, { return value; } - var result = _this4._nodes.map(function (key) { + var validations = _this4._nodes.map(function (key) { var path = (opts.path ? opts.path + '.' : '') + key, field = _this4.fields[key], innerOptions = _extends({}, opts, { key: key, path: path, parent: value }); @@ -158,9 +159,12 @@ inherits(ObjectSchema, MixedSchema, { return true; }); - result = endEarly ? Promise.all(result).catch(scopeError(value)) : collectErrors(result, value, opts.path, errors); + validations = endEarly ? Promise.all(validations).catch(scopeError(value)) : collectErrors({ validations: validations, value: value, errors: errors, + path: opts.path, + sort: sortByFields(_this4) + }); - return result.then(function () { + return validations.then(function () { return value; }); }); diff --git a/lib/util/_.js b/lib/util/_.js index 6d2607610..3f3d52846 100644 --- a/lib/util/_.js +++ b/lib/util/_.js @@ -33,16 +33,27 @@ function settled(promises) { return Promise.all(promises.map(settle)); } -function collectErrors(promises, value, path) { - var errors = arguments.length <= 3 || arguments[3] === undefined ? [] : arguments[3]; +function collectErrors(_ref) { + var validations = _ref.validations; + var value = _ref.value; + var path = _ref.path; + var _ref$errors = _ref.errors; + var errors = _ref$errors === undefined ? [] : _ref$errors; + var sort = _ref.sort; // unwrap aggregate errors errors = errors.inner && errors.inner.length ? errors.inner : [].concat(errors); - return settled(promises).then(function (results) { - errors = results.reduce(function (arr, r) { - return !r.fulfilled ? arr.concat(r.value) : arr; - }, errors); + return settled(validations).then(function (results) { + var nestedErrors = results.filter(function (r) { + return !r.fulfilled; + }).reduce(function (arr, r) { + return arr.concat(r.value); + }, []); + + if (sort) nestedErrors.sort(sort); + //show parent errors after the nested ones: name.first, name + errors = nestedErrors.concat(errors); if (errors.length) throw new ValidationError(errors, value, path); }); diff --git a/lib/util/sortByFields.js b/lib/util/sortByFields.js new file mode 100644 index 000000000..8b3b69861 --- /dev/null +++ b/lib/util/sortByFields.js @@ -0,0 +1,20 @@ +"use strict"; + +function findIndex(arr, err) { + var idx = Infinity; + arr.some(function (key, ii) { + if (err.path.indexOf(key) !== -1) { + idx = ii; + return true; + } + }); + + return idx; +} + +module.exports = function sortByFields(schema) { + var keys = Object.keys(schema.fields); + return function (a, b) { + return findIndex(keys, a) - findIndex(keys, b); + }; +}; \ No newline at end of file