87 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
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
 | 
						|
    });
 | 
						|
};
 |