Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 1 | 'use strict'; |
| 2 | |
Tim van der Lippe | 0a9b84d | 2021-03-24 11:53:15 +0000 | [diff] [blame] | 3 | const optionsMatches = require('./utils/optionsMatches'); |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 4 | const putIfAbsent = require('./utils/putIfAbsent'); |
Tim van der Lippe | 0a9b84d | 2021-03-24 11:53:15 +0000 | [diff] [blame] | 5 | const validateDisableSettings = require('./validateDisableSettings'); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 6 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame] | 7 | /** @typedef {import('postcss').Comment} PostcssComment */ |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 8 | /** @typedef {import('stylelint').DisabledRange} DisabledRange */ |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 9 | /** @typedef {import('stylelint').RangeType} RangeType */ |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 10 | /** @typedef {import('stylelint').DisableReportRange} DisableReportRange */ |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 11 | |
| 12 | /** |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame] | 13 | * @param {import('stylelint').LintResult[]} results |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 14 | */ |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame] | 15 | module.exports = function needlessDisables(results) { |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 16 | results.forEach((result) => { |
Tim van der Lippe | 0a9b84d | 2021-03-24 11:53:15 +0000 | [diff] [blame] | 17 | const settings = validateDisableSettings(result._postcssResult, 'reportNeedlessDisables'); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 18 | |
Tim van der Lippe | 0a9b84d | 2021-03-24 11:53:15 +0000 | [diff] [blame] | 19 | if (!settings) return; |
Tim van der Lippe | cc71b28 | 2021-02-12 15:51:14 +0000 | [diff] [blame] | 20 | |
Tim van der Lippe | 0a9b84d | 2021-03-24 11:53:15 +0000 | [diff] [blame] | 21 | const [enabled, options, stylelintResult] = settings; |
Tim van der Lippe | cc71b28 | 2021-02-12 15:51:14 +0000 | [diff] [blame] | 22 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame] | 23 | const rangeData = stylelintResult.disabledRanges; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 24 | |
Tim van der Lippe | 0a9b84d | 2021-03-24 11:53:15 +0000 | [diff] [blame] | 25 | if (!rangeData) return; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 26 | |
Tim van der Lippe | cc71b28 | 2021-02-12 15:51:14 +0000 | [diff] [blame] | 27 | const disabledWarnings = stylelintResult.disabledWarnings || []; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 28 | |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 29 | // A map from `stylelint-disable` comments to the set of rules that |
| 30 | // are usefully disabled by each comment. We track this |
| 31 | // comment-by-comment rather than range-by-range because ranges that |
| 32 | // disable *all* rules are duplicated for each rule they apply to in |
| 33 | // practice. |
| 34 | /** @type {Map<PostcssComment, Set<string>>}} */ |
| 35 | const usefulDisables = new Map(); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 36 | |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 37 | for (const warning of disabledWarnings) { |
| 38 | const rule = warning.rule; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 39 | const ruleRanges = rangeData[rule]; |
| 40 | |
| 41 | if (ruleRanges) { |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 42 | for (const range of ruleRanges) { |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 43 | if (isWarningInRange(warning, range)) { |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 44 | putIfAbsent(usefulDisables, range.comment, () => new Set()).add(rule); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 45 | } |
| 46 | } |
| 47 | } |
| 48 | |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 49 | for (const range of rangeData.all) { |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 50 | if (isWarningInRange(warning, range)) { |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 51 | putIfAbsent(usefulDisables, range.comment, () => new Set()).add(rule); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 52 | } |
| 53 | } |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 54 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 55 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame] | 56 | const allRangeComments = new Set(rangeData.all.map((range) => range.comment)); |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 57 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame] | 58 | for (const [rule, ranges] of Object.entries(rangeData)) { |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 59 | for (const range of ranges) { |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame] | 60 | if (rule !== 'all' && allRangeComments.has(range.comment)) continue; |
| 61 | |
Tim van der Lippe | 0a9b84d | 2021-03-24 11:53:15 +0000 | [diff] [blame] | 62 | if (enabled === optionsMatches(options, 'except', rule)) continue; |
| 63 | |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 64 | const useful = usefulDisables.get(range.comment) || new Set(); |
| 65 | |
| 66 | // Only emit a warning if this range's comment isn't useful for this rule. |
| 67 | // For the special rule "all", only emit a warning if it's not useful for |
Tim van der Lippe | cc71b28 | 2021-02-12 15:51:14 +0000 | [diff] [blame] | 68 | // *any* rules, because it covers all of them. |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 69 | if (rule === 'all' ? useful.size !== 0 : useful.has(rule)) continue; |
| 70 | |
| 71 | // If the comment doesn't have a location, we can't report a useful error. |
| 72 | // In practice we expect all comments to have locations, though. |
| 73 | if (!range.comment.source || !range.comment.source.start) continue; |
| 74 | |
| 75 | result.warnings.push({ |
| 76 | text: `Needless disable for "${rule}"`, |
| 77 | rule: '--report-needless-disables', |
| 78 | line: range.comment.source.start.line, |
| 79 | column: range.comment.source.start.column, |
Tim van der Lippe | 0a9b84d | 2021-03-24 11:53:15 +0000 | [diff] [blame] | 80 | severity: options.severity, |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 81 | }); |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 82 | } |
| 83 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 84 | }); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 85 | }; |
| 86 | |
| 87 | /** |
| 88 | * @param {import('stylelint').DisabledWarning} warning |
| 89 | * @param {RangeType} range |
| 90 | * @return {boolean} |
| 91 | */ |
| 92 | function isWarningInRange(warning, range) { |
| 93 | const line = warning.line; |
| 94 | |
| 95 | // Need to check if range.end exist, because line number type cannot be compared to undefined |
| 96 | return ( |
| 97 | range.start <= line && |
| 98 | ((range.end !== undefined && range.end >= line) || range.end === undefined) |
| 99 | ); |
| 100 | } |