.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / formatters / stringFormatter.js
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 table = require("table");
9 const utils = require("postcss-reporter/lib/util");
10
11 const MARGIN_WIDTHS = 9;
12
13 const levelColors = {
14   info: "blue",
15   warning: "yellow",
16   error: "red"
17 };
18
19 function deprecationsFormatter(results) {
20   const allDeprecationWarnings = _.flatMap(results, "deprecations");
21   const uniqueDeprecationWarnings = _.uniqBy(allDeprecationWarnings, "text");
22
23   if (!uniqueDeprecationWarnings || !uniqueDeprecationWarnings.length) {
24     return "";
25   }
26
27   return uniqueDeprecationWarnings.reduce((output, warning) => {
28     output += chalk.yellow("Deprecation Warning: ");
29     output += warning.text;
30     if (warning.reference) {
31       output += chalk.dim(" See: ");
32       output += chalk.dim.underline(warning.reference);
33     }
34     return output + "\n";
35   }, "\n");
36 }
37
38 function invalidOptionsFormatter(results) {
39   const allInvalidOptionWarnings = _.flatMap(results, r =>
40     r.invalidOptionWarnings.map(w => w.text)
41   );
42   const uniqueInvalidOptionWarnings = _.uniq(allInvalidOptionWarnings);
43
44   return uniqueInvalidOptionWarnings.reduce((output, warning) => {
45     output += chalk.red("Invalid Option: ");
46     output += warning;
47     return output + "\n";
48   }, "\n");
49 }
50
51 function logFrom(fromValue) {
52   if (fromValue.charAt(0) === "<") return fromValue;
53   return path
54     .relative(process.cwd(), fromValue)
55     .split(path.sep)
56     .join("/");
57 }
58
59 function getMessageWidth(columnWidths) {
60   if (!process.stdout.isTTY) {
61     return columnWidths[3];
62   }
63
64   const availableWidth =
65     process.stdout.columns < 80 ? 80 : process.stdout.columns;
66   const fullWidth = _.sum(_.values(columnWidths));
67
68   // If there is no reason to wrap the text, we won't align the last column to the right
69   if (availableWidth > fullWidth + MARGIN_WIDTHS) {
70     return columnWidths[3];
71   }
72
73   return availableWidth - (fullWidth - columnWidths[3] + MARGIN_WIDTHS);
74 }
75
76 function formatter(messages, source) {
77   if (!messages.length) return "";
78
79   const orderedMessages = _.sortBy(
80     messages,
81     m => (m.line ? 2 : 1), // positionless first
82     m => m.line,
83     m => m.column
84   );
85
86   // Create a list of column widths, needed to calculate
87   // the size of the message column and if needed wrap it.
88   const columnWidths = { 0: 1, 1: 1, 2: 1, 3: 1, 4: 1 };
89
90   const calculateWidths = function(columns) {
91     _.forOwn(columns, (value, key) => {
92       const normalisedValue = value ? value.toString() : value;
93       columnWidths[key] = Math.max(
94         columnWidths[key],
95         stringWidth(normalisedValue)
96       );
97     });
98
99     return columns;
100   };
101
102   let output = "\n";
103
104   if (source) {
105     output += chalk.underline(logFrom(source)) + "\n";
106   }
107
108   const cleanedMessages = orderedMessages.map(message => {
109     const location = utils.getLocation(message);
110     const severity = message.severity;
111     const row = [
112       location.line || "",
113       location.column || "",
114       symbols[severity]
115         ? chalk[levelColors[severity]](symbols[severity])
116         : severity,
117       message.text
118         // Remove all control characters (newline, tab and etc)
119         .replace(/[\x01-\x1A]+/g, " ") // eslint-disable-line
120         .replace(/\.$/, "")
121         .replace(
122           new RegExp(_.escapeRegExp("(" + message.rule + ")") + "$"),
123           ""
124         ),
125       chalk.dim(message.rule || "")
126     ];
127
128     calculateWidths(row);
129
130     return row;
131   });
132
133   output += table
134     .table(cleanedMessages, {
135       border: table.getBorderCharacters("void"),
136       columns: {
137         0: { alignment: "right", width: columnWidths[0], paddingRight: 0 },
138         1: { alignment: "left", width: columnWidths[1] },
139         2: { alignment: "center", width: columnWidths[2] },
140         3: {
141           alignment: "left",
142           width: getMessageWidth(columnWidths),
143           wrapWord: true
144         },
145         4: { alignment: "left", width: columnWidths[4], paddingRight: 0 }
146       },
147       drawHorizontalLine: () => false
148     })
149     .split("\n")
150     .map(el =>
151       el.replace(/(\d+)\s+(\d+)/, (m, p1, p2) => chalk.dim(p1 + ":" + p2))
152     )
153     .join("\n");
154
155   return output;
156 }
157
158 module.exports = function(results) {
159   let output = invalidOptionsFormatter(results);
160   output += deprecationsFormatter(results);
161
162   output = results.reduce((output, result) => {
163     // Treat parseErrors as warnings
164     if (result.parseErrors) {
165       result.parseErrors.forEach(error =>
166         result.warnings.push({
167           line: error.line,
168           column: error.column,
169           rule: error.stylelintType,
170           severity: "error",
171           text: `${error.text} (${error.stylelintType})`
172         })
173       );
174     }
175     output += formatter(result.warnings, result.source);
176     return output;
177   }, output);
178
179   // Ensure consistent padding
180   output = output.trim();
181
182   if (output !== "") {
183     output = "\n" + output + "\n\n";
184   }
185
186   return output;
187 };