105 lines
3.6 KiB
JavaScript
Executable File
105 lines
3.6 KiB
JavaScript
Executable File
import chalk from 'chalk';
|
|
import { padNoAnsi, enumerate } from './utils';
|
|
import stripAnsi from 'strip-ansi';
|
|
/**
|
|
* Get the input as highlighted keywords to show to the user
|
|
* with the error that was generated from parsing the input.
|
|
*
|
|
* @param nodes AST nodes
|
|
* @param error A parsing error
|
|
*/
|
|
function highlight(nodes, error) {
|
|
const strings = [];
|
|
let errorIndex = undefined;
|
|
function foundError() {
|
|
if (errorIndex !== undefined)
|
|
return;
|
|
errorIndex = stripAnsi(strings.join(' ')).length;
|
|
}
|
|
if (error.nodes.length === 0)
|
|
return;
|
|
nodes.forEach(node => {
|
|
if (error.nodes.includes(node)) {
|
|
foundError();
|
|
return strings.push(chalk.red(node.raw));
|
|
}
|
|
else {
|
|
if (node.type === 'shortOptions') {
|
|
let failed = false;
|
|
let s = '';
|
|
for (const option of node.options) {
|
|
if (error.nodes.includes(option)) {
|
|
s += chalk.red(option.raw);
|
|
failed = true;
|
|
}
|
|
else {
|
|
s += chalk.dim(option.raw);
|
|
}
|
|
}
|
|
const prefix = failed ? chalk.red(`-`) : chalk.dim('-');
|
|
if (failed) {
|
|
foundError();
|
|
}
|
|
return strings.push(prefix + s);
|
|
}
|
|
return strings.push(chalk.dim(node.raw));
|
|
}
|
|
});
|
|
return { colorized: strings.join(' '), errorIndex: errorIndex !== null && errorIndex !== void 0 ? errorIndex : 0 };
|
|
}
|
|
/**
|
|
* An error UI
|
|
*
|
|
* @param breadcrumbs The command breadcrumbs to print with the error
|
|
*/
|
|
export function errorBox(nodes, errors, breadcrumbs) {
|
|
let withHighlight = [];
|
|
let errorMessages = [];
|
|
for (const error of errors) {
|
|
const highlighted = highlight(nodes, error);
|
|
withHighlight.push({ message: error.message, highlighted });
|
|
}
|
|
let number = 1;
|
|
const maxNumberWidth = String(withHighlight.length).length;
|
|
errorMessages.push(chalk.red.bold('error: ') +
|
|
'found ' +
|
|
chalk.yellow(withHighlight.length) +
|
|
' error' +
|
|
(withHighlight.length > 1 ? 's' : ''));
|
|
errorMessages.push('');
|
|
withHighlight
|
|
.filter(x => x.highlighted)
|
|
.forEach(x => {
|
|
if (!x.highlighted) {
|
|
throw new Error('WELP');
|
|
}
|
|
const pad = ''.padStart(x.highlighted.errorIndex);
|
|
errorMessages.push(` ${x.highlighted.colorized}`);
|
|
for (const [index, line] of enumerate(x.message.split('\n'))) {
|
|
const prefix = index === 0 ? chalk.bold('^') : ' ';
|
|
const msg = chalk.red(` ${pad} ${prefix} ${line}`);
|
|
errorMessages.push(msg);
|
|
}
|
|
errorMessages.push('');
|
|
number++;
|
|
});
|
|
const withNoHighlight = withHighlight.filter(x => !x.highlighted);
|
|
if (number > 1) {
|
|
if (withNoHighlight.length === 1) {
|
|
errorMessages.push('Along the following error:');
|
|
}
|
|
else if (withNoHighlight.length > 1) {
|
|
errorMessages.push('Along the following errors:');
|
|
}
|
|
}
|
|
withNoHighlight.forEach(({ message }) => {
|
|
const num = chalk.red.bold(`${padNoAnsi(number.toString(), maxNumberWidth, 'start')}.`);
|
|
errorMessages.push(` ${num} ${chalk.red(message)}`);
|
|
number++;
|
|
});
|
|
const helpCmd = chalk.yellow(breadcrumbs.join(' ') + ' --help');
|
|
errorMessages.push('');
|
|
errorMessages.push(chalk.red.bold('hint: ') + `for more information, try '${helpCmd}'`);
|
|
return errorMessages.join('\n');
|
|
}
|
|
//# sourceMappingURL=errorBox.js.map
|