From 5d0ca77d775ab3263122f54e6decd65341348fc1 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Sun, 26 Mar 2017 14:51:14 +0200 Subject: [PATCH] Reworks validator module. Why: * Technically speaking validator can check if a value is valid only in specific circumstances, like when a value is from a keyword list; * methods are no longer called `isValid<...>` but `is<...>` which doesn't say if particular value is valid or not. --- lib/optimizer/level-1/optimize.js | 2 +- lib/optimizer/level-2/break-up.js | 39 ++- lib/optimizer/level-2/can-override.js | 81 +++-- .../level-2/properties/override-properties.js | 7 +- .../level-2/properties/understandable.js | 2 +- lib/optimizer/validator.js | 322 ++++++------------ lib/reader/rebase.js | 2 +- 7 files changed, 186 insertions(+), 269 deletions(-) diff --git a/lib/optimizer/level-1/optimize.js b/lib/optimizer/level-1/optimize.js index 3879b3df..5a6da47c 100644 --- a/lib/optimizer/level-1/optimize.js +++ b/lib/optimizer/level-1/optimize.js @@ -422,7 +422,7 @@ function optimizeBody(properties, context) { break; } - if (valueIsUrl && !context.validator.isValidUrl(value)) { + if (valueIsUrl && !context.validator.isUrl(value)) { property.unused = true; context.warnings.push('Broken URL \'' + value + '\' at ' + formatPosition(property.value[j][2][0]) + '. Ignoring.'); break; diff --git a/lib/optimizer/level-2/break-up.js b/lib/optimizer/level-2/break-up.js index 7bdfdc4b..e3e495da 100644 --- a/lib/optimizer/level-2/break-up.js +++ b/lib/optimizer/level-2/break-up.js @@ -21,13 +21,13 @@ function _anyIsInherit(values) { 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]); }; } @@ -57,7 +57,10 @@ 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]); }; } @@ -93,10 +96,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; @@ -105,7 +108,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 { @@ -113,7 +116,7 @@ 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]; @@ -137,10 +140,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; } @@ -229,10 +232,10 @@ function font(property, compactable, validator) { // fuzzy match style, variant, weight, and stretch on first elements while (index < fuzzyMatched) { - isStretchValid = validator.isValidKeywordValue('font-stretch', values[index][1], true); - isStyleValid = validator.isValidKeywordValue('font-style', values[index][1], true); - isVariantValid = validator.isValidKeywordValue('font-variant', values[index][1], true); - isWeightValid = validator.isValidKeywordValue('font-weight', values[index][1], true); + 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]]; @@ -256,7 +259,7 @@ function font(property, compactable, validator) { } // now comes font-size ... - if (validator.isValidFontSize(values[index][1])) { + if (validator.isFontSizeKeyword(values[index][1]) || validator.isUnit(values[index][1]) && !validator.isDynamicUnit(values[index][1])) { size.value = [values[index]]; isSizeSet = true; index++; @@ -269,7 +272,7 @@ function font(property, compactable, validator) { } // ... and perhaps line-height - if (isSizeSet && values[index] && values[index][1] == Marker.FORWARD_SLASH && values[index + 1] && validator.isValidLineHeight(values[index + 1][1])) { + 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++; @@ -389,7 +392,7 @@ 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; @@ -398,7 +401,7 @@ function listStyle(property, compactable, validator) { // ... then `type`... for (index = 0, total = values.length; index < total; index++) { - if (validator.isValidListStyleType(values[index][1])) { + if (validator.isListStyleTypeKeyword(values[index][1])) { type.value = [values[index]]; values.splice(index, 1); break; @@ -406,7 +409,7 @@ function listStyle(property, compactable, validator) { } // ... and what's left is a `position` - if (values.length > 0 && validator.isValidListStylePosition(values[0][1])) + if (values.length > 0 && validator.isListStylePositionKeyword(values[0][1])) position.value = [values[0]]; return components; diff --git a/lib/optimizer/level-2/can-override.js b/lib/optimizer/level-2/can-override.js index a6a49e67..c960ec5f 100644 --- a/lib/optimizer/level-2/can-override.js +++ b/lib/optimizer/level-2/can-override.js @@ -1,11 +1,22 @@ var understandable = require('./properties/understandable'); +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 +24,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 +36,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; } @@ -51,13 +62,13 @@ function fontFamily(validator, value1, value2) { } 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; } @@ -66,56 +77,58 @@ 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.isValidVariable(value1) && validator.isValidVariable(value2)) { + } else if (validator.isVariable(value1) && validator.isVariable(value2)) { return true; } - return validator.isValidTextShadow(value2); + return validator.isUnit(value2) || validator.isColor(value2) || validator.isGlobal(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; } @@ -131,13 +144,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 = { diff --git a/lib/optimizer/level-2/properties/override-properties.js b/lib/optimizer/level-2/properties/override-properties.js index 3c9d8d2a..c3ed3662 100644 --- a/lib/optimizer/level-2/properties/override-properties.js +++ b/lib/optimizer/level-2/properties/override-properties.js @@ -124,8 +124,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,7 +272,7 @@ 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; component = findComponentIn(right, left); @@ -289,7 +290,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; } diff --git a/lib/optimizer/level-2/properties/understandable.js b/lib/optimizer/level-2/properties/understandable.js index 6c77db50..032169a2 100644 --- a/lib/optimizer/level-2/properties/understandable.js +++ b/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/lib/optimizer/validator.js b/lib/optimizer/validator.js index 04b0b3b0..5fc69d08 100644 --- a/lib/optimizer/validator.js +++ b/lib/optimizer/validator.js @@ -1,44 +1,25 @@ -var Units = [ - '%', - 'ch', - 'cm', - 'em', - 'ex', - 'in', - 'mm', - 'pc', - 'pt', - 'px', - 'rem', - 'vh', - 'vm', - 'vmax', - 'vmin', - 'vw' -]; -var cssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + Units.join('|') + '|)|auto|inherit)'; -var cssCalcRegexStr = '(\\-moz\\-|\\-webkit\\-)?calc\\([^\\)]+\\)'; -var cssFunctionNoVendorRegexStr = '[A-Z]+(\\-|[A-Z]|[0-9])+\\(.*?\\)'; -var cssFunctionVendorRegexStr = '\\-(\\-|[A-Z]|[0-9])+\\(.*?\\)'; -var cssVariableRegexStr = 'var\\(\\-\\-[^\\)]+\\)'; -var cssFunctionAnyRegexStr = '(' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')'; -var cssUnitOrCalcRegexStr = '(' + cssUnitRegexStr + '|' + cssCalcRegexStr + ')'; - -var cssFunctionNoVendorRegex = new RegExp('^' + cssFunctionNoVendorRegexStr + '$', 'i'); -var cssVariableRegex = new RegExp('^' + cssVariableRegexStr + '$', 'i'); -var cssFunctionAnyRegex = new RegExp('^' + cssFunctionAnyRegexStr + '$', 'i'); -var cssUnitRegex = new RegExp('^' + cssUnitRegexStr + '$', 'i'); -var cssUnitOrCalcRegex = new RegExp('^' + cssUnitOrCalcRegexStr + '$', 'i'); - +var functionNoVendorRegexStr = '[A-Z]+(\\-|[A-Z]|[0-9])+\\(.*?\\)'; +var functionVendorRegexStr = '\\-(\\-|[A-Z]|[0-9])+\\(.*?\\)'; +var variableRegexStr = 'var\\(\\-\\-[^\\)]+\\)'; +var functionAnyRegexStr = '(' + variableRegexStr + '|' + functionNoVendorRegexStr + '|' + functionVendorRegexStr + ')'; + +var calcRegex = new RegExp('^(\\-moz\\-|\\-webkit\\-)?calc\\([^\\)]+\\)$', 'i'); +var functionAnyRegex = new RegExp('^' + functionAnyRegexStr + '$', 'i'); +var hslColorRegex = /^hsl\(\s*[\-\.\d]+\s*,\s*[\.\d]+%\s*,\s*[\.\d]+%\s*\)|hsla\(\s*[\-\.\d]+\s*,\s*[\.\d]+%\s*,\s*[\.\d]+%\s*,\s*[\.\d]+\s*\)$/; +var longHexColorRegex = /^#[0-9a-f]{6}$/i; +var namedEntityRegex = /^[a-z]+$/i; +var prefixRegex = /^-([a-z0-9]|-)*$/i; +var rgbColorRegex = /^rgb\(\s*[\d]{1,3}\s*,\s*[\d]{1,3}\s*,\s*[\d]{1,3}\s*\)|rgba\(\s*[\d]{1,3}\s*,\s*[\d]{1,3}\s*,\s*[\d]{1,3}\s*,\s*[\.\d]+\s*\)$/; +var shortHexColorRegex = /^#[0-9a-f]{3}$/i; var urlRegex = /^url\([\s\S]+\)$/i; - -var globalKeywords = [ - 'inherit', - 'initial', - 'unset' -]; +var variableRegex = new RegExp('^' + variableRegexStr + '$', 'i'); var Keywords = { + '^': [ + 'inherit', + 'initial', + 'unset' + ], '*-style': [ 'auto', 'dashed', @@ -106,6 +87,9 @@ var Keywords = { 'none', 'right' ], + 'color': [ + 'transparent' + ], 'cursor': [ 'all-scroll', 'auto', @@ -291,175 +275,97 @@ var Keywords = { ] }; -var VENDOR_PREFIX_PATTERN = /(^|\W)-\w+\-/; - -function areSameFunction(value1, value2) { - if (!isValidFunction(value1) || !isValidFunction(value2)) { - return false; - } - - var function1Name = value1.substring(0, value1.indexOf('(')); - var function2Name = value2.substring(0, value2.indexOf('(')); - - return function1Name === function2Name; -} - -function hasNoVendorPrefix(value) { - return VENDOR_PREFIX_PATTERN.test(value); -} - -function isValidBackgroundAttachment(value) { - return Keywords['background-attachment'].indexOf(value) > -1; -} - -function isValidBackgroundClip(value) { - return Keywords['background-clip'].indexOf(value) > -1; -} - -function isValidBackgroundRepeat(value) { - return Keywords['background-repeat'].indexOf(value) > -1; -} - -function isValidBackgroundOrigin(value) { - return Keywords['background-origin'].indexOf(value) > -1; -} - -function isValidBackgroundPosition(value) { - var parts; - var i, l; - - if (value === 'inherit') { - return true; - } - - parts = value.split(' '); - for (i = 0, l = parts.length; i < l; i++) { - if (parts[i] === '') { - continue; - } else if (isValidBackgroundPositionPart(parts[i])) { - continue; - } - - return false; - } - - return true; -} - -function isValidBackgroundPositionPart(value) { - return Keywords['background-position'].indexOf(value) > -1 || cssUnitOrCalcRegex.test(value); -} - -function isValidBackgroundSizePart(value) { - return Keywords['background-size'].indexOf(value) > -1 || cssUnitRegex.test(value); -} - -function isValidColor(value) { - return isValidNamedColor(value) || - isValidColorValue(value); -} - -function isValidColorValue(value) { - return isValidHexColor(value) || - isValidRgbaColor(value) || - isValidHslaColor(value); -} - -function isValidFontSize(compatibleCssUnitRegex, value) { - return isValidUnit(compatibleCssUnitRegex, value) || Keywords['font-size'].indexOf(value) > -1; -} - -function isValidFunction(value) { - return !urlRegex.test(value) && cssFunctionAnyRegex.test(value); -} - -function isValidFunctionWithoutVendorPrefix(value) { - return !urlRegex.test(value) && cssFunctionNoVendorRegex.test(value); -} - -function isValidGlobalValue(value) { - return globalKeywords.indexOf(value) > -1; -} +var Units = [ + '%', + 'ch', + 'cm', + 'em', + 'ex', + 'in', + 'mm', + 'pc', + 'pt', + 'px', + 'rem', + 'vh', + 'vm', + 'vmax', + 'vmin', + 'vw' +]; -function isValidHexColor(value) { - return (value.length === 4 || value.length === 7) && value[0] === '#'; +function isColor(value) { + return value != 'auto' && + ( + isKeyword('color')(value) || + isHexColor(value) || + isColorFunction(value) || + isNamedEntity(value) + ); } -function isValidHslaColor(value) { - return value.length > 0 && value.indexOf('hsla(') === 0 && value.indexOf(')') === value.length - 1; +function isColorFunction(value) { + return isRgbColor(value) || isHslColor(value); } -function isValidImage(value) { - return value == 'none' || value == 'inherit' || isValidUrl(value); +function isDynamicUnit(value) { + return calcRegex.test(value); } -function isValidKeywordValue(propertyName, value, includeGlobal) { - return Keywords[propertyName].indexOf(value) > -1 || includeGlobal && isValidGlobalValue(value); +function isFunction(value) { + return functionAnyRegex.test(value); } -function isValidLineHeight(compatibleCssUnitRegex, value) { - return isValidUnit(compatibleCssUnitRegex, value) || isValidNumber(value) || Keywords['line-height'].indexOf(value) > -1; +function isHexColor(value) { + return shortHexColorRegex.test(value) || longHexColorRegex.test(value); } -function isValidListStyleType(value) { - return Keywords['list-style-type'].indexOf(value) > -1; +function isHslColor(value) { + return hslColorRegex.test(value); } -function isValidListStylePosition(value) { - return Keywords['list-style-position'].indexOf(value) > -1; +function isImage(value) { + return value == 'none' || value == 'inherit' || isUrl(value); } -function isValidNamedColor(value) { - // We don't really check if it's a valid color value, but allow any letters in it - return value !== 'auto' && (value === 'transparent' || value === 'inherit' || /^[a-zA-Z]+$/.test(value)); +function isKeyword(propertyName) { + return function(value) { + return Keywords[propertyName].indexOf(value) > -1; + }; } -function isValidNumber(value) { - return ('' + parseFloat(value)) === value; +function isNamedEntity(value) { + return namedEntityRegex.test(value); } -function isValidRgbaColor(value) { - return value.length > 0 && value.indexOf('rgba(') === 0 && value.indexOf(')') === value.length - 1; +function isNumber(value) { + return value.length > 0 && ('' + parseFloat(value)) === value; } -function isValidStyle(value) { - return Keywords['*-style'].indexOf(value) > -1; +function isRgbColor(value) { + return rgbColorRegex.test(value); } -function isValidTextShadow(compatibleCssUnitRegex, value) { - return isValidUnitWithoutFunction(compatibleCssUnitRegex, value) || - isValidColor(value) || - isValidGlobalValue(value); +function isPrefixed(value) { + return prefixRegex.test(value); } -function isValidUnit(compatibleCssUnitAnyRegex, value) { - return compatibleCssUnitAnyRegex.test(value); +function isVariable(value) { + return variableRegex.test(value); } -function isValidUnitWithoutFunction(compatibleCssUnitRegex, value) { +function isUnit(compatibleCssUnitRegex, value) { return compatibleCssUnitRegex.test(value); } -function isValidUrl(value) { +function isUrl(value) { return urlRegex.test(value); } -function isValidVariable(value) { - return cssVariableRegex.test(value); -} - -function isValidVendorPrefixedValue(value) { - return /^-([A-Za-z0-9]|-)*$/gi.test(value); -} - -function isValidWidth(compatibleCssUnitRegex, value) { - return isValidUnit(compatibleCssUnitRegex, value) || Keywords.width.indexOf(value) > -1; -} - -function isValidZIndex(value) { +function isZIndex(value) { return value == 'auto' || - isValidGlobalValue(value) || - value.length > 0 && value == ('' + parseInt(value)); + isNumber(value) || + isKeyword('^')(value); } function validator(compatibility) { @@ -467,46 +373,40 @@ function validator(compatibility) { return !(value in compatibility.units) || compatibility.units[value] === true; }); - var compatibleCssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + '|)|auto|inherit)'; - var compatibleCssUnitRegex = new RegExp('^' + compatibleCssUnitRegexStr + '$', 'i'); - var compatibleCssUnitAnyRegex = new RegExp('^(none|' + Keywords.width.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i'); - var colorOpacity = compatibility.colors.opacity; + var compatibleCssUnitRegex = new RegExp('^(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + '|)|auto|inherit)$', 'i'); return { - areSameFunction: areSameFunction, - colorOpacity: colorOpacity, - hasNoVendorPrefix: hasNoVendorPrefix, - isValidBackgroundAttachment: isValidBackgroundAttachment, - isValidBackgroundClip: isValidBackgroundClip, - isValidBackgroundOrigin: isValidBackgroundOrigin, - isValidBackgroundPosition: isValidBackgroundPosition, - isValidBackgroundPositionPart: isValidBackgroundPositionPart, - isValidBackgroundRepeat: isValidBackgroundRepeat, - isValidBackgroundSizePart: isValidBackgroundSizePart, - isValidColor: isValidColor, - isValidColorValue: isValidColorValue, - isValidFontSize: isValidFontSize.bind(null, compatibleCssUnitRegex), - isValidFunction: isValidFunction, - isValidFunctionWithoutVendorPrefix: isValidFunctionWithoutVendorPrefix, - isValidGlobalValue: isValidGlobalValue, - isValidHexColor: isValidHexColor, - isValidHslaColor: isValidHslaColor, - isValidImage: isValidImage, - isValidKeywordValue: isValidKeywordValue, - isValidLineHeight: isValidLineHeight.bind(null, compatibleCssUnitRegex), - isValidListStylePosition: isValidListStylePosition, - isValidListStyleType: isValidListStyleType, - isValidNamedColor: isValidNamedColor, - isValidRgbaColor: isValidRgbaColor, - isValidStyle: isValidStyle, - isValidTextShadow: isValidTextShadow.bind(null, compatibleCssUnitRegex), - isValidUnit: isValidUnit.bind(null, compatibleCssUnitAnyRegex), - isValidUnitWithoutFunction: isValidUnitWithoutFunction.bind(null, compatibleCssUnitRegex), - isValidUrl: isValidUrl, - isValidVariable: isValidVariable, - isValidVendorPrefixedValue: isValidVendorPrefixedValue, - isValidWidth: isValidWidth.bind(null, compatibleCssUnitRegex), - isValidZIndex: isValidZIndex + colorOpacity: compatibility.colors.opacity, + isBackgroundAttachmentKeyword: isKeyword('background-attachment'), + isBackgroundClipKeyword: isKeyword('background-clip'), + isBackgroundOriginKeyword: isKeyword('background-origin'), + isBackgroundPositionKeyword: isKeyword('background-position'), + isBackgroundRepeatKeyword: isKeyword('background-repeat'), + isBackgroundSizeKeyword: isKeyword('background-size'), + isColor: isColor, + isColorFunction: isColorFunction, + isDynamicUnit: isDynamicUnit, + isFontSizeKeyword: isKeyword('font-size'), + isFontStretchKeyword: isKeyword('font-stretch'), + isFontStyleKeyword: isKeyword('font-style'), + isFontVariantKeyword: isKeyword('font-variant'), + isFontWeightKeyword: isKeyword('font-weight'), + isFunction: isFunction, + isGlobal: isKeyword('^'), + isHslColor: isHslColor, + isImage: isImage, + isKeyword: isKeyword, + isLineHeightKeyword: isKeyword('line-height'), + isListStylePositionKeyword: isKeyword('list-style-position'), + isListStyleTypeKeyword: isKeyword('list-style-type'), + isPrefixed: isPrefixed, + isRgbColor: isRgbColor, + isStyleKeyword: isKeyword('*-style'), + isUnit: isUnit.bind(null, compatibleCssUnitRegex), + isUrl: isUrl, + isVariable: isVariable, + isWidth: isKeyword('width'), + isZIndex: isZIndex }; } diff --git a/lib/reader/rebase.js b/lib/reader/rebase.js index 4e0ff975..181b319a 100644 --- a/lib/reader/rebase.js +++ b/lib/reader/rebase.js @@ -91,7 +91,7 @@ function rebaseProperties(properties, validator, rebaseConfig) { for (j = 2 /* 0 is Token.PROPERTY, 1 is name */, m = property.length; j < m; j++) { value = property[j][1]; - if (validator.isValidUrl(value)) { + if (validator.isUrl(value)) { property[j][1] = rewriteUrl(value, rebaseConfig); } } -- 2.34.1