Fixes #989 - edge case in removing unused at-rules.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 5 Mar 2018 12:52:35 +0000 (13:52 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 5 Mar 2018 18:36:00 +0000 (19:36 +0100)
When a value has `!important` in it then it should be stripped bare
before matching to the list of at-rules.

History.md
lib/optimizer/level-2/remove-unused-at-rules.js
test/optimizer/level-2/remove-unused-at-rules-test.js

index a847168..8e0cf46 100644 (file)
@@ -10,6 +10,7 @@
 ==================
 
 * Fixed issue [#988](https://github.com/jakubpawlowicz/clean-css/issues/988) - edge case in dropping default animation-duration.
+* Fixed issue [#989](https://github.com/jakubpawlowicz/clean-css/issues/989) - edge case in removing unused at rules.
 
 [4.1.9 / 2017-09-19](https://github.com/jakubpawlowicz/clean-css/compare/v4.1.8...v4.1.9)
 ==================
index 71d916d..23d4d7c 100644 (file)
@@ -8,10 +8,13 @@ var Token = require('../../tokenizer/token');
 var animationNameRegex = /^(\-moz\-|\-o\-|\-webkit\-)?animation-name$/;
 var animationRegex = /^(\-moz\-|\-o\-|\-webkit\-)?animation$/;
 var keyframeRegex = /^@(\-moz\-|\-o\-|\-webkit\-)?keyframes /;
+var importantRegex = /\s*!important$/;
 var optionalMatchingQuotesRegex = /^(['"]?)(.*)\1$/;
 
-function removeQuotes(value) {
-  return value.replace(optionalMatchingQuotesRegex, '$2');
+function normalize(value) {
+  return value
+    .replace(optionalMatchingQuotesRegex, '$2')
+    .replace(importantRegex, '');
 }
 
 function removeUnusedAtRules(tokens, context) {
@@ -112,7 +115,7 @@ function matchFontFace(token, atRules) {
       property = token[2][i];
 
       if (property[1][1] == 'font-family') {
-        match = removeQuotes(property[2][1].toLowerCase());
+        match = normalize(property[2][1].toLowerCase());
         atRules[match] = atRules[match] || [];
         atRules[match].push(token);
         break;
@@ -139,7 +142,7 @@ function markFontFacesAsUsed(atRules) {
         component = wrappedProperty.components[6];
 
         for (j = 0, m = component.value.length; j < m; j++) {
-          normalizedMatch = removeQuotes(component.value[j][1].toLowerCase());
+          normalizedMatch = normalize(component.value[j][1].toLowerCase());
 
           if (normalizedMatch in atRules) {
             delete atRules[normalizedMatch];
@@ -151,7 +154,7 @@ function markFontFacesAsUsed(atRules) {
 
       if (property[1][1] == 'font-family') {
         for (j = 2, m = property.length; j < m; j++) {
-          normalizedMatch = removeQuotes(property[j][1].toLowerCase());
+          normalizedMatch = normalize(property[j][1].toLowerCase());
 
           if (normalizedMatch in atRules) {
             delete atRules[normalizedMatch];
index 3a5a270..04b41f0 100644 (file)
@@ -80,6 +80,10 @@ vows.describe('remove unused at rules')
         '@font-face{font-family:test}.block{font:16px test!important}',
         '@font-face{font-family:test}.block{font:16px test!important}'
       ],
+      'one used as font-family with !important': [
+        '@font-face{font-family:test}.block{font-family:test!important}',
+        '@font-face{font-family:test}.block{font-family:test!important}'
+      ],
       'one used declaration in another @font-face': [
         '@font-face{font-family:test;font-weight:normal}@font-face{font-family:test;font-weight:bold}',
         ''