diff --git a/.changeset/rude-hornets-begin.md b/.changeset/rude-hornets-begin.md new file mode 100644 index 0000000000..d1aaf43d77 --- /dev/null +++ b/.changeset/rude-hornets-begin.md @@ -0,0 +1,5 @@ +--- +"stylelint": patch +--- + +Fixed: `declaration-block-no-duplicate-properties` autofix for `!important` diff --git a/lib/rules/declaration-block-no-duplicate-properties/__tests__/index.js b/lib/rules/declaration-block-no-duplicate-properties/__tests__/index.js index 9049919421..d0fe44bb57 100644 --- a/lib/rules/declaration-block-no-duplicate-properties/__tests__/index.js +++ b/lib/rules/declaration-block-no-duplicate-properties/__tests__/index.js @@ -187,6 +187,24 @@ testRule({ endLine: 1, endColumn: 55, }, + { + code: 'a { color: red !important; color: blue; }', + fixed: 'a { color: red !important; }', + message: messages.rejected('color'), + line: 1, + column: 28, + endLine: 1, + endColumn: 33, + }, + { + code: 'a { color: red !important; color: blue !important; }', + fixed: 'a { color: blue !important; }', + message: messages.rejected('color'), + line: 1, + column: 28, + endLine: 1, + endColumn: 33, + }, ], }); @@ -231,6 +249,11 @@ testRule({ fixed: 'p { display: inline-block; font-weight: 400; font-size: 1rem; color: red; }', message: messages.rejected('font-size'), }, + { + code: 'p { font-size: 16px !important; font-weight: 400; font-size: 1rem; }', + fixed: 'p { font-size: 16px !important; font-weight: 400; }', + message: messages.rejected('font-size'), + }, ], }); @@ -252,6 +275,16 @@ testRule({ fixed: 'p { font-size: 16px; font-weight: 400; }', message: messages.rejected('font-size'), }, + { + code: 'p { font-size: 16px !important; font-weight: 400; font-size: 1rem; }', + fixed: 'p { font-size: 16px !important; font-weight: 400; }', + message: messages.rejected('font-size'), + }, + { + code: 'p { font-size: 16px; font-size: 16px !important; font-weight: 400; }', + fixed: 'p { font-size: 16px !important; font-weight: 400; }', + message: messages.rejected('font-size'), + }, ], }); @@ -291,6 +324,16 @@ testRule({ fixed: 'p { width: -moz-fit-content; }', message: messages.rejected('width'), }, + { + code: 'p { width: -moz-fit-content; width: -moz-fit-content !important; }', + fixed: 'p { width: -moz-fit-content !important; }', + message: messages.rejected('width'), + }, + { + code: 'p { width: 100% !important; width: -moz-fit-content; }', + fixed: 'p { width: 100% !important; }', + message: messages.rejected('width'), + }, ], }); @@ -309,6 +352,9 @@ testRule({ { code: 'p { color: pink; background: orange; color: orange }', }, + { + code: 'p { color: pink; color: orange !important; }', + }, ], reject: [ @@ -322,6 +368,11 @@ testRule({ fixed: 'p { color: pink; background: white; }', message: messages.rejected('background'), }, + { + code: 'p { background: orange; color: pink; background: white !important; }', + fixed: 'p { color: pink; background: white !important; }', + message: messages.rejected('background'), + }, ], }); diff --git a/lib/rules/declaration-block-no-duplicate-properties/index.js b/lib/rules/declaration-block-no-duplicate-properties/index.js index d81addb5ab..31a70524e0 100644 --- a/lib/rules/declaration-block-no-duplicate-properties/index.js +++ b/lib/rules/declaration-block-no-duplicate-properties/index.js @@ -66,6 +66,7 @@ const rule = (primary, secondaryOptions, context) => { const prop = decl.prop; const lowerProp = decl.prop.toLowerCase(); const value = decl.value; + const important = decl.important; if (!isStandardSyntaxProperty(prop)) { return; @@ -88,11 +89,19 @@ const rule = (primary, secondaryOptions, context) => { const indexDuplicate = decls.findIndex((d) => d.prop.toLowerCase() === lowerProp); if (indexDuplicate !== -1) { + const duplicateDecl = decls[indexDuplicate]; + const duplicateValue = duplicateDecl ? duplicateDecl.value : ''; + const duplicateImportant = duplicateDecl ? duplicateDecl.important : false; + if (ignoreDiffValues || ignorePrefixlessSameValues) { // fails if duplicates are not consecutive if (indexDuplicate !== decls.length - 1) { if (context.fix) { - removePreviousDuplicate(decls, lowerProp); + if (!important && duplicateImportant) { + decl.remove(); + } else { + removePreviousDuplicate(decls, lowerProp); + } return; } @@ -108,14 +117,15 @@ const rule = (primary, secondaryOptions, context) => { return; } - const duplicateDecl = decls[indexDuplicate]; - const duplicateValue = duplicateDecl ? duplicateDecl.value : ''; - if (ignorePrefixlessSameValues) { // fails if values of consecutive, unprefixed duplicates are equal if (vendor.unprefixed(value) !== vendor.unprefixed(duplicateValue)) { if (context.fix) { - removePreviousDuplicate(decls, lowerProp); + if (!important && duplicateImportant) { + decl.remove(); + } else { + removePreviousDuplicate(decls, lowerProp); + } return; } @@ -159,7 +169,11 @@ const rule = (primary, secondaryOptions, context) => { } if (context.fix) { - removePreviousDuplicate(decls, lowerProp); + if (!important && duplicateImportant) { + decl.remove(); + } else { + removePreviousDuplicate(decls, lowerProp); + } return; }