1 | export function loadDiagnostic(context, postcssError, filePath) {
|
2 | if (!postcssError || !context) {
|
3 | return;
|
4 | }
|
5 | const level = postcssError.level === 'warning' ? 'warn' : postcssError.level || 'error';
|
6 | const diagnostic = {
|
7 | level,
|
8 | type: 'css',
|
9 | language: 'postcss',
|
10 | header: `postcss ${level}`,
|
11 | code: postcssError.status && postcssError.status.toString(),
|
12 | relFilePath: null,
|
13 | absFilePath: null,
|
14 | messageText: postcssError.reason || postcssError.message || JSON.stringify(postcssError),
|
15 | lines: [],
|
16 | };
|
17 | if (filePath) {
|
18 | diagnostic.absFilePath = filePath;
|
19 | diagnostic.relFilePath = formatFileName(context.config.rootDir, diagnostic.absFilePath);
|
20 | diagnostic.header = formatHeader('postcss', diagnostic.absFilePath, context.config.rootDir, postcssError.line);
|
21 | if (postcssError.line > -1) {
|
22 | try {
|
23 | const sourceText = context.fs.readFileSync(diagnostic.absFilePath);
|
24 | const srcLines = sourceText.split(/(\r?\n)/);
|
25 | const errorLine = {
|
26 | lineIndex: postcssError.line - 1,
|
27 | lineNumber: postcssError.line,
|
28 | text: srcLines[postcssError.line - 1],
|
29 | errorCharStart: postcssError.column,
|
30 | errorLength: 0,
|
31 | };
|
32 | for (let i = errorLine.errorCharStart; i >= 0; i--) {
|
33 | if (STOP_CHARS.indexOf(errorLine.text.charAt(i)) > -1) {
|
34 | break;
|
35 | }
|
36 | errorLine.errorCharStart = i;
|
37 | }
|
38 | for (let j = errorLine.errorCharStart; j <= errorLine.text.length; j++) {
|
39 | if (STOP_CHARS.indexOf(errorLine.text.charAt(j)) > -1) {
|
40 | break;
|
41 | }
|
42 | errorLine.errorLength++;
|
43 | }
|
44 | if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {
|
45 | errorLine.errorLength = 1;
|
46 | errorLine.errorCharStart--;
|
47 | }
|
48 | diagnostic.lines.push(errorLine);
|
49 | if (errorLine.lineIndex > 0) {
|
50 | const previousLine = {
|
51 | lineIndex: errorLine.lineIndex - 1,
|
52 | lineNumber: errorLine.lineNumber - 1,
|
53 | text: srcLines[errorLine.lineIndex - 1],
|
54 | errorCharStart: -1,
|
55 | errorLength: -1,
|
56 | };
|
57 | diagnostic.lines.unshift(previousLine);
|
58 | }
|
59 | if (errorLine.lineIndex + 1 < srcLines.length) {
|
60 | const nextLine = {
|
61 | lineIndex: errorLine.lineIndex + 1,
|
62 | lineNumber: errorLine.lineNumber + 1,
|
63 | text: srcLines[errorLine.lineIndex + 1],
|
64 | errorCharStart: -1,
|
65 | errorLength: -1,
|
66 | };
|
67 | diagnostic.lines.push(nextLine);
|
68 | }
|
69 | }
|
70 | catch (e) {
|
71 | console.error(`StylePostcssPlugin loadDiagnostic, ${e}`);
|
72 | }
|
73 | }
|
74 | }
|
75 | context.diagnostics.push(diagnostic);
|
76 | }
|
77 | function formatFileName(rootDir, fileName) {
|
78 | if (!rootDir || !fileName)
|
79 | return '';
|
80 | fileName = fileName.replace(rootDir, '');
|
81 | if (/\/|\\/.test(fileName.charAt(0))) {
|
82 | fileName = fileName.substr(1);
|
83 | }
|
84 | if (fileName.length > 80) {
|
85 | fileName = '...' + fileName.substr(fileName.length - 80);
|
86 | }
|
87 | return fileName;
|
88 | }
|
89 | function formatHeader(type, fileName, rootDir, startLineNumber = null, endLineNumber = null) {
|
90 | let header = `${type}: ${formatFileName(rootDir, fileName)}`;
|
91 | if (startLineNumber !== null && startLineNumber > 0) {
|
92 | if (endLineNumber !== null && endLineNumber > startLineNumber) {
|
93 | header += `, lines: ${startLineNumber} - ${endLineNumber}`;
|
94 | }
|
95 | else {
|
96 | header += `, line: ${startLineNumber}`;
|
97 | }
|
98 | }
|
99 | return header;
|
100 | }
|
101 | const STOP_CHARS = [
|
102 | '',
|
103 | '\n',
|
104 | '\r',
|
105 | '\t',
|
106 | ' ',
|
107 | ':',
|
108 | ';',
|
109 | ',',
|
110 | '{',
|
111 | '}',
|
112 | '.',
|
113 | '#',
|
114 | '@',
|
115 | '!',
|
116 | '[',
|
117 | ']',
|
118 | '(',
|
119 | ')',
|
120 | '&',
|
121 | '+',
|
122 | '~',
|
123 | '^',
|
124 | '*',
|
125 | '$',
|
126 | ];
|