-
-
Notifications
You must be signed in to change notification settings - Fork 52
/
Copy pathformatErrors.js
69 lines (63 loc) · 2.39 KB
/
formatErrors.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import path from 'path';
import chalk from 'chalk';
import levenshtein from './levenshtein.js';
/** @typedef {import('../types/main').Error} Error */
/**
* @param {Error[]} errors
* @param {{ relativeFrom?: string; files: string[] }} opts
*/
// @ts-expect-error we need empty obj to destructure from
export function formatErrors(errors, { relativeFrom = process.cwd(), files } = {}) {
let output = [];
let number = 0;
for (const error of errors) {
number += 1;
const filePath = path.relative(relativeFrom, error.filePath);
if (error.onlyAnchorMissing === true) {
output.push(
`${number}. missing ${chalk.red.bold(
`id="${error.usage[0].anchor}"`,
)} in ${chalk.cyanBright(filePath)}`,
);
} else {
const firstAttribute = error.usage[0].attribute;
const title =
firstAttribute === 'src' || firstAttribute === 'srcset' ? 'file' : 'reference target';
output.push(`${number}. missing ${title} ${chalk.red.bold(filePath)}`);
}
const usageLength = error.usage.length;
for (let i = 0; i < 3 && i < usageLength; i += 1) {
const usage = error.usage[i];
const usagePath = path.relative(relativeFrom, usage.file);
const clickAbleLink = chalk.cyanBright(`${usagePath}:${usage.line + 1}:${usage.character}`);
const attributeStart = chalk.gray(`${usage.attribute}="`);
const attributeEnd = chalk.gray('"');
output.push(` from ${clickAbleLink} via ${attributeStart}${usage.value}${attributeEnd}`);
}
if (usageLength > 3) {
const more = chalk.red((usageLength - 3).toString());
output.push(` ... ${more} more references to this target`);
}
output.push('');
/**
* Also consider finding the updated path. This can be useful when documentation is restructured
* For instance, the folder name was changed, but the file name was not.
*/
let suggestion;
let lowestScore = -1;
files.forEach(file => {
const filePathToCompare = file.replace(relativeFrom + '/', '');
const score = levenshtein(filePathToCompare, filePath);
if (score && (lowestScore === -1 || score < lowestScore)) {
lowestScore = score;
suggestion = filePathToCompare;
}
});
if (suggestion) {
output.push(
chalk.italic(`Suggestion: did you mean ${chalk.magenta(suggestion)} instead?\n\n`),
);
}
}
return output.join('\n');
}