[6a3a178] | 1 | var hasOwnProperty = Object.prototype.hasOwnProperty;
|
---|
| 2 |
|
---|
| 3 | function isEqualSelectors(a, b) {
|
---|
| 4 | var cursor1 = a.head;
|
---|
| 5 | var cursor2 = b.head;
|
---|
| 6 |
|
---|
| 7 | while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {
|
---|
| 8 | cursor1 = cursor1.next;
|
---|
| 9 | cursor2 = cursor2.next;
|
---|
| 10 | }
|
---|
| 11 |
|
---|
| 12 | return cursor1 === null && cursor2 === null;
|
---|
| 13 | }
|
---|
| 14 |
|
---|
| 15 | function isEqualDeclarations(a, b) {
|
---|
| 16 | var cursor1 = a.head;
|
---|
| 17 | var cursor2 = b.head;
|
---|
| 18 |
|
---|
| 19 | while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {
|
---|
| 20 | cursor1 = cursor1.next;
|
---|
| 21 | cursor2 = cursor2.next;
|
---|
| 22 | }
|
---|
| 23 |
|
---|
| 24 | return cursor1 === null && cursor2 === null;
|
---|
| 25 | }
|
---|
| 26 |
|
---|
| 27 | function compareDeclarations(declarations1, declarations2) {
|
---|
| 28 | var result = {
|
---|
| 29 | eq: [],
|
---|
| 30 | ne1: [],
|
---|
| 31 | ne2: [],
|
---|
| 32 | ne2overrided: []
|
---|
| 33 | };
|
---|
| 34 |
|
---|
| 35 | var fingerprints = Object.create(null);
|
---|
| 36 | var declarations2hash = Object.create(null);
|
---|
| 37 |
|
---|
| 38 | for (var cursor = declarations2.head; cursor; cursor = cursor.next) {
|
---|
| 39 | declarations2hash[cursor.data.id] = true;
|
---|
| 40 | }
|
---|
| 41 |
|
---|
| 42 | for (var cursor = declarations1.head; cursor; cursor = cursor.next) {
|
---|
| 43 | var data = cursor.data;
|
---|
| 44 |
|
---|
| 45 | if (data.fingerprint) {
|
---|
| 46 | fingerprints[data.fingerprint] = data.important;
|
---|
| 47 | }
|
---|
| 48 |
|
---|
| 49 | if (declarations2hash[data.id]) {
|
---|
| 50 | declarations2hash[data.id] = false;
|
---|
| 51 | result.eq.push(data);
|
---|
| 52 | } else {
|
---|
| 53 | result.ne1.push(data);
|
---|
| 54 | }
|
---|
| 55 | }
|
---|
| 56 |
|
---|
| 57 | for (var cursor = declarations2.head; cursor; cursor = cursor.next) {
|
---|
| 58 | var data = cursor.data;
|
---|
| 59 |
|
---|
| 60 | if (declarations2hash[data.id]) {
|
---|
| 61 | // when declarations1 has an overriding declaration, this is not a difference
|
---|
| 62 | // unless no !important is used on prev and !important is used on the following
|
---|
| 63 | if (!hasOwnProperty.call(fingerprints, data.fingerprint) ||
|
---|
| 64 | (!fingerprints[data.fingerprint] && data.important)) {
|
---|
| 65 | result.ne2.push(data);
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | result.ne2overrided.push(data);
|
---|
| 69 | }
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | return result;
|
---|
| 73 | }
|
---|
| 74 |
|
---|
| 75 | function addSelectors(dest, source) {
|
---|
| 76 | source.each(function(sourceData) {
|
---|
| 77 | var newStr = sourceData.id;
|
---|
| 78 | var cursor = dest.head;
|
---|
| 79 |
|
---|
| 80 | while (cursor) {
|
---|
| 81 | var nextStr = cursor.data.id;
|
---|
| 82 |
|
---|
| 83 | if (nextStr === newStr) {
|
---|
| 84 | return;
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | if (nextStr > newStr) {
|
---|
| 88 | break;
|
---|
| 89 | }
|
---|
| 90 |
|
---|
| 91 | cursor = cursor.next;
|
---|
| 92 | }
|
---|
| 93 |
|
---|
| 94 | dest.insert(dest.createItem(sourceData), cursor);
|
---|
| 95 | });
|
---|
| 96 |
|
---|
| 97 | return dest;
|
---|
| 98 | }
|
---|
| 99 |
|
---|
| 100 | // check if simpleselectors has no equal specificity and element selector
|
---|
| 101 | function hasSimilarSelectors(selectors1, selectors2) {
|
---|
| 102 | var cursor1 = selectors1.head;
|
---|
| 103 |
|
---|
| 104 | while (cursor1 !== null) {
|
---|
| 105 | var cursor2 = selectors2.head;
|
---|
| 106 |
|
---|
| 107 | while (cursor2 !== null) {
|
---|
| 108 | if (cursor1.data.compareMarker === cursor2.data.compareMarker) {
|
---|
| 109 | return true;
|
---|
| 110 | }
|
---|
| 111 |
|
---|
| 112 | cursor2 = cursor2.next;
|
---|
| 113 | }
|
---|
| 114 |
|
---|
| 115 | cursor1 = cursor1.next;
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | return false;
|
---|
| 119 | }
|
---|
| 120 |
|
---|
| 121 | // test node can't to be skipped
|
---|
| 122 | function unsafeToSkipNode(node) {
|
---|
| 123 | switch (node.type) {
|
---|
| 124 | case 'Rule':
|
---|
| 125 | // unsafe skip ruleset with selector similarities
|
---|
| 126 | return hasSimilarSelectors(node.prelude.children, this);
|
---|
| 127 |
|
---|
| 128 | case 'Atrule':
|
---|
| 129 | // can skip at-rules with blocks
|
---|
| 130 | if (node.block) {
|
---|
| 131 | // unsafe skip at-rule if block contains something unsafe to skip
|
---|
| 132 | return node.block.children.some(unsafeToSkipNode, this);
|
---|
| 133 | }
|
---|
| 134 | break;
|
---|
| 135 |
|
---|
| 136 | case 'Declaration':
|
---|
| 137 | return false;
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 | // unsafe by default
|
---|
| 141 | return true;
|
---|
| 142 | }
|
---|
| 143 |
|
---|
| 144 | module.exports = {
|
---|
| 145 | isEqualSelectors: isEqualSelectors,
|
---|
| 146 | isEqualDeclarations: isEqualDeclarations,
|
---|
| 147 | compareDeclarations: compareDeclarations,
|
---|
| 148 | addSelectors: addSelectors,
|
---|
| 149 | hasSimilarSelectors: hasSimilarSelectors,
|
---|
| 150 | unsafeToSkipNode: unsafeToSkipNode
|
---|
| 151 | };
|
---|