Skip to content

Commit

Permalink
Add mixin-no-risky-parent-selectors rule.
Browse files Browse the repository at this point in the history
  • Loading branch information
pamelalozano16 committed May 2, 2024
1 parent 26c105c commit 5b83763
Show file tree
Hide file tree
Showing 5 changed files with 419 additions and 2 deletions.
Expand Up @@ -83,8 +83,7 @@ testRule({
line: 2,
column: 20,
message: messages.rejected("scssy"),
description:
"One file, ext not from an allowed list, space at the end."
description: "One file, ext not from an allowed list, space at the end."
},
{
code: `
Expand Down
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 5b83763

Please sign in to comment.