Skip to content

Commit

Permalink
Add function-no-interpolation rule
Browse files Browse the repository at this point in the history
  • Loading branch information
pamelalozano16 committed Aug 31, 2023
1 parent 9aa4449 commit 6e6db13
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,9 @@
# 5.2.0

- Added: `function-no-interpolation` rule to forbid interpolation in calc functions (#539).

**Full Changelog**: https://github.com/stylelint-scss/stylelint-scss/compare/v5.1.0...v5.2.0

# 5.1.0

- Added: `function-disallowed-list` rule support to ban specific built-in functions (#422, #844).
Expand Down
5 changes: 2 additions & 3 deletions README.md
Expand Up @@ -30,9 +30,7 @@ Create the `.stylelintrc.json` config file (or open the existing one), add `styl

```jsonc
{
"plugins": [
"stylelint-scss"
],
"plugins": ["stylelint-scss"],
"rules": {
// recommended rules
"at-rule-no-unknown": null,
Expand Down Expand Up @@ -145,6 +143,7 @@ Please also see the [example configs](./docs/examples/) for special cases.
- [`function-color-relative`](./src/rules/function-color-relative/README.md): Encourage the use of the [scale-color](https://sass-lang.com/documentation/modules/color#scale-color) function over regular color functions.
- [`function-disallowed-list`](./src/rules/function-disallowed-list/README.md): Specify a list of disallowed functions. Should be used **instead of** Stylelint's [function-disallowed-list](https://stylelint.io/user-guide/rules/function-disallowed-list).
- [`function-no-unknown`](./src/rules/function-no-unknown/README.md): Disallow unknown functions. Should be used **instead of** Stylelint's [function-no-unknown](https://stylelint.io/user-guide/rules/function-no-unknown).
- [`function-no-interpolation`](./src/rules/function-no-interpolation/README.md): Forbids interpolation in `calc()`, `clamp()`, `min()`, and `max()` functions.
- [`function-quote-no-quoted-strings-inside`](./src/rules/function-quote-no-quoted-strings-inside/README.md): Disallow quoted strings inside the [quote function](https://sass-lang.com/documentation/modules/string#quote) (Autofixable).
- [`function-unquote-no-unquoted-strings-inside`](./src/rules/function-unquote-no-unquoted-strings-inside/README.md): Disallow unquoted strings inside the [unquote function](https://sass-lang.com/documentation/modules/string#unquote) (Autofixable).

Expand Down
64 changes: 64 additions & 0 deletions src/rules/function-no-interpolation/README.md
@@ -0,0 +1,64 @@
# function-no-interpolation

Since the release of [first-class `calc()`](https://sass-lang.com/documentation/values/calculations/),
calculation functions `calc()`, `clamp()`, `min()`, and `max()` accept variables
and function calls as arguments.

This rule forbids interpolation in `calc()`, `clamp()`, `min()`, and `max()`
functions to avoid extra verbose or even invalid CSS.

<!-- prettier-ignore -->
```scss
.a { .b: calc(#{$c} + 1); }
/** ↑
* This argument */
```

## Options

### `true`

The following patterns are considered warnings:

<!-- prettier-ignore -->
```scss
$c: 1;
.a { .b: calc(#{$c + 1}); }
```

<!-- prettier-ignore -->
```scss
$c: 1;
.a { .b: calc(max(#{$c})); }
```

<!-- prettier-ignore -->
```scss
$c: 1;
.a { .b: min(#{$c}); }
```

<!-- prettier-ignore -->
```scss
$c: 1;
.a { .b: clamp(#{$c} + 2px); }
```

The following patterns are _not_ considered warnings:

<!-- prettier-ignore -->
```scss
.a { .b: calc(1 + 1); }
```

<!-- prettier-ignore -->
```scss
$c: 1;
.a { .b: abc(#{$c} + 1px); }
```

<!-- prettier-ignore -->
```scss
$c: 1;
.a { .b: calc(abc(#{$c})); }
```
82 changes: 82 additions & 0 deletions src/rules/function-no-interpolation/__tests__/index.js
@@ -0,0 +1,82 @@
"use strict";

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

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

accept: [
{
code: `.a { .b: calc(1 + 1); }`,
description: "`calc` function, no interpolation"
},
{
code: `
$c: 1;
.a { .b: abc(#{$c} + 1px); }
`,
description: "Allowed function with interpolation"
},
{
code: `
$c: 1;
.a { .b: calc(abc(#{$c})); }
`,
description: "Allowed function with interpolation nested in `calc`"
}
],
reject: [
{
code: `
$c: 1;
.a { .b: calc(#{$c} + 1); }
`,
line: 3,
column: 12,
message: messages.rejected("calc"),
description: "`calc` function one argument interpolated"
},
{
code: `
$c: 1;
.a { .b: calc(#{$c + 1}); }
`,
line: 3,
column: 12,
message: messages.rejected("calc"),
description: "`calc` function all arguments interpolated"
},
{
code: `
$c: 1;
.a { .b: calc(max(#{$c})); }
`,
line: 3,
column: 12,
message: messages.rejected("max"),
description: "`max` function with interpolation"
},
{
code: `
$c: 1;
.a { .b: min(#{$c} + 1px); }
`,
line: 3,
column: 12,
message: messages.rejected("min"),
description: "`max` function with interpolation"
},
{
code: `
$c: 1;
.a { .b: clamp(#{$c} + #{$d}); }
`,
line: 3,
column: 12,
message: messages.rejected("clamp"),
description: "`clamp` function with interpolation"
}
]
});
56 changes: 56 additions & 0 deletions src/rules/function-no-interpolation/index.js
@@ -0,0 +1,56 @@
"use strict";

const { utils } = require("stylelint");
const namespace = require("../../utils/namespace");
const ruleUrl = require("../../utils/ruleUrl");
const valueParser = require("postcss-value-parser");

const ruleName = namespace("function-no-interpolation");

const messages = utils.ruleMessages(ruleName, {
rejected: func => `Unexpected interpolation in "${func}".`
});

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

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

if (!validOptions) {
return;
}

const calculationFunctions = ["calc", "max", "min", "clamp"];

root.walkDecls(decl => {
valueParser(decl.value).walk(node => {
if (node.type !== "function" || node.value === "") {
return;
}
if (
calculationFunctions.includes(node.value) &&
node.nodes.some(
args => args.type === "word" && /^#{.*|\s*}/.test(args.value)
)
) {
utils.report({
message: messages.rejected(node.value),
node: decl,
word: decl.name,
result,
ruleName
});
}
});
});
};
}

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

module.exports = rule;
1 change: 1 addition & 0 deletions src/rules/index.js
Expand Up @@ -43,6 +43,7 @@ const rules = {
"double-slash-comment-inline": require("./double-slash-comment-inline"),
"double-slash-comment-whitespace-inside": require("./double-slash-comment-whitespace-inside"),
"function-disallowed-list": require("./function-disallowed-list"),
"function-no-interpolation": require("./function-no-interpolation"),
"function-color-relative": require("./function-color-relative"),
"function-no-unknown": require("./function-no-unknown"),
"function-quote-no-quoted-strings-inside": require("./function-quote-no-quoted-strings-inside"),
Expand Down

0 comments on commit 6e6db13

Please sign in to comment.