"use strict"; const indentString = require("indent-string"); const supportsColor = require("supports-color"); const matchVirtualProperty = require("@validatem/match-virtual-property"); const asExpression = require("as-expression"); const AggregrateValidationError = require("./aggregrate-validation-error"); // TODO: Omit the "At (root)" for path-less errors, to avoid confusion when singular values are being compared? // TODO: Move out the path generating logic into a separate module, to better support custom error formatting code function joinPathSegments(segments) { return (segments.length > 0) ? segments.join(" -> ") : "(root)"; } // NOTE: We do some manual ANSI escape code stuff here for now, because using `chalk` would significantly inflate the bundle size of the core. // TODO: Find a better solution for this. let openHighlight, openDim, closeColor; if (supportsColor.stderr) { openHighlight = `\u001b[36m`; // cyan openDim = `\u001b[90m`; // gray closeColor = `\u001b[39m`; } else { openHighlight = ""; openDim = ""; closeColor = ""; } function renderErrorList(errors, subErrorLevels = 0) { let rephrasedErrors = errors.map((error, i) => { let pathSegments = error.path.map((segment) => { if (segment == null) { throw new Error(`Unexpected empty path segment encountered; this is a bug, please report it!`); } else if (typeof segment === "string" || typeof segment === "number") { return openHighlight + String(segment) + closeColor; } else if (matchVirtualProperty(segment)) { return openDim + `(${segment.name})` + closeColor; } else { throw new Error(`Unexpected path segment encountered: ${segment}; this is a bug, please report it!`); } }); let lineCharacter = (i < errors.length - 1) ? "├─" : "└─"; let mainLine = asExpression(() => { if (subErrorLevels > 0) { let message = (pathSegments.length > 0) ? `${lineCharacter} ${joinPathSegments(pathSegments)}: ${error.message}` : `${lineCharacter} ${error.message}`; return indentString(message, subErrorLevels * 4); } else { return (pathSegments.length > 0) ? ` - At ${joinPathSegments(pathSegments)}: ${error.message}` : ` - ${error.message}`; } }); if (error.subErrors != null && error.subErrors.length > 0) { let renderedSubErrors = renderErrorList(error.subErrors, subErrorLevels + 1); return mainLine + "\n" + renderedSubErrors; } else { return mainLine; } }); return rephrasedErrors.map((error) => { return `${error}`; }).join("\n"); } module.exports = function aggregrateAndThrowErrors(errors) { let detailLines = renderErrorList(errors); if (errors.length > 0) { return new AggregrateValidationError(`One or more validation errors occurred:\n${detailLines}`, { errors: errors }); } };