Improve error display heuristics for complex cases where errors occur in a subpath

master
Sven Slootweg 4 years ago
parent 1d5d7be21d
commit 6a1d0b3369

@ -22,6 +22,31 @@ function unpackNestedEithers(errors) {
})); }));
} }
function hasNestedPaths(error) {
if (error.path.length > 0) {
return true;
} else if (error.subErrors != null) {
return error.subErrors.some((subError) => {
return hasNestedPaths(subError);
});
} else {
return false;
}
}
function errorAtLeastOneOf(errors) {
return new ValidationError(`Must satisfy at least one of:`, {
subErrors: unpackNestedEithers(errors),
__isValidatemEitherError: true
});
}
function errorAllOf(errors) {
return new ValidationError("Must satisfy all of the following:", {
subErrors: errors
});
}
module.exports = function (alternatives) { module.exports = function (alternatives) {
if (!Array.isArray(alternatives)) { if (!Array.isArray(alternatives)) {
throw new Error(`Must specify an array of alternatives`); throw new Error(`Must specify an array of alternatives`);
@ -42,9 +67,7 @@ module.exports = function (alternatives) {
} else if (errors.length === 1) { } else if (errors.length === 1) {
allErrors.push(errors[0]); allErrors.push(errors[0]);
} else { } else {
allErrors.push(new ValidationError("Must satisfy all of the following:", { allErrors.push(errorAllOf(errors));
subErrors: errors
}));
} }
} }
@ -61,19 +84,22 @@ module.exports = function (alternatives) {
*/ */
let nestedErrors = allErrors.filter((error) => { let nestedErrors = allErrors.filter((error) => {
return (error.path.length !== 0); return hasNestedPaths(error);
}); });
if (nestedErrors.length > 0) {
let sameOrigin = areErrorsFromSameOrigin(nestedErrors); let sameOrigin = areErrorsFromSameOrigin(nestedErrors);
if (nestedErrors.length > 0 && sameOrigin) { if (sameOrigin || nestedErrors.length === 1) {
// 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). // 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 }); return validationResult({ errors: nestedErrors });
} else { } else {
throw new ValidationError(`Must satisfy at least one of:`, { // Somewhere, possibly nested inside of a "must satisfy all", we've seen errors at varying subpaths. This means that the user probably tried to match some sort of arm, but we don't know which, because the origins are not identical. Therefore we will just remove all the top-level errors, and only show the ones that are at *some* sort of sub-path.
subErrors: unpackNestedEithers(allErrors), throw errorAtLeastOneOf(nestedErrors);
__isValidatemEitherError: true }
}); } else {
// We have no idea what the intention was, as there are no nested errors. Just show all of the errors.
throw errorAtLeastOneOf(allErrors);
} }
}); });
} }

Loading…
Cancel
Save