forked from validatem/either
Unpack nested either errors, and correctly represent alternatives that produced more than one error
This commit is contained in:
parent
e49e90f91b
commit
5b329cadd5
24
index.js
24
index.js
|
@ -3,6 +3,7 @@
|
|||
// TODO: Rename this to something more appropriate, like any/anyOf? How to make sure that doesn't cause confusion with `oneOf`?
|
||||
|
||||
const splitFilter = require("split-filter");
|
||||
const flatten = require("flatten");
|
||||
|
||||
const ValidationError = require("@validatem/error");
|
||||
const combinator = require("@validatem/combinator");
|
||||
|
@ -10,6 +11,18 @@ const validationResult = require("@validatem/validation-result");
|
|||
|
||||
const areErrorsFromSameOrigin = require("./src/are-errors-from-same-origin");
|
||||
|
||||
function unpackNestedEithers(errors) {
|
||||
// NOTE: We only unpack `either` errors that occurred *at the same level* as this error, ie. where there's directly a case of `either(either(...), ...)`, without any kind of data nesting (like `arrayOf` or `hasShape`) inbetween. Nested-data failures should still be shown separately, as their resolution strategy is actually different; unlike same-level nested `either` errors, where the nesting is purely an implementation detail that allows composing sets of alternatives together.
|
||||
|
||||
return flatten(errors.map((error) => {
|
||||
if (error.path.length === 0 && error.__isValidatemEitherError) {
|
||||
return error.subErrors;
|
||||
} else {
|
||||
return error;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
module.exports = function (alternatives) {
|
||||
if (!Array.isArray(alternatives)) {
|
||||
throw new Error(`Must specify an array of alternatives`);
|
||||
|
@ -27,8 +40,12 @@ module.exports = function (alternatives) {
|
|||
|
||||
if (errors.length === 0) {
|
||||
return newValue;
|
||||
} else if (errors.length === 1) {
|
||||
allErrors.push(errors[0]);
|
||||
} else {
|
||||
allErrors.push(...errors);
|
||||
allErrors.push(new ValidationError("Must satisfy all of the following:", {
|
||||
subErrors: errors
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +71,10 @@ module.exports = function (alternatives) {
|
|||
// One of the alternatives *did* match, but it failed somewhere further down the tree, and we don't have any errors originating from *other* nested rules. Chances are that the user intended to match the failing branch, so we pretend that the other alternatives don't exist, and pass through the original error(s).
|
||||
return validationResult({ errors: nestedErrors });
|
||||
} else {
|
||||
throw new ValidationError(`Must satisfy at least one of:`, { subErrors: allErrors });
|
||||
throw new ValidationError(`Must satisfy at least one of:`, {
|
||||
subErrors: unpackNestedEithers(allErrors),
|
||||
__isValidatemEitherError: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"@validatem/combinator": "^0.1.1",
|
||||
"@validatem/error": "^1.0.0",
|
||||
"@validatem/validation-result": "^0.1.2",
|
||||
"flatten": "^1.0.3",
|
||||
"split-filter": "^1.1.3"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue