| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 | 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    });};
 |