cspell
Version:
A Spelling Checker for Code!
141 lines • 5.2 kB
JavaScript
import chalk from 'chalk';
import * as iPath from 'path';
import strip from 'strip-ansi';
import { pad, width } from '../util/util.js';
const colWidthDictionaryName = 20;
export function emitTraceResults(results, options) {
const maxWordLength = results
.map((r) => r.foundWord || r.word)
.reduce((a, b) => Math.max(a, width(b)), 'Word'.length);
const maxDictNameLength = results
.map((r) => r.dictName.length)
.reduce((a, b) => Math.max(a, b), colWidthDictionaryName);
const cols = {
word: maxWordLength,
dictName: maxDictNameLength,
terminalWidth: options.lineWidth ?? (process.stdout.columns || 120),
location: options.dictionaryPathFormat === 'hide' ? 0 : 30,
};
const col = new Intl.Collator();
results.sort((a, b) => col.compare(a.dictName, b.dictName));
emitHeader(cols);
results.forEach((r) => emitTraceResult(r, cols, options));
}
function emitHeader(colWidths) {
const line = [
pad('Word', colWidths.word),
'F',
pad('Dictionary', colWidths.dictName),
colWidths.location ? pad('Dictionary Location', colWidths.location) : '',
];
console.log(chalk.underline(line.join(' ').trim().slice(0, colWidths.terminalWidth)));
}
function emitTraceResult(r, colWidths, options) {
const { word: wordColWidth, terminalWidth, dictName: widthName } = colWidths;
const errors = r.errors?.map((e) => e.message)?.join('\n\t') || '';
const word = pad(r.foundWord || r.word, wordColWidth);
const cWord = word.replace(/[+]/g, chalk.yellow('+'));
const w = r.forbidden ? chalk.red(cWord) : chalk.green(cWord);
const f = calcFoundChar(r);
const a = r.dictActive ? '*' : ' ';
const dictName = pad(r.dictName.slice(0, widthName - 1) + a, widthName);
const dictColor = r.dictActive ? chalk.yellowBright : chalk.rgb(200, 128, 50);
const n = dictColor(dictName);
const info = [w, f, n].join(' ') + ' ';
const used = width(strip(info));
const widthSrc = terminalWidth - used;
const c = colorize(errors ? chalk.red : chalk.white);
const s = c(formatDictionaryLocation(r.dictSource, widthSrc, { iPath, ...options }));
const line = info + s;
console.log(line.trim());
if (errors) {
console.error('\t' + chalk.red(errors));
}
}
function trimMid(s, w) {
s = s.trim();
if (s.length <= w) {
return s;
}
const l = Math.floor((w - 3) / 2);
const r = Math.ceil((w - 3) / 2);
return s.slice(0, l) + '...' + s.slice(-r);
}
function calcFoundChar(r) {
const errors = r.errors?.map((e) => e.message)?.join('\n\t') || '';
let color = chalk.dim;
color = r.found ? chalk.whiteBright : color;
color = r.forbidden ? chalk.red : color;
color = r.noSuggest ? chalk.yellowBright : color;
color = errors ? chalk.red : color;
let char = '-';
char = r.found ? '*' : char;
char = r.forbidden ? '!' : char;
char = r.noSuggest ? 'I' : char;
char = errors ? 'X' : char;
return color(char);
}
function formatDictionaryLocation(dictSource, maxWidth, { cwd, dictionaryPathFormat: format, iPath, }) {
let relPath = cwd ? iPath.relative(cwd, dictSource) : dictSource;
const idxNodeModule = relPath.lastIndexOf('node_modules');
const isNodeModule = idxNodeModule >= 0;
if (format === 'hide')
return '';
if (format === 'short') {
const prefix = isNodeModule
? '[node_modules]/'
: relPath.startsWith('..' + iPath.sep + '..')
? '.../'
: relPath.startsWith('..' + iPath.sep)
? '../'
: '';
return prefix + iPath.basename(dictSource);
}
if (format === 'full')
return dictSource;
relPath = isNodeModule ? relPath.slice(idxNodeModule) : relPath;
const usePath = relPath.length < dictSource.length ? relPath : dictSource;
return trimMidPath(usePath, maxWidth, iPath.sep);
}
function colorize(fn) {
return (s) => (s ? fn(s) : '');
}
function trimMidPath(s, w, sep) {
if (s.length <= w)
return s;
const parts = s.split(sep);
if (parts[parts.length - 1].length > w)
return trimMid(s, w);
function join(left, right) {
// if (left === right) return parts.join(sep);
return [...parts.slice(0, left), '...', ...parts.slice(right)].join(sep);
}
let left = 0, right = parts.length, last = '';
for (let i = 0; i < parts.length; ++i) {
const incLeft = i & 1 ? 1 : 0;
const incRight = incLeft ? 0 : -1;
const next = join(left + incLeft, right + incRight);
if (next.length > w)
break;
left += incLeft;
right += incRight;
last = next;
}
for (let i = left + 1; i < right; ++i) {
const next = join(i, right);
if (next.length > w)
break;
last = next;
}
for (let i = right - 1; i > left; --i) {
const next = join(left, i);
if (next.length > w)
break;
last = next;
}
return last || trimMid(s, w);
}
export const __testing__ = {
trimMidPath,
};
//# sourceMappingURL=traceEmitter.js.map