diff options
Diffstat (limited to 'node_modules/csso/lib/compressor/restructure/utils.js')
| -rw-r--r-- | node_modules/csso/lib/compressor/restructure/utils.js | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/node_modules/csso/lib/compressor/restructure/utils.js b/node_modules/csso/lib/compressor/restructure/utils.js new file mode 100644 index 00000000..70c92c51 --- /dev/null +++ b/node_modules/csso/lib/compressor/restructure/utils.js @@ -0,0 +1,141 @@ +var hasOwnProperty = Object.prototype.hasOwnProperty; + +function isEqualLists(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.value.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]) { + // if declarations1 has overriding declaration, this is not a difference + // but take in account !important - prev should be equal or greater than follow + if (hasOwnProperty.call(fingerprints, data.fingerprint) && + Number(fingerprints[data.fingerprint]) >= Number(data.value.important)) { + result.ne2overrided.push(data); + } else { + result.ne2.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 selector +function hasSimilarSelectors(selectors1, selectors2) { + return selectors1.some(function(a) { + return selectors2.some(function(b) { + return a.compareMarker === b.compareMarker; + }); + }); +} + +// test node can't to be skipped +function unsafeToSkipNode(node) { + switch (node.type) { + case 'Ruleset': + // unsafe skip ruleset with selector similarities + return hasSimilarSelectors(node.selector.selectors, this); + + case 'Atrule': + // can skip at-rules with blocks + if (node.block) { + // non-stylesheet blocks are safe to skip since have no selectors + if (node.block.type !== 'StyleSheet') { + return false; + } + + // unsafe skip at-rule if block contains something unsafe to skip + return node.block.rules.some(unsafeToSkipNode, this); + } + break; + } + + // unsafe by default + return true; +} + +module.exports = { + isEqualLists: isEqualLists, + isEqualDeclarations: isEqualDeclarations, + compareDeclarations: compareDeclarations, + addSelectors: addSelectors, + hasSimilarSelectors: hasSimilarSelectors, + unsafeToSkipNode: unsafeToSkipNode +}; |
