diff --git a/.changeset/great-feet-brake.md b/.changeset/great-feet-brake.md new file mode 100644 index 0000000000..7708315d67 --- /dev/null +++ b/.changeset/great-feet-brake.md @@ -0,0 +1,5 @@ +--- +"stylelint": patch +--- + +Fixed: `selector-pseudo-class-no-unknown` false negatives for pseudo-elements with matching names diff --git a/lib/rules/selector-pseudo-class-no-unknown/__tests__/index.js b/lib/rules/selector-pseudo-class-no-unknown/__tests__/index.js index 54dc317bae..31e9b4def1 100644 --- a/lib/rules/selector-pseudo-class-no-unknown/__tests__/index.js +++ b/lib/rules/selector-pseudo-class-no-unknown/__tests__/index.js @@ -202,6 +202,22 @@ testRule({ endLine: 1, endColumn: 7, }, + { + code: ':slotted {}', + message: messages.rejected(':slotted'), + line: 1, + column: 1, + endLine: 1, + endColumn: 9, + }, + { + code: ':placeholder {}', + message: messages.rejected(':placeholder'), + line: 1, + column: 1, + endLine: 1, + endColumn: 13, + }, { code: '@page :blank:unknown { }', message: messages.rejected(':unknown'), diff --git a/lib/rules/selector-pseudo-class-no-unknown/index.js b/lib/rules/selector-pseudo-class-no-unknown/index.js index 4cdd9700d5..3c2b372fb2 100644 --- a/lib/rules/selector-pseudo-class-no-unknown/index.js +++ b/lib/rules/selector-pseudo-class-no-unknown/index.js @@ -7,6 +7,7 @@ const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule'); const isStandardSyntaxSelector = require('../../utils/isStandardSyntaxSelector'); const { atRulePagePseudoClasses, + levelOneAndTwoPseudoElements, pseudoClasses, pseudoElements, webkitScrollbarPseudoClasses, @@ -68,8 +69,13 @@ const rule = (primary, secondaryOptions) => { return; } - // Ignore pseudo-elements - if (value.slice(0, 2) === '::') { + if (value.startsWith('::')) { + return; + } + + const name = value.replace(/^:*/, '').toLowerCase(); + + if (levelOneAndTwoPseudoElements.has(name)) { return; } @@ -77,8 +83,8 @@ const rule = (primary, secondaryOptions) => { return; } + const hasVendorPrefix = vendor.prefix(name); let index = null; - const name = value.slice(1).toLowerCase(); if (isAtRule(node) && node.name === 'page') { if (atRulePagePseudoClasses.has(name)) { @@ -86,8 +92,10 @@ const rule = (primary, secondaryOptions) => { } index = atRuleParamIndex(node) + pseudoNode.sourceIndex; + } else if (pseudoElements.has(name) && !hasVendorPrefix) { + index = pseudoNode.sourceIndex; } else { - if (vendor.prefix(name) || pseudoClasses.has(name) || pseudoElements.has(name)) { + if (hasVendorPrefix || pseudoClasses.has(name)) { return; }