UNPKG

2.9 kBJavaScriptView Raw
1'use strict';
2
3const _ = require('lodash');
4
5/** @typedef {import('stylelint').RangeType} RangeType */
6/** @typedef {import('stylelint').UnusedRange} UnusedRange */
7/** @typedef {import('stylelint').StylelintDisableOptionsReport} StylelintDisableOptionsReport */
8
9/**
10 * @param {import('stylelint').StylelintResult[]} results
11 * @returns {StylelintDisableOptionsReport}
12 */
13module.exports = function (results) {
14 /** @type {StylelintDisableOptionsReport} */
15 const report = [];
16
17 results.forEach((result) => {
18 // File with `CssSyntaxError` have not `_postcssResult`
19 if (!result._postcssResult) {
20 return;
21 }
22
23 /** @type {{ranges: UnusedRange[], source: string}} */
24 const unused = { source: result.source || '', ranges: [] };
25
26 /** @type {{[ruleName: string]: Array<RangeType>}} */
27 const rangeData = _.cloneDeep(result._postcssResult.stylelint.disabledRanges);
28
29 if (!rangeData) {
30 return;
31 }
32
33 const disabledWarnings = result._postcssResult.stylelint.disabledWarnings || [];
34
35 disabledWarnings.forEach((warning) => {
36 const rule = warning.rule;
37
38 const ruleRanges = rangeData[rule];
39
40 if (ruleRanges) {
41 // Back to front so we get the *last* range that applies to the warning
42 for (const range of ruleRanges.reverse()) {
43 if (isWarningInRange(warning, range)) {
44 range.used = true;
45
46 return;
47 }
48 }
49 }
50
51 for (const range of rangeData.all.reverse()) {
52 if (isWarningInRange(warning, range)) {
53 range.used = true;
54
55 return;
56 }
57 }
58 });
59
60 Object.keys(rangeData).forEach((rule) => {
61 rangeData[rule].forEach((range) => {
62 // Is an equivalent range already marked as unused?
63 const alreadyMarkedUnused = unused.ranges.find((unusedRange) => {
64 return unusedRange.start === range.start && unusedRange.end === range.end;
65 });
66
67 // If this range is unused and no equivalent is marked,
68 // mark this range as unused
69 if (!range.used && !alreadyMarkedUnused) {
70 unused.ranges.push({
71 start: range.start,
72 end: range.end,
73 unusedRule: rule,
74 });
75 }
76
77 // If this range is used but an equivalent has been marked as unused,
78 // remove that equivalent. This can happen because of the duplication
79 // of ranges in rule-specific range sets and the "all" range set
80 if (range.used && alreadyMarkedUnused) {
81 _.remove(unused.ranges, alreadyMarkedUnused);
82 }
83 });
84 });
85
86 unused.ranges = _.sortBy(unused.ranges, ['start', 'end']);
87
88 report.push(unused);
89 });
90
91 return report;
92};
93
94/**
95 * @param {import('stylelint').DisabledWarning} warning
96 * @param {RangeType} range
97 * @return {boolean}
98 */
99function isWarningInRange(warning, range) {
100 const line = warning.line;
101
102 // Need to check if range.end exist, because line number type cannot be compared to undefined
103 return (
104 range.start <= line &&
105 ((range.end !== undefined && range.end >= line) || range.end === undefined)
106 );
107}