diff options
Diffstat (limited to 'node_modules/clean-css/lib/optimizer/level-2')
16 files changed, 1323 insertions, 186 deletions
diff --git a/node_modules/clean-css/lib/optimizer/level-2/break-up.js b/node_modules/clean-css/lib/optimizer/level-2/break-up.js index 9e44d5a1f..b48ccf23d 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/break-up.js +++ b/node_modules/clean-css/lib/optimizer/level-2/break-up.js @@ -3,20 +3,31 @@ var InvalidPropertyError = require('./invalid-property-error'); var wrapSingle = require('../wrap-for-optimizing').single; var Token = require('../../tokenizer/token'); +var Marker = require('../../tokenizer/marker'); var formatPosition = require('../../utils/format-position'); -var MULTIPLEX_SEPARATOR = ','; +function _anyIsInherit(values) { + var i, l; + + for (i = 0, l = values.length; i < l; i++) { + if (values[i][1] == 'inherit') { + return true; + } + } + + return false; +} function _colorFilter(validator) { return function (value) { - return value[1] == 'invert' || validator.isValidColor(value[1]) || validator.isValidVendorPrefixedValue(value[1]); + return value[1] == 'invert' || validator.isColor(value[1]) || validator.isPrefixed(value[1]); }; } function _styleFilter(validator) { return function (value) { - return value[1] != 'inherit' && validator.isValidStyle(value[1]) && !validator.isValidColorValue(value[1]); + return value[1] != 'inherit' && validator.isStyleKeyword(value[1]) && !validator.isColorFunction(value[1]); }; } @@ -46,10 +57,80 @@ function _wrapDefault(name, property, compactable) { function _widthFilter(validator) { return function (value) { - return value[1] != 'inherit' && validator.isValidWidth(value[1]) && !validator.isValidStyle(value[1]) && !validator.isValidColorValue(value[1]); + return value[1] != 'inherit' && + (validator.isWidth(value[1]) || validator.isUnit(value[1]) && !validator.isDynamicUnit(value[1])) && + !validator.isStyleKeyword(value[1]) && + !validator.isColorFunction(value[1]); }; } +function animation(property, compactable, validator) { + var duration = _wrapDefault(property.name + '-duration', property, compactable); + var timing = _wrapDefault(property.name + '-timing-function', property, compactable); + var delay = _wrapDefault(property.name + '-delay', property, compactable); + var iteration = _wrapDefault(property.name + '-iteration-count', property, compactable); + var direction = _wrapDefault(property.name + '-direction', property, compactable); + var fill = _wrapDefault(property.name + '-fill-mode', property, compactable); + var play = _wrapDefault(property.name + '-play-state', property, compactable); + var name = _wrapDefault(property.name + '-name', property, compactable); + var components = [duration, timing, delay, iteration, direction, fill, play, name]; + var values = property.value; + var value; + var durationSet = false; + var timingSet = false; + var delaySet = false; + var iterationSet = false; + var directionSet = false; + var fillSet = false; + var playSet = false; + var nameSet = false; + var i; + var l; + + if (property.value.length == 1 && property.value[0][1] == 'inherit') { + duration.value = timing.value = delay.value = iteration.value = direction.value = fill.value = play.value = name.value = property.value; + return components; + } + + if (values.length > 1 && _anyIsInherit(values)) { + throw new InvalidPropertyError('Invalid animation values at ' + formatPosition(values[0][2][0]) + '. Ignoring.'); + } + + for (i = 0, l = values.length; i < l; i++) { + value = values[i]; + + if (validator.isTime(value[1]) && !durationSet) { + duration.value = [value]; + durationSet = true; + } else if (validator.isTime(value[1]) && !delaySet) { + delay.value = [value]; + delaySet = true; + } else if ((validator.isGlobal(value[1]) || validator.isAnimationTimingFunction(value[1])) && !timingSet) { + timing.value = [value]; + timingSet = true; + } else if ((validator.isAnimationIterationCountKeyword(value[1]) || validator.isPositiveNumber(value[1])) && !iterationSet) { + iteration.value = [value]; + iterationSet = true; + } else if (validator.isAnimationDirectionKeyword(value[1]) && !directionSet) { + direction.value = [value]; + directionSet = true; + } else if (validator.isAnimationFillModeKeyword(value[1]) && !fillSet) { + fill.value = [value]; + fillSet = true; + } else if (validator.isAnimationPlayStateKeyword(value[1]) && !playSet) { + play.value = [value]; + playSet = true; + } else if ((validator.isAnimationNameKeyword(value[1]) || validator.isIdentifier(value[1])) && !nameSet) { + name.value = [value]; + nameSet = true; + } else { + throw new InvalidPropertyError('Invalid animation value at ' + formatPosition(value[2][0]) + '. Ignoring.'); + } + } + + return components; +} + function background(property, compactable, validator) { var image = _wrapDefault('background-image', property, compactable); var position = _wrapDefault('background-position', property, compactable); @@ -82,10 +163,10 @@ function background(property, compactable, validator) { for (var i = values.length - 1; i >= 0; i--) { var value = values[i]; - if (validator.isValidBackgroundAttachment(value[1])) { + if (validator.isBackgroundAttachmentKeyword(value[1])) { attachment.value = [value]; anyValueSet = true; - } else if (validator.isValidBackgroundClip(value[1]) || validator.isValidBackgroundOrigin(value[1])) { + } else if (validator.isBackgroundClipKeyword(value[1]) || validator.isBackgroundOriginKeyword(value[1])) { if (clipSet) { origin.value = [value]; originSet = true; @@ -94,7 +175,7 @@ function background(property, compactable, validator) { clipSet = true; } anyValueSet = true; - } else if (validator.isValidBackgroundRepeat(value[1])) { + } else if (validator.isBackgroundRepeatKeyword(value[1])) { if (repeatSet) { repeat.value.unshift(value); } else { @@ -102,13 +183,13 @@ function background(property, compactable, validator) { repeatSet = true; } anyValueSet = true; - } else if (validator.isValidBackgroundPositionPart(value[1]) || validator.isValidBackgroundSizePart(value[1])) { + } else if (validator.isBackgroundPositionKeyword(value[1]) || validator.isBackgroundSizeKeyword(value[1]) || validator.isUnit(value[1]) || validator.isDynamicUnit(value[1])) { if (i > 0) { var previousValue = values[i - 1]; - if (previousValue[1] == '/') { + if (previousValue[1] == Marker.FORWARD_SLASH) { size.value = [value]; - } else if (i > 1 && values[i - 2][1] == '/') { + } else if (i > 1 && values[i - 2][1] == Marker.FORWARD_SLASH) { size.value = [previousValue, value]; i -= 2; } else { @@ -126,10 +207,10 @@ 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]) || validator.isValidVendorPrefixedValue(value[1]))) { + } else if ((color.value[0][1] == compactable[color.name].defaultValue || color.value[0][1] == 'none') && (validator.isColor(value[1]) || validator.isPrefixed(value[1]))) { color.value = [value]; anyValueSet = true; - } else if (validator.isValidUrl(value[1]) || validator.isValidFunction(value[1])) { + } else if (validator.isUrl(value[1]) || validator.isFunction(value[1])) { image.value = [value]; anyValueSet = true; } @@ -150,7 +231,7 @@ function borderRadius(property, compactable) { var splitAt = -1; for (var i = 0, l = values.length; i < l; i++) { - if (values[i][1] == '/') { + if (values[i][1] == Marker.FORWARD_SLASH) { splitAt = i; break; } @@ -180,6 +261,122 @@ function borderRadius(property, compactable) { return target.components; } +function font(property, compactable, validator) { + var style = _wrapDefault('font-style', property, compactable); + var variant = _wrapDefault('font-variant', property, compactable); + var weight = _wrapDefault('font-weight', property, compactable); + var stretch = _wrapDefault('font-stretch', property, compactable); + var size = _wrapDefault('font-size', property, compactable); + var height = _wrapDefault('line-height', property, compactable); + var family = _wrapDefault('font-family', property, compactable); + var components = [style, variant, weight, stretch, size, height, family]; + var values = property.value; + var fuzzyMatched = 4; // style, variant, weight, and stretch + var index = 0; + var isStretchSet = false; + var isStretchValid; + var isStyleSet = false; + var isStyleValid; + var isVariantSet = false; + var isVariantValid; + var isWeightSet = false; + var isWeightValid; + var isSizeSet = false; + var appendableFamilyName = false; + + if (!values[index]) { + throw new InvalidPropertyError('Missing font values at ' + formatPosition(property.all[property.position][1][2][0]) + '. Ignoring.'); + } + + if (values.length == 1 && values[0][1] == 'inherit') { + style.value = variant.value = weight.value = stretch.value = size.value = height.value = family.value = values; + return components; + } + + if (values.length == 1 && (validator.isFontKeyword(values[0][1]) || validator.isGlobal(values[0][1]) || validator.isPrefixed(values[0][1]))) { + values[0][1] = Marker.INTERNAL + values[0][1]; + style.value = variant.value = weight.value = stretch.value = size.value = height.value = family.value = values; + return components; + } + + if (values.length > 1 && _anyIsInherit(values)) { + throw new InvalidPropertyError('Invalid font values at ' + formatPosition(values[0][2][0]) + '. Ignoring.'); + } + + // fuzzy match style, variant, weight, and stretch on first elements + while (index < fuzzyMatched) { + isStretchValid = validator.isFontStretchKeyword(values[index][1]) || validator.isGlobal(values[index][1]); + isStyleValid = validator.isFontStyleKeyword(values[index][1]) || validator.isGlobal(values[index][1]); + isVariantValid = validator.isFontVariantKeyword(values[index][1]) || validator.isGlobal(values[index][1]); + isWeightValid = validator.isFontWeightKeyword(values[index][1]) || validator.isGlobal(values[index][1]); + + if (isStyleValid && !isStyleSet) { + style.value = [values[index]]; + isStyleSet = true; + } else if (isVariantValid && !isVariantSet) { + variant.value = [values[index]]; + isVariantSet = true; + } else if (isWeightValid && !isWeightSet) { + weight.value = [values[index]]; + isWeightSet = true; + } else if (isStretchValid && !isStretchSet) { + stretch.value = [values[index]]; + isStretchSet = true; + } else if (isStyleValid && isStyleSet || isVariantValid && isVariantSet || isWeightValid && isWeightSet || isStretchValid && isStretchSet) { + throw new InvalidPropertyError('Invalid font style / variant / weight / stretch value at ' + formatPosition(values[0][2][0]) + '. Ignoring.'); + } else { + break; + } + + index++; + } + + // now comes font-size ... + if (validator.isFontSizeKeyword(values[index][1]) || validator.isUnit(values[index][1]) && !validator.isDynamicUnit(values[index][1])) { + size.value = [values[index]]; + isSizeSet = true; + index++; + } else { + throw new InvalidPropertyError('Missing font size at ' + formatPosition(values[0][2][0]) + '. Ignoring.'); + } + + if (!values[index]) { + throw new InvalidPropertyError('Missing font family at ' + formatPosition(values[0][2][0]) + '. Ignoring.'); + } + + // ... and perhaps line-height + if (isSizeSet && values[index] && values[index][1] == Marker.FORWARD_SLASH && values[index + 1] && (validator.isLineHeightKeyword(values[index + 1][1]) || validator.isUnit(values[index + 1][1]) || validator.isNumber(values[index + 1][1]))) { + height.value = [values[index + 1]]; + index++; + index++; + } + + // ... and whatever comes next is font-family + family.value = []; + + while (values[index]) { + if (values[index][1] == Marker.COMMA) { + appendableFamilyName = false; + } else { + if (appendableFamilyName) { + family.value[family.value.length - 1][1] += Marker.SPACE + values[index][1]; + } else { + family.value.push(values[index]); + } + + appendableFamilyName = true; + } + + index++; + } + + if (family.value.length === 0) { + throw new InvalidPropertyError('Missing font family at ' + formatPosition(values[0][2][0]) + '. Ignoring.'); + } + + return components; +} + function fourValues(property, compactable) { var componentNames = compactable[property.name].components; var components = []; @@ -242,7 +439,7 @@ function multiplex(splitWith) { components[i].multiplex = true; for (j = 1, m = splitComponents.length; j < m; j++) { - components[i].value.push([Token.PROPERTY_VALUE, MULTIPLEX_SEPARATOR]); + components[i].value.push([Token.PROPERTY_VALUE, Marker.COMMA]); Array.prototype.push.apply(components[i].value, splitComponents[j][i].value); } } @@ -268,25 +465,26 @@ function listStyle(property, compactable, validator) { // `image` first... for (index = 0, total = values.length; index < total; index++) { - if (validator.isValidUrl(values[index][1]) || values[index][1] == '0') { + if (validator.isUrl(values[index][1]) || values[index][1] == '0') { image.value = [values[index]]; values.splice(index, 1); break; } } - // ... then `type`... + // ... then `position` for (index = 0, total = values.length; index < total; index++) { - if (validator.isValidListStyleType(values[index][1])) { - type.value = [values[index]]; + if (validator.isListStylePositionKeyword(values[index][1])) { + position.value = [values[index]]; values.splice(index, 1); break; } } - // ... and what's left is a `position` - if (values.length > 0 && validator.isValidListStylePosition(values[0][1])) - position.value = [values[0]]; + // ... and what's left is a `type` + if (values.length > 0 && (validator.isListStyleTypeKeyword(values[0][1]) || validator.isIdentifier(values[0][1]))) { + type.value = [values[0]]; + } return components; } @@ -352,9 +550,11 @@ function widthStyleColor(property, compactable, validator) { } module.exports = { + animation: animation, background: background, border: widthStyleColor, borderRadius: borderRadius, + font: font, fourValues: fourValues, listStyle: listStyle, multiplex: multiplex, diff --git a/node_modules/clean-css/lib/optimizer/level-2/can-override.js b/node_modules/clean-css/lib/optimizer/level-2/can-override.js index 2617234ca..10d3bba17 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/can-override.js +++ b/node_modules/clean-css/lib/optimizer/level-2/can-override.js @@ -1,11 +1,52 @@ var understandable = require('./properties/understandable'); +function animationIterationCount(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !(validator.isAnimationIterationCountKeyword(value2) || validator.isPositiveNumber(value2))) { + return false; + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { + return true; + } + + return validator.isAnimationIterationCountKeyword(value2) || validator.isPositiveNumber(value2); +} + +function animationName(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !(validator.isAnimationNameKeyword(value2) || validator.isIdentifier(value2))) { + return false; + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { + return true; + } + + return validator.isAnimationNameKeyword(value2) || validator.isIdentifier(value2); +} + +function animationTimingFunction(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !(validator.isAnimationTimingFunction(value2) || validator.isGlobal(value2))) { + return false; + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { + return true; + } + + return validator.isAnimationTimingFunction(value2) || validator.isGlobal(value2); +} + +function areSameFunction(validator, value1, value2) { + if (!validator.isFunction(value1) || !validator.isFunction(value2)) { + return false; + } + + var function1Name = value1.substring(0, value1.indexOf('(')); + var function2Name = value2.substring(0, value2.indexOf('(')); + + return function1Name === function2Name; +} + function backgroundPosition(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue('background-position', value2, true)) { + if (!understandable(validator, value1, value2, 0, true) && !(validator.isBackgroundPositionKeyword(value2) || validator.isGlobal(value2))) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; - } else if (validator.isValidKeywordValue('background-position', value2, true)) { + } else if (validator.isBackgroundPositionKeyword(value2) || validator.isGlobal(value2)) { return true; } @@ -13,11 +54,11 @@ function backgroundPosition(validator, value1, value2) { } function backgroundSize(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue('background-size', value2, true)) { + if (!understandable(validator, value1, value2, 0, true) && !(validator.isBackgroundSizeKeyword(value2) || validator.isGlobal(value2))) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; - } else if (validator.isValidKeywordValue('background-size', value2, true)) { + } else if (validator.isBackgroundSizeKeyword(value2) || validator.isGlobal(value2)) { return true; } @@ -25,15 +66,15 @@ function backgroundSize(validator, value1, value2) { } function color(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidColor(value2)) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isColor(value2)) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; - } else if (!validator.colorOpacity && (validator.isValidRgbaColor(value1) || validator.isValidHslaColor(value1))) { + } else if (!validator.colorOpacity && (validator.isRgbColor(value1) || validator.isHslColor(value1))) { return false; - } else if (!validator.colorOpacity && (validator.isValidRgbaColor(value2) || validator.isValidHslaColor(value2))) { + } else if (!validator.colorOpacity && (validator.isRgbColor(value2) || validator.isHslColor(value2))) { return false; - } else if (validator.isValidColor(value1) && validator.isValidColor(value2)) { + } else if (validator.isColor(value1) && validator.isColor(value2)) { return true; } @@ -46,14 +87,18 @@ function components(overrideCheckers) { }; } +function fontFamily(validator, value1, value2) { + return understandable(validator, value1, value2, 0, true); +} + function image(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidImage(value2)) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isImage(value2)) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; - } else if (validator.isValidImage(value2)) { + } else if (validator.isImage(value2)) { return true; - } else if (validator.isValidImage(value1)) { + } else if (validator.isImage(value1)) { return false; } @@ -62,56 +107,76 @@ function image(validator, value1, value2) { function keyword(propertyName) { return function(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue(propertyName, value2)) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isKeyword(propertyName)(value2)) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; } - return validator.isValidKeywordValue(propertyName, value2, false); + return validator.isKeyword(propertyName)(value2); }; } function keywordWithGlobal(propertyName) { return function(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue(propertyName, value2, true)) { + if (!understandable(validator, value1, value2, 0, true) && !(validator.isKeyword(propertyName)(value2) || validator.isGlobal(value2))) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; } - return validator.isValidKeywordValue(propertyName, value2, true); + return validator.isKeyword(propertyName)(value2) || validator.isGlobal(value2); }; } function sameFunctionOrValue(validator, value1, value2) { - return validator.areSameFunction(value1, value2) ? + return areSameFunction(validator, value1, value2) ? true : value1 === value2; } + + function textShadow(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidTextShadow(value2)) { + if (!understandable(validator, value1, value2, 0, true) && !(validator.isUnit(value2) || validator.isColor(value2) || validator.isGlobal(value2))) { + return false; + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { + return true; + } + + return validator.isUnit(value2) || validator.isColor(value2) || validator.isGlobal(value2); +} + +function time(validator, value1, value2) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isTime(value2)) { + return false; + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { + return true; + } else if (validator.isTime(value1) && !validator.isTime(value2)) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isTime(value2)) { + return true; + } else if (validator.isTime(value1)) { + return false; + } else if (validator.isFunction(value1) && !validator.isPrefixed(value1) && validator.isFunction(value2) && !validator.isPrefixed(value2)) { return true; } - return validator.isValidTextShadow(value2); + return sameFunctionOrValue(validator, value1, value2); } function unit(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidUnitWithoutFunction(value2)) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isUnit(value2)) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; - } else if (validator.isValidUnitWithoutFunction(value1) && !validator.isValidUnitWithoutFunction(value2)) { + } else if (validator.isUnit(value1) && !validator.isUnit(value2)) { return false; - } else if (validator.isValidUnitWithoutFunction(value2)) { + } else if (validator.isUnit(value2)) { return true; - } else if (validator.isValidUnitWithoutFunction(value1)) { + } else if (validator.isUnit(value1)) { return false; - } else if (validator.isValidFunctionWithoutVendorPrefix(value1) && validator.isValidFunctionWithoutVendorPrefix(value2)) { + } else if (validator.isFunction(value1) && !validator.isPrefixed(value1) && validator.isFunction(value2) && !validator.isPrefixed(value2)) { return true; } @@ -127,13 +192,13 @@ function unitOrKeywordWithGlobal(propertyName) { } function zIndex(validator, value1, value2) { - if (!understandable(validator, value1, value2, 0, true) && !validator.isValidZIndex(value2)) { + if (!understandable(validator, value1, value2, 0, true) && !validator.isZIndex(value2)) { return false; - } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; } - return validator.isValidZIndex(value2); + return validator.isZIndex(value2); } module.exports = { @@ -141,9 +206,16 @@ module.exports = { color: color, components: components, image: image, + time: time, unit: unit }, property: { + animationDirection: keywordWithGlobal('animation-direction'), + animationFillMode: keyword('animation-fill-mode'), + animationIterationCount: animationIterationCount, + animationName: animationName, + animationPlayState: keywordWithGlobal('animation-play-state'), + animationTimingFunction: animationTimingFunction, backgroundAttachment: keyword('background-attachment'), backgroundClip: keywordWithGlobal('background-clip'), backgroundOrigin: keyword('background-origin'), @@ -157,8 +229,11 @@ module.exports = { cursor: keywordWithGlobal('cursor'), display: keywordWithGlobal('display'), float: keywordWithGlobal('float'), - fontStyle: keywordWithGlobal('font-style'), left: unitOrKeywordWithGlobal('left'), + fontFamily: fontFamily, + fontStretch: keywordWithGlobal('font-stretch'), + fontStyle: keywordWithGlobal('font-style'), + fontVariant: keywordWithGlobal('font-variant'), fontWeight: keywordWithGlobal('font-weight'), listStyleType: keywordWithGlobal('list-style-type'), listStylePosition: keywordWithGlobal('list-style-position'), diff --git a/node_modules/clean-css/lib/optimizer/level-2/compactable.js b/node_modules/clean-css/lib/optimizer/level-2/compactable.js index 9cf334d44..97e7e2aca 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/compactable.js +++ b/node_modules/clean-css/lib/optimizer/level-2/compactable.js @@ -35,6 +35,141 @@ var override = require('../../utils/override'); // Puts the shorthand together from its components. // var compactable = { + 'animation': { + canOverride: canOverride.generic.components([ + canOverride.generic.time, + canOverride.property.animationTimingFunction, + canOverride.generic.time, + canOverride.property.animationIterationCount, + canOverride.property.animationDirection, + canOverride.property.animationFillMode, + canOverride.property.animationPlayState, + canOverride.property.animationName + ]), + components: [ + 'animation-duration', + 'animation-timing-function', + 'animation-delay', + 'animation-iteration-count', + 'animation-direction', + 'animation-fill-mode', + 'animation-play-state', + 'animation-name' + ], + breakUp: breakUp.multiplex(breakUp.animation), + defaultValue: 'none', + restore: restore.multiplex(restore.withoutDefaults), + shorthand: true, + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, + 'animation-delay': { + canOverride: canOverride.generic.time, + componentOf: [ + 'animation' + ], + defaultValue: '0s', + intoMultiplexMode: 'real', + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, + 'animation-direction': { + canOverride: canOverride.property.animationDirection, + componentOf: [ + 'animation' + ], + defaultValue: 'normal', + intoMultiplexMode: 'real', + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, + 'animation-duration': { + canOverride: canOverride.generic.time, + componentOf: [ + 'animation' + ], + defaultValue: '0s', + intoMultiplexMode: 'real', + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, + 'animation-fill-mode': { + canOverride: canOverride.property.animationFillMode, + componentOf: [ + 'animation' + ], + defaultValue: 'none', + intoMultiplexMode: 'real', + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, + 'animation-iteration-count': { + canOverride: canOverride.property.animationIterationCount, + componentOf: [ + 'animation' + ], + defaultValue: '1', + intoMultiplexMode: 'real', + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, + 'animation-name': { + canOverride: canOverride.property.animationName, + componentOf: [ + 'animation' + ], + defaultValue: 'none', + intoMultiplexMode: 'real', + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, + 'animation-play-state': { + canOverride: canOverride.property.animationPlayState, + componentOf: [ + 'animation' + ], + defaultValue: 'running', + intoMultiplexMode: 'real', + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, + 'animation-timing-function': { + canOverride: canOverride.property.animationTimingFunction, + componentOf: [ + 'animation' + ], + defaultValue: 'ease', + intoMultiplexMode: 'real', + vendorPrefixes: [ + '-moz-', + '-o-', + '-webkit-' + ] + }, 'background': { canOverride: canOverride.generic.components([ canOverride.generic.image, @@ -67,7 +202,8 @@ var compactable = { componentOf: [ 'background' ], - defaultValue: 'scroll' + defaultValue: 'scroll', + intoMultiplexMode: 'real' }, 'background-clip': { canOverride: canOverride.property.backgroundClip, @@ -75,6 +211,7 @@ var compactable = { 'background' ], defaultValue: 'border-box', + intoMultiplexMode: 'real', shortestValue: 'border-box' }, 'background-color': { @@ -83,6 +220,7 @@ var compactable = { 'background' ], defaultValue: 'transparent', + intoMultiplexMode: 'real', // otherwise real color will turn into default since color appears in last multiplex only multiplexLastOnly: true, nonMergeableValue: 'none', shortestValue: 'red' @@ -92,7 +230,8 @@ var compactable = { componentOf: [ 'background' ], - defaultValue: 'none' + defaultValue: 'none', + intoMultiplexMode: 'default' }, 'background-origin': { canOverride: canOverride.property.backgroundOrigin, @@ -100,6 +239,7 @@ var compactable = { 'background' ], defaultValue: 'padding-box', + intoMultiplexMode: 'real', shortestValue: 'border-box' }, 'background-position': { @@ -109,6 +249,7 @@ var compactable = { ], defaultValue: ['0', '0'], doubleValues: true, + intoMultiplexMode: 'real', shortestValue: '0' }, 'background-repeat': { @@ -117,7 +258,8 @@ var compactable = { 'background' ], defaultValue: ['repeat'], - doubleValues: true + doubleValues: true, + intoMultiplexMode: 'real' }, 'background-size': { canOverride: canOverride.property.backgroundSize, @@ -126,6 +268,7 @@ var compactable = { ], defaultValue: ['auto'], doubleValues: true, + intoMultiplexMode: 'real', shortestValue: '0 0' }, 'bottom': { @@ -216,6 +359,7 @@ var compactable = { 'border-width' ], defaultValue: 'medium', + oppositeTo: 'border-top-width', shortestValue: '0' }, 'border-collapse': { @@ -230,7 +374,9 @@ var compactable = { canOverride.generic.color, canOverride.generic.color ]), - componentOf: ['border'], + componentOf: [ + 'border' + ], components: [ 'border-top-color', 'border-right-color', @@ -281,6 +427,7 @@ var compactable = { 'border-width' ], defaultValue: 'medium', + oppositeTo: 'border-right-width', shortestValue: '0' }, 'border-radius': { @@ -344,6 +491,7 @@ var compactable = { 'border-width' ], defaultValue: 'medium', + oppositeTo: 'border-left-width', shortestValue: '0' }, 'border-style': { @@ -428,6 +576,7 @@ var compactable = { 'border-width' ], defaultValue: 'medium', + oppositeTo: 'border-bottom-width', shortestValue: '0' }, 'border-width': { @@ -438,6 +587,9 @@ var compactable = { canOverride.generic.unit, canOverride.generic.unit ]), + componentOf: [ + 'border' + ], components: [ 'border-top-width', 'border-right-width', @@ -469,18 +621,53 @@ var compactable = { canOverride: canOverride.property.float, defaultValue: 'none' }, + 'font': { + breakUp: breakUp.font, + canOverride: canOverride.generic.components([ + canOverride.property.fontStyle, + canOverride.property.fontVariant, + canOverride.property.fontWeight, + canOverride.property.fontStretch, + canOverride.generic.unit, + canOverride.generic.unit, + canOverride.property.fontFamily + ]), + components: [ + 'font-style', + 'font-variant', + 'font-weight', + 'font-stretch', + 'font-size', + 'line-height', + 'font-family' + ], + restore: restore.font, + shorthand: true + }, + 'font-family': { + canOverride: canOverride.property.fontFamily, + defaultValue: 'user|agent|specific' + }, 'font-size': { canOverride: canOverride.generic.unit, defaultValue: 'medium', shortestValue: '0' }, + 'font-stretch': { + canOverride: canOverride.property.fontStretch, + defaultValue: 'normal' + }, 'font-style': { canOverride: canOverride.property.fontStyle, defaultValue: 'normal' }, + 'font-variant': { + canOverride: canOverride.property.fontVariant, + defaultValue: 'normal' + }, 'font-weight': { canOverride: canOverride.property.fontWeight, - defaultValue: '400', + defaultValue: 'normal', shortestValue: '400' }, 'height': { @@ -563,28 +750,32 @@ var compactable = { componentOf: [ 'margin' ], - defaultValue: '0' + defaultValue: '0', + oppositeTo: 'margin-top' }, 'margin-left': { canOverride: canOverride.generic.unit, componentOf: [ 'margin' ], - defaultValue: '0' + defaultValue: '0', + oppositeTo: 'margin-right' }, 'margin-right': { canOverride: canOverride.generic.unit, componentOf: [ 'margin' ], - defaultValue: '0' + defaultValue: '0', + oppositeTo: 'margin-left' }, 'margin-top': { canOverride: canOverride.generic.unit, componentOf: [ 'margin' ], - defaultValue: '0' + defaultValue: '0', + oppositeTo: 'margin-bottom' }, 'outline': { canOverride: canOverride.generic.components([ @@ -660,28 +851,32 @@ var compactable = { componentOf: [ 'padding' ], - defaultValue: '0' + defaultValue: '0', + oppositeTo: 'padding-top' }, 'padding-left': { canOverride: canOverride.generic.unit, componentOf: [ 'padding' ], - defaultValue: '0' + defaultValue: '0', + oppositeTo: 'padding-right' }, 'padding-right': { canOverride: canOverride.generic.unit, componentOf: [ 'padding' ], - defaultValue: '0' + defaultValue: '0', + oppositeTo: 'padding-left' }, 'padding-top': { canOverride: canOverride.generic.unit, componentOf: [ 'padding' ], - defaultValue: '0' + defaultValue: '0', + oppositeTo: 'padding-bottom' }, 'position': { canOverride: canOverride.property.position, diff --git a/node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js b/node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js index 4a91a8331..29049302a 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js +++ b/node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js @@ -14,6 +14,19 @@ var PSEUDO_CLASSES_WITH_ARGUMENTS = [ ':nth-of-type' ]; var RELATION_PATTERN = /[>\+~]/; +var UNMIXABLE_PSEUDO_CLASSES = [ + ':after', + ':before', + ':first-letter', + ':first-line', + ':lang' +]; +var UNMIXABLE_PSEUDO_ELEMENTS = [ + '::after', + '::before', + '::first-letter', + '::first-line' +]; var Level = { DOUBLE_QUOTE: 'double-quote', @@ -21,7 +34,7 @@ var Level = { ROOT: 'root' }; -function isMergeable(selector, mergeablePseudoClasses, mergeablePseudoElements) { +function isMergeable(selector, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) { var singleSelectors = split(selector, Marker.COMMA); var singleSelector; var i, l; @@ -31,7 +44,7 @@ function isMergeable(selector, mergeablePseudoClasses, mergeablePseudoElements) if (singleSelector.length === 0 || isDeepSelector(singleSelector) || - (singleSelector.indexOf(Marker.COLON) > -1 && !areMergeable(singleSelector, extractPseudoFrom(singleSelector), mergeablePseudoClasses, mergeablePseudoElements))) { + (singleSelector.indexOf(Marker.COLON) > -1 && !areMergeable(singleSelector, extractPseudoFrom(singleSelector), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging))) { return false; } } @@ -122,11 +135,11 @@ function extractPseudoFrom(selector) { return list; } -function areMergeable(selector, matches, mergeablePseudoClasses, mergeablePseudoElements) { +function areMergeable(selector, matches, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) { return areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements) && needArguments(matches) && (matches.length < 2 || !someIncorrectlyChained(selector, matches)) && - (matches.length < 2 || !someMixed(matches)); + (matches.length < 2 || multiplePseudoMerging && allMixable(matches)); } function areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements) { @@ -217,20 +230,30 @@ function someIncorrectlyChained(selector, matches) { return false; } -function someMixed(matches) { - var firstIsPseudoElement = DOUBLE_COLON_PATTERN.test(matches[0]); +function allMixable(matches) { + var unmixableMatches = 0; var match; var i, l; for (i = 0, l = matches.length; i < l; i++) { match = matches[i]; - if (DOUBLE_COLON_PATTERN.test(match) != firstIsPseudoElement) { - return true; + if (isPseudoElement(match)) { + unmixableMatches += UNMIXABLE_PSEUDO_ELEMENTS.indexOf(match) > -1 ? 1 : 0; + } else { + unmixableMatches += UNMIXABLE_PSEUDO_CLASSES.indexOf(match) > -1 ? 1 : 0; + } + + if (unmixableMatches > 1) { + return false; } } - return false; + return true; +} + +function isPseudoElement(pseudo) { + return DOUBLE_COLON_PATTERN.test(pseudo); } module.exports = isMergeable; diff --git a/node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js b/node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js index 7c0537501..b148bacd7 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js +++ b/node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js @@ -19,7 +19,8 @@ function mergeAdjacent(tokens, context) { var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod; var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses; var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements; - var mergeLimit = 8191; + var mergeLimit = options.compatibility.selectors.mergeLimit; + var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging; for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; @@ -34,8 +35,8 @@ function mergeAdjacent(tokens, context) { optimizeProperties(lastToken[2], true, true, context); token[2] = []; } else if (lastToken[0] == Token.RULE && serializeBody(token[2]) == serializeBody(lastToken[2]) && - isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements) && - isMergeable(serializeRules(lastToken[1]), mergeablePseudoClasses, mergeablePseudoElements) && + isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) && + isMergeable(serializeRules(lastToken[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) && lastToken[1].length < mergeLimit) { lastToken[1] = tidyRules(lastToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings); lastToken[1] = lastToken.length > 1 ? sortSelectors(lastToken[1], selectorsSortingMethod) : lastToken[1]; diff --git a/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js b/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js index bdcf53ec0..82db950fe 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js +++ b/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js @@ -42,6 +42,7 @@ function mergeNonAdjacentByBody(tokens, context) { var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod; var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses; var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements; + var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging; var candidates = {}; for (var i = tokens.length - 1; i >= 0; i--) { @@ -58,8 +59,8 @@ function mergeNonAdjacentByBody(tokens, context) { var candidateBody = serializeBody(token[2]); var oldToken = candidates[candidateBody]; if (oldToken && - isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements) && - isMergeable(serializeRules(oldToken[1]), mergeablePseudoClasses, mergeablePseudoElements)) { + isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) && + isMergeable(serializeRules(oldToken[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging)) { if (token[2].length > 0) { token[1] = tidyRules(oldToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings); diff --git a/node_modules/clean-css/lib/optimizer/level-2/optimize.js b/node_modules/clean-css/lib/optimizer/level-2/optimize.js index 78cd44666..9be961d09 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/optimize.js +++ b/node_modules/clean-css/lib/optimizer/level-2/optimize.js @@ -6,6 +6,7 @@ var reduceNonAdjacent = require('./reduce-non-adjacent'); var removeDuplicateFontAtRules = require('./remove-duplicate-font-at-rules'); var removeDuplicateMediaQueries = require('./remove-duplicate-media-queries'); var removeDuplicates = require('./remove-duplicates'); +var removeUnusedAtRules = require('./remove-unused-at-rules'); var restructure = require('./restructure'); var optimizeProperties = require('./properties/optimize'); @@ -27,6 +28,9 @@ function removeEmpty(tokens) { removeEmpty(token[2]); isEmpty = token[2].length === 0; break; + case Token.AT_RULE: + isEmpty = token[1].length === 0; + break; case Token.AT_RULE_BLOCK: isEmpty = token[2].length === 0; } @@ -109,6 +113,10 @@ function level2Optimize(tokens, context, withRestructuring) { removeDuplicateMediaQueries(tokens, context); } + if (levelOptions.removeUnusedAtRules) { + removeUnusedAtRules(tokens, context); + } + if (levelOptions.mergeMedia) { reduced = mergeMediaQueries(tokens, context); for (i = reduced.length - 1; i >= 0; i--) { @@ -116,7 +124,9 @@ function level2Optimize(tokens, context, withRestructuring) { } } - removeEmpty(tokens); + if (levelOptions.removeEmpty) { + removeEmpty(tokens); + } return tokens; } diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/is-mergeable-shorthand.js b/node_modules/clean-css/lib/optimizer/level-2/properties/is-mergeable-shorthand.js new file mode 100644 index 000000000..ee7191ef6 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/is-mergeable-shorthand.js @@ -0,0 +1,11 @@ +var Marker = require('../../../tokenizer/marker'); + +function isMergeableShorthand(shorthand) { + if (shorthand.name != 'font') { + return true; + } + + return shorthand.value[0][1].indexOf(Marker.INTERNAL) == -1; +} + +module.exports = isMergeableShorthand; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js b/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js index a75c4ed63..bcfeeb609 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js @@ -4,52 +4,410 @@ var populateComponents = require('./populate-components'); var compactable = require('../compactable'); var deepClone = require('../clone').deep; +var restoreWithComponents = require('../restore-with-components'); +var restoreFromOptimizing = require('../../restore-from-optimizing'); var wrapSingle = require('../../wrap-for-optimizing').single; +var serializeBody = require('../../../writer/one-time').body; var Token = require('../../../tokenizer/token'); +function mergeIntoShorthands(properties, validator) { + var candidates = {}; + var descriptor; + var componentOf; + var property; + var i, l; + var j, m; + + // there is no shorthand property made up of less than 3 longhands + if (properties.length < 3) { + return; + } + + for (i = 0, l = properties.length; i < l; i++) { + property = properties[i]; + descriptor = compactable[property.name]; + + if (property.unused) { + continue; + } + + if (property.hack) { + continue; + } + + if (property.block) { + continue; + } + + invalidateOrCompact(properties, i, candidates, validator); + + if (descriptor && descriptor.componentOf) { + for (j = 0, m = descriptor.componentOf.length; j < m; j++) { + componentOf = descriptor.componentOf[j]; + + candidates[componentOf] = candidates[componentOf] || {}; + candidates[componentOf][property.name] = property; + } + } + } + + invalidateOrCompact(properties, i, candidates, validator); +} + +function invalidateOrCompact(properties, position, candidates, validator) { + var invalidatedBy = properties[position]; + var shorthandName; + var shorthandDescriptor; + var candidateComponents; + + for (shorthandName in candidates) { + if (undefined !== invalidatedBy && shorthandName == invalidatedBy.name) { + continue; + } + + shorthandDescriptor = compactable[shorthandName]; + candidateComponents = candidates[shorthandName]; + if (invalidatedBy && invalidates(candidates, shorthandName, invalidatedBy)) { + delete candidates[shorthandName]; + continue; + } + + if (shorthandDescriptor.components.length > Object.keys(candidateComponents).length) { + continue; + } + + if (mixedImportance(candidateComponents)) { + continue; + } + + if (!overridable(candidateComponents, shorthandName, validator)) { + continue; + } + + if (!mergeable(candidateComponents)) { + continue; + } + + if (mixedInherit(candidateComponents)) { + replaceWithInheritBestFit(properties, candidateComponents, shorthandName, validator); + } else { + replaceWithShorthand(properties, candidateComponents, shorthandName, validator); + } + } +} + +function invalidates(candidates, shorthandName, invalidatedBy) { + var shorthandDescriptor = compactable[shorthandName]; + var invalidatedByDescriptor = compactable[invalidatedBy.name]; + var componentName; + + if ('overridesShorthands' in shorthandDescriptor && shorthandDescriptor.overridesShorthands.indexOf(invalidatedBy.name) > -1) { + return true; + } + + if (invalidatedByDescriptor && 'componentOf' in invalidatedByDescriptor) { + for (componentName in candidates[shorthandName]) { + if (invalidatedByDescriptor.componentOf.indexOf(componentName) > -1) { + return true; + } + } + } + + return false; +} + function mixedImportance(components) { var important; + var componentName; - for (var name in components) { - if (undefined !== important && components[name].important != important) + for (componentName in components) { + if (undefined !== important && components[componentName].important != important) { return true; + } - important = components[name].important; + important = components[componentName].important; } return false; } +function overridable(components, shorthandName, validator) { + var descriptor = compactable[shorthandName]; + var newValuePlaceholder = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, shorthandName], + [Token.PROPERTY_VALUE, descriptor.defaultValue] + ]; + var newProperty = wrapSingle(newValuePlaceholder); + var component; + var mayOverride; + var i, l; + + populateComponents([newProperty], validator, []); + + for (i = 0, l = descriptor.components.length; i < l; i++) { + component = components[descriptor.components[i]]; + mayOverride = compactable[component.name].canOverride; + + if (!everyValuesPair(mayOverride.bind(null, validator), newProperty.components[i], component)) { + return false; + } + } + + return true; +} + +function mergeable(components) { + var lastCount = null; + var currentCount; + var componentName; + var component; + var descriptor; + var values; + + for (componentName in components) { + component = components[componentName]; + descriptor = compactable[componentName]; + + if (!('restore' in descriptor)) { + continue; + } + + restoreFromOptimizing([component.all[component.position]], restoreWithComponents); + values = descriptor.restore(component, compactable); + + currentCount = values.length; + + if (lastCount !== null && currentCount !== lastCount) { + return false; + } + + lastCount = currentCount; + } + + return true; +} + +function mixedInherit(components) { + var componentName; + var lastValue = null; + var currentValue; + + for (componentName in components) { + currentValue = hasInherit(components[componentName]); + + if (lastValue !== null && lastValue !== currentValue) { + return true; + } + + lastValue = currentValue; + } + + return false; +} + +function replaceWithInheritBestFit(properties, candidateComponents, shorthandName, validator) { + var viaLonghands = buildSequenceWithInheritLonghands(candidateComponents, shorthandName, validator); + var viaShorthand = buildSequenceWithInheritShorthand(candidateComponents, shorthandName, validator); + var longhandTokensSequence = viaLonghands[0]; + var shorthandTokensSequence = viaShorthand[0]; + var isLonghandsShorter = serializeBody(longhandTokensSequence).length < serializeBody(shorthandTokensSequence).length; + var newTokensSequence = isLonghandsShorter ? longhandTokensSequence : shorthandTokensSequence; + var newProperty = isLonghandsShorter ? viaLonghands[1] : viaShorthand[1]; + var newComponents = isLonghandsShorter ? viaLonghands[2] : viaShorthand[2]; + var all = candidateComponents[Object.keys(candidateComponents)[0]].all; + var componentName; + var oldComponent; + var newComponent; + var newToken; + + newProperty.position = all.length; + newProperty.shorthand = true; + newProperty.dirty = true; + newProperty.all = all; + newProperty.all.push(newTokensSequence[0]); + + properties.push(newProperty); + + for (componentName in candidateComponents) { + oldComponent = candidateComponents[componentName]; + oldComponent.unused = true; + + if (oldComponent.name in newComponents) { + newComponent = newComponents[oldComponent.name]; + newToken = findTokenIn(newTokensSequence, componentName); + + newComponent.position = all.length; + newComponent.all = all; + newComponent.all.push(newToken); + + properties.push(newComponent); + } + } +} + +function buildSequenceWithInheritLonghands(components, shorthandName, validator) { + var tokensSequence = []; + var inheritComponents = {}; + var nonInheritComponents = {}; + var descriptor = compactable[shorthandName]; + var shorthandToken = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, shorthandName], + [Token.PROPERTY_VALUE, descriptor.defaultValue] + ]; + var newProperty = wrapSingle(shorthandToken); + var component; + var longhandToken; + var newComponent; + var nameMetadata; + var i, l; + + populateComponents([newProperty], validator, []); + + for (i = 0, l = descriptor.components.length; i < l; i++) { + component = components[descriptor.components[i]]; + + if (hasInherit(component)) { + longhandToken = component.all[component.position].slice(0, 2); + Array.prototype.push.apply(longhandToken, component.value); + tokensSequence.push(longhandToken); + + newComponent = deepClone(component); + newComponent.value = inferComponentValue(components, newComponent.name); + + newProperty.components[i] = newComponent; + inheritComponents[component.name] = deepClone(component); + } else { + newComponent = deepClone(component); + newComponent.all = component.all; + newProperty.components[i] = newComponent; + + nonInheritComponents[component.name] = component; + } + } + + nameMetadata = joinMetadata(nonInheritComponents, 1); + shorthandToken[1].push(nameMetadata); + + restoreFromOptimizing([newProperty], restoreWithComponents); + + shorthandToken = shorthandToken.slice(0, 2); + Array.prototype.push.apply(shorthandToken, newProperty.value); + + tokensSequence.unshift(shorthandToken); + + return [tokensSequence, newProperty, inheritComponents]; +} + +function inferComponentValue(components, propertyName) { + var descriptor = compactable[propertyName]; + + if ('oppositeTo' in descriptor) { + return components[descriptor.oppositeTo].value; + } else { + return [[Token.PROPERTY_VALUE, descriptor.defaultValue]]; + } +} + function joinMetadata(components, at) { var metadata = []; var component; var originalValue; var componentMetadata; - var name; + var componentName; - for (name in components) { - component = components[name]; + for (componentName in components) { + component = components[componentName]; originalValue = component.all[component.position]; componentMetadata = originalValue[at][originalValue[at].length - 1]; Array.prototype.push.apply(metadata, componentMetadata); } - return metadata; + return metadata.sort(metadataSorter); +} + +function metadataSorter(metadata1, metadata2) { + var line1 = metadata1[0]; + var line2 = metadata2[0]; + var column1 = metadata1[1]; + var column2 = metadata2[1]; + + if (line1 < line2) { + return -1; + } else if (line1 === line2) { + return column1 < column2 ? -1 : 1; + } else { + return 1; + } } -function replaceWithShorthand(properties, candidateComponents, name, validator) { - var descriptor = compactable[name]; +function buildSequenceWithInheritShorthand(components, shorthandName, validator) { + var tokensSequence = []; + var inheritComponents = {}; + var nonInheritComponents = {}; + var descriptor = compactable[shorthandName]; + var shorthandToken = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, shorthandName], + [Token.PROPERTY_VALUE, 'inherit'] + ]; + var newProperty = wrapSingle(shorthandToken); + var component; + var longhandToken; + var nameMetadata; + var valueMetadata; + var i, l; + + populateComponents([newProperty], validator, []); + + for (i = 0, l = descriptor.components.length; i < l; i++) { + component = components[descriptor.components[i]]; + + if (hasInherit(component)) { + inheritComponents[component.name] = component; + } else { + longhandToken = component.all[component.position].slice(0, 2); + Array.prototype.push.apply(longhandToken, component.value); + tokensSequence.push(longhandToken); + + nonInheritComponents[component.name] = deepClone(component); + } + } + + nameMetadata = joinMetadata(inheritComponents, 1); + shorthandToken[1].push(nameMetadata); + + valueMetadata = joinMetadata(inheritComponents, 2); + shorthandToken[2].push(valueMetadata); + + tokensSequence.unshift(shorthandToken); + + return [tokensSequence, newProperty, nonInheritComponents]; +} + +function findTokenIn(tokens, componentName) { + var i, l; + + for (i = 0, l = tokens.length; i < l; i++) { + if (tokens[i][1][1] == componentName) { + return tokens[i]; + } + } +} + +function replaceWithShorthand(properties, candidateComponents, shorthandName, validator) { + var descriptor = compactable[shorthandName]; var nameMetadata; var valueMetadata; var newValuePlaceholder = [ Token.PROPERTY, - [Token.PROPERTY_NAME, name], + [Token.PROPERTY_NAME, shorthandName], [Token.PROPERTY_VALUE, descriptor.defaultValue] ]; - var mayOverride; var all; var newProperty = wrapSingle(newValuePlaceholder); @@ -61,13 +419,6 @@ function replaceWithShorthand(properties, candidateComponents, name, validator) for (var i = 0, l = descriptor.components.length; i < l; i++) { var component = candidateComponents[descriptor.components[i]]; - if (hasInherit(component)) - return; - - mayOverride = compactable[component.name].canOverride; - if (!everyValuesPair(mayOverride.bind(null, validator), newProperty.components[i], component)) - return; - newProperty.components[i] = deepClone(component); newProperty.important = component.important; @@ -91,67 +442,4 @@ function replaceWithShorthand(properties, candidateComponents, name, validator) properties.push(newProperty); } -function invalidateOrCompact(properties, position, candidates, validator) { - var property = properties[position]; - - for (var name in candidates) { - if (undefined !== property && name == property.name) - continue; - - var descriptor = compactable[name]; - var candidateComponents = candidates[name]; - if (descriptor.components.length > Object.keys(candidateComponents).length) { - delete candidates[name]; - continue; - } - - if (mixedImportance(candidateComponents)) - continue; - - replaceWithShorthand(properties, candidateComponents, name, validator); - } -} - -function mergeIntoShorthands(properties, validator) { - var candidates = {}; - var descriptor; - var componentOf; - var property; - var i, l; - var j, m; - - if (properties.length < 3) - return; - - for (i = 0, l = properties.length; i < l; i++) { - property = properties[i]; - - if (property.unused) - continue; - - if (property.hack) - continue; - - if (property.block) - continue; - - descriptor = compactable[property.name]; - if (!descriptor || !descriptor.componentOf) - continue; - - if (property.shorthand) { - invalidateOrCompact(properties, i, candidates, validator); - } else { - for (j = 0, m = descriptor.componentOf.length; j < m; j++) { - componentOf = descriptor.componentOf[j]; - - candidates[componentOf] = candidates[componentOf] || {}; - candidates[componentOf][property.name] = property; - } - } - } - - invalidateOrCompact(properties, i, candidates, validator); -} - module.exports = mergeIntoShorthands; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js b/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js index 250b05fc4..5dc4bfb98 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js @@ -11,7 +11,8 @@ var restoreFromOptimizing = require('../../restore-from-optimizing'); var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel; function optimizeProperties(properties, withOverriding, withMerging, context) { - var _properties = wrapForOptimizing(properties, false); + var levelOptions = context.options.level[OptimizationLevel.Two]; + var _properties = wrapForOptimizing(properties, false, levelOptions.skipProperties); var _property; var i, l; @@ -24,12 +25,12 @@ function optimizeProperties(properties, withOverriding, withMerging, context) { } } - if (withOverriding && context.options.level[OptimizationLevel.Two].overrideProperties) { - overrideProperties(_properties, withMerging, context.options.compatibility, context.validator); + if (withMerging && levelOptions.mergeIntoShorthands) { + mergeIntoShorthands(_properties, context.validator); } - if (withMerging && context.options.level[OptimizationLevel.Two].mergeIntoShorthands) { - mergeIntoShorthands(_properties, context.validator); + if (withOverriding && levelOptions.overrideProperties) { + overrideProperties(_properties, withMerging, context.options.compatibility, context.validator); } restoreFromOptimizing(_properties, restoreWithComponents); diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js b/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js index 3c9d8d2af..3749720c9 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js @@ -2,6 +2,7 @@ var hasInherit = require('./has-inherit'); var everyValuesPair = require('./every-values-pair'); var findComponentIn = require('./find-component-in'); var isComponentOf = require('./is-component-of'); +var isMergeableShorthand = require('./is-mergeable-shorthand'); var overridesNonComponentShorthand = require('./overrides-non-component-shorthand'); var sameVendorPrefixesIn = require('./vendor-prefixes').same; @@ -73,16 +74,44 @@ function overrideShorthand(property, by) { function turnIntoMultiplex(property, size) { property.multiplex = true; - for (var i = 0, l = property.components.length; i < l; i++) { - var component = property.components[i]; - if (component.multiplex) - continue; + if (compactable[property.name].shorthand) { + turnShorthandValueIntoMultiplex(property, size); + } else { + turnLonghandValueIntoMultiplex(property, size); + } +} - var value = component.value.slice(0); +function turnShorthandValueIntoMultiplex(property, size) { + var component; + var i, l; - for (var j = 1; j < size; j++) { - component.value.push([Token.PROPERTY_VALUE, Marker.COMMA]); - Array.prototype.push.apply(component.value, value); + for (i = 0, l = property.components.length; i < l; i++) { + component = property.components[i]; + + if (!component.multiplex) { + turnLonghandValueIntoMultiplex(component, size); + } + } +} + +function turnLonghandValueIntoMultiplex(property, size) { + var withRealValue = compactable[property.name].intoMultiplexMode == 'real'; + var withValue = withRealValue ? + property.value.slice(0) : + compactable[property.name].defaultValue; + var i = multiplexSize(property); + var j; + var m = withValue.length; + + for (; i < size; i++) { + property.value.push([Token.PROPERTY_VALUE, Marker.COMMA]); + + if (Array.isArray(withValue)) { + for (j = 0; j < m; j++) { + property.value.push(withRealValue ? withValue[j] : [Token.PROPERTY_VALUE, withValue[j]]); + } + } else { + property.value.push(withRealValue ? withValue : [Token.PROPERTY_VALUE, withValue]); } } } @@ -124,8 +153,9 @@ function moreSameShorthands(properties, startAt, name) { function overridingFunction(shorthand, validator) { for (var i = 0, l = shorthand.components.length; i < l; i++) { - if (anyValue(validator.isValidFunction, shorthand.components[i])) + if (!anyValue(validator.isUrl, shorthand.components[i]) && anyValue(validator.isFunction, shorthand.components[i])) { return true; + } } return false; @@ -271,8 +301,13 @@ function overrideProperties(properties, withMerging, compatibility, validator) { if (!sameVendorPrefixesIn([left], right.components)) continue; - if (!anyValue(validator.isValidFunction, left) && overridingFunction(right, validator)) + if (!anyValue(validator.isFunction, left) && overridingFunction(right, validator)) + continue; + + if (!isMergeableShorthand(right)) { + left.unused = true; continue; + } component = findComponentIn(right, left); mayOverride = compactable[left.name].canOverride; @@ -289,7 +324,7 @@ function overrideProperties(properties, withMerging, compatibility, validator) { continue; } - if (!anyValue(validator.isValidFunction, left) && overridingFunction(right, validator)) { + if (!anyValue(validator.isFunction, left) && overridingFunction(right, validator)) { continue; } @@ -325,6 +360,9 @@ function overrideProperties(properties, withMerging, compatibility, validator) { if (overridingFunction(left, validator)) continue; + if (!isMergeableShorthand(left)) + continue; + component = findComponentIn(left, right); if (everyValuesPair(mayOverride.bind(null, validator), component, right)) { var disabledBackgroundMerging = @@ -367,6 +405,11 @@ function overrideProperties(properties, withMerging, compatibility, validator) { continue; } + if (!isMergeableShorthand(right)) { + left.unused = true; + continue; + } + for (k = left.components.length - 1; k >= 0; k--) { var leftComponent = left.components[k]; var rightComponent = right.components[k]; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/understandable.js b/node_modules/clean-css/lib/optimizer/level-2/properties/understandable.js index 6c77db50d..032169a24 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/properties/understandable.js +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/understandable.js @@ -5,7 +5,7 @@ function understandable(validator, value1, value2, _position, isPaired) { return false; } - if (isPaired && validator.isValidVariable(value1) !== validator.isValidVariable(value2)) { + if (isPaired && validator.isVariable(value1) !== validator.isVariable(value2)) { return false; } diff --git a/node_modules/clean-css/lib/optimizer/level-2/reduce-non-adjacent.js b/node_modules/clean-css/lib/optimizer/level-2/reduce-non-adjacent.js index 3461bb268..6ce0902b9 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/reduce-non-adjacent.js +++ b/node_modules/clean-css/lib/optimizer/level-2/reduce-non-adjacent.js @@ -13,6 +13,7 @@ function reduceNonAdjacent(tokens, context) { var options = context.options; var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses; var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements; + var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging; var candidates = {}; var repeated = []; @@ -27,7 +28,7 @@ function reduceNonAdjacent(tokens, context) { var selectorAsString = serializeRules(token[1]); var isComplexAndNotSpecial = token[1].length > 1 && - isMergeable(selectorAsString, mergeablePseudoClasses, mergeablePseudoElements); + isMergeable(selectorAsString, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging); var wrappedSelectors = wrappedSelectorsFrom(token[1]); var selectors = isComplexAndNotSpecial ? [selectorAsString].concat(wrappedSelectors) : @@ -88,6 +89,7 @@ function reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, con function reduceComplexNonAdjacentCases(tokens, candidates, options, context) { var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses; var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements; + var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging; var localContext = {}; function filterOut(idx) { @@ -109,7 +111,7 @@ function reduceComplexNonAdjacentCases(tokens, candidates, options, context) { var intoToken = tokens[intoPosition]; var reducedBodies = []; - var selectors = isMergeable(complexSelector, mergeablePseudoClasses, mergeablePseudoElements) ? + var selectors = isMergeable(complexSelector, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) ? into[0].list : [complexSelector]; diff --git a/node_modules/clean-css/lib/optimizer/level-2/remove-unused-at-rules.js b/node_modules/clean-css/lib/optimizer/level-2/remove-unused-at-rules.js new file mode 100644 index 000000000..e60d5e7c2 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/remove-unused-at-rules.js @@ -0,0 +1,232 @@ +var populateComponents = require('./properties/populate-components'); + +var wrapForOptimizing = require('../wrap-for-optimizing').single; +var restoreFromOptimizing = require('../restore-from-optimizing'); + +var Token = require('../../tokenizer/token'); + +var animationNameRegex = /^(\-moz\-|\-o\-|\-webkit\-)?animation-name$/; +var animationRegex = /^(\-moz\-|\-o\-|\-webkit\-)?animation$/; +var keyframeRegex = /^@(\-moz\-|\-o\-|\-webkit\-)?keyframes /; + +function removeUnusedAtRules(tokens, context) { + removeUnusedAtRule(tokens, matchCounterStyle, markCounterStylesAsUsed, context); + removeUnusedAtRule(tokens, matchFontFace, markFontFacesAsUsed, context); + removeUnusedAtRule(tokens, matchKeyframe, markKeyframesAsUsed, context); + removeUnusedAtRule(tokens, matchNamespace, markNamespacesAsUsed, context); +} + +function removeUnusedAtRule(tokens, matchCallback, markCallback, context) { + var atRules = {}; + var atRule; + var token; + var zeroAt; + var i, l; + + for (i = 0, l = tokens.length; i < l; i++) { + matchCallback(tokens[i], atRules); + } + + if (Object.keys(atRules).length === 0) { + return; + } + + markUsedAtRules(tokens, markCallback, atRules, context); + + for (atRule in atRules) { + token = atRules[atRule]; + zeroAt = token[0] == Token.AT_RULE ? 1 : 2; + token[zeroAt] = []; + } +} + +function markUsedAtRules(tokens, markCallback, atRules, context) { + var boundMarkCallback = markCallback(atRules); + var i, l; + + for (i = 0, l = tokens.length; i < l; i++) { + switch (tokens[i][0]) { + case Token.RULE: + boundMarkCallback(tokens[i], context); + break; + case Token.NESTED_BLOCK: + markUsedAtRules(tokens[i][2], markCallback, atRules, context); + } + } +} + +function matchCounterStyle(token, atRules) { + var match; + + if (token[0] == Token.AT_RULE_BLOCK && token[1][0][1].indexOf('@counter-style') === 0) { + match = token[1][0][1].split(' ')[1]; + atRules[match] = token; + } +} + +function markCounterStylesAsUsed(atRules) { + return function (token, context) { + var property; + var wrappedProperty; + var i, l; + + for (i = 0, l = token[2].length; i < l; i++) { + property = token[2][i]; + + if (property[1][1] == 'list-style') { + wrappedProperty = wrapForOptimizing(property); + populateComponents([wrappedProperty], context.validator, context.warnings); + + if (wrappedProperty.components[0].value[0][1] in atRules) { + delete atRules[property[2][1]]; + } + + restoreFromOptimizing([wrappedProperty]); + } + + if (property[1][1] == 'list-style-type' && property[2][1] in atRules) { + delete atRules[property[2][1]]; + } + } + }; +} + +function matchFontFace(token, atRules) { + var property; + var match; + var i, l; + + if (token[0] == Token.AT_RULE_BLOCK && token[1][0][1] == '@font-face') { + for (i = 0, l = token[2].length; i < l; i++) { + property = token[2][i]; + + if (property[1][1] == 'font-family') { + match = property[2][1].toLowerCase(); + atRules[match] = token; + break; + } + } + } +} + +function markFontFacesAsUsed(atRules) { + return function (token, context) { + var property; + var wrappedProperty; + var component; + var normalizedMatch; + var i, l; + var j, m; + + for (i = 0, l = token[2].length; i < l; i++) { + property = token[2][i]; + + if (property[1][1] == 'font') { + wrappedProperty = wrapForOptimizing(property); + populateComponents([wrappedProperty], context.validator, context.warnings); + component = wrappedProperty.components[6]; + + for (j = 0, m = component.value.length; j < m; j++) { + normalizedMatch = component.value[j][1].toLowerCase(); + + if (normalizedMatch in atRules) { + delete atRules[normalizedMatch]; + } + } + + restoreFromOptimizing([wrappedProperty]); + } + + if (property[1][1] == 'font-family') { + for (j = 2, m = property.length; j < m; j++) { + normalizedMatch = property[j][1].toLowerCase(); + + if (normalizedMatch in atRules) { + delete atRules[normalizedMatch]; + } + } + } + } + }; +} + +function matchKeyframe(token, atRules) { + var match; + + if (token[0] == Token.NESTED_BLOCK && keyframeRegex.test(token[1][0][1])) { + match = token[1][0][1].split(' ')[1]; + atRules[match] = token; + } +} + +function markKeyframesAsUsed(atRules) { + return function (token, context) { + var property; + var wrappedProperty; + var component; + var i, l; + var j, m; + + for (i = 0, l = token[2].length; i < l; i++) { + property = token[2][i]; + + if (animationRegex.test(property[1][1])) { + wrappedProperty = wrapForOptimizing(property); + populateComponents([wrappedProperty], context.validator, context.warnings); + component = wrappedProperty.components[7]; + + for (j = 0, m = component.value.length; j < m; j++) { + if (component.value[j][1] in atRules) { + delete atRules[component.value[j][1]]; + } + } + + restoreFromOptimizing([wrappedProperty]); + } + + if (animationNameRegex.test(property[1][1])) { + for (j = 2, m = property.length; j < m; j++) { + if (property[j][1] in atRules) { + delete atRules[property[j][1]]; + } + } + } + } + }; +} + +function matchNamespace(token, atRules) { + var match; + + if (token[0] == Token.AT_RULE && token[1].indexOf('@namespace') === 0) { + match = token[1].split(' ')[1]; + atRules[match] = token; + } +} + +function markNamespacesAsUsed(atRules) { + var namespaceRegex = new RegExp(Object.keys(atRules).join('\\\||') + '\\\|', 'g'); + + return function (token) { + var match; + var scope; + var normalizedMatch; + var i, l; + var j, m; + + for (i = 0, l = token[1].length; i < l; i++) { + scope = token[1][i]; + match = scope[1].match(namespaceRegex); + + for (j = 0, m = match.length; j < m; j++) { + normalizedMatch = match[j].substring(0, match[j].length - 1); + + if (normalizedMatch in atRules) { + delete atRules[normalizedMatch]; + } + } + } + }; +} + +module.exports = removeUnusedAtRules; diff --git a/node_modules/clean-css/lib/optimizer/level-2/restore.js b/node_modules/clean-css/lib/optimizer/level-2/restore.js index 149688c5b..13f12e496 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/restore.js +++ b/node_modules/clean-css/lib/optimizer/level-2/restore.js @@ -135,6 +135,59 @@ function borderRadius(property, compactable) { } } +function font(property, compactable) { + var components = property.components; + var restored = []; + var component; + var componentIndex = 0; + var fontFamilyIndex = 0; + + if (property.value[0][1].indexOf(Marker.INTERNAL) === 0) { + property.value[0][1] = property.value[0][1].substring(Marker.INTERNAL.length); + return property.value; + } + + // first four components are optional + while (componentIndex < 4) { + component = components[componentIndex]; + + if (component.value[0][1] != compactable[component.name].defaultValue) { + Array.prototype.push.apply(restored, component.value); + } + + componentIndex++; + } + + // then comes font-size + Array.prototype.push.apply(restored, components[componentIndex].value); + componentIndex++; + + // then may come line-height + if (components[componentIndex].value[0][1] != compactable[components[componentIndex].name].defaultValue) { + Array.prototype.push.apply(restored, [[Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]]); + Array.prototype.push.apply(restored, components[componentIndex].value); + } + + componentIndex++; + + // then comes font-family + while (components[componentIndex].value[fontFamilyIndex]) { + restored.push(components[componentIndex].value[fontFamilyIndex]); + + if (components[componentIndex].value[fontFamilyIndex + 1]) { + restored.push([Token.PROPERTY_VALUE, Marker.COMMA]); + } + + fontFamilyIndex++; + } + + if (isInheritOnly(restored)) { + return [restored[0]]; + } + + return restored; +} + function fourValues(property) { var components = property.components; var value1 = components[0].value[0]; @@ -227,6 +280,7 @@ function withoutDefaults(property, compactable) { module.exports = { background: background, borderRadius: borderRadius, + font: font, fourValues: fourValues, multiplex: multiplex, withoutDefaults: withoutDefaults diff --git a/node_modules/clean-css/lib/optimizer/level-2/restructure.js b/node_modules/clean-css/lib/optimizer/level-2/restructure.js index 2635415ae..90b8bfa65 100644 --- a/node_modules/clean-css/lib/optimizer/level-2/restructure.js +++ b/node_modules/clean-css/lib/optimizer/level-2/restructure.js @@ -25,7 +25,8 @@ function restructure(tokens, context) { var options = context.options; var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses; var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements; - var mergeLimit = 8191; + var mergeLimit = options.compatibility.selectors.mergeLimit; + var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging; var specificityCache = context.cache.specificity; var movableTokens = {}; var movedProperties = []; @@ -86,7 +87,7 @@ function restructure(tokens, context) { var mergeableTokens = []; for (var i = sourceTokens.length - 1; i >= 0; i--) { - if (!isMergeable(serializeRules(sourceTokens[i][1]), mergeablePseudoClasses, mergeablePseudoElements)) { + if (!isMergeable(serializeRules(sourceTokens[i][1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging)) { continue; } |