Skip to content

Commit

Permalink
Add mixin-no-risky-parent-selectors rule. (#985)
Browse files Browse the repository at this point in the history
  • Loading branch information
pamelalozano16 committed May 3, 2024
1 parent 90caa27 commit d06186d
Show file tree
Hide file tree
Showing 4 changed files with 418 additions and 0 deletions.
144 changes: 144 additions & 0 deletions src/rules/at-mixin-no-risky-nesting-selector/README.md
@@ -0,0 +1,144 @@
# at-mixin-no-risky-nesting-selector

Disallow risky nesting selectors within a mixin.

If a mixin contains a parent selector within another style rule, and is used in a nested context,
the output selector may include the outermost parent selector in an unexpected way.

In this example:
```scss
@mixin foo {
.a {
color: blue;
.b & {
color: red;
}
}
}

.c {
@include foo;
}
```

The user may expect `.c` to go outside all selectors in `foo`:
`.c .b .a {...}`

But this outputs:
```scss
.c .a {
color: blue;
}
.b .c .a {
color: red;
}
```

However, if we pull the parent selector into the child and make the child style rule a sibling:
```scss
@mixin foo {
.a {
color: blue;
}
.b .a {
color: red;
}
}

.c {
@include foo;
}
```

It outputs:
```scss
.c .a {
color: blue;
}
.c .b .a {
color: red;
}
```

This only occurs when a parent selector meets all of the following conditions:
- Is within a `@mixin` rule.
- Is nested within another style rule.
- Is not positioned at the beginning of a complex selector.

## Options

### `true`

The following patterns are considered warnings:

```scss
@mixin foo {
.bar {
color: blue;
.baz & {
color: red;
}
}
}
```

```scss
@mixin foo {
.bar {
color: blue;
.qux, .baz & .quux{
color: red;
}
}
}
```

The following patterns are _not_ considered warnings:

```scss
.foo {
.bar {
color: blue;
.baz & {
color: red;
}
}
}
```

```scss
@mixin foo {
.bar {
color: blue;
& .baz {
color: red;
}
}
}
```

```scss
.bar {
color: blue;
.baz & {
color: red;
}
}
```

```scss
.foo {
color: blue;
& .bar, .baz & .qux {
color: red;
}
}
```

```scss
@mixin foo {
.baz & {
color: red;
}
}
```
206 changes: 206 additions & 0 deletions src/rules/at-mixin-no-risky-nesting-selector/__tests__/index.js
@@ -0,0 +1,206 @@
"use strict";

const { ruleName } = require("..");

testRule({
ruleName,
config: [true],
customSyntax: "postcss-scss",

accept: [
{
code: `
.parent {
color: blue;
& .b {
color: red;
}
}
`,
description: "Nested parent selector"
},
{
code: `
.parent {
color: blue;
& .b, &.context {
color: red;
}
}
`,
description: "Nested parent selector in complex selector"
},
{
code: `
.bar {
& .parent {
color: blue;
.context {
color: red;
}
}
}
`,
description: "Parent selector nested in another style rule"
},
{
code: `
@mixin foo {
&.context {
color: red;
}
}
`,
description: "Parent selector in mixin"
},
{
code: `
.bar {
.parent {
color: blue;
& .context {
color: red;
}
}
}
`,
description: "Parent selector nested in more than one style rule"
},
{
code: `
.parent {
color: blue;
.context & {
color: red;
}
}
`,
description: "Selector ending in parent selector"
},
{
code: `
.parent {
color: blue;
.context & .b {
color: red;
}
}
`,
description: "Parent selector in the middle of complex selector"
},
{
code: `
.parent {
color: blue;
& .b, .context & {
color: red;
}
}
`,
description: "Complex selector, one ending in parent selector"
},
{
code: `
@mixin foo {
.parent {
color: blue;
& .context {
color: red;
}
}
}
`,
description: "Parent selector in mixin, nested, at the beginning"
},
{
code: `
@mixin foo {
.bar & {
color: red;
}
}
`,
description: "Parent selector in mixin, at the end"
},
{
code: `
@mixin foo {
.parent {
.bar, & {
color: red;
}
}
}
`,
description: "Complex selector in mixin, nested, no following class."
}
],

reject: [
{
code: `
@mixin foo {
.bar {
color: blue;
.baz & {
color: red;
}
}
}
`,
description: "Parent selector nested in selector within a mixin",
message:
"Unexpected nested parent selector in @mixin rule. (scss/at-mixin-no-risky-nesting-selector)",
column: 11,
endColumn: 12,
endLine: 7,
line: 5
},
{
code: `
@mixin foo {
.bar {
color: blue;
& .qux, .baz & .quux{
color: red;
}
}
}
`,
description: "Parent selector nested in complex selector within mixin",
message:
"Unexpected nested parent selector in @mixin rule. (scss/at-mixin-no-risky-nesting-selector)",
column: 11,
endColumn: 12,
endLine: 7,
line: 5
},
{
code: `
@mixin foo {
.bar {
color: blue;
& .qux & {
color: red;
}
}
}
`,
description: "Parent selector nested in complex selector within mixin",
message:
"Unexpected nested parent selector in @mixin rule. (scss/at-mixin-no-risky-nesting-selector)",
column: 11,
endColumn: 12,
endLine: 7,
line: 5
}
]
});

0 comments on commit d06186d

Please sign in to comment.