From: Jakub Pawlowicz Date: Sat, 11 Apr 2015 09:14:33 +0000 (+0100) Subject: Restores compatibility in validator. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=daf74ca01b6373415e6aa2775da777621ef49a85;p=clean-css.git Restores compatibility in validator. Fixes validator with proper OO as we need to handle state there to keep a list of compatible units. --- diff --git a/lib/clean.js b/lib/clean.js index 2fa5563d..a6bf97db 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -21,6 +21,7 @@ var Compatibility = require('./utils/compatibility'); var InputSourceMapTracker = require('./utils/input-source-map-tracker'); var SourceTracker = require('./utils/source-tracker'); var SourceReader = require('./utils/source-reader'); +var Validator = require('./properties/validator'); var fs = require('fs'); var path = require('path'); @@ -66,7 +67,8 @@ CleanCSS.prototype.minify = function(data, callback) { options: this.options, debug: this.options.debug, localOnly: !callback, - sourceTracker: new SourceTracker() + sourceTracker: new SourceTracker(), + validator: new Validator(this.options.compatibility) }; if (context.options.sourceMap) diff --git a/lib/properties/break-up.js b/lib/properties/break-up.js index e585d9a2..49d77d36 100644 --- a/lib/properties/break-up.js +++ b/lib/properties/break-up.js @@ -1,14 +1,17 @@ var wrapSingle = require('./wrap-for-optimizing').single; -var validator = require('./validator'); var Splitter = require('../utils/splitter'); -function _colorFilter(value) { - return value[0] == 'invert' || validator.isValidColor(value[0]); +function _colorFilter(validator) { + return function (value) { + return value[0] == 'invert' || validator.isValidColor(value[0]); + }; } -function _styleFilter(value) { - return value[0] != 'inherit' && validator.isValidStyle(value[0]); +function _styleFilter(validator) { + return function (value) { + return value[0] != 'inherit' && validator.isValidStyle(value[0]); + }; } function _wrapDefault(name, property, compactable) { @@ -21,11 +24,13 @@ function _wrapDefault(name, property, compactable) { return wrapSingle([[name, property.important], [descriptor.defaultValue]]); } -function _widthFilter(value) { - return value[0] != 'inherit' && validator.isValidWidth(value[0]); +function _widthFilter(validator) { + return function (value) { + return value[0] != 'inherit' && validator.isValidWidth(value[0]); + }; } -function background(property, compactable) { +function background(property, compactable, validator) { var image = _wrapDefault('background-image', property, compactable); var position = _wrapDefault('background-position', property, compactable); var size = _wrapDefault('background-size', property, compactable); @@ -168,7 +173,7 @@ function fourValues(property, compactable) { } function multipleValues(splitWith) { - return function (property, compactable) { + return function (property, compactable, validator) { var splitsAt = []; var values = property.value; var i, j, l, m; @@ -180,7 +185,7 @@ function multipleValues(splitWith) { } if (splitsAt.length === 0) - return splitWith(property, compactable); + return splitWith(property, compactable, validator); var splitComponents = []; @@ -192,7 +197,7 @@ function multipleValues(splitWith) { var _property = _wrapDefault(property.name, property, compactable); _property.value = values.slice(from, to); - splitComponents.push(splitWith(_property, compactable)); + splitComponents.push(splitWith(_property, compactable, validator)); } var components = splitComponents[0]; @@ -211,7 +216,7 @@ function multipleValues(splitWith) { }; } -function listStyle(property, compactable) { +function listStyle(property, compactable, validator) { var type = _wrapDefault('list-style-type', property, compactable); var position = _wrapDefault('list-style-position', property, compactable); var image = _wrapDefault('list-style-image', property, compactable); @@ -235,7 +240,7 @@ function listStyle(property, compactable) { return components; } -function widthStyleColor(property, compactable) { +function widthStyleColor(property, compactable, validator) { var descriptor = compactable[property.name]; var components = [ _wrapDefault(descriptor.components[0], property, compactable), @@ -268,7 +273,7 @@ function widthStyleColor(property, compactable) { // so we'll try to parse it caring as little about order as possible if (values.length > 0) { - matches = values.filter(_widthFilter); + matches = values.filter(_widthFilter(validator)); match = matches.length > 1 && matches[0] == 'none' ? matches[1] : matches[0]; if (match) { width.value = [match]; @@ -277,7 +282,7 @@ function widthStyleColor(property, compactable) { } if (values.length > 0) { - match = values.filter(_styleFilter)[0]; + match = values.filter(_styleFilter(validator))[0]; if (match) { style.value = [match]; values.splice(values.indexOf(match), 1); @@ -285,7 +290,7 @@ function widthStyleColor(property, compactable) { } if (values.length > 0) { - match = values.filter(_colorFilter)[0]; + match = values.filter(_colorFilter(validator))[0]; if (match) { color.value = [match]; values.splice(values.indexOf(match), 1); diff --git a/lib/properties/can-override.js b/lib/properties/can-override.js index ffccfd2e..eda02741 100644 --- a/lib/properties/can-override.js +++ b/lib/properties/can-override.js @@ -1,5 +1,3 @@ -var validator = require('./validator'); - // 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. @@ -16,7 +14,7 @@ function always() { return true; } -function backgroundImage(property1, property2) { +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) @@ -30,15 +28,15 @@ function backgroundImage(property1, property2) { return false; // Functions with the same name can override each other; same values can override each other - return sameFunctionOrValue(property1, property2); + return sameFunctionOrValue(property1, property2, validator); } -function border(property1, property2) { - return color(property1.components[2], property2.components[2]); +function border(property1, property2, validator) { + return color(property1.components[2], property2.components[2], validator); } // Use for color properties (color, background-color, border-color, etc.) -function color(property1, property2) { +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 @@ -62,7 +60,7 @@ function color(property1, property2) { return sameFunctionOrValue(property1, property2); } -function twoOptionalFunctions(property1, property2) { +function twoOptionalFunctions(property1, property2, validator) { var value1 = _valueOf(property1); var value2 = _valueOf(property2); @@ -76,7 +74,7 @@ function sameValue(property1, property2) { return value1 === value2; } -function sameFunctionOrValue(property1, property2) { +function sameFunctionOrValue(property1, property2, validator) { var value1 = _valueOf(property1); var value2 = _valueOf(property2); @@ -88,7 +86,7 @@ function sameFunctionOrValue(property1, property2) { } // Use for properties containing CSS units (margin-top, padding-left, etc.) -function unit(property1, property2) { +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, @@ -111,7 +109,7 @@ function unit(property1, property2) { } // Functions with the same name can override each other; same values can override each other - return sameFunctionOrValue(property1, property2); + return sameFunctionOrValue(property1, property2, validator); } module.exports = { diff --git a/lib/properties/optimizer.js b/lib/properties/optimizer.js index ed3d33c2..e55c5684 100644 --- a/lib/properties/optimizer.js +++ b/lib/properties/optimizer.js @@ -82,7 +82,7 @@ var shorthands = { '-webkit-transition-timing-function': ['-webkit-transition'] }; -function _optimize(properties, mergeAdjacent, aggressiveMerging) { +function _optimize(properties, mergeAdjacent, aggressiveMerging, validator) { var overrideMapping = {}; var lastName = null; var j; @@ -143,7 +143,7 @@ function _optimize(properties, mergeAdjacent, aggressiveMerging) { if (!wasImportant && (wasHack && !isHack || !wasHack && isHack)) continue; - if (!wasHack && !isHack && !longhandToShorthand && canOverride && !canOverride(toRemove, property)) + if (!wasHack && !isHack && !longhandToShorthand && canOverride && !canOverride(toRemove, property, validator)) continue; if (wasImportant && !isImportant || wasImportant && isHack) { @@ -180,13 +180,13 @@ function _optimize(properties, mergeAdjacent, aggressiveMerging) { } } -function optimize(selector, properties, mergeAdjacent, withCompacting, options) { +function optimize(selector, properties, mergeAdjacent, withCompacting, options, validator) { var _properties = wrapForOptimizing(properties); - populateComponents(_properties); - _optimize(_properties, mergeAdjacent, options.aggressiveMerging); + populateComponents(_properties, validator); + _optimize(_properties, mergeAdjacent, options.aggressiveMerging, validator); if (withCompacting && options.shorthandCompacting && !options.sourceMap) { - compactOverrides(_properties, options.compatibility); + compactOverrides(_properties, options.compatibility, validator); // compactShorthands(_properties, false, options.compatibility); // compactShorthands(_properties, true, options.compatibility); } diff --git a/lib/properties/override-compactor.js b/lib/properties/override-compactor.js index 059a4c83..b15aee77 100644 --- a/lib/properties/override-compactor.js +++ b/lib/properties/override-compactor.js @@ -15,7 +15,7 @@ function nameMatchFilter(to) { }; } -function wouldBreakCompatibility(property) { +function wouldBreakCompatibility(property, validator) { for (var i = 0; i < property.components.length; i++) { var component = property.components[i]; var descriptor = compactable[component.name]; @@ -24,7 +24,7 @@ function wouldBreakCompatibility(property) { var _component = shallowClone(component); _component.value = [[descriptor.defaultValue]]; - if (!canOverride(_component, component)) + if (!canOverride(_component, component, validator)) return true; } @@ -157,7 +157,7 @@ function wouldResultInLongerValue(left, right) { return lengthBefore < lengthAfter; } -function compactOverrides(properties, compatibility) { +function compactOverrides(properties, compatibility, validator) { var mayOverride, right, left, component; var i, j, k; @@ -182,7 +182,7 @@ function compactOverrides(properties, compatibility) { component = right.components.filter(nameMatchFilter(left))[0]; mayOverride = (compactable[left.name] && compactable[left.name].canOverride) || canOverride.sameValue; - if (mayOverride(left, component)) { + if (mayOverride(left, component, validator)) { left.unused = true; } } else if (left.shorthand && !right.shorthand && isComponentOf(left, right)) { @@ -191,14 +191,14 @@ function compactOverrides(properties, compatibility) { continue; component = left.components.filter(nameMatchFilter(right))[0]; - if (mayOverride(component, right)) { + if (mayOverride(component, right, validator)) { var disabledBackgroundSizeMerging = !compatibility.properties.backgroundSizeMerging && component.name.indexOf('background-size') > -1; var nonMergeableValue = compactable[right.name].nonMergeableValue === right.value[0][0]; if (disabledBackgroundSizeMerging || nonMergeableValue) continue; - if (!compatibility.properties.merging && wouldBreakCompatibility(left)) + if (!compatibility.properties.merging && wouldBreakCompatibility(left, validator)) continue; if (component.value[0][0] != right.value[0][0] && (hasInherits(left) || hasInherits(right))) @@ -231,7 +231,7 @@ function compactOverrides(properties, compatibility) { var rightComponent = right.components[k]; mayOverride = compactable[leftComponent.name].canOverride || canOverride.sameValue; - if (!mayOverride(leftComponent, rightComponent) || !canOverride.twoOptionalFunctions(leftComponent, rightComponent)) + if (!mayOverride(leftComponent, rightComponent, validator) || !canOverride.twoOptionalFunctions(leftComponent, rightComponent, validator)) continue propertyLoop; } diff --git a/lib/properties/populate-components.js b/lib/properties/populate-components.js index 8e4d2031..9544d5ac 100644 --- a/lib/properties/populate-components.js +++ b/lib/properties/populate-components.js @@ -1,6 +1,6 @@ var compactable = require('./compactable'); -function populateComponents(properties) { +function populateComponents(properties, validator) { for (var i = properties.length - 1; i >= 0; i--) { var property = properties[i]; var descriptor = compactable[property.name]; @@ -8,7 +8,7 @@ function populateComponents(properties) { if (descriptor && descriptor.shorthand) { property.shorthand = true; property.dirty = true; - property.components = descriptor.breakUp(property, compactable); + property.components = descriptor.breakUp(property, compactable, validator); if (property.components.length > 0) property.multiplex = Array.isArray(property.components[0].value[0][0]); diff --git a/lib/properties/validator.js b/lib/properties/validator.js index b06b6987..b9958084 100644 --- a/lib/properties/validator.js +++ b/lib/properties/validator.js @@ -30,86 +30,103 @@ var styleKeywords = ['auto', 'inherit', 'hidden', 'none', 'dotted', 'dashed', 's 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 compatibleCssUnitRegex; -// var compatibleCssUnitAnyRegex; - -// var validator = { -// // FIXME: we need a proper OO here -// setCompatibility: function (compatibility) { -// if (compatibility.units.rem) { -// compatibleCssUnitRegex = cssUnitRegex; -// compatibleCssUnitAnyRegex = cssUnitAnyRegex; -// return; -// } - -// var validUnits = allUnits.slice(0).filter(function (value) { -// return value != 'rem'; -// }); - -// var compatibleCssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + ')|auto|inherit)'; -// compatibleCssUnitRegex = new RegExp('^' + compatibleCssUnitRegexStr + '$', 'i'); -// compatibleCssUnitAnyRegex = new RegExp('^(none|' + widthKeywords.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i'); -// } - -function isValidHexColor(s) { - return (s.length === 4 || s.length === 7) && s[0] === '#'; +function Validator(compatibility) { + if (compatibility.units.rem) { + this.compatibleCssUnitRegex = cssUnitRegex; + this.compatibleCssUnitAnyRegex = cssUnitAnyRegex; + } else { + var validUnits = allUnits.slice(0).filter(function (value) { + return value != 'rem'; + }); + + var compatibleCssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + ')|auto|inherit)'; + this.compatibleCssUnitRegex = new RegExp('^' + compatibleCssUnitRegexStr + '$', 'i'); + this.compatibleCssUnitAnyRegex = new RegExp('^(none|' + widthKeywords.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i'); + } } -function isValidRgbaColor(s) { + +Validator.prototype.isValidHexColor = function (s) { + return (s.length === 4 || s.length === 7) && s[0] === '#'; +}; + +Validator.prototype.isValidRgbaColor = function (s) { s = s.split(' ').join(''); return s.length > 0 && s.indexOf('rgba(') === 0 && s.indexOf(')') === s.length - 1; -} -function isValidHslaColor(s) { +}; + +Validator.prototype.isValidHslaColor = function (s) { s = s.split(' ').join(''); return s.length > 0 && s.indexOf('hsla(') === 0 && s.indexOf(')') === s.length - 1; -} -function isValidNamedColor(s) { +}; + +Validator.prototype.isValidNamedColor = function (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 isValidVariable(s) { +}; + +Validator.prototype.isValidVariable = function (s) { return cssVariableRegex.test(s); -} -function isValidColor(s) { - return isValidNamedColor(s) || isValidHexColor(s) || isValidRgbaColor(s) || isValidHslaColor(s) || isValidVariable(s) || isValidVendorPrefixedValue(s); -} -function isValidUrl(s) { +}; + +Validator.prototype.isValidColor = function (s) { + return this.isValidNamedColor(s) || + this.isValidHexColor(s) || + this.isValidRgbaColor(s) || + this.isValidHslaColor(s) || + this.isValidVariable(s) || + this.isValidVendorPrefixedValue(s); +}; + +Validator.prototype.isValidUrl = function (s) { // NOTE: at this point all URLs are replaced with placeholders by clean-css, so we check for those placeholders return s.indexOf('__ESCAPED_URL_CLEAN_CSS') === 0; -} -function isValidUnit(s) { - return cssUnitAnyRegex.test(s); -} -function isValidUnitWithoutFunction(s) { - return cssUnitRegex.test(s); -} -function isValidAndCompatibleUnit(s) { +}; + +Validator.prototype.isValidUnit = function (s) { return cssUnitAnyRegex.test(s); -} -function isValidAndCompatibleUnitWithoutFunction(s) { +}; + +Validator.prototype.isValidUnitWithoutFunction = function (s) { return cssUnitRegex.test(s); -} -function isValidFunctionWithoutVendorPrefix(s) { +}; + +Validator.prototype.isValidAndCompatibleUnit = function (s) { + return this.compatibleCssUnitAnyRegex.test(s); +}; + +Validator.prototype.isValidAndCompatibleUnitWithoutFunction = function (s) { + return this.compatibleCssUnitRegex.test(s); +}; + +Validator.prototype.isValidFunctionWithoutVendorPrefix = function (s) { return cssFunctionNoVendorRegex.test(s); -} -function isValidFunctionWithVendorPrefix(s) { +}; + +Validator.prototype.isValidFunctionWithVendorPrefix = function (s) { return cssFunctionVendorRegex.test(s); -} -function isValidFunction(s) { +}; + +Validator.prototype.isValidFunction = function (s) { return cssFunctionAnyRegex.test(s); -} -function isValidBackgroundRepeat(s) { - return backgroundRepeatKeywords.indexOf(s) >= 0 || isValidVariable(s); -} -function isValidBackgroundAttachment(s) { - return backgroundAttachmentKeywords.indexOf(s) >= 0 || isValidVariable(s); -} -function isValidBackgroundBox(s) { - return backgroundBoxKeywords.indexOf(s) >= 0 || isValidVariable(s); -} -function isValidBackgroundPositionPart(s) { - return backgroundPositionKeywords.indexOf(s) >= 0 || cssUnitOrCalcRegex.test(s) || isValidVariable(s); -} -function isValidBackgroundPosition(s) { +}; + +Validator.prototype.isValidBackgroundRepeat = function (s) { + return backgroundRepeatKeywords.indexOf(s) >= 0 || this.isValidVariable(s); +}; + +Validator.prototype.isValidBackgroundAttachment = function (s) { + return backgroundAttachmentKeywords.indexOf(s) >= 0 || this.isValidVariable(s); +}; + +Validator.prototype.isValidBackgroundBox = function (s) { + return backgroundBoxKeywords.indexOf(s) >= 0 || this.isValidVariable(s); +}; + +Validator.prototype.isValidBackgroundPositionPart = function (s) { + return backgroundPositionKeywords.indexOf(s) >= 0 || cssUnitOrCalcRegex.test(s) || this.isValidVariable(s); +}; + +Validator.prototype.isValidBackgroundPosition = function (s) { if (s === 'inherit') return true; @@ -117,75 +134,55 @@ function isValidBackgroundPosition(s) { for (var i = 0, l = parts.length; i < l; i++) { if (parts[i] === '') continue; - if (isValidBackgroundPositionPart(parts[i]) || isValidVariable(parts[i])) + if (this.isValidBackgroundPositionPart(parts[i]) || this.isValidVariable(parts[i])) continue; return false; } return true; -} -function isValidBackgroundSizePart(s) { - return backgroundSizeKeywords.indexOf(s) >= 0 || cssUnitRegex.test(s) || isValidVariable(s); -} -function isValidBackgroundPositionAndSize(s) { +}; + +Validator.prototype.isValidBackgroundSizePart = function (s) { + return backgroundSizeKeywords.indexOf(s) >= 0 || cssUnitRegex.test(s) || this.isValidVariable(s); +}; + +Validator.prototype.isValidBackgroundPositionAndSize = function (s) { if (s.indexOf('/') < 0) return false; var twoParts = new Splitter('/').split(s); - return isValidBackgroundSizePart(twoParts.pop()) && isValidBackgroundPositionPart(twoParts.pop()); -} -function isValidListStyleType(s) { - return listStyleTypeKeywords.indexOf(s) >= 0 || isValidVariable(s); -} -function isValidListStylePosition(s) { - return listStylePositionKeywords.indexOf(s) >= 0 || isValidVariable(s); -} -function isValidStyle(s) { - return styleKeywords.indexOf(s) >= 0 || isValidVariable(s); -} -function isValidWidth(s) { - return isValidUnit(s) || widthKeywords.indexOf(s) >= 0 || isValidVariable(s); -} -function isValidVendorPrefixedValue(s) { + return this.isValidBackgroundSizePart(twoParts.pop()) && this.isValidBackgroundPositionPart(twoParts.pop()); +}; + +Validator.prototype.isValidListStyleType = function (s) { + return listStyleTypeKeywords.indexOf(s) >= 0 || this.isValidVariable(s); +}; + +Validator.prototype.isValidListStylePosition = function (s) { + return listStylePositionKeywords.indexOf(s) >= 0 || this.isValidVariable(s); +}; + +Validator.prototype.isValidStyle = function (s) { + return styleKeywords.indexOf(s) >= 0 || this.isValidVariable(s); +}; + +Validator.prototype.isValidWidth = function (s) { + return this.isValidUnit(s) || widthKeywords.indexOf(s) >= 0 || this.isValidVariable(s); +}; + +Validator.prototype.isValidVendorPrefixedValue = function (s) { return /^-([A-Za-z0-9]|-)*$/gi.test(s); -} -function areSameFunction(a, b) { - if (!isValidFunction(a) || !isValidFunction(b)) +}; + +Validator.prototype.areSameFunction = function (a, b) { + if (!this.isValidFunction(a) || !this.isValidFunction(b)) return false; var f1name = a.substring(0, a.indexOf('(')); var f2name = b.substring(0, b.indexOf('(')); return f1name === f2name; -} - -module.exports = { - isValidHexColor: isValidHexColor, - isValidRgbaColor: isValidRgbaColor, - isValidHslaColor: isValidHslaColor, - isValidNamedColor: isValidNamedColor, - isValidVariable: isValidVariable, - isValidColor: isValidColor, - isValidUrl: isValidUrl, - isValidUnit: isValidUnit, - isValidUnitWithoutFunction: isValidUnitWithoutFunction, - isValidAndCompatibleUnit: isValidAndCompatibleUnit, - isValidAndCompatibleUnitWithoutFunction: isValidAndCompatibleUnitWithoutFunction, - isValidFunctionWithoutVendorPrefix: isValidFunctionWithoutVendorPrefix, - isValidFunctionWithVendorPrefix: isValidFunctionWithVendorPrefix, - isValidFunction: isValidFunction, - isValidBackgroundRepeat: isValidBackgroundRepeat, - isValidBackgroundAttachment: isValidBackgroundAttachment, - isValidBackgroundBox: isValidBackgroundBox, - isValidBackgroundPositionPart: isValidBackgroundPositionPart, - isValidBackgroundPosition: isValidBackgroundPosition, - isValidBackgroundSizePart: isValidBackgroundSizePart, - isValidBackgroundPositionAndSize: isValidBackgroundPositionAndSize, - isValidListStyleType: isValidListStyleType, - isValidListStylePosition: isValidListStylePosition, - isValidStyle: isValidStyle, - isValidWidth: isValidWidth, - isValidVendorPrefixedValue: isValidVendorPrefixedValue, - areSameFunction: areSameFunction }; + +module.exports = Validator; diff --git a/lib/selectors/optimizers/advanced.js b/lib/selectors/optimizers/advanced.js index 923b6e54..1df89465 100644 --- a/lib/selectors/optimizers/advanced.js +++ b/lib/selectors/optimizers/advanced.js @@ -7,8 +7,9 @@ var canReorderSingle = require('../reorderable').canReorderSingle; var stringifyBody = require('../../stringifier/one-time').body; var stringifySelectors = require('../../stringifier/one-time').selectors; -function AdvancedOptimizer(options) { +function AdvancedOptimizer(options, context) { this.options = options; + this.validator = context.validator; } function unsafeSelector(value) { @@ -75,7 +76,7 @@ AdvancedOptimizer.prototype.mergeAdjacent = function (tokens) { if (lastToken[0] == 'selector' && stringifySelectors(token[1]) == stringifySelectors(lastToken[1])) { var joinAt = [lastToken[2].length]; Array.prototype.push.apply(lastToken[2], token[2]); - optimizeProperties(token[1], lastToken[2], joinAt, true, this.options); + optimizeProperties(token[1], lastToken[2], joinAt, true, this.options, this.validator); token[2] = []; } else if (lastToken[0] == 'selector' && stringifyBody(token[2]) == stringifyBody(lastToken[2]) && !this.isSpecial(stringifySelectors(token[1])) && !this.isSpecial(stringifySelectors(lastToken[1]))) { @@ -221,7 +222,7 @@ AdvancedOptimizer.prototype.reduceSelector = function (tokens, selector, data, o joinsAt.push((joinsAt[j - 1] || 0) + bodiesAsList[j].length); } - optimizeProperties(selector, bodies, joinsAt, false, this.options); + optimizeProperties(selector, bodies, joinsAt, false, this.options, this.validator); var processedCount = processedTokens.length; var propertyIdx = bodies.length - 1; @@ -301,7 +302,7 @@ AdvancedOptimizer.prototype.mergeNonAdjacentBySelector = function (tokens) { Array.prototype.push.apply(target[2], moved[2]); } - optimizeProperties(target[1], target[2], joinAt, true, this.options); + optimizeProperties(target[1], target[2], joinAt, true, this.options, this.validator); moved[2] = []; } } @@ -683,16 +684,16 @@ AdvancedOptimizer.prototype.removeEmpty = function (tokens) { } }; -function recursivelyOptimizeProperties(tokens, options) { +function recursivelyOptimizeProperties(tokens, options, validator) { for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; switch (token[0]) { case 'selector': - optimizeProperties(token[1], token[2], false, true, options); + optimizeProperties(token[1], token[2], false, true, options, validator); break; case 'block': - recursivelyOptimizeProperties(token[2], options); + recursivelyOptimizeProperties(token[2], options, validator); } } } @@ -708,7 +709,7 @@ AdvancedOptimizer.prototype.optimize = function (tokens) { } }); - recursivelyOptimizeProperties(tokens, self.options); + recursivelyOptimizeProperties(tokens, self.options, self.validator); self.removeDuplicates(tokens); self.mergeAdjacent(tokens); diff --git a/test/integration-test.js b/test/integration-test.js index a0077a13..0bd16b3f 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -1859,7 +1859,7 @@ title']{display:block}", ] }, { compatibility: { selectors: { adjacentSpace: true } } }), 'units - IE8 compatibility': cssContext({ - 'rems': 'div{padding-top:16px;padding-top:1rem}' + 'rems': 'div{padding-top:16px;color:red;padding-top:1rem}' }, { compatibility: 'ie8' }), 'redefined more granular properties with property merging': cssContext({ 'should merge background with background-attachment': [ diff --git a/test/properties/break-up-test.js b/test/properties/break-up-test.js index dd39ada1..e3f1cfde 100644 --- a/test/properties/break-up-test.js +++ b/test/properties/break-up-test.js @@ -3,12 +3,15 @@ var assert = require('assert'); var wrapForOptimizing = require('../../lib/properties/wrap-for-optimizing').all; var populateComponents = require('../../lib/properties/populate-components'); +var Validator = require('../../lib/properties/validator'); +var Compatibility = require('../../lib/utils/compatibility'); var breakUp = require('../../lib/properties/break-up'); function _breakUp(properties) { + var validator = new Validator(new Compatibility().toOptions()); var wrapped = wrapForOptimizing(properties); - populateComponents(wrapped); + populateComponents(wrapped, validator); return wrapped[0].components; } diff --git a/test/properties/longhand-overriding-test.js b/test/properties/longhand-overriding-test.js index e4990a86..001311eb 100644 --- a/test/properties/longhand-overriding-test.js +++ b/test/properties/longhand-overriding-test.js @@ -6,6 +6,7 @@ var optimize = require('../../lib/properties/optimizer'); var Tokenizer = require('../../lib/selectors/tokenizer'); var SourceTracker = require('../../lib/utils/source-tracker'); var Compatibility = require('../../lib/utils/compatibility'); +var Validator = require('../../lib/properties/validator'); var addOptimizationMetadata = require('../../lib/selectors/optimization-metadata'); function _optimize(source) { @@ -18,7 +19,8 @@ function _optimize(source) { addOptimizationMetadata(tokens); var compatibility = new Compatibility().toOptions(); - optimize(tokens[0][1], tokens[0][2], false, true, { compatibility: compatibility, aggressiveMerging: true, shorthandCompacting: true }); + var validator = new Validator(compatibility); + optimize(tokens[0][1], tokens[0][2], false, true, { compatibility: compatibility, aggressiveMerging: true, shorthandCompacting: true }, validator); return tokens[0][2]; } diff --git a/test/properties/optimizer-test.js b/test/properties/optimizer-test.js index ca3b8acc..4fca81ea 100644 --- a/test/properties/optimizer-test.js +++ b/test/properties/optimizer-test.js @@ -6,9 +6,11 @@ var optimize = require('../../lib/properties/optimizer'); var Tokenizer = require('../../lib/selectors/tokenizer'); var SourceTracker = require('../../lib/utils/source-tracker'); var Compatibility = require('../../lib/utils/compatibility'); +var Validator = require('../../lib/properties/validator'); var addOptimizationMetadata = require('../../lib/selectors/optimization-metadata'); var compatibility = new Compatibility().toOptions(); +var validator = new Validator(compatibility); function _optimize(source, mergeAdjacent, aggressiveMerging) { var tokens = new Tokenizer({ @@ -18,7 +20,7 @@ function _optimize(source, mergeAdjacent, aggressiveMerging) { }).toTokens(source); addOptimizationMetadata(tokens); - optimize(tokens[0][1], tokens[0][2], mergeAdjacent, true, { compatibility: compatibility, aggressiveMerging: aggressiveMerging }); + optimize(tokens[0][1], tokens[0][2], mergeAdjacent, true, { compatibility: compatibility, aggressiveMerging: aggressiveMerging }, validator); return tokens[0][2]; } diff --git a/test/properties/override-compacting-test.js b/test/properties/override-compacting-test.js index 616a017d..d935225f 100644 --- a/test/properties/override-compacting-test.js +++ b/test/properties/override-compacting-test.js @@ -6,6 +6,7 @@ var optimize = require('../../lib/properties/optimizer'); var Tokenizer = require('../../lib/selectors/tokenizer'); var SourceTracker = require('../../lib/utils/source-tracker'); var Compatibility = require('../../lib/utils/compatibility'); +var Validator = require('../../lib/properties/validator'); var addOptimizationMetadata = require('../../lib/selectors/optimization-metadata'); function _optimize(source, compatibility, aggressiveMerging) { @@ -16,13 +17,14 @@ function _optimize(source, compatibility, aggressiveMerging) { }).toTokens(source); compatibility = new Compatibility(compatibility).toOptions(); + var validator = new Validator(compatibility); var options = { aggressiveMerging: undefined === aggressiveMerging ? true : aggressiveMerging, compatibility: compatibility, shorthandCompacting: true }; addOptimizationMetadata(tokens); - optimize(tokens[0][1], tokens[0][2], false, true, options); + optimize(tokens[0][1], tokens[0][2], false, true, options, validator); return tokens[0][2]; } @@ -310,7 +312,7 @@ vows.describe(optimize) ]); } }, - 'multiplex longhand into multiplex shorthand123': { + 'multiplex longhand into multiplex shorthand': { 'topic': 'p{background:no-repeat,no-repeat;background-position:top left,bottom left}', 'into': function (topic) { assert.deepEqual(_optimize(topic), [ diff --git a/test/properties/restore-shorthands-test.js b/test/properties/restore-shorthands-test.js index 7a852540..c7ede636 100644 --- a/test/properties/restore-shorthands-test.js +++ b/test/properties/restore-shorthands-test.js @@ -7,13 +7,18 @@ var shallowClone = require('../../lib/properties/clone').shallow; var restoreShorthands = require('../../lib/properties/restore-shorthands'); +var Compatibility = require('../../lib/utils/compatibility'); +var Validator = require('../../lib/properties/validator'); + +var validator = new Validator(new Compatibility().toOptions()); + vows.describe(restoreShorthands) .addBatch({ 'longhands': { 'topic': function () { var properties = ['/*comment */', [['margin-top', false, false], ['0']]]; var _properties = wrapForOptimizing(properties); - populateComponents(_properties); + populateComponents(_properties, validator); restoreShorthands(_properties); return properties; @@ -26,7 +31,7 @@ vows.describe(restoreShorthands) 'topic': function () { var properties = ['/*comment */', [['background', false, false], ['url(image.png)']]]; var _properties = wrapForOptimizing(properties); - populateComponents(_properties); + populateComponents(_properties, validator); properties[1].pop(); _properties[0].dirty = true; @@ -42,7 +47,7 @@ vows.describe(restoreShorthands) 'topic': function () { var properties = [[['background', false, false], ['url(image.png)']]]; var _properties = wrapForOptimizing(properties); - populateComponents(_properties); + populateComponents(_properties, validator); _properties[0].value = []; _properties[0].dirty = true; @@ -58,7 +63,7 @@ vows.describe(restoreShorthands) 'topic': function () { var properties = [[['background', false, false], ['url(image.png)']]]; var _properties = wrapForOptimizing(properties); - populateComponents(_properties); + populateComponents(_properties, validator); var cloned = shallowClone(_properties[0]); cloned.components = _properties[0].components; diff --git a/test/properties/restore-test.js b/test/properties/restore-test.js index 2d3f9826..9d1202fd 100644 --- a/test/properties/restore-test.js +++ b/test/properties/restore-test.js @@ -3,13 +3,16 @@ var assert = require('assert'); var wrapForOptimizing = require('../../lib/properties/wrap-for-optimizing').single; var compactable = require('../../lib/properties/compactable'); +var Compatibility = require('../../lib/utils/compatibility'); +var Validator = require('../../lib/properties/validator'); var restore = require('../../lib/properties/restore'); function _breakUp(property) { + var validator = new Validator(new Compatibility().toOptions()); var descriptor = compactable[property[0][0]]; var _property = wrapForOptimizing(property); - _property.components = descriptor.breakUp(_property, compactable); + _property.components = descriptor.breakUp(_property, compactable, validator); _property.multiplex = Array.isArray(_property.components[0].value[0][0]); return _property; } diff --git a/test/selectors/optimizer-test.js b/test/selectors/optimizer-test.js index 332f0199..a8ca567c 100644 --- a/test/selectors/optimizer-test.js +++ b/test/selectors/optimizer-test.js @@ -3,6 +3,7 @@ var assert = require('assert'); var SelectorsOptimizer = require('../../lib/selectors/optimizer'); var stringify = require('../../lib/stringifier/simple'); var Compatibility = require('../../lib/utils/compatibility'); +var Validator = require('../../lib/properties/validator'); var SourceTracker = require('../../lib/utils/source-tracker'); function optimizerContext(group, specs, options) { @@ -17,7 +18,8 @@ function optimizerContext(group, specs, options) { options.compatibility = new Compatibility(options.compatibility).toOptions(); var outerContext = { options: {}, - sourceTracker: new SourceTracker() + sourceTracker: new SourceTracker(), + validator: new Validator(options.compatibility) }; function optimized(target) { diff --git a/test/selectors/tokenizer-source-maps-test.js b/test/selectors/tokenizer-source-maps-test.js index 47c2476f..cfabed94 100644 --- a/test/selectors/tokenizer-source-maps-test.js +++ b/test/selectors/tokenizer-source-maps-test.js @@ -396,7 +396,7 @@ vows.describe('source-maps/analyzer') ] ] ], - 'in properties123': [ + 'in properties': [ 'div{__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0(2,5)__background:__ESCAPED_URL_CLEAN_CSS0(0,20)__;color:blue}a{font-family:__ESCAPED_FREE_TEXT_CLEAN_CSS0(1,3)__;color:red}', [ [