From e8987b4a1f017cbe3840f2610b764a1f0b6c3cbb Mon Sep 17 00:00:00 2001 From: Issei Horie Date: Mon, 5 Jun 2023 10:31:17 +0900 Subject: [PATCH 1/3] Add splitList option to selector-nested-pattern rule --- lib/rules/selector-nested-pattern/README.md | 34 ++++++++++ .../__tests__/index.js | 39 +++++++++++- lib/rules/selector-nested-pattern/index.js | 63 +++++++++++++------ 3 files changed, 115 insertions(+), 21 deletions(-) diff --git a/lib/rules/selector-nested-pattern/README.md b/lib/rules/selector-nested-pattern/README.md index 23a9e13fb4..9f2a560e66 100644 --- a/lib/rules/selector-nested-pattern/README.md +++ b/lib/rules/selector-nested-pattern/README.md @@ -77,3 +77,37 @@ a { &:focus {} } ``` + +## Optional secondary options + +### `splitList: true | false` (default: `false`) + +Split selector lists into individual selectors. + +For example, with `true`. + +Given the string: + +```json +"^&:(?:hover|focus)$" +``` + +The following patterns are considered problems: + + +```css +a { + .bar:hover, + &:focus {} +} +``` + +The following patterns are _not_ considered problems: + + +```css +a { + &:hover, + &:focus {} +} +``` diff --git a/lib/rules/selector-nested-pattern/__tests__/index.js b/lib/rules/selector-nested-pattern/__tests__/index.js index 4b8f9f7f5a..e9288f5674 100644 --- a/lib/rules/selector-nested-pattern/__tests__/index.js +++ b/lib/rules/selector-nested-pattern/__tests__/index.js @@ -152,12 +152,45 @@ testRule({ endColumn: 18, }, { - code: '.foo { &:hover, &focus {} }', - message: messages.expected('&:hover, &focus', '^&:(?:hover|focus)$'), + code: '.foo { &:hover, &:focus {} }', + message: messages.expected('&:hover, &:focus', '^&:(?:hover|focus)$'), line: 1, column: 8, endLine: 1, - endColumn: 23, + endColumn: 24, + }, + ], +}); + +testRule({ + ruleName, + config: ['^&:(?:hover|focus)$', { splitList: true }], + + accept: [ + { + code: '.foo { &:hover {} }', + }, + { + code: '.foo { &:hover, &:focus {} }', + }, + ], + + reject: [ + { + code: '.foo { .bar:hover {} }', + message: messages.expected('.bar:hover', '^&:(?:hover|focus)$'), + line: 1, + column: 8, + endLine: 1, + endColumn: 18, + }, + { + code: '.foo { .bar:hover, &:focus {} }', + message: messages.expected('.bar:hover', '^&:(?:hover|focus)$'), + line: 1, + column: 8, + endLine: 1, + endColumn: 18, }, ], }); diff --git a/lib/rules/selector-nested-pattern/index.js b/lib/rules/selector-nested-pattern/index.js index d43c826e64..b5d405bfa7 100644 --- a/lib/rules/selector-nested-pattern/index.js +++ b/lib/rules/selector-nested-pattern/index.js @@ -4,7 +4,7 @@ const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule'); const report = require('../../utils/report'); const ruleMessages = require('../../utils/ruleMessages'); const validateOptions = require('../../utils/validateOptions'); -const { isRegExp, isString } = require('../../utils/validateTypes'); +const { isBoolean, isRegExp, isString } = require('../../utils/validateTypes'); const ruleName = 'selector-nested-pattern'; @@ -17,18 +17,30 @@ const meta = { }; /** @type {import('stylelint').Rule} */ -const rule = (primary) => { +const rule = (primary, secondaryOptions) => { return (root, result) => { - const validOptions = validateOptions(result, ruleName, { - actual: primary, - possible: [isRegExp, isString], - }); + const validOptions = validateOptions( + result, + ruleName, + { + actual: primary, + possible: [isRegExp, isString], + }, + { + actual: secondaryOptions, + possible: { + splitList: [isBoolean], + }, + optional: true, + }, + ); if (!validOptions) { return; } const normalizedPattern = isString(primary) ? new RegExp(primary) : primary; + const splitList = secondaryOptions && secondaryOptions.splitList; root.walkRules((ruleNode) => { if (ruleNode.parent && ruleNode.parent.type !== 'rule') { @@ -39,20 +51,35 @@ const rule = (primary) => { return; } - const selector = ruleNode.selector; + if (splitList) { + ruleNode.selectors.forEach((selector) => { + if (!normalizedPattern.test(selector)) { + report({ + result, + ruleName, + message: messages.expected, + messageArgs: [selector, primary], + node: ruleNode, + word: selector, + }); + } + }); + } else { + const selector = ruleNode.selector; - if (normalizedPattern.test(selector)) { - return; - } + if (normalizedPattern.test(selector)) { + return; + } - report({ - result, - ruleName, - message: messages.expected, - messageArgs: [selector, primary], - node: ruleNode, - word: selector, - }); + report({ + result, + ruleName, + message: messages.expected, + messageArgs: [selector, primary], + node: ruleNode, + word: selector, + }); + } }); }; }; From 9952b71d808ac5935573fbc2f5a55de65b997f40 Mon Sep 17 00:00:00 2001 From: Masafumi Koba <473530+ybiquitous@users.noreply.github.com> Date: Mon, 5 Jun 2023 11:58:33 +0900 Subject: [PATCH 2/3] Add changelog entry --- .changeset/chilled-lizards-film.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chilled-lizards-film.md diff --git a/.changeset/chilled-lizards-film.md b/.changeset/chilled-lizards-film.md new file mode 100644 index 0000000000..7078ddd0e3 --- /dev/null +++ b/.changeset/chilled-lizards-film.md @@ -0,0 +1,5 @@ +--- +"stylelint": minor +--- + +Added: `splitList: boolean` to `selector-nested-pattern` From 33239f984d6606fed515836f656ecda43a6fa93b Mon Sep 17 00:00:00 2001 From: Issei Horie Date: Mon, 5 Jun 2023 12:09:43 +0900 Subject: [PATCH 3/3] use ternary operator --- lib/rules/selector-nested-pattern/index.js | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/lib/rules/selector-nested-pattern/index.js b/lib/rules/selector-nested-pattern/index.js index b5d405bfa7..6d10d4fbe0 100644 --- a/lib/rules/selector-nested-pattern/index.js +++ b/lib/rules/selector-nested-pattern/index.js @@ -51,24 +51,11 @@ const rule = (primary, secondaryOptions) => { return; } - if (splitList) { - ruleNode.selectors.forEach((selector) => { - if (!normalizedPattern.test(selector)) { - report({ - result, - ruleName, - message: messages.expected, - messageArgs: [selector, primary], - node: ruleNode, - word: selector, - }); - } - }); - } else { - const selector = ruleNode.selector; + const selectors = splitList ? ruleNode.selectors : [ruleNode.selector]; + for (const selector of selectors) { if (normalizedPattern.test(selector)) { - return; + continue; } report({