| var walk = require('css-tree').walk; | 
| var utils = require('./utils'); | 
|   | 
| /* | 
|     At this step all rules has single simple selector. We try to join by equal | 
|     declaration blocks to first rule, e.g. | 
|   | 
|     .a { color: red } | 
|     b { ... } | 
|     .b { color: red } | 
|     -> | 
|     .a, .b { color: red } | 
|     b { ... } | 
| */ | 
|   | 
| function processRule(node, item, list) { | 
|     var selectors = node.prelude.children; | 
|     var declarations = node.block.children; | 
|     var nodeCompareMarker = selectors.first().compareMarker; | 
|     var skippedCompareMarkers = {}; | 
|   | 
|     list.nextUntil(item.next, function(next, nextItem) { | 
|         // skip non-ruleset node if safe | 
|         if (next.type !== 'Rule') { | 
|             return utils.unsafeToSkipNode.call(selectors, next); | 
|         } | 
|   | 
|         if (node.pseudoSignature !== next.pseudoSignature) { | 
|             return true; | 
|         } | 
|   | 
|         var nextFirstSelector = next.prelude.children.head; | 
|         var nextDeclarations = next.block.children; | 
|         var nextCompareMarker = nextFirstSelector.data.compareMarker; | 
|   | 
|         // if next ruleset has same marked as one of skipped then stop joining | 
|         if (nextCompareMarker in skippedCompareMarkers) { | 
|             return true; | 
|         } | 
|   | 
|         // try to join by selectors | 
|         if (selectors.head === selectors.tail) { | 
|             if (selectors.first().id === nextFirstSelector.data.id) { | 
|                 declarations.appendList(nextDeclarations); | 
|                 list.remove(nextItem); | 
|                 return; | 
|             } | 
|         } | 
|   | 
|         // try to join by properties | 
|         if (utils.isEqualDeclarations(declarations, nextDeclarations)) { | 
|             var nextStr = nextFirstSelector.data.id; | 
|   | 
|             selectors.some(function(data, item) { | 
|                 var curStr = data.id; | 
|   | 
|                 if (nextStr < curStr) { | 
|                     selectors.insert(nextFirstSelector, item); | 
|                     return true; | 
|                 } | 
|   | 
|                 if (!item.next) { | 
|                     selectors.insert(nextFirstSelector); | 
|                     return true; | 
|                 } | 
|             }); | 
|   | 
|             list.remove(nextItem); | 
|             return; | 
|         } | 
|   | 
|         // go to next ruleset if current one can be skipped (has no equal specificity nor element selector) | 
|         if (nextCompareMarker === nodeCompareMarker) { | 
|             return true; | 
|         } | 
|   | 
|         skippedCompareMarkers[nextCompareMarker] = true; | 
|     }); | 
| } | 
|   | 
| module.exports = function mergeRule(ast) { | 
|     walk(ast, { | 
|         visit: 'Rule', | 
|         enter: processRule | 
|     }); | 
| }; |