summaryrefslogtreecommitdiff
path: root/node_modules/csso/lib/restructure/utils.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/csso/lib/restructure/utils.js')
-rw-r--r--node_modules/csso/lib/restructure/utils.js142
1 files changed, 142 insertions, 0 deletions
diff --git a/node_modules/csso/lib/restructure/utils.js b/node_modules/csso/lib/restructure/utils.js
new file mode 100644
index 00000000..792cc59b
--- /dev/null
+++ b/node_modules/csso/lib/restructure/utils.js
@@ -0,0 +1,142 @@
+const { hasOwnProperty } = Object.prototype;
+
+export 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;
+}
+
+export 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;
+}
+
+export 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;
+}
+
+export 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
+export 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
+export 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;
+}