Skip to content

Commit

Permalink
Merge pull request #326 from rambleraptor/unquote
Browse files Browse the repository at this point in the history
Lint rule to check for unquote() receiving an unquoted string
  • Loading branch information
kristerkari committed May 31, 2019
2 parents 8cfa902 + d8ccd2a commit 4d6b887
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/rules/function-unquote-no-unquoted-strings-inside/README.md
@@ -0,0 +1,46 @@
# function-unquote-no-unquoted-strings-inside

Disallow unquoted strings inside the [unquote function](https://sass-lang.com/documentation/functions/string#unquote)

```scss
p {
font-family: unquote(Helvetica);
/** ↑ ↑
* This function call is unnecessary
*/
}
```

## Options

### `true`

The following patterns are considered violations:

```scss
a {
font-family: unquote(Helvetica);
}
```

```scss
$font: Helvetica;
p {
font-family: quote($font);
}
```

The following patterns are _not_ considered violations:

```scss
a {
color: unquote("blue");
}
```

```scss
$font: "Helvetica";
p {
font-family: unquote($font);
}
```
@@ -0,0 +1,64 @@
import rule, { ruleName, messages } from "..";

// always-intermediate
testRule(rule, {
ruleName,
config: [true],
syntax: "scss",
fix: true,

accept: [
{
code: `
p {
font-family: unquote("Helvetica");
}
`,
description: "accepts strings with quotes"
},
{
code: `
$font: "Helvetica";
p {
font-family: unquote($font);
}
`,
description: "accepts variables representing strings that are quoted."
}
],

reject: [
{
code: `
p {
font-family: unquote(Helvetica);
}
`,
description: "does not accept strings without quotes",
message: messages.rejected,
line: 3,
fixed: `
p {
font-family: Helvetica;
}
`
},
{
code: `
$font: Helvetica;
p {
font-family: unquote($font);
}
`,
description:
"does not accept variables representing strings that are quoted.",
line: 4,
fixed: `
$font: Helvetica;
p {
font-family: $font;
}
`
}
]
});
76 changes: 76 additions & 0 deletions src/rules/function-unquote-no-unquoted-strings-inside/index.js
@@ -0,0 +1,76 @@
import { utils } from "stylelint";
import { namespace, isNativeCssFunction } from "../../utils";
import valueParser from "postcss-value-parser";

export const ruleName = namespace(
"function-unquote-no-unquoted-strings-inside"
);

export const messages = utils.ruleMessages(ruleName, {
rejected: "Unquote function used with an already-unquoted string"
});

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

if (!validOptions) {
return;
}

// Setup variable naming.
const vars = {};

root.walkDecls(decl => {
if (decl.prop[0] !== "$") {
return;
}

valueParser(decl.value).walk(node => {
vars[decl.prop] = node.type;
});
});

root.walkDecls(decl => {
valueParser(decl.value).walk(node => {
// Verify that we're only looking at functions.
if (
node.type !== "function" ||
isNativeCssFunction(node.value) ||
node.value === ""
) {
return;
}

// Verify we're only looking at quote() calls.
if (node.value !== "unquote") {
return;
}

// Report error if first character is a quote.
// postcss-value-parser represents quoted strings as type 'string' (as opposed to word)
if (
(!node.nodes[0].quote && node.nodes[0].value[0] !== "$") ||
vars[node.nodes[0].value] === "word"
) {
if (context.fix) {
const contents = /unquote\((.*)\)/.exec(decl.value);

decl.value = contents[1];
} else {
utils.report({
message: messages.rejected,
node: decl,
result,
ruleName
});
}
}
});
});
};
}

export default rule;
2 changes: 2 additions & 0 deletions src/rules/index.js
Expand Up @@ -30,6 +30,7 @@ import doubleSlashCommentEmptyLineBefore from "./double-slash-comment-empty-line
import doubleSlashCommentInline from "./double-slash-comment-inline";
import doubleSlashCommentWhitespaceInside from "./double-slash-comment-whitespace-inside";
import functionNoQuotedStrings from "./function-quote-no-quoted-strings-inside";
import functionNoUnquotedStrings from "./function-unquote-no-unquoted-strings-inside";
import mediaFeatureValueDollarVariable from "./media-feature-value-dollar-variable";
import noDollarVariables from "./no-dollar-variables";
import noDuplicateDollarVariables from "./no-duplicate-dollar-variables";
Expand Down Expand Up @@ -74,6 +75,7 @@ export default {
"double-slash-comment-inline": doubleSlashCommentInline,
"double-slash-comment-whitespace-inside": doubleSlashCommentWhitespaceInside,
"function-quote-no-quoted-strings-inside": functionNoQuotedStrings,
"function-unquote-no-unquoted-strings-inside": functionNoUnquotedStrings,
"media-feature-value-dollar-variable": mediaFeatureValueDollarVariable,
"no-dollar-variables": noDollarVariables,
"no-duplicate-dollar-variables": noDuplicateDollarVariables,
Expand Down

0 comments on commit 4d6b887

Please sign in to comment.