Spaces:
Configuration error
Configuration error
; | |
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; | |