diff --git a/lib/rules/no-descending-specificity/README.md b/lib/rules/no-descending-specificity/README.md index 4c8a7ea5f7..ab1b676c2e 100644 --- a/lib/rules/no-descending-specificity/README.md +++ b/lib/rules/no-descending-specificity/README.md @@ -105,3 +105,24 @@ a {} #baz a {} } ``` + +### `ignore: ["selectors-within-list"]` + +Ignores selectors within list of selectors. + +The following patterns are considered violations: + +```css +b a {} +h1 {} +h2 {} +h3 {} +a {} +``` + +The following patterns are *not* considered violations: + +```css +b a {} +h1, h2, h3, a {} +``` diff --git a/lib/rules/no-descending-specificity/__tests__/index.js b/lib/rules/no-descending-specificity/__tests__/index.js index 7321d902c6..8e109c2bbe 100644 --- a/lib/rules/no-descending-specificity/__tests__/index.js +++ b/lib/rules/no-descending-specificity/__tests__/index.js @@ -239,3 +239,27 @@ testRule(rule, { } ] }); + +testRule(rule, { + ruleName, + config: [true, { ignore: ["selectors-within-list"] }], + skipBasicChecks: true, + + accept: [ + { + code: "b a {} h1, h2, h3, a {}" + }, + { + code: "b a {} a, h1, h2, h3 {}" + } + ], + + reject: [ + { + code: "b a {} h1 {} h2 {} h3 {} a {}", + message: messages.rejected("a", "b a"), + line: 1, + column: 26 + } + ] +}); diff --git a/lib/rules/no-descending-specificity/index.js b/lib/rules/no-descending-specificity/index.js index 945e9b8583..54aa62420a 100644 --- a/lib/rules/no-descending-specificity/index.js +++ b/lib/rules/no-descending-specificity/index.js @@ -7,6 +7,7 @@ const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule"); const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector"); const keywordSets = require("../../reference/keywordSets"); const nodeContextLookup = require("../../utils/nodeContextLookup"); +const optionsMatches = require("../../utils/optionsMatches"); const parseSelector = require("../../utils/parseSelector"); const report = require("../../utils/report"); const resolvedNestedSelector = require("postcss-resolve-nested-selector"); @@ -20,9 +21,22 @@ const messages = ruleMessages(ruleName, { rejected: (b, a) => `Expected selector "${b}" to come before selector "${a}"` }); -const rule = function(actual) { +const rule = function(on, options) { return (root, result) => { - const validOptions = validateOptions(result, ruleName, { actual }); + const validOptions = validateOptions( + result, + ruleName, + { + actual: on + }, + { + optional: true, + actual: options, + possible: { + ignore: ["selectors-within-list"] + } + } + ); if (!validOptions) { return; @@ -41,6 +55,14 @@ const rule = function(actual) { return; } + // Ignores selectors within list of selectors + if ( + optionsMatches(options, "ignore", "selectors-within-list") && + rule.selectors.length > 1 + ) { + return; + } + const comparisonContext = selectorContextLookup.getContext( rule, findAtRuleContext(rule)