Files
react-native-devtools-frontend/node_modules/stylelint/lib/formatters/stringFormatter.js
T
Tim van der Lippe 4cb097430f Update Stylelint and Postcss
R=jacktfranklin@chromium.org

Bug: none
Change-Id: I961be18530d3ccbc4efed0c2cda9bd603b14e27b
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3372931
Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
Commit-Queue: Tim Van der Lippe <tvanderlippe@chromium.org>
2022-01-07 14:36:30 +00:00

272 lines
6.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
const path = require('path');
const stringWidth = require('string-width');
const table = require('table');
const { yellow, dim, underline, blue, red, green } = require('picocolors');
const MARGIN_WIDTHS = 9;
/**
* @param {string} s
* @returns {string}
*/
function nope(s) {
return s;
}
const levelColors = {
info: blue,
warning: yellow,
error: red,
success: nope,
};
const symbols = {
info: blue('ℹ'),
warning: yellow('⚠'),
error: red('✖'),
success: green('✔'),
};
/**
* @param {import('stylelint').LintResult[]} results
* @returns {string}
*/
function deprecationsFormatter(results) {
const allDeprecationWarnings = results.flatMap((result) => result.deprecations);
if (allDeprecationWarnings.length === 0) {
return '';
}
const seenText = new Set();
return allDeprecationWarnings.reduce((output, warning) => {
if (seenText.has(warning.text)) return output;
seenText.add(warning.text);
output += yellow('Deprecation Warning: ');
output += warning.text;
if (warning.reference) {
output += dim(' See: ');
output += dim(underline(warning.reference));
}
return `${output}\n`;
}, '\n');
}
/**
* @param {import('stylelint').LintResult[]} results
* @return {string}
*/
function invalidOptionsFormatter(results) {
const allInvalidOptionWarnings = results.flatMap((result) =>
result.invalidOptionWarnings.map((warning) => warning.text),
);
const uniqueInvalidOptionWarnings = [...new Set(allInvalidOptionWarnings)];
return uniqueInvalidOptionWarnings.reduce((output, warning) => {
output += red('Invalid Option: ');
output += warning;
return `${output}\n`;
}, '\n');
}
/**
* @param {string} fromValue
* @param {string} cwd
* @return {string}
*/
function logFrom(fromValue, cwd) {
if (fromValue.startsWith('<')) return fromValue;
return path.relative(cwd, fromValue).split(path.sep).join('/');
}
/**
* @param {{[k: number]: number}} columnWidths
* @return {number}
*/
function getMessageWidth(columnWidths) {
if (!process.stdout.isTTY) {
return columnWidths[3];
}
const availableWidth = process.stdout.columns < 80 ? 80 : process.stdout.columns;
const fullWidth = Object.values(columnWidths).reduce((a, b) => a + b);
// If there is no reason to wrap the text, we won't align the last column to the right
if (availableWidth > fullWidth + MARGIN_WIDTHS) {
return columnWidths[3];
}
return availableWidth - (fullWidth - columnWidths[3] + MARGIN_WIDTHS);
}
/**
* @param {import('stylelint').Warning[]} messages
* @param {string} source
* @param {string} cwd
* @return {string}
*/
function formatter(messages, source, cwd) {
if (!messages.length) return '';
const orderedMessages = [...messages].sort((a, b) => {
// positionless first
if (!a.line && b.line) return -1;
// positionless first
if (a.line && !b.line) return 1;
if (a.line < b.line) return -1;
if (a.line > b.line) return 1;
if (a.column < b.column) return -1;
if (a.column > b.column) return 1;
return 0;
});
/**
* Create a list of column widths, needed to calculate
* the size of the message column and if needed wrap it.
* @type {{[k: string]: number}}
*/
const columnWidths = { 0: 1, 1: 1, 2: 1, 3: 1, 4: 1 };
/**
* @param {[string, string, string, string, string]} columns
* @return {[string, string, string, string, string]}
*/
function calculateWidths(columns) {
for (const [key, value] of Object.entries(columns)) {
const normalisedValue = value ? value.toString() : value;
columnWidths[key] = Math.max(columnWidths[key], stringWidth(normalisedValue));
}
return columns;
}
let output = '\n';
if (source) {
output += `${underline(logFrom(source, cwd))}\n`;
}
/**
* @param {import('stylelint').Warning} message
* @return {string}
*/
function formatMessageText(message) {
let result = message.text;
result = result
// Remove all control characters (newline, tab and etc)
.replace(/[\u0001-\u001A]+/g, ' ') // eslint-disable-line no-control-regex
.replace(/\.$/, '');
const ruleString = ` (${message.rule})`;
if (result.endsWith(ruleString)) {
result = result.slice(0, result.lastIndexOf(ruleString));
}
return result;
}
const cleanedMessages = orderedMessages.map((message) => {
const { line, column, severity } = message;
/**
* @type {[string, string, string, string, string]}
*/
const row = [
line ? line.toString() : '',
column ? column.toString() : '',
symbols[severity] ? levelColors[severity](symbols[severity]) : severity,
formatMessageText(message),
dim(message.rule || ''),
];
calculateWidths(row);
return row;
});
output += table
.table(cleanedMessages, {
border: table.getBorderCharacters('void'),
columns: {
0: { alignment: 'right', width: columnWidths[0], paddingRight: 0 },
1: { alignment: 'left', width: columnWidths[1] },
2: { alignment: 'center', width: columnWidths[2] },
3: {
alignment: 'left',
width: getMessageWidth(columnWidths),
wrapWord: getMessageWidth(columnWidths) > 1,
},
4: { alignment: 'left', width: columnWidths[4], paddingRight: 0 },
},
drawHorizontalLine: () => false,
})
.split('\n')
.map(
/**
* @param {string} el
* @returns {string}
*/
(el) => el.replace(/(\d+)\s+(\d+)/, (_m, p1, p2) => dim(`${p1}:${p2}`)),
)
.join('\n');
return output;
}
/**
* @type {import('stylelint').Formatter}
*/
module.exports = function (results, returnValue) {
let output = invalidOptionsFormatter(results);
output += deprecationsFormatter(results);
output = results.reduce((accum, result) => {
// Treat parseErrors as warnings
if (result.parseErrors) {
for (const error of result.parseErrors)
result.warnings.push({
line: error.line,
column: error.column,
rule: error.stylelintType,
severity: 'error',
text: `${error.text} (${error.stylelintType})`,
});
}
accum += formatter(
result.warnings,
result.source || '',
(returnValue && returnValue.cwd) || process.cwd(),
);
return accum;
}, output);
// Ensure consistent padding
output = output.trim();
if (output !== '') {
output = `\n${output}\n\n`;
}
return output;
};