Fixes #947 - selector based filtering.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sat, 17 Jun 2017 06:37:45 +0000 (08:37 +0200)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Sat, 17 Jun 2017 06:37:45 +0000 (08:37 +0200)
Why:

* Sometimes it may be useful to rewrite or drop certain properties based
  on selector value.

History.md
README.md
lib/optimizer/level-1/optimize.js
test/module-test.js

index c6eee7d..f095351 100644 (file)
@@ -4,6 +4,7 @@
 * Adds `process` method for compatibility with optimize-css-assets-webpack-plugin.
 * Fixed issue [#861](https://github.com/jakubpawlowicz/clean-css/issues/861) - new `transition` property optimizer.
 * Fixed issue [#895](https://github.com/jakubpawlowicz/clean-css/issues/895) - ignoring specific styles.
+* Fixed issue [#947](https://github.com/jakubpawlowicz/clean-css/issues/947) - selector based filtering.
 
 [4.1.4 / 2017-06-14](https://github.com/jakubpawlowicz/clean-css/compare/v4.1.3...v4.1.4)
 ==================
index 1c5b8f1..7fa0712 100644 (file)
--- a/README.md
+++ b/README.md
@@ -121,6 +121,7 @@ clean-css 4.2 will introduce the following changes / features:
 * Adds `process` method for compatibility with optimize-css-assets-webpack-plugin;
 * new `transition` property optimizer;
 * preserves any CSS content between `/* clean-css ignore:start */` and `/* clean-css ignore:end */` comments;
+* allows filtering based on selector in `transform` callback, see [example](#how-to-apply-arbitrary-transformations-to-css-properties);
 
 ## Constructor options
 
@@ -533,7 +534,7 @@ var source = '.block{background-image:url(/path/to/image.png)}';
 var output = new CleanCSS({
   level: {
     1: {
-      transform: function (propertyName, propertyValue) {
+      transform: function (propertyName, propertyValue, selector /* `selector` available since 4.2.0-pre */) {
         if (propertyName == 'background-image' && propertyValue.indexOf('/path/to') > -1) {
           return propertyValue.replace('/path/to', '../valid/path/to');
         }
index 5a6da47..56f2f60 100644 (file)
@@ -19,6 +19,8 @@ var Marker = require('../../tokenizer/marker');
 var formatPosition = require('../../utils/format-position');
 var split = require('../../utils/split');
 
+var serializeRules = require('../../writer/one-time').rules;
+
 var IgnoreProperty = 'ignore-property';
 
 var CHARSET_TOKEN = '@charset';
@@ -344,8 +346,9 @@ function removeUrlQuotes(value) {
     value;
 }
 
-function transformValue(propertyName, propertyValue, transformCallback) {
-  var transformedValue = transformCallback(propertyName, propertyValue);
+function transformValue(propertyName, propertyValue, rule, transformCallback) {
+  var selector = serializeRules(rule);
+  var transformedValue = transformCallback(propertyName, propertyValue, selector);
 
   if (transformedValue === undefined) {
     return propertyValue;
@@ -358,7 +361,7 @@ function transformValue(propertyName, propertyValue, transformCallback) {
 
 //
 
-function optimizeBody(properties, context) {
+function optimizeBody(rule, properties, context) {
   var options = context.options;
   var levelOptions = options.level[OptimizationLevel.One];
   var property, name, type, value;
@@ -403,7 +406,7 @@ function optimizeBody(properties, context) {
     }
 
     if (property.block) {
-      optimizeBody(property.value[0][1], context);
+      optimizeBody(rule, property.value[0][1], context);
       continue;
     }
 
@@ -462,7 +465,7 @@ function optimizeBody(properties, context) {
         }
       }
 
-      value = transformValue(name, value, levelOptions.transform);
+      value = transformValue(name, value, rule, levelOptions.transform);
 
       if (value === IgnoreProperty) {
         property.unused = true;
@@ -635,7 +638,7 @@ function level1Optimize(tokens, context) {
         mayHaveCharset = true;
         break;
       case Token.AT_RULE_BLOCK:
-        optimizeBody(token[2], context);
+        optimizeBody(token[1], token[2], context);
         afterRules = true;
         break;
       case Token.NESTED_BLOCK:
@@ -649,7 +652,7 @@ function level1Optimize(tokens, context) {
       case Token.RULE:
         token[1] = levelOptions.tidySelectors ? tidyRules(token[1], !ie7Hack, adjacentSpace, format, context.warnings) : token[1];
         token[1] = token[1].length > 1 ? sortSelectors(token[1], levelOptions.selectorsSortingMethod) : token[1];
-        optimizeBody(token[2], context);
+        optimizeBody(token[1], token[2], context);
         afterRules = true;
         break;
     }
index d0e423a..7d38b80 100644 (file)
@@ -447,6 +447,24 @@ vows.describe('module tests').addBatch({
         assert.equal(output.styles, '.block{border-image:url(image.png)}');
       }
     },
+    'allows dropping properties based on selector': {
+      'topic': function () {
+        return new CleanCSS({
+          level: {
+            1: {
+              transform: function (propertyName, propertyValue, selector) {
+                if (propertyName.indexOf('-o-') === 0 && selector == '.block-2') {
+                  return false;
+                }
+              }
+            }
+          }
+        }).minify('.block-1{-o-border-radius:2px}.block-2{-o-border-radius:5px;width:1rem}');
+      },
+      'gives right output': function (error, output) {
+        assert.equal(output.styles, '.block-1{-o-border-radius:2px}.block-2{width:1rem}');
+      }
+    },
     'combined with level 2 optimization': {
       'topic': function () {
         return new CleanCSS({