diff options
Diffstat (limited to 'node_modules/csso/cjs/restructure/utils.cjs')
| -rw-r--r-- | node_modules/csso/cjs/restructure/utils.cjs | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/node_modules/csso/cjs/restructure/utils.cjs b/node_modules/csso/cjs/restructure/utils.cjs new file mode 100644 index 00000000..cd66a6a8 --- /dev/null +++ b/node_modules/csso/cjs/restructure/utils.cjs @@ -0,0 +1,151 @@ +'use strict'; + +const { hasOwnProperty } = Object.prototype; + +function isEqualSelectors(a, b) { + let cursor1 = a.head; + let 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) { + let cursor1 = a.head; + let 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) { + const result = { + eq: [], + ne1: [], + ne2: [], + ne2overrided: [] + }; + + const fingerprints = Object.create(null); + const declarations2hash = Object.create(null); + + for (let cursor = declarations2.head; cursor; cursor = cursor.next) { + declarations2hash[cursor.data.id] = true; + } + + for (let cursor = declarations1.head; cursor; cursor = cursor.next) { + const 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 (let cursor = declarations2.head; cursor; cursor = cursor.next) { + const 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.forEach((sourceData) => { + const newStr = sourceData.id; + let cursor = dest.head; + + while (cursor) { + const 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) { + let cursor1 = selectors1.head; + + while (cursor1 !== null) { + let 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 skipped +function 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; +} + +exports.addSelectors = addSelectors; +exports.compareDeclarations = compareDeclarations; +exports.hasSimilarSelectors = hasSimilarSelectors; +exports.isEqualDeclarations = isEqualDeclarations; +exports.isEqualSelectors = isEqualSelectors; +exports.unsafeToSkipNode = unsafeToSkipNode; |
