diff --git a/lib/rules/selector-combinator-space-after/__tests__/index.js b/lib/rules/selector-combinator-space-after/__tests__/index.js index eb05188292..a153b793a4 100644 --- a/lib/rules/selector-combinator-space-after/__tests__/index.js +++ b/lib/rules/selector-combinator-space-after/__tests__/index.js @@ -554,33 +554,9 @@ testRule({ code: 'a { > /*comment*/a, > /*comment*/.b{} }', description: 'scss nesting and comment', }, - ], - - reject: [ { - code: 'a { >/*comment*/a {} }', - fixed: 'a { > /*comment*/a {} }', - description: 'scss nesting and comment', - message: messages.expectedAfter('>'), - line: 1, - column: 5, - }, - { - code: 'a { >/*comment*/a, >/*comment*/.b{} }', - fixed: 'a { > /*comment*/a, > /*comment*/.b{} }', - description: 'scss nesting, comment and comma', - warnings: [ - { - message: messages.expectedAfter('>'), - line: 1, - column: 5, - }, - { - message: messages.expectedAfter('>'), - line: 1, - column: 20, - }, - ], + code: 'a ~, b {}', + description: 'scss trailing combinator', }, ], }); @@ -596,33 +572,9 @@ testRule({ code: 'a { >/*comment*/a, >/*comment*/.b {} }', description: 'scss nesting and comment', }, - ], - - reject: [ { - code: 'a { > /*comment*/a {} }', - fixed: 'a { >/*comment*/a {} }', - description: 'scss nesting and comment', - message: messages.rejectedAfter('>'), - line: 1, - column: 5, - }, - { - code: 'a { > /*comment*/a, > /*comment*/.b {} }', - fixed: 'a { >/*comment*/a, >/*comment*/.b {} }', - description: 'scss nesting, comment and comma', - warnings: [ - { - message: messages.rejectedAfter('>'), - line: 1, - column: 5, - }, - { - message: messages.rejectedAfter('>'), - line: 1, - column: 21, - }, - ], + code: 'a ~, b {}', + description: 'scss trailing combinator', }, ], }); diff --git a/lib/rules/selectorCombinatorSpaceChecker.js b/lib/rules/selectorCombinatorSpaceChecker.js index c6731dc1bc..d8c73a846a 100644 --- a/lib/rules/selectorCombinatorSpaceChecker.js +++ b/lib/rules/selectorCombinatorSpaceChecker.js @@ -2,6 +2,7 @@ 'use strict'; +const isStandardSyntaxCombinator = require('../utils/isStandardSyntaxCombinator'); const isStandardSyntaxRule = require('../utils/isStandardSyntaxRule'); const parseSelector = require('../utils/parseSelector'); const report = require('../utils/report'); @@ -19,6 +20,11 @@ module.exports = function (opts) { const fixedSelector = parseSelector(selector, opts.result, rule, (selectorTree) => { selectorTree.walkCombinators((node) => { + // Ignore non-standard combinators + if (!isStandardSyntaxCombinator(node)) { + return; + } + // Ignore spaced descendant combinator if (/\s/.test(node.value)) { return; diff --git a/lib/utils/__tests__/isStandardSyntaxCombinator.test.js b/lib/utils/__tests__/isStandardSyntaxCombinator.test.js index ed73f96d59..65b71d3454 100644 --- a/lib/utils/__tests__/isStandardSyntaxCombinator.test.js +++ b/lib/utils/__tests__/isStandardSyntaxCombinator.test.js @@ -60,6 +60,26 @@ describe('isStandardSyntaxCombinator', () => { expect(isStandardSyntaxCombinator(func)).toBeFalsy(); }); }); + it('last node is combinator', () => { + rules('a ~, {}', (func) => { + expect(isStandardSyntaxCombinator(func)).toBeFalsy(); + }); + }); + it('first node is combinator', () => { + rules('~ b {}', (func) => { + expect(isStandardSyntaxCombinator(func)).toBeFalsy(); + }); + }); + it('last node (in first container) is combinator', () => { + rules('a ~, b {}', (func) => { + expect(isStandardSyntaxCombinator(func)).toBeFalsy(); + }); + }); + it('first node (in second container) is combinator', () => { + rules('a, ~ b {}', (func) => { + expect(isStandardSyntaxCombinator(func)).toBeFalsy(); + }); + }); }); function rules(css, cb) { diff --git a/lib/utils/isStandardSyntaxCombinator.js b/lib/utils/isStandardSyntaxCombinator.js index 2a929510ca..2eba3d9677 100644 --- a/lib/utils/isStandardSyntaxCombinator.js +++ b/lib/utils/isStandardSyntaxCombinator.js @@ -7,6 +7,28 @@ * @return {boolean} If `true`, the combinator is standard */ module.exports = function (node) { + // if it's not a combinator, then it's not a standard combinator + if (node.type !== 'combinator') { + return false; + } + // Ignore reference combinators like `/deep/` - return node.type === 'combinator' && !node.value.startsWith('/') && !node.value.endsWith('/'); + if (node.value.startsWith('/') || node.value.endsWith('/')) { + return false; + } + + // ignore the combinators that are the first or last node in their container + if (node.parent !== undefined && node.parent !== null) { + let parent = node.parent; + + if (node === parent.first) { + return false; + } + + if (node === parent.last) { + return false; + } + } + + return true; };