Adds granular control over level 1 optimizations.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 9 Jan 2017 14:17:39 +0000 (15:17 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Tue, 10 Jan 2017 06:47:49 +0000 (07:47 +0100)
Why:

* So users can turn them on/off selectively;
* still keeping sane defaults for most users.

Note: moves `properties.fontWeight` compatibility flag to level 1
optimizations as that's not a compatibility flag, but rather a
user preference - see #756.

README.md
bin/cleancss
lib/optimizer/level-1/optimize.js
lib/options/optimization-level.js
lib/utils/compatibility.js
test/optimizer/level-1/optimize-test.js
test/options/optimization-level-test.js
test/utils/compatibility-test.js

index 5bc4cfa..0d6ccfa 100644 (file)
--- a/README.md
+++ b/README.md
@@ -115,13 +115,30 @@ Level 0 optimizations:
 cleancss -O0 one.css
 ```
 
-Level 1 optimizations:
+Level 1 optimizations (default):
 
 ```bash
 cleancss -O1 one.css
-cleancss -O1 roundingPrecision:4;specialComments:1 one.css
+cleancss -O1 keepQuotes:on;roundingPrecision:4;specialComments:1 one.css
+# `cleanupCharsets` controls `@charset` moving to the front of a stylesheet; defaults to `on`
+# `keepNegativePaddings` controls negative paddings removal; defaults to `off`
+# `keepQuotes` controls keeping quotes when unnecessary; defaults to `off`
+# `keepWhitespace` controls keeping unused whitespace; defaults to `off`
+# `normalizeUrls` controls URL normalzation; default to `on`
+# `optimizeBackground` controls `background` property optimizatons; defaults to `on`
+# `optimizeBorderRadius` controls `border-radius` property optimizatons; defaults to `on`
+# `optimizeFilter` controls `filter` property optimizatons; defaults to `on`
+# `optimizeFont controls `font` property optimizatons; defaults to `on`
+# `optimizeFontWeight` controls `font-weight` property optimizatons; defaults to `on`
+# `optimizeOutline` controls `outline` property optimizatons; defaults to `on`
+# `replaceMultipleZeros` contols removing redundant zeros; defaults to `on`
+# `replaceTimeUnits` controls replacing time units with shorter values; defaults to `on
+# `replaceZeroUnits` controls replacing zero values with units; defaults to `on`
 # `roundingPrecision` rounds pixel values to `N` decimal places; `off` disables rounding; defaults to `off`
 # `specialComments` denotes a number of /*! ... */ comments preserved; defaults to `all`
+# `tidyAtRules` controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `on`
+# `tidyBlockScopes` controls block scopes (e.g. `@media`) optimizing; defaults to `on`
+# `tidySelectors` controls selectors optimizing; defaults to `on`
 ```
 
 Level 2 optimizations:
@@ -184,12 +201,29 @@ The output of `minify` method (or the 2nd argument to passed callback) is a hash
 The `level` option can be either `0`, `1` (default), or `2`, or a fine-grained configuration given via a hash:
 
 ```js
-// level 1 optimizations
+// level 1 optimizations (default)
 new CleanCSS({
   level: {
     1: {
-      roundingPrecision: 3, // rounds pixel values to `N` decimal places; `off` disables rounding; defaults to `off`
-      specialComments: 0 // denotes a number of /*! ... */ comments preserved; defaults to `all`
+      cleanupCharsets: true, // controls `@charset` moving to the front of a stylesheet; defaults to `true`
+      keepNegativePaddings: false, // controls negative paddings removal; defaults to `false`
+      keepQuotes: false, // controls keeping quotes when unnecessary; defaults to `false`
+      keepWhitespace: false, // controls keeping unused whitespace; defaults to `false`
+      normalizeUrls: true, // controls URL normalzation; default to `true`
+      optimizeBackground: true, // controls `background` property optimizatons; defaults to `true`
+      optimizeBorderRadius: true, // controls `border-radius` property optimizatons; defaults to `true`
+      optimizeFilter: true, // controls `filter` property optimizatons; defaults to `true`
+      optimizeFont: true, // ontrols `font` property optimizatons; defaults to `true`
+      optimizeFontWeight: true, // controls `font-weight` property optimizatons; defaults to `true`
+      optimizeOutline: true, // controls `outline` property optimizatons; defaults to `true`
+      replaceMultipleZeros: true, // contols removing redundant zeros; defaults to `true`
+      replaceTimeUnits: true, // controls replacing time units with shorter values; defaults to `true`
+      replaceZeroUnits: true, // controls replacing zero values with units; defaults to `true`
+      roundingPrecision: false, // rounds pixel values to `N` decimal places; `false` disables rounding; defaults to `false`
+      specialComments: 'all', // denotes a number of /*! ... */ comments preserved; defaults to `all`
+      tidyAtRules: true, // controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `true`
+      tidyBlockScopes: true, // controls block scopes (e.g. `@media`) optimizing; defaults to `true`
+      tidySelectors: true // controls selectors optimizing; defaults to `true`
     }
   }
 });
@@ -397,7 +431,6 @@ with the following options available:
 * `'[+-]properties.backgroundOriginMerging'` - turn on / off background-origin merging into shorthand
 * `'[+-]properties.backgroundSizeMerging'` - turn on / off background-size merging into shorthand
 * `'[+-]properties.colors'` - turn on / off any color optimizations
-* `'[+-]properties.fontWeight'` - turn on / off any `font-weight` optimizations
 * `'[+-]properties.ieBangHack'` - turn on / off IE bang hack removal
 * `'[+-]properties.iePrefixHack'` - turn on / off IE prefix hack removal
 * `'[+-]properties.ieSuffixHack'` - turn on / off IE suffix hack removal
index 5a5b4dc..bb11a71 100755 (executable)
@@ -38,9 +38,26 @@ commands.on('--help', function () {
   console.log('');
   console.log('  Level 1 optimizations:');
   console.log('    %> cleancss -O1 one.css');
-  console.log('    %> cleancss -O1 roundingPrecision:4;specialComments:1 one.css');
+  console.log('    %> cleancss -O1 keepQuotes:on;roundingPrecision:4;specialComments:1 one.css');
+  console.log('    %> # `cleanupCharsets` controls `@charset` moving to the front of a stylesheet; defaults to `on`');
+  console.log('    %> # `keepNegativePaddings` controls negative paddings removal; defaults to `off`');
+  console.log('    %> # `keepQuotes` controls keeping quotes when unnecessary; defaults to `off`');
+  console.log('    %> # `keepWhitespace` controls keeping unused whitespace; defaults to `off`');
+  console.log('    %> # `normalizeUrls` controls URL normalzation; default to `on`');
+  console.log('    %> # `optimizeBackground` controls `background` property optimizatons; defaults to `on`');
+  console.log('    %> # `optimizeBorderRadius` controls `border-radius` property optimizatons; defaults to `on`');
+  console.log('    %> # `optimizeFilter` controls `filter` property optimizatons; defaults to `on`');
+  console.log('    %> # `optimizeFont controls `font` property optimizatons; defaults to `on` ');
+  console.log('    %> # `optimizeFontWeight` controls `font-weight` property optimizatons; defaults to `on`');
+  console.log('    %> # `optimizeOutline` controls `outline` property optimizatons; defaults to `on`');
+  console.log('    %> # `replaceMultipleZeros` contols removing redundant zeros; defaults to `on`');
+  console.log('    %> # `replaceTimeUnits` controls replacing time units with shorter values; defaults to `on');
+  console.log('    %> # `replaceZeroUnits` controls replacing zero values with units; defaults to `on`');
   console.log('    %> # `roundingPrecision` rounds pixel values to `N` decimal places; `off` disables rounding; defaults to `off`');
   console.log('    %> # `specialComments` denotes a number of /*! ... */ comments preserved; defaults to `all`');
+  console.log('    %> # `tidyAtRules` controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `on`');
+  console.log('    %> # `tidyBlockScopes` controls block scopes (e.g. `@media`) optimizing; defaults to `on`');
+  console.log('    %> # `tidySelectors` controls selectors optimizing; defaults to `on`');
   console.log('');
   console.log('  Level 2 optimizations:');
   console.log('    %> cleancss -O2 one.css');
index bd7b2b8..c48c58a 100644 (file)
@@ -143,7 +143,7 @@ function optimizeColors(name, value, compatibility) {
   return shortenHex(value);
 }
 
-function optimizeFilters(property) {
+function optimizeFilter(property) {
   if (property.value.length == 1) {
     property.value[0][1] = property.value[0][1].replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\W)/, function (match, filter, suffix) {
       return filter.toLowerCase() + suffix;
@@ -160,10 +160,11 @@ function optimizeFont(property, options) {
   var hasNumeral = FONT_NUMERAL_WEIGHTS.indexOf(values[0][1]) > -1 ||
     values[1] && FONT_NUMERAL_WEIGHTS.indexOf(values[1][1]) > -1 ||
     values[2] && FONT_NUMERAL_WEIGHTS.indexOf(values[2][1]) > -1;
+  var canOptimizeFontWeight = options.level[OptimizationLevel.One].optimizeFontWeight;
   var normalCount = 0;
   var toOptimize;
 
-  if (!options.compatibility.properties.fontWeight) {
+  if (!canOptimizeFontWeight) {
     return;
   }
 
@@ -205,7 +206,7 @@ function optimizeFont(property, options) {
     toOptimize = 2;
   }
 
-  if (toOptimize !== undefined) {
+  if (toOptimize !== undefined && canOptimizeFontWeight) {
     optimizeFontWeight(property, toOptimize);
     property.dirty = true;
   }
@@ -250,8 +251,9 @@ function optimizeOutline(property) {
 }
 
 function optimizePixelLengths(_, value, compatibility) {
-  if (!WHOLE_PIXEL_VALUE.test(value))
+  if (!WHOLE_PIXEL_VALUE.test(value)) {
     return value;
+  }
 
   return value.replace(WHOLE_PIXEL_VALUE, function (match, val) {
     var newValue;
@@ -404,6 +406,7 @@ function removeUrlQuotes(value) {
 
 function optimizeBody(properties, context) {
   var options = context.options;
+  var levelOptions = options.level[OptimizationLevel.One];
   var property, name, type, value;
   var valueIsUrl;
   var propertyToken;
@@ -432,7 +435,7 @@ function optimizeBody(properties, context) {
       property.unused = true;
     }
 
-    if (name.indexOf('padding') === 0 && (isNegative(property.value[0]) || isNegative(property.value[1]) || isNegative(property.value[2]) || isNegative(property.value[3]))) {
+    if (!levelOptions.keepNegativePaddings && name.indexOf('padding') === 0 && (isNegative(property.value[0]) || isNegative(property.value[1]) || isNegative(property.value[2]) || isNegative(property.value[3]))) {
       property.unused = true;
     }
 
@@ -463,42 +466,57 @@ function optimizeBody(properties, context) {
       }
 
       if (valueIsUrl) {
-        value = normalizeUrl(value);
-        value = options.compatibility.properties.urlQuotes ?
-          value :
-          removeUrlQuotes(value);
+        value = levelOptions.normalizeUrls ?
+          normalizeUrl(value) :
+          value;
+        value = !options.compatibility.properties.urlQuotes ?
+          removeUrlQuotes(value) :
+          value;
       } else if (isQuoted(value)) {
-        value = removeQuotes(name, value);
+        value = levelOptions.keepQuotes ?
+          value :
+          removeQuotes(name, value);
       } else {
-        value = optimizeWhitespace(name, value);
+        value = levelOptions.keepWhitespace ?
+          value :
+          optimizeWhitespace(name, value);
         value = optimizePrecision(name, value, options.precision);
         value = optimizePixelLengths(name, value, options.compatibility);
-        value = optimizeTimeUnits(name, value);
-        value = optimizeZeroUnits(name, value);
+        value = levelOptions.replaceTimeUnits ?
+          optimizeTimeUnits(name, value) :
+          value;
+        value = levelOptions.replaceZeroUnits ?
+          optimizeZeroUnits(name, value) :
+          value;
+
         if (options.compatibility.properties.zeroUnits) {
           value = optimizeZeroDegUnit(name, value);
           value = optimizeUnits(name, value, options.unitsRegexp);
         }
-        if (options.compatibility.properties.colors)
+
+        if (options.compatibility.properties.colors) {
           value = optimizeColors(name, value, options.compatibility);
+        }
       }
 
       property.value[j][1] = value;
     }
 
-    optimizeMultipleZeros(property);
+    if (levelOptions.replaceMultipleZeros) {
+      optimizeMultipleZeros(property);
+    }
 
-    if (name == 'background') {
+    if (name == 'background' && levelOptions.optimizeBackground) {
       optimizeBackground(property);
-    } else if (name.indexOf('border') === 0 && name.indexOf('radius') > 0) {
+    } else if (name.indexOf('border') === 0 && name.indexOf('radius') > 0 && levelOptions.optimizeBorderRadius) {
       optimizeBorderRadius(property);
-    } else if (name == 'filter') {
-      optimizeFilters(property);
-    } else if (name == 'font') {
+    } else if (name == 'filter'&& levelOptions.optimizeFilter) {
+      optimizeFilter(property);
+    } else if (name == 'font' && levelOptions.optimizeFont) {
       optimizeFont(property, options);
-    } else if (name == 'font-weight' && options.compatibility.properties.fontWeight) {
+    } else if (name == 'font-weight' && levelOptions.optimizeFontWeight) {
       optimizeFontWeight(property, 0);
-    } else if (name == 'outline') {
+    } else if (name == 'outline' && levelOptions.optimizeOutline) {
       optimizeOutline(property);
     }
   }
@@ -611,6 +629,7 @@ function isImport(token) {
 
 function level1Optimize(tokens, context) {
   var options = context.options;
+  var levelOptions = options.level[OptimizationLevel.One];
   var ie7Hack = options.compatibility.selectors.ie7Hack;
   var adjacentSpace = options.compatibility.selectors.adjacentSpace;
   var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace;
@@ -619,7 +638,7 @@ function level1Optimize(tokens, context) {
   var afterRules = false;
 
   options.unitsRegexp = options.unitsRegexp || buildUnitRegexp(options);
-  options.precision = options.precision || buildPrecisionOptions(options.level[OptimizationLevel.One].roundingPrecision);
+  options.precision = options.precision || buildPrecisionOptions(levelOptions.roundingPrecision);
   options.commentsKept = options.commentsKept || 0;
 
   for (var i = 0, l = tokens.length; i < l; i++) {
@@ -627,7 +646,8 @@ function level1Optimize(tokens, context) {
 
     switch (token[0]) {
       case Token.AT_RULE:
-        token[1] = isImport(token) && afterRules ? '' : tidyAtRule(token[1]);
+        token[1] = isImport(token) && afterRules ? '' : token[1];
+        token[1] = levelOptions.tidyAtRules ? tidyAtRule(token[1]) : token[1];
         mayHaveCharset = true;
         break;
       case Token.AT_RULE_BLOCK:
@@ -635,7 +655,7 @@ function level1Optimize(tokens, context) {
         afterRules = true;
         break;
       case Token.BLOCK:
-        token[1] = tidyBlock(token[1], spaceAfterClosingBrace);
+        token[1] = levelOptions.tidyBlockScopes ? tidyBlock(token[1], spaceAfterClosingBrace) : token[1];
         level1Optimize(token[2], context);
         afterRules = true;
         break;
@@ -643,7 +663,7 @@ function level1Optimize(tokens, context) {
         optimizeComment(token, options);
         break;
       case Token.RULE:
-        token[1] = tidyRules(token[1], !ie7Hack, adjacentSpace, beautify, context.warnings);
+        token[1] = levelOptions.tidySelectors ? tidyRules(token[1], !ie7Hack, adjacentSpace, beautify, context.warnings) : token[1];
         optimizeBody(token[2], context);
         afterRules = true;
         break;
@@ -656,7 +676,7 @@ function level1Optimize(tokens, context) {
     }
   }
 
-  if (mayHaveCharset) {
+  if (levelOptions.cleanupCharsets && mayHaveCharset) {
     cleanupCharsets(tokens);
   }
 
index 74e24f7..9c04287 100644 (file)
@@ -11,8 +11,25 @@ var DEFAULTS = {};
 
 DEFAULTS[OptimizationLevel.Zero] = {};
 DEFAULTS[OptimizationLevel.One] = {
+  cleanupCharsets: true,
+  keepNegativePaddings: false,
+  keepQuotes: false,
+  keepWhitespace: false,
+  normalizeUrls: true,
+  optimizeBackground: true,
+  optimizeBorderRadius: true,
+  optimizeFilter: true,
+  optimizeFont: true,
+  optimizeFontWeight: true,
+  optimizeOutline: true,
+  replaceMultipleZeros: true,
+  replaceTimeUnits: true,
+  replaceZeroUnits: true,
   roundingPrecision: roundingPrecisionFrom(undefined),
-  specialComments: 'all'
+  specialComments: 'all',
+  tidyAtRules: true,
+  tidyBlockScopes: true,
+  tidySelectors: true
 };
 DEFAULTS[OptimizationLevel.Two] = {
   adjacentRulesMerging: true,
index 0733b91..c714d1d 100644 (file)
@@ -8,7 +8,6 @@ var DEFAULTS = {
       backgroundOriginMerging: true, // background-origin to shorthand
       backgroundSizeMerging: true, // background-size to shorthand
       colors: true, // any kind of color transformations, like `#ff00ff` to `#f0f` or `#fff` into `red`
-      fontWeight: true, // normal -> '400'
       ieBangHack: false, // !ie suffix hacks on IE<8
       iePrefixHack: false, // underscore / asterisk prefix hacks on IE
       ieSuffixHack: false, // \9 suffix hacks on IE6-9
index f63d758..cda11b2 100644 (file)
@@ -433,7 +433,7 @@ vows.describe('level 1 optimizations')
         'a{font:bold .9em sans-serif}',
         'a{font:bold .9em sans-serif}'
       ]
-    }, { level: 1, compatibility: { properties: { fontWeight: false } } })
+    }, { level: { 1: { optimizeFontWeight: false } } })
   )
   .addBatch(
     optimizerContext('ie hacks', {
@@ -1023,4 +1023,144 @@ vows.describe('level 1 optimizations')
       ]
     }, { level: 1 })
   )
+  .addBatch(
+    optimizerContext('@charset cleanup off', {
+      'stays where it is': [
+        '.block{color:#f10}@charset \'utf-8\';b{font-weight:bolder}',
+        '.block{color:#f10}@charset \'utf-8\';b{font-weight:bolder}'
+      ]
+    }, { level: { 1: { cleanupCharsets: false } } })
+  )
+  .addBatch(
+    optimizerContext('negative padding optimizations off', {
+      'stays as it is': [
+        '.block{padding:-2px}',
+        '.block{padding:-2px}'
+      ]
+    }, { level: { 1: { keepNegativePaddings: true } } })
+  )
+  .addBatch(
+    optimizerContext('quotes optimizations off', {
+      'stays as it is': [
+        '.block{font:"Arial"}',
+        '.block{font:"Arial"}'
+      ]
+    }, { level: { 1: { keepQuotes: true } } })
+  )
+  .addBatch(
+    optimizerContext('whitespace optimizations off', {
+      'stays as it is': [
+        '.block{clip:rect(0, 0, 0, 0)}',
+        '.block{clip:rect(0, 0, 0, 0)}'
+      ]
+    }, { level: { 1: { keepWhitespace: true } } })
+  )
+  .addBatch(
+    optimizerContext('URL normalization off', {
+      'stays as it is': [
+        '.block{background:URL(image.png)}',
+        '.block{background:URL(image.png)}'
+      ]
+    }, { rebase: false, level: { 1: { normalizeUrls: false } } })
+  )
+  .addBatch(
+    optimizerContext('background optimizations off', {
+      'stays as it is': [
+        '.block{background:transparent}',
+        '.block{background:transparent}'
+      ]
+    }, { level: { 1: { optimizeBackground: false } } })
+  )
+  .addBatch(
+    optimizerContext('border-radius optimizations off', {
+      'stays as it is': [
+        '.block{border-radius:2px 3px/2px 3px}',
+        '.block{border-radius:2px 3px/2px 3px}'
+      ]
+    }, { level: { 1: { optimizeBorderRadius: false } } })
+  )
+  .addBatch(
+    optimizerContext('filter optimizations off', {
+      'stays as it is': [
+        '.block{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80)}',
+        '.block{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80)}'
+      ]
+    }, { level: { 1: { optimizeFilter: false } } })
+  )
+  .addBatch(
+    optimizerContext('font optimizations off', {
+      'stays as it is': [
+        '.block{font:normal Arial,sans-serif}',
+        '.block{font:normal Arial,sans-serif}'
+      ]
+    }, { level: { 1: { optimizeFont: false } } })
+  )
+  .addBatch(
+    optimizerContext('font-weight optimizations off', {
+      'stays as it is': [
+        '.block{font-weight:bold}',
+        '.block{font-weight:bold}'
+      ],
+      'stays as it is in font': [
+        '.block{font:normal Arial,sans-serif}',
+        '.block{font:normal Arial,sans-serif}'
+      ]
+    }, { level: { 1: { optimizeFontWeight: false } } })
+  )
+  .addBatch(
+    optimizerContext('outline optimizations off', {
+      'stays as it is': [
+        '.block{outline:none}',
+        '.block{outline:none}'
+      ]
+    }, { level: { 1: { optimizeOutline: false } } })
+  )
+  .addBatch(
+    optimizerContext('replace multiple zeros optimization off', {
+      'stays as it is': [
+        '.block{margin:0 0 0 0}',
+        '.block{margin:0 0 0 0}'
+      ]
+    }, { level: { 1: { replaceMultipleZeros: false } } })
+  )
+  .addBatch(
+    optimizerContext('replace time units optimizations off', {
+      'stays as it is': [
+          '.block{animation-duration:500ms}',
+          '.block{animation-duration:500ms}'
+      ]
+    }, { level: { 1: { replaceTimeUnits: false } } })
+  )
+  .addBatch(
+    optimizerContext('replace zero units optimizations off', {
+      'stays as it is': [
+          '.block{margin:010px}',
+          '.block{margin:010px}'
+      ]
+    }, { level: { 1: { replaceZeroUnits: false } } })
+  )
+  .addBatch(
+    optimizerContext('tidy at-rules optimizations off', {
+      'stays as it is': [
+          '@charset   "utf-8";',
+          '@charset   "utf-8";'
+      ]
+    }, { level: { 1: { tidyAtRules: false } } })
+  )
+  .addBatch(
+    optimizerContext('tidy block scopes optimizations off', {
+      'stays as it is': [
+          '@media ( min-width: 50px ){.block{color:red}}',
+          '@media ( min-width: 50px ){.block{color:red}}'
+      ]
+    }, { level: { 1: { tidyBlockScopes: false } } })
+  )
+  .addBatch(
+    optimizerContext('tidy block scopes optimizations off', {
+      'stays as it is': [
+          '.block > .another-block{color:red}',
+          '.block > .another-block{color:red}'
+      ]
+    }, { level: { 1: { tidySelectors: false } } })
+  )
   .export(module);
index 33f2649..bed2f87 100644 (file)
@@ -19,8 +19,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       }
     },
@@ -47,8 +64,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       }
     },
@@ -64,8 +98,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       },
       'has level 2 options': function (levelOptions) {
@@ -106,8 +157,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 0
+          specialComments: 0,
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       },
       'has level 2 options': function (levelOptions) {
@@ -137,8 +205,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 0
+          specialComments: 0,
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       },
       'has level 2 options': function (levelOptions) {
@@ -168,8 +253,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 0
+          specialComments: 0,
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       },
       'has level 2 options': function (levelOptions) {
@@ -199,8 +301,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(3),
-          specialComments: 0
+          specialComments: 0,
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       }
     },
@@ -216,8 +335,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       },
       'has level 2 options': function (levelOptions) {
@@ -247,8 +383,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       },
       'has level 2 options': function (levelOptions) {
@@ -278,8 +431,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       },
       'has level 2 options': function (levelOptions) {
@@ -309,8 +479,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       },
       'has level 2 options': function (levelOptions) {
@@ -340,8 +527,25 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: roundingPrecisionFrom(undefined),
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       }
     },
@@ -357,6 +561,20 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: {
             'ch': 4,
             'cm': 4,
@@ -375,7 +593,10 @@ vows.describe(optimizationLevelFrom)
             'vw': 4,
             '%': 4
           },
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       }
     },
@@ -391,6 +612,20 @@ vows.describe(optimizationLevelFrom)
       },
       'has level 1 options': function (levelOptions) {
         assert.deepEqual(levelOptions['1'], {
+          cleanupCharsets: true,
+          keepNegativePaddings: false,
+          keepQuotes: false,
+          keepWhitespace: false,
+          normalizeUrls: true,
+          optimizeBackground: true,
+          optimizeBorderRadius: true,
+          optimizeFilter: true,
+          optimizeFont: true,
+          optimizeFontWeight: true,
+          optimizeOutline: true,
+          replaceMultipleZeros: true,
+          replaceTimeUnits: true,
+          replaceZeroUnits: true,
           roundingPrecision: {
             'ch': 5,
             'cm': 5,
@@ -409,7 +644,10 @@ vows.describe(optimizationLevelFrom)
             'vw': 5,
             '%': 1
           },
-          specialComments: 'all'
+          specialComments: 'all',
+          tidyAtRules: true,
+          tidyBlockScopes: true,
+          tidySelectors: true
         });
       }
     }
index 123adc8..ed25cf1 100644 (file)
@@ -14,7 +14,6 @@ vows.describe(compatibility)
         assert.isTrue(compat.properties.backgroundClipMerging);
         assert.isTrue(compat.properties.backgroundOriginMerging);
         assert.isTrue(compat.properties.backgroundSizeMerging);
-        assert.isTrue(compat.properties.fontWeight);
         assert.isFalse(compat.properties.ieBangHack);
         assert.isFalse(compat.properties.iePrefixHack);
         assert.isFalse(compat.properties.ieSuffixHack);
@@ -88,7 +87,6 @@ vows.describe(compatibility)
         assert.isTrue(compat.properties.backgroundOriginMerging);
         assert.isTrue(compat.properties.backgroundSizeMerging);
         assert.isTrue(compat.properties.colors);
-        assert.isTrue(compat.properties.fontWeight);
         assert.isFalse(compat.properties.ieBangHack);
         assert.isFalse(compat.properties.iePrefixHack);
         assert.isTrue(compat.properties.ieSuffixHack);
@@ -121,7 +119,6 @@ vows.describe(compatibility)
         assert.isFalse(compat.properties.backgroundOriginMerging);
         assert.isFalse(compat.properties.backgroundSizeMerging);
         assert.isTrue(compat.properties.colors);
-        assert.isTrue(compat.properties.fontWeight);
         assert.isFalse(compat.properties.ieBangHack);
         assert.isTrue(compat.properties.iePrefixHack);
         assert.isTrue(compat.properties.ieSuffixHack);
@@ -154,7 +151,6 @@ vows.describe(compatibility)
         assert.isFalse(compat.properties.backgroundOriginMerging);
         assert.isFalse(compat.properties.backgroundSizeMerging);
         assert.isTrue(compat.properties.colors);
-        assert.isTrue(compat.properties.fontWeight);
         assert.isTrue(compat.properties.ieBangHack);
         assert.isTrue(compat.properties.iePrefixHack);
         assert.isTrue(compat.properties.ieSuffixHack);