diff --git a/lib/rules/selector-not-notation/__tests__/index.js b/lib/rules/selector-not-notation/__tests__/index.js index a7ec2c43dc..3957dc123b 100644 --- a/lib/rules/selector-not-notation/__tests__/index.js +++ b/lib/rules/selector-not-notation/__tests__/index.js @@ -5,7 +5,7 @@ const { messages, ruleName } = require('..'); testRule({ ruleName, config: ['simple'], - fix: false, + fix: true, accept: [ { @@ -80,7 +80,7 @@ testRule({ testRule({ ruleName, config: ['complex'], - fix: false, + fix: true, accept: [ { @@ -99,11 +99,19 @@ testRule({ reject: [ { - code: ':not(.foo):not(a) {}', - fixed: ':not(.foo, a) {}', + code: ':not(.foo ,:hover ):not( a,div) {}', + fixed: ':not(.foo, :hover, a, div) {}', message: messages.expected('complex'), line: 1, - column: 11, + column: 21, + }, + { + code: ':not():not(a) {}', + fixed: ':not(a) {}', + message: messages.expected('complex'), + line: 1, + column: 21, + skip: true, }, ], }); diff --git a/lib/rules/selector-not-notation/index.js b/lib/rules/selector-not-notation/index.js index 600256db75..de861028c8 100644 --- a/lib/rules/selector-not-notation/index.js +++ b/lib/rules/selector-not-notation/index.js @@ -22,6 +22,8 @@ const meta = { url: 'https://stylelint.io/user-guide/rules/list/selector-not-not /** @typedef {import('postcss-selector-parser').Node} Node */ /** @typedef {import('postcss-selector-parser').Selector} Selector */ +/** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */ +/** @typedef {import('postcss-selector-parser').Container} Container */ /** * @param {Node} node @@ -96,10 +98,7 @@ const rule = (primary, _, context) => { if (!hasConsecutiveNot) return; - if (context.fix) { - /* TODO */ - return; - } + if (context.fix) return fixComplex(/** @type {Pseudo} */ (prev)); } else { const selectors = pseudo.nodes; @@ -131,7 +130,7 @@ const rule = (primary, _, context) => { }; /** - * @param {import('postcss-selector-parser').Pseudo} not + * @param {Pseudo} not */ function fixSimple(not) { const simpleSelectors = not.nodes @@ -144,12 +143,13 @@ function fixSimple(not) { }); not.empty(); + // @ts-ignore not.nodes.push(simpleSelectors.shift()); for (const s of simpleSelectors) { - const last = not.parent.last; + const last = /** @type {Container} */ (not.parent).last; - not.parent.insertAfter( + /** @type {Container} */ (not.parent).insertAfter( last, last.clone({ nodes: [s], @@ -158,6 +158,33 @@ function fixSimple(not) { } } +/** + * @param {Pseudo} previousNot + */ +function fixComplex(previousNot) { + const indentAndTrimRight = (/** @type {Selector[]} */ selectors) => { + for (const s of selectors) { + s.nodes[0].rawSpaceBefore = ' '; + s.nodes[0].rawSpaceAfter = ''; + } + }; + const [head, ...tail] = previousNot.nodes; + let node = previousNot.next(); + + head.nodes[0].rawSpaceAfter = ''; + indentAndTrimRight(tail); + + while (isNot(node)) { + const selectors = /** @type {Pseudo} */ (node).nodes; + const prev = node; + + indentAndTrimRight(selectors); + previousNot.nodes = previousNot.nodes.concat(selectors); + node = node.next(); + prev.remove(); + } +} + rule.ruleName = ruleName; rule.messages = messages; rule.meta = meta;