Skip to content

Commit

Permalink
Add declaration-block-no-duplicate-custom-properties (#5125)
Browse files Browse the repository at this point in the history
* feat(rules): add new rule declaration-block-no-duplicate-custom-properties

* fix(docs): fix description for general readme

* refactor: resolve PR comments by jeddy3

* refactor: resolve PR comments by vankop
  • Loading branch information
voskresla committed Feb 6, 2021
1 parent ae0ad14 commit a4911aa
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/user-guide/rules/list.md
Expand Up @@ -41,6 +41,7 @@ Grouped first by the following categories and then by the [_thing_](http://apps.

### Declaration block

- [`declaration-block-no-duplicate-custom-properties`](../../../lib/rules/declaration-block-no-duplicate-custom-properties/README.md): Disallow duplicate custom properties within declaration blocks.
- [`declaration-block-no-duplicate-properties`](../../../lib/rules/declaration-block-no-duplicate-properties/README.md): Disallow duplicate properties within declaration blocks.
- [`declaration-block-no-shorthand-property-overrides`](../../../lib/rules/declaration-block-no-shorthand-property-overrides/README.md): Disallow shorthand properties that override related longhand properties.

Expand Down
@@ -0,0 +1,40 @@
# declaration-block-no-duplicate-custom-properties

Disallow duplicate custom properties within declaration blocks.

<!-- prettier-ignore -->
```css
a { --custom-property: pink; --custom-property: orange; }
/** ↑ ↑
* These duplicated custom properties */
```

This rule is case-sensitive.

## Options

### `true`

The following patterns are considered violations:

<!-- prettier-ignore -->
```css
a { --custom-property: pink; --custom-property: orange; }
```

<!-- prettier-ignore -->
```css
a { --custom-property: pink; background: orange; --custom-property: orange }
```

The following patterns are _not_ considered violations:

<!-- prettier-ignore -->
```css
a { --custom-property: pink; }
```

<!-- prettier-ignore -->
```css
a { --custom-property: pink; --cUstOm-prOpErtY: orange; }
```
@@ -0,0 +1,165 @@
'use strict';

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

testRule({
ruleName,
config: [true],

accept: [
{
code: 'a { --custom-property: 1 }',
},
{
code: 'a { --custom-property: 1; --cUstOm-prOpErtY: 1 }',
},
{
code: 'a { --custom-property: 1; color: pink; --cUstOm-prOpErtY: 1 }',
},
{
code: 'a { color: var(--custom-property, --custom-property) }',
},
{
code: 'a { --custom-property: pink; @media { --custom-property: orange; } }',
description: 'nested',
},
{
code:
'a { --custom-property: pink; @media { --custom-property: orange; &::before { --custom-property: black; } } }',
description: 'double nested',
},
{
code:
'a { --custom-property: pink; { &:hover { --custom-property: orange; --cUstOm-prOpErtY: black; } } }',
description: 'spec nested',
},
{
code:
'a { --cUstOm-prOpErtY: pink; { &:hover { --custom-property: orange; --cUstOm-prOpErtY: black; } } }',
description: 'spec nested',
},
],

reject: [
{
code: 'a { --custom-property: 1; --custom-property: 2; }',
message: messages.rejected('--custom-property'),
},
{
code: 'a { --custom-property: 1; color: pink; --custom-property: 1; }',
message: messages.rejected('--custom-property'),
},
{
code: 'a { --custom-property: 1; --cUstOm-prOpErtY: 1; color: pink; --cUstOm-prOpErtY: 1; }',
message: messages.rejected('--cUstOm-prOpErtY'),
},
{
code:
'a { --custom-property: pink; { &:hover { --custom-property: orange; --custom-property: black; } } }',
description: 'spec nested',
message: messages.rejected('--custom-property'),
},
{
code:
'a { --custom-property: pink; @media { --custom-property: orange; --custom-property: black; } }',
description: 'nested',
message: messages.rejected('--custom-property'),
},
{
code:
'@media { --custom-property: orange; .foo { --custom-property: black; --custom-property: white; } }',
description: 'nested',
message: messages.rejected('--custom-property'),
},
{
code:
'a { --custom-property: pink; @media { --custom-property: orange; &::before { --custom-property: black; --custom-property: white; } } }',
description: 'double nested',
message: messages.rejected('--custom-property'),
},
{
code:
'a { --custom-property: pink; @media { --custom-property: orange; .foo { --custom-property: black; --custom-property: white; } } }',
description: 'double nested again',
message: messages.rejected('--custom-property'),
},
],
});

testRule({
ruleName,
config: [true],
skipBasicChecks: true,
syntax: 'html',

accept: [
{
code: '<style>a { --custom-property: pink; }</style>',
},
{
code: '<a style="--custom-property: pink;"></a>',
},
{
code:
'<style>a { --custom-property: pink; }</style><style>a { --custom-property: pink; }</style>',
},
{
code: '<a style="--custom-property: pink;"></a><a style="--custom-property: pink;"></a>',
},
{
code:
'<a style="--custom-property: pink; --cUstOm-prOpErtY: pink;"></a><a style="--custom-property: pink;"></a>',
},
],

reject: [
{
code: '<a style="--custom-property: pink; --custom-property: orange"></a>',
message: messages.rejected('--custom-property'),
},
{
code:
'<style>p { color: pink; --custom-property: orange; --custom-property: white; }</style>',
message: messages.rejected('--custom-property'),
},
{
code: '<a style="--custom-property: orange; color: pink; --custom-property: white;"></a>',
message: messages.rejected('--custom-property'),
},
{
code:
'<a style="--cUstOm-prOpErtY: orange; color: pink; --custom-property: white; --cUstOm-prOpErtY: black;"></a>',
message: messages.rejected('--cUstOm-prOpErtY'),
},
],
});

testRule({
ruleName,
config: [true],
skipBasicChecks: true,
syntax: 'css-in-js',

accept: [
{
code:
"import styled from 'react-emotion'\nexport default styled.div` --custom-property: pink; `;",
},
{
code:
"import styled from 'react-emotion'\nexport default styled.div` --custom-property: pink; --cUstOm-prOpErtY: pink; `;",
},
],
reject: [
{
code:
"import styled from 'styled-components';\nexport default styled.div` --custom-property: pink; --custom-property: orange; `;",
message: messages.rejected('--custom-property'),
},
{
code:
"import styled from 'react-emotion'\nexport default styled.div` --custom-property: pink; --custom-property: orange; `;",
message: messages.rejected('--custom-property'),
},
],
});
@@ -0,0 +1,61 @@
// @ts-nocheck

'use strict';

const eachDeclarationBlock = require('../../utils/eachDeclarationBlock');
const isCustomProperty = require('../../utils/isCustomProperty');
const isStandardSyntaxProperty = require('../../utils/isStandardSyntaxProperty');
const report = require('../../utils/report');
const ruleMessages = require('../../utils/ruleMessages');
const validateOptions = require('../../utils/validateOptions');

const ruleName = 'declaration-block-no-duplicate-custom-properties';

const messages = ruleMessages(ruleName, {
rejected: (property) => `Unexpected duplicate "${property}"`,
});

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

if (!validOptions) {
return;
}

eachDeclarationBlock(root, (eachDecl) => {
const decls = new Set();

eachDecl((decl) => {
const prop = decl.prop;

if (!isStandardSyntaxProperty(prop)) {
return;
}

if (!isCustomProperty(prop)) {
return;
}

const isDuplicate = decls.has(prop);

if (isDuplicate) {
report({
message: messages.rejected(prop),
node: decl,
result,
ruleName,
});

return;
}

decls.add(prop);
});
});
};
}

rule.ruleName = ruleName;
rule.messages = messages;
module.exports = rule;
3 changes: 3 additions & 0 deletions lib/rules/index.js
Expand Up @@ -72,6 +72,9 @@ const rules = {
'custom-property-pattern': importLazy(() => require('./custom-property-pattern'))(),
'declaration-bang-space-after': importLazy(() => require('./declaration-bang-space-after'))(),
'declaration-bang-space-before': importLazy(() => require('./declaration-bang-space-before'))(),
'declaration-block-no-duplicate-custom-properties': importLazy(() =>
require('./declaration-block-no-duplicate-custom-properties'),
)(),
'declaration-block-no-duplicate-properties': importLazy(() =>
require('./declaration-block-no-duplicate-properties'),
)(),
Expand Down

0 comments on commit a4911aa

Please sign in to comment.