Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ignorePseudoClasses: [] to max-nesting-depth #5620

Merged
merged 13 commits into from Oct 27, 2021
58 changes: 58 additions & 0 deletions lib/rules/max-nesting-depth/README.md
Expand Up @@ -353,3 +353,61 @@ a {
}
}
```

### `ignorePseudoClasses: ["/regex/", /regex/, "string"]`

Ignore the specified pseudo classes.
lachieh marked this conversation as resolved.
Show resolved Hide resolved

For example, with `1` and given:

```json
["hover", "active"]
lachieh marked this conversation as resolved.
Show resolved Hide resolved
```

The following patterns are _not_ considered problems:

<!-- prettier-ignore -->
```css
.a {
&:hover { /* ignored */
.b { /* 1 */
lachieh marked this conversation as resolved.
Show resolved Hide resolved
top: 0;
}
}
}
```

<!-- prettier-ignore -->
```css
.a {
&:hover, &:active { /* ignored */
.b { /* 1 */
top: 0;
}
}
}
```

The following patterns are considered problems:

<!-- prettier-ignore -->
```css
.a {
&:visited { /* 1 */
.b { /* 2 */
top: 0;
}
}
}
```

<!-- prettier-ignore -->
```css
.a {
&:hover, &:visited { /* 1 */
.b { /* 2 */
top: 0;
}
}
}
```
32 changes: 32 additions & 0 deletions lib/rules/max-nesting-depth/__tests__/index.js
Expand Up @@ -166,6 +166,38 @@ testRule({
],
});

testRule({
ruleName,
config: [1, { ignorePseudoClasses: ['hover', '/^custom-.*$/'] }],
lachieh marked this conversation as resolved.
Show resolved Hide resolved

accept: [
{
code: '.a { &:hover { .b { top: 0; } } }',
lachieh marked this conversation as resolved.
Show resolved Hide resolved
},
{
code: '.a { &:hover, &:custom-pseudo { .b { top: 0; } } }',
},
],

reject: [
{
code: '.a { &:visited { .b { top: 0; } } }',
message: messages.expected(1),
description: 'pseudo-class not ignored',
},
{
code: '.a { &:custom-pseudo, &:visited { .b { top: 0; } } }',
message: messages.expected(1),
description: 'ignored pseudo-class alongside pseudo-class',
},
{
code: '.a { &:hover, .b { .c { top: 0; } } }',
message: messages.expected(1),
description: 'pseudo-class alongside class',
},
],
});

testRule({
ruleName,
config: [1, { ignoreAtRules: ['media', '/^my-/'] }],
Expand Down
25 changes: 23 additions & 2 deletions lib/rules/max-nesting-depth/index.js
Expand Up @@ -25,7 +25,7 @@ const rule = (primary, secondaryOptions) => {
isAtRule(node) && optionsMatches(secondaryOptions, 'ignoreAtRules', node.name);

return (root, result) => {
validateOptions(
const validOptions = validateOptions(
result,
ruleName,
{
Expand All @@ -38,10 +38,13 @@ const rule = (primary, secondaryOptions) => {
possible: {
ignore: ['blockless-at-rules', 'pseudo-classes'],
ignoreAtRules: [isString, isRegExp],
ignorePseudoClasses: [isString, isRegExp],
},
},
);

if (!validOptions) return;

root.walkRules(checkStatement);
root.walkAtRules(checkStatement);

Expand Down Expand Up @@ -108,13 +111,31 @@ const rule = (primary, secondaryOptions) => {
return selectors.every((sel) => sel.startsWith('&:') && sel[2] !== ':');
}

/**
* @param {string[]} selectors
* @returns {boolean}
*/
function containsIgnoredPseudoClassesOnly(selectors) {
return selectors.every((selector) => {
const pseudoRule = selector.startsWith('&:') && selector[2] !== ':' && selector.substr(2);
lachieh marked this conversation as resolved.
Show resolved Hide resolved

if (!pseudoRule) return false;

return optionsMatches(secondaryOptions, 'ignorePseudoClasses', pseudoRule);
});
}

if (
(optionsMatches(secondaryOptions, 'ignore', 'blockless-at-rules') &&
isAtRule(node) &&
node.every((child) => !isDeclaration(child))) ||
(optionsMatches(secondaryOptions, 'ignore', 'pseudo-classes') &&
isRule(node) &&
containsPseudoClassesOnly(node.selector))
containsPseudoClassesOnly(node.selector)) ||
(isRule(node) &&
secondaryOptions &&
secondaryOptions.ignorePseudoClasses &&
containsIgnoredPseudoClassesOnly(node.selectors))
lachieh marked this conversation as resolved.
Show resolved Hide resolved
) {
return nestingDepth(parent, level);
}
Expand Down