Skip to content

Commit

Permalink
Add mixins-no-risky-parent-selectors rule.
Browse files Browse the repository at this point in the history
  • Loading branch information
pamelalozano16 committed Apr 2, 2024
1 parent 353e633 commit 0e8b7b0
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const rules = {
"function-unquote-no-unquoted-strings-inside": require("./function-unquote-no-unquoted-strings-inside"),
"map-keys-quotes": require("./map-keys-quotes"),
"media-feature-value-dollar-variable": require("./media-feature-value-dollar-variable"),
"mixins-no-risky-parent-selectors": require("./mixins-no-risky-parent-selectors"),
"no-dollar-variables": require("./no-dollar-variables"),
"no-duplicate-dollar-variables": require("./no-duplicate-dollar-variables"),
"no-duplicate-mixins": require("./no-duplicate-mixins"),
Expand Down
44 changes: 44 additions & 0 deletions src/rules/mixins-no-risky-parent-selectors/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# at-use-no-redundant-alias

Disallow redundant namespace aliases.

```scss
@use "foo" as foo;
/** ↑
* Disallow this */
```

By default, the [module's namespace](https://sass-lang.com/documentation/at-rules/use/#loading-members)
is the last component of the module’s URL.

## Options

### `true`

The following patterns are considered warnings:

```scss
@use "foo" as foo;
```

```scss
@use "sass:math" as math;
```

```scss
@use "src/corners" as corners;
```

The following patterns are _not_ considered warnings:

```scss
@use "foo" as bar;
```

```scss
@use "sass:math";
```

```scss
@use "src/corners" as c;
```
130 changes: 130 additions & 0 deletions src/rules/mixins-no-risky-parent-selectors/__tests__/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"use strict";

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

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

accept: [
{
code: `
.parent {
color: blue;
& .b, &.context {
color: red;
}
}
`,
description: "Default namespace"
},
{
code: `
.parent {
color: blue;
& .b & .context {
color: red;
}
}
`,
description: "Default namespace"
}
],

reject: [
{
code: `
@mixin foo {
.parent {
color: blue;
&.context {
color: red;
}
}
}
`,
description: "Default namespace",
message:
"Unexpected redundant namespace. (scss/mixins-no-risky-parent-selectors)"
},
{
code: `
.bar {
.parent {
color: blue;
&.context {
color: red;
}
}
}
`,
description: "Default namespace",
message:
"Unexpected redundant namespace. (scss/mixins-no-risky-parent-selectors)"
},
{
code: `
.parent {
color: blue;
.context & {
color: red;
}
}
`,
description: "Default namespace",
message:
"Unexpected redundant namespace. (scss/mixins-no-risky-parent-selectors)"
},
{
code: `
.parent {
color: blue;
& .b, .context & {
color: red;
}
}
`,
description: "Default namespace",
message:
"Unexpected redundant namespace. (scss/mixins-no-risky-parent-selectors)"
},
{
code: `
@mixin foo {
color: blue;
@at-root & {
color: red;
}
}
`,
description: "Default namespace",
message:
"Unexpected redundant namespace. (scss/mixins-no-risky-parent-selectors)"
},
{
code: `
@mixin foo {
color: blue;
@at-root .b {
& {
color: red;
}
}
}
`,
description: "Default namespace",
message:
"Unexpected redundant namespace. (scss/mixins-no-risky-parent-selectors)"
}
]
});
80 changes: 80 additions & 0 deletions src/rules/mixins-no-risky-parent-selectors/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"use strict";

const { utils } = require("stylelint");
const namespace = require("../../utils/namespace");
const ruleUrl = require("../../utils/ruleUrl");

const ruleName = namespace("mixins-no-risky-parent-selectors");

const messages = utils.ruleMessages(ruleName, {
rejected: `Unexpected redundant namespace.`
});

const meta = {
url: ruleUrl(ruleName)
};

function isWithinMixinOrAtRoot(node) {
let parent = node.parent;
while (parent) {
if (
parent.type === "atrule" &&
(parent.name === "mixin" || parent.name === "at-root")
) {
return true;
}
parent = parent.parent;
}
return false;
}

function hasNestedParentSelector(selectors) {
return selectors
.split(",")
.some(
selector =>
selector.includes("&") && !selector.replace(" ", "").startsWith("&")
);
}

function rule(actual) {
return (root, result) => {
const validOptions = utils.validateOptions(result, ruleName, { actual });

if (!validOptions) {
return;
}

root.walkAtRules("at-root", node => {
if (node.params?.includes("&")) {
utils.report({
message: messages.rejected,
node,
result,
ruleName
});
}
});
root.walkRules(node => {
if (
node.selector?.includes("&") &&
(isWithinMixinOrAtRoot(node) ||
hasNestedParentSelector(node.selector) ||
node.parent.parent.selector)
) {
utils.report({
message: messages.rejected,
node,
result,
ruleName
});
}
});
};
}

rule.ruleName = ruleName;
rule.messages = messages;
rule.meta = meta;

module.exports = rule;

0 comments on commit 0e8b7b0

Please sign in to comment.