/
prettyDiagnostic.js
115 lines (101 loc) 路 2.97 KB
/
prettyDiagnostic.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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// @flow strict-local
import type {Diagnostic} from '@parcel/diagnostic';
import type {PluginOptions} from '@parcel/types';
import formatCodeFrame from '@parcel/codeframe';
import mdAnsi from '@parcel/markdown-ansi';
import chalk from 'chalk';
import path from 'path';
import nullthrows from 'nullthrows';
// $FlowFixMe
import terminalLink from 'terminal-link';
export type FormattedCodeFrame = {|
location: string,
code: string,
|};
export type AnsiDiagnosticResult = {|
message: string,
stack: string,
/** A formatted string containing all code frames, including their file locations. */
codeframe: string,
/** A list of code frames with highlighted code and file locations separately. */
frames: Array<FormattedCodeFrame>,
hints: Array<string>,
documentation: string,
|};
export default async function prettyDiagnostic(
diagnostic: Diagnostic,
options?: PluginOptions,
terminalWidth?: number,
): Promise<AnsiDiagnosticResult> {
let {
origin,
message,
stack,
codeFrames,
hints,
skipFormatting,
documentationURL,
} = diagnostic;
let result = {
message:
mdAnsi(`**${origin ?? 'unknown'}**: `) +
(skipFormatting ? message : mdAnsi(message)),
stack: '',
codeframe: '',
frames: [],
hints: [],
documentation: '',
};
if (codeFrames != null) {
for (let codeFrame of codeFrames) {
let filePath = codeFrame.filePath;
if (filePath != null && options && !path.isAbsolute(filePath)) {
filePath = path.join(options.projectRoot, filePath);
}
let highlights = codeFrame.codeHighlights;
let code =
codeFrame.code ??
(options &&
(await options.inputFS.readFile(nullthrows(filePath), 'utf8')));
let formattedCodeFrame = '';
if (code != null) {
formattedCodeFrame = formatCodeFrame(code, highlights, {
useColor: true,
syntaxHighlighting: true,
language:
// $FlowFixMe sketchy null checks do not matter here...
codeFrame.language ||
(filePath != null ? path.extname(filePath).substr(1) : undefined),
terminalWidth,
});
}
let location =
typeof filePath !== 'string'
? ''
: `${filePath}:${highlights[0].start.line}:${highlights[0].start.column}`;
result.codeframe += location ? chalk.gray.underline(location) + '\n' : '';
result.codeframe += formattedCodeFrame;
if (codeFrame !== codeFrames[codeFrames.length - 1]) {
result.codeframe += '\n\n';
}
result.frames.push({
location,
code: formattedCodeFrame,
});
}
}
if (stack != null) {
result.stack = stack;
}
if (Array.isArray(hints) && hints.length) {
result.hints = hints.map(h => {
return mdAnsi(h);
});
}
if (documentationURL != null) {
result.documentation = terminalLink('Learn more', documentationURL, {
fallback: (text, url) => `${text}: ${url}`,
});
}
return result;
}