You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.4 KiB
JavaScript

4 years ago
"use strict";
const defaultValue = require("default-value");
const asExpression = require("as-expression");
const splitFilterN = require("split-filter-n");
const combinator = require("@validatem/combinator");
const ValidationError = require("@validatem/error");
const matchValidationError = require("@validatem/match-validation-error");
const validationResult = require("@validatem/validation-result");
// TODO: Document that this passes on context
function concat(arrays) {
return arrays.slice(1).reduce((combined, array) => {
return combined.concat(array);
}, arrays[0]);
}
module.exports = function wrapError(message, code, rules, options = {}) {
if (typeof code !== "string") {
throw new Error(`'code' argument must be a string`);
} else if (typeof message !== "string") {
throw new Error(`'message' argument must be a string`);
} else if (rules == null) {
throw new Error(`'rules' argument is required`);
} else {
let preserveOriginalErrors = defaultValue(options.preserveOriginalErrors, false);
4 years ago
return combinator((value, applyValidators, context) => {
let result = applyValidators(value, rules, context);
4 years ago
if (result.errors.length > 0) {
let { errors, newValue } = result;
4 years ago
let errorsByType = splitFilterN(errors, [ "validationRoot", "validationPath", "other" ], (error) => {
if (matchValidationError(error)) {
if (error.path.length === 0) {
return "validationRoot";
} else {
return "validationPath";
}
4 years ago
} else {
return "other";
4 years ago
}
});
4 years ago
let hasRootValidationErrors = errorsByType.validationRoot.length > 0;
let hasPathValidationErrors = errorsByType.validationPath.length > 0;
let hasValidationErrors = hasRootValidationErrors || hasPathValidationErrors;
4 years ago
let transformedValidationErrors = asExpression(() => {
if (hasValidationErrors) {
if (!preserveOriginalErrors) {
return [ new ValidationError(message, { code: code }) ];
} else {
// If possible, we try to move any subpath errors into the subErrors of an (optionally newly-created) root error. Otherwise, it can become difficult for the user to correlate together the root and subpath errors that are related, when we start changing the messages of the root errors.
if (errorsByType.validationRoot.length === 0) {
return [ new ValidationError(message, { code: code, subErrors: errorsByType.validationPath }) ];
} else if (errorsByType.validationRoot.length === 1) {
let error = errorsByType.validationRoot[0];
// TODO: Currently we cannot set `originalError` due to a bug in `create-error`; switch to a better error implementation
return [ new ValidationError(`${message} (${error.message})`, { code: code, subErrors: errorsByType.validationPath }) ];
} else {
// If there are multiple root errors, we cannot determine which root error the subpath errors belong to, so we'll just provide them as a flat list
return concat([
errorsByType.validationRoot.map((error) => {
return new ValidationError(`${message} (${error.message})`, { code: code })
}),
errorsByType.validationPath
]);
}
}
} else {
return [];
4 years ago
}
});
return validationResult({
newValue: newValue,
errors: concat([
transformedValidationErrors,
errorsByType.other
])
});
} else {
return result;
}
});
}
4 years ago
};