| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 | var hasOwnProperty = Object.prototype.hasOwnProperty;function isEqualSelectors(a, b) {    var cursor1 = a.head;    var cursor2 = b.head;    while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {        cursor1 = cursor1.next;        cursor2 = cursor2.next;    }    return cursor1 === null && cursor2 === null;}function isEqualDeclarations(a, b) {    var cursor1 = a.head;    var cursor2 = b.head;    while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {        cursor1 = cursor1.next;        cursor2 = cursor2.next;    }    return cursor1 === null && cursor2 === null;}function compareDeclarations(declarations1, declarations2) {    var result = {        eq: [],        ne1: [],        ne2: [],        ne2overrided: []    };    var fingerprints = Object.create(null);    var declarations2hash = Object.create(null);    for (var cursor = declarations2.head; cursor; cursor = cursor.next)  {        declarations2hash[cursor.data.id] = true;    }    for (var cursor = declarations1.head; cursor; cursor = cursor.next)  {        var data = cursor.data;        if (data.fingerprint) {            fingerprints[data.fingerprint] = data.important;        }        if (declarations2hash[data.id]) {            declarations2hash[data.id] = false;            result.eq.push(data);        } else {            result.ne1.push(data);        }    }    for (var cursor = declarations2.head; cursor; cursor = cursor.next)  {        var data = cursor.data;        if (declarations2hash[data.id]) {            // when declarations1 has an overriding declaration, this is not a difference            // unless no !important is used on prev and !important is used on the following            if (!hasOwnProperty.call(fingerprints, data.fingerprint) ||                (!fingerprints[data.fingerprint] && data.important)) {                result.ne2.push(data);            }            result.ne2overrided.push(data);        }    }    return result;}function addSelectors(dest, source) {    source.each(function(sourceData) {        var newStr = sourceData.id;        var cursor = dest.head;        while (cursor) {            var nextStr = cursor.data.id;            if (nextStr === newStr) {                return;            }            if (nextStr > newStr) {                break;            }            cursor = cursor.next;        }        dest.insert(dest.createItem(sourceData), cursor);    });    return dest;}// check if simpleselectors has no equal specificity and element selectorfunction hasSimilarSelectors(selectors1, selectors2) {    var cursor1 = selectors1.head;    while (cursor1 !== null) {        var cursor2 = selectors2.head;        while (cursor2 !== null) {            if (cursor1.data.compareMarker === cursor2.data.compareMarker) {                return true;            }            cursor2 = cursor2.next;        }        cursor1 = cursor1.next;    }    return false;}// test node can't to be skippedfunction unsafeToSkipNode(node) {    switch (node.type) {        case 'Rule':            // unsafe skip ruleset with selector similarities            return hasSimilarSelectors(node.prelude.children, this);        case 'Atrule':            // can skip at-rules with blocks            if (node.block) {                // unsafe skip at-rule if block contains something unsafe to skip                return node.block.children.some(unsafeToSkipNode, this);            }            break;        case 'Declaration':            return false;    }    // unsafe by default    return true;}module.exports = {    isEqualSelectors: isEqualSelectors,    isEqualDeclarations: isEqualDeclarations,    compareDeclarations: compareDeclarations,    addSelectors: addSelectors,    hasSimilarSelectors: hasSimilarSelectors,    unsafeToSkipNode: unsafeToSkipNode};
 |