diff --git a/History.md b/History.md index 90bb2dbae..8baf029b1 100644 --- a/History.md +++ b/History.md @@ -13,6 +13,7 @@ * Simplifies URL rebasing with a single `rebaseTo` option in API or inferred from `--output` in CLI. * Splits `inliner` option into `inlineRequest` and `inlineTimeout`. * Fixed issue [#209](https://github.com/jakubpawlowicz/clean-css/issues/209) - adds output formatting via `format` flag. +* Fixed issue [#290](https://github.com/jakubpawlowicz/clean-css/issues/290) - removes aggressive merging. * Fixed issue [#432](https://github.com/jakubpawlowicz/clean-css/issues/432) - adds URLs normalization. * Fixed issue [#460](https://github.com/jakubpawlowicz/clean-css/issues/460) - unescaped semicolon in selector. * Fixed issue [#657](https://github.com/jakubpawlowicz/clean-css/issues/657) - adds property name validation. diff --git a/README.md b/README.md index 47b11e9de..4e3fc6646 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ There will be some breaking changes: * level 1 optimizations are the new default, up to 3.x it was level 2; * `--keep-line-breaks` / `keepBreaks` option is replaced with `--format keep-breaks` / `{ format: 'keep-breaks' }` to ease transition. * `sourceMap` option is API has to be a boolean from now on. If you want to specify an input source map pass it a 2nd argument to `minify` method or via a hash instead; +* `--skip-aggressive-merging` / `aggressiveMerging` option is removed as aggressive merging is gone too, replaced by smarter override merging. Please note this list is not final. You are more than welcome to comment these changes in [4.0 release discussion](https://github.com/jakubpawlowicz/clean-css/issues/842) thread. @@ -76,7 +77,6 @@ Options: -O [optimizations] Turn on level optimizations; optionally accepts a list of fine-grained options, defaults to `1`, see examples below --inline [rules] Enables inlining for listed sources (defaults to `local`) --inline-timeout [seconds] Per connection timeout when fetching remote stylesheets (defaults to 5 seconds) - --skip-aggressive-merging Disable properties merging based on their order --skip-rebase Disable URLs rebasing --source-map Enables building input's source map --source-map-inline-sources Enables inlining sources inside source maps @@ -199,7 +199,6 @@ var minified = new CleanCSS().minify(source).styles; CleanCSS constructor accepts a hash as a parameter, i.e., `new CleanCSS(options)` with the following options available: -* `aggressiveMerging` - set to false to disable aggressive merging of properties. * `compatibility` - enables compatibility mode, see [below for more examples](#how-to-set-a-compatibility-mode) * `format` - formats output CSS by using indentation and one rule or property per line. * `inline` - whether to inline `@import` rules, can be `['all']`, `['local']` (default), `['remote']`, or a blacklisted domain/path e.g. `['!fonts.googleapis.com']` diff --git a/bin/cleancss b/bin/cleancss index 55f1d8456..c25210b30 100755 --- a/bin/cleancss +++ b/bin/cleancss @@ -20,7 +20,6 @@ commands .option('-O [optimizations]', 'Turn on level optimizations; optionally accepts a list of fine-grained options, defaults to `1`, see examples below', function (val) { return Math.abs(parseInt(val)); }) .option('--inline [rules]', 'Enables inlining for listed sources (defaults to `local`)') .option('--inline-timeout [seconds]', 'Per connection timeout when fetching remote stylesheets (defaults to 5 seconds)', parseFloat) - .option('--skip-aggressive-merging', 'Disable properties merging based on their order') .option('--skip-rebase', 'Disable URLs rebasing') .option('--source-map', 'Enables building input\'s source map') .option('--source-map-inline-sources', 'Enables inlining sources inside source maps'); @@ -125,7 +124,6 @@ if (!fromStdin && commands.args.length === 0) { // Now coerce commands into CleanCSS configuration... var debugMode = commands.debug; var options = { - aggressiveMerging: commands.skipAggressiveMerging ? false : true, compatibility: commands.compatibility, format: commands.format, inline: commands.inline || 'local', diff --git a/lib/clean.js b/lib/clean.js index 6db9f5943..06b8948fe 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -31,7 +31,6 @@ var CleanCSS = module.exports = function CleanCSS(options) { options = options || {}; this.options = { - aggressiveMerging: undefined === options.aggressiveMerging ? true : !!options.aggressiveMerging, compatibility: compatibility(options.compatibility), format: formatFrom(options.format), inline: inlineOptionsFrom(options.inline), diff --git a/lib/optimizer/level-2/break-up.js b/lib/optimizer/level-2/break-up.js index 6e6f57759..9e44d5a1f 100644 --- a/lib/optimizer/level-2/break-up.js +++ b/lib/optimizer/level-2/break-up.js @@ -10,7 +10,7 @@ var MULTIPLEX_SEPARATOR = ','; function _colorFilter(validator) { return function (value) { - return value[1] == 'invert' || validator.isValidColor(value[1]); + return value[1] == 'invert' || validator.isValidColor(value[1]) || validator.isValidVendorPrefixedValue(value[1]); }; } @@ -46,7 +46,7 @@ function _wrapDefault(name, property, compactable) { function _widthFilter(validator) { return function (value) { - return value[1] != 'inherit' && validator.isValidWidth(value[1]) && !validator.isValidStyleKeyword(value[1]) && !validator.isValidColorValue(value[1]); + return value[1] != 'inherit' && validator.isValidWidth(value[1]) && !validator.isValidStyle(value[1]) && !validator.isValidColorValue(value[1]); }; } @@ -85,7 +85,7 @@ function background(property, compactable, validator) { if (validator.isValidBackgroundAttachment(value[1])) { attachment.value = [value]; anyValueSet = true; - } else if (validator.isValidBackgroundBox(value[1])) { + } else if (validator.isValidBackgroundClip(value[1]) || validator.isValidBackgroundOrigin(value[1])) { if (clipSet) { origin.value = [value]; originSet = true; @@ -126,7 +126,7 @@ function background(property, compactable, validator) { positionSet = true; } anyValueSet = true; - } else if ((color.value[0][1] == compactable[color.name].defaultValue || color.value[0][1] == 'none') && validator.isValidColor(value[1])) { + } else if ((color.value[0][1] == compactable[color.name].defaultValue || color.value[0][1] == 'none') && (validator.isValidColor(value[1]) || validator.isValidVendorPrefixedValue(value[1]))) { color.value = [value]; anyValueSet = true; } else if (validator.isValidUrl(value[1]) || validator.isValidFunction(value[1])) { diff --git a/lib/optimizer/level-2/can-override.js b/lib/optimizer/level-2/can-override.js index 6405e979b..9cb4debea 100644 --- a/lib/optimizer/level-2/can-override.js +++ b/lib/optimizer/level-2/can-override.js @@ -1,142 +1,180 @@ -// Functions that decide what value can override what. -// The main purpose is to disallow removing CSS fallbacks. -// A separate implementation is needed for every different kind of CSS property. -// ----- -// The generic idea is that properties that have wider browser support are 'more understandable' -// than others and that 'less understandable' values can't override more understandable ones. - -// Use when two tokens of the same property can always be merged -function always() { - return true; -} - -function alwaysButIntoFunction(property1, property2, validator) { - var value1 = property1.value[0][1]; - var value2 = property2.value[0][1]; - - var validFunction1 = validator.isValidFunction(value1); - var validFunction2 = validator.isValidFunction(value2); +var understandable = require('./compacting/understandable'); - if (validFunction1 && validFunction2) { - return validator.areSameFunction(value1, value2); - } else if (!validFunction1 && validFunction2) { +function backgroundPosition(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue('background-position', value2, true)) { return false; - } else { + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + return true; + } else if (validator.isValidKeywordValue('background-position', value2, true)) { return true; } + + return unit(validator, value1, value2); } -function backgroundImage(property1, property2, validator) { - // The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa - // Understandability: (none | url | inherit) > (same function) > (same value) +function backgroundSize(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue('background-size', value2, true)) { + return false; + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + return true; + } else if (validator.isValidKeywordValue('background-size', value2, true)) { + return true; + } - // (none | url) - var image1 = property1.value[0][1]; - var image2 = property2.value[0][1]; + return unit(validator, value1, value2); +} - if (image2 == 'none' || image2 == 'inherit' || validator.isValidUrl(image2)) +function color(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidColor(value2)) { + return false; + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { return true; - if (image1 == 'none' || image1 == 'inherit' || validator.isValidUrl(image1)) + } else if (!validator.colorOpacity && (validator.isValidRgbaColor(value1) || validator.isValidHslaColor(value1))) { + return false; + } else if (!validator.colorOpacity && (validator.isValidRgbaColor(value2) || validator.isValidHslaColor(value2))) { return false; + } else if (validator.isValidColor(value1) && validator.isValidColor(value2)) { + return true; + } - // Functions with the same name can override each other; same values can override each other - return sameFunctionOrValue(property1, property2, validator); + return sameFunctionOrValue(validator, value1, value2); } -function border(property1, property2, validator) { - return color(property1.components[2], property2.components[2], validator); +function components(overrideCheckers) { + return function (validator, value1, value2, position) { + return overrideCheckers[position](validator, value1, value2); + }; } -// Use for color properties (color, background-color, border-color, etc.) -function color(property1, property2, validator) { - // The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa - // Understandability: (hex | named) > (rgba | hsla) > (same function name) > anything else - // NOTE: at this point rgb and hsl are replaced by hex values by clean-css - - var color1 = property1.value[0][1]; - var color2 = property2.value[0][1]; - - if (!validator.colorOpacity && (validator.isValidRgbaColor(color1) || validator.isValidHslaColor(color1))) +function image(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidImage(value2)) { return false; - if (!validator.colorOpacity && (validator.isValidRgbaColor(color2) || validator.isValidHslaColor(color2))) - return false; - - // (hex | named) - if (validator.isValidNamedColor(color2) || validator.isValidHexColor(color2)) + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { return true; - if (validator.isValidNamedColor(color1) || validator.isValidHexColor(color1)) - return false; - - // (rgba|hsla) - if (validator.isValidRgbaColor(color2) || validator.isValidHslaColor(color2)) + } else if (validator.isValidImage(value2)) { return true; - if (validator.isValidRgbaColor(color1) || validator.isValidHslaColor(color1)) + } else if (validator.isValidImage(value1)) { return false; + } - // Functions with the same name can override each other; same values can override each other - return sameFunctionOrValue(property1, property2, validator); + return sameFunctionOrValue(validator, value1, value2); } -function twoOptionalFunctions(property1, property2, validator) { - var value1 = property1.value[0][1]; - var value2 = property2.value[0][1]; +function keyword(propertyName) { + return function(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue(propertyName, value2)) { + return false; + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + return true; + } - return !(validator.isValidFunction(value1) ^ validator.isValidFunction(value2)); + return validator.isValidKeywordValue(propertyName, value2, false); + }; } -function sameValue(property1, property2) { - var value1 = property1.value[0][1]; - var value2 = property2.value[0][1]; +function keywordWithGlobal(propertyName) { + return function(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue(propertyName, value2, true)) { + return false; + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + return true; + } - return value1 === value2; + return validator.isValidKeywordValue(propertyName, value2, true); + }; } -function sameFunctionOrValue(property1, property2, validator) { - var value1 = property1.value[0][1]; - var value2 = property2.value[0][1]; +function sameFunctionOrValue(validator, value1, value2) { + return validator.areSameFunction(value1, value2) ? + true : + value1 === value2; +} - // Functions with the same name can override each other - if (validator.areSameFunction(value1, value2)) +function textShadow(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidTextShadow(value2)) { + return false; + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { return true; + } - return value1 === value2; + return validator.isValidTextShadow(value2); } -// Use for properties containing CSS units (margin-top, padding-left, etc.) -function unit(property1, property2, validator) { - // The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa - // Understandability: (unit without functions) > (same functions | standard functions) > anything else - // NOTE: there is no point in having different vendor-specific functions override each other or standard functions, - // or having standard functions override vendor-specific functions, but standard functions can override each other - // NOTE: vendor-specific property values are not taken into consideration here at the moment - var value1 = property1.value[0][1]; - var value2 = property2.value[0][1]; - - if (validator.isValidAndCompatibleUnitWithoutFunction(value1) && !validator.isValidAndCompatibleUnitWithoutFunction(value2)) +function unit(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidUnitWithoutFunction(value2)) { return false; - - if (validator.isValidUnitWithoutFunction(value2)) + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + return true; + } else if (validator.isValidUnitWithoutFunction(value1) && !validator.isValidUnitWithoutFunction(value2)) { + return false; + } else if (validator.isValidUnitWithoutFunction(value2)) { return true; - if (validator.isValidUnitWithoutFunction(value1)) + } else if (validator.isValidUnitWithoutFunction(value1)) { return false; + } else if (validator.isValidFunctionWithoutVendorPrefix(value1) && validator.isValidFunctionWithoutVendorPrefix(value2)) { + return true; + } + + return sameFunctionOrValue(validator, value1, value2); +} + +function unitOrKeywordWithGlobal(propertyName) { + var byKeyword = keywordWithGlobal(propertyName); - // Standard non-vendor-prefixed functions can override each other - if (validator.isValidFunctionWithoutVendorPrefix(value2) && validator.isValidFunctionWithoutVendorPrefix(value1)) { + return function(validator, value1, value2) { + return unit(validator, value1, value2) || byKeyword(validator, value1, value2); + }; +} + +function zIndex(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isValidZIndex(value2)) { + return false; + } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { return true; } - // Functions with the same name can override each other; same values can override each other - return sameFunctionOrValue(property1, property2, validator); + return validator.isValidZIndex(value2); } module.exports = { - always: always, - alwaysButIntoFunction: alwaysButIntoFunction, - backgroundImage: backgroundImage, - border: border, - color: color, - sameValue: sameValue, - sameFunctionOrValue: sameFunctionOrValue, - twoOptionalFunctions: twoOptionalFunctions, - unit: unit + generic: { + color: color, + components: components, + image: image, + unit: unit + }, + property: { + backgroundAttachment: keyword('background-attachment'), + backgroundClip: keywordWithGlobal('background-clip'), + backgroundOrigin: keyword('background-origin'), + backgroundPosition: backgroundPosition, + backgroundRepeat: keyword('background-repeat'), + backgroundSize: backgroundSize, + bottom: unitOrKeywordWithGlobal('bottom'), + borderCollapse: keyword('border-collapse'), + borderStyle: keywordWithGlobal('*-style'), + clear: keywordWithGlobal('clear'), + cursor: keywordWithGlobal('cursor'), + display: keywordWithGlobal('display'), + float: keywordWithGlobal('float'), + fontStyle: keywordWithGlobal('font-style'), + left: unitOrKeywordWithGlobal('left'), + fontWeight: keywordWithGlobal('font-weight'), + listStyleType: keywordWithGlobal('list-style-type'), + listStylePosition: keywordWithGlobal('list-style-position'), + outlineStyle: keywordWithGlobal('*-style'), + overflow: keywordWithGlobal('overflow'), + position: keywordWithGlobal('position'), + right: unitOrKeywordWithGlobal('right'), + textAlign: keywordWithGlobal('text-align'), + textDecoration: keywordWithGlobal('text-decoration'), + textOverflow: keywordWithGlobal('text-overflow'), + textShadow: textShadow, + top: unitOrKeywordWithGlobal('top'), + transform: sameFunctionOrValue, + verticalAlign: unitOrKeywordWithGlobal('vertical-align'), + visibility: keywordWithGlobal('visibility'), + whiteSpace: keywordWithGlobal('white-space'), + zIndex: zIndex + } }; diff --git a/lib/optimizer/level-2/compactable.js b/lib/optimizer/level-2/compactable.js index e77c635d2..f69c40c6a 100644 --- a/lib/optimizer/level-2/compactable.js +++ b/lib/optimizer/level-2/compactable.js @@ -14,7 +14,7 @@ var restore = require('./restore'); // * components: array (Only specify for shorthand properties.) // Contains the names of the granular properties this shorthand compacts. // -// * canOverride: function (Default is canOverride.sameValue - meaning that they'll only be merged if they have the same value.) +// * canOverride: function // Returns whether two tokens of this property can be merged with each other. // This property has no meaning for shorthands. // @@ -33,12 +33,17 @@ var restore = require('./restore'); // Puts the shorthand together from its components. // var compactable = { - 'color': { - canOverride: canOverride.color, - defaultValue: 'transparent', - shortestValue: 'red' - }, 'background': { + canOverride: canOverride.generic.components([ + canOverride.generic.image, + canOverride.property.backgroundPosition, + canOverride.property.backgroundSize, + canOverride.property.backgroundRepeat, + canOverride.property.backgroundAttachment, + canOverride.property.backgroundOrigin, + canOverride.property.backgroundClip, + canOverride.generic.color + ]), components: [ 'background-image', 'background-position', @@ -55,8 +60,15 @@ var compactable = { shortestValue: '0', shorthand: true }, + 'background-attachment': { + canOverride: canOverride.property.backgroundAttachment, + componentOf: [ + 'background' + ], + defaultValue: 'scroll' + }, 'background-clip': { - canOverride: canOverride.always, + canOverride: canOverride.property.backgroundClip, componentOf: [ 'background' ], @@ -64,7 +76,7 @@ var compactable = { shortestValue: 'border-box' }, 'background-color': { - canOverride: canOverride.color, + canOverride: canOverride.generic.color, componentOf: [ 'background' ], @@ -74,30 +86,22 @@ var compactable = { shortestValue: 'red' }, 'background-image': { - canOverride: canOverride.backgroundImage, + canOverride: canOverride.generic.image, componentOf: [ 'background' ], defaultValue: 'none' }, 'background-origin': { - canOverride: canOverride.always, + canOverride: canOverride.property.backgroundOrigin, componentOf: [ 'background' ], defaultValue: 'padding-box', shortestValue: 'border-box' }, - 'background-repeat': { - canOverride: canOverride.always, - componentOf: [ - 'background' - ], - defaultValue: ['repeat'], - doubleValues: true - }, 'background-position': { - canOverride: canOverride.alwaysButIntoFunction, + canOverride: canOverride.property.backgroundPosition, componentOf: [ 'background' ], @@ -105,8 +109,16 @@ var compactable = { doubleValues: true, shortestValue: '0' }, + 'background-repeat': { + canOverride: canOverride.property.backgroundRepeat, + componentOf: [ + 'background' + ], + defaultValue: ['repeat'], + doubleValues: true + }, 'background-size': { - canOverride: canOverride.alwaysButIntoFunction, + canOverride: canOverride.property.backgroundSize, componentOf: [ 'background' ], @@ -114,16 +126,17 @@ var compactable = { doubleValues: true, shortestValue: '0 0' }, - 'background-attachment': { - canOverride: canOverride.always, - componentOf: [ - 'background' - ], - defaultValue: 'scroll' + 'bottom': { + canOverride: canOverride.property.bottom, + defaultValue: 'auto' }, 'border': { breakUp: breakUp.border, - canOverride: canOverride.border, + canOverride: canOverride.generic.components([ + canOverride.generic.unit, + canOverride.property.borderStyle, + canOverride.generic.color + ]), components: [ 'border-width', 'border-style', @@ -142,7 +155,11 @@ var compactable = { }, 'border-bottom': { breakUp: breakUp.border, - canOverride: canOverride.border, + canOverride: canOverride.generic.components([ + canOverride.generic.unit, + canOverride.property.borderStyle, + canOverride.generic.color + ]), components: [ 'border-bottom-width', 'border-bottom-style', @@ -153,7 +170,7 @@ var compactable = { shorthand: true }, 'border-bottom-color': { - canOverride: canOverride.color, + canOverride: canOverride.generic.color, componentOf: [ 'border-bottom', 'border-color' @@ -161,7 +178,7 @@ var compactable = { defaultValue: 'none' }, 'border-bottom-style': { - canOverride: canOverride.always, + canOverride: canOverride.property.borderStyle, componentOf: [ 'border-bottom', 'border-style' @@ -169,7 +186,7 @@ var compactable = { defaultValue: 'none' }, 'border-bottom-width': { - canOverride: canOverride.unit, + canOverride: canOverride.generic.unit, componentOf: [ 'border-bottom', 'border-width' @@ -177,9 +194,18 @@ var compactable = { defaultValue: 'medium', shortestValue: '0' }, + 'border-collapse': { + canOverride: canOverride.property.borderCollapse, + defaultValue: 'separate' + }, 'border-color': { breakUp: breakUp.fourValues, - canOverride: canOverride.color, + canOverride: canOverride.generic.components([ + canOverride.generic.color, + canOverride.generic.color, + canOverride.generic.color, + canOverride.generic.color + ]), componentOf: ['border'], components: [ 'border-top-color', @@ -194,7 +220,11 @@ var compactable = { }, 'border-left': { breakUp: breakUp.border, - canOverride: canOverride.border, + canOverride: canOverride.generic.components([ + canOverride.generic.unit, + canOverride.property.borderStyle, + canOverride.generic.color + ]), components: [ 'border-left-width', 'border-left-style', @@ -205,7 +235,7 @@ var compactable = { shorthand: true }, 'border-left-color': { - canOverride: canOverride.color, + canOverride: canOverride.generic.color, componentOf: [ 'border-color', 'border-left' @@ -213,7 +243,7 @@ var compactable = { defaultValue: 'none' }, 'border-left-style': { - canOverride: canOverride.always, + canOverride: canOverride.property.borderStyle, componentOf: [ 'border-left', 'border-style' @@ -221,7 +251,7 @@ var compactable = { defaultValue: 'none' }, 'border-left-width': { - canOverride: canOverride.unit, + canOverride: canOverride.generic.unit, componentOf: [ 'border-left', 'border-width' @@ -231,7 +261,11 @@ var compactable = { }, 'border-right': { breakUp: breakUp.border, - canOverride: canOverride.border, + canOverride: canOverride.generic.components([ + canOverride.generic.unit, + canOverride.property.borderStyle, + canOverride.generic.color + ]), components: [ 'border-right-width', 'border-right-style', @@ -242,7 +276,7 @@ var compactable = { shorthand: true }, 'border-right-color': { - canOverride: canOverride.color, + canOverride: canOverride.generic.color, componentOf: [ 'border-color', 'border-right' @@ -250,7 +284,7 @@ var compactable = { defaultValue: 'none' }, 'border-right-style': { - canOverride: canOverride.always, + canOverride: canOverride.property.borderStyle, componentOf: [ 'border-right', 'border-style' @@ -258,7 +292,7 @@ var compactable = { defaultValue: 'none' }, 'border-right-width': { - canOverride: canOverride.unit, + canOverride: canOverride.generic.unit, componentOf: [ 'border-right', 'border-width' @@ -268,7 +302,12 @@ var compactable = { }, 'border-style': { breakUp: breakUp.fourValues, - canOverride: canOverride.always, + canOverride: canOverride.generic.components([ + canOverride.property.borderStyle, + canOverride.property.borderStyle, + canOverride.property.borderStyle, + canOverride.property.borderStyle + ]), componentOf: [ 'border' ], @@ -284,7 +323,11 @@ var compactable = { }, 'border-top': { breakUp: breakUp.border, - canOverride: canOverride.border, + canOverride: canOverride.generic.components([ + canOverride.generic.unit, + canOverride.property.borderStyle, + canOverride.generic.color + ]), components: [ 'border-top-width', 'border-top-style', @@ -295,7 +338,7 @@ var compactable = { shorthand: true }, 'border-top-color': { - canOverride: canOverride.color, + canOverride: canOverride.generic.color, componentOf: [ 'border-color', 'border-top' @@ -303,7 +346,7 @@ var compactable = { defaultValue: 'none' }, 'border-top-style': { - canOverride: canOverride.always, + canOverride: canOverride.property.borderStyle, componentOf: [ 'border-style', 'border-top' @@ -311,7 +354,7 @@ var compactable = { defaultValue: 'none' }, 'border-top-width': { - canOverride: canOverride.unit, + canOverride: canOverride.generic.unit, componentOf: [ 'border-top', 'border-width' @@ -321,7 +364,12 @@ var compactable = { }, 'border-width': { breakUp: breakUp.fourValues, - canOverride: canOverride.unit, + canOverride: canOverride.generic.components([ + canOverride.generic.unit, + canOverride.generic.unit, + canOverride.generic.unit, + canOverride.generic.unit + ]), components: [ 'border-top-width', 'border-right-width', @@ -333,55 +381,149 @@ var compactable = { shortestValue: '0', shorthand: true }, + 'clear': { + canOverride: canOverride.property.clear, + defaultValue: 'none' + }, + 'color': { + canOverride: canOverride.generic.color, + defaultValue: 'transparent', + shortestValue: 'red' + }, + 'cursor': { + canOverride: canOverride.property.cursor, + defaultValue: 'auto' + }, + 'display': { + canOverride: canOverride.property.display, + }, + 'float': { + canOverride: canOverride.property.float, + defaultValue: 'none' + }, 'font-size': { - canOverride: canOverride.unit, + canOverride: canOverride.generic.unit, defaultValue: 'medium', shortestValue: '0' }, + 'font-style': { + canOverride: canOverride.property.fontStyle, + defaultValue: 'normal' + }, + 'font-weight': { + canOverride: canOverride.property.fontWeight, + defaultValue: '400', + shortestValue: '400' + }, 'height': { - canOverride: canOverride.unit, + canOverride: canOverride.generic.unit, defaultValue: 'auto', shortestValue: '0' }, + 'left': { + canOverride: canOverride.property.left, + defaultValue: 'auto' + }, + 'line-height': { + canOverride: canOverride.generic.unit, + defaultValue: 'normal', + shortestValue: '0' + }, 'list-style': { + canOverride: canOverride.generic.components([ + canOverride.property.listStyleType, + canOverride.property.listStylePosition, + canOverride.property.listStyleImage + ]), components: [ 'list-style-type', 'list-style-position', 'list-style-image' ], - canOverride: canOverride.always, breakUp: breakUp.listStyle, restore: restore.withoutDefaults, defaultValue: 'outside', // can't use 'disc' because that'd override default 'decimal' for
    shortestValue: 'none', shorthand: true }, - 'list-style-type' : { - canOverride: canOverride.always, + 'list-style-image' : { + canOverride: canOverride.generic.image, componentOf: [ 'list-style' ], - defaultValue: '__hack', - // NOTE: we can't tell the real default value here, it's 'disc' for
      and 'decimal' for
        - // -- this is a hack, but it doesn't matter because this value will be either overridden or it will disappear at the final step anyway - shortestValue: 'none' + defaultValue: 'none' }, 'list-style-position' : { - canOverride: canOverride.always, + canOverride: canOverride.property.listStylePosition, componentOf: [ 'list-style' ], defaultValue: 'outside', shortestValue: 'inside' }, - 'list-style-image' : { - canOverride: canOverride.always, + 'list-style-type' : { + canOverride: canOverride.property.listStyleType, componentOf: [ 'list-style' ], - defaultValue: 'none' + // NOTE: we can't tell the real default value here, it's 'disc' for
          and 'decimal' for
            + // this is a hack, but it doesn't matter because this value will be either overridden or + // it will disappear at the final step anyway + defaultValue: 'decimal|disc', + shortestValue: 'none' + }, + 'margin': { + breakUp: breakUp.fourValues, + canOverride: canOverride.generic.components([ + canOverride.generic.unit, + canOverride.generic.unit, + canOverride.generic.unit, + canOverride.generic.unit + ]), + components: [ + 'margin-top', + 'margin-right', + 'margin-bottom', + 'margin-left' + ], + defaultValue: '0', + restore: restore.fourValues, + shorthand: true + }, + 'margin-bottom': { + canOverride: canOverride.generic.unit, + componentOf: [ + 'margin' + ], + defaultValue: '0' + }, + 'margin-left': { + canOverride: canOverride.generic.unit, + componentOf: [ + 'margin' + ], + defaultValue: '0' + }, + 'margin-right': { + canOverride: canOverride.generic.unit, + componentOf: [ + 'margin' + ], + defaultValue: '0' + }, + 'margin-top': { + canOverride: canOverride.generic.unit, + componentOf: [ + 'margin' + ], + defaultValue: '0' }, 'outline': { + canOverride: canOverride.generic.components([ + canOverride.generic.color, + canOverride.property.outlineStyle, + canOverride.generic.unit + ]), components: [ 'outline-color', 'outline-style', @@ -393,7 +535,7 @@ var compactable = { shorthand: true }, 'outline-color': { - canOverride: canOverride.color, + canOverride: canOverride.generic.color, componentOf: [ 'outline' ], @@ -401,36 +543,141 @@ var compactable = { shortestValue: 'red' }, 'outline-style': { - canOverride: canOverride.always, + canOverride: canOverride.property.outlineStyle, componentOf: [ 'outline' ], defaultValue: 'none' }, 'outline-width': { - canOverride: canOverride.unit, + canOverride: canOverride.generic.unit, componentOf: [ 'outline' ], defaultValue: 'medium', shortestValue: '0' }, + 'overflow': { + canOverride: canOverride.property.overflow, + defaultValue: 'visible' + }, + 'overflow-x': { + canOverride: canOverride.property.overflow, + defaultValue: 'visible' + }, + 'overflow-y': { + canOverride: canOverride.property.overflow, + defaultValue: 'visible' + }, + 'padding': { + breakUp: breakUp.fourValues, + canOverride: canOverride.generic.components([ + canOverride.generic.unit, + canOverride.generic.unit, + canOverride.generic.unit, + canOverride.generic.unit + ]), + components: [ + 'padding-top', + 'padding-right', + 'padding-bottom', + 'padding-left' + ], + defaultValue: '0', + restore: restore.fourValues, + shorthand: true + }, + 'padding-bottom': { + canOverride: canOverride.generic.unit, + componentOf: [ + 'padding' + ], + defaultValue: '0' + }, + 'padding-left': { + canOverride: canOverride.generic.unit, + componentOf: [ + 'padding' + ], + defaultValue: '0' + }, + 'padding-right': { + canOverride: canOverride.generic.unit, + componentOf: [ + 'padding' + ], + defaultValue: '0' + }, + 'padding-top': { + canOverride: canOverride.generic.unit, + componentOf: [ + 'padding' + ], + defaultValue: '0' + }, + 'position': { + canOverride: canOverride.property.position, + defaultValue: 'static' + }, + 'right': { + canOverride: canOverride.property.right, + defaultValue: 'auto' + }, + 'text-align': { + canOverride: canOverride.property.textAlign, + // NOTE: we can't tell the real default value here, as it depends on default text direction + // this is a hack, but it doesn't matter because this value will be either overridden or + // it will disappear anyway + defaultValue: 'left|right' + }, + 'text-decoration': { + canOverride: canOverride.property.textDecoration, + defaultValue: 'none' + }, + 'text-overflow': { + canOverride: canOverride.property.textOverflow, + defaultValue: 'none' + }, + 'text-shadow': { + canOverride: canOverride.property.textShadow, + defaultValue: 'none' + }, + 'top': { + canOverride: canOverride.property.top, + defaultValue: 'auto' + }, '-moz-transform': { - canOverride: canOverride.sameFunctionOrValue + canOverride: canOverride.property.transform }, '-ms-transform': { - canOverride: canOverride.sameFunctionOrValue + canOverride: canOverride.property.transform }, '-webkit-transform': { - canOverride: canOverride.sameFunctionOrValue + canOverride: canOverride.property.transform }, 'transform': { - canOverride: canOverride.sameFunctionOrValue + canOverride: canOverride.property.transform + }, + 'vertical-align': { + canOverride: canOverride.property.verticalAlign, + defaultValue: 'baseline' + }, + 'visibility': { + canOverride: canOverride.property.visibility, + defaultValue: 'visible' + }, + 'white-space': { + canOverride: canOverride.property.whiteSpace, + defaultValue: 'normal' }, 'width': { - canOverride: canOverride.unit, + canOverride: canOverride.generic.unit, defaultValue: 'auto', shortestValue: '0' + }, + 'z-index': { + canOverride: canOverride.property.zIndex, + defaultValue: 'auto' } }; @@ -448,7 +695,7 @@ var addFourValueShorthand = function (prop, components, options) { for (var i = 0; i < components.length; i++) { compactable[components[i]] = { breakUp: options.breakUp || breakUp.fourValues, - canOverride: options.canOverride || canOverride.unit, + canOverride: options.canOverride || canOverride.generic.unit, componentOf: options.componentOf, defaultValue: options.defaultValue || '0', shortestValue: options.shortestValue @@ -471,26 +718,4 @@ var addFourValueShorthand = function (prop, components, options) { }); }); -addFourValueShorthand('padding', [ - 'padding-top', - 'padding-right', - 'padding-bottom', - 'padding-left' -], { - componentOf: [ - 'padding' - ] -}); - -addFourValueShorthand('margin', [ - 'margin-top', - 'margin-right', - 'margin-bottom', - 'margin-left' -], { - componentOf: [ - 'margin' - ] -}); - module.exports = compactable; diff --git a/lib/optimizer/level-2/compacting/every-combination.js b/lib/optimizer/level-2/compacting/every-combination.js deleted file mode 100644 index af3efc492..000000000 --- a/lib/optimizer/level-2/compacting/every-combination.js +++ /dev/null @@ -1,28 +0,0 @@ -var shallowClone = require('../clone').shallow; - -var Marker = require('../../../tokenizer/marker'); - -function everyCombination(fn, left, right, validator) { - var samePositon = !left.shorthand && !right.shorthand && !left.multiplex && !right.multiplex; - var _left = shallowClone(left); - var _right = shallowClone(right); - - for (var i = 0, l = left.value.length; i < l; i++) { - for (var j = 0, m = right.value.length; j < m; j++) { - if (left.value[i][1] == Marker.COMMA || right.value[j][1] == Marker.COMMA) - continue; - - if (samePositon && i != j) - continue; - - _left.value = [left.value[i]]; - _right.value = [right.value[j]]; - if (!fn(_left, _right, validator)) - return false; - } - } - - return true; -} - -module.exports = everyCombination; diff --git a/lib/optimizer/level-2/compacting/every-values-pair.js b/lib/optimizer/level-2/compacting/every-values-pair.js new file mode 100644 index 000000000..44fcb7d53 --- /dev/null +++ b/lib/optimizer/level-2/compacting/every-values-pair.js @@ -0,0 +1,28 @@ +var Marker = require('../../../tokenizer/marker'); + +function everyValuesPair(fn, left, right) { + var leftSize = left.value.length; + var rightSize = right.value.length; + var total = Math.max(leftSize, rightSize); + var lowerBound = Math.min(leftSize, rightSize) - 1; + var leftValue; + var rightValue; + var position; + + for (position = 0; position < total; position++) { + leftValue = left.value[position] && left.value[position][1] || leftValue; + rightValue = right.value[position] && right.value[position][1] || rightValue; + + if (leftValue == Marker.COMMA || rightValue == Marker.COMMA) { + continue; + } + + if (!fn(leftValue, rightValue, position, position <= lowerBound)) { + return false; + } + } + + return true; +} + +module.exports = everyValuesPair; diff --git a/lib/optimizer/level-2/compacting/optimize.js b/lib/optimizer/level-2/compacting/optimize.js index 53e2af0dc..3311abe21 100644 --- a/lib/optimizer/level-2/compacting/optimize.js +++ b/lib/optimizer/level-2/compacting/optimize.js @@ -2,7 +2,6 @@ var populateComponents = require('./populate-components'); var compactOverrides = require('./override-compactor'); var compactShorthands = require('./shorthand-compactor'); -var compactable = require('../compactable'); var restoreWithComponents = require('../restore-with-components'); var wrapForOptimizing = require('../../wrap-for-optimizing').all; @@ -11,115 +10,18 @@ var restoreFromOptimizing = require('../../restore-from-optimizing'); var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel; -var serializeProperty = require('../../../writer/one-time').property; - -function _optimize(properties, mergeAdjacent, aggressiveMerging, validator) { - var overrideMapping = {}; - var lastName = null; - var lastProperty; - var j; - - function mergeablePosition(position) { - if (mergeAdjacent === false || mergeAdjacent === true) - return mergeAdjacent; - - return mergeAdjacent.indexOf(position) > -1; - } - - function sameValue(position) { - var left = properties[position - 1]; - var right = properties[position]; - - return serializeProperty(left.all, left.position) == serializeProperty(right.all, right.position); - } - - propertyLoop: - for (var position = 0, total = properties.length; position < total; position++) { - var property = properties[position]; - var _name = (property.name == '-ms-filter' || property.name == 'filter') ? - (lastName == 'background' || lastName == 'background-image' ? lastName : property.name) : - property.name; - var isImportant = property.important; - var isHack = property.hack; - - if (property.unused) - continue; - - if (position > 0 && lastProperty && _name == lastName && isImportant == lastProperty.important && isHack == lastProperty.hack && sameValue(position) && !lastProperty.unused) { - property.unused = true; - continue; - } - - // comment is necessary - we assume that if two properties are one after another - // then it is intentional way of redefining property which may not be widely supported - // e.g. a{display:inline-block;display:-moz-inline-box} - // however if `mergeablePosition` yields true then the rule does not apply - // (e.g merging two adjacent selectors: `a{display:block}a{display:block}`) - if (_name in overrideMapping && (aggressiveMerging && _name != lastName || mergeablePosition(position))) { - var toOverridePositions = overrideMapping[_name]; - var canOverride = compactable[_name] && compactable[_name].canOverride; - var anyRemoved = false; - - for (j = toOverridePositions.length - 1; j >= 0; j--) { - var toRemove = properties[toOverridePositions[j]]; - var longhandToShorthand = toRemove.name != _name; - var wasImportant = toRemove.important; - var wasHack = toRemove.hack; - - if (toRemove.unused) - continue; - - if (longhandToShorthand && wasImportant) - continue; - - if (!wasImportant && (wasHack && !isHack || !wasHack && isHack)) - continue; - - if (wasImportant && (isHack == 'star' || isHack == 'underscore')) - continue; - - if (!wasHack && !isHack && !longhandToShorthand && canOverride && !canOverride(toRemove, property, validator)) - continue; - - if (wasImportant && !isImportant || wasImportant && isHack) { - property.unused = true; - lastProperty = property; - continue propertyLoop; - } else { - anyRemoved = true; - toRemove.unused = true; - } - } - - if (anyRemoved) { - position = -1; - lastProperty = null; - lastName = null; - overrideMapping = {}; - continue; - } - } else { - overrideMapping[_name] = overrideMapping[_name] || []; - overrideMapping[_name].push(position); - } - - lastName = _name; - lastProperty = property; - } -} - -function compactorOptimize(selector, properties, mergeAdjacent, withCompacting, overrideOptions, context) { +function compactorOptimize(selector, properties, withCompacting, overrideOptions, context) { var validator = context.validator; var warnings = context.warnings; - var _properties = wrapForOptimizing(properties, false); + var _property; + populateComponents(_properties, validator, warnings); - _optimize(_properties, mergeAdjacent, context.options.aggressiveMerging, validator); for (var i = 0, l = _properties.length; i < l; i++) { - var _property = _properties[i]; + _property = _properties[i]; if (_property.block) { - compactorOptimize(selector, _property.value[0][1], mergeAdjacent, withCompacting, overrideOptions, context); + compactorOptimize(selector, _property.value[0][1], withCompacting, overrideOptions, context); } } diff --git a/lib/optimizer/level-2/compacting/override-compactor.js b/lib/optimizer/level-2/compacting/override-compactor.js index a0f074756..e77284ace 100644 --- a/lib/optimizer/level-2/compacting/override-compactor.js +++ b/lib/optimizer/level-2/compacting/override-compactor.js @@ -1,11 +1,10 @@ var hasInherit = require('./has-inherit'); -var everyCombination = require('./every-combination'); +var everyValuesPair = require('./every-values-pair'); var findComponentIn = require('./find-component-in'); var isComponentOf = require('./is-component-of'); var overridesNonComponentShorthand = require('./overrides-non-component-shorthand'); var sameVendorPrefixesIn = require('./vendor-prefixes').same; -var canOverride = require('../can-override'); var compactable = require('../compactable'); var deepClone = require('../clone').deep; var deepClone = require('../clone').deep; @@ -28,8 +27,9 @@ function wouldBreakCompatibility(property, validator) { var _component = shallowClone(component); _component.value = [[Token.PROPERTY_VALUE, descriptor.defaultValue]]; - if (!canOverride(_component, component, validator)) + if (!everyValuesPair(canOverride.bind(null, validator), _component, component)) { return true; + } } return false; @@ -220,6 +220,7 @@ function compactOverrides(properties, compatibility, merging, validator) { var overriddenComponents; var overriddenComponent; var overridingComponent; + var overridable; var i, j, k; propertyLoop: @@ -232,7 +233,7 @@ function compactOverrides(properties, compatibility, merging, validator) { if (right.block) continue; - mayOverride = compactable[right.name].canOverride || canOverride.sameValue; + mayOverride = compactable[right.name].canOverride; traverseLoop: for (j = i - 1; j >= 0; j--) { @@ -247,7 +248,10 @@ function compactOverrides(properties, compatibility, merging, validator) { if (left.unused || right.unused) continue; - if (left.hack && !right.hack || !left.hack && right.hack) + if (left.hack && !right.hack && !right.important || !left.hack && !left.important && right.hack) + continue; + + if (left.important == right.important && left.hack != right.hack) continue; if (hasInherit(right)) @@ -268,8 +272,8 @@ function compactOverrides(properties, compatibility, merging, validator) { continue; component = findComponentIn(right, left); - mayOverride = (compactable[left.name] && compactable[left.name].canOverride) || canOverride.sameValue; - if (everyCombination(mayOverride, left, component, validator)) { + mayOverride = compactable[left.name].canOverride; + if (everyValuesPair(mayOverride.bind(null, validator), left, component)) { left.unused = true; } } else if (right.shorthand && overridesNonComponentShorthand(right, left)) { @@ -293,9 +297,9 @@ function compactOverrides(properties, compatibility, merging, validator) { for (k = overriddenComponents.length - 1; k >= 0; k--) { overriddenComponent = overriddenComponents[k]; overridingComponent = findComponentIn(right, overriddenComponent); - mayOverride = (overriddenComponent.name in compactable && compactable[overriddenComponent.name].canOverride) || canOverride.sameValue; + mayOverride = compactable[overriddenComponent.name].canOverride; - if (!everyCombination(mayOverride, left, overridingComponent, validator)) { + if (!everyValuesPair(mayOverride.bind(null, validator), left, overridingComponent)) { continue traverseLoop; } } @@ -319,7 +323,7 @@ function compactOverrides(properties, compatibility, merging, validator) { continue; component = findComponentIn(left, right); - if (everyCombination(mayOverride, component, right, validator)) { + if (everyValuesPair(mayOverride.bind(null, validator), component, right)) { var disabledBackgroundMerging = !compatibility.properties.backgroundClipMerging && component.name.indexOf('background-clip') > -1 || !compatibility.properties.backgroundOriginMerging && component.name.indexOf('background-origin') > -1 || @@ -364,10 +368,8 @@ function compactOverrides(properties, compatibility, merging, validator) { var leftComponent = left.components[k]; var rightComponent = right.components[k]; - mayOverride = compactable[leftComponent.name].canOverride || canOverride.sameValue; - if (!everyCombination(mayOverride, leftComponent, rightComponent, validator)) - continue propertyLoop; - if (!everyCombination(canOverride.twoOptionalFunctions, leftComponent, rightComponent, validator) && validator.isValidFunction(rightComponent)) + mayOverride = compactable[leftComponent.name].canOverride; + if (!everyValuesPair(mayOverride.bind(null, validator), leftComponent, rightComponent)) continue propertyLoop; } @@ -380,8 +382,8 @@ function compactOverrides(properties, compatibility, merging, validator) { continue; component = findComponentIn(left, right); - mayOverride = compactable[right.name].canOverride || canOverride.sameValue; - if (!everyCombination(mayOverride, component, right, validator)) + mayOverride = compactable[right.name].canOverride; + if (!everyValuesPair(mayOverride.bind(null, validator), component, right)) continue; if (left.important && !right.important) { @@ -398,15 +400,34 @@ function compactOverrides(properties, compatibility, merging, validator) { right.dirty = true; } else if (left.name == right.name) { // two non-shorthands should be merged based on understandability + overridable = true; - if (left.important && !right.important) { + if (right.shorthand) { + for (k = right.components.length - 1; k >= 0 && overridable; k--) { + overriddenComponent = left.components[k]; + overridingComponent = right.components[k]; + mayOverride = compactable[overridingComponent.name].canOverride; + + overridable = overridable && everyValuesPair(mayOverride.bind(null, validator), overriddenComponent, overridingComponent); + } + } else { + mayOverride = compactable[right.name].canOverride; + overridable = everyValuesPair(mayOverride.bind(null, validator), left, right); + } + + if (left.important && !right.important && overridable) { right.unused = true; continue; } - mayOverride = compactable[right.name].canOverride || canOverride.sameValue; - if (!everyCombination(mayOverride, left, right, validator)) + if (!left.important && right.important && overridable) { + left.unused = true; continue; + } + + if (!overridable) { + continue; + } left.unused = true; } diff --git a/lib/optimizer/level-2/compacting/shorthand-compactor.js b/lib/optimizer/level-2/compacting/shorthand-compactor.js index 34e8f0056..96501fe7e 100644 --- a/lib/optimizer/level-2/compacting/shorthand-compactor.js +++ b/lib/optimizer/level-2/compacting/shorthand-compactor.js @@ -1,4 +1,4 @@ -var everyCombination = require('./every-combination'); +var everyValuesPair = require('./every-values-pair'); var hasInherit = require('./has-inherit'); var populateComponents = require('./populate-components'); @@ -49,6 +49,7 @@ function replaceWithShorthand(properties, candidateComponents, name, validator) [Token.PROPERTY_NAME, name], [Token.PROPERTY_VALUE, descriptor.defaultValue] ]; + var mayOverride; var all; var newProperty = wrapSingle(newValuePlaceholder); @@ -59,12 +60,12 @@ function replaceWithShorthand(properties, candidateComponents, name, validator) for (var i = 0, l = descriptor.components.length; i < l; i++) { var component = candidateComponents[descriptor.components[i]]; - var canOverride = compactable[component.name].canOverride; if (hasInherit(component)) return; - if (!everyCombination(canOverride, newProperty.components[i], component, validator)) + mayOverride = compactable[component.name].canOverride; + if (!everyValuesPair(mayOverride.bind(null, validator), newProperty.components[i], component)) return; newProperty.components[i] = deepClone(component); diff --git a/lib/optimizer/level-2/compacting/understandable.js b/lib/optimizer/level-2/compacting/understandable.js new file mode 100644 index 000000000..6c77db50d --- /dev/null +++ b/lib/optimizer/level-2/compacting/understandable.js @@ -0,0 +1,15 @@ +var sameVendorPrefixes = require('./vendor-prefixes').same; + +function understandable(validator, value1, value2, _position, isPaired) { + if (!sameVendorPrefixes(value1, value2)) { + return false; + } + + if (isPaired && validator.isValidVariable(value1) !== validator.isValidVariable(value2)) { + return false; + } + + return true; +} + +module.exports = understandable; diff --git a/lib/optimizer/level-2/compacting/vendor-prefixes.js b/lib/optimizer/level-2/compacting/vendor-prefixes.js index 511fd604e..f9ab52728 100644 --- a/lib/optimizer/level-2/compacting/vendor-prefixes.js +++ b/lib/optimizer/level-2/compacting/vendor-prefixes.js @@ -1,26 +1,23 @@ -var VENDOR_PREFIX_PATTERN = /$\-moz\-|\-ms\-|\-o\-|\-webkit\-/; +var VENDOR_PREFIX_PATTERN = /(?:^|\W)(\-\w+\-)/g; -function prefixesIn(tokens) { +function unique(value) { var prefixes = []; + var match; - for (var i = 0, l = tokens.length; i < l; i++) { - var token = tokens[i]; - - for (var j = 0, m = token.value.length; j < m; j++) { - var match = VENDOR_PREFIX_PATTERN.exec(token.value[j][0]); - - if (match && prefixes.indexOf(match[0]) == -1) - prefixes.push(match[0]); + while ((match = VENDOR_PREFIX_PATTERN.exec(value)) !== null) { + if (prefixes.indexOf(match[0]) == -1) { + prefixes.push(match[0]); } } return prefixes; } -function same(left, right) { - return prefixesIn(left).sort().join(',') == prefixesIn(right).sort().join(','); +function same(value1, value2) { + return unique(value1).sort().join(',') == unique(value2).sort().join(','); } module.exports = { + unique: unique, same: same }; diff --git a/lib/optimizer/level-2/merge-adjacent.js b/lib/optimizer/level-2/merge-adjacent.js index 386a0b37e..bc00fc267 100644 --- a/lib/optimizer/level-2/merge-adjacent.js +++ b/lib/optimizer/level-2/merge-adjacent.js @@ -34,9 +34,8 @@ function mergeAdjacent(tokens, context) { } if (lastToken[0] == Token.RULE && serializeRules(token[1]) == serializeRules(lastToken[1])) { - var joinAt = [lastToken[2].length]; Array.prototype.push.apply(lastToken[2], token[2]); - compactorOptimize(token[1], lastToken[2], joinAt, true, OVERRIDE_OPTIONS, context); + compactorOptimize(token[1], lastToken[2], true, OVERRIDE_OPTIONS, context); token[2] = []; } else if (lastToken[0] == Token.RULE && serializeBody(token[2]) == serializeBody(lastToken[2]) && isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements) && diff --git a/lib/optimizer/level-2/merge-non-adjacent-by-selector.js b/lib/optimizer/level-2/merge-non-adjacent-by-selector.js index c5b53558e..3a142addd 100644 --- a/lib/optimizer/level-2/merge-non-adjacent-by-selector.js +++ b/lib/optimizer/level-2/merge-non-adjacent-by-selector.js @@ -50,7 +50,6 @@ function mergeNonAdjacentBySelector(tokens, context) { var moved = topToBottom ? tokenOne : tokenTwo; var target = topToBottom ? tokenTwo : tokenOne; var movedProperties = extractProperties(moved); - var joinAt; while (from != to) { var traversedProperties = extractProperties(tokens[from]); @@ -68,15 +67,13 @@ function mergeNonAdjacentBySelector(tokens, context) { } if (topToBottom) { - joinAt = [moved[2].length]; Array.prototype.push.apply(moved[2], target[2]); target[2] = moved[2]; } else { - joinAt = [target[2].length]; Array.prototype.push.apply(target[2], moved[2]); } - compactorOptimize(target[1], target[2], joinAt, true, OVERRIDE_OPTIONS, context); + compactorOptimize(target[1], target[2], true, OVERRIDE_OPTIONS, context); moved[2] = []; } } diff --git a/lib/optimizer/level-2/optimize.js b/lib/optimizer/level-2/optimize.js index a84a76a4c..60e614792 100644 --- a/lib/optimizer/level-2/optimize.js +++ b/lib/optimizer/level-2/optimize.js @@ -61,7 +61,7 @@ function recursivelyOptimizeProperties(tokens, context) { switch (token[0]) { case Token.RULE: - compactorOptimize(token[1], token[2], false, true, OVERRIDE_OPTIONS, context); + compactorOptimize(token[1], token[2], true, OVERRIDE_OPTIONS, context); break; case Token.BLOCK: recursivelyOptimizeProperties(token[2], context); diff --git a/lib/optimizer/level-2/reduce-non-adjacent.js b/lib/optimizer/level-2/reduce-non-adjacent.js index c71b0b211..18f4d9e44 100644 --- a/lib/optimizer/level-2/reduce-non-adjacent.js +++ b/lib/optimizer/level-2/reduce-non-adjacent.js @@ -146,7 +146,6 @@ function reduceComplexNonAdjacentCases(tokens, candidates, options, context) { function reduceSelector(tokens, selector, data, context, options, outerContext) { var bodies = []; var bodiesAsList = []; - var joinsAt = []; var processedTokens = []; for (var j = data.length - 1, m = 0; j >= 0; j--) { @@ -162,12 +161,7 @@ function reduceSelector(tokens, selector, data, context, options, outerContext) processedTokens.push(where); } - for (j = 0, m = bodiesAsList.length; j < m; j++) { - if (bodiesAsList[j].length > 0) - joinsAt.push((joinsAt.length > 0 ? joinsAt[joinsAt.length - 1] : 0) + bodiesAsList[j].length); - } - - compactorOptimize(selector, bodies, joinsAt, false, OVERRIDE_OPTIONS, outerContext); + compactorOptimize(selector, bodies, false, OVERRIDE_OPTIONS, outerContext); var processedCount = processedTokens.length; var propertyIdx = bodies.length - 1; diff --git a/lib/optimizer/validator.js b/lib/optimizer/validator.js index 4321a71ae..35f041ea9 100644 --- a/lib/optimizer/validator.js +++ b/lib/optimizer/validator.js @@ -1,219 +1,469 @@ -// Validates various CSS property values - -var widthKeywords = ['thin', 'thick', 'medium', 'inherit', 'initial']; -var allUnits = ['px', '%', 'em', 'in', 'cm', 'mm', 'ex', 'pt', 'pc', 'ch', 'rem', 'vh', 'vm', 'vmin', 'vmax', 'vw']; -var cssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + allUnits.join('|') + '|)|auto|inherit)'; +var Units = [ + '%', + 'ch', + 'cm', + 'em', + 'ex', + 'in', + 'mm', + 'pc', + 'pt', + 'px', + 'rem', + 'vh', + 'vm', + 'vmax', + 'vmin', + 'vw' +]; +var cssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + Units.join('|') + '|)|auto|inherit)'; var cssCalcRegexStr = '(\\-moz\\-|\\-webkit\\-)?calc\\([^\\)]+\\)'; var cssFunctionNoVendorRegexStr = '[A-Z]+(\\-|[A-Z]|[0-9])+\\(.*?\\)'; var cssFunctionVendorRegexStr = '\\-(\\-|[A-Z]|[0-9])+\\(.*?\\)'; var cssVariableRegexStr = 'var\\(\\-\\-[^\\)]+\\)'; var cssFunctionAnyRegexStr = '(' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')'; var cssUnitOrCalcRegexStr = '(' + cssUnitRegexStr + '|' + cssCalcRegexStr + ')'; -var cssUnitAnyRegexStr = '(none|' + widthKeywords.join('|') + '|' + cssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')'; var cssFunctionNoVendorRegex = new RegExp('^' + cssFunctionNoVendorRegexStr + '$', 'i'); -var cssFunctionVendorRegex = new RegExp('^' + cssFunctionVendorRegexStr + '$', 'i'); var cssVariableRegex = new RegExp('^' + cssVariableRegexStr + '$', 'i'); var cssFunctionAnyRegex = new RegExp('^' + cssFunctionAnyRegexStr + '$', 'i'); var cssUnitRegex = new RegExp('^' + cssUnitRegexStr + '$', 'i'); var cssUnitOrCalcRegex = new RegExp('^' + cssUnitOrCalcRegexStr + '$', 'i'); -var cssUnitAnyRegex = new RegExp('^' + cssUnitAnyRegexStr + '$', 'i'); var urlRegex = /^url\([\s\S]+\)$/i; -var backgroundRepeatKeywords = ['repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'inherit']; -var backgroundAttachmentKeywords = ['inherit', 'scroll', 'fixed', 'local']; -var backgroundPositionKeywords = ['center', 'top', 'bottom', 'left', 'right']; -var backgroundSizeKeywords = ['contain', 'cover']; -var backgroundBoxKeywords = ['border-box', 'content-box', 'padding-box']; -var styleKeywords = ['auto', 'inherit', 'hidden', 'none', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset']; -var listStyleTypeKeywords = ['armenian', 'circle', 'cjk-ideographic', 'decimal', 'decimal-leading-zero', 'disc', 'georgian', 'hebrew', 'hiragana', 'hiragana-iroha', 'inherit', 'katakana', 'katakana-iroha', 'lower-alpha', 'lower-greek', 'lower-latin', 'lower-roman', 'none', 'square', 'upper-alpha', 'upper-latin', 'upper-roman']; -var listStylePositionKeywords = ['inside', 'outside', 'inherit']; +var globalKeywords = [ + 'inherit', + 'initial', + 'unset' +]; + +var Keywords = { + '*-style': [ + 'auto', + 'dashed', + 'dotted', + 'double', + 'groove', + 'hidden', + 'inset', + 'none', + 'outset', + 'ridge', + 'solid' + ], + 'background-attachment': [ + 'fixed', + 'inherit', + 'local', + 'scroll' + ], + 'background-clip': [ + 'border-box', + 'content-box', + 'inherit', + 'padding-box', + 'text' + ], + 'background-origin': [ + 'border-box', + 'content-box', + 'inherit', + 'padding-box' + ], + 'background-position': [ + 'bottom', + 'center', + 'left', + 'right', + 'top' + ], + 'background-repeat': [ + 'no-repeat', + 'inherit', + 'repeat', + 'repeat-x', + 'repeat-y', + 'round', + 'space' + ], + 'background-size': [ + 'auto', + 'cover', + 'contain' + ], + 'border-collapse': [ + 'collapse', + 'inherit', + 'separate' + ], + 'bottom': [ + 'auto' + ], + 'clear': [ + 'both', + 'left', + 'none', + 'right' + ], + 'cursor': [ + 'all-scroll', + 'auto', + 'col-resize', + 'crosshair', + 'default', + 'e-resize', + 'help', + 'move', + 'n-resize', + 'ne-resize', + 'no-drop', + 'not-allowed', + 'nw-resize', + 'pointer', + 'progress', + 'row-resize', + 's-resize', + 'se-resize', + 'sw-resize', + 'text', + 'vertical-text', + 'w-resize', + 'wait' + ], + 'display': [ + 'block', + 'inline', + 'inline-block', + 'inline-table', + 'list-item', + 'none', + 'table', + 'table-caption', + 'table-cell', + 'table-column', + 'table-column-group', + 'table-footer-group', + 'table-header-group', + 'table-row', + 'table-row-group' + ], + 'float': [ + 'left', + 'none', + 'right' + ], + 'left': [ + 'auto' + ], + 'font-style': [ + 'italic', + 'normal', + 'oblique' + ], + 'font-weight': [ + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900', + 'bold', + 'bolder', + 'lighter', + 'normal' + ], + 'list-style-position': [ + 'inside', + 'outside' + ], + 'list-style-type': [ + 'armenian', + 'circle', + 'decimal', + 'decimal-leading-zero', + 'disc', + 'decimal|disc', // this is the default value of list-style-type, see comment in compactable.js + 'georgian', + 'lower-alpha', + 'lower-greek', + 'lower-latin', + 'lower-roman', + 'none', + 'square', + 'upper-alpha', + 'upper-latin', + 'upper-roman' + ], + 'overflow': [ + 'auto', + 'hidden', + 'scroll', + 'visible' + ], + 'position': [ + 'absolute', + 'fixed', + 'relative', + 'static' + ], + 'right': [ + 'auto' + ], + 'text-align': [ + 'center', + 'justify', + 'left', + 'left|right', // this is the default value of list-style-type, see comment in compactable.js + 'right' + ], + 'text-decoration': [ + 'line-through', + 'none', + 'overline', + 'underline' + ], + 'text-overflow': [ + 'clip', + 'ellipsis' + ], + 'top': [ + 'auto' + ], + 'vertical-align': [ + 'baseline', + 'bottom', + 'middle', + 'sub', + 'super', + 'text-bottom', + 'text-top', + 'top' + ], + 'visibility': [ + 'collapse', + 'hidden', + 'visible' + ], + 'white-space': [ + 'normal', + 'nowrap', + 'pre' + ], + 'width': [ + 'inherit', + 'initial', + 'medium', + 'thick', + 'thin' + ] +}; + +var VENDOR_PREFIX_PATTERN = /(^|\W)-\w+\-/; + +function areSameFunction(value1, value2) { + if (!isValidFunction(value1) || !isValidFunction(value2)) { + return false; + } -function isValidHexColor(s) { - return (s.length === 4 || s.length === 7) && s[0] === '#'; -} + var function1Name = value1.substring(0, value1.indexOf('(')); + var function2Name = value2.substring(0, value2.indexOf('(')); -function isValidRgbaColor(s) { - s = s.split(' ').join(''); - return s.length > 0 && s.indexOf('rgba(') === 0 && s.indexOf(')') === s.length - 1; + return function1Name === function2Name; } -function isValidHslaColor(s) { - s = s.split(' ').join(''); - return s.length > 0 && s.indexOf('hsla(') === 0 && s.indexOf(')') === s.length - 1; +function hasNoVendorPrefix(value) { + return VENDOR_PREFIX_PATTERN.test(value); } -function isValidNamedColor(s) { - // We don't really check if it's a valid color value, but allow any letters in it - return s !== 'auto' && (s === 'transparent' || s === 'inherit' || /^[a-zA-Z]+$/.test(s)); +function isValidBackgroundAttachment(value) { + return Keywords['background-attachment'].indexOf(value) > -1; } -function isValidVariable(s) { - return cssVariableRegex.test(s); +function isValidBackgroundClip(value) { + return Keywords['background-clip'].indexOf(value) > -1; } -function isValidColor(s) { - return isValidNamedColor(s) || - isValidColorValue(s) || - isValidVariable(s) || - isValidVendorPrefixedValue(s); +function isValidBackgroundRepeat(value) { + return Keywords['background-repeat'].indexOf(value) > -1; } -function isValidColorValue(s) { - return isValidHexColor(s) || - isValidRgbaColor(s) || - isValidHslaColor(s); +function isValidBackgroundOrigin(value) { + return Keywords['background-origin'].indexOf(value) > -1; } -function isValidUrl(s) { - return urlRegex.test(s); -} +function isValidBackgroundPosition(value) { + var parts; + var i, l; -function isValidUnit(s) { - return cssUnitAnyRegex.test(s); -} + if (value === 'inherit') { + return true; + } + + parts = value.split(' '); + for (i = 0, l = parts.length; i < l; i++) { + if (parts[i] === '') { + continue; + } else if (isValidBackgroundPositionPart(parts[i])) { + continue; + } + + return false; + } -function isValidUnitWithoutFunction(s) { - return cssUnitRegex.test(s); + return true; } -function isValidAndCompatibleUnit(compatibleCssUnitAnyRegex, s) { - return compatibleCssUnitAnyRegex.test(s); +function isValidBackgroundPositionPart(value) { + return Keywords['background-position'].indexOf(value) > -1 || cssUnitOrCalcRegex.test(value); } -function isValidAndCompatibleUnitWithoutFunction(compatibleCssUnitRegex, s) { - return compatibleCssUnitRegex.test(s); +function isValidBackgroundSizePart(value) { + return Keywords['background-size'].indexOf(value) > -1 || cssUnitRegex.test(value); } -function isValidFunctionWithoutVendorPrefix(s) { - return !urlRegex.test(s) && cssFunctionNoVendorRegex.test(s); +function isValidColor(value) { + return isValidNamedColor(value) || + isValidColorValue(value); } -function isValidFunctionWithVendorPrefix(s) { - return !urlRegex.test(s) && cssFunctionVendorRegex.test(s); +function isValidColorValue(value) { + return isValidHexColor(value) || + isValidRgbaColor(value) || + isValidHslaColor(value); } -function isValidFunction(s) { - return !urlRegex.test(s) && cssFunctionAnyRegex.test(s); +function isValidFunction(value) { + return !urlRegex.test(value) && cssFunctionAnyRegex.test(value); } -function isValidBackgroundRepeat(s) { - return backgroundRepeatKeywords.indexOf(s) >= 0 || isValidVariable(s); +function isValidFunctionWithoutVendorPrefix(value) { + return !urlRegex.test(value) && cssFunctionNoVendorRegex.test(value); } -function isValidBackgroundAttachment(s) { - return backgroundAttachmentKeywords.indexOf(s) >= 0 || isValidVariable(s); +function isValidGlobalValue(value) { + return globalKeywords.indexOf(value) > -1; } -function isValidBackgroundBox(s) { - return backgroundBoxKeywords.indexOf(s) >= 0 || isValidVariable(s); +function isValidHexColor(value) { + return (value.length === 4 || value.length === 7) && value[0] === '#'; } -function isValidBackgroundPositionPart(s) { - return backgroundPositionKeywords.indexOf(s) >= 0 || cssUnitOrCalcRegex.test(s) || isValidVariable(s); +function isValidHslaColor(value) { + return value.length > 0 && value.indexOf('hsla(') === 0 && value.indexOf(')') === value.length - 1; } -function isValidBackgroundPosition(s) { - if (s === 'inherit') - return true; +function isValidImage(value) { + return value == 'none' || value == 'inherit' || isValidUrl(value); +} - var parts = s.split(' '); - for (var i = 0, l = parts.length; i < l; i++) { - if (parts[i] === '') - continue; - if (isValidBackgroundPositionPart(parts[i]) || isValidVariable(parts[i])) - continue; +function isValidKeywordValue(propertyName, value, includeGlobal) { + return Keywords[propertyName].indexOf(value) > -1 || includeGlobal && isValidGlobalValue(value); +} - return false; - } +function isValidListStyleType(value) { + return Keywords['list-style-type'].indexOf(value) > -1; +} - return true; +function isValidListStylePosition(value) { + return Keywords['list-style-position'].indexOf(value) > -1; } -function isValidBackgroundSizePart(s) { - return backgroundSizeKeywords.indexOf(s) >= 0 || cssUnitRegex.test(s) || isValidVariable(s); +function isValidNamedColor(value) { + // We don't really check if it's a valid color value, but allow any letters in it + return value !== 'auto' && (value === 'transparent' || value === 'inherit' || /^[a-zA-Z]+$/.test(value)); } -function isValidListStyleType(s) { - return listStyleTypeKeywords.indexOf(s) >= 0 || isValidVariable(s); +function isValidRgbaColor(value) { + return value.length > 0 && value.indexOf('rgba(') === 0 && value.indexOf(')') === value.length - 1; } -function isValidListStylePosition(s) { - return listStylePositionKeywords.indexOf(s) >= 0 || isValidVariable(s); +function isValidStyle(value) { + return Keywords['*-style'].indexOf(value) > -1; } -function isValidStyle(s) { - return isValidStyleKeyword(s) || isValidVariable(s); +function isValidTextShadow(compatibleCssUnitRegex, value) { + return isValidUnitWithoutFunction(compatibleCssUnitRegex, value) || + isValidColor(value) || + isValidGlobalValue(value); } -function isValidStyleKeyword(s) { - return styleKeywords.indexOf(s) >= 0; +function isValidUnit(compatibleCssUnitAnyRegex, value) { + return compatibleCssUnitAnyRegex.test(value); } -function isValidWidth(s) { - return isValidUnit(s) || isValidWidthKeyword(s) || isValidVariable(s); +function isValidUnitWithoutFunction(compatibleCssUnitRegex, value) { + return compatibleCssUnitRegex.test(value); } -function isValidWidthKeyword(s) { - return widthKeywords.indexOf(s) >= 0; +function isValidUrl(value) { + return urlRegex.test(value); } -function isValidVendorPrefixedValue(s) { - return /^-([A-Za-z0-9]|-)*$/gi.test(s); +function isValidVariable(value) { + return cssVariableRegex.test(value); } -function areSameFunction(a, b) { - if (!isValidFunction(a) || !isValidFunction(b)) - return false; +function isValidVendorPrefixedValue(value) { + return /^-([A-Za-z0-9]|-)*$/gi.test(value); +} - var f1name = a.substring(0, a.indexOf('(')); - var f2name = b.substring(0, b.indexOf('(')); +function isValidWidth(compatibleCssUnitRegex, value) { + return isValidUnit(compatibleCssUnitRegex, value) || Keywords.width.indexOf(value) > -1; +} - return f1name === f2name; +function isValidZIndex(value) { + return value == 'auto' || + isValidGlobalValue(value) || + value.length > 0 && value == ('' + parseInt(value)); } function validator(compatibility) { - var validUnits = allUnits.slice(0).filter(function (value) { + var validUnits = Units.slice(0).filter(function (value) { return !(value in compatibility.units) || compatibility.units[value] === true; }); var compatibleCssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + '|)|auto|inherit)'; var compatibleCssUnitRegex = new RegExp('^' + compatibleCssUnitRegexStr + '$', 'i'); - var compatibleCssUnitAnyRegex = new RegExp('^(none|' + widthKeywords.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i'); + var compatibleCssUnitAnyRegex = new RegExp('^(none|' + Keywords.width.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i'); var colorOpacity = compatibility.colors.opacity; return { + areSameFunction: areSameFunction, colorOpacity: colorOpacity, - isValidHexColor: isValidHexColor, - isValidRgbaColor: isValidRgbaColor, - isValidHslaColor: isValidHslaColor, - isValidNamedColor: isValidNamedColor, - isValidVariable: isValidVariable, - isValidColor: isValidColor, - isValidColorValue: isValidColorValue, - isValidUrl: isValidUrl, - isValidUnit: isValidUnit, - isValidUnitWithoutFunction: isValidUnitWithoutFunction, - isValidAndCompatibleUnit: isValidAndCompatibleUnit.bind(null, compatibleCssUnitAnyRegex), - isValidAndCompatibleUnitWithoutFunction: isValidAndCompatibleUnitWithoutFunction.bind(null, compatibleCssUnitRegex), - isValidFunctionWithoutVendorPrefix: isValidFunctionWithoutVendorPrefix, - isValidFunctionWithVendorPrefix: isValidFunctionWithVendorPrefix, - isValidFunction: isValidFunction, - isValidBackgroundRepeat: isValidBackgroundRepeat, + hasNoVendorPrefix: hasNoVendorPrefix, isValidBackgroundAttachment: isValidBackgroundAttachment, - isValidBackgroundBox: isValidBackgroundBox, - isValidBackgroundPositionPart: isValidBackgroundPositionPart, + isValidBackgroundClip: isValidBackgroundClip, + isValidBackgroundOrigin: isValidBackgroundOrigin, isValidBackgroundPosition: isValidBackgroundPosition, + isValidBackgroundPositionPart: isValidBackgroundPositionPart, + isValidBackgroundRepeat: isValidBackgroundRepeat, isValidBackgroundSizePart: isValidBackgroundSizePart, - isValidListStyleType: isValidListStyleType, + isValidColor: isValidColor, + isValidColorValue: isValidColorValue, + isValidFunction: isValidFunction, + isValidFunctionWithoutVendorPrefix: isValidFunctionWithoutVendorPrefix, + isValidGlobalValue: isValidGlobalValue, + isValidHexColor: isValidHexColor, + isValidHslaColor: isValidHslaColor, + isValidImage: isValidImage, + isValidKeywordValue: isValidKeywordValue, isValidListStylePosition: isValidListStylePosition, + isValidListStyleType: isValidListStyleType, + isValidNamedColor: isValidNamedColor, + isValidRgbaColor: isValidRgbaColor, isValidStyle: isValidStyle, - isValidStyleKeyword: isValidStyleKeyword, - isValidWidth: isValidWidth, - isValidWidthKeyword: isValidWidthKeyword, + isValidTextShadow: isValidTextShadow.bind(null, compatibleCssUnitRegex), + isValidUnit: isValidUnit.bind(null, compatibleCssUnitAnyRegex), + isValidUnitWithoutFunction: isValidUnitWithoutFunction.bind(null, compatibleCssUnitRegex), + isValidUrl: isValidUrl, + isValidVariable: isValidVariable, isValidVendorPrefixedValue: isValidVendorPrefixedValue, - areSameFunction: areSameFunction + isValidWidth: isValidWidth.bind(null, compatibleCssUnitRegex), + isValidZIndex: isValidZIndex }; } diff --git a/test/binary-test.js b/test/binary-test.js index ec3635625..160f7905c 100644 --- a/test/binary-test.js +++ b/test/binary-test.js @@ -447,12 +447,12 @@ vows.describe('./bin/cleancss') }) .addBatch({ 'neighbour merging': { - 'of (yet) unmergeable properties': pipedContext('a{display:inline-block;color:red;display:-moz-block}', '-O2 --skip-aggressive-merging', { + 'of unmergeable properties': pipedContext('a{display:inline-block;color:red;display:-moz-block}', '-O2', { 'gets right result': function (error, stdout) { assert.equal(stdout, 'a{display:inline-block;color:red;display:-moz-block}'); } }), - 'of mergeable properties': pipedContext('a{background:red;display:block;background:white}', '-O2 --skip-aggressive-merging', { + 'of mergeable properties': pipedContext('a{background:red;display:block;background:white}', '-O2', { 'gets right result': function (error, stdout) { assert.equal(stdout, 'a{background:#fff;display:block}'); } diff --git a/test/fixtures/big-min.css b/test/fixtures/big-min.css index 65ba94193..78dd57a90 100644 --- a/test/fixtures/big-min.css +++ b/test/fixtures/big-min.css @@ -212,7 +212,6 @@ section article{margin:0 0 16px} .type_element{white-space:nowrap} .nature_edito{font-weight:400;font-size:16px;font-family:FetteEngschrift,'Arial Narrow',sans-serif} .bloc_bg_gris2{background:#f8f9fb;padding:8px 16px} -.bt_fonce a,.btn,.btn_abo,.btn_fonce,.btn_petit{background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(enabled=false)} .mgl5{margin-left:5px} .mgr5{margin-right:5px} .mgb5{margin-bottom:5px} @@ -254,9 +253,10 @@ section article{margin:0 0 16px} .bloc_abo{border-top:3px solid #ffd500} img[width="312"],img[width="642"]{margin-bottom:6px} img[width="202"]{margin-bottom:4px} -.btn,.btn_abo,.btn_fonce,.btn_petit{display:inline-block;padding:4px 10px;margin-bottom:0;color:#000b15;text-align:center;font-weight:700;vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(top,#fff,#e6e6e6);border:1px solid #ccc;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);cursor:pointer} -.bt_fonce a,.btn_fonce{color:#fff;background-color:#000b15;background-image:-moz-linear-gradient(top,#5d666d,#000b15);background-image:-ms-linear-gradient(top,#5d666d,#000b15);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5d666d),to(#000b15));background-image:-webkit-linear-gradient(top,#5d666d,#000b15);background-image:-o-linear-gradient(top,#5d666d,#000b15);background-image:linear-gradient(top,#5d666d,#000b15);border-color:#000b15;border-color:rgba(0,0,0,.1)} -.btn_abo{color:#000b15;background-color:#ffc600;background-image:-moz-linear-gradient(top,#ffe562,#ffc600);background-image:-ms-linear-gradient(top,#ffe562,#ffc600);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ffe562),to(#ffc600));background-image:-webkit-linear-gradient(top,#ffe562,#ffc600);background-image:-o-linear-gradient(top,#ffe562,#ffc600);background-image:linear-gradient(top,#ffe562,#ffc600);border-color:#ffc600;border-color:rgba(0,0,0,.1)} +.btn,.btn_abo,.btn_fonce,.btn_petit{display:inline-block;padding:4px 10px;margin-bottom:0;color:#000b15;text-align:center;font-weight:700;vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);border:1px solid #ccc;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);cursor:pointer} +.bt_fonce a,.btn_abo,.btn_fonce{background-repeat:repeat-x;border-color:rgba(0,0,0,.1)} +.bt_fonce a,.btn_fonce{color:#fff;background-color:#000b15;background-image:-moz-linear-gradient(top,#5d666d,#000b15);background-image:-ms-linear-gradient(top,#5d666d,#000b15);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5d666d),to(#000b15));background-image:-webkit-linear-gradient(top,#5d666d,#000b15);background-image:-o-linear-gradient(top,#5d666d,#000b15);background-image:linear-gradient(top,#5d666d,#000b15);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5d666d', endColorstr='#000b15', GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)} +.btn_abo{color:#000b15;background-color:#ffc600;background-image:-moz-linear-gradient(top,#ffe562,#ffc600);background-image:-ms-linear-gradient(top,#ffe562,#ffc600);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ffe562),to(#ffc600));background-image:-webkit-linear-gradient(top,#ffe562,#ffc600);background-image:-o-linear-gradient(top,#ffe562,#ffc600);background-image:linear-gradient(top,#ffe562,#ffc600);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe562', endColorstr='#ffc600', GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)} .az,.titre_bt_fleche .bt{float:right;border-left:1px solid #e4e6e9} .haut_rubrique,.titres_abonnes{border-bottom:6px solid #e9edf0} .btn.large{width:100%;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box} @@ -745,11 +745,11 @@ img[height="97"]+.ico29x29{bottom:6%;left:3.5%} .conteneur_carrousel .repere.actif,.conteneur_carrousel .repere:hover{background-position:-11px -24px;cursor:pointer} .conteneur_carrousel img{display:block;border:0} .portfolio_appel_revolutionnaire .portfolio_data_container h2,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .reperes{display:none} -.portfolio_appel_revolutionnaire .portfolio_data_container{position:absolute;left:0;right:0;bottom:0;background:#000;background:rgba(0,0,0,.8);color:#fff;text-shadow:0 1px 0 #000;padding:16px;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";opacity:0;-webkit-transition:opacity 1s;-moz-transition:opacity 1s;-o-transition:opacity 1s;transition:opacity 1s} +.portfolio_appel_revolutionnaire .portfolio_data_container{position:absolute;left:0;right:0;bottom:0;background:rgba(0,0,0,.8);color:#fff;text-shadow:0 1px 0 #000;padding:16px;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";opacity:0;-webkit-transition:opacity 1s;-moz-transition:opacity 1s;-o-transition:opacity 1s;transition:opacity 1s} .portfolio_appel_revolutionnaire .elt.shown .portfolio_data_container{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";opacity:.8} .portfolio_appel_revolutionnaire .portfolio_data_container .credits{opacity:.5;padding-left:4px} .portfolio_appel_revolutionnaire .carrousel .elt{width:644px;height:322px} -.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .precedent,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant{position:absolute;top:0;left:0;width:165px;height:322px;background:#000;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=60)";background:rgba(0,0,0,.6)} +.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .precedent,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant{position:absolute;top:0;left:0;width:165px;height:322px;background:rgba(0,0,0,.6);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"} .portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .precedent:hover,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant:hover{cursor:pointer} .portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .precedent span,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant span{display:block;margin:111px 0 0;text-indent:0;font-size:72px;width:40px;height:100px;line-height:95px;text-align:center;background:#fff;background:-moz-linear-gradient(left,#eee 0,#fff 50%,#fff 100%);background:-webkit-gradient(linear,left center,right center,color-stop(0,#eee),color-stop(50%,#fff),color-stop(100%,#fff));background:-webkit-linear-gradient(left,#eee 0,#fff 50%,#fff 100%);background:-o-linear-gradient(left,#eee 0,#fff 50%,#fff 100%);background:-ms-linear-gradient(left,#eee 0,#fff 50%,#fff 100%);background:linear-gradient(left,#eee 0,#fff 50%,#fff 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0 );border:solid #ddd;border-width:0 0 0 1px;box-shadow:0 0 1px 1px #000;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";opacity:.2;-webkit-transition:opacity 1s;-moz-transition:opacity 1s;-o-transition:opacity 1s;transition:opacity 1s} .portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant span{border-width:0 1px 0 0;margin:111px 0 0 124px;background:-moz-linear-gradient(left,#fff 0,#fff 55%,#eee 100%);background:-webkit-gradient(linear,left center,right center,color-stop(0,#fff),color-stop(55%,#fff),color-stop(100%,#eee));background:-webkit-linear-gradient(left,#fff 0,#fff 55%,#eee 100%);background:-o-linear-gradient(left,#fff 0,#fff 55%,#eee 100%);background:-ms-linear-gradient(left,#fff 0,#fff 55%,#eee 100%);background:linear-gradient(left,#fff 0,#fff 55%,#eee 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0 )} @@ -1574,7 +1574,7 @@ img.spacer{width:1px;height:1px} #header-liberation .header-base .nav .nav1 a:hover{text-decoration:none} #header-liberation .header-base .nav .nav2{position:absolute;z-index:5000;bottom:0;left:0;width:100%} #header-liberation .header-base .nav .nav2 li{display:block;float:left} -#header-liberation .header-base .nav .nav2 li a{position:relative;display:block} +#header-liberation .header-base .nav .nav2 li a{position:relative} #core-liberation form p{padding-top:10px;padding-bottom:10px} ul.errorlist{background:#fafafa;border:1px solid #e20000;color:#2e2e2e;margin:0 0 5px;padding:5px} ul.errorlist li{font-size:11px;font-weight:400;color:#e20000} @@ -1697,7 +1697,7 @@ body.iframe{padding-top:0} #header-liberation .header-base .nav .nav1 .on a span,#header-liberation .header-base .nav .nav1 a:hover span,#header-liberation .header-base .nav-no-js>li:hover .nav1 a span{width:9px;height:9px} #header-liberation .header-base .nav .nav2{display:none;height:28px} #header-liberation .header-base .nav .on .nav2{display:block} -#header-liberation .header-base .nav .nav2 li a{height:26px;padding:6px 24px 0 0;font-size:12px;font-family:Arial,Verdana,sans-serif;text-transform:none} +#header-liberation .header-base .nav .nav2 li a{display:block;height:26px;padding:6px 24px 0 0;font-size:12px;font-family:Arial,Verdana,sans-serif;text-transform:none} #header-liberation .header-base .nav .nav2 li a:hover{text-decoration:none} #header-liberation .header-base .nav .nav2 li.on{font-weight:700} #header-liberation .header-base .nav .nav2 li a span{display:block;position:absolute;top:6px;right:11px;width:1px;height:13px;left:auto} diff --git a/test/fixtures/bootstrap-min.css b/test/fixtures/bootstrap-min.css index 98b77c113..84507d8f6 100644 --- a/test/fixtures/bootstrap-min.css +++ b/test/fixtures/bootstrap-min.css @@ -22,7 +22,7 @@ sub{bottom:-.25em} img{border:0} hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} *,:after,:before,input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box} -code,kbd,pre,samp{font-size:1em} +code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em} button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit} .glyphicon,address{font-style:normal} button{overflow:visible} @@ -30,8 +30,10 @@ button,select{text-transform:none} button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer} button[disabled],html input[disabled]{cursor:default} button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0} +input{line-height:normal} input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0} input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto} +input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield} input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none} td,th{padding:0} @media print{ @@ -811,7 +813,7 @@ tbody.collapse.in{display:table-row-group} .collapsing{height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility} .caret{display:inline-block;width:0;height:0;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent} .dropdown-toggle:focus{outline:0} -.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)} .dropdown-header,.dropdown-menu>li>a{padding:3px 20px;white-space:nowrap;display:block;line-height:1.42857143} .btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group-vertical>.btn:not(:first-child):not(:last-child),.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0} .dropdown-menu.pull-right{right:0;left:auto} @@ -1266,7 +1268,7 @@ a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-gro .embed-responsive.embed-responsive-16by9{padding-bottom:56.25%} .embed-responsive.embed-responsive-4by3{padding-bottom:75%} .well{min-height:20px;padding:19px;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)} -.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)} +.well blockquote{border-color:rgba(0,0,0,.15)} .well-lg{padding:24px;border-radius:6px} .well-sm{padding:9px;border-radius:3px} .close{float:right;font-size:21px;font-weight:700;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2} @@ -1280,7 +1282,7 @@ button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;bor .modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)} .modal-open .modal{overflow-x:hidden;overflow-y:auto} .modal-dialog{position:relative;width:auto;margin:10px} -.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)} +.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)} .modal-backdrop{position:absolute;top:0;right:0;left:0;background-color:#000} .modal-backdrop.in{filter:alpha(opacity=50);opacity:.5} .modal-header{min-height:16.42857143px;padding:15px;border-bottom:1px solid #e5e5e5} @@ -1318,7 +1320,7 @@ button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;bor .tooltip.bottom .tooltip-arrow{left:50%;margin-left:-5px} .tooltip.bottom-left .tooltip-arrow{right:5px;margin-top:-5px} .tooltip.bottom-right .tooltip-arrow{left:5px;margin-top:-5px} -.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-size:14px;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)} +.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-size:14px;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)} .popover.top{margin-top:-10px} .popover.right{margin-left:10px} .popover.bottom{margin-top:10px} @@ -1329,14 +1331,14 @@ button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;bor .carousel,.carousel-inner{position:relative} .popover>.arrow{border-width:11px} .popover>.arrow:after{content:"";border-width:10px} -.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0} +.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:rgba(0,0,0,.25);border-bottom-width:0} .popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0} -.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0} +.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25);border-left-width:0} .popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0} -.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)} +.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:rgba(0,0,0,.25)} .carousel-inner>.active,.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0} .popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff} -.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)} +.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:rgba(0,0,0,.25)} .popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff} .carousel-inner{width:100%;overflow:hidden} .carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left} diff --git a/test/integration-test.js b/test/integration-test.js index 7407e2c1b..df1d6415c 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -2203,18 +2203,6 @@ vows.describe('integration tests') ] }) ) - .addBatch( - optimizerContext('duplicate properties with aggressive merging disabled', { - 'of (yet) unmergeable properties': [ - 'a{display:inline-block;color:red;display:-moz-block}', - 'a{display:inline-block;color:red;display:-moz-block}' - ], - 'of mergeable properties': [ - 'a{background:red;display:block;background:white}', - 'a{background:#fff;display:block}' - ] - }, { aggressiveMerging: false, level: 2 }) - ) .addBatch( optimizerContext('rerun optimizers', { 'selectors reducible once': [ diff --git a/test/module-test.js b/test/module-test.js index a3ede008a..baa5bc834 100644 --- a/test/module-test.js +++ b/test/module-test.js @@ -315,14 +315,6 @@ vows.describe('module tests').addBatch({ assert.equal(minified.styles, 'a{color:#fff}'); } }, - 'aggressive merging': { - 'topic': function () { - return new CleanCSS({ level: { 2: { aggressiveMerging: true } } }).minify('a{display:block;color:red;display:inline-block}'); - }, - 'gets right output': function (minified) { - assert.equal(minified.styles, 'a{color:red;display:inline-block}'); - } - }, 'process import': { 'topic': function () { return new CleanCSS({ inline: 'all' }).minify('@import url(/test/fixtures/partials/one.css);'); diff --git a/test/optimizer/level-2/break-up-test.js b/test/optimizer/level-2/break-up-test.js index fd220f3f7..2e4ba1c92 100644 --- a/test/optimizer/level-2/break-up-test.js +++ b/test/optimizer/level-2/break-up-test.js @@ -844,7 +844,7 @@ vows.describe(breakUp) }, 'has border-top-style': function (components) { assert.equal(components[0].name, 'list-style-type'); - assert.deepEqual(components[0].value, [['property-value', '__hack']]); + assert.deepEqual(components[0].value, [['property-value', 'decimal|disc']]); }, 'has border-right-style': function (components) { assert.equal(components[1].name, 'list-style-position'); diff --git a/test/optimizer/level-2/compacting/longhand-overriding-test.js b/test/optimizer/level-2/compacting/longhand-overriding-test.js index fb58d8816..2302debb4 100644 --- a/test/optimizer/level-2/compacting/longhand-overriding-test.js +++ b/test/optimizer/level-2/compacting/longhand-overriding-test.js @@ -17,7 +17,6 @@ function _optimize(source) { var compat = compatibility(); var options = { - aggressiveMerging: true, compatibility: compat, level: { 2: { @@ -31,7 +30,6 @@ function _optimize(source) { optimize( tokens[0][1], tokens[0][2], - false, true, { enabled: true, merging: true }, { options: options, validator: validator(compat) } @@ -81,7 +79,9 @@ function overrideContext(longhands) { var defaultValues = { 'list-style-image': 'none', 'background': '0 0', - 'border-color': 'red' + 'border-color': 'red', + 'border-style': 'none', + 'list-style': 'none' }; for (var longhand in longhands) { diff --git a/test/optimizer/level-2/compacting/optimize-test.js b/test/optimizer/level-2/compacting/optimize-test.js index 010d395a1..d7927ade4 100644 --- a/test/optimizer/level-2/compacting/optimize-test.js +++ b/test/optimizer/level-2/compacting/optimize-test.js @@ -8,10 +8,9 @@ var inputSourceMapTracker = require('../../../../lib/reader/input-source-map-tra var compatibility = require('../../../../lib/utils/compatibility'); var validator = require('../../../../lib/optimizer/validator'); -function _optimize(source, mergeAdjacent, aggressiveMerging, compatibilityOptions) { +function _optimize(source, compatibilityOptions) { var compat = compatibility(compatibilityOptions); var options = { - aggressiveMerging: aggressiveMerging, compatibility: compat, level: { 2: { @@ -31,7 +30,6 @@ function _optimize(source, mergeAdjacent, aggressiveMerging, compatibilityOption optimize( tokens[0][1], tokens[0][2], - mergeAdjacent, true, { enabled: true, merging: true }, { options: options, validator: validator(compat) } @@ -42,47 +40,42 @@ function _optimize(source, mergeAdjacent, aggressiveMerging, compatibilityOption vows.describe(optimize) .addBatch({ - 'of two adjacent properties': { + 'of two properties': { 'topic': function () { - return _optimize('a{display:-moz-inline-box;display:inline-block}', false, true); + return _optimize('a{display:inline-block;color:red;display:block}'); }, 'into': function (properties) { assert.deepEqual(properties, [ [ 'property', - ['property-name', 'display', [[1, 2, undefined]]], - ['property-value', '-moz-inline-box', [[1, 10, undefined]]] + ['property-name', 'color', [[1, 23, undefined]]], + ['property-value', 'red', [[1, 29, undefined]]] ], [ 'property', - ['property-name', 'display', [[1, 26, undefined]]], - ['property-value', 'inline-block', [[1, 34, undefined]]] + ['property-name', 'display', [[1, 33, undefined]]], + ['property-value', 'block', [[1, 41, undefined]]] ] ]); } }, - 'of two properties ': { + 'of two adjacent properties': { 'topic': function () { - return _optimize('a{display:inline-block;color:red;display:block}', false, true); + return _optimize('a{display:-moz-inline-box;display:inline-block}'); }, 'into': function (properties) { assert.deepEqual(properties, [ [ 'property', - ['property-name', 'color', [[1, 23, undefined]]], - ['property-value', 'red', [[1, 29, undefined]]] - ], - [ - 'property', - ['property-name', 'display', [[1, 33, undefined]]], - ['property-value', 'block', [[1, 41, undefined]]] + ['property-name', 'display', [[1, 26, undefined]]], + ['property-value', 'inline-block', [[1, 34, undefined]]] ] ]); } }, 'of two same properties with same value where latter is a hack': { 'topic': function () { - return _optimize('a{margin:0;_margin:0}', false, true); + return _optimize('a{margin:0;_margin:0}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -101,7 +94,7 @@ vows.describe(optimize) }, 'of two same properties with same value where latter is !important': { 'topic': function () { - return _optimize('a{margin:0;margin:0 !important}', false, true); + return _optimize('a{margin:0;margin:0 !important}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -115,7 +108,7 @@ vows.describe(optimize) }, 'of two properties where former is !important': { 'topic': function () { - return _optimize('a{display:inline-block!important;color:red;display:block}', false, true); + return _optimize('a{display:inline-block!important;color:red;display:block}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -132,9 +125,9 @@ vows.describe(optimize) ]); } }, - 'of two properties where latter is !important': { + 'of two properties where latter is !important': { 'topic': function () { - return _optimize('a{display:inline-block;color:red;display:block!important}', false, true); + return _optimize('a{display:inline-block;color:red;display:block!important}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -151,9 +144,9 @@ vows.describe(optimize) ]); } }, - 'of two properties where both are !important': { + 'of two properties where both are !important': { 'topic': function () { - return _optimize('a{display:inline-block!important;color:red;display:block!important}', false, true); + return _optimize('a{display:inline-block!important;color:red;display:block!important}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -172,15 +165,10 @@ vows.describe(optimize) }, 'of many properties': { 'topic': function () { - return _optimize('a{display:inline-block;color:red;font-weight:bolder;font-weight:700;display:block!important;color:#fff}', false, true); + return _optimize('a{display:inline-block;color:red;font-weight:bolder;font-weight:700;display:block!important;color:#fff}'); }, 'into': function (properties) { assert.deepEqual(properties, [ - [ - 'property', - ['property-name', 'font-weight', [[1, 33, undefined]]], - ['property-value', 'bolder', [[1, 45, undefined]]] - ], [ 'property', ['property-name', 'font-weight', [[1, 52, undefined]]], @@ -201,7 +189,7 @@ vows.describe(optimize) }, 'both redefined': { 'topic': function () { - return _optimize('p{display:block;display:-moz-inline-box;color:red;display:table-cell}', false, true); + return _optimize('p{display:block;display:-moz-inline-box;color:red;display:table-cell}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -220,7 +208,7 @@ vows.describe(optimize) }, 'filter treated as background': { 'topic': function () { - return _optimize('p{background:-moz-linear-gradient();background:-webkit-linear-gradient();filter:"progid:DXImageTransform";background:linear-gradient()}', false, true); + return _optimize('p{background:-moz-linear-gradient();background:-webkit-linear-gradient();filter:"progid:DXImageTransform";background:linear-gradient()}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -249,7 +237,7 @@ vows.describe(optimize) }, 'filter treated as background-image': { 'topic': function () { - return _optimize('p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();filter:"progid:DXImageTransform";background-image:linear-gradient()}', false, true); + return _optimize('p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();filter:"progid:DXImageTransform";background-image:linear-gradient()}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -278,7 +266,7 @@ vows.describe(optimize) }, '-ms-filter treated as background': { 'topic': function () { - return _optimize('p{background:-moz-linear-gradient();background:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background:linear-gradient()}', false, true); + return _optimize('p{background:-moz-linear-gradient();background:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background:linear-gradient()}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -307,7 +295,7 @@ vows.describe(optimize) }, '-ms-filter treated as background-image': { 'topic': function () { - return _optimize('p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background-image:linear-gradient()}', false, true); + return _optimize('p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background-image:linear-gradient()}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -336,7 +324,7 @@ vows.describe(optimize) }, 'longhand then shorthand 123': { 'topic': function () { - return _optimize('p{border-left-style:solid;border:1px dotted red}', false, true); + return _optimize('p{border-left-style:solid;border:1px dotted red}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -352,7 +340,7 @@ vows.describe(optimize) }, 'longhand then shorthand with important': { 'topic': function () { - return _optimize('p{border-left-style:solid!important;border:1px dotted red}', false, true); + return _optimize('p{border-left-style:solid!important;border:1px dotted red}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -373,7 +361,7 @@ vows.describe(optimize) }, 'shorthand then longhand': { 'topic': function () { - return _optimize('p{background:url(image.png);background-image:#fff}', false, true); + return _optimize('p{background:url(image.png);background-image:#fff}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -394,7 +382,7 @@ vows.describe(optimize) .addBatch({ 'list-style fuzzy matching': { 'topic': function () { - return _optimize('p{list-style:inside none}', false, true); + return _optimize('p{list-style:inside none}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -411,7 +399,7 @@ vows.describe(optimize) .addBatch({ 'ie hacks - normal before hack': { 'topic': function () { - return _optimize('p{color:red;display:none;color:#fff\\9}', false, true); + return _optimize('p{color:red;display:none;color:#fff\\9}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -435,7 +423,7 @@ vows.describe(optimize) }, 'ie hacks - normal after hack': { 'topic': function () { - return _optimize('p{color:red\\9;display:none;color:#fff}', false, true); + return _optimize('p{color:red\\9;display:none;color:#fff}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -459,7 +447,7 @@ vows.describe(optimize) }, 'ie hacks - hack after hack': { 'topic': function () { - return _optimize('p{color:red\\9;display:none;color:#fff\\9}', false, true); + return _optimize('p{color:red\\9;display:none;color:#fff\\9}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -475,116 +463,55 @@ vows.describe(optimize) ] ]); } - } - }) - .addBatch({ - 'mergeAdjacent is true': { - 'topic': function () { - return _optimize('p{display:block;display:inline-block}', true, true); - }, - 'into': function (properties) { - assert.deepEqual(properties, [ - [ - 'property', - ['property-name', 'display', [[1, 16, undefined]]], - ['property-value', 'inline-block', [[1, 24, undefined]]] - ] - ]); - } }, - 'mergeAdjacent is false': { + 'not overriddable': { 'topic': function () { - return _optimize('p{display:block;display:inline-block}', false, true); + return _optimize('a{display:inline-block;color:red;display:-moz-block}'); }, 'into': function (properties) { assert.deepEqual(properties, [ [ 'property', ['property-name', 'display', [[1, 2, undefined]]], - ['property-value', 'block', [[1, 10, undefined]]] - ], - [ - 'property', - ['property-name', 'display', [[1, 16, undefined]]], - ['property-value', 'inline-block', [[1, 24, undefined]]] - ] - ]); - } - }, - 'mergeAdjacent is an array with irrelevant join positions': { - 'topic': function () { - return _optimize('p{display:block;display:inline-block;color:red}', [2], true); - }, - 'into': function (properties) { - assert.deepEqual(properties, [ - [ - 'property', - ['property-name', 'display', [[1, 2, undefined]]], - ['property-value', 'block', [[1, 10, undefined]]] - ], - [ - 'property', - ['property-name', 'display', [[1, 16, undefined]]], - ['property-value', 'inline-block', [[1, 24, undefined]]] + ['property-value', 'inline-block', [[1, 10, undefined]]] ], [ 'property', - ['property-name', 'color', [[1, 37, undefined]]], - ['property-value', 'red', [[1, 43, undefined]]] - ] - ]); - } - }, - 'mergeAdjacent is an array with relevant join positions': { - 'topic': function () { - return _optimize('p{display:block;display:inline-block;color:red}', [1], true); - }, - 'into': function (properties) { - assert.deepEqual(properties, [ - [ - 'property', - ['property-name', 'display', [[1, 16, undefined]]], - ['property-value', 'inline-block', [[1, 24, undefined]]] + ['property-name', 'color', [[1, 23, undefined]]], + ['property-value', 'red', [[1, 29, undefined]]] ], [ 'property', - ['property-name', 'color', [[1, 37, undefined]]], - ['property-value', 'red', [[1, 43, undefined]]] + ['property-name', 'display', [[1, 33, undefined]]], + ['property-value', '-moz-block', [[1, 41, undefined]]] ] ]); } } }) .addBatch({ - 'aggressive off - (yet) not overriddable': { + 'understandable - 2 properties, both !important, 2nd less understandable': { 'topic': function () { - return _optimize('a{display:inline-block;color:red;display:-moz-block}', false); + return _optimize('a{color:red!important;display:block;color:rgba(0,255,0,.5)!important}'); }, 'into': function (properties) { assert.deepEqual(properties, [ [ 'property', - ['property-name', 'display', [[1, 2, undefined]]], - ['property-value', 'inline-block', [[1, 10, undefined]]] - ], - [ - 'property', - ['property-name', 'color', [[1, 23, undefined]]], - ['property-value', 'red', [[1, 29, undefined]]] + ['property-name', 'display', [[1, 22, undefined]]], + ['property-value', 'block', [[1, 30, undefined]]] ], [ 'property', - ['property-name', 'display', [[1, 33, undefined]]], - ['property-value', '-moz-block', [[1, 41, undefined]]] + ['property-name', 'color', [[1, 36, undefined]]], + ['property-value', 'rgba(0,255,0,.5)!important', [[1, 42, undefined]]] ] ]); } - } - }) - .addBatch({ - 'understandable - 2 properties, both !important, 2nd less understandable': { + }, + 'understandable - 2 properties, both !important, 2nd less understandable - IE8 mode': { 'topic': function () { - return _optimize('a{color:red!important;display:block;color:rgba(0,255,0,.5)!important}', false, true); + return _optimize('a{color:red!important;display:block;color:rgba(0,255,0,.5)!important}', 'ie8'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -608,7 +535,7 @@ vows.describe(optimize) }, 'understandable - 2 properties, both !important, 2nd more understandable': { 'topic': function () { - return _optimize('a{color:rgba(0,255,0,.5)!important;display:block;color:red!important}', false, true); + return _optimize('a{color:rgba(0,255,0,.5)!important;display:block;color:red!important}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -627,7 +554,21 @@ vows.describe(optimize) }, 'understandable - 2 adjacent properties, both !important, 2nd less understandable': { 'topic': function () { - return _optimize('a{background:red!important;background:rgba(0,255,0,.5)!important}', false, true); + return _optimize('a{background:red!important;background:rgba(0,255,0,.5)!important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'rgba(0,255,0,.5)!important', [[1, 38, undefined]]] + ] + ]); + } + }, + 'understandable - 2 adjacent properties, both !important, 2nd less understandable - IE8 mode': { + 'topic': function () { + return _optimize('a{background:red!important;background:rgba(0,255,0,.5)!important}', 'ie8'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -646,7 +587,7 @@ vows.describe(optimize) }, 'understandable - 2 adjacent properties, both !important and understandable': { 'topic': function () { - return _optimize('a{background:rgba(0,255,0,.5)!important;background:red!important}', false, true); + return _optimize('a{background:rgba(0,255,0,.5)!important;background:red!important}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -660,7 +601,7 @@ vows.describe(optimize) }, 'understandable - 2 adjacent -ms-transform with different values': { 'topic': function () { - return _optimize('div{-ms-transform:translate(0,0);-ms-transform:translate3d(0,0,0)}', false, true); + return _optimize('div{-ms-transform:translate(0,0);-ms-transform:translate3d(0,0,0)}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -679,7 +620,7 @@ vows.describe(optimize) }, 'understandable - 2 non-adjacent -ms-transform with different values': { 'topic': function () { - return _optimize('div{-ms-transform:translate(0,0);-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}', false, true); + return _optimize('div{-ms-transform:translate(0,0);-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -703,7 +644,7 @@ vows.describe(optimize) }, 'understandable - 2 adjacent transform with different values': { 'topic': function () { - return _optimize('div{transform:translate(0,0);transform:translate3d(0,0,0)}', false, true); + return _optimize('div{transform:translate(0,0);transform:translate3d(0,0,0)}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -722,7 +663,7 @@ vows.describe(optimize) }, 'understandable - 2 non-adjacent transform with different values': { 'topic': function () { - return _optimize('div{transform:translate(0,0);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}', false, true); + return _optimize('div{transform:translate(0,0);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -746,7 +687,23 @@ vows.describe(optimize) }, 'understandable - border(hex) with border(rgba)': { 'topic': function () { - return _optimize('a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)}', false, true); + return _optimize('a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 31, undefined]]], + ['property-value', 'solid', [[1, 35, undefined]]], + ['property-value', 'rgba(1,0,0,.5)', [[1, 41, undefined]]] + ] + ]); + } + }, + 'understandable - border(hex) with border(rgba) - IE8 mode': { + 'topic': function () { + return _optimize('a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)}', 'ie8'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -769,7 +726,7 @@ vows.describe(optimize) }, 'understandable - border(hex) with border(rgba !important)': { 'topic': function () { - return _optimize('a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)!important}', false, true); + return _optimize('a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)!important}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -785,7 +742,7 @@ vows.describe(optimize) }, 'understandable - border(hex !important) with border(hex)': { 'topic': function () { - return _optimize('a{border:1px solid #fff!important;display:block;border:1px solid #fff}', false, true); + return _optimize('a{border:1px solid #fff!important;display:block;border:1px solid #fff}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -806,7 +763,7 @@ vows.describe(optimize) }, 'understandable - border(hex) with border(hex !important)': { 'topic': function () { - return _optimize('a{border:1px solid #fff;display:block;border:1px solid #fff!important}', false, true); + return _optimize('a{border:1px solid #fff;display:block;border:1px solid #fff!important}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -827,7 +784,7 @@ vows.describe(optimize) }, 'understandable - unit with function with unit without one': { 'topic': function () { - return _optimize('a{border-top-width:calc(100%);display:block;border-top-width:1px}', false, true); + return _optimize('a{border-top-width:calc(100%);display:block;border-top-width:1px}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -846,7 +803,7 @@ vows.describe(optimize) }, 'understandable - unit without function with unit with one': { 'topic': function () { - return _optimize('a{border-top-width:1px;display:block;border-top-width:calc(100%)}', false, true); + return _optimize('a{border-top-width:1px;display:block;border-top-width:calc(100%)}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -870,7 +827,7 @@ vows.describe(optimize) }, 'understandable - non adjacent units': { 'topic': function () { - return _optimize('a{margin-top:80px;padding-top:30px;margin-top:10vmin}', false, true); + return _optimize('a{margin-top:80px;padding-top:30px;margin-top:10vmin}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -891,7 +848,7 @@ vows.describe(optimize) .addBatch({ 'understandable - non adjacent units in IE8 mode': { 'topic': function () { - return _optimize('a{margin-top:80px;padding-top:30px;margin-top:10vmin}', false, true, 'ie8'); + return _optimize('a{margin-top:80px;padding-top:30px;margin-top:10vmin}', 'ie8'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -915,7 +872,7 @@ vows.describe(optimize) }, 'understandable - 2 adjacent properties, both !important, 2nd more understandable in IE8 mode': { 'topic': function () { - return _optimize('a{background:rgba(0,255,0,.5)!important;background:red!important}', false, true, 'ie8'); + return _optimize('a{background:rgba(0,255,0,.5)!important;background:red!important}', 'ie8'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -934,7 +891,7 @@ vows.describe(optimize) }, 'understandable - border(hex) with border(rgba !important) in IE8 mode': { 'topic': function () { - return _optimize('a{border:1px solid #fff!important;border:1px solid rgba(1,0,0,.5)!important}', false, true, 'ie8'); + return _optimize('a{border:1px solid #fff!important;border:1px solid rgba(1,0,0,.5)!important}', 'ie8'); }, 'into': function (properties) { assert.deepEqual(properties, [ diff --git a/test/optimizer/level-2/compacting/override-compacting-test.js b/test/optimizer/level-2/compacting/override-compacting-test.js index b3b6829ee..fbc12732a 100644 --- a/test/optimizer/level-2/compacting/override-compacting-test.js +++ b/test/optimizer/level-2/compacting/override-compacting-test.js @@ -8,7 +8,7 @@ var inputSourceMapTracker = require('../../../../lib/reader/input-source-map-tra var compatibility = require('../../../../lib/utils/compatibility'); var validator = require('../../../../lib/optimizer/validator'); -function _optimize(source, compat, aggressiveMerging) { +function _optimize(source, compat) { var tokens = tokenize(source, { inputSourceMapTracker: inputSourceMapTracker(), options: {}, @@ -17,7 +17,6 @@ function _optimize(source, compat, aggressiveMerging) { compat = compatibility(compat); var options = { - aggressiveMerging: undefined === aggressiveMerging ? true : aggressiveMerging, compatibility: compat, level: { 2: { @@ -28,7 +27,6 @@ function _optimize(source, compat, aggressiveMerging) { optimize( tokens[0][1], tokens[0][2], - false, true, { enabled: true, merging: true }, { options: options, validator: validator(compat) } @@ -728,25 +726,6 @@ vows.describe(optimize) ]); } }, - 'with aggressive off': { - 'topic': function () { - return _optimize('a{background:white;color:red;background:red}', undefined, false); - }, - 'into': function (properties) { - assert.deepEqual(properties, [ - [ - 'property', - ['property-name', 'background', [[1, 2, undefined]]], - ['property-value', 'red', [[1, 40, undefined]]] - ], - [ - 'property', - ['property-name', 'color', [[1, 19, undefined]]], - ['property-value', 'red', [[1, 25, undefined]]] - ] - ]); - } - }, 'background-clip, -origin, and -size': { 'topic': function () { return _optimize('a{background:url(/image.png);background-size:10px;background-origin:border-box;background-clip:padding-box}'); @@ -893,6 +872,22 @@ vows.describe(optimize) 'topic': function () { return _optimize('a{border:1px solid #000;border-color:rgba(255,0,0,.5)}'); }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'solid', [[1, 13, undefined]]], + ['property-value', 'rgba(255,0,0,.5)', [[1, 37, undefined]]], + ] + ]); + } + }, + 'border - hex and rgb colors - IE8 mode': { + 'topic': function () { + return _optimize('a{border:1px solid #000;border-color:rgba(255,0,0,.5)}', 'ie8'); + }, 'into': function (properties) { assert.deepEqual(properties, [ [ @@ -914,6 +909,20 @@ vows.describe(optimize) 'topic': function () { return _optimize('a{border-color:#000;border-color:rgba(255,0,0,.5)}'); }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-color', [[1, 2, undefined]]], + ['property-value', 'rgba(255,0,0,.5)', [[1, 33, undefined]]], + ] + ]); + } + }, + 'border-color - hex then rgb - IE8 mode': { + 'topic': function () { + return _optimize('a{border-color:#000;border-color:rgba(255,0,0,.5)}', 'ie8'); + }, 'into': function (properties) { assert.deepEqual(properties, [ [ @@ -947,6 +956,21 @@ vows.describe(optimize) 'topic': function () { return _optimize('a{border-color:red;border-color:#000 rgba(255,0,0,.5)}'); }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-color', [[1, 2, undefined]]], + ['property-value', '#000', [[1, 32, undefined]]], + ['property-value', 'rgba(255,0,0,.5)', [[1, 37, undefined]]], + ] + ]); + } + }, + 'border-color - hex then rgb with multiple values - IE8 mode': { + 'topic': function () { + return _optimize('a{border-color:red;border-color:#000 rgba(255,0,0,.5)}', 'ie8'); + }, 'into': function (properties) { assert.deepEqual(properties, [ [ @@ -1064,6 +1088,29 @@ vows.describe(optimize) ]); } }, + 'outline with vendor prefixed color 1234': { + 'topic': function () { + return _optimize('a{outline:red solid 1px;outline:-webkit-focus-ring-color auto 5px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'outline', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 10, undefined]]], + ['property-value', 'solid', [[1, 14, undefined]]], + ['property-value', '1px', [[1, 20, undefined]]] + ], + [ + 'property', + ['property-name', 'outline', [[1, 24, undefined]]], + ['property-value', '-webkit-focus-ring-color', [[1, 32, undefined]]], + ['property-value', 'auto', [[1, 57, undefined]]], + ['property-value', '5px', [[1, 62, undefined]]] + ] + ]); + } + }, 'padding': { 'topic': function () { return _optimize('a{padding:10px;padding-right:20px;padding-left:20px}'); @@ -1099,6 +1146,20 @@ vows.describe(optimize) 'topic': function () { return _optimize('a{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4)}'); }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 34, undefined]]], + ['property-value', 'rgba(1,2,3,.4)', [[1, 40, undefined]]], + ] + ]); + } + }, + 'colors with different understandability - IE8 mode': { + 'topic': function () { + return _optimize('a{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4)}', 'ie8'); + }, 'into': function (properties) { assert.deepEqual(properties, [ [ @@ -1146,6 +1207,20 @@ vows.describe(optimize) 'topic': function () { return _optimize('a{color:#fff;color:rgba(1,2,3,.4)!important}'); }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 13, undefined]]], + ['property-value', 'rgba(1,2,3,.4)!important', [[1, 19, undefined]]], + ] + ]); + } + }, + 'colors with different understandability and importance #2 - IE8 mode': { + 'topic': function () { + return _optimize('a{color:#fff;color:rgba(1,2,3,.4)!important}', 'ie8'); + }, 'into': function (properties) { assert.deepEqual(properties, [ [ @@ -1547,11 +1622,494 @@ vows.describe(optimize) } } }) + .addBatch({ + 'bottom': { + 'topic': function () { + return _optimize('.block{bottom:0;bottom:2rem}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'bottom', [[1, 16, undefined]]], + ['property-value', '2rem', [[1, 23, undefined]]] + ] + ]); + } + }, + 'bottom - non overriddable': { + 'topic': function () { + return _optimize('.block{bottom:2rem;bottom:calc(1vm + 1px)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'bottom', [[1, 7, undefined]]], + ['property-value', '2rem', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', 'bottom', [[1, 19, undefined]]], + ['property-value', 'calc(1vm + 1px)', [[1, 26, undefined]]] + ] + ]); + } + }, + 'cursor': { + 'topic': function () { + return _optimize('.block{cursor:auto;cursor:pointer}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'cursor', [[1, 19, undefined]]], + ['property-value', 'pointer', [[1, 26, undefined]]] + ] + ]); + } + }, + 'cursor - non overriddable': { + 'topic': function () { + return _optimize('.block{cursor:pointer;cursor:url(image.png)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'cursor', [[1, 7, undefined]]], + ['property-value', 'pointer', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', 'cursor', [[1, 22, undefined]]], + ['property-value', 'url(image.png)', [[1, 29, undefined]]] + ] + ]); + } + }, + 'left': { + 'topic': function () { + return _optimize('.block{left:0;left:2rem}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'left', [[1, 14, undefined]]], + ['property-value', '2rem', [[1, 19, undefined]]] + ] + ]); + } + }, + 'left - non overriddable': { + 'topic': function () { + return _optimize('.block{left:2rem;left:calc(1vm + 1px)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'left', [[1, 7, undefined]]], + ['property-value', '2rem', [[1, 12, undefined]]] + ], + [ + 'property', + ['property-name', 'left', [[1, 17, undefined]]], + ['property-value', 'calc(1vm + 1px)', [[1, 22, undefined]]] + ] + ]); + } + }, + 'position': { + 'topic': function () { + return _optimize('.block{position:static;position:relative}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'position', [[1, 23, undefined]]], + ['property-value', 'relative', [[1, 32, undefined]]] + ] + ]); + } + }, + 'position - non overriddable': { + 'topic': function () { + return _optimize('.block{position:fixed;position:sticky}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'position', [[1, 7, undefined]]], + ['property-value', 'fixed', [[1, 16, undefined]]] + ], + [ + 'property', + ['property-name', 'position', [[1, 22, undefined]]], + ['property-value', 'sticky', [[1, 31, undefined]]] + ] + ]); + } + }, + 'overflow': { + 'topic': function () { + return _optimize('.block{overflow:hidden;overflow:visible}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'overflow', [[1, 23, undefined]]], + ['property-value', 'visible', [[1, 32, undefined]]] + ] + ]); + } + }, + 'overflow - non overriddable': { + 'topic': function () { + return _optimize('.block{overflow:hidden;overflow:-moz-scrollbars-none }'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'overflow', [[1, 7, undefined]]], + ['property-value', 'hidden', [[1, 16, undefined]]] + ], + [ + 'property', + ['property-name', 'overflow', [[1, 23, undefined]]], + ['property-value', '-moz-scrollbars-none', [[1, 32, undefined]]] + ] + ]); + } + }, + 'right': { + 'topic': function () { + return _optimize('.block{right:0;right:2rem}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'right', [[1, 15, undefined]]], + ['property-value', '2rem', [[1, 21, undefined]]] + ] + ]); + } + }, + 'right - non overriddable': { + 'topic': function () { + return _optimize('.block{right:2rem;right:calc(1vm + 1px)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'right', [[1, 7, undefined]]], + ['property-value', '2rem', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'right', [[1, 18, undefined]]], + ['property-value', 'calc(1vm + 1px)', [[1, 24, undefined]]] + ] + ]); + } + }, + 'top': { + 'topic': function () { + return _optimize('.block{top:0;top:2rem}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'top', [[1, 13, undefined]]], + ['property-value', '2rem', [[1, 17, undefined]]] + ] + ]); + } + }, + 'top - non overriddable': { + 'topic': function () { + return _optimize('.block{top:2rem;top:calc(1vm + 1px)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'top', [[1, 7, undefined]]], + ['property-value', '2rem', [[1, 11, undefined]]] + ], + [ + 'property', + ['property-name', 'top', [[1, 16, undefined]]], + ['property-value', 'calc(1vm + 1px)', [[1, 20, undefined]]] + ] + ]); + } + }, + 'text-align': { + 'topic': function () { + return _optimize('.block{text-align:center;text-align:justify}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'text-align', [[1, 25, undefined]]], + ['property-value', 'justify', [[1, 36, undefined]]] + ] + ]); + } + }, + 'text-align - non overriddable': { + 'topic': function () { + return _optimize('.block{text-align:center;text-align:start}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'text-align', [[1, 7, undefined]]], + ['property-value', 'center', [[1, 18, undefined]]] + ], + [ + 'property', + ['property-name', 'text-align', [[1, 25, undefined]]], + ['property-value', 'start', [[1, 36, undefined]]] + ] + ]); + } + }, + 'text-decoration': { + 'topic': function () { + return _optimize('.block{text-decoration:none;text-decoration:underline}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'text-decoration', [[1, 28, undefined]]], + ['property-value', 'underline', [[1, 44, undefined]]] + ] + ]); + } + }, + 'text-decoration - non overriddable': { + 'topic': function () { + return _optimize('.block{text-decoration:none;text-decoration:blink}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'text-decoration', [[1, 7, undefined]]], + ['property-value', 'none', [[1, 23, undefined]]] + ], + [ + 'property', + ['property-name', 'text-decoration', [[1, 28, undefined]]], + ['property-value', 'blink', [[1, 44, undefined]]] + ] + ]); + } + }, + 'text-overflow': { + 'topic': function () { + return _optimize('.block{text-overflow:clip;text-overflow:ellipsis}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'text-overflow', [[1, 26, undefined]]], + ['property-value', 'ellipsis', [[1, 40, undefined]]] + ] + ]); + } + }, + 'text-overflow - non overriddable': { + 'topic': function () { + return _optimize('.block{text-overflow:clip;text-overflow:"..."}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'text-overflow', [[1, 7, undefined]]], + ['property-value', 'clip', [[1, 21, undefined]]] + ], + [ + 'property', + ['property-name', 'text-overflow', [[1, 26, undefined]]], + ['property-value', '"..."', [[1, 40, undefined]]] + ] + ]); + } + }, + 'vertical-align': { + 'topic': function () { + return _optimize('.block{vertical-align:sub;vertical-align:middle}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'vertical-align', [[1, 26, undefined]]], + ['property-value', 'middle', [[1, 41, undefined]]] + ] + ]); + } + }, + 'vertical-align - non overriddable': { + 'topic': function () { + return _optimize('.block{vertical-align:sub;vertical-align:-webkit-funky-align}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'vertical-align', [[1, 7, undefined]]], + ['property-value', 'sub', [[1, 22, undefined]]] + ], + [ + 'property', + ['property-name', 'vertical-align', [[1, 26, undefined]]], + ['property-value', '-webkit-funky-align', [[1, 41, undefined]]] + ] + ]); + } + }, + 'visibility': { + 'topic': function () { + return _optimize('.block{visibility:collapse;visibility:visible}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'visibility', [[1, 27, undefined]]], + ['property-value', 'visible', [[1, 38, undefined]]] + ] + ]); + } + }, + 'visibility - non overriddable': { + 'topic': function () { + return _optimize('.block{visibility:collapse;visibility:var(--visibility)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'visibility', [[1, 7, undefined]]], + ['property-value', 'collapse', [[1, 18, undefined]]] + ], + [ + 'property', + ['property-name', 'visibility', [[1, 27, undefined]]], + ['property-value', 'var(--visibility)', [[1, 38, undefined]]] + ] + ]); + } + }, + 'white-space': { + 'topic': function () { + return _optimize('.block{white-space:normal;white-space:nowrap}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'white-space', [[1, 26, undefined]]], + ['property-value', 'nowrap', [[1, 38, undefined]]] + ] + ]); + } + }, + 'white-space - non overriddable': { + 'topic': function () { + return _optimize('.block{white-space:normal;white-space:var(--white-space)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'white-space', [[1, 7, undefined]]], + ['property-value', 'normal', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'white-space', [[1, 26, undefined]]], + ['property-value', 'var(--white-space)', [[1, 38, undefined]]] + ] + ]); + } + }, + 'z-index': { + 'topic': function () { + return _optimize('.block{z-index:auto;z-index:-1}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'z-index', [[1, 20, undefined]]], + ['property-value', '-1', [[1, 28, undefined]]] + ] + ]); + } + }, + 'z-index - non overriddable': { + 'topic': function () { + return _optimize('.block{z-index:auto;z-index:"15"}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'z-index', [[1, 7, undefined]]], + ['property-value', 'auto', [[1, 15, undefined]]] + ], + [ + 'property', + ['property-name', 'z-index', [[1, 20, undefined]]], + ['property-value', '"15"', [[1, 28, undefined]]] + ] + ]); + } + } + }) .addBatch({ 'overriding !important by a star hack': { 'topic': function () { return _optimize('a{color:red!important;display:block;*color:#fff}'); }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red!important', [[1, 8, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 22, undefined]]], + ['property-value', 'block', [[1, 30, undefined]]] + ] + ]); + } + }, + 'overriding !important by an !important star hack': { + 'topic': function () { + return _optimize('a{color:red!important;display:block;*color:#fff!important}'); + }, 'into': function (properties) { assert.deepEqual(properties, [ [ @@ -1567,7 +2125,7 @@ vows.describe(optimize) [ 'property', ['property-name', '*color', [[1, 36, undefined]]], - ['property-value', '#fff', [[1, 43, undefined]]] + ['property-value', '#fff!important', [[1, 43, undefined]]] ] ]); } @@ -1576,6 +2134,25 @@ vows.describe(optimize) 'topic': function () { return _optimize('a{color:red!important;display:block;_color:#fff}'); }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red!important', [[1, 8, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 22, undefined]]], + ['property-value', 'block', [[1, 30, undefined]]] + ] + ]); + } + }, + 'overriding !important by an !important underscore hack': { + 'topic': function () { + return _optimize('a{color:red!important;display:block;_color:#fff!important}'); + }, 'into': function (properties) { assert.deepEqual(properties, [ [ @@ -1591,7 +2168,7 @@ vows.describe(optimize) [ 'property', ['property-name', '_color', [[1, 36, undefined]]], - ['property-value', '#fff', [[1, 43, undefined]]] + ['property-value', '#fff!important', [[1, 43, undefined]]] ] ]); } diff --git a/test/optimizer/level-2/compacting/shorthand-compacting-test.js b/test/optimizer/level-2/compacting/shorthand-compacting-test.js index 573950ecc..5fc1f5f70 100644 --- a/test/optimizer/level-2/compacting/shorthand-compacting-test.js +++ b/test/optimizer/level-2/compacting/shorthand-compacting-test.js @@ -17,7 +17,6 @@ function _optimize(source) { var compat = compatibility(compat); var options = { - aggressiveMerging: true, compatibility: compat, level: { 2: { @@ -28,7 +27,6 @@ function _optimize(source) { optimize( tokens[0][1], tokens[0][2], - false, true, { enabled: true, merging: true }, { options: options, validator: validator(compat) } @@ -551,7 +549,7 @@ vows.describe(optimize) }, 'mixed understandability of units': { 'topic': function () { - return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:calc(100% - 20px)}'); + return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:-moz-calc(100% - 20px)}'); }, 'into': function (properties) { assert.deepEqual(properties, [ @@ -573,7 +571,7 @@ vows.describe(optimize) [ 'property', ['property-name', 'padding-right', [[1, 55, undefined]]], - ['property-value', 'calc(100% - 20px)', [[1, 69, undefined]]] + ['property-value', '-moz-calc(100% - 20px)', [[1, 69, undefined]]] ] ]); } diff --git a/test/optimizer/level-2/compacting/understandable-test.js b/test/optimizer/level-2/compacting/understandable-test.js new file mode 100644 index 000000000..48c734d18 --- /dev/null +++ b/test/optimizer/level-2/compacting/understandable-test.js @@ -0,0 +1,60 @@ +var assert = require('assert'); +var vows = require('vows'); + +var compatibility = require('../../../../lib/utils/compatibility'); +var validator = require('../../../../lib/optimizer/validator'); + +var understandable = require('../../../../lib/optimizer/level-2/compacting/understandable'); + +vows.describe(understandable) + .addBatch({ + 'same vendor prefixes': { + 'topic': function () { + return [validator(compatibility({})), '-moz-calc(100% / 2)', '-moz-calc(50% / 2)', 0, true]; + }, + 'is understandable': function (topic) { + assert.isTrue(understandable.apply(null, topic)); + } + }, + 'different vendor prefixes': { + 'topic': function () { + return [validator(compatibility({})), '-moz-calc(100% / 2)', 'calc(50% / 2)', 0, true]; + }, + 'is not understandable': function (topic) { + assert.isFalse(understandable.apply(null, topic)); + } + }, + 'different vendor prefixes when comparing non-pair values': { + 'topic': function () { + return [validator(compatibility({})), '-moz-calc(100% / 2)', 'calc(50% / 2)', 0, false]; + }, + 'is not understandable': function (topic) { + assert.isFalse(understandable.apply(null, topic)); + } + }, + 'variables': { + 'topic': function () { + return [validator(compatibility({})), 'var(--x)', 'var(--y)', 0, true]; + }, + 'is understandable': function (topic) { + assert.isTrue(understandable.apply(null, topic)); + } + }, + 'variable and value': { + 'topic': function () { + return [validator(compatibility({})), 'var(--x)', 'block', 0, true]; + }, + 'is not understandable': function (topic) { + assert.isFalse(understandable.apply(null, topic)); + } + }, + 'variable and value when comparing non-pair values': { + 'topic': function () { + return [validator(compatibility({})), 'var(--x)', 'block', 0, false]; + }, + 'is understandable': function (topic) { + assert.isTrue(understandable.apply(null, topic)); + } + } + }) + .export(module); diff --git a/test/optimizer/level-2/optimize-test.js b/test/optimizer/level-2/optimize-test.js index b49298e59..3af8b3894 100644 --- a/test/optimizer/level-2/optimize-test.js +++ b/test/optimizer/level-2/optimize-test.js @@ -15,32 +15,16 @@ vows.describe('level 2 optimizer') 'shorthands and no space after closing brace': [ '.a{background:rgba(0,0,0,0)url(//example.com/a.jpg)}', '.a{background:url(//example.com/a.jpg) rgba(0,0,0,0)}' - ] - }, { level: 2 }) - ) - .addBatch( - optimizerContext('level 2 on & aggressive merging on', { - 'repeated' : [ + ], + 'repeated': [ 'a{color:red;color:red}', 'a{color:red}' - ] - }, { level: 2, aggressiveMerging: true }) - ) - .addBatch( - optimizerContext('level 2 on & aggressive merging on - IE8 mode', { + ], 'units': [ '.one{width:1px;width:1rem;display:block}.two{color:red}.one{width:2px;width:1.1rem}', - '.one{display:block;width:2px;width:1.1rem}.two{color:red}' - ] - }, { level: 2, aggressiveMerging: true, compatibility: 'ie8' }) - ) - .addBatch( - optimizerContext('level 2 on & aggressive merging off', { - 'repeated' : [ - 'a{color:red;color:red}', - 'a{color:red}' + '.one{display:block;width:1.1rem}.two{color:red}' ] - }, { level: 2, aggressiveMerging: false }) + }, { level: 2 }) ) .addBatch( optimizerContext('level 2 off', { diff --git a/test/optimizer/level-2/reduce-non-adjacent-test.js b/test/optimizer/level-2/reduce-non-adjacent-test.js index 1af450415..1eeef5d52 100644 --- a/test/optimizer/level-2/reduce-non-adjacent-test.js +++ b/test/optimizer/level-2/reduce-non-adjacent-test.js @@ -10,7 +10,7 @@ vows.describe('remove duplicates') ], 'multiple selectors': [ 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', - 'a{margin:0;color:red}.one{color:red}a,p{color:red;padding:0}' + 'a{margin:0}.one{color:red}a,p{color:red;padding:0}' ], 'with one redefined property': [ '.block-1{color:red;display:block}.block-2{color:red}.block-1{color:#fff;margin:2px}', @@ -127,20 +127,12 @@ vows.describe('remove duplicates') }, { level: { 2: { restructureRules: true } } }) ) .addBatch( - optimizerContext('level 2 on and aggressive merging off', { + optimizerContext('level 2 off but reduceNonAdjacentRules and compacting on', { 'non-adjacent with multi selectors': [ 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', - '.one,a,p{color:red}a{padding:10px;margin:0}a,p{padding:0}' + 'a{margin:0}.one{color:red}a,p{color:red;padding:0}' ] - }, { aggressiveMerging: false, level: { 2: { restructureRules: true } } }) - ) - .addBatch( - optimizerContext('level 2 off but reduceNonAdjacentRules on', { - 'non-adjacent with multi selectors': [ - 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', - 'a{margin:0;color:red}.one{color:red}a,p{color:red;padding:0}' - ] - }, { level: { 2: { all: false, reduceNonAdjacentRules: true } } }) + }, { level: { 2: { all: false, reduceNonAdjacentRules: true, compactShorthands: true } } }) ) .addBatch( optimizerContext('level 2 off', {