123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- var compactable = require('./compactable');
- var wrapForOptimizing = require('./wrap-for-optimizing').all;
- var populateComponents = require('./populate-components');
- var compactOverrides = require('./override-compactor');
- var compactShorthands = require('./shorthand-compactor');
- var removeUnused = require('./remove-unused');
- var restoreFromOptimizing = require('./restore-from-optimizing');
- var stringifyProperty = require('../stringifier/one-time').property;
- var shorthands = {
- 'animation-delay': ['animation'],
- 'animation-direction': ['animation'],
- 'animation-duration': ['animation'],
- 'animation-fill-mode': ['animation'],
- 'animation-iteration-count': ['animation'],
- 'animation-name': ['animation'],
- 'animation-play-state': ['animation'],
- 'animation-timing-function': ['animation'],
- '-moz-animation-delay': ['-moz-animation'],
- '-moz-animation-direction': ['-moz-animation'],
- '-moz-animation-duration': ['-moz-animation'],
- '-moz-animation-fill-mode': ['-moz-animation'],
- '-moz-animation-iteration-count': ['-moz-animation'],
- '-moz-animation-name': ['-moz-animation'],
- '-moz-animation-play-state': ['-moz-animation'],
- '-moz-animation-timing-function': ['-moz-animation'],
- '-o-animation-delay': ['-o-animation'],
- '-o-animation-direction': ['-o-animation'],
- '-o-animation-duration': ['-o-animation'],
- '-o-animation-fill-mode': ['-o-animation'],
- '-o-animation-iteration-count': ['-o-animation'],
- '-o-animation-name': ['-o-animation'],
- '-o-animation-play-state': ['-o-animation'],
- '-o-animation-timing-function': ['-o-animation'],
- '-webkit-animation-delay': ['-webkit-animation'],
- '-webkit-animation-direction': ['-webkit-animation'],
- '-webkit-animation-duration': ['-webkit-animation'],
- '-webkit-animation-fill-mode': ['-webkit-animation'],
- '-webkit-animation-iteration-count': ['-webkit-animation'],
- '-webkit-animation-name': ['-webkit-animation'],
- '-webkit-animation-play-state': ['-webkit-animation'],
- '-webkit-animation-timing-function': ['-webkit-animation'],
- 'border-color': ['border'],
- 'border-style': ['border'],
- 'border-width': ['border'],
- 'border-bottom': ['border'],
- 'border-bottom-color': ['border-bottom', 'border-color', 'border'],
- 'border-bottom-style': ['border-bottom', 'border-style', 'border'],
- 'border-bottom-width': ['border-bottom', 'border-width', 'border'],
- 'border-left': ['border'],
- 'border-left-color': ['border-left', 'border-color', 'border'],
- 'border-left-style': ['border-left', 'border-style', 'border'],
- 'border-left-width': ['border-left', 'border-width', 'border'],
- 'border-right': ['border'],
- 'border-right-color': ['border-right', 'border-color', 'border'],
- 'border-right-style': ['border-right', 'border-style', 'border'],
- 'border-right-width': ['border-right', 'border-width', 'border'],
- 'border-top': ['border'],
- 'border-top-color': ['border-top', 'border-color', 'border'],
- 'border-top-style': ['border-top', 'border-style', 'border'],
- 'border-top-width': ['border-top', 'border-width', 'border'],
- 'font-family': ['font'],
- 'font-size': ['font'],
- 'font-style': ['font'],
- 'font-variant': ['font'],
- 'font-weight': ['font'],
- 'transition-delay': ['transition'],
- 'transition-duration': ['transition'],
- 'transition-property': ['transition'],
- 'transition-timing-function': ['transition'],
- '-moz-transition-delay': ['-moz-transition'],
- '-moz-transition-duration': ['-moz-transition'],
- '-moz-transition-property': ['-moz-transition'],
- '-moz-transition-timing-function': ['-moz-transition'],
- '-o-transition-delay': ['-o-transition'],
- '-o-transition-duration': ['-o-transition'],
- '-o-transition-property': ['-o-transition'],
- '-o-transition-timing-function': ['-o-transition'],
- '-webkit-transition-delay': ['-webkit-transition'],
- '-webkit-transition-duration': ['-webkit-transition'],
- '-webkit-transition-property': ['-webkit-transition'],
- '-webkit-transition-timing-function': ['-webkit-transition']
- };
- function _optimize(properties, mergeAdjacent, aggressiveMerging, validator) {
- var overrideMapping = {};
- var lastName = null;
- var lastProperty;
- var j;
- function mergeablePosition(position) {
- if (mergeAdjacent === false || mergeAdjacent === true)
- return mergeAdjacent;
- return mergeAdjacent.indexOf(position) > -1;
- }
- function sameValue(position) {
- var left = properties[position - 1];
- var right = properties[position];
- return stringifyProperty(left.all, left.position) == stringifyProperty(right.all, right.position);
- }
- propertyLoop:
- for (var position = 0, total = properties.length; position < total; position++) {
- var property = properties[position];
- var _name = (property.name == '-ms-filter' || property.name == 'filter') ?
- (lastName == 'background' || lastName == 'background-image' ? lastName : property.name) :
- property.name;
- var isImportant = property.important;
- var isHack = property.hack;
- if (property.unused)
- continue;
- if (position > 0 && lastProperty && _name == lastName && isImportant == lastProperty.important && isHack == lastProperty.hack && sameValue(position) && !lastProperty.unused) {
- property.unused = true;
- continue;
- }
- // comment is necessary - we assume that if two properties are one after another
- // then it is intentional way of redefining property which may not be widely supported
- // e.g. a{display:inline-block;display:-moz-inline-box}
- // however if `mergeablePosition` yields true then the rule does not apply
- // (e.g merging two adjacent selectors: `a{display:block}a{display:block}`)
- if (_name in overrideMapping && (aggressiveMerging && _name != lastName || mergeablePosition(position))) {
- var toOverridePositions = overrideMapping[_name];
- var canOverride = compactable[_name] && compactable[_name].canOverride;
- var anyRemoved = false;
- for (j = toOverridePositions.length - 1; j >= 0; j--) {
- var toRemove = properties[toOverridePositions[j]];
- var longhandToShorthand = toRemove.name != _name;
- var wasImportant = toRemove.important;
- var wasHack = toRemove.hack;
- if (toRemove.unused)
- continue;
- if (longhandToShorthand && wasImportant)
- continue;
- if (!wasImportant && (wasHack && !isHack || !wasHack && isHack))
- continue;
- if (wasImportant && (isHack == 'star' || isHack == 'underscore'))
- continue;
- if (!wasHack && !isHack && !longhandToShorthand && canOverride && !canOverride(toRemove, property, validator))
- continue;
- if (wasImportant && !isImportant || wasImportant && isHack) {
- property.unused = true;
- lastProperty = property;
- continue propertyLoop;
- } else {
- anyRemoved = true;
- toRemove.unused = true;
- }
- }
- if (anyRemoved) {
- position = -1;
- lastProperty = null;
- lastName = null;
- overrideMapping = {};
- continue;
- }
- } else {
- overrideMapping[_name] = overrideMapping[_name] || [];
- overrideMapping[_name].push(position);
- // TODO: to be removed with
- // certain shorthand (see values of `shorthands`) should trigger removal of
- // longhand properties (see keys of `shorthands`)
- var _shorthands = shorthands[_name];
- if (_shorthands) {
- for (j = _shorthands.length - 1; j >= 0; j--) {
- var shorthand = _shorthands[j];
- overrideMapping[shorthand] = overrideMapping[shorthand] || [];
- overrideMapping[shorthand].push(position);
- }
- }
- }
- lastName = _name;
- lastProperty = property;
- }
- }
- function optimize(selector, properties, mergeAdjacent, withCompacting, options, context) {
- var validator = context.validator;
- var warnings = context.warnings;
- var _properties = wrapForOptimizing(properties);
- populateComponents(_properties, validator, warnings);
- _optimize(_properties, mergeAdjacent, options.aggressiveMerging, validator);
- for (var i = 0, l = _properties.length; i < l; i++) {
- var _property = _properties[i];
- if (_property.variable && _property.block)
- optimize(selector, _property.value[0], mergeAdjacent, withCompacting, options, context);
- }
- if (withCompacting && options.shorthandCompacting) {
- compactOverrides(_properties, options.compatibility, validator);
- compactShorthands(_properties, options.sourceMap, validator);
- }
- restoreFromOptimizing(_properties);
- removeUnused(_properties);
- }
- module.exports = optimize;
|