Skip to content

Commit

Permalink
Add rule metadata to public LinterResult API (#6166)
Browse files Browse the repository at this point in the history
Add rule URL to `githubFormatter` output
  • Loading branch information
ybiquitous committed Jun 24, 2022
1 parent ca712dd commit 8d890c0
Show file tree
Hide file tree
Showing 16 changed files with 1,469 additions and 31 deletions.
6 changes: 6 additions & 0 deletions docs/developer-guide/formatters.md
Expand Up @@ -56,6 +56,12 @@ And the second argument (`returnValue`) is an object (type `LinterResult`) with
// Present if Stylelint was configured with a `maxWarnings` count
"maxWarnings": 10,
"foundWarnings": 15
},
"ruleMetadata": {
"block-no-empty": {
"url": "https://stylelint.io/user-guide/rules/list/block-no-empty"
},
// other rules...
}
}
```
Expand Down
6 changes: 6 additions & 0 deletions lib/__tests__/stylelintignore-test/stylelintignore.test.js
Expand Up @@ -70,6 +70,7 @@ describe('stylelintignore', () => {
output: '[]',
reportedDisables: [],
results: [],
ruleMetadata: {},
});
});

Expand Down Expand Up @@ -106,6 +107,7 @@ describe('stylelintignore', () => {
output: '[]',
reportedDisables: [],
results: [],
ruleMetadata: {},
});
});

Expand All @@ -122,6 +124,7 @@ describe('stylelintignore', () => {
output: '[]',
reportedDisables: [],
results: [],
ruleMetadata: {},
});
});
});
Expand Down Expand Up @@ -185,6 +188,7 @@ describe('stylelintignore with options.cwd', () => {
output: '[]',
reportedDisables: [],
results: [],
ruleMetadata: {},
});
});

Expand Down Expand Up @@ -223,6 +227,7 @@ describe('stylelintignore with options.cwd', () => {
output: '[]',
reportedDisables: [],
results: [],
ruleMetadata: {},
});
});

Expand All @@ -240,6 +245,7 @@ describe('stylelintignore with options.cwd', () => {
output: '[]',
reportedDisables: [],
results: [],
ruleMetadata: {},
});
});
});
Expand Down
10 changes: 8 additions & 2 deletions lib/formatters/__tests__/githubFormatter.test.js
Expand Up @@ -31,8 +31,14 @@ test('githubFormatter', () => {
],
},
];
const returnValue = {
ruleMetadata: {
foo: { url: 'https://stylelint.io/rules/foo' },
bar: {},
},
};

expect(githubFormatter(results))
.toBe(`::error file=path/to/file.css,line=1,col=2,endLine=1,endColumn=5,title=Stylelint problem::Unexpected "foo" (foo)
expect(githubFormatter(results, returnValue))
.toBe(`::error file=path/to/file.css,line=1,col=2,endLine=1,endColumn=5,title=Stylelint problem::Unexpected "foo" (foo) - https://stylelint.io/rules/foo
::warning file=a.css,line=10,col=20,title=Stylelint problem::Unexpected "bar" (bar)`);
});
5 changes: 4 additions & 1 deletion lib/formatters/__tests__/prepareFormatterOutput.js
Expand Up @@ -10,7 +10,10 @@ symbolConversions.set('⚠', '‼');
symbolConversions.set('✖', '×');

module.exports = function (results, formatter) {
let output = stripAnsi(formatter(results)).trim();
const returnValue = {
ruleMetadata: {},
};
let output = stripAnsi(formatter(results, returnValue)).trim();

for (const [nix, win] of symbolConversions.entries()) {
output = output.replace(new RegExp(nix, 'g'), win);
Expand Down
24 changes: 20 additions & 4 deletions lib/formatters/githubFormatter.js
Expand Up @@ -5,16 +5,32 @@
*
* @type {import('stylelint').Formatter}
*/
module.exports = function githubFormatter(results) {
module.exports = function githubFormatter(results, returnValue) {
const title = 'Stylelint problem';
const metadata = returnValue.ruleMetadata;

return results
.flatMap(({ source, warnings }) =>
warnings.map(({ line, column, endLine, endColumn, text, severity }) => {
warnings.map(({ line, column, endLine, endColumn, text, severity, rule }) => {
const msg = buildMessage(text, metadata[rule]);

return endLine === undefined
? `::${severity} file=${source},line=${line},col=${column},title=${title}::${text}`
: `::${severity} file=${source},line=${line},col=${column},endLine=${endLine},endColumn=${endColumn},title=${title}::${text}`;
? `::${severity} file=${source},line=${line},col=${column},title=${title}::${msg}`
: `::${severity} file=${source},line=${line},col=${column},endLine=${endLine},endColumn=${endColumn},title=${title}::${msg}`;
}),
)
.join('\n');
};

/**
* @param {string} msg
* @param {Partial<import('stylelint').RuleMeta> | undefined} metadata
* @returns {string}
*/
function buildMessage(msg, metadata) {
if (!metadata) return msg;

if (!metadata.url) return msg;

return `${msg} - ${metadata.url}`;
}
23 changes: 4 additions & 19 deletions lib/formatters/verboseFormatter.js
Expand Up @@ -10,11 +10,12 @@ const terminalLink = require('./terminalLink');
/** @typedef {import('stylelint').LintResult} LintResult */
/** @typedef {import('stylelint').Warning} Warning */
/** @typedef {import('stylelint').Severity} Severity */
/** @typedef {import('stylelint').RuleMeta} RuleMeta */

/**
* @type {Formatter}
*/
module.exports = function (results, returnValue) {
module.exports = function verboseFormatter(results, returnValue) {
let output = stringFormatter(results, returnValue);

if (output === '') {
Expand Down Expand Up @@ -54,7 +55,6 @@ module.exports = function (results, returnValue) {
output += '\n0 problems found\n';
} else {
const warningsBySeverity = groupBy(warnings, (w) => w.severity);
const metadata = ruleMetadata(results);

/**
* @param {Severity} severity
Expand All @@ -68,6 +68,7 @@ module.exports = function (results, returnValue) {
output += underline(`${problems.length} ${pluralize(severity, problems.length)} found\n`);

const problemsByRule = groupBy(problems, (w) => w.rule);
const metadata = returnValue.ruleMetadata;

for (const [rule, list] of Object.entries(problemsByRule)) {
output += dim(` ${ruleLink(rule, metadata[rule])}: ${list.length}\n`);
Expand Down Expand Up @@ -117,25 +118,9 @@ function fileLink(source) {
return terminalLink(source, `file://${source}`);
}

/**
* @param {LintResult[]} results
* @returns {Record<string, { url?: string }>}
*/
function ruleMetadata(results) {
const firstResult = results[0];

return (
(firstResult &&
firstResult._postcssResult &&
firstResult._postcssResult.stylelint &&
firstResult._postcssResult.stylelint.ruleMetadata) ||
{}
);
}

/**
* @param {string} rule
* @param {{ url?: string } | undefined} metadata
* @param {Partial<RuleMeta> | undefined} metadata
* @returns {string}
*/
function ruleLink(rule, metadata) {
Expand Down
18 changes: 15 additions & 3 deletions lib/prepareReturnValue.js
Expand Up @@ -18,7 +18,7 @@ const reportDisables = require('./reportDisables');
*
* @returns {LinterResult}
*/
function prepareReturnValue(stylelintResults, maxWarnings, formatter, cwd) {
module.exports = function prepareReturnValue(stylelintResults, maxWarnings, formatter, cwd) {
reportDisables(stylelintResults);
needlessDisables(stylelintResults);
invalidScopeDisables(stylelintResults);
Expand All @@ -38,6 +38,7 @@ function prepareReturnValue(stylelintResults, maxWarnings, formatter, cwd) {
results: [],
output: '',
reportedDisables: [],
ruleMetadata: getRuleMetadata(stylelintResults),
};

if (maxWarnings !== undefined) {
Expand All @@ -52,6 +53,17 @@ function prepareReturnValue(stylelintResults, maxWarnings, formatter, cwd) {
returnValue.results = stylelintResults;

return returnValue;
}
};

/**
* @param {StylelintResult[]} lintResults
*/
function getRuleMetadata(lintResults) {
const [lintResult] = lintResults;

module.exports = prepareReturnValue;
if (lintResult === undefined) return {};

if (lintResult._postcssResult === undefined) return {};

return lintResult._postcssResult.stylelint.ruleMetadata;
}

0 comments on commit 8d890c0

Please sign in to comment.