Skip to content

Commit

Permalink
Fix declaration-block-no-duplicate-properties false positives with …
Browse files Browse the repository at this point in the history
…option `consecutive-duplicates-with-different-syntaxes` (#6797)

Co-authored-by: Masafumi Koba <473530+ybiquitous@users.noreply.github.com>
  • Loading branch information
romainmenke and ybiquitous committed Apr 19, 2023
1 parent afe410a commit 28328a6
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/many-toes-smell.md
@@ -0,0 +1,5 @@
---
"stylelint": patch
---

Fixed: `declaration-block-no-duplicate-properties` false positives with option `ignore: ["consecutive-duplicates-with-different-syntaxes"]`
Expand Up @@ -302,16 +302,29 @@ testRule({
{ code: 'p { margin: 10dvw 10dvw; margin: 10vw 10vw; padding: 0; }' },
{ code: 'p { margin: 10dvh 10dvw 10dvh; margin: 10vw 10vw; padding: 0; }' },
{ code: 'p { width: 100%; width: fit-content; }' },
{ code: 'p { width: min-content; width: max-content; }' },
{ code: 'p { width: calc(10px + 2px); width: calc(10px + 2rem); }' },
{ code: 'p { width: calc(10px + 2px); width: calc(10rem + 2rem); }' },
{ code: 'p { width: min(10px, 11px); width: max(10px, 11px); }' },
{ code: 'p { width: calc((10px + 2px)); width: calc((10rem + 2rem)); }' },
{ code: 'p { width: calc((10px + 2px) + 10px); width: calc((10rem + 2rem) + 10px); }' },
{ code: 'p { width: $a; width: calc(1 + $a); }', description: 'using SCSS variables' },
{ code: 'p { width: _$a; width: _$a2; }', description: 'using invalid value' },
{ code: 'p { width: env(foo); width: env(--bar); }' },
{ code: 'p { width: env(--foo); width: env(bar); }' },
],

reject: [
{
code: 'p { width: 100vw ; width: 100vw; }',
fixed: 'p { width: 100vw; }',
message: messages.rejected('width'),
},
{
code: 'p { width: calc(100vw /* a comment */ + 10vw); width: calc(100vw + 10vw); }',
fixed: 'p { width: calc(100vw + 10vw); }',
message: messages.rejected('width'),
},
{
code: 'p { width: 100vw; height: 100vh; width: 100dvw; }',
fixed: 'p { height: 100vh; width: 100dvw; }',
Expand Down Expand Up @@ -342,11 +355,6 @@ testRule({
fixed: 'p { height: 100vh; width: 100dvw !important; }',
message: messages.rejected('width'),
},
{
code: 'p { width: min-content; width: max-content; height: 100%; }',
fixed: 'p { width: max-content; height: 100%; }',
message: messages.rejected('width'),
},
{
code: 'p { width: calc(10px + 4rem); width: calc(10px + 2rem); }',
fixed: 'p { width: calc(10px + 2rem); }',
Expand All @@ -357,6 +365,21 @@ testRule({
fixed: 'p { width: calc(10px + 2rem); }',
message: messages.rejected('width'),
},
{
code: 'p { width: var(--foo); width: var(--bar); }',
fixed: 'p { width: var(--bar); }',
message: messages.rejected('width'),
},
{
code: 'p { content: "foo"; content: "bar"; }',
fixed: 'p { content: "bar"; }',
message: messages.rejected('content'),
},
{
code: 'p { image: url(#foo); image: url(#bar); }',
fixed: 'p { image: url(#bar); }',
message: messages.rejected('image'),
},
],
});

Expand Down
42 changes: 28 additions & 14 deletions lib/rules/declaration-block-no-duplicate-properties/index.js
Expand Up @@ -30,6 +30,7 @@ const hasChildren = (node) => 'children' in node && node.children instanceof Lis

/** @type {(node1: CssNode[], node2: CssNode[]) => boolean} */
const isEqualValueNodes = (nodes1, nodes2) => {
// Different lengths indicate different syntaxes.
if (nodes1.length !== nodes2.length) {
return false;
}
Expand All @@ -38,34 +39,47 @@ const isEqualValueNodes = (nodes1, nodes2) => {
const node1 = nodes1[i];
const node2 = nodes2[i];

// Different types indicate different syntaxes.
if (typeof node1 === 'undefined' || typeof node2 === 'undefined' || node1.type !== node2.type) {
return false;
}

const node1Name = 'name' in node1 ? String(node1.name) : '';
const node2Name = 'name' in node2 ? String(node2.name) : '';

// Custom properties have unknown value syntaxes but are equal for CSS parsers.
if (
node1.type === 'Identifier' &&
isCustomProperty(node1Name) &&
node2.type === 'Identifier' &&
isCustomProperty(node2Name)
) {
continue;
}

// Different ident or function names indicate different syntaxes.
if (node1Name.toLowerCase() !== node2Name.toLowerCase()) {
return false;
}

const node1Unit = 'unit' in node1 ? node1.unit : '';
const node2Unit = 'unit' in node2 ? node2.unit : '';

// Different units indicate different syntaxes.
if (node1Unit !== node2Unit) {
return false;
}

const node1Children = hasChildren(node1) ? node1.children.toArray() : null;
const node2Children = hasChildren(node2) ? node2.children.toArray() : null;

if (Array.isArray(node1Children) && Array.isArray(node2Children)) {
const node1Name = 'name' in node1 ? String(node1.name) : '';
const node2Name = 'name' in node2 ? String(node2.name) : '';

if (node1Name.toLowerCase() !== node2Name.toLowerCase()) {
return false;
}

if (isEqualValueNodes(node1Children, node2Children)) {
continue;
} else {
return false;
}
}

const node1Unit = 'unit' in node1 ? node1.unit : '';
const node2Unit = 'unit' in node2 ? node2.unit : '';

if (node1Unit !== node2Unit) {
return false;
}
}

return true;
Expand Down

0 comments on commit 28328a6

Please sign in to comment.