var QUOTED_BUT_SAFE_PATTERN = /^['"][a-zA-Z][a-zA-Z\d\-_]+['"]$/;
var URL_PREFIX_PATTERN = /^url\(/i;
-var valueMinifiers = {
- 'background': function (value, index, total) {
- return index === 0 && total == 1 && (value == 'none' || value == 'transparent') ? '0 0' : value;
- },
- 'font-weight': function (value, _index, _total, options) {
- if (!options.compatibility.properties.fontWeight) {
- return value;
- } else if (value == 'normal') {
- return '400';
- } else if (value == 'bold') {
- return '700';
- } else {
- return value;
- }
- },
- 'outline': function (value, index, total) {
- return index === 0 && total == 1 && value == 'none' ? '0' : value;
- }
-};
-
function isNegative(value) {
return value && value[1][0] == '-' && parseFloat(value[1]) < 0;
}
-function zeroMinifier(name, value) {
- if (value.indexOf('0') == -1)
- return value;
-
- if (value.indexOf('-') > -1) {
- value = value
- .replace(/([^\w\d\-]|^)\-0([^\.]|$)/g, '$10$2')
- .replace(/([^\w\d\-]|^)\-0([^\.]|$)/g, '$10$2');
- }
-
- return value
- .replace(/(^|\s)0+([1-9])/g, '$1$2')
- .replace(/(^|\D)\.0+(\D|$)/g, '$10$2')
- .replace(/(^|\D)\.0+(\D|$)/g, '$10$2')
- .replace(/\.([1-9]*)0+(\D|$)/g, function (match, nonZeroPart, suffix) {
- return (nonZeroPart.length > 0 ? '.' : '') + nonZeroPart + suffix;
- })
- .replace(/(^|\D)0\.(\d)/g, '$1.$2');
+function isQuoted(value) {
+ return QUOTED_PATTERN.test(value);
}
-function zeroDegMinifier(_, value) {
- if (value.indexOf('0deg') == -1)
- return value;
-
- return value.replace(/\(0deg\)/g, '(0)');
+function isUrl(value) {
+ return URL_PREFIX_PATTERN.test(value);
}
-function whitespaceMinifier(name, value) {
- if (name.indexOf('filter') > -1 || value.indexOf(' ') == -1 || value.indexOf('expression') === 0)
- return value;
-
- if (value.indexOf(Marker.SINGLE_QUOTE) > -1 || value.indexOf(Marker.DOUBLE_QUOTE) > -1)
- return value;
-
- value = value.replace(/\s+/g, ' ');
-
- if (value.indexOf('calc') > -1)
- value = value.replace(/\) ?\/ ?/g, ')/ ');
-
+function normalizeUrl(value) {
return value
- .replace(/(\(;?)\s+/g, '$1')
- .replace(/\s+(;?\))/g, '$1')
- .replace(/, /g, ',');
+ .replace(URL_PREFIX_PATTERN, 'url(')
+ .replace(/\\?\n|\\?\r\n/g, '');
}
-function precisionMinifier(_, value, precisionOptions) {
- var optimizedValue = value.replace(/(\d)\.($|\D)/g, '$1$2');
+function optimizeBackground(property) {
+ var values = property.value;
- if (!precisionOptions.matcher || value.indexOf('.') === -1) {
- return optimizedValue;
+ if (values.length == 1 && values[0][1] == 'none') {
+ values[0][1] = '0 0';
}
- return optimizedValue
- .replace(precisionOptions.matcher, function (match, integerPart, fractionPart, unit) {
- var multiplier = precisionOptions.units[unit].multiplier;
- var parsedInteger = parseInt(integerPart);
- var integer = isNaN(parsedInteger) ? 0 : parsedInteger;
- var fraction = parseFloat(fractionPart);
-
- return Math.round((integer + fraction) * multiplier) / multiplier + unit;
- });
-}
-
-function unitMinifier(name, value, unitsRegexp) {
- if (/^(?:\-moz\-calc|\-webkit\-calc|calc)\(/.test(value))
- return value;
-
- if (name == 'flex' || name == '-ms-flex' || name == '-webkit-flex' || name == 'flex-basis' || name == '-webkit-flex-basis')
- return value;
-
- if (value.indexOf('%') > 0 && (name == 'height' || name == 'max-height'))
- return value;
-
- return value
- .replace(unitsRegexp, '$1' + '0' + '$2')
- .replace(unitsRegexp, '$1' + '0' + '$2');
+ if (values.length == 1 && values[0][1] == 'transparent') {
+ values[0][1] = '0 0';
+ }
}
-function multipleZerosMinifier(property) {
+function optimizeBorderRadius(property) {
var values = property.value;
var spliceAt;
- if (values.length == 4 && values[0][1] === '0' && values[1][1] === '0' && values[2][1] === '0' && values[3][1] === '0') {
- if (property.name.indexOf('box-shadow') > -1) {
- spliceAt = 2;
- } else {
- spliceAt = 1;
- }
+ if (values.length == 3 && values[1][1] == '/' && values[0][1] == values[2][1]) {
+ spliceAt = 1;
+ } else if (values.length == 5 && values[2][1] == '/' && values[0][1] == values[3][1] && values[1][1] == values[4][1]) {
+ spliceAt = 2;
+ } else if (values.length == 7 && values[3][1] == '/' && values[0][1] == values[4][1] && values[1][1] == values[5][1] && values[2][1] == values[6][1]) {
+ spliceAt = 3;
+ } else if (values.length == 9 && values[4][1] == '/' && values[0][1] == values[5][1] && values[1][1] == values[6][1] && values[2][1] == values[7][1] && values[3][1] == values[8][1]) {
+ spliceAt = 4;
}
if (spliceAt) {
}
}
-function colorMininifier(name, value, compatibility) {
+function optimizeColors(name, value, compatibility) {
if (value.indexOf('#') === -1 && value.indexOf('rgb') == -1 && value.indexOf('hsl') == -1) {
return shortenHex(value);
}
(colorFunction == 'hsla' && tokens.length == 4) ||
(colorFunction == 'rgb' && tokens.length == 3 && colorDef.indexOf('%') > 0) ||
(colorFunction == 'rgba' && tokens.length == 4 && colorDef.indexOf('%') > 0);
- if (!applies)
+
+ if (!applies) {
return match;
+ }
- if (tokens[1].indexOf('%') == -1)
+ if (tokens[1].indexOf('%') == -1) {
tokens[1] += '%';
- if (tokens[2].indexOf('%') == -1)
+ }
+
+ if (tokens[2].indexOf('%') == -1) {
tokens[2] += '%';
+ }
+
return colorFunction + '(' + tokens.join(',') + ')';
});
if (compatibility.colors.opacity && name.indexOf('background') == -1) {
value = value.replace(/(?:rgba|hsla)\(0,0%?,0%?,0\)/g, function (match) {
- if (split(value, ',').pop().indexOf('gradient(') > -1)
+ if (split(value, ',').pop().indexOf('gradient(') > -1) {
return match;
+ }
return 'transparent';
});
return shortenHex(value);
}
-function pixelLengthMinifier(_, value, compatibility) {
+function optimizeFilters(property) {
+ if (property.value.length == 1) {
+ property.value[0][1] = property.value[0][1].replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\W)/, function (match, filter, suffix) {
+ return filter.toLowerCase() + suffix;
+ });
+ }
+
+ property.value[0][1] = property.value[0][1]
+ .replace(/,(\S)/g, ', $1')
+ .replace(/ ?= ?/g, '=');
+}
+
+function optimizeFont(property, options) {
+ var values = property.value;
+ var hasNumeral = FONT_NUMERAL_WEIGHTS.indexOf(values[0][1]) > -1 ||
+ values[1] && FONT_NUMERAL_WEIGHTS.indexOf(values[1][1]) > -1 ||
+ values[2] && FONT_NUMERAL_WEIGHTS.indexOf(values[2][1]) > -1;
+ var normalCount = 0;
+ var toOptimize;
+
+ if (!options.compatibility.properties.fontWeight) {
+ return;
+ }
+
+ if (hasNumeral) {
+ return;
+ }
+
+ if (values[1] && values[1][1] == '/') {
+ return;
+ }
+
+ if (values[0][1] == 'normal') {
+ normalCount++;
+ }
+
+ if (values[1] && values[1][1] == 'normal') {
+ normalCount++;
+ }
+
+ if (values[2] && values[2][1] == 'normal') {
+ normalCount++;
+ }
+
+ if (normalCount > 1) {
+ return;
+ }
+
+ if (FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[0][1]) > -1) {
+ toOptimize = 0;
+ } else if (values[1] && FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[1][1]) > -1) {
+ toOptimize = 1;
+ } else if (values[2] && FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[2][1]) > -1) {
+ toOptimize = 2;
+ } else if (FONT_NAME_WEIGHTS.indexOf(values[0][1]) > -1) {
+ toOptimize = 0;
+ } else if (values[1] && FONT_NAME_WEIGHTS.indexOf(values[1][1]) > -1) {
+ toOptimize = 1;
+ } else if (values[2] && FONT_NAME_WEIGHTS.indexOf(values[2][1]) > -1) {
+ toOptimize = 2;
+ }
+
+ if (toOptimize !== undefined) {
+ optimizeFontWeight(property, toOptimize);
+ property.dirty = true;
+ }
+}
+
+function optimizeFontWeight(property, atIndex) {
+ var value = property.value[atIndex][1];
+
+ if (value == 'normal') {
+ value = '400';
+ } else if (value == 'bold') {
+ value = '700';
+ }
+
+ property.value[atIndex][1] = value;
+}
+
+function optimizeMultipleZeros(property) {
+ var values = property.value;
+ var spliceAt;
+
+ if (values.length == 4 && values[0][1] === '0' && values[1][1] === '0' && values[2][1] === '0' && values[3][1] === '0') {
+ if (property.name.indexOf('box-shadow') > -1) {
+ spliceAt = 2;
+ } else {
+ spliceAt = 1;
+ }
+ }
+
+ if (spliceAt) {
+ property.value.splice(spliceAt);
+ property.dirty = true;
+ }
+}
+
+function optimizeOutline(property) {
+ var values = property.value;
+
+ if (values.length == 1 && values[0][1] == 'none') {
+ values[0][1] = '0';
+ }
+}
+
+function optimizePixelLengths(_, value, compatibility) {
if (!WHOLE_PIXEL_VALUE.test(value))
return value;
var newValue;
var intVal = parseInt(val);
- if (intVal === 0)
+ if (intVal === 0) {
return match;
+ }
- if (compatibility.properties.shorterLengthUnits && compatibility.units.pt && intVal * 3 % 4 === 0)
+ if (compatibility.properties.shorterLengthUnits && compatibility.units.pt && intVal * 3 % 4 === 0) {
newValue = intVal * 3 / 4 + 'pt';
+ }
- if (compatibility.properties.shorterLengthUnits && compatibility.units.pc && intVal % 16 === 0)
+ if (compatibility.properties.shorterLengthUnits && compatibility.units.pc && intVal % 16 === 0) {
newValue = intVal / 16 + 'pc';
+ }
- if (compatibility.properties.shorterLengthUnits && compatibility.units.in && intVal % 96 === 0)
+ if (compatibility.properties.shorterLengthUnits && compatibility.units.in && intVal % 96 === 0) {
newValue = intVal / 96 + 'in';
+ }
- if (newValue)
+ if (newValue) {
newValue = match.substring(0, match.indexOf(val)) + newValue;
+ }
return newValue && newValue.length < match.length ? newValue : match;
});
}
-function timeUnitMinifier(_, value) {
+function optimizePrecision(_, value, precisionOptions) {
+ var optimizedValue = value.replace(/(\d)\.($|\D)/g, '$1$2');
+
+ if (!precisionOptions.matcher || value.indexOf('.') === -1) {
+ return optimizedValue;
+ }
+
+ return optimizedValue
+ .replace(precisionOptions.matcher, function (match, integerPart, fractionPart, unit) {
+ var multiplier = precisionOptions.units[unit].multiplier;
+ var parsedInteger = parseInt(integerPart);
+ var integer = isNaN(parsedInteger) ? 0 : parsedInteger;
+ var fraction = parseFloat(fractionPart);
+
+ return Math.round((integer + fraction) * multiplier) / multiplier + unit;
+ });
+}
+
+function optimizeTimeUnits(_, value) {
if (!TIME_VALUE.test(value))
return value;
});
}
-function minifyBorderRadius(property) {
- var values = property.value;
- var spliceAt;
-
- if (values.length == 3 && values[1][1] == '/' && values[0][1] == values[2][1])
- spliceAt = 1;
- else if (values.length == 5 && values[2][1] == '/' && values[0][1] == values[3][1] && values[1][1] == values[4][1])
- spliceAt = 2;
- else if (values.length == 7 && values[3][1] == '/' && values[0][1] == values[4][1] && values[1][1] == values[5][1] && values[2][1] == values[6][1])
- spliceAt = 3;
- else if (values.length == 9 && values[4][1] == '/' && values[0][1] == values[5][1] && values[1][1] == values[6][1] && values[2][1] == values[7][1] && values[3][1] == values[8][1])
- spliceAt = 4;
+function optimizeUnits(name, value, unitsRegexp) {
+ if (/^(?:\-moz\-calc|\-webkit\-calc|calc)\(/.test(value)) {
+ return value;
+ }
- if (spliceAt) {
- property.value.splice(spliceAt);
- property.dirty = true;
+ if (name == 'flex' || name == '-ms-flex' || name == '-webkit-flex' || name == 'flex-basis' || name == '-webkit-flex-basis') {
+ return value;
}
-}
-function minifyFilter(property) {
- if (property.value.length == 1) {
- property.value[0][1] = property.value[0][1].replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\W)/, function (match, filter, suffix) {
- return filter.toLowerCase() + suffix;
- });
+ if (value.indexOf('%') > 0 && (name == 'height' || name == 'max-height')) {
+ return value;
}
- property.value[0][1] = property.value[0][1]
- .replace(/,(\S)/g, ', $1')
- .replace(/ ?= ?/g, '=');
+ return value
+ .replace(unitsRegexp, '$1' + '0' + '$2')
+ .replace(unitsRegexp, '$1' + '0' + '$2');
}
-function minifyFont(property, options) {
- var values = property.value;
- var hasNumeral = FONT_NUMERAL_WEIGHTS.indexOf(values[0][1]) > -1 ||
- values[1] && FONT_NUMERAL_WEIGHTS.indexOf(values[1][1]) > -1 ||
- values[2] && FONT_NUMERAL_WEIGHTS.indexOf(values[2][1]) > -1;
-
- if (!options.compatibility.properties.fontWeight) {
- return;
+function optimizeWhitespace(name, value) {
+ if (name.indexOf('filter') > -1 || value.indexOf(' ') == -1 || value.indexOf('expression') === 0) {
+ return value;
}
- if (hasNumeral)
- return;
-
- if (values[1] && values[1][1] == '/')
- return;
-
- var normalCount = 0;
- if (values[0][1] == 'normal')
- normalCount++;
- if (values[1] && values[1][1] == 'normal')
- normalCount++;
- if (values[2] && values[2][1] == 'normal')
- normalCount++;
-
- if (normalCount > 1)
- return;
+ if (value.indexOf(Marker.SINGLE_QUOTE) > -1 || value.indexOf(Marker.DOUBLE_QUOTE) > -1) {
+ return value;
+ }
- var toOptimize;
- if (FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[0][1]) > -1)
- toOptimize = 0;
- else if (values[1] && FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[1][1]) > -1)
- toOptimize = 1;
- else if (values[2] && FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[2][1]) > -1)
- toOptimize = 2;
- else if (FONT_NAME_WEIGHTS.indexOf(values[0][1]) > -1)
- toOptimize = 0;
- else if (values[1] && FONT_NAME_WEIGHTS.indexOf(values[1][1]) > -1)
- toOptimize = 1;
- else if (values[2] && FONT_NAME_WEIGHTS.indexOf(values[2][1]) > -1)
- toOptimize = 2;
+ value = value.replace(/\s+/g, ' ');
- if (toOptimize !== undefined) {
- property.value[toOptimize][1] = valueMinifiers['font-weight'](values[toOptimize][1], null, null, options);
- property.dirty = true;
+ if (value.indexOf('calc') > -1) {
+ value = value.replace(/\) ?\/ ?/g, ')/ ');
}
-}
-function normalizeUrl(value) {
return value
- .replace(URL_PREFIX_PATTERN, 'url(')
- .replace(/\\?\n|\\?\r\n/g, '');
+ .replace(/(\(;?)\s+/g, '$1')
+ .replace(/\s+(;?\))/g, '$1')
+ .replace(/, /g, ',');
}
-function removeUrlQuotes(value) {
- return /^url\(['"].+['"]\)$/.test(value) && !/^url\(['"].*[\*\s\(\)'"].*['"]\)$/.test(value) && !/^url\(['"]data:[^;]+;charset/.test(value) ?
- value.replace(/["']/g, '') :
- value;
+function optimizeZeroDegUnit(_, value) {
+ if (value.indexOf('0deg') == -1) {
+ return value;
+ }
+
+ return value.replace(/\(0deg\)/g, '(0)');
}
-function isQuoted(value) {
- return QUOTED_PATTERN.test(value);
+function optimizeZeroUnits(name, value) {
+ if (value.indexOf('0') == -1) {
+ return value;
+ }
+
+ if (value.indexOf('-') > -1) {
+ value = value
+ .replace(/([^\w\d\-]|^)\-0([^\.]|$)/g, '$10$2')
+ .replace(/([^\w\d\-]|^)\-0([^\.]|$)/g, '$10$2');
+ }
+
+ return value
+ .replace(/(^|\s)0+([1-9])/g, '$1$2')
+ .replace(/(^|\D)\.0+(\D|$)/g, '$10$2')
+ .replace(/(^|\D)\.0+(\D|$)/g, '$10$2')
+ .replace(/\.([1-9]*)0+(\D|$)/g, function (match, nonZeroPart, suffix) {
+ return (nonZeroPart.length > 0 ? '.' : '') + nonZeroPart + suffix;
+ })
+ .replace(/(^|\D)0\.(\d)/g, '$1.$2');
}
function removeQuotes(name, value) {
value;
}
+function removeUrlQuotes(value) {
+ return /^url\(['"].+['"]\)$/.test(value) && !/^url\(['"].*[\*\s\(\)'"].*['"]\)$/.test(value) && !/^url\(['"]data:[^;]+;charset/.test(value) ?
+ value.replace(/["']/g, '') :
+ value;
+}
+
+//
+
function optimizeBody(properties, context) {
var options = context.options;
var property, name, type, value;
property.unused = true;
}
- if (name.indexOf('padding') === 0 && (isNegative(property.value[0]) || isNegative(property.value[1]) || isNegative(property.value[2]) || isNegative(property.value[3])))
+ if (name.indexOf('padding') === 0 && (isNegative(property.value[0]) || isNegative(property.value[1]) || isNegative(property.value[2]) || isNegative(property.value[3]))) {
property.unused = true;
+ }
- if (property.unused)
+ if (property.unused) {
continue;
+ }
if (property.block) {
optimizeBody(property.value[0][1], context);
break;
}
- if (valueMinifiers[name]) {
- value = valueMinifiers[name](value, j, m, options);
- }
-
if (valueIsUrl) {
value = normalizeUrl(value);
value = options.compatibility.properties.urlQuotes ?
} else if (isQuoted(value)) {
value = removeQuotes(name, value);
} else {
- value = whitespaceMinifier(name, value);
- value = precisionMinifier(name, value, options.precision);
- value = pixelLengthMinifier(name, value, options.compatibility);
- value = timeUnitMinifier(name, value);
- value = zeroMinifier(name, value);
+ value = optimizeWhitespace(name, value);
+ value = optimizePrecision(name, value, options.precision);
+ value = optimizePixelLengths(name, value, options.compatibility);
+ value = optimizeTimeUnits(name, value);
+ value = optimizeZeroUnits(name, value);
if (options.compatibility.properties.zeroUnits) {
- value = zeroDegMinifier(name, value);
- value = unitMinifier(name, value, options.unitsRegexp);
+ value = optimizeZeroDegUnit(name, value);
+ value = optimizeUnits(name, value, options.unitsRegexp);
}
if (options.compatibility.properties.colors)
- value = colorMininifier(name, value, options.compatibility);
+ value = optimizeColors(name, value, options.compatibility);
}
property.value[j][1] = value;
}
- multipleZerosMinifier(property);
-
- if (name.indexOf('border') === 0 && name.indexOf('radius') > 0)
- minifyBorderRadius(property);
- else if (name == 'filter')
- minifyFilter(property);
- else if (name == 'font')
- minifyFont(property, options);
+ optimizeMultipleZeros(property);
+
+ if (name == 'background') {
+ optimizeBackground(property);
+ } else if (name.indexOf('border') === 0 && name.indexOf('radius') > 0) {
+ optimizeBorderRadius(property);
+ } else if (name == 'filter') {
+ optimizeFilters(property);
+ } else if (name == 'font') {
+ optimizeFont(property, options);
+ } else if (name == 'font-weight' && options.compatibility.properties.fontWeight) {
+ optimizeFontWeight(property, 0);
+ } else if (name == 'outline') {
+ optimizeOutline(property);
+ }
}
restoreFromOptimizing(_properties);
}
}
-function isUrl(value) {
- return URL_PREFIX_PATTERN.test(value);
-}
-
function removeComments(tokens, options) {
var token;
var i;
var otherUnits = ['ch', 'rem', 'vh', 'vm', 'vmax', 'vmin', 'vw'];
otherUnits.forEach(function (unit) {
- if (options.compatibility.units[unit])
+ if (options.compatibility.units[unit]) {
units.push(unit);
+ }
});
return new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')(\\W|$)', 'g');