UNPKG

@informalsystems/quint

Version:

Core tool for the Quint specification language

101 lines 4.81 kB
"use strict"; /* ---------------------------------------------------------------------------------- * Copyright 2022 Informal Systems * Licensed under the Apache License, Version 2.0. * See LICENSE in the project root for license information. * --------------------------------------------------------------------------------- */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createFinders = exports.formatError = void 0; /** * Human-friendly error reporting for Quint errors. From the read text and an error * message containing localization errors, fetch offending lines and highlights * offending sections with ^^^ strings. * * @author Gabriela Moreira * * @module */ const maybe_1 = require("@sweet-monads/maybe"); const json_bigint_1 = __importDefault(require("json-bigint")); const line_column_1 = __importDefault(require("line-column")); /** Generate a string with formatted error reporting for a given error message * * @param code a map from all possible loc sources to their file contents * @param finders a map of from all possible loc sources to a line-column lib * finder object created from the text for that source, used as cached maps of indexes * @param message the error message to be reported * @param lineOffset a maybe number to add to line numbers in error messages, * the default value is `just(1)`. * No source info is printed if `lineOffset == none()`. * * @returns a formatted string with error information * */ function formatError(code, finders, message, lineOffset = (0, maybe_1.just)(1)) { if (message.locs.length === 0) { return `error: ${message.explanation}`; } try { // try to extract the location of the error return message.locs.reduce((output, loc) => { const text = code.get(loc.source); const finder = finders.get(loc.source); // If lineOffset is a number, print the source location. // If lineOfsset is undefined, omit the source location (e.g., in REPL). const locString = lineOffset.isJust() ? `${loc.source}:${loc.start.line + lineOffset.value}:${loc.start.col + 1} - ` : ''; output += `${locString}error: ${message.explanation}\n`; const endLine = loc.end ? loc.end.line : loc.start.line; const endCol = loc.end ? loc.end.col : loc.start.col; for (let i = loc.start.line; i <= endLine; i++) { // finder's indexes start at 1 const lineStartIndex = finder.toIndex(i + 1, 1); const line = text.slice(lineStartIndex).split('\n')[0]; const lineStartCol = i === loc.start.line ? loc.start.col : 0; const lineEndCol = i === endLine ? endCol : line.length - 1; const lineIndex = lineOffset.map(offs => offs + i); output += formatLine(lineIndex, lineStartCol, lineEndCol, line); } return output; }, ''); } catch (error) { // If it happens that an error occurs during the error reconstruction, // print that we could not construct a good explanation, instead of throwing. console.error('\nSomething unexpected happened during error reconstruction. Please report a bug.\n'); console.error('Include this in the bug report: {'); console.trace(error.message); console.log('Trying to format', json_bigint_1.default.stringify(message.locs)); console.error('} // end of the bug report\n'); // return the bare bones error message return `error: ${message.explanation}`; } } exports.formatError = formatError; /** * Create line column finders (from the line-column lib) for each file in a map. * * @param sourceCode - a map of file names to their contents * * @returns a map of file names to their finders */ function createFinders(sourceCode) { return new Map([...sourceCode.entries()].map(([path, code]) => [path, (0, line_column_1.default)(code)])); } exports.createFinders = createFinders; function formatLine(lineIndex, startCol, endCol, line) { let output = ''; const lineNumberIndicator = lineIndex.isJust() ? `${lineIndex.value}: ` : ''; output += `${lineNumberIndicator}${line}\n`; // Add margin according to how much space the indicator takes output += ' '.repeat(lineNumberIndicator.length); // Write ^ characters for columns that should be highlited in this line output += ' '.repeat(startCol); output += '^'.repeat(1 + endCol - startCol); output += '\n'; return output; } //# sourceMappingURL=errorReporter.js.map