+var compactable = require('./compactable');
+var deepClone = require('./clone').deep;
+var populateComponents = require('./populate-components');
+var wrapSingle = require('./wrap-for-optimizing').single;
-// // Compacts the tokens by transforming properties into their shorthand notations when possible
-
-// module.exports = (function () {
-// var isHackValue = function (t) { return t.value === '__hack'; };
-
-// var compactShorthands = function(tokens, isImportant, processable, Token) {
-// // Contains the components found so far, grouped by shorthand name
-// var componentsSoFar = { };
-
-// // Initializes a prop in componentsSoFar
-// var initSoFar = function (shprop, last, clearAll) {
-// var found = {};
-// var shorthandPosition;
-
-// if (!clearAll && componentsSoFar[shprop]) {
-// for (var i = 0; i < processable[shprop].components.length; i++) {
-// var prop = processable[shprop].components[i];
-// found[prop] = [];
-
-// if (!(componentsSoFar[shprop].found[prop]))
-// continue;
-
-// for (var ii = 0; ii < componentsSoFar[shprop].found[prop].length; ii++) {
-// var comp = componentsSoFar[shprop].found[prop][ii];
-
-// if (comp.trashed)
-// continue;
-
-// found[prop].push(comp);
-
-// if (comp.position && (!shorthandPosition || comp.position < shorthandPosition))
-// shorthandPosition = comp.position;
-// }
-// }
-// }
-// componentsSoFar[shprop] = {
-// lastShorthand: last,
-// found: found,
-// shorthandPosition: shorthandPosition
-// };
-// };
-
-// // Adds a component to componentsSoFar
-// var addComponentSoFar = function (token, index) {
-// var shprop = processable[token.name].componentOf;
-// if (!componentsSoFar[shprop])
-// initSoFar(shprop);
-// if (!componentsSoFar[shprop].found[token.name])
-// componentsSoFar[shprop].found[token.name] = [];
-
-// // Add the newfound component to componentsSoFar
-// componentsSoFar[shprop].found[token.name].push(token);
-
-// if (!componentsSoFar[shprop].shorthandPosition && index) {
-// // If the haven't decided on where the shorthand should go, put it in the place of this component
-// componentsSoFar[shprop].shorthandPosition = index;
-// }
-// };
-
-// // Tries to compact a prop in componentsSoFar
-// var compactSoFar = function (prop) {
-// var i;
-// var componentsCount = processable[prop].components.length;
-
-// // Check basics
-// if (!componentsSoFar[prop] || !componentsSoFar[prop].found)
-// return false;
-
-// // Find components for the shorthand
-// var components = [];
-// var realComponents = [];
-// for (i = 0 ; i < componentsCount; i++) {
-// // Get property name
-// var pp = processable[prop].components[i];
-
-// if (componentsSoFar[prop].found[pp] && componentsSoFar[prop].found[pp].length) {
-// // We really found it
-// var foundRealComp = componentsSoFar[prop].found[pp][0];
-// components.push(foundRealComp);
-// if (foundRealComp.real !== false) {
-// realComponents.push(foundRealComp);
-// }
-// } else if (componentsSoFar[prop].lastShorthand) {
-// // It's defined in the previous shorthand
-// var c = componentsSoFar[prop].lastShorthand.components[i].clone(isImportant);
-// components.push(c);
-// } else {
-// // Couldn't find this component at all
-// return false;
-// }
-// }
-
-// if (realComponents.length === 0) {
-// // Couldn't find enough components, sorry
-// return false;
-// }
-
-// if (realComponents.length === componentsCount) {
-// // When all the components are from real values, only allow shorthanding if their understandability allows it
-// // This is the case when every component can override their default values, or when all of them use the same function
-
-// var canOverrideDefault = true;
-// var functionNameMatches = true;
-// var functionName;
-
-// for (var ci = 0; ci < realComponents.length; ci++) {
-// var rc = realComponents[ci];
-
-// if (!processable[rc.name].canOverride(processable[rc.name].defaultValue, rc.value)) {
-// canOverrideDefault = false;
-// }
-// var iop = rc.value.indexOf('(');
-// if (iop >= 0) {
-// var otherFunctionName = rc.value.substring(0, iop);
-// if (functionName)
-// functionNameMatches = functionNameMatches && otherFunctionName === functionName;
-// else
-// functionName = otherFunctionName;
-// }
-// }
-
-// if (!canOverrideDefault || !functionNameMatches)
-// return false;
-// }
-
-// // Compact the components into a shorthand
-// var compacted = processable[prop].putTogether(prop, components, isImportant);
-// if (!(compacted instanceof Array)) {
-// compacted = [compacted];
-// }
-
-// var compactedLength = Token.getDetokenizedLength(compacted);
-// var authenticLength = Token.getDetokenizedLength(realComponents);
-
-// if (realComponents.length === componentsCount || compactedLength < authenticLength || components.some(isHackValue)) {
-// compacted[0].isShorthand = true;
-// compacted[0].components = processable[prop].breakUp(compacted[0]);
-
-// // Mark the granular components for deletion
-// for (i = 0; i < realComponents.length; i++) {
-// realComponents[i].isMarkedForDeletion = true;
-// }
-
-// // Mark the position of the new shorthand
-// tokens[componentsSoFar[prop].shorthandPosition].replaceWith = compacted;
-
-// // Reinitialize the thing for further compacting
-// initSoFar(prop, compacted[0]);
-// for (i = 1; i < compacted.length; i++) {
-// addComponentSoFar(compacted[i]);
-// }
-
-// // Yes, we can keep the new shorthand!
-// return true;
-// }
-
-// return false;
-// };
-
-// // Tries to compact all properties currently in componentsSoFar
-// var compactAllSoFar = function () {
-// for (var i in componentsSoFar) {
-// if (componentsSoFar.hasOwnProperty(i)) {
-// while (compactSoFar(i)) { }
-// }
-// }
-// };
-
-// var i, token;
-
-// // Go through each token and collect components for each shorthand as we go on
-// for (i = 0; i < tokens.length; i++) {
-// token = tokens[i];
-// if (token.trashed) {
-// continue;
-// }
-// if (!processable[token.name]) {
-// // We don't know what it is, move on
-// continue;
-// }
-// if (processable[token.name].isShorthand) {
-// // Found an instance of a full shorthand
-// // NOTE: we should NOT mix together tokens that come before and after the shorthands
-
-// if (token.important === isImportant || (token.important && !isImportant)) {
-// // Try to compact what we've found so far
-// while (compactSoFar(token.name)) { }
-// // Reset
-// initSoFar(token.name, token, true);
-// }
-
-// // TODO: when the old optimizer is removed, take care of this corner case:
-// // div{background-color:#111;background-image:url(aaa);background:linear-gradient(aaa);background-repeat:no-repeat;background-position:1px 2px;background-attachment:scroll}
-// // -> should not be shorthanded / minified at all because the result wouldn't be equivalent to the original in any browser
-// } else if (processable[token.name].componentOf) {
-// // Found a component of a shorthand
-// if (token.important === isImportant) {
-// // Same importantness
-// token.position = i;
-// addComponentSoFar(token, i);
-// } else if (!isImportant && token.important) {
-// // Use importants for optimalization opportunities
-// // https://github.com/jakubpawlowicz/clean-css/issues/184
-// var importantTrickComp = new Token(token.name, token.value, isImportant);
-// importantTrickComp.irrelevant = true;
-// importantTrickComp.real = false;
-// addComponentSoFar(importantTrickComp);
-// }
-// } else {
-// // This is not a shorthand and not a component, don't care about it
-// continue;
-// }
-// }
-
-// // Perform all possible compactions
-// compactAllSoFar();
-
-// // Process the results - throw away stuff marked for deletion, insert compacted things, etc.
-// var result = [];
-// for (i = 0; i < tokens.length; i++) {
-// token = tokens[i];
-
-// if (token.replaceWith) {
-// for (var ii = 0; ii < token.replaceWith.length; ii++) {
-// result.push(token.replaceWith[ii]);
-// }
-// }
-// if (!token.trashed) {
-// result.push(token);
-// }
-
-// token.trashed = false;
-// token.replaceWith = null;
-// }
-
-// return result;
-// };
-
-// return {
-// compactShorthands: compactShorthands
-// };
-
-// })();
+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 replaceWithShorthand(properties, candidateComponents, name, validator) {
+ var descriptor = compactable[name];
+ var newValuePlaceholder = [[name, false, false], [descriptor.defaultValue]];
+ 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]];
+ var canOverride = compactable[component.name].canOverride;
+
+ if (!canOverride(newProperty.components[i], component, validator))
+ return;
+
+ newProperty.components[i] = deepClone(component);
+ newProperty.important = component.important;
+
+ all = component.all;
+ }
+
+ for (var componentName in candidateComponents) {
+ candidateComponents[componentName].unused = true;
+ }
+
+ newProperty.position = all.length;
+ newProperty.all = all;
+ newProperty.all.push(newValuePlaceholder);
+ newValuePlaceholder[0][1] = newProperty.important;
+
+ 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 compactShortands(properties, compatibility, validator) {
+ var candidates = {};
+
+ for (var i = 0, l = properties.length; i < l; i++) {
+ var property = properties[i];
+ if (property.unused)
+ continue;
+
+ var descriptor = compactable[property.name];
+ if (!descriptor || !descriptor.componentOf)
+ continue;
+
+ if (property.shorthand) {
+ invalidateOrCompact(properties, i, candidates, validator);
+ } else {
+ var componentOf = descriptor.componentOf;
+ candidates[componentOf] = candidates[componentOf] || {};
+ candidates[componentOf][property.name] = property;
+ }
+ }
+
+ invalidateOrCompact(properties, i, candidates, validator);
+}
+
+module.exports = compactShortands;
-// 'shorthand properties': cssContext({
-// 'shorthand background #1' : [
-// 'div{background-color:#111;background-image:url(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}',
-// 'div{background:url(aaa)#111}'
-// ],
-// 'shorthand background #2' : [
-// 'div{background-color:#111;background-image:url(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}',
-// 'div{background:url(aaa)no-repeat #111}'
-// ],
-// 'shorthand important background' : [
-// 'div{background-color:#111!important;background-image:url(aaa)!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important;background-size:auto!important;background-origin:padding-box!important;background-clip:border-box!important}',
-// 'div{background:url(aaa)#111!important}'
-// ],
-// 'shorthand important background overriding': [
-// 'a{background:url(a.jpg) !important; background-color:#fff !important}',
-// 'a{background:url(a.jpg)#fff!important}'
-// ],
-// 'shorthand important background overriding by non-mergeable property': [
-// 'a{background:url(a.jpg) !important; background-color:#fff !important; background-size:10px 10px !important}',
-// 'a{background:url(a.jpg)#fff!important;background-size:10px 10px!important}'
-// ],
-// 'shorthand background-repeat correctly': [
-// 'a{background:url(/image/path.png) no-repeat repeat}',
-// 'a{background:url(/image/path.png)no-repeat repeat}'
-// ],
-// 'shorthand border-width': [
-// '.t{border-top-width:7px;border-bottom-width:7px;border-left-width:4px;border-right-width:4px}',
-// '.t{border-width:7px 4px}'
-// ],
-// 'shorthand border-color #1': [
-// '.t{border-top-color:#9fce00;border-bottom-color:#9fce00;border-left-color:#9fce00;border-right-color:#9fce00}',
-// '.t{border-color:#9fce00}'
-// ],
-// 'shorthand border-color #2': [
-// '.t{border-right-color:#002;border-bottom-color:#003;border-top-color:#001;border-left-color:#004}',
-// '.t{border-color:#001 #002 #003 #004}'
-// ],
-// 'shorthand border-radius': [
-// '.t{border-top-left-radius:7px;border-bottom-right-radius:6px;border-bottom-left-radius:5px;border-top-right-radius:3px}',
-// '.t{border-radius:7px 3px 6px 5px}'
-// ],
-// 'shorthand border-radius none': 'li{border-radius:none}',
-// 'shorthand list-style #1': [
-// '.t{list-style-type:circle;list-style-position:outside;list-style-image:url(aaa)}',
-// '.t{list-style:circle url(aaa)}'
-// ],
-// 'shorthand list-style #2': [
-// '.t{list-style-image:url(aaa);list-style-type:circle;list-style-position:inside}',
-// '.t{list-style:circle inside url(aaa)}'
-// ]
-// }),
-// 'cares about understandability of shorthand components': cssContext({
-// 'linear-gradient should NOT clear out background with color only' : [
-// 'div{background:#fff;background:linear-gradient(whatever)}',
-// 'div{background:#fff;background:linear-gradient(whatever)}'
-// ],
-// 'linear-gradient should NOT clear out background with color only, even if it has a color' : [
-// 'div{background:#fff;background:linear-gradient(whatever) #222}',
-// 'div{background:#fff;background:linear-gradient(whatever)#222}'
-// ],
-// 'a background-image with just a linear-gradient should not be compacted to a shorthand' : [
-// 'div{background-color:#111;background-image:linear-gradient(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll}',
-// 'div{background-color:#111;background-image:linear-gradient(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll}'
-// ],
-// 'a background-image with a none and a linear-gradient should result in two shorthands' : [
-// 'div{background-color:#111;background-image:none;background-image:linear-gradient(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}',
-// 'div{background:#111;background:linear-gradient(aaa)#111}'
-// ]
-// }),
-// 'cares about understandability of border components': cssContext({
-// 'border(none) with border(rgba)': 'a{border:none;border:1px solid rgba(1,0,0,.5)}',
-// 'border(rgba) with border(none)': 'a{border:1px solid rgba(1,0,0,.5);border:none}',
-// 'border(hex) with border(rgba)': 'a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)}'
-// }),
-// 'merge same properties sensibly': cssContext({
-// 'should merge color values with same understandability #1': [
-// 'p{color:red;color:#fff;color:blue}',
-// 'p{color:#00f}'
-// ],
-// 'should merge color values with same understandability #2': [
-// 'p{color:red;color:#fff;color:blue;color:transparent}',
-// 'p{color:transparent}'
-// ],
-// 'should NOT destroy less understandable values': [
-// 'p{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4)}',
-// 'p{color:#00f;color:rgba(1,2,3,.4)}'
-// ],
-// 'should destroy even less understandable values if a more understandable one comes after them': [
-// 'p{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4);color:#9fce00}',
-// 'p{color:#9fce00}'
-// ],
-// 'should merge functions with the same name but keep different functions intact': [
-// 'p{background:-webkit-linear-gradient(aaa);background:-webkit-linear-gradient(bbb);background:linear-gradient(aaa);}',
-// 'p{background:-webkit-linear-gradient(bbb);background:linear-gradient(aaa)}'
-// ],
-// 'should merge nonimportant + important into one important': [
-// 'a{color:#aaa;color:#bbb!important}',
-// 'a{color:#bbb!important}'
-// ],
-// 'should merge important + nonimportant into one important': [
-// 'a{color:#aaa!important;color:#bbb}',
-// 'a{color:#aaa!important}'
-// ],
-// 'should merge importants just like nonimportants while also overriding them': [
-// 'p{color:red!important;color:#fff!important;color:blue!important;color:rgba(1,2,3,.4)}',
-// 'p{color:#00f!important}'
-// ]
-// }),
-// 'shorthand granular properties when other granular properties are already covered by the shorthand': cssContext({
-// 'should consider the already existing margin to shorthand margin-top and margin-bottom': [
-// 'p{margin:5px;margin-top:foo(1);margin-left:foo(2)}',
-// 'p{margin:5px;margin:foo(1)5px 5px foo(2)}'
-// ],
-// 'should merge margin-top and margin-left with shorthand if their understandability is the same': [
-// 'p{margin:5px;margin-top:1px;margin-left:2px}',
-// 'p{margin:1px 5px 5px 2px}'
-// ],
-// 'should NOT shorthand to margin-top if the result would be longer than the input': [
-// 'p{margin:5px;margin-top:foo(1)}',
-// 'p{margin:5px;margin-top:foo(1)}'
-// ],
-// 'should consider the already existing background to shorthand background-color': [
-// 'p{background:#9fce00;background-color:rgba(1,2,3,.4)}',
-// 'p{background:#9fce00;background:rgba(1,2,3,.4)}'
-// ],
-// 'should NOT touch important outline-color but should minify default value of outline to 0': [
-// 'p{outline:medium;outline-color:#9fce00!important}',
-// 'p{outline:0;outline-color:#9fce00!important}'
-// ]
-// }),
-// 'take advantage of importants for optimalization opportunities': cssContext({
-// 'should take into account important margin-left to shorthand non-important margin-top, margin-right and margin-bottom': [
-// 'p{margin-top:1px;margin-right:2px;margin-bottom:3px;margin-left:4px !important}',
-// 'p{margin:1px 2px 3px;margin-left:4px!important}'
-// ],
-// 'should take into account important margin-bottom and margin-left to shorten shorthanded non-important margin-top and margin-bottom': [
-// 'p{margin-top:1px;margin-right:2px;margin-bottom:3px!important;margin-left:4px !important}',
-// 'p{margin:1px 2px;margin-bottom:3px!important;margin-left:4px!important}'
-// ],
-// 'should take into account important margin-right and margin-left to shorten shorthanded non-important margin-top and margin-bottom': [
-// 'p{margin-top:1px;margin-bottom:3px;margin-right:2px!important;margin-left:4px !important}',
-// 'p{margin:1px 0 3px;margin-right:2px!important;margin-left:4px!important}'
-// ],
-// 'should take into account important margin-right and margin-left to shorten shorthanded non-important margin-top and margin-bottom #2': [
-// 'p{margin-top:1px;margin-bottom:1px;margin-right:2px!important;margin-left:4px !important}',
-// 'p{margin:1px;margin-right:2px!important;margin-left:4px!important}'
-// ],
-// 'should take into account important background-color and shorthand others into background': [
-// 'p{background-color:#9fce00!important;background-image:url(hello);background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y;background-size:auto;background-origin:padding-box;background-clip:border-box}',
-// 'p{background-color:#9fce00!important;background:url(hello)1px 2px repeat-y}'
-// ],
-// 'should take into account important outline-color and default value of outline-width': [
-// 'p{outline:inset medium;outline-color:#9fce00!important;outline-style:inset!important}',
-// 'p{outline:0;outline-color:#9fce00!important;outline-style:inset!important}'
-// ],
-// 'should take into account important background-position remove its irrelevant counterpart': [
-// 'p{background:#9fce00 url(hello) 4px 5px;background-position:5px 3px!important}',
-// 'p{background:url(hello)#9fce00;background-position:5px 3px!important}'
-// ],
-// 'should take into account important background-position and assign the shortest possible value for its irrelevant counterpart': [
-// 'p{background:transparent;background-position:5px 3px!important}',
-// 'p{background:0;background-position:5px 3px!important}'
-// ]
-// }),
-// 'properly care about inherit': cssContext({
-// 'merge multiple inherited margin granular properties into one inherited shorthand': [
-// 'p{margin-top:inherit;margin-right:inherit;margin-bottom:inherit;margin-left:inherit}',
-// 'p{margin:inherit}'
-// ],
-// 'merge multiple inherited background granular properties into one inherited shorthand': [
-// 'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:inherit;;background-size:inherit;background-origin:inherit;background-clip:inherit}',
-// 'p{background:inherit}'
-// ],
-// 'when shorter, optimize inherited/non-inherited background granular properties into an inherited shorthand and some non-inherited granular properties': [
-// 'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:repeat-y;background-size:inherit;background-origin:inherit;background-clip:inherit}',
-// 'p{background:inherit;background-repeat:repeat-y}'
-// ],
-// 'when shorter, optimize inherited/non-inherited background granular properties into a non-inherited shorthand and some inherited granular properties': [
-// 'p{background-color:#9fce00;background-image:inherit;background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y;background-size:auto;background-clip:inherit;background-origin:padding-box;}',
-// 'p{background:1px 2px repeat-y #9fce00;background-image:inherit;background-clip:inherit}'
-// ],
-// 'put inherit to the place where it consumes the least space': [
-// 'div{padding:0;padding-bottom:inherit;padding-right:inherit}',
-// 'div{padding:inherit;padding-top:0;padding-left:0}'
-// ]
-// }),
-// 'complex granular properties': cssContext({
-// 'two granular properties': 'a{border-bottom:1px solid red;border-color:red}',
-// 'more understandable granular property should override less understandable': [
-// 'a{border-color:rgba(0,0,0,.5);border-color:red}',
-// 'a{border-color:red}'
-// ],
-// 'less understandable granular property should NOT override more understandable': [
-// 'a{border-color:red;border-color:rgba(0,0,0,.5)}',
-// 'a{border-color:red;border-color:rgba(0,0,0,.5)}'
-// ],
-// 'two same granular properties redefined': [
-// 'a{border-color:rgba(0,0,0,.5);border-color:red;border:0}',
-// 'a{border:0}'
-// ],
-// 'important granular property redefined': 'a{border-color:red!important;border:0}',
-// 'important granular property redefined with important': [
-// 'a{border-color:red!important;border:0!important}',
-// 'a{border:0!important}'
-// ],
-// 'mix of border properties': [
-// 'a{border-top:1px solid red;border-top-color:#0f0;color:red;border-top-width:2px;border-bottom-width:1px;border:0;border-left:1px solid red}',
-// 'a{color:red;border:0;border-left:1px solid red}'
-// ]
-// }),
+var vows = require('vows');
+var assert = require('assert');
+
+var optimize = require('../../lib/properties/optimizer');
+
+var Tokenizer = require('../../lib/selectors/tokenizer');
+var SourceTracker = require('../../lib/utils/source-tracker');
+var Compatibility = require('../../lib/utils/compatibility');
+var Validator = require('../../lib/properties/validator');
+var addOptimizationMetadata = require('../../lib/selectors/optimization-metadata');
+
+function _optimize(source) {
+ var tokens = new Tokenizer({
+ options: {},
+ sourceTracker: new SourceTracker(),
+ warnings: []
+ }).toTokens(source);
+
+ var compatibility = new Compatibility(compatibility).toOptions();
+ var validator = new Validator(compatibility);
+ var options = {
+ aggressiveMerging: true,
+ compatibility: compatibility,
+ shorthandCompacting: true
+ };
+ addOptimizationMetadata(tokens);
+ optimize(tokens[0][1], tokens[0][2], false, true, options, validator);
+
+ return tokens[0][2];
+}
+
+vows.describe(optimize)
+ .addBatch({
+ 'shorthand background #1': {
+ 'topic': 'p{background-color:#111;background-image:__ESCAPED_URL_CLEAN_CSS0__;background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['background', false , false], ['__ESCAPED_URL_CLEAN_CSS0__'], ['#111']]
+ ]);
+ }
+ },
+ 'shorthand background #2': {
+ 'topic': 'p{background-color:#111;background-image:__ESCAPED_URL_CLEAN_CSS0__;background-repeat:no-repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['background', false , false], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], ['#111']]
+ ]);
+ }
+ },
+ 'shorthand important background': {
+ 'topic': 'p{background-color:#111!important;background-image:__ESCAPED_URL_CLEAN_CSS0__!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important;background-size:auto!important;background-origin:padding-box!important;background-clip:border-box!important}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['background', true , false], ['__ESCAPED_URL_CLEAN_CSS0__'], ['#111']]
+ ]);
+ }
+ },
+ 'shorthand border-width': {
+ 'topic': 'p{border-top-width:7px;border-bottom-width:7px;border-left-width:4px;border-right-width:4px}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['border-width', false , false], ['7px'], ['4px']]
+ ]);
+ }
+ },
+ 'shorthand border-color #1': {
+ 'topic': 'p{border-top-color:#9fce00;border-bottom-color:#9fce00;border-left-color:#9fce00;border-right-color:#9fce00}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['border-color', false , false], ['#9fce00']]
+ ]);
+ }
+ },
+ 'shorthand border-color #2': {
+ 'topic': 'p{border-right-color:#002;border-bottom-color:#003;border-top-color:#001;border-left-color:#004}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['border-color', false , false], ['#001'], ['#002'], ['#003'], ['#004']]
+ ]);
+ }
+ },
+ 'shorthand border-radius': {
+ 'topic': 'p{border-top-left-radius:7px;border-bottom-right-radius:6px;border-bottom-left-radius:5px;border-top-right-radius:3px}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['border-radius', false , false], ['7px'], ['3px'], ['6px'], ['5px']]
+ ]);
+ }
+ },
+ 'shorthand list-style #1': {
+ 'topic': 'a{list-style-type:circle;list-style-position:outside;list-style-image:__ESCAPED_URL_CLEAN_CSS0__}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['list-style', false , false], ['circle'], ['__ESCAPED_URL_CLEAN_CSS0__']]
+ ]);
+ }
+ },
+ 'shorthand list-style #2': {
+ 'topic': 'a{list-style-image:__ESCAPED_URL_CLEAN_CSS0__;list-style-type:circle;list-style-position:inside}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['list-style', false , false], ['circle'], ['inside'], ['__ESCAPED_URL_CLEAN_CSS0__']]
+ ]);
+ }
+ },
+ 'shorthand margin': {
+ 'topic': 'a{margin-top:10px;margin-right:5px;margin-bottom:3px;margin-left:2px}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['margin', false , false], ['10px'], ['5px'], ['3px'], ['2px']]
+ ]);
+ }
+ },
+ 'shorthand padding': {
+ 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:2px}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['padding', false , false], ['10px'], ['2px'], ['3px'], ['5px']]
+ ]);
+ }
+ },
+ 'mixed': {
+ 'topic': 'a{padding-top:10px;margin-top:3px;padding-left:5px;margin-left:3px;padding-bottom:3px;margin-bottom:3px;padding-right:2px;margin-right:3px}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['padding', false , false], ['10px'], ['2px'], ['3px'], ['5px']],
+ [['margin', false , false], ['3px']]
+ ]);
+ }
+ },
+ 'with other properties': {
+ 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;color:red;padding-right:2px;width:100px}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['color', false , false], ['red']],
+ [['width', false , false], ['100px']],
+ [['padding', false , false], ['10px'], ['2px'], ['3px'], ['5px']]
+ ]);
+ }
+ }
+ })
+ .addBatch({
+ 'not enough components': {
+ 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['padding-top', false , false], ['10px']],
+ [['padding-left', false , false], ['5px']],
+ [['padding-bottom', false , false], ['3px']]
+ ]);
+ }
+ },
+ 'mixed importance': {
+ 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:2px!important}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['padding-top', false , false], ['10px']],
+ [['padding-left', false , false], ['5px']],
+ [['padding-bottom', false , false], ['3px']],
+ [['padding-right', true , false], ['2px']]
+ ]);
+ }
+ },
+ 'mixed understandability of units': {
+ 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:calc(100% - 20px)}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['padding-top', false , false], ['10px']],
+ [['padding-left', false , false], ['5px']],
+ [['padding-bottom', false , false], ['3px']],
+ [['padding-right', false , false], ['calc(100% - 20px)']]
+ ]);
+ }
+ },
+ 'mixed understandability of images': {
+ 'topic': 'p{background-color:#111;background-image:linear-gradient(sth);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}',
+ 'into': function (topic) {
+ assert.deepEqual(_optimize(topic), [
+ [['background-color', false , false], ['#111']],
+ [['background-image', false , false], ['linear-gradient(sth)']],
+ [['background-repeat', false , false], ['repeat']],
+ [['background-position', false , false], ['0'], ['0']],
+ [['background-attachment', false , false], ['scroll']],
+ [['background-size', false , false], ['auto']],
+ [['background-origin', false , false], ['padding-box']],
+ [['background-clip', false , false], ['border-box']]
+ ]);
+ }
+ }
+ })
+ .export(module);