aboutsummaryrefslogtreecommitdiff
path: root/node_modules/clean-css/lib/optimizer/level-2
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-05-03 15:35:00 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-05-03 15:35:00 +0200
commitde98e0b232509d5f40c135d540a70e415272ff85 (patch)
treea79222a5b58484ab3b80d18efcaaa7ccc4769b33 /node_modules/clean-css/lib/optimizer/level-2
parente0c9d480a73fa629c1e4a47d3e721f1d2d345406 (diff)
node_modules
Diffstat (limited to 'node_modules/clean-css/lib/optimizer/level-2')
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/break-up.js362
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/can-override.js180
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/clone.js33
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/compactable.js787
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/extract-properties.js73
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/invalid-property-error.js10
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js236
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js49
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/merge-media-queries.js103
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js79
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-selector.js78
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/optimize.js124
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js28
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/find-component-in.js40
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/has-inherit.js10
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/is-component-of.js22
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js157
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js39
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js441
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/overrides-non-component-shorthand.js9
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/populate-components.js42
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/understandable.js15
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/properties/vendor-prefixes.js23
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/reduce-non-adjacent.js178
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/remove-duplicate-font-at-rules.js30
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/remove-duplicate-media-queries.js30
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/remove-duplicates.js43
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/reorderable.js93
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/restore-with-components.js13
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/restore.js233
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/restructure.js388
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/rules-overlap.js32
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/specificities-overlap.js34
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/specificity.js77
-rw-r--r--node_modules/clean-css/lib/optimizer/level-2/tidy-rule-duplicates.js21
35 files changed, 4112 insertions, 0 deletions
diff --git a/node_modules/clean-css/lib/optimizer/level-2/break-up.js b/node_modules/clean-css/lib/optimizer/level-2/break-up.js
new file mode 100644
index 000000000..9e44d5a1f
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/break-up.js
@@ -0,0 +1,362 @@
+var InvalidPropertyError = require('./invalid-property-error');
+
+var wrapSingle = require('../wrap-for-optimizing').single;
+
+var Token = require('../../tokenizer/token');
+
+var formatPosition = require('../../utils/format-position');
+
+var MULTIPLEX_SEPARATOR = ',';
+
+function _colorFilter(validator) {
+ return function (value) {
+ return value[1] == 'invert' || validator.isValidColor(value[1]) || validator.isValidVendorPrefixedValue(value[1]);
+ };
+}
+
+function _styleFilter(validator) {
+ return function (value) {
+ return value[1] != 'inherit' && validator.isValidStyle(value[1]) && !validator.isValidColorValue(value[1]);
+ };
+}
+
+function _wrapDefault(name, property, compactable) {
+ var descriptor = compactable[name];
+ if (descriptor.doubleValues && descriptor.defaultValue.length == 2) {
+ return wrapSingle([
+ Token.PROPERTY,
+ [Token.PROPERTY_NAME, name],
+ [Token.PROPERTY_VALUE, descriptor.defaultValue[0]],
+ [Token.PROPERTY_VALUE, descriptor.defaultValue[1]]
+ ]);
+ } else if (descriptor.doubleValues && descriptor.defaultValue.length == 1) {
+ return wrapSingle([
+ Token.PROPERTY,
+ [Token.PROPERTY_NAME, name],
+ [Token.PROPERTY_VALUE, descriptor.defaultValue[0]]
+ ]);
+ } else {
+ return wrapSingle([
+ Token.PROPERTY,
+ [Token.PROPERTY_NAME, name],
+ [Token.PROPERTY_VALUE, descriptor.defaultValue]
+ ]);
+ }
+}
+
+function _widthFilter(validator) {
+ return function (value) {
+ return value[1] != 'inherit' && validator.isValidWidth(value[1]) && !validator.isValidStyle(value[1]) && !validator.isValidColorValue(value[1]);
+ };
+}
+
+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);
+ var repeat = _wrapDefault('background-repeat', property, compactable);
+ var attachment = _wrapDefault('background-attachment', property, compactable);
+ var origin = _wrapDefault('background-origin', property, compactable);
+ var clip = _wrapDefault('background-clip', property, compactable);
+ var color = _wrapDefault('background-color', property, compactable);
+ var components = [image, position, size, repeat, attachment, origin, clip, color];
+ var values = property.value;
+
+ var positionSet = false;
+ var clipSet = false;
+ var originSet = false;
+ var repeatSet = false;
+
+ var anyValueSet = false;
+
+ if (property.value.length == 1 && property.value[0][1] == 'inherit') {
+ // NOTE: 'inherit' is not a valid value for background-attachment
+ color.value = image.value = repeat.value = position.value = size.value = origin.value = clip.value = property.value;
+ return components;
+ }
+
+ if (property.value.length == 1 && property.value[0][1] == '0 0') {
+ return components;
+ }
+
+ for (var i = values.length - 1; i >= 0; i--) {
+ var value = values[i];
+
+ if (validator.isValidBackgroundAttachment(value[1])) {
+ attachment.value = [value];
+ anyValueSet = true;
+ } else if (validator.isValidBackgroundClip(value[1]) || validator.isValidBackgroundOrigin(value[1])) {
+ if (clipSet) {
+ origin.value = [value];
+ originSet = true;
+ } else {
+ clip.value = [value];
+ clipSet = true;
+ }
+ anyValueSet = true;
+ } else if (validator.isValidBackgroundRepeat(value[1])) {
+ if (repeatSet) {
+ repeat.value.unshift(value);
+ } else {
+ repeat.value = [value];
+ repeatSet = true;
+ }
+ anyValueSet = true;
+ } else if (validator.isValidBackgroundPositionPart(value[1]) || validator.isValidBackgroundSizePart(value[1])) {
+ if (i > 0) {
+ var previousValue = values[i - 1];
+
+ if (previousValue[1] == '/') {
+ size.value = [value];
+ } else if (i > 1 && values[i - 2][1] == '/') {
+ size.value = [previousValue, value];
+ i -= 2;
+ } else {
+ if (!positionSet)
+ position.value = [];
+
+ position.value.unshift(value);
+ positionSet = true;
+ }
+ } else {
+ if (!positionSet)
+ position.value = [];
+
+ position.value.unshift(value);
+ 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]))) {
+ color.value = [value];
+ anyValueSet = true;
+ } else if (validator.isValidUrl(value[1]) || validator.isValidFunction(value[1])) {
+ image.value = [value];
+ anyValueSet = true;
+ }
+ }
+
+ if (clipSet && !originSet)
+ origin.value = clip.value.slice(0);
+
+ if (!anyValueSet) {
+ throw new InvalidPropertyError('Invalid background value at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+ }
+
+ return components;
+}
+
+function borderRadius(property, compactable) {
+ var values = property.value;
+ var splitAt = -1;
+
+ for (var i = 0, l = values.length; i < l; i++) {
+ if (values[i][1] == '/') {
+ splitAt = i;
+ break;
+ }
+ }
+
+ if (splitAt === 0 || splitAt === values.length - 1) {
+ throw new InvalidPropertyError('Invalid border-radius value at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+ }
+
+ var target = _wrapDefault(property.name, property, compactable);
+ target.value = splitAt > -1 ?
+ values.slice(0, splitAt) :
+ values.slice(0);
+ target.components = fourValues(target, compactable);
+
+ var remainder = _wrapDefault(property.name, property, compactable);
+ remainder.value = splitAt > -1 ?
+ values.slice(splitAt + 1) :
+ values.slice(0);
+ remainder.components = fourValues(remainder, compactable);
+
+ for (var j = 0; j < 4; j++) {
+ target.components[j].multiplex = true;
+ target.components[j].value = target.components[j].value.concat(remainder.components[j].value);
+ }
+
+ return target.components;
+}
+
+function fourValues(property, compactable) {
+ var componentNames = compactable[property.name].components;
+ var components = [];
+ var value = property.value;
+
+ if (value.length < 1)
+ return [];
+
+ if (value.length < 2)
+ value[1] = value[0].slice(0);
+ if (value.length < 3)
+ value[2] = value[0].slice(0);
+ if (value.length < 4)
+ value[3] = value[1].slice(0);
+
+ for (var i = componentNames.length - 1; i >= 0; i--) {
+ var component = wrapSingle([
+ Token.PROPERTY,
+ [Token.PROPERTY_NAME, componentNames[i]]
+ ]);
+ component.value = [value[i]];
+ components.unshift(component);
+ }
+
+ return components;
+}
+
+function multiplex(splitWith) {
+ return function (property, compactable, validator) {
+ var splitsAt = [];
+ var values = property.value;
+ var i, j, l, m;
+
+ // find split commas
+ for (i = 0, l = values.length; i < l; i++) {
+ if (values[i][1] == ',')
+ splitsAt.push(i);
+ }
+
+ if (splitsAt.length === 0)
+ return splitWith(property, compactable, validator);
+
+ var splitComponents = [];
+
+ // split over commas, and into components
+ for (i = 0, l = splitsAt.length; i <= l; i++) {
+ var from = i === 0 ? 0 : splitsAt[i - 1] + 1;
+ var to = i < l ? splitsAt[i] : values.length;
+
+ var _property = _wrapDefault(property.name, property, compactable);
+ _property.value = values.slice(from, to);
+
+ splitComponents.push(splitWith(_property, compactable, validator));
+ }
+
+ var components = splitComponents[0];
+
+ // group component values from each split
+ for (i = 0, l = components.length; i < l; i++) {
+ components[i].multiplex = true;
+
+ for (j = 1, m = splitComponents.length; j < m; j++) {
+ components[i].value.push([Token.PROPERTY_VALUE, MULTIPLEX_SEPARATOR]);
+ Array.prototype.push.apply(components[i].value, splitComponents[j][i].value);
+ }
+ }
+
+ return components;
+ };
+}
+
+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);
+ var components = [type, position, image];
+
+ if (property.value.length == 1 && property.value[0][1] == 'inherit') {
+ type.value = position.value = image.value = [property.value[0]];
+ return components;
+ }
+
+ var values = property.value.slice(0);
+ var total = values.length;
+ var index = 0;
+
+ // `image` first...
+ for (index = 0, total = values.length; index < total; index++) {
+ if (validator.isValidUrl(values[index][1]) || values[index][1] == '0') {
+ image.value = [values[index]];
+ values.splice(index, 1);
+ break;
+ }
+ }
+
+ // ... then `type`...
+ for (index = 0, total = values.length; index < total; index++) {
+ if (validator.isValidListStyleType(values[index][1])) {
+ type.value = [values[index]];
+ values.splice(index, 1);
+ break;
+ }
+ }
+
+ // ... and what's left is a `position`
+ if (values.length > 0 && validator.isValidListStylePosition(values[0][1]))
+ position.value = [values[0]];
+
+ return components;
+}
+
+function widthStyleColor(property, compactable, validator) {
+ var descriptor = compactable[property.name];
+ var components = [
+ _wrapDefault(descriptor.components[0], property, compactable),
+ _wrapDefault(descriptor.components[1], property, compactable),
+ _wrapDefault(descriptor.components[2], property, compactable)
+ ];
+ var color, style, width;
+
+ for (var i = 0; i < 3; i++) {
+ var component = components[i];
+
+ if (component.name.indexOf('color') > 0)
+ color = component;
+ else if (component.name.indexOf('style') > 0)
+ style = component;
+ else
+ width = component;
+ }
+
+ if ((property.value.length == 1 && property.value[0][1] == 'inherit') ||
+ (property.value.length == 3 && property.value[0][1] == 'inherit' && property.value[1][1] == 'inherit' && property.value[2][1] == 'inherit')) {
+ color.value = style.value = width.value = [property.value[0]];
+ return components;
+ }
+
+ var values = property.value.slice(0);
+ var match, matches;
+
+ // NOTE: usually users don't follow the required order of parts in this shorthand,
+ // so we'll try to parse it caring as little about order as possible
+
+ if (values.length > 0) {
+ matches = values.filter(_widthFilter(validator));
+ match = matches.length > 1 && (matches[0][1] == 'none' || matches[0][1] == 'auto') ? matches[1] : matches[0];
+ if (match) {
+ width.value = [match];
+ values.splice(values.indexOf(match), 1);
+ }
+ }
+
+ if (values.length > 0) {
+ match = values.filter(_styleFilter(validator))[0];
+ if (match) {
+ style.value = [match];
+ values.splice(values.indexOf(match), 1);
+ }
+ }
+
+ if (values.length > 0) {
+ match = values.filter(_colorFilter(validator))[0];
+ if (match) {
+ color.value = [match];
+ values.splice(values.indexOf(match), 1);
+ }
+ }
+
+ return components;
+}
+
+module.exports = {
+ background: background,
+ border: widthStyleColor,
+ borderRadius: borderRadius,
+ fourValues: fourValues,
+ listStyle: listStyle,
+ multiplex: multiplex,
+ outline: widthStyleColor
+};
diff --git a/node_modules/clean-css/lib/optimizer/level-2/can-override.js b/node_modules/clean-css/lib/optimizer/level-2/can-override.js
new file mode 100644
index 000000000..2617234ca
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/can-override.js
@@ -0,0 +1,180 @@
+var understandable = require('./properties/understandable');
+
+function backgroundPosition(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue('background-position', value2, true)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ } else if (validator.isValidKeywordValue('background-position', value2, true)) {
+ return true;
+ }
+
+ return unit(validator, value1, value2);
+}
+
+function backgroundSize(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue('background-size', value2, true)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ } else if (validator.isValidKeywordValue('background-size', value2, true)) {
+ return true;
+ }
+
+ return unit(validator, value1, value2);
+}
+
+function color(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidColor(value2)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ } else if (!validator.colorOpacity && (validator.isValidRgbaColor(value1) || validator.isValidHslaColor(value1))) {
+ return false;
+ } else if (!validator.colorOpacity && (validator.isValidRgbaColor(value2) || validator.isValidHslaColor(value2))) {
+ return false;
+ } else if (validator.isValidColor(value1) && validator.isValidColor(value2)) {
+ return true;
+ }
+
+ return sameFunctionOrValue(validator, value1, value2);
+}
+
+function components(overrideCheckers) {
+ return function (validator, value1, value2, position) {
+ return overrideCheckers[position](validator, value1, value2);
+ };
+}
+
+function image(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidImage(value2)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ } else if (validator.isValidImage(value2)) {
+ return true;
+ } else if (validator.isValidImage(value1)) {
+ return false;
+ }
+
+ return sameFunctionOrValue(validator, value1, value2);
+}
+
+function keyword(propertyName) {
+ return function(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue(propertyName, value2)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ }
+
+ return validator.isValidKeywordValue(propertyName, value2, false);
+ };
+}
+
+function keywordWithGlobal(propertyName) {
+ return function(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidKeywordValue(propertyName, value2, true)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ }
+
+ return validator.isValidKeywordValue(propertyName, value2, true);
+ };
+}
+
+function sameFunctionOrValue(validator, value1, value2) {
+ return validator.areSameFunction(value1, value2) ?
+ true :
+ value1 === value2;
+}
+
+function textShadow(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidTextShadow(value2)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ }
+
+ return validator.isValidTextShadow(value2);
+}
+
+function unit(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidUnitWithoutFunction(value2)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ } else if (validator.isValidUnitWithoutFunction(value1) && !validator.isValidUnitWithoutFunction(value2)) {
+ return false;
+ } else if (validator.isValidUnitWithoutFunction(value2)) {
+ return true;
+ } else if (validator.isValidUnitWithoutFunction(value1)) {
+ return false;
+ } else if (validator.isValidFunctionWithoutVendorPrefix(value1) && validator.isValidFunctionWithoutVendorPrefix(value2)) {
+ return true;
+ }
+
+ return sameFunctionOrValue(validator, value1, value2);
+}
+
+function unitOrKeywordWithGlobal(propertyName) {
+ var byKeyword = keywordWithGlobal(propertyName);
+
+ return function(validator, value1, value2) {
+ return unit(validator, value1, value2) || byKeyword(validator, value1, value2);
+ };
+}
+
+function zIndex(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isValidZIndex(value2)) {
+ return false;
+ } else if (validator.isValidVariable(value1) && validator.isValidVariable(value2)) {
+ return true;
+ }
+
+ return validator.isValidZIndex(value2);
+}
+
+module.exports = {
+ generic: {
+ color: color,
+ components: components,
+ image: image,
+ unit: unit
+ },
+ property: {
+ backgroundAttachment: keyword('background-attachment'),
+ backgroundClip: keywordWithGlobal('background-clip'),
+ backgroundOrigin: keyword('background-origin'),
+ backgroundPosition: backgroundPosition,
+ backgroundRepeat: keyword('background-repeat'),
+ backgroundSize: backgroundSize,
+ bottom: unitOrKeywordWithGlobal('bottom'),
+ borderCollapse: keyword('border-collapse'),
+ borderStyle: keywordWithGlobal('*-style'),
+ clear: keywordWithGlobal('clear'),
+ cursor: keywordWithGlobal('cursor'),
+ display: keywordWithGlobal('display'),
+ float: keywordWithGlobal('float'),
+ fontStyle: keywordWithGlobal('font-style'),
+ left: unitOrKeywordWithGlobal('left'),
+ fontWeight: keywordWithGlobal('font-weight'),
+ listStyleType: keywordWithGlobal('list-style-type'),
+ listStylePosition: keywordWithGlobal('list-style-position'),
+ outlineStyle: keywordWithGlobal('*-style'),
+ overflow: keywordWithGlobal('overflow'),
+ position: keywordWithGlobal('position'),
+ right: unitOrKeywordWithGlobal('right'),
+ textAlign: keywordWithGlobal('text-align'),
+ textDecoration: keywordWithGlobal('text-decoration'),
+ textOverflow: keywordWithGlobal('text-overflow'),
+ textShadow: textShadow,
+ top: unitOrKeywordWithGlobal('top'),
+ transform: sameFunctionOrValue,
+ verticalAlign: unitOrKeywordWithGlobal('vertical-align'),
+ visibility: keywordWithGlobal('visibility'),
+ whiteSpace: keywordWithGlobal('white-space'),
+ zIndex: zIndex
+ }
+};
diff --git a/node_modules/clean-css/lib/optimizer/level-2/clone.js b/node_modules/clean-css/lib/optimizer/level-2/clone.js
new file mode 100644
index 000000000..3830095e9
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/clone.js
@@ -0,0 +1,33 @@
+var wrapSingle = require('../wrap-for-optimizing').single;
+
+var Token = require('../../tokenizer/token');
+
+function deep(property) {
+ var cloned = shallow(property);
+ for (var i = property.components.length - 1; i >= 0; i--) {
+ var component = shallow(property.components[i]);
+ component.value = property.components[i].value.slice(0);
+ cloned.components.unshift(component);
+ }
+
+ cloned.dirty = true;
+ cloned.value = property.value.slice(0);
+
+ return cloned;
+}
+
+function shallow(property) {
+ var cloned = wrapSingle([
+ Token.PROPERTY,
+ [Token.PROPERTY_NAME, property.name]
+ ]);
+ cloned.important = property.important;
+ cloned.hack = property.hack;
+ cloned.unused = false;
+ return cloned;
+}
+
+module.exports = {
+ deep: deep,
+ shallow: shallow
+};
diff --git a/node_modules/clean-css/lib/optimizer/level-2/compactable.js b/node_modules/clean-css/lib/optimizer/level-2/compactable.js
new file mode 100644
index 000000000..9cf334d44
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/compactable.js
@@ -0,0 +1,787 @@
+// Contains the interpretation of CSS properties, as used by the property optimizer
+
+var breakUp = require('./break-up');
+var canOverride = require('./can-override');
+var restore = require('./restore');
+
+var override = require('../../utils/override');
+
+// Properties to process
+// Extend this object in order to add support for more properties in the optimizer.
+//
+// Each key in this object represents a CSS property and should be an object.
+// Such an object contains properties that describe how the represented CSS property should be handled.
+// Possible options:
+//
+// * components: array (Only specify for shorthand properties.)
+// Contains the names of the granular properties this shorthand compacts.
+//
+// * canOverride: function
+// Returns whether two tokens of this property can be merged with each other.
+// This property has no meaning for shorthands.
+//
+// * defaultValue: string
+// Specifies the default value of the property according to the CSS standard.
+// For shorthand, this is used when every component is set to its default value, therefore it should be the shortest possible default value of all the components.
+//
+// * shortestValue: string
+// Specifies the shortest possible value the property can possibly have.
+// (Falls back to defaultValue if unspecified.)
+//
+// * breakUp: function (Only specify for shorthand properties.)
+// Breaks the shorthand up to its components.
+//
+// * restore: function (Only specify for shorthand properties.)
+// Puts the shorthand together from its components.
+//
+var compactable = {
+ 'background': {
+ canOverride: canOverride.generic.components([
+ canOverride.generic.image,
+ canOverride.property.backgroundPosition,
+ canOverride.property.backgroundSize,
+ canOverride.property.backgroundRepeat,
+ canOverride.property.backgroundAttachment,
+ canOverride.property.backgroundOrigin,
+ canOverride.property.backgroundClip,
+ canOverride.generic.color
+ ]),
+ components: [
+ 'background-image',
+ 'background-position',
+ 'background-size',
+ 'background-repeat',
+ 'background-attachment',
+ 'background-origin',
+ 'background-clip',
+ 'background-color'
+ ],
+ breakUp: breakUp.multiplex(breakUp.background),
+ defaultValue: '0 0',
+ restore: restore.multiplex(restore.background),
+ shortestValue: '0',
+ shorthand: true
+ },
+ 'background-attachment': {
+ canOverride: canOverride.property.backgroundAttachment,
+ componentOf: [
+ 'background'
+ ],
+ defaultValue: 'scroll'
+ },
+ 'background-clip': {
+ canOverride: canOverride.property.backgroundClip,
+ componentOf: [
+ 'background'
+ ],
+ defaultValue: 'border-box',
+ shortestValue: 'border-box'
+ },
+ 'background-color': {
+ canOverride: canOverride.generic.color,
+ componentOf: [
+ 'background'
+ ],
+ defaultValue: 'transparent',
+ multiplexLastOnly: true,
+ nonMergeableValue: 'none',
+ shortestValue: 'red'
+ },
+ 'background-image': {
+ canOverride: canOverride.generic.image,
+ componentOf: [
+ 'background'
+ ],
+ defaultValue: 'none'
+ },
+ 'background-origin': {
+ canOverride: canOverride.property.backgroundOrigin,
+ componentOf: [
+ 'background'
+ ],
+ defaultValue: 'padding-box',
+ shortestValue: 'border-box'
+ },
+ 'background-position': {
+ canOverride: canOverride.property.backgroundPosition,
+ componentOf: [
+ 'background'
+ ],
+ defaultValue: ['0', '0'],
+ doubleValues: true,
+ shortestValue: '0'
+ },
+ 'background-repeat': {
+ canOverride: canOverride.property.backgroundRepeat,
+ componentOf: [
+ 'background'
+ ],
+ defaultValue: ['repeat'],
+ doubleValues: true
+ },
+ 'background-size': {
+ canOverride: canOverride.property.backgroundSize,
+ componentOf: [
+ 'background'
+ ],
+ defaultValue: ['auto'],
+ doubleValues: true,
+ shortestValue: '0 0'
+ },
+ 'bottom': {
+ canOverride: canOverride.property.bottom,
+ defaultValue: 'auto'
+ },
+ 'border': {
+ breakUp: breakUp.border,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.property.borderStyle,
+ canOverride.generic.color
+ ]),
+ components: [
+ 'border-width',
+ 'border-style',
+ 'border-color'
+ ],
+ defaultValue: 'none',
+ overridesShorthands: [
+ 'border-bottom',
+ 'border-left',
+ 'border-right',
+ 'border-top'
+ ],
+ restore: restore.withoutDefaults,
+ shorthand: true,
+ shorthandComponents: true
+ },
+ 'border-bottom': {
+ breakUp: breakUp.border,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.property.borderStyle,
+ canOverride.generic.color
+ ]),
+ components: [
+ 'border-bottom-width',
+ 'border-bottom-style',
+ 'border-bottom-color'
+ ],
+ defaultValue: 'none',
+ restore: restore.withoutDefaults,
+ shorthand: true
+ },
+ 'border-bottom-color': {
+ canOverride: canOverride.generic.color,
+ componentOf: [
+ 'border-bottom',
+ 'border-color'
+ ],
+ defaultValue: 'none'
+ },
+ 'border-bottom-left-radius': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'border-radius'
+ ],
+ defaultValue: '0',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-'
+ ]
+ },
+ 'border-bottom-right-radius': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'border-radius'
+ ],
+ defaultValue: '0',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-'
+ ]
+ },
+ 'border-bottom-style': {
+ canOverride: canOverride.property.borderStyle,
+ componentOf: [
+ 'border-bottom',
+ 'border-style'
+ ],
+ defaultValue: 'none'
+ },
+ 'border-bottom-width': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'border-bottom',
+ 'border-width'
+ ],
+ defaultValue: 'medium',
+ shortestValue: '0'
+ },
+ 'border-collapse': {
+ canOverride: canOverride.property.borderCollapse,
+ defaultValue: 'separate'
+ },
+ 'border-color': {
+ breakUp: breakUp.fourValues,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.color,
+ canOverride.generic.color,
+ canOverride.generic.color,
+ canOverride.generic.color
+ ]),
+ componentOf: ['border'],
+ components: [
+ 'border-top-color',
+ 'border-right-color',
+ 'border-bottom-color',
+ 'border-left-color'
+ ],
+ defaultValue: 'none',
+ restore: restore.fourValues,
+ shortestValue: 'red',
+ shorthand: true
+ },
+ 'border-left': {
+ breakUp: breakUp.border,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.property.borderStyle,
+ canOverride.generic.color
+ ]),
+ components: [
+ 'border-left-width',
+ 'border-left-style',
+ 'border-left-color'
+ ],
+ defaultValue: 'none',
+ restore: restore.withoutDefaults,
+ shorthand: true
+ },
+ 'border-left-color': {
+ canOverride: canOverride.generic.color,
+ componentOf: [
+ 'border-color',
+ 'border-left'
+ ],
+ defaultValue: 'none'
+ },
+ 'border-left-style': {
+ canOverride: canOverride.property.borderStyle,
+ componentOf: [
+ 'border-left',
+ 'border-style'
+ ],
+ defaultValue: 'none'
+ },
+ 'border-left-width': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'border-left',
+ 'border-width'
+ ],
+ defaultValue: 'medium',
+ shortestValue: '0'
+ },
+ 'border-radius': {
+ breakUp: breakUp.borderRadius,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.generic.unit,
+ canOverride.generic.unit,
+ canOverride.generic.unit
+ ]),
+ components: [
+ 'border-top-left-radius',
+ 'border-top-right-radius',
+ 'border-bottom-right-radius',
+ 'border-bottom-left-radius'
+ ],
+ defaultValue: '0',
+ restore: restore.borderRadius,
+ shorthand: true,
+ vendorPrefixes: [
+ '-moz-',
+ '-o-'
+ ]
+ },
+ 'border-right': {
+ breakUp: breakUp.border,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.property.borderStyle,
+ canOverride.generic.color
+ ]),
+ components: [
+ 'border-right-width',
+ 'border-right-style',
+ 'border-right-color'
+ ],
+ defaultValue: 'none',
+ restore: restore.withoutDefaults,
+ shorthand: true
+ },
+ 'border-right-color': {
+ canOverride: canOverride.generic.color,
+ componentOf: [
+ 'border-color',
+ 'border-right'
+ ],
+ defaultValue: 'none'
+ },
+ 'border-right-style': {
+ canOverride: canOverride.property.borderStyle,
+ componentOf: [
+ 'border-right',
+ 'border-style'
+ ],
+ defaultValue: 'none'
+ },
+ 'border-right-width': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'border-right',
+ 'border-width'
+ ],
+ defaultValue: 'medium',
+ shortestValue: '0'
+ },
+ 'border-style': {
+ breakUp: breakUp.fourValues,
+ canOverride: canOverride.generic.components([
+ canOverride.property.borderStyle,
+ canOverride.property.borderStyle,
+ canOverride.property.borderStyle,
+ canOverride.property.borderStyle
+ ]),
+ componentOf: [
+ 'border'
+ ],
+ components: [
+ 'border-top-style',
+ 'border-right-style',
+ 'border-bottom-style',
+ 'border-left-style'
+ ],
+ defaultValue: 'none',
+ restore: restore.fourValues,
+ shorthand: true
+ },
+ 'border-top': {
+ breakUp: breakUp.border,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.property.borderStyle,
+ canOverride.generic.color
+ ]),
+ components: [
+ 'border-top-width',
+ 'border-top-style',
+ 'border-top-color'
+ ],
+ defaultValue: 'none',
+ restore: restore.withoutDefaults,
+ shorthand: true
+ },
+ 'border-top-color': {
+ canOverride: canOverride.generic.color,
+ componentOf: [
+ 'border-color',
+ 'border-top'
+ ],
+ defaultValue: 'none'
+ },
+ 'border-top-left-radius': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'border-radius'
+ ],
+ defaultValue: '0',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-'
+ ]
+ },
+ 'border-top-right-radius': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'border-radius'
+ ],
+ defaultValue: '0',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-'
+ ]
+ },
+ 'border-top-style': {
+ canOverride: canOverride.property.borderStyle,
+ componentOf: [
+ 'border-style',
+ 'border-top'
+ ],
+ defaultValue: 'none'
+ },
+ 'border-top-width': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'border-top',
+ 'border-width'
+ ],
+ defaultValue: 'medium',
+ shortestValue: '0'
+ },
+ 'border-width': {
+ breakUp: breakUp.fourValues,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.generic.unit,
+ canOverride.generic.unit,
+ canOverride.generic.unit
+ ]),
+ components: [
+ 'border-top-width',
+ 'border-right-width',
+ 'border-bottom-width',
+ 'border-left-width'
+ ],
+ defaultValue: 'medium',
+ restore: restore.fourValues,
+ shortestValue: '0',
+ shorthand: true
+ },
+ 'clear': {
+ canOverride: canOverride.property.clear,
+ defaultValue: 'none'
+ },
+ 'color': {
+ canOverride: canOverride.generic.color,
+ defaultValue: 'transparent',
+ shortestValue: 'red'
+ },
+ 'cursor': {
+ canOverride: canOverride.property.cursor,
+ defaultValue: 'auto'
+ },
+ 'display': {
+ canOverride: canOverride.property.display,
+ },
+ 'float': {
+ canOverride: canOverride.property.float,
+ defaultValue: 'none'
+ },
+ 'font-size': {
+ canOverride: canOverride.generic.unit,
+ defaultValue: 'medium',
+ shortestValue: '0'
+ },
+ 'font-style': {
+ canOverride: canOverride.property.fontStyle,
+ defaultValue: 'normal'
+ },
+ 'font-weight': {
+ canOverride: canOverride.property.fontWeight,
+ defaultValue: '400',
+ shortestValue: '400'
+ },
+ 'height': {
+ canOverride: canOverride.generic.unit,
+ defaultValue: 'auto',
+ shortestValue: '0'
+ },
+ 'left': {
+ canOverride: canOverride.property.left,
+ defaultValue: 'auto'
+ },
+ 'line-height': {
+ canOverride: canOverride.generic.unit,
+ defaultValue: 'normal',
+ shortestValue: '0'
+ },
+ 'list-style': {
+ canOverride: canOverride.generic.components([
+ canOverride.property.listStyleType,
+ canOverride.property.listStylePosition,
+ canOverride.property.listStyleImage
+ ]),
+ components: [
+ 'list-style-type',
+ 'list-style-position',
+ 'list-style-image'
+ ],
+ breakUp: breakUp.listStyle,
+ restore: restore.withoutDefaults,
+ defaultValue: 'outside', // can't use 'disc' because that'd override default 'decimal' for <ol>
+ shortestValue: 'none',
+ shorthand: true
+ },
+ 'list-style-image' : {
+ canOverride: canOverride.generic.image,
+ componentOf: [
+ 'list-style'
+ ],
+ defaultValue: 'none'
+ },
+ 'list-style-position' : {
+ canOverride: canOverride.property.listStylePosition,
+ componentOf: [
+ 'list-style'
+ ],
+ defaultValue: 'outside',
+ shortestValue: 'inside'
+ },
+ 'list-style-type' : {
+ canOverride: canOverride.property.listStyleType,
+ componentOf: [
+ 'list-style'
+ ],
+ // NOTE: we can't tell the real default value here, it's 'disc' for <ul> and 'decimal' for <ol>
+ // this is a hack, but it doesn't matter because this value will be either overridden or
+ // it will disappear at the final step anyway
+ defaultValue: 'decimal|disc',
+ shortestValue: 'none'
+ },
+ 'margin': {
+ breakUp: breakUp.fourValues,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.generic.unit,
+ canOverride.generic.unit,
+ canOverride.generic.unit
+ ]),
+ components: [
+ 'margin-top',
+ 'margin-right',
+ 'margin-bottom',
+ 'margin-left'
+ ],
+ defaultValue: '0',
+ restore: restore.fourValues,
+ shorthand: true
+ },
+ 'margin-bottom': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'margin'
+ ],
+ defaultValue: '0'
+ },
+ 'margin-left': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'margin'
+ ],
+ defaultValue: '0'
+ },
+ 'margin-right': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'margin'
+ ],
+ defaultValue: '0'
+ },
+ 'margin-top': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'margin'
+ ],
+ defaultValue: '0'
+ },
+ 'outline': {
+ canOverride: canOverride.generic.components([
+ canOverride.generic.color,
+ canOverride.property.outlineStyle,
+ canOverride.generic.unit
+ ]),
+ components: [
+ 'outline-color',
+ 'outline-style',
+ 'outline-width'
+ ],
+ breakUp: breakUp.outline,
+ restore: restore.withoutDefaults,
+ defaultValue: '0',
+ shorthand: true
+ },
+ 'outline-color': {
+ canOverride: canOverride.generic.color,
+ componentOf: [
+ 'outline'
+ ],
+ defaultValue: 'invert',
+ shortestValue: 'red'
+ },
+ 'outline-style': {
+ canOverride: canOverride.property.outlineStyle,
+ componentOf: [
+ 'outline'
+ ],
+ defaultValue: 'none'
+ },
+ 'outline-width': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'outline'
+ ],
+ defaultValue: 'medium',
+ shortestValue: '0'
+ },
+ 'overflow': {
+ canOverride: canOverride.property.overflow,
+ defaultValue: 'visible'
+ },
+ 'overflow-x': {
+ canOverride: canOverride.property.overflow,
+ defaultValue: 'visible'
+ },
+ 'overflow-y': {
+ canOverride: canOverride.property.overflow,
+ defaultValue: 'visible'
+ },
+ 'padding': {
+ breakUp: breakUp.fourValues,
+ canOverride: canOverride.generic.components([
+ canOverride.generic.unit,
+ canOverride.generic.unit,
+ canOverride.generic.unit,
+ canOverride.generic.unit
+ ]),
+ components: [
+ 'padding-top',
+ 'padding-right',
+ 'padding-bottom',
+ 'padding-left'
+ ],
+ defaultValue: '0',
+ restore: restore.fourValues,
+ shorthand: true
+ },
+ 'padding-bottom': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'padding'
+ ],
+ defaultValue: '0'
+ },
+ 'padding-left': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'padding'
+ ],
+ defaultValue: '0'
+ },
+ 'padding-right': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'padding'
+ ],
+ defaultValue: '0'
+ },
+ 'padding-top': {
+ canOverride: canOverride.generic.unit,
+ componentOf: [
+ 'padding'
+ ],
+ defaultValue: '0'
+ },
+ 'position': {
+ canOverride: canOverride.property.position,
+ defaultValue: 'static'
+ },
+ 'right': {
+ canOverride: canOverride.property.right,
+ defaultValue: 'auto'
+ },
+ 'text-align': {
+ canOverride: canOverride.property.textAlign,
+ // NOTE: we can't tell the real default value here, as it depends on default text direction
+ // this is a hack, but it doesn't matter because this value will be either overridden or
+ // it will disappear anyway
+ defaultValue: 'left|right'
+ },
+ 'text-decoration': {
+ canOverride: canOverride.property.textDecoration,
+ defaultValue: 'none'
+ },
+ 'text-overflow': {
+ canOverride: canOverride.property.textOverflow,
+ defaultValue: 'none'
+ },
+ 'text-shadow': {
+ canOverride: canOverride.property.textShadow,
+ defaultValue: 'none'
+ },
+ 'top': {
+ canOverride: canOverride.property.top,
+ defaultValue: 'auto'
+ },
+ 'transform': {
+ canOverride: canOverride.property.transform,
+ vendorPrefixes: [
+ '-moz-',
+ '-ms-',
+ '-webkit-'
+ ]
+ },
+ 'vertical-align': {
+ canOverride: canOverride.property.verticalAlign,
+ defaultValue: 'baseline'
+ },
+ 'visibility': {
+ canOverride: canOverride.property.visibility,
+ defaultValue: 'visible'
+ },
+ 'white-space': {
+ canOverride: canOverride.property.whiteSpace,
+ defaultValue: 'normal'
+ },
+ 'width': {
+ canOverride: canOverride.generic.unit,
+ defaultValue: 'auto',
+ shortestValue: '0'
+ },
+ 'z-index': {
+ canOverride: canOverride.property.zIndex,
+ defaultValue: 'auto'
+ }
+};
+
+function cloneDescriptor(propertyName, prefix) {
+ var clonedDescriptor = override(compactable[propertyName], {});
+
+ if ('componentOf' in clonedDescriptor) {
+ clonedDescriptor.componentOf = clonedDescriptor.componentOf.map(function (shorthandName) {
+ return prefix + shorthandName;
+ });
+ }
+
+ if ('components' in clonedDescriptor) {
+ clonedDescriptor.components = clonedDescriptor.components.map(function (longhandName) {
+ return prefix + longhandName;
+ });
+ }
+
+ return clonedDescriptor;
+}
+
+// generate vendor-prefixed properties
+var vendorPrefixedCompactable = {};
+
+for (var propertyName in compactable) {
+ var descriptor = compactable[propertyName];
+
+ if (!('vendorPrefixes' in descriptor)) {
+ continue;
+ }
+
+ for (var i = 0; i < descriptor.vendorPrefixes.length; i++) {
+ var prefix = descriptor.vendorPrefixes[i];
+ var clonedDescriptor = cloneDescriptor(propertyName, prefix);
+ delete clonedDescriptor.vendorPrefixes;
+
+ vendorPrefixedCompactable[prefix + propertyName] = clonedDescriptor;
+ }
+
+ delete descriptor.vendorPrefixes;
+}
+
+module.exports = override(compactable, vendorPrefixedCompactable);
diff --git a/node_modules/clean-css/lib/optimizer/level-2/extract-properties.js b/node_modules/clean-css/lib/optimizer/level-2/extract-properties.js
new file mode 100644
index 000000000..8b9b1c2e0
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/extract-properties.js
@@ -0,0 +1,73 @@
+// This extractor is used in level 2 optimizations
+// IMPORTANT: Mind Token class and this code is not related!
+// Properties will be tokenized in one step, see #429
+
+var Token = require('../../tokenizer/token');
+var serializeRules = require('../../writer/one-time').rules;
+var serializeValue = require('../../writer/one-time').value;
+
+function extractProperties(token) {
+ var properties = [];
+ var inSpecificSelector;
+ var property;
+ var name;
+ var value;
+ var i, l;
+
+ if (token[0] == Token.RULE) {
+ inSpecificSelector = !/[\.\+>~]/.test(serializeRules(token[1]));
+
+ for (i = 0, l = token[2].length; i < l; i++) {
+ property = token[2][i];
+
+ if (property[0] != Token.PROPERTY)
+ continue;
+
+ name = property[1][1];
+ if (name.length === 0)
+ continue;
+
+ if (name.indexOf('--') === 0)
+ continue;
+
+ value = serializeValue(property, i);
+
+ properties.push([
+ name,
+ value,
+ findNameRoot(name),
+ token[2][i],
+ name + ':' + value,
+ token[1],
+ inSpecificSelector
+ ]);
+ }
+ } else if (token[0] == Token.NESTED_BLOCK) {
+ for (i = 0, l = token[2].length; i < l; i++) {
+ properties = properties.concat(extractProperties(token[2][i]));
+ }
+ }
+
+ return properties;
+}
+
+function findNameRoot(name) {
+ if (name == 'list-style')
+ return name;
+ if (name.indexOf('-radius') > 0)
+ return 'border-radius';
+ if (name == 'border-collapse' || name == 'border-spacing' || name == 'border-image')
+ return name;
+ if (name.indexOf('border-') === 0 && /^border\-\w+\-\w+$/.test(name))
+ return name.match(/border\-\w+/)[0];
+ if (name.indexOf('border-') === 0 && /^border\-\w+$/.test(name))
+ return 'border';
+ if (name.indexOf('text-') === 0)
+ return name;
+ if (name == '-chrome-')
+ return name;
+
+ return name.replace(/^\-\w+\-/, '').match(/([a-zA-Z]+)/)[0].toLowerCase();
+}
+
+module.exports = extractProperties;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/invalid-property-error.js b/node_modules/clean-css/lib/optimizer/level-2/invalid-property-error.js
new file mode 100644
index 000000000..86d5b5f9b
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/invalid-property-error.js
@@ -0,0 +1,10 @@
+function InvalidPropertyError(message) {
+ this.name = 'InvalidPropertyError';
+ this.message = message;
+ this.stack = (new Error()).stack;
+}
+
+InvalidPropertyError.prototype = Object.create(Error.prototype);
+InvalidPropertyError.prototype.constructor = InvalidPropertyError;
+
+module.exports = InvalidPropertyError;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js b/node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js
new file mode 100644
index 000000000..4a91a8331
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js
@@ -0,0 +1,236 @@
+var Marker = require('../../tokenizer/marker');
+var split = require('../../utils/split');
+
+var DEEP_SELECTOR_PATTERN = /\/deep\//;
+var DOUBLE_COLON_PATTERN = /^::/;
+var NOT_PSEUDO = ':not';
+var PSEUDO_CLASSES_WITH_ARGUMENTS = [
+ ':dir',
+ ':lang',
+ ':not',
+ ':nth-child',
+ ':nth-last-child',
+ ':nth-last-of-type',
+ ':nth-of-type'
+];
+var RELATION_PATTERN = /[>\+~]/;
+
+var Level = {
+ DOUBLE_QUOTE: 'double-quote',
+ SINGLE_QUOTE: 'single-quote',
+ ROOT: 'root'
+};
+
+function isMergeable(selector, mergeablePseudoClasses, mergeablePseudoElements) {
+ var singleSelectors = split(selector, Marker.COMMA);
+ var singleSelector;
+ var i, l;
+
+ for (i = 0, l = singleSelectors.length; i < l; i++) {
+ singleSelector = singleSelectors[i];
+
+ if (singleSelector.length === 0 ||
+ isDeepSelector(singleSelector) ||
+ (singleSelector.indexOf(Marker.COLON) > -1 && !areMergeable(singleSelector, extractPseudoFrom(singleSelector), mergeablePseudoClasses, mergeablePseudoElements))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function isDeepSelector(selector) {
+ return DEEP_SELECTOR_PATTERN.test(selector);
+}
+
+function extractPseudoFrom(selector) {
+ var list = [];
+ var character;
+ var buffer = [];
+ var level = Level.ROOT;
+ var roundBracketLevel = 0;
+ var isQuoted;
+ var isEscaped;
+ var isPseudo = false;
+ var isRelation;
+ var wasColon = false;
+ var index;
+ var len;
+
+ for (index = 0, len = selector.length; index < len; index++) {
+ character = selector[index];
+
+ isRelation = !isEscaped && RELATION_PATTERN.test(character);
+ isQuoted = level == Level.DOUBLE_QUOTE || level == Level.SINGLE_QUOTE;
+
+ if (isEscaped) {
+ buffer.push(character);
+ } else if (character == Marker.DOUBLE_QUOTE && level == Level.ROOT) {
+ buffer.push(character);
+ level = Level.DOUBLE_QUOTE;
+ } else if (character == Marker.DOUBLE_QUOTE && level == Level.DOUBLE_QUOTE) {
+ buffer.push(character);
+ level = Level.ROOT;
+ } else if (character == Marker.SINGLE_QUOTE && level == Level.ROOT) {
+ buffer.push(character);
+ level = Level.SINGLE_QUOTE;
+ } else if (character == Marker.SINGLE_QUOTE && level == Level.SINGLE_QUOTE) {
+ buffer.push(character);
+ level = Level.ROOT;
+ } else if (isQuoted) {
+ buffer.push(character);
+ } else if (character == Marker.OPEN_ROUND_BRACKET) {
+ buffer.push(character);
+ roundBracketLevel++;
+ } else if (character == Marker.CLOSE_ROUND_BRACKET && roundBracketLevel == 1 && isPseudo) {
+ buffer.push(character);
+ list.push(buffer.join(''));
+ roundBracketLevel--;
+ buffer = [];
+ isPseudo = false;
+ } else if (character == Marker.CLOSE_ROUND_BRACKET) {
+ buffer.push(character);
+ roundBracketLevel--;
+ } else if (character == Marker.COLON && roundBracketLevel === 0 && isPseudo && !wasColon) {
+ list.push(buffer.join(''));
+ buffer = [];
+ buffer.push(character);
+ } else if (character == Marker.COLON && roundBracketLevel === 0 && !wasColon) {
+ buffer = [];
+ buffer.push(character);
+ isPseudo = true;
+ } else if (character == Marker.SPACE && roundBracketLevel === 0 && isPseudo) {
+ list.push(buffer.join(''));
+ buffer = [];
+ isPseudo = false;
+ } else if (isRelation && roundBracketLevel === 0 && isPseudo) {
+ list.push(buffer.join(''));
+ buffer = [];
+ isPseudo = false;
+ } else {
+ buffer.push(character);
+ }
+
+ isEscaped = character == Marker.BACK_SLASH;
+ wasColon = character == Marker.COLON;
+ }
+
+ if (buffer.length > 0 && isPseudo) {
+ list.push(buffer.join(''));
+ }
+
+ return list;
+}
+
+function areMergeable(selector, matches, mergeablePseudoClasses, mergeablePseudoElements) {
+ return areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements) &&
+ needArguments(matches) &&
+ (matches.length < 2 || !someIncorrectlyChained(selector, matches)) &&
+ (matches.length < 2 || !someMixed(matches));
+}
+
+function areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements) {
+ var match;
+ var name;
+ var i, l;
+
+ for (i = 0, l = matches.length; i < l; i++) {
+ match = matches[i];
+ name = match.indexOf(Marker.OPEN_ROUND_BRACKET) > -1 ?
+ match.substring(0, match.indexOf(Marker.OPEN_ROUND_BRACKET)) :
+ match;
+
+ if (mergeablePseudoClasses.indexOf(name) === -1 && mergeablePseudoElements.indexOf(name) === -1) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function needArguments(matches) {
+ var match;
+ var name;
+ var bracketOpensAt;
+ var hasArguments;
+ var i, l;
+
+ for (i = 0, l = matches.length; i < l; i++) {
+ match = matches[i];
+
+ bracketOpensAt = match.indexOf(Marker.OPEN_ROUND_BRACKET);
+ hasArguments = bracketOpensAt > -1;
+ name = hasArguments ?
+ match.substring(0, bracketOpensAt) :
+ match;
+
+ if (hasArguments && PSEUDO_CLASSES_WITH_ARGUMENTS.indexOf(name) == -1) {
+ return false;
+ }
+
+ if (!hasArguments && PSEUDO_CLASSES_WITH_ARGUMENTS.indexOf(name) > -1) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function someIncorrectlyChained(selector, matches) {
+ var positionInSelector = 0;
+ var match;
+ var matchAt;
+ var nextMatch;
+ var nextMatchAt;
+ var name;
+ var nextName;
+ var areChained;
+ var i, l;
+
+ for (i = 0, l = matches.length; i < l; i++) {
+ match = matches[i];
+ nextMatch = matches[i + 1];
+
+ if (!nextMatch) {
+ break;
+ }
+
+ matchAt = selector.indexOf(match, positionInSelector);
+ nextMatchAt = selector.indexOf(match, matchAt + 1);
+ positionInSelector = nextMatchAt;
+ areChained = matchAt + match.length == nextMatchAt;
+
+ if (areChained) {
+ name = match.indexOf(Marker.OPEN_ROUND_BRACKET) > -1 ?
+ match.substring(0, match.indexOf(Marker.OPEN_ROUND_BRACKET)) :
+ match;
+ nextName = nextMatch.indexOf(Marker.OPEN_ROUND_BRACKET) > -1 ?
+ nextMatch.substring(0, nextMatch.indexOf(Marker.OPEN_ROUND_BRACKET)) :
+ nextMatch;
+
+ if (name != NOT_PSEUDO || nextName != NOT_PSEUDO) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function someMixed(matches) {
+ var firstIsPseudoElement = DOUBLE_COLON_PATTERN.test(matches[0]);
+ var match;
+ var i, l;
+
+ for (i = 0, l = matches.length; i < l; i++) {
+ match = matches[i];
+
+ if (DOUBLE_COLON_PATTERN.test(match) != firstIsPseudoElement) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+module.exports = isMergeable;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js b/node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js
new file mode 100644
index 000000000..7c0537501
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js
@@ -0,0 +1,49 @@
+var isMergeable = require('./is-mergeable');
+
+var optimizeProperties = require('./properties/optimize');
+
+var sortSelectors = require('../level-1/sort-selectors');
+var tidyRules = require('../level-1/tidy-rules');
+
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
+var serializeBody = require('../../writer/one-time').body;
+var serializeRules = require('../../writer/one-time').rules;
+
+var Token = require('../../tokenizer/token');
+
+function mergeAdjacent(tokens, context) {
+ var lastToken = [null, [], []];
+ var options = context.options;
+ var adjacentSpace = options.compatibility.selectors.adjacentSpace;
+ var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod;
+ var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
+ var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
+ var mergeLimit = 8191;
+
+ for (var i = 0, l = tokens.length; i < l; i++) {
+ var token = tokens[i];
+
+ if (token[0] != Token.RULE) {
+ lastToken = [null, [], []];
+ continue;
+ }
+
+ if (lastToken[0] == Token.RULE && serializeRules(token[1]) == serializeRules(lastToken[1])) {
+ Array.prototype.push.apply(lastToken[2], token[2]);
+ optimizeProperties(lastToken[2], true, true, context);
+ token[2] = [];
+ } else if (lastToken[0] == Token.RULE && serializeBody(token[2]) == serializeBody(lastToken[2]) &&
+ isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements) &&
+ isMergeable(serializeRules(lastToken[1]), mergeablePseudoClasses, mergeablePseudoElements) &&
+ lastToken[1].length < mergeLimit) {
+ lastToken[1] = tidyRules(lastToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings);
+ lastToken[1] = lastToken.length > 1 ? sortSelectors(lastToken[1], selectorsSortingMethod) : lastToken[1];
+ token[2] = [];
+ } else {
+ lastToken = token;
+ }
+ }
+}
+
+module.exports = mergeAdjacent;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/merge-media-queries.js b/node_modules/clean-css/lib/optimizer/level-2/merge-media-queries.js
new file mode 100644
index 000000000..c3c60dc24
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/merge-media-queries.js
@@ -0,0 +1,103 @@
+var canReorder = require('./reorderable').canReorder;
+var canReorderSingle = require('./reorderable').canReorderSingle;
+var extractProperties = require('./extract-properties');
+var rulesOverlap = require('./rules-overlap');
+
+var serializeRules = require('../../writer/one-time').rules;
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+var Token = require('../../tokenizer/token');
+
+function mergeMediaQueries(tokens, context) {
+ var mergeSemantically = context.options.level[OptimizationLevel.Two].mergeSemantically;
+ var specificityCache = context.cache.specificity;
+ var candidates = {};
+ var reduced = [];
+
+ for (var i = tokens.length - 1; i >= 0; i--) {
+ var token = tokens[i];
+ if (token[0] != Token.NESTED_BLOCK) {
+ continue;
+ }
+
+ var key = serializeRules(token[1]);
+ var candidate = candidates[key];
+ if (!candidate) {
+ candidate = [];
+ candidates[key] = candidate;
+ }
+
+ candidate.push(i);
+ }
+
+ for (var name in candidates) {
+ var positions = candidates[name];
+
+ positionLoop:
+ for (var j = positions.length - 1; j > 0; j--) {
+ var positionOne = positions[j];
+ var tokenOne = tokens[positionOne];
+ var positionTwo = positions[j - 1];
+ var tokenTwo = tokens[positionTwo];
+
+ directionLoop:
+ for (var direction = 1; direction >= -1; direction -= 2) {
+ var topToBottom = direction == 1;
+ var from = topToBottom ? positionOne + 1 : positionTwo - 1;
+ var to = topToBottom ? positionTwo : positionOne;
+ var delta = topToBottom ? 1 : -1;
+ var source = topToBottom ? tokenOne : tokenTwo;
+ var target = topToBottom ? tokenTwo : tokenOne;
+ var movedProperties = extractProperties(source);
+
+ while (from != to) {
+ var traversedProperties = extractProperties(tokens[from]);
+ from += delta;
+
+ if (mergeSemantically && allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties, specificityCache)) {
+ continue;
+ }
+
+ if (!canReorder(movedProperties, traversedProperties, specificityCache))
+ continue directionLoop;
+ }
+
+ target[2] = topToBottom ?
+ source[2].concat(target[2]) :
+ target[2].concat(source[2]);
+ source[2] = [];
+
+ reduced.push(target);
+ continue positionLoop;
+ }
+ }
+ }
+
+ return reduced;
+}
+
+function allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties, specificityCache) {
+ var movedProperty;
+ var movedRule;
+ var traversedProperty;
+ var traversedRule;
+ var i, l;
+ var j, m;
+
+ for (i = 0, l = movedProperties.length; i < l; i++) {
+ movedProperty = movedProperties[i];
+ movedRule = movedProperty[5];
+
+ for (j = 0, m = traversedProperties.length; j < m; j++) {
+ traversedProperty = traversedProperties[j];
+ traversedRule = traversedProperty[5];
+
+ if (rulesOverlap(movedRule, traversedRule, true) && !canReorderSingle(movedProperty, traversedProperty, specificityCache)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+module.exports = mergeMediaQueries;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js b/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js
new file mode 100644
index 000000000..bdcf53ec0
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js
@@ -0,0 +1,79 @@
+var isMergeable = require('./is-mergeable');
+
+var sortSelectors = require('../level-1/sort-selectors');
+var tidyRules = require('../level-1/tidy-rules');
+
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
+var serializeBody = require('../../writer/one-time').body;
+var serializeRules = require('../../writer/one-time').rules;
+
+var Token = require('../../tokenizer/token');
+
+function unsafeSelector(value) {
+ return /\.|\*| :/.test(value);
+}
+
+function isBemElement(token) {
+ var asString = serializeRules(token[1]);
+ return asString.indexOf('__') > -1 || asString.indexOf('--') > -1;
+}
+
+function withoutModifier(selector) {
+ return selector.replace(/--[^ ,>\+~:]+/g, '');
+}
+
+function removeAnyUnsafeElements(left, candidates) {
+ var leftSelector = withoutModifier(serializeRules(left[1]));
+
+ for (var body in candidates) {
+ var right = candidates[body];
+ var rightSelector = withoutModifier(serializeRules(right[1]));
+
+ if (rightSelector.indexOf(leftSelector) > -1 || leftSelector.indexOf(rightSelector) > -1)
+ delete candidates[body];
+ }
+}
+
+function mergeNonAdjacentByBody(tokens, context) {
+ var options = context.options;
+ var mergeSemantically = options.level[OptimizationLevel.Two].mergeSemantically;
+ var adjacentSpace = options.compatibility.selectors.adjacentSpace;
+ var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod;
+ var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
+ var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
+ var candidates = {};
+
+ for (var i = tokens.length - 1; i >= 0; i--) {
+ var token = tokens[i];
+ if (token[0] != Token.RULE)
+ continue;
+
+ if (token[2].length > 0 && (!mergeSemantically && unsafeSelector(serializeRules(token[1]))))
+ candidates = {};
+
+ if (token[2].length > 0 && mergeSemantically && isBemElement(token))
+ removeAnyUnsafeElements(token, candidates);
+
+ var candidateBody = serializeBody(token[2]);
+ var oldToken = candidates[candidateBody];
+ if (oldToken &&
+ isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements) &&
+ isMergeable(serializeRules(oldToken[1]), mergeablePseudoClasses, mergeablePseudoElements)) {
+
+ if (token[2].length > 0) {
+ token[1] = tidyRules(oldToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings);
+ token[1] = token[1].length > 1 ? sortSelectors(token[1], selectorsSortingMethod) : token[1];
+ } else {
+ token[1] = oldToken[1].concat(token[1]);
+ }
+
+ oldToken[2] = [];
+ candidates[candidateBody] = null;
+ }
+
+ candidates[serializeBody(token[2])] = token;
+ }
+}
+
+module.exports = mergeNonAdjacentByBody;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-selector.js b/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-selector.js
new file mode 100644
index 000000000..5e23064eb
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-selector.js
@@ -0,0 +1,78 @@
+var canReorder = require('./reorderable').canReorder;
+var extractProperties = require('./extract-properties');
+
+var optimizeProperties = require('./properties/optimize');
+
+var serializeRules = require('../../writer/one-time').rules;
+
+var Token = require('../../tokenizer/token');
+
+function mergeNonAdjacentBySelector(tokens, context) {
+ var specificityCache = context.cache.specificity;
+ var allSelectors = {};
+ var repeatedSelectors = [];
+ var i;
+
+ for (i = tokens.length - 1; i >= 0; i--) {
+ if (tokens[i][0] != Token.RULE)
+ continue;
+ if (tokens[i][2].length === 0)
+ continue;
+
+ var selector = serializeRules(tokens[i][1]);
+ allSelectors[selector] = [i].concat(allSelectors[selector] || []);
+
+ if (allSelectors[selector].length == 2)
+ repeatedSelectors.push(selector);
+ }
+
+ for (i = repeatedSelectors.length - 1; i >= 0; i--) {
+ var positions = allSelectors[repeatedSelectors[i]];
+
+ selectorIterator:
+ for (var j = positions.length - 1; j > 0; j--) {
+ var positionOne = positions[j - 1];
+ var tokenOne = tokens[positionOne];
+ var positionTwo = positions[j];
+ var tokenTwo = tokens[positionTwo];
+
+ directionIterator:
+ for (var direction = 1; direction >= -1; direction -= 2) {
+ var topToBottom = direction == 1;
+ var from = topToBottom ? positionOne + 1 : positionTwo - 1;
+ var to = topToBottom ? positionTwo : positionOne;
+ var delta = topToBottom ? 1 : -1;
+ var moved = topToBottom ? tokenOne : tokenTwo;
+ var target = topToBottom ? tokenTwo : tokenOne;
+ var movedProperties = extractProperties(moved);
+
+ while (from != to) {
+ var traversedProperties = extractProperties(tokens[from]);
+ from += delta;
+
+ // traversed then moved as we move selectors towards the start
+ var reorderable = topToBottom ?
+ canReorder(movedProperties, traversedProperties, specificityCache) :
+ canReorder(traversedProperties, movedProperties, specificityCache);
+
+ if (!reorderable && !topToBottom)
+ continue selectorIterator;
+ if (!reorderable && topToBottom)
+ continue directionIterator;
+ }
+
+ if (topToBottom) {
+ Array.prototype.push.apply(moved[2], target[2]);
+ target[2] = moved[2];
+ } else {
+ Array.prototype.push.apply(target[2], moved[2]);
+ }
+
+ optimizeProperties(target[2], true, true, context);
+ moved[2] = [];
+ }
+ }
+ }
+}
+
+module.exports = mergeNonAdjacentBySelector;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/optimize.js b/node_modules/clean-css/lib/optimizer/level-2/optimize.js
new file mode 100644
index 000000000..78cd44666
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/optimize.js
@@ -0,0 +1,124 @@
+var mergeAdjacent = require('./merge-adjacent');
+var mergeMediaQueries = require('./merge-media-queries');
+var mergeNonAdjacentByBody = require('./merge-non-adjacent-by-body');
+var mergeNonAdjacentBySelector = require('./merge-non-adjacent-by-selector');
+var reduceNonAdjacent = require('./reduce-non-adjacent');
+var removeDuplicateFontAtRules = require('./remove-duplicate-font-at-rules');
+var removeDuplicateMediaQueries = require('./remove-duplicate-media-queries');
+var removeDuplicates = require('./remove-duplicates');
+var restructure = require('./restructure');
+
+var optimizeProperties = require('./properties/optimize');
+
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
+var Token = require('../../tokenizer/token');
+
+function removeEmpty(tokens) {
+ for (var i = 0, l = tokens.length; i < l; i++) {
+ var token = tokens[i];
+ var isEmpty = false;
+
+ switch (token[0]) {
+ case Token.RULE:
+ isEmpty = token[1].length === 0 || token[2].length === 0;
+ break;
+ case Token.NESTED_BLOCK:
+ removeEmpty(token[2]);
+ isEmpty = token[2].length === 0;
+ break;
+ case Token.AT_RULE_BLOCK:
+ isEmpty = token[2].length === 0;
+ }
+
+ if (isEmpty) {
+ tokens.splice(i, 1);
+ i--;
+ l--;
+ }
+ }
+}
+
+function recursivelyOptimizeBlocks(tokens, context) {
+ for (var i = 0, l = tokens.length; i < l; i++) {
+ var token = tokens[i];
+
+ if (token[0] == Token.NESTED_BLOCK) {
+ var isKeyframes = /@(-moz-|-o-|-webkit-)?keyframes/.test(token[1][0][1]);
+ level2Optimize(token[2], context, !isKeyframes);
+ }
+ }
+}
+
+function recursivelyOptimizeProperties(tokens, context) {
+ for (var i = 0, l = tokens.length; i < l; i++) {
+ var token = tokens[i];
+
+ switch (token[0]) {
+ case Token.RULE:
+ optimizeProperties(token[2], true, true, context);
+ break;
+ case Token.NESTED_BLOCK:
+ recursivelyOptimizeProperties(token[2], context);
+ }
+ }
+}
+
+function level2Optimize(tokens, context, withRestructuring) {
+ var levelOptions = context.options.level[OptimizationLevel.Two];
+ var reduced;
+ var i;
+
+ recursivelyOptimizeBlocks(tokens, context);
+ recursivelyOptimizeProperties(tokens, context);
+
+ if (levelOptions.removeDuplicateRules) {
+ removeDuplicates(tokens, context);
+ }
+
+ if (levelOptions.mergeAdjacentRules) {
+ mergeAdjacent(tokens, context);
+ }
+
+ if (levelOptions.reduceNonAdjacentRules) {
+ reduceNonAdjacent(tokens, context);
+ }
+
+ if (levelOptions.mergeNonAdjacentRules && levelOptions.mergeNonAdjacentRules != 'body') {
+ mergeNonAdjacentBySelector(tokens, context);
+ }
+
+ if (levelOptions.mergeNonAdjacentRules && levelOptions.mergeNonAdjacentRules != 'selector') {
+ mergeNonAdjacentByBody(tokens, context);
+ }
+
+ if (levelOptions.restructureRules && levelOptions.mergeAdjacentRules && withRestructuring) {
+ restructure(tokens, context);
+ mergeAdjacent(tokens, context);
+ }
+
+ if (levelOptions.restructureRules && !levelOptions.mergeAdjacentRules && withRestructuring) {
+ restructure(tokens, context);
+ }
+
+ if (levelOptions.removeDuplicateFontRules) {
+ removeDuplicateFontAtRules(tokens, context);
+ }
+
+ if (levelOptions.removeDuplicateMediaBlocks) {
+ removeDuplicateMediaQueries(tokens, context);
+ }
+
+ if (levelOptions.mergeMedia) {
+ reduced = mergeMediaQueries(tokens, context);
+ for (i = reduced.length - 1; i >= 0; i--) {
+ level2Optimize(reduced[i][2], context, false);
+ }
+ }
+
+ removeEmpty(tokens);
+
+ return tokens;
+}
+
+module.exports = level2Optimize;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js b/node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js
new file mode 100644
index 000000000..44fcb7d53
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js
@@ -0,0 +1,28 @@
+var Marker = require('../../../tokenizer/marker');
+
+function everyValuesPair(fn, left, right) {
+ var leftSize = left.value.length;
+ var rightSize = right.value.length;
+ var total = Math.max(leftSize, rightSize);
+ var lowerBound = Math.min(leftSize, rightSize) - 1;
+ var leftValue;
+ var rightValue;
+ var position;
+
+ for (position = 0; position < total; position++) {
+ leftValue = left.value[position] && left.value[position][1] || leftValue;
+ rightValue = right.value[position] && right.value[position][1] || rightValue;
+
+ if (leftValue == Marker.COMMA || rightValue == Marker.COMMA) {
+ continue;
+ }
+
+ if (!fn(leftValue, rightValue, position, position <= lowerBound)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+module.exports = everyValuesPair;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/find-component-in.js b/node_modules/clean-css/lib/optimizer/level-2/properties/find-component-in.js
new file mode 100644
index 000000000..dd7c719d5
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/find-component-in.js
@@ -0,0 +1,40 @@
+var compactable = require('../compactable');
+
+function findComponentIn(shorthand, longhand) {
+ var comparator = nameComparator(longhand);
+
+ return findInDirectComponents(shorthand, comparator) || findInSubComponents(shorthand, comparator);
+}
+
+function nameComparator(to) {
+ return function (property) {
+ return to.name === property.name;
+ };
+}
+
+function findInDirectComponents(shorthand, comparator) {
+ return shorthand.components.filter(comparator)[0];
+}
+
+function findInSubComponents(shorthand, comparator) {
+ var shorthandComponent;
+ var longhandMatch;
+ var i, l;
+
+ if (!compactable[shorthand.name].shorthandComponents) {
+ return;
+ }
+
+ for (i = 0, l = shorthand.components.length; i < l; i++) {
+ shorthandComponent = shorthand.components[i];
+ longhandMatch = findInDirectComponents(shorthandComponent, comparator);
+
+ if (longhandMatch) {
+ return longhandMatch;
+ }
+ }
+
+ return;
+}
+
+module.exports = findComponentIn;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/has-inherit.js b/node_modules/clean-css/lib/optimizer/level-2/properties/has-inherit.js
new file mode 100644
index 000000000..84f220d32
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/has-inherit.js
@@ -0,0 +1,10 @@
+function hasInherit(property) {
+ for (var i = property.value.length - 1; i >= 0; i--) {
+ if (property.value[i][1] == 'inherit')
+ return true;
+ }
+
+ return false;
+}
+
+module.exports = hasInherit;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/is-component-of.js b/node_modules/clean-css/lib/optimizer/level-2/properties/is-component-of.js
new file mode 100644
index 000000000..237de7d10
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/is-component-of.js
@@ -0,0 +1,22 @@
+var compactable = require('../compactable');
+
+function isComponentOf(property1, property2, shallow) {
+ return isDirectComponentOf(property1, property2) ||
+ !shallow && !!compactable[property1.name].shorthandComponents && isSubComponentOf(property1, property2);
+}
+
+function isDirectComponentOf(property1, property2) {
+ var descriptor = compactable[property1.name];
+
+ return 'components' in descriptor && descriptor.components.indexOf(property2.name) > -1;
+}
+
+function isSubComponentOf(property1, property2) {
+ return property1
+ .components
+ .some(function (component) {
+ return isDirectComponentOf(component, property2);
+ });
+}
+
+module.exports = isComponentOf;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js b/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js
new file mode 100644
index 000000000..a75c4ed63
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js
@@ -0,0 +1,157 @@
+var everyValuesPair = require('./every-values-pair');
+var hasInherit = require('./has-inherit');
+var populateComponents = require('./populate-components');
+
+var compactable = require('../compactable');
+var deepClone = require('../clone').deep;
+
+var wrapSingle = require('../../wrap-for-optimizing').single;
+
+var Token = require('../../../tokenizer/token');
+
+function mixedImportance(components) {
+ var important;
+
+ for (var name in components) {
+ if (undefined !== important && components[name].important != important)
+ return true;
+
+ important = components[name].important;
+ }
+
+ return false;
+}
+
+function joinMetadata(components, at) {
+ var metadata = [];
+ var component;
+ var originalValue;
+ var componentMetadata;
+ var name;
+
+ for (name in components) {
+ component = components[name];
+ originalValue = component.all[component.position];
+ componentMetadata = originalValue[at][originalValue[at].length - 1];
+
+ Array.prototype.push.apply(metadata, componentMetadata);
+ }
+
+ return metadata;
+}
+
+function replaceWithShorthand(properties, candidateComponents, name, validator) {
+ var descriptor = compactable[name];
+ var nameMetadata;
+ var valueMetadata;
+ var newValuePlaceholder = [
+ Token.PROPERTY,
+ [Token.PROPERTY_NAME, name],
+ [Token.PROPERTY_VALUE, descriptor.defaultValue]
+ ];
+ var mayOverride;
+ var all;
+
+ var newProperty = wrapSingle(newValuePlaceholder);
+ newProperty.shorthand = true;
+ newProperty.dirty = true;
+
+ populateComponents([newProperty], validator, []);
+
+ for (var i = 0, l = descriptor.components.length; i < l; i++) {
+ var component = candidateComponents[descriptor.components[i]];
+
+ if (hasInherit(component))
+ return;
+
+ mayOverride = compactable[component.name].canOverride;
+ if (!everyValuesPair(mayOverride.bind(null, validator), newProperty.components[i], component))
+ return;
+
+ newProperty.components[i] = deepClone(component);
+ newProperty.important = component.important;
+
+ all = component.all;
+ }
+
+ for (var componentName in candidateComponents) {
+ candidateComponents[componentName].unused = true;
+ }
+
+ nameMetadata = joinMetadata(candidateComponents, 1);
+ newValuePlaceholder[1].push(nameMetadata);
+
+ valueMetadata = joinMetadata(candidateComponents, 2);
+ newValuePlaceholder[2].push(valueMetadata);
+
+ newProperty.position = all.length;
+ newProperty.all = all;
+ newProperty.all.push(newValuePlaceholder);
+
+ properties.push(newProperty);
+}
+
+function invalidateOrCompact(properties, position, candidates, validator) {
+ var property = properties[position];
+
+ for (var name in candidates) {
+ if (undefined !== property && name == property.name)
+ continue;
+
+ var descriptor = compactable[name];
+ var candidateComponents = candidates[name];
+ if (descriptor.components.length > Object.keys(candidateComponents).length) {
+ delete candidates[name];
+ continue;
+ }
+
+ if (mixedImportance(candidateComponents))
+ continue;
+
+ replaceWithShorthand(properties, candidateComponents, name, validator);
+ }
+}
+
+function mergeIntoShorthands(properties, validator) {
+ var candidates = {};
+ var descriptor;
+ var componentOf;
+ var property;
+ var i, l;
+ var j, m;
+
+ if (properties.length < 3)
+ return;
+
+ for (i = 0, l = properties.length; i < l; i++) {
+ property = properties[i];
+
+ if (property.unused)
+ continue;
+
+ if (property.hack)
+ continue;
+
+ if (property.block)
+ continue;
+
+ descriptor = compactable[property.name];
+ if (!descriptor || !descriptor.componentOf)
+ continue;
+
+ if (property.shorthand) {
+ invalidateOrCompact(properties, i, candidates, validator);
+ } else {
+ for (j = 0, m = descriptor.componentOf.length; j < m; j++) {
+ componentOf = descriptor.componentOf[j];
+
+ candidates[componentOf] = candidates[componentOf] || {};
+ candidates[componentOf][property.name] = property;
+ }
+ }
+ }
+
+ invalidateOrCompact(properties, i, candidates, validator);
+}
+
+module.exports = mergeIntoShorthands;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js b/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js
new file mode 100644
index 000000000..250b05fc4
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js
@@ -0,0 +1,39 @@
+var mergeIntoShorthands = require('./merge-into-shorthands');
+var overrideProperties = require('./override-properties');
+var populateComponents = require('./populate-components');
+
+var restoreWithComponents = require('../restore-with-components');
+
+var wrapForOptimizing = require('../../wrap-for-optimizing').all;
+var removeUnused = require('../../remove-unused');
+var restoreFromOptimizing = require('../../restore-from-optimizing');
+
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+function optimizeProperties(properties, withOverriding, withMerging, context) {
+ var _properties = wrapForOptimizing(properties, false);
+ var _property;
+ var i, l;
+
+ populateComponents(_properties, context.validator, context.warnings);
+
+ for (i = 0, l = _properties.length; i < l; i++) {
+ _property = _properties[i];
+ if (_property.block) {
+ optimizeProperties(_property.value[0][1], withOverriding, withMerging, context);
+ }
+ }
+
+ if (withOverriding && context.options.level[OptimizationLevel.Two].overrideProperties) {
+ overrideProperties(_properties, withMerging, context.options.compatibility, context.validator);
+ }
+
+ if (withMerging && context.options.level[OptimizationLevel.Two].mergeIntoShorthands) {
+ mergeIntoShorthands(_properties, context.validator);
+ }
+
+ restoreFromOptimizing(_properties, restoreWithComponents);
+ removeUnused(_properties);
+}
+
+module.exports = optimizeProperties;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js b/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js
new file mode 100644
index 000000000..3c9d8d2af
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js
@@ -0,0 +1,441 @@
+var hasInherit = require('./has-inherit');
+var everyValuesPair = require('./every-values-pair');
+var findComponentIn = require('./find-component-in');
+var isComponentOf = require('./is-component-of');
+var overridesNonComponentShorthand = require('./overrides-non-component-shorthand');
+var sameVendorPrefixesIn = require('./vendor-prefixes').same;
+
+var compactable = require('../compactable');
+var deepClone = require('../clone').deep;
+var deepClone = require('../clone').deep;
+var restoreWithComponents = require('../restore-with-components');
+var shallowClone = require('../clone').shallow;
+
+var restoreFromOptimizing = require('../../restore-from-optimizing');
+
+var Token = require('../../../tokenizer/token');
+var Marker = require('../../../tokenizer/marker');
+
+var serializeProperty = require('../../../writer/one-time').property;
+
+function wouldBreakCompatibility(property, validator) {
+ for (var i = 0; i < property.components.length; i++) {
+ var component = property.components[i];
+ var descriptor = compactable[component.name];
+ var canOverride = descriptor && descriptor.canOverride || canOverride.sameValue;
+
+ var _component = shallowClone(component);
+ _component.value = [[Token.PROPERTY_VALUE, descriptor.defaultValue]];
+
+ if (!everyValuesPair(canOverride.bind(null, validator), _component, component)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function overrideIntoMultiplex(property, by) {
+ by.unused = true;
+
+ turnIntoMultiplex(by, multiplexSize(property));
+ property.value = by.value;
+}
+
+function overrideByMultiplex(property, by) {
+ by.unused = true;
+ property.multiplex = true;
+ property.value = by.value;
+}
+
+function overrideSimple(property, by) {
+ by.unused = true;
+ property.value = by.value;
+}
+
+function override(property, by) {
+ if (by.multiplex)
+ overrideByMultiplex(property, by);
+ else if (property.multiplex)
+ overrideIntoMultiplex(property, by);
+ else
+ overrideSimple(property, by);
+}
+
+function overrideShorthand(property, by) {
+ by.unused = true;
+
+ for (var i = 0, l = property.components.length; i < l; i++) {
+ override(property.components[i], by.components[i], property.multiplex);
+ }
+}
+
+function turnIntoMultiplex(property, size) {
+ property.multiplex = true;
+
+ for (var i = 0, l = property.components.length; i < l; i++) {
+ var component = property.components[i];
+ if (component.multiplex)
+ continue;
+
+ var value = component.value.slice(0);
+
+ for (var j = 1; j < size; j++) {
+ component.value.push([Token.PROPERTY_VALUE, Marker.COMMA]);
+ Array.prototype.push.apply(component.value, value);
+ }
+ }
+}
+
+function multiplexSize(component) {
+ var size = 0;
+
+ for (var i = 0, l = component.value.length; i < l; i++) {
+ if (component.value[i][1] == Marker.COMMA)
+ size++;
+ }
+
+ return size + 1;
+}
+
+function lengthOf(property) {
+ var fakeAsArray = [
+ Token.PROPERTY,
+ [Token.PROPERTY_NAME, property.name]
+ ].concat(property.value);
+ return serializeProperty([fakeAsArray], 0).length;
+}
+
+function moreSameShorthands(properties, startAt, name) {
+ // Since we run the main loop in `compactOverrides` backwards, at this point some
+ // properties may not be marked as unused.
+ // We should consider reverting the order if possible
+ var count = 0;
+
+ for (var i = startAt; i >= 0; i--) {
+ if (properties[i].name == name && !properties[i].unused)
+ count++;
+ if (count > 1)
+ break;
+ }
+
+ return count > 1;
+}
+
+function overridingFunction(shorthand, validator) {
+ for (var i = 0, l = shorthand.components.length; i < l; i++) {
+ if (anyValue(validator.isValidFunction, shorthand.components[i]))
+ return true;
+ }
+
+ return false;
+}
+
+function anyValue(fn, property) {
+ for (var i = 0, l = property.value.length; i < l; i++) {
+ if (property.value[i][1] == Marker.COMMA)
+ continue;
+
+ if (fn(property.value[i][1]))
+ return true;
+ }
+
+ return false;
+}
+
+function wouldResultInLongerValue(left, right) {
+ if (!left.multiplex && !right.multiplex || left.multiplex && right.multiplex)
+ return false;
+
+ var multiplex = left.multiplex ? left : right;
+ var simple = left.multiplex ? right : left;
+ var component;
+
+ var multiplexClone = deepClone(multiplex);
+ restoreFromOptimizing([multiplexClone], restoreWithComponents);
+
+ var simpleClone = deepClone(simple);
+ restoreFromOptimizing([simpleClone], restoreWithComponents);
+
+ var lengthBefore = lengthOf(multiplexClone) + 1 + lengthOf(simpleClone);
+
+ if (left.multiplex) {
+ component = findComponentIn(multiplexClone, simpleClone);
+ overrideIntoMultiplex(component, simpleClone);
+ } else {
+ component = findComponentIn(simpleClone, multiplexClone);
+ turnIntoMultiplex(simpleClone, multiplexSize(multiplexClone));
+ overrideByMultiplex(component, multiplexClone);
+ }
+
+ restoreFromOptimizing([simpleClone], restoreWithComponents);
+
+ var lengthAfter = lengthOf(simpleClone);
+
+ return lengthBefore <= lengthAfter;
+}
+
+function isCompactable(property) {
+ return property.name in compactable;
+}
+
+function noneOverrideHack(left, right) {
+ return !left.multiplex &&
+ (left.name == 'background' || left.name == 'background-image') &&
+ right.multiplex &&
+ (right.name == 'background' || right.name == 'background-image') &&
+ anyLayerIsNone(right.value);
+}
+
+function anyLayerIsNone(values) {
+ var layers = intoLayers(values);
+
+ for (var i = 0, l = layers.length; i < l; i++) {
+ if (layers[i].length == 1 && layers[i][0][1] == 'none')
+ return true;
+ }
+
+ return false;
+}
+
+function intoLayers(values) {
+ var layers = [];
+
+ for (var i = 0, layer = [], l = values.length; i < l; i++) {
+ var value = values[i];
+ if (value[1] == Marker.COMMA) {
+ layers.push(layer);
+ layer = [];
+ } else {
+ layer.push(value);
+ }
+ }
+
+ layers.push(layer);
+ return layers;
+}
+
+function overrideProperties(properties, withMerging, compatibility, validator) {
+ var mayOverride, right, left, component;
+ var overriddenComponents;
+ var overriddenComponent;
+ var overridingComponent;
+ var overridable;
+ var i, j, k;
+
+ propertyLoop:
+ for (i = properties.length - 1; i >= 0; i--) {
+ right = properties[i];
+
+ if (!isCompactable(right))
+ continue;
+
+ if (right.block)
+ continue;
+
+ mayOverride = compactable[right.name].canOverride;
+
+ traverseLoop:
+ for (j = i - 1; j >= 0; j--) {
+ left = properties[j];
+
+ if (!isCompactable(left))
+ continue;
+
+ if (left.block)
+ continue;
+
+ if (left.unused || right.unused)
+ continue;
+
+ if (left.hack && !right.hack && !right.important || !left.hack && !left.important && right.hack)
+ continue;
+
+ if (left.important == right.important && left.hack[0] != right.hack[0])
+ continue;
+
+ if (left.important == right.important && (left.hack[0] != right.hack[0] || (left.hack[1] && left.hack[1] != right.hack[1])))
+ continue;
+
+ if (hasInherit(right))
+ continue;
+
+ if (noneOverrideHack(left, right))
+ continue;
+
+ if (right.shorthand && isComponentOf(right, left)) {
+ // maybe `left` can be overridden by `right` which is a shorthand?
+ if (!right.important && left.important)
+ continue;
+
+ if (!sameVendorPrefixesIn([left], right.components))
+ continue;
+
+ if (!anyValue(validator.isValidFunction, left) && overridingFunction(right, validator))
+ continue;
+
+ component = findComponentIn(right, left);
+ mayOverride = compactable[left.name].canOverride;
+ if (everyValuesPair(mayOverride.bind(null, validator), left, component)) {
+ left.unused = true;
+ }
+ } else if (right.shorthand && overridesNonComponentShorthand(right, left)) {
+ // `right` is a shorthand while `left` can be overriden by it, think `border` and `border-top`
+ if (!right.important && left.important) {
+ continue;
+ }
+
+ if (!sameVendorPrefixesIn([left], right.components)) {
+ continue;
+ }
+
+ if (!anyValue(validator.isValidFunction, left) && overridingFunction(right, validator)) {
+ continue;
+ }
+
+ overriddenComponents = left.shorthand ?
+ left.components:
+ [left];
+
+ for (k = overriddenComponents.length - 1; k >= 0; k--) {
+ overriddenComponent = overriddenComponents[k];
+ overridingComponent = findComponentIn(right, overriddenComponent);
+ mayOverride = compactable[overriddenComponent.name].canOverride;
+
+ if (!everyValuesPair(mayOverride.bind(null, validator), left, overridingComponent)) {
+ continue traverseLoop;
+ }
+ }
+
+ left.unused = true;
+ } else if (withMerging && left.shorthand && !right.shorthand && isComponentOf(left, right, true)) {
+ // maybe `right` can be pulled into `left` which is a shorthand?
+ if (right.important && !left.important)
+ continue;
+
+ if (!right.important && left.important) {
+ right.unused = true;
+ continue;
+ }
+
+ // Pending more clever algorithm in #527
+ if (moreSameShorthands(properties, i - 1, left.name))
+ continue;
+
+ if (overridingFunction(left, validator))
+ continue;
+
+ component = findComponentIn(left, right);
+ if (everyValuesPair(mayOverride.bind(null, validator), component, right)) {
+ var disabledBackgroundMerging =
+ !compatibility.properties.backgroundClipMerging && component.name.indexOf('background-clip') > -1 ||
+ !compatibility.properties.backgroundOriginMerging && component.name.indexOf('background-origin') > -1 ||
+ !compatibility.properties.backgroundSizeMerging && component.name.indexOf('background-size') > -1;
+ var nonMergeableValue = compactable[right.name].nonMergeableValue === right.value[0][1];
+
+ if (disabledBackgroundMerging || nonMergeableValue)
+ continue;
+
+ if (!compatibility.properties.merging && wouldBreakCompatibility(left, validator))
+ continue;
+
+ if (component.value[0][1] != right.value[0][1] && (hasInherit(left) || hasInherit(right)))
+ continue;
+
+ if (wouldResultInLongerValue(left, right))
+ continue;
+
+ if (!left.multiplex && right.multiplex)
+ turnIntoMultiplex(left, multiplexSize(right));
+
+ override(component, right);
+ left.dirty = true;
+ }
+ } else if (withMerging && left.shorthand && right.shorthand && left.name == right.name) {
+ // merge if all components can be merged
+
+ if (!left.multiplex && right.multiplex)
+ continue;
+
+ if (!right.important && left.important) {
+ right.unused = true;
+ continue propertyLoop;
+ }
+
+ if (right.important && !left.important) {
+ left.unused = true;
+ continue;
+ }
+
+ for (k = left.components.length - 1; k >= 0; k--) {
+ var leftComponent = left.components[k];
+ var rightComponent = right.components[k];
+
+ mayOverride = compactable[leftComponent.name].canOverride;
+ if (!everyValuesPair(mayOverride.bind(null, validator), leftComponent, rightComponent))
+ continue propertyLoop;
+ }
+
+ overrideShorthand(left, right);
+ left.dirty = true;
+ } else if (withMerging && left.shorthand && right.shorthand && isComponentOf(left, right)) {
+ // border is a shorthand but any of its components is a shorthand too
+
+ if (!left.important && right.important)
+ continue;
+
+ component = findComponentIn(left, right);
+ mayOverride = compactable[right.name].canOverride;
+ if (!everyValuesPair(mayOverride.bind(null, validator), component, right))
+ continue;
+
+ if (left.important && !right.important) {
+ right.unused = true;
+ continue;
+ }
+
+ var rightRestored = compactable[right.name].restore(right, compactable);
+ if (rightRestored.length > 1)
+ continue;
+
+ component = findComponentIn(left, right);
+ override(component, right);
+ right.dirty = true;
+ } else if (left.name == right.name) {
+ // two non-shorthands should be merged based on understandability
+ overridable = true;
+
+ if (right.shorthand) {
+ for (k = right.components.length - 1; k >= 0 && overridable; k--) {
+ overriddenComponent = left.components[k];
+ overridingComponent = right.components[k];
+ mayOverride = compactable[overridingComponent.name].canOverride;
+
+ overridable = overridable && everyValuesPair(mayOverride.bind(null, validator), overriddenComponent, overridingComponent);
+ }
+ } else {
+ mayOverride = compactable[right.name].canOverride;
+ overridable = everyValuesPair(mayOverride.bind(null, validator), left, right);
+ }
+
+ if (left.important && !right.important && overridable) {
+ right.unused = true;
+ continue;
+ }
+
+ if (!left.important && right.important && overridable) {
+ left.unused = true;
+ continue;
+ }
+
+ if (!overridable) {
+ continue;
+ }
+
+ left.unused = true;
+ }
+ }
+ }
+}
+
+module.exports = overrideProperties;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/overrides-non-component-shorthand.js b/node_modules/clean-css/lib/optimizer/level-2/properties/overrides-non-component-shorthand.js
new file mode 100644
index 000000000..c385218a9
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/overrides-non-component-shorthand.js
@@ -0,0 +1,9 @@
+var compactable = require('../compactable');
+
+function overridesNonComponentShorthand(property1, property2) {
+ return property1.name in compactable &&
+ 'overridesShorthands' in compactable[property1.name] &&
+ compactable[property1.name].overridesShorthands.indexOf(property2.name) > -1;
+}
+
+module.exports = overridesNonComponentShorthand;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/populate-components.js b/node_modules/clean-css/lib/optimizer/level-2/properties/populate-components.js
new file mode 100644
index 000000000..c587e83c4
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/populate-components.js
@@ -0,0 +1,42 @@
+var compactable = require('../compactable');
+var InvalidPropertyError = require('../invalid-property-error');
+
+function populateComponents(properties, validator, warnings) {
+ var component;
+ var j, m;
+
+ for (var i = properties.length - 1; i >= 0; i--) {
+ var property = properties[i];
+ var descriptor = compactable[property.name];
+
+ if (descriptor && descriptor.shorthand) {
+ property.shorthand = true;
+ property.dirty = true;
+
+ try {
+ property.components = descriptor.breakUp(property, compactable, validator);
+
+ if (descriptor.shorthandComponents) {
+ for (j = 0, m = property.components.length; j < m; j++) {
+ component = property.components[j];
+ component.components = compactable[component.name].breakUp(component, compactable, validator);
+ }
+ }
+ } catch (e) {
+ if (e instanceof InvalidPropertyError) {
+ property.components = []; // this will set property.unused to true below
+ warnings.push(e.message);
+ } else {
+ throw e;
+ }
+ }
+
+ if (property.components.length > 0)
+ property.multiplex = property.components[0].multiplex;
+ else
+ property.unused = true;
+ }
+ }
+}
+
+module.exports = populateComponents;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/understandable.js b/node_modules/clean-css/lib/optimizer/level-2/properties/understandable.js
new file mode 100644
index 000000000..6c77db50d
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/understandable.js
@@ -0,0 +1,15 @@
+var sameVendorPrefixes = require('./vendor-prefixes').same;
+
+function understandable(validator, value1, value2, _position, isPaired) {
+ if (!sameVendorPrefixes(value1, value2)) {
+ return false;
+ }
+
+ if (isPaired && validator.isValidVariable(value1) !== validator.isValidVariable(value2)) {
+ return false;
+ }
+
+ return true;
+}
+
+module.exports = understandable;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/vendor-prefixes.js b/node_modules/clean-css/lib/optimizer/level-2/properties/vendor-prefixes.js
new file mode 100644
index 000000000..f9ab52728
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/properties/vendor-prefixes.js
@@ -0,0 +1,23 @@
+var VENDOR_PREFIX_PATTERN = /(?:^|\W)(\-\w+\-)/g;
+
+function unique(value) {
+ var prefixes = [];
+ var match;
+
+ while ((match = VENDOR_PREFIX_PATTERN.exec(value)) !== null) {
+ if (prefixes.indexOf(match[0]) == -1) {
+ prefixes.push(match[0]);
+ }
+ }
+
+ return prefixes;
+}
+
+function same(value1, value2) {
+ return unique(value1).sort().join(',') == unique(value2).sort().join(',');
+}
+
+module.exports = {
+ unique: unique,
+ same: same
+};
diff --git a/node_modules/clean-css/lib/optimizer/level-2/reduce-non-adjacent.js b/node_modules/clean-css/lib/optimizer/level-2/reduce-non-adjacent.js
new file mode 100644
index 000000000..3461bb268
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/reduce-non-adjacent.js
@@ -0,0 +1,178 @@
+var isMergeable = require('./is-mergeable');
+
+var optimizeProperties = require('./properties/optimize');
+
+var cloneArray = require('../../utils/clone-array');
+
+var Token = require('../../tokenizer/token');
+
+var serializeBody = require('../../writer/one-time').body;
+var serializeRules = require('../../writer/one-time').rules;
+
+function reduceNonAdjacent(tokens, context) {
+ var options = context.options;
+ var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
+ var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
+ var candidates = {};
+ var repeated = [];
+
+ for (var i = tokens.length - 1; i >= 0; i--) {
+ var token = tokens[i];
+
+ if (token[0] != Token.RULE) {
+ continue;
+ } else if (token[2].length === 0) {
+ continue;
+ }
+
+ var selectorAsString = serializeRules(token[1]);
+ var isComplexAndNotSpecial = token[1].length > 1 &&
+ isMergeable(selectorAsString, mergeablePseudoClasses, mergeablePseudoElements);
+ var wrappedSelectors = wrappedSelectorsFrom(token[1]);
+ var selectors = isComplexAndNotSpecial ?
+ [selectorAsString].concat(wrappedSelectors) :
+ [selectorAsString];
+
+ for (var j = 0, m = selectors.length; j < m; j++) {
+ var selector = selectors[j];
+
+ if (!candidates[selector])
+ candidates[selector] = [];
+ else
+ repeated.push(selector);
+
+ candidates[selector].push({
+ where: i,
+ list: wrappedSelectors,
+ isPartial: isComplexAndNotSpecial && j > 0,
+ isComplex: isComplexAndNotSpecial && j === 0
+ });
+ }
+ }
+
+ reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, context);
+ reduceComplexNonAdjacentCases(tokens, candidates, options, context);
+}
+
+function wrappedSelectorsFrom(list) {
+ var wrapped = [];
+
+ for (var i = 0; i < list.length; i++) {
+ wrapped.push([list[i][1]]);
+ }
+
+ return wrapped;
+}
+
+function reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, context) {
+ function filterOut(idx, bodies) {
+ return data[idx].isPartial && bodies.length === 0;
+ }
+
+ function reduceBody(token, newBody, processedCount, tokenIdx) {
+ if (!data[processedCount - tokenIdx - 1].isPartial)
+ token[2] = newBody;
+ }
+
+ for (var i = 0, l = repeated.length; i < l; i++) {
+ var selector = repeated[i];
+ var data = candidates[selector];
+
+ reduceSelector(tokens, data, {
+ filterOut: filterOut,
+ callback: reduceBody
+ }, options, context);
+ }
+}
+
+function reduceComplexNonAdjacentCases(tokens, candidates, options, context) {
+ var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
+ var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
+ var localContext = {};
+
+ function filterOut(idx) {
+ return localContext.data[idx].where < localContext.intoPosition;
+ }
+
+ function collectReducedBodies(token, newBody, processedCount, tokenIdx) {
+ if (tokenIdx === 0)
+ localContext.reducedBodies.push(newBody);
+ }
+
+ allSelectors:
+ for (var complexSelector in candidates) {
+ var into = candidates[complexSelector];
+ if (!into[0].isComplex)
+ continue;
+
+ var intoPosition = into[into.length - 1].where;
+ var intoToken = tokens[intoPosition];
+ var reducedBodies = [];
+
+ var selectors = isMergeable(complexSelector, mergeablePseudoClasses, mergeablePseudoElements) ?
+ into[0].list :
+ [complexSelector];
+
+ localContext.intoPosition = intoPosition;
+ localContext.reducedBodies = reducedBodies;
+
+ for (var j = 0, m = selectors.length; j < m; j++) {
+ var selector = selectors[j];
+ var data = candidates[selector];
+
+ if (data.length < 2)
+ continue allSelectors;
+
+ localContext.data = data;
+
+ reduceSelector(tokens, data, {
+ filterOut: filterOut,
+ callback: collectReducedBodies
+ }, options, context);
+
+ if (serializeBody(reducedBodies[reducedBodies.length - 1]) != serializeBody(reducedBodies[0]))
+ continue allSelectors;
+ }
+
+ intoToken[2] = reducedBodies[0];
+ }
+}
+
+function reduceSelector(tokens, data, context, options, outerContext) {
+ var bodies = [];
+ var bodiesAsList = [];
+ var processedTokens = [];
+
+ for (var j = data.length - 1; j >= 0; j--) {
+ if (context.filterOut(j, bodies))
+ continue;
+
+ var where = data[j].where;
+ var token = tokens[where];
+ var clonedBody = cloneArray(token[2]);
+
+ bodies = bodies.concat(clonedBody);
+ bodiesAsList.push(clonedBody);
+ processedTokens.push(where);
+ }
+
+ optimizeProperties(bodies, true, false, outerContext);
+
+ var processedCount = processedTokens.length;
+ var propertyIdx = bodies.length - 1;
+ var tokenIdx = processedCount - 1;
+
+ while (tokenIdx >= 0) {
+ if ((tokenIdx === 0 || (bodies[propertyIdx] && bodiesAsList[tokenIdx].indexOf(bodies[propertyIdx]) > -1)) && propertyIdx > -1) {
+ propertyIdx--;
+ continue;
+ }
+
+ var newBody = bodies.splice(propertyIdx + 1);
+ context.callback(tokens[processedTokens[tokenIdx]], newBody, processedCount, tokenIdx);
+
+ tokenIdx--;
+ }
+}
+
+module.exports = reduceNonAdjacent;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/remove-duplicate-font-at-rules.js b/node_modules/clean-css/lib/optimizer/level-2/remove-duplicate-font-at-rules.js
new file mode 100644
index 000000000..bc85d5d67
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/remove-duplicate-font-at-rules.js
@@ -0,0 +1,30 @@
+var Token = require('../../tokenizer/token');
+
+var serializeAll = require('../../writer/one-time').all;
+
+var FONT_FACE_SCOPE = '@font-face';
+
+function removeDuplicateFontAtRules(tokens) {
+ var fontAtRules = [];
+ var token;
+ var key;
+ var i, l;
+
+ for (i = 0, l = tokens.length; i < l; i++) {
+ token = tokens[i];
+
+ if (token[0] != Token.AT_RULE_BLOCK && token[1][0][1] != FONT_FACE_SCOPE) {
+ continue;
+ }
+
+ key = serializeAll([token]);
+
+ if (fontAtRules.indexOf(key) > -1) {
+ token[2] = [];
+ } else {
+ fontAtRules.push(key);
+ }
+ }
+}
+
+module.exports = removeDuplicateFontAtRules;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/remove-duplicate-media-queries.js b/node_modules/clean-css/lib/optimizer/level-2/remove-duplicate-media-queries.js
new file mode 100644
index 000000000..2c8f31d9d
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/remove-duplicate-media-queries.js
@@ -0,0 +1,30 @@
+var Token = require('../../tokenizer/token');
+
+var serializeAll = require('../../writer/one-time').all;
+var serializeRules = require('../../writer/one-time').rules;
+
+function removeDuplicateMediaQueries(tokens) {
+ var candidates = {};
+ var candidate;
+ var token;
+ var key;
+ var i, l;
+
+ for (i = 0, l = tokens.length; i < l; i++) {
+ token = tokens[i];
+ if (token[0] != Token.NESTED_BLOCK) {
+ continue;
+ }
+
+ key = serializeRules(token[1]) + '%' + serializeAll(token[2]);
+ candidate = candidates[key];
+
+ if (candidate) {
+ candidate[2] = [];
+ }
+
+ candidates[key] = token;
+ }
+}
+
+module.exports = removeDuplicateMediaQueries;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/remove-duplicates.js b/node_modules/clean-css/lib/optimizer/level-2/remove-duplicates.js
new file mode 100644
index 000000000..9aa6ace93
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/remove-duplicates.js
@@ -0,0 +1,43 @@
+var Token = require('../../tokenizer/token');
+
+var serializeBody = require('../../writer/one-time').body;
+var serializeRules = require('../../writer/one-time').rules;
+
+function removeDuplicates(tokens) {
+ var matched = {};
+ var moreThanOnce = [];
+ var id, token;
+ var body, bodies;
+
+ for (var i = 0, l = tokens.length; i < l; i++) {
+ token = tokens[i];
+ if (token[0] != Token.RULE)
+ continue;
+
+ id = serializeRules(token[1]);
+
+ if (matched[id] && matched[id].length == 1)
+ moreThanOnce.push(id);
+ else
+ matched[id] = matched[id] || [];
+
+ matched[id].push(i);
+ }
+
+ for (i = 0, l = moreThanOnce.length; i < l; i++) {
+ id = moreThanOnce[i];
+ bodies = [];
+
+ for (var j = matched[id].length - 1; j >= 0; j--) {
+ token = tokens[matched[id][j]];
+ body = serializeBody(token[2]);
+
+ if (bodies.indexOf(body) > -1)
+ token[2] = [];
+ else
+ bodies.push(body);
+ }
+ }
+}
+
+module.exports = removeDuplicates;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/reorderable.js b/node_modules/clean-css/lib/optimizer/level-2/reorderable.js
new file mode 100644
index 000000000..4a3747a08
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/reorderable.js
@@ -0,0 +1,93 @@
+// TODO: it'd be great to merge it with the other canReorder functionality
+
+var rulesOverlap = require('./rules-overlap');
+var specificitiesOverlap = require('./specificities-overlap');
+
+var FLEX_PROPERTIES = /align\-items|box\-align|box\-pack|flex|justify/;
+var BORDER_PROPERTIES = /^border\-(top|right|bottom|left|color|style|width|radius)/;
+
+function canReorder(left, right, cache) {
+ for (var i = right.length - 1; i >= 0; i--) {
+ for (var j = left.length - 1; j >= 0; j--) {
+ if (!canReorderSingle(left[j], right[i], cache))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function canReorderSingle(left, right, cache) {
+ var leftName = left[0];
+ var leftValue = left[1];
+ var leftNameRoot = left[2];
+ var leftSelector = left[5];
+ var leftInSpecificSelector = left[6];
+ var rightName = right[0];
+ var rightValue = right[1];
+ var rightNameRoot = right[2];
+ var rightSelector = right[5];
+ var rightInSpecificSelector = right[6];
+
+ if (leftName == 'font' && rightName == 'line-height' || rightName == 'font' && leftName == 'line-height')
+ return false;
+ if (FLEX_PROPERTIES.test(leftName) && FLEX_PROPERTIES.test(rightName))
+ return false;
+ if (leftNameRoot == rightNameRoot && unprefixed(leftName) == unprefixed(rightName) && (vendorPrefixed(leftName) ^ vendorPrefixed(rightName)))
+ return false;
+ if (leftNameRoot == 'border' && BORDER_PROPERTIES.test(rightNameRoot) && (leftName == 'border' || leftName == rightNameRoot || (leftValue != rightValue && sameBorderComponent(leftName, rightName))))
+ return false;
+ if (rightNameRoot == 'border' && BORDER_PROPERTIES.test(leftNameRoot) && (rightName == 'border' || rightName == leftNameRoot || (leftValue != rightValue && sameBorderComponent(leftName, rightName))))
+ return false;
+ if (leftNameRoot == 'border' && rightNameRoot == 'border' && leftName != rightName && (isSideBorder(leftName) && isStyleBorder(rightName) || isStyleBorder(leftName) && isSideBorder(rightName)))
+ return false;
+ if (leftNameRoot != rightNameRoot)
+ return true;
+ if (leftName == rightName && leftNameRoot == rightNameRoot && (leftValue == rightValue || withDifferentVendorPrefix(leftValue, rightValue)))
+ return true;
+ if (leftName != rightName && leftNameRoot == rightNameRoot && leftName != leftNameRoot && rightName != rightNameRoot)
+ return true;
+ if (leftName != rightName && leftNameRoot == rightNameRoot && leftValue == rightValue)
+ return true;
+ if (rightInSpecificSelector && leftInSpecificSelector && !inheritable(leftNameRoot) && !inheritable(rightNameRoot) && !rulesOverlap(rightSelector, leftSelector, false))
+ return true;
+ if (!specificitiesOverlap(leftSelector, rightSelector, cache))
+ return true;
+
+ return false;
+}
+
+function vendorPrefixed(name) {
+ return /^\-(?:moz|webkit|ms|o)\-/.test(name);
+}
+
+function unprefixed(name) {
+ return name.replace(/^\-(?:moz|webkit|ms|o)\-/, '');
+}
+
+function sameBorderComponent(name1, name2) {
+ return name1.split('-').pop() == name2.split('-').pop();
+}
+
+function isSideBorder(name) {
+ return name == 'border-top' || name == 'border-right' || name == 'border-bottom' || name == 'border-left';
+}
+
+function isStyleBorder(name) {
+ return name == 'border-color' || name == 'border-style' || name == 'border-width';
+}
+
+function withDifferentVendorPrefix(value1, value2) {
+ return vendorPrefixed(value1) && vendorPrefixed(value2) && value1.split('-')[1] != value2.split('-')[2];
+}
+
+function inheritable(name) {
+ // According to http://www.w3.org/TR/CSS21/propidx.html
+ // Others will be catched by other, preceeding rules
+ return name == 'font' || name == 'line-height' || name == 'list-style';
+}
+
+module.exports = {
+ canReorder: canReorder,
+ canReorderSingle: canReorderSingle
+};
diff --git a/node_modules/clean-css/lib/optimizer/level-2/restore-with-components.js b/node_modules/clean-css/lib/optimizer/level-2/restore-with-components.js
new file mode 100644
index 000000000..caf7c4c94
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/restore-with-components.js
@@ -0,0 +1,13 @@
+var compactable = require('./compactable');
+
+function restoreWithComponents(property) {
+ var descriptor = compactable[property.name];
+
+ if (descriptor && descriptor.shorthand) {
+ return descriptor.restore(property, compactable);
+ } else {
+ return property.value;
+ }
+}
+
+module.exports = restoreWithComponents;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/restore.js b/node_modules/clean-css/lib/optimizer/level-2/restore.js
new file mode 100644
index 000000000..149688c5b
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/restore.js
@@ -0,0 +1,233 @@
+var shallowClone = require('./clone').shallow;
+
+var Token = require('../../tokenizer/token');
+var Marker = require('../../tokenizer/marker');
+
+function isInheritOnly(values) {
+ for (var i = 0, l = values.length; i < l; i++) {
+ var value = values[i][1];
+
+ if (value != 'inherit' && value != Marker.COMMA && value != Marker.FORWARD_SLASH)
+ return false;
+ }
+
+ return true;
+}
+
+function background(property, compactable, lastInMultiplex) {
+ var components = property.components;
+ var restored = [];
+ var needsOne, needsBoth;
+
+ function restoreValue(component) {
+ Array.prototype.unshift.apply(restored, component.value);
+ }
+
+ function isDefaultValue(component) {
+ var descriptor = compactable[component.name];
+
+ if (descriptor.doubleValues && descriptor.defaultValue.length == 1) {
+ return component.value[0][1] == descriptor.defaultValue[0] && (component.value[1] ? component.value[1][1] == descriptor.defaultValue[0] : true);
+ } else if (descriptor.doubleValues && descriptor.defaultValue.length != 1) {
+ return component.value[0][1] == descriptor.defaultValue[0] && (component.value[1] ? component.value[1][1] : component.value[0][1]) == descriptor.defaultValue[1];
+ } else {
+ return component.value[0][1] == descriptor.defaultValue;
+ }
+ }
+
+ for (var i = components.length - 1; i >= 0; i--) {
+ var component = components[i];
+ var isDefault = isDefaultValue(component);
+
+ if (component.name == 'background-clip') {
+ var originComponent = components[i - 1];
+ var isOriginDefault = isDefaultValue(originComponent);
+
+ needsOne = component.value[0][1] == originComponent.value[0][1];
+
+ needsBoth = !needsOne && (
+ (isOriginDefault && !isDefault) ||
+ (!isOriginDefault && !isDefault) ||
+ (!isOriginDefault && isDefault && component.value[0][1] != originComponent.value[0][1]));
+
+ if (needsOne) {
+ restoreValue(originComponent);
+ } else if (needsBoth) {
+ restoreValue(component);
+ restoreValue(originComponent);
+ }
+
+ i--;
+ } else if (component.name == 'background-size') {
+ var positionComponent = components[i - 1];
+ var isPositionDefault = isDefaultValue(positionComponent);
+
+ needsOne = !isPositionDefault && isDefault;
+
+ needsBoth = !needsOne &&
+ (isPositionDefault && !isDefault || !isPositionDefault && !isDefault);
+
+ if (needsOne) {
+ restoreValue(positionComponent);
+ } else if (needsBoth) {
+ restoreValue(component);
+ restored.unshift([Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]);
+ restoreValue(positionComponent);
+ } else if (positionComponent.value.length == 1) {
+ restoreValue(positionComponent);
+ }
+
+ i--;
+ } else {
+ if (isDefault || compactable[component.name].multiplexLastOnly && !lastInMultiplex)
+ continue;
+
+ restoreValue(component);
+ }
+ }
+
+ if (restored.length === 0 && property.value.length == 1 && property.value[0][1] == '0')
+ restored.push(property.value[0]);
+
+ if (restored.length === 0)
+ restored.push([Token.PROPERTY_VALUE, compactable[property.name].defaultValue]);
+
+ if (isInheritOnly(restored))
+ return [restored[0]];
+
+ return restored;
+}
+
+function borderRadius(property, compactable) {
+ if (property.multiplex) {
+ var horizontal = shallowClone(property);
+ var vertical = shallowClone(property);
+
+ for (var i = 0; i < 4; i++) {
+ var component = property.components[i];
+
+ var horizontalComponent = shallowClone(property);
+ horizontalComponent.value = [component.value[0]];
+ horizontal.components.push(horizontalComponent);
+
+ var verticalComponent = shallowClone(property);
+ // FIXME: only shorthand compactor (see breakup#borderRadius) knows that border radius
+ // longhands have two values, whereas tokenizer does not care about populating 2nd value
+ // if it's missing, hence this fallback
+ verticalComponent.value = [component.value[1] || component.value[0]];
+ vertical.components.push(verticalComponent);
+ }
+
+ var horizontalValues = fourValues(horizontal, compactable);
+ var verticalValues = fourValues(vertical, compactable);
+
+ if (horizontalValues.length == verticalValues.length &&
+ horizontalValues[0][1] == verticalValues[0][1] &&
+ (horizontalValues.length > 1 ? horizontalValues[1][1] == verticalValues[1][1] : true) &&
+ (horizontalValues.length > 2 ? horizontalValues[2][1] == verticalValues[2][1] : true) &&
+ (horizontalValues.length > 3 ? horizontalValues[3][1] == verticalValues[3][1] : true)) {
+ return horizontalValues;
+ } else {
+ return horizontalValues.concat([[Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]]).concat(verticalValues);
+ }
+ } else {
+ return fourValues(property, compactable);
+ }
+}
+
+function fourValues(property) {
+ var components = property.components;
+ var value1 = components[0].value[0];
+ var value2 = components[1].value[0];
+ var value3 = components[2].value[0];
+ var value4 = components[3].value[0];
+
+ if (value1[1] == value2[1] && value1[1] == value3[1] && value1[1] == value4[1]) {
+ return [value1];
+ } else if (value1[1] == value3[1] && value2[1] == value4[1]) {
+ return [value1, value2];
+ } else if (value2[1] == value4[1]) {
+ return [value1, value2, value3];
+ } else {
+ return [value1, value2, value3, value4];
+ }
+}
+
+function multiplex(restoreWith) {
+ return function (property, compactable) {
+ if (!property.multiplex)
+ return restoreWith(property, compactable, true);
+
+ var multiplexSize = 0;
+ var restored = [];
+ var componentMultiplexSoFar = {};
+ var i, l;
+
+ // At this point we don't know what's the multiplex size, e.g. how many background layers are there
+ for (i = 0, l = property.components[0].value.length; i < l; i++) {
+ if (property.components[0].value[i][1] == Marker.COMMA)
+ multiplexSize++;
+ }
+
+ for (i = 0; i <= multiplexSize; i++) {
+ var _property = shallowClone(property);
+
+ // We split multiplex into parts and restore them one by one
+ for (var j = 0, m = property.components.length; j < m; j++) {
+ var componentToClone = property.components[j];
+ var _component = shallowClone(componentToClone);
+ _property.components.push(_component);
+
+ // The trick is some properties has more than one value, so we iterate over values looking for
+ // a multiplex separator - a comma
+ for (var k = componentMultiplexSoFar[_component.name] || 0, n = componentToClone.value.length; k < n; k++) {
+ if (componentToClone.value[k][1] == Marker.COMMA) {
+ componentMultiplexSoFar[_component.name] = k + 1;
+ break;
+ }
+
+ _component.value.push(componentToClone.value[k]);
+ }
+ }
+
+ // No we can restore shorthand value
+ var lastInMultiplex = i == multiplexSize;
+ var _restored = restoreWith(_property, compactable, lastInMultiplex);
+ Array.prototype.push.apply(restored, _restored);
+
+ if (i < multiplexSize)
+ restored.push([Token.PROPERTY_VALUE, Marker.COMMA]);
+ }
+
+ return restored;
+ };
+}
+
+function withoutDefaults(property, compactable) {
+ var components = property.components;
+ var restored = [];
+
+ for (var i = components.length - 1; i >= 0; i--) {
+ var component = components[i];
+ var descriptor = compactable[component.name];
+
+ if (component.value[0][1] != descriptor.defaultValue)
+ restored.unshift(component.value[0]);
+ }
+
+ if (restored.length === 0)
+ restored.push([Token.PROPERTY_VALUE, compactable[property.name].defaultValue]);
+
+ if (isInheritOnly(restored))
+ return [restored[0]];
+
+ return restored;
+}
+
+module.exports = {
+ background: background,
+ borderRadius: borderRadius,
+ fourValues: fourValues,
+ multiplex: multiplex,
+ withoutDefaults: withoutDefaults
+};
diff --git a/node_modules/clean-css/lib/optimizer/level-2/restructure.js b/node_modules/clean-css/lib/optimizer/level-2/restructure.js
new file mode 100644
index 000000000..2635415ae
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/restructure.js
@@ -0,0 +1,388 @@
+var canReorderSingle = require('./reorderable').canReorderSingle;
+var extractProperties = require('./extract-properties');
+var isMergeable = require('./is-mergeable');
+var tidyRuleDuplicates = require('./tidy-rule-duplicates');
+
+var Token = require('../../tokenizer/token');
+
+var cloneArray = require('../../utils/clone-array');
+
+var serializeBody = require('../../writer/one-time').body;
+var serializeRules = require('../../writer/one-time').rules;
+
+function naturalSorter(a, b) {
+ return a > b ? 1 : -1;
+}
+
+function cloneAndMergeSelectors(propertyA, propertyB) {
+ var cloned = cloneArray(propertyA);
+ cloned[5] = cloned[5].concat(propertyB[5]);
+
+ return cloned;
+}
+
+function restructure(tokens, context) {
+ var options = context.options;
+ var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
+ var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
+ var mergeLimit = 8191;
+ var specificityCache = context.cache.specificity;
+ var movableTokens = {};
+ var movedProperties = [];
+ var multiPropertyMoveCache = {};
+ var movedToBeDropped = [];
+ var maxCombinationsLevel = 2;
+ var ID_JOIN_CHARACTER = '%';
+
+ function sendToMultiPropertyMoveCache(position, movedProperty, allFits) {
+ for (var i = allFits.length - 1; i >= 0; i--) {
+ var fit = allFits[i][0];
+ var id = addToCache(movedProperty, fit);
+
+ if (multiPropertyMoveCache[id].length > 1 && processMultiPropertyMove(position, multiPropertyMoveCache[id])) {
+ removeAllMatchingFromCache(id);
+ break;
+ }
+ }
+ }
+
+ function addToCache(movedProperty, fit) {
+ var id = cacheId(fit);
+ multiPropertyMoveCache[id] = multiPropertyMoveCache[id] || [];
+ multiPropertyMoveCache[id].push([movedProperty, fit]);
+ return id;
+ }
+
+ function removeAllMatchingFromCache(matchId) {
+ var matchSelectors = matchId.split(ID_JOIN_CHARACTER);
+ var forRemoval = [];
+ var i;
+
+ for (var id in multiPropertyMoveCache) {
+ var selectors = id.split(ID_JOIN_CHARACTER);
+ for (i = selectors.length - 1; i >= 0; i--) {
+ if (matchSelectors.indexOf(selectors[i]) > -1) {
+ forRemoval.push(id);
+ break;
+ }
+ }
+ }
+
+ for (i = forRemoval.length - 1; i >= 0; i--) {
+ delete multiPropertyMoveCache[forRemoval[i]];
+ }
+ }
+
+ function cacheId(cachedTokens) {
+ var id = [];
+ for (var i = 0, l = cachedTokens.length; i < l; i++) {
+ id.push(serializeRules(cachedTokens[i][1]));
+ }
+ return id.join(ID_JOIN_CHARACTER);
+ }
+
+ function tokensToMerge(sourceTokens) {
+ var uniqueTokensWithBody = [];
+ var mergeableTokens = [];
+
+ for (var i = sourceTokens.length - 1; i >= 0; i--) {
+ if (!isMergeable(serializeRules(sourceTokens[i][1]), mergeablePseudoClasses, mergeablePseudoElements)) {
+ continue;
+ }
+
+ mergeableTokens.unshift(sourceTokens[i]);
+ if (sourceTokens[i][2].length > 0 && uniqueTokensWithBody.indexOf(sourceTokens[i]) == -1)
+ uniqueTokensWithBody.push(sourceTokens[i]);
+ }
+
+ return uniqueTokensWithBody.length > 1 ?
+ mergeableTokens :
+ [];
+ }
+
+ function shortenIfPossible(position, movedProperty) {
+ var name = movedProperty[0];
+ var value = movedProperty[1];
+ var key = movedProperty[4];
+ var valueSize = name.length + value.length + 1;
+ var allSelectors = [];
+ var qualifiedTokens = [];
+
+ var mergeableTokens = tokensToMerge(movableTokens[key]);
+ if (mergeableTokens.length < 2)
+ return;
+
+ var allFits = findAllFits(mergeableTokens, valueSize, 1);
+ var bestFit = allFits[0];
+ if (bestFit[1] > 0)
+ return sendToMultiPropertyMoveCache(position, movedProperty, allFits);
+
+ for (var i = bestFit[0].length - 1; i >=0; i--) {
+ allSelectors = bestFit[0][i][1].concat(allSelectors);
+ qualifiedTokens.unshift(bestFit[0][i]);
+ }
+
+ allSelectors = tidyRuleDuplicates(allSelectors);
+ dropAsNewTokenAt(position, [movedProperty], allSelectors, qualifiedTokens);
+ }
+
+ function fitSorter(fit1, fit2) {
+ return fit1[1] > fit2[1] ? 1 : (fit1[1] == fit2[1] ? 0 : -1);
+ }
+
+ function findAllFits(mergeableTokens, propertySize, propertiesCount) {
+ var combinations = allCombinations(mergeableTokens, propertySize, propertiesCount, maxCombinationsLevel - 1);
+ return combinations.sort(fitSorter);
+ }
+
+ function allCombinations(tokensVariant, propertySize, propertiesCount, level) {
+ var differenceVariants = [[tokensVariant, sizeDifference(tokensVariant, propertySize, propertiesCount)]];
+ if (tokensVariant.length > 2 && level > 0) {
+ for (var i = tokensVariant.length - 1; i >= 0; i--) {
+ var subVariant = Array.prototype.slice.call(tokensVariant, 0);
+ subVariant.splice(i, 1);
+ differenceVariants = differenceVariants.concat(allCombinations(subVariant, propertySize, propertiesCount, level - 1));
+ }
+ }
+
+ return differenceVariants;
+ }
+
+ function sizeDifference(tokensVariant, propertySize, propertiesCount) {
+ var allSelectorsSize = 0;
+ for (var i = tokensVariant.length - 1; i >= 0; i--) {
+ allSelectorsSize += tokensVariant[i][2].length > propertiesCount ? serializeRules(tokensVariant[i][1]).length : -1;
+ }
+ return allSelectorsSize - (tokensVariant.length - 1) * propertySize + 1;
+ }
+
+ function dropAsNewTokenAt(position, properties, allSelectors, mergeableTokens) {
+ var i, j, k, m;
+ var allProperties = [];
+
+ for (i = mergeableTokens.length - 1; i >= 0; i--) {
+ var mergeableToken = mergeableTokens[i];
+
+ for (j = mergeableToken[2].length - 1; j >= 0; j--) {
+ var mergeableProperty = mergeableToken[2][j];
+
+ for (k = 0, m = properties.length; k < m; k++) {
+ var property = properties[k];
+
+ var mergeablePropertyName = mergeableProperty[1][1];
+ var propertyName = property[0];
+ var propertyBody = property[4];
+ if (mergeablePropertyName == propertyName && serializeBody([mergeableProperty]) == propertyBody) {
+ mergeableToken[2].splice(j, 1);
+ break;
+ }
+ }
+ }
+ }
+
+ for (i = properties.length - 1; i >= 0; i--) {
+ allProperties.unshift(properties[i][3]);
+ }
+
+ var newToken = [Token.RULE, allSelectors, allProperties];
+ tokens.splice(position, 0, newToken);
+ }
+
+ function dropPropertiesAt(position, movedProperty) {
+ var key = movedProperty[4];
+ var toMove = movableTokens[key];
+
+ if (toMove && toMove.length > 1) {
+ if (!shortenMultiMovesIfPossible(position, movedProperty))
+ shortenIfPossible(position, movedProperty);
+ }
+ }
+
+ function shortenMultiMovesIfPossible(position, movedProperty) {
+ var candidates = [];
+ var propertiesAndMergableTokens = [];
+ var key = movedProperty[4];
+ var j, k;
+
+ var mergeableTokens = tokensToMerge(movableTokens[key]);
+ if (mergeableTokens.length < 2)
+ return;
+
+ movableLoop:
+ for (var value in movableTokens) {
+ var tokensList = movableTokens[value];
+
+ for (j = mergeableTokens.length - 1; j >= 0; j--) {
+ if (tokensList.indexOf(mergeableTokens[j]) == -1)
+ continue movableLoop;
+ }
+
+ candidates.push(value);
+ }
+
+ if (candidates.length < 2)
+ return false;
+
+ for (j = candidates.length - 1; j >= 0; j--) {
+ for (k = movedProperties.length - 1; k >= 0; k--) {
+ if (movedProperties[k][4] == candidates[j]) {
+ propertiesAndMergableTokens.unshift([movedProperties[k], mergeableTokens]);
+ break;
+ }
+ }
+ }
+
+ return processMultiPropertyMove(position, propertiesAndMergableTokens);
+ }
+
+ function processMultiPropertyMove(position, propertiesAndMergableTokens) {
+ var valueSize = 0;
+ var properties = [];
+ var property;
+
+ for (var i = propertiesAndMergableTokens.length - 1; i >= 0; i--) {
+ property = propertiesAndMergableTokens[i][0];
+ var fullValue = property[4];
+ valueSize += fullValue.length + (i > 0 ? 1 : 0);
+
+ properties.push(property);
+ }
+
+ var mergeableTokens = propertiesAndMergableTokens[0][1];
+ var bestFit = findAllFits(mergeableTokens, valueSize, properties.length)[0];
+ if (bestFit[1] > 0)
+ return false;
+
+ var allSelectors = [];
+ var qualifiedTokens = [];
+ for (i = bestFit[0].length - 1; i >= 0; i--) {
+ allSelectors = bestFit[0][i][1].concat(allSelectors);
+ qualifiedTokens.unshift(bestFit[0][i]);
+ }
+
+ allSelectors = tidyRuleDuplicates(allSelectors);
+ dropAsNewTokenAt(position, properties, allSelectors, qualifiedTokens);
+
+ for (i = properties.length - 1; i >= 0; i--) {
+ property = properties[i];
+ var index = movedProperties.indexOf(property);
+
+ delete movableTokens[property[4]];
+
+ if (index > -1 && movedToBeDropped.indexOf(index) == -1)
+ movedToBeDropped.push(index);
+ }
+
+ return true;
+ }
+
+ function boundToAnotherPropertyInCurrrentToken(property, movedProperty, token) {
+ var propertyName = property[0];
+ var movedPropertyName = movedProperty[0];
+ if (propertyName != movedPropertyName)
+ return false;
+
+ var key = movedProperty[4];
+ var toMove = movableTokens[key];
+ return toMove && toMove.indexOf(token) > -1;
+ }
+
+ for (var i = tokens.length - 1; i >= 0; i--) {
+ var token = tokens[i];
+ var isRule;
+ var j, k, m;
+ var samePropertyAt;
+
+ if (token[0] == Token.RULE) {
+ isRule = true;
+ } else if (token[0] == Token.NESTED_BLOCK) {
+ isRule = false;
+ } else {
+ continue;
+ }
+
+ // We cache movedProperties.length as it may change in the loop
+ var movedCount = movedProperties.length;
+
+ var properties = extractProperties(token);
+ movedToBeDropped = [];
+
+ var unmovableInCurrentToken = [];
+ for (j = properties.length - 1; j >= 0; j--) {
+ for (k = j - 1; k >= 0; k--) {
+ if (!canReorderSingle(properties[j], properties[k], specificityCache)) {
+ unmovableInCurrentToken.push(j);
+ break;
+ }
+ }
+ }
+
+ for (j = properties.length - 1; j >= 0; j--) {
+ var property = properties[j];
+ var movedSameProperty = false;
+
+ for (k = 0; k < movedCount; k++) {
+ var movedProperty = movedProperties[k];
+
+ if (movedToBeDropped.indexOf(k) == -1 && (!canReorderSingle(property, movedProperty, specificityCache) && !boundToAnotherPropertyInCurrrentToken(property, movedProperty, token) ||
+ movableTokens[movedProperty[4]] && movableTokens[movedProperty[4]].length === mergeLimit)) {
+ dropPropertiesAt(i + 1, movedProperty, token);
+
+ if (movedToBeDropped.indexOf(k) == -1) {
+ movedToBeDropped.push(k);
+ delete movableTokens[movedProperty[4]];
+ }
+ }
+
+ if (!movedSameProperty) {
+ movedSameProperty = property[0] == movedProperty[0] && property[1] == movedProperty[1];
+
+ if (movedSameProperty) {
+ samePropertyAt = k;
+ }
+ }
+ }
+
+ if (!isRule || unmovableInCurrentToken.indexOf(j) > -1)
+ continue;
+
+ var key = property[4];
+
+ if (movedSameProperty && movedProperties[samePropertyAt][5].length + property[5].length > mergeLimit) {
+ dropPropertiesAt(i + 1, movedProperties[samePropertyAt]);
+ movedProperties.splice(samePropertyAt, 1);
+ movableTokens[key] = [token];
+ movedSameProperty = false;
+ } else {
+ movableTokens[key] = movableTokens[key] || [];
+ movableTokens[key].push(token);
+ }
+
+ if (movedSameProperty) {
+ movedProperties[samePropertyAt] = cloneAndMergeSelectors(movedProperties[samePropertyAt], property);
+ } else {
+ movedProperties.push(property);
+ }
+ }
+
+ movedToBeDropped = movedToBeDropped.sort(naturalSorter);
+ for (j = 0, m = movedToBeDropped.length; j < m; j++) {
+ var dropAt = movedToBeDropped[j] - j;
+ movedProperties.splice(dropAt, 1);
+ }
+ }
+
+ var position = tokens[0] && tokens[0][0] == Token.AT_RULE && tokens[0][1].indexOf('@charset') === 0 ? 1 : 0;
+ for (; position < tokens.length - 1; position++) {
+ var isImportRule = tokens[position][0] === Token.AT_RULE && tokens[position][1].indexOf('@import') === 0;
+ var isComment = tokens[position][0] === Token.COMMENT;
+ if (!(isImportRule || isComment))
+ break;
+ }
+
+ for (i = 0; i < movedProperties.length; i++) {
+ dropPropertiesAt(position, movedProperties[i]);
+ }
+}
+
+module.exports = restructure;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/rules-overlap.js b/node_modules/clean-css/lib/optimizer/level-2/rules-overlap.js
new file mode 100644
index 000000000..811a517b2
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/rules-overlap.js
@@ -0,0 +1,32 @@
+var MODIFIER_PATTERN = /\-\-.+$/;
+
+function rulesOverlap(rule1, rule2, bemMode) {
+ var scope1;
+ var scope2;
+ var i, l;
+ var j, m;
+
+ for (i = 0, l = rule1.length; i < l; i++) {
+ scope1 = rule1[i][1];
+
+ for (j = 0, m = rule2.length; j < m; j++) {
+ scope2 = rule2[j][1];
+
+ if (scope1 == scope2) {
+ return true;
+ }
+
+ if (bemMode && withoutModifiers(scope1) == withoutModifiers(scope2)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function withoutModifiers(scope) {
+ return scope.replace(MODIFIER_PATTERN, '');
+}
+
+module.exports = rulesOverlap;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/specificities-overlap.js b/node_modules/clean-css/lib/optimizer/level-2/specificities-overlap.js
new file mode 100644
index 000000000..bde037446
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/specificities-overlap.js
@@ -0,0 +1,34 @@
+var specificity = require('./specificity');
+
+function specificitiesOverlap(selector1, selector2, cache) {
+ var specificity1;
+ var specificity2;
+ var i, l;
+ var j, m;
+
+ for (i = 0, l = selector1.length; i < l; i++) {
+ specificity1 = findSpecificity(selector1[i][1], cache);
+
+ for (j = 0, m = selector2.length; j < m; j++) {
+ specificity2 = findSpecificity(selector2[j][1], cache);
+
+ if (specificity1[0] === specificity2[0] && specificity1[1] === specificity2[1] && specificity1[2] === specificity2[2]) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function findSpecificity(selector, cache) {
+ var value;
+
+ if (!(selector in cache)) {
+ cache[selector] = value = specificity(selector);
+ }
+
+ return value || cache[selector];
+}
+
+module.exports = specificitiesOverlap;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/specificity.js b/node_modules/clean-css/lib/optimizer/level-2/specificity.js
new file mode 100644
index 000000000..bbd224f15
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/specificity.js
@@ -0,0 +1,77 @@
+var Marker = require('../../tokenizer/marker');
+
+var Selector = {
+ ADJACENT_SIBLING: '+',
+ DESCENDANT: '>',
+ DOT: '.',
+ HASH: '#',
+ NON_ADJACENT_SIBLING: '~',
+ PSEUDO: ':'
+};
+
+var LETTER_PATTERN = /[a-zA-Z]/;
+var NOT_PREFIX = ':not(';
+var SEPARATOR_PATTERN = /[\s,\(>~\+]/;
+
+function specificity(selector) {
+ var result = [0, 0, 0];
+ var character;
+ var isEscaped;
+ var isSingleQuoted;
+ var isDoubleQuoted;
+ var roundBracketLevel = 0;
+ var couldIntroduceNewTypeSelector;
+ var withinNotPseudoClass = false;
+ var wasPseudoClass = false;
+ var i, l;
+
+ for (i = 0, l = selector.length; i < l; i++) {
+ character = selector[i];
+
+ if (isEscaped) {
+ // noop
+ } else if (character == Marker.SINGLE_QUOTE && !isDoubleQuoted && !isSingleQuoted) {
+ isSingleQuoted = true;
+ } else if (character == Marker.SINGLE_QUOTE && !isDoubleQuoted && isSingleQuoted) {
+ isSingleQuoted = false;
+ } else if (character == Marker.DOUBLE_QUOTE && !isDoubleQuoted && !isSingleQuoted) {
+ isDoubleQuoted = true;
+ } else if (character == Marker.DOUBLE_QUOTE && isDoubleQuoted && !isSingleQuoted) {
+ isDoubleQuoted = false;
+ } else if (isSingleQuoted || isDoubleQuoted) {
+ continue;
+ } else if (roundBracketLevel > 0 && !withinNotPseudoClass) {
+ // noop
+ } else if (character == Marker.OPEN_ROUND_BRACKET) {
+ roundBracketLevel++;
+ } else if (character == Marker.CLOSE_ROUND_BRACKET && roundBracketLevel == 1) {
+ roundBracketLevel--;
+ withinNotPseudoClass = false;
+ } else if (character == Marker.CLOSE_ROUND_BRACKET) {
+ roundBracketLevel--;
+ } else if (character == Selector.HASH) {
+ result[0]++;
+ } else if (character == Selector.DOT || character == Marker.OPEN_SQUARE_BRACKET) {
+ result[1]++;
+ } else if (character == Selector.PSEUDO && !wasPseudoClass && !isNotPseudoClass(selector, i)) {
+ result[1]++;
+ withinNotPseudoClass = false;
+ } else if (character == Selector.PSEUDO) {
+ withinNotPseudoClass = true;
+ } else if ((i === 0 || couldIntroduceNewTypeSelector) && LETTER_PATTERN.test(character)) {
+ result[2]++;
+ }
+
+ isEscaped = character == Marker.BACK_SLASH;
+ wasPseudoClass = character == Selector.PSEUDO;
+ couldIntroduceNewTypeSelector = !isEscaped && SEPARATOR_PATTERN.test(character);
+ }
+
+ return result;
+}
+
+function isNotPseudoClass(selector, index) {
+ return selector.indexOf(NOT_PREFIX, index) === index;
+}
+
+module.exports = specificity;
diff --git a/node_modules/clean-css/lib/optimizer/level-2/tidy-rule-duplicates.js b/node_modules/clean-css/lib/optimizer/level-2/tidy-rule-duplicates.js
new file mode 100644
index 000000000..30a9c2177
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-2/tidy-rule-duplicates.js
@@ -0,0 +1,21 @@
+function ruleSorter(s1, s2) {
+ return s1[1] > s2[1] ? 1 : -1;
+}
+
+function tidyRuleDuplicates(rules) {
+ var list = [];
+ var repeated = [];
+
+ for (var i = 0, l = rules.length; i < l; i++) {
+ var rule = rules[i];
+
+ if (repeated.indexOf(rule[1]) == -1) {
+ repeated.push(rule[1]);
+ list.push(rule);
+ }
+ }
+
+ return list.sort(ruleSorter);
+}
+
+module.exports = tidyRuleDuplicates;