1 | 'use strict';
|
2 |
|
3 | const _ = require('lodash');
|
4 | const chalk = require('chalk');
|
5 | const path = require('path');
|
6 | const stringWidth = require('string-width');
|
7 | const symbols = require('log-symbols');
|
8 | const utils = require('postcss-reporter/lib/util');
|
9 |
|
10 | let table;
|
11 |
|
12 | const MARGIN_WIDTHS = 9;
|
13 |
|
14 | const levelColors = {
|
15 | info: 'blue',
|
16 | warning: 'yellow',
|
17 | error: 'red',
|
18 | success: undefined,
|
19 | };
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | function deprecationsFormatter(results) {
|
26 | const allDeprecationWarnings = _.flatMap(results, 'deprecations');
|
27 | const uniqueDeprecationWarnings = _.uniqBy(allDeprecationWarnings, 'text');
|
28 |
|
29 | if (!uniqueDeprecationWarnings || !uniqueDeprecationWarnings.length) {
|
30 | return '';
|
31 | }
|
32 |
|
33 | return uniqueDeprecationWarnings.reduce((output, warning) => {
|
34 | output += chalk.yellow('Deprecation Warning: ');
|
35 | output += warning.text;
|
36 |
|
37 | if (warning.reference) {
|
38 | output += chalk.dim(' See: ');
|
39 | output += chalk.dim.underline(warning.reference);
|
40 | }
|
41 |
|
42 | return `${output}\n`;
|
43 | }, '\n');
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | function invalidOptionsFormatter(results) {
|
51 | const allInvalidOptionWarnings = _.flatMap(results, (r) =>
|
52 | r.invalidOptionWarnings.map((w) => w.text),
|
53 | );
|
54 | const uniqueInvalidOptionWarnings = [...new Set(allInvalidOptionWarnings)];
|
55 |
|
56 | return uniqueInvalidOptionWarnings.reduce((output, warning) => {
|
57 | output += chalk.red('Invalid Option: ');
|
58 | output += warning;
|
59 |
|
60 | return `${output}\n`;
|
61 | }, '\n');
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 | function logFrom(fromValue) {
|
69 | if (fromValue.startsWith('<')) return fromValue;
|
70 |
|
71 | return path
|
72 | .relative(process.cwd(), fromValue)
|
73 | .split(path.sep)
|
74 | .join('/');
|
75 | }
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | function getMessageWidth(columnWidths) {
|
82 | if (!process.stdout.isTTY) {
|
83 | return columnWidths[3];
|
84 | }
|
85 |
|
86 | const availableWidth = process.stdout.columns < 80 ? 80 : process.stdout.columns;
|
87 | const fullWidth = Object.values(columnWidths).reduce((a, b) => a + b);
|
88 |
|
89 |
|
90 | if (availableWidth > fullWidth + MARGIN_WIDTHS) {
|
91 | return columnWidths[3];
|
92 | }
|
93 |
|
94 | return availableWidth - (fullWidth - columnWidths[3] + MARGIN_WIDTHS);
|
95 | }
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | function formatter(messages, source) {
|
103 | if (!messages.length) return '';
|
104 |
|
105 | const orderedMessages = _.sortBy(
|
106 | messages,
|
107 | (m) => (m.line ? 2 : 1),
|
108 | (m) => m.line,
|
109 | (m) => m.column,
|
110 | );
|
111 |
|
112 | |
113 |
|
114 |
|
115 |
|
116 |
|
117 | const columnWidths = { 0: 1, 1: 1, 2: 1, 3: 1, 4: 1 };
|
118 |
|
119 | |
120 |
|
121 |
|
122 |
|
123 | function calculateWidths(columns) {
|
124 | for (const [key, value] of Object.entries(columns)) {
|
125 | const normalisedValue = value ? value.toString() : value;
|
126 |
|
127 | columnWidths[key] = Math.max(columnWidths[key], stringWidth(normalisedValue));
|
128 | }
|
129 |
|
130 | return columns;
|
131 | }
|
132 |
|
133 | let output = '\n';
|
134 |
|
135 | if (source) {
|
136 | output += `${chalk.underline(logFrom(source))}\n`;
|
137 | }
|
138 |
|
139 | const cleanedMessages = orderedMessages.map((message) => {
|
140 | const location = utils.getLocation(message);
|
141 | const severity = (message.severity);
|
142 | |
143 |
|
144 |
|
145 | const row = [
|
146 | location.line ? location.line.toString() : '',
|
147 | location.column ? location.column.toString() : '',
|
148 | symbols[severity]
|
149 | ? chalk[ (levelColors[severity])](symbols[severity])
|
150 | : severity,
|
151 | message.text
|
152 |
|
153 | .replace(/[\x01-\x1A]+/g, ' ')
|
154 | .replace(/\.$/, '')
|
155 |
|
156 | .replace(new RegExp(_.escapeRegExp('(' + message.rule + ')') + '$'), ''),
|
157 | chalk.dim(message.rule || ''),
|
158 | ];
|
159 |
|
160 | calculateWidths(row);
|
161 |
|
162 | return row;
|
163 | });
|
164 |
|
165 | if (!table) {
|
166 | table = require('table');
|
167 | }
|
168 |
|
169 | output += table
|
170 | .table(cleanedMessages, {
|
171 | border: table.getBorderCharacters('void'),
|
172 | columns: {
|
173 | 0: { alignment: 'right', width: columnWidths[0], paddingRight: 0 },
|
174 | 1: { alignment: 'left', width: columnWidths[1] },
|
175 | 2: { alignment: 'center', width: columnWidths[2] },
|
176 | 3: {
|
177 | alignment: 'left',
|
178 | width: getMessageWidth(columnWidths),
|
179 | wrapWord: getMessageWidth(columnWidths) > 1,
|
180 | },
|
181 | 4: { alignment: 'left', width: columnWidths[4], paddingRight: 0 },
|
182 | },
|
183 | drawHorizontalLine: () => false,
|
184 | })
|
185 | .split('\n')
|
186 | .map(
|
187 | |
188 |
|
189 |
|
190 |
|
191 | (el) => el.replace(/(\d+)\s+(\d+)/, (m, p1, p2) => chalk.dim(`${p1}:${p2}`)),
|
192 | )
|
193 | .join('\n');
|
194 |
|
195 | return output;
|
196 | }
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 | module.exports = function(results) {
|
203 | let output = invalidOptionsFormatter(results);
|
204 |
|
205 | output += deprecationsFormatter(results);
|
206 |
|
207 | output = results.reduce((output, result) => {
|
208 |
|
209 | if (result.parseErrors) {
|
210 | result.parseErrors.forEach((error) =>
|
211 | result.warnings.push({
|
212 | line: error.line,
|
213 | column: error.column,
|
214 | rule: error.stylelintType,
|
215 | severity: 'error',
|
216 | text: `${error.text} (${error.stylelintType})`,
|
217 | }),
|
218 | );
|
219 | }
|
220 |
|
221 | output += formatter(result.warnings, result.source || '');
|
222 |
|
223 | return output;
|
224 | }, output);
|
225 |
|
226 |
|
227 | output = output.trim();
|
228 |
|
229 | if (output !== '') {
|
230 | output = `\n${output}\n\n`;
|
231 | }
|
232 |
|
233 | return output;
|
234 | };
|