152 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| var hasOwnProperty = Object.prototype.hasOwnProperty;
 | |
| 
 | |
| function isEqualSelectors(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.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]) {
 | |
|             // 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.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) {
 | |
|     var cursor1 = selectors1.head;
 | |
| 
 | |
|     while (cursor1 !== null) {
 | |
|         var 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;
 | |
| }
 | |
| 
 | |
| module.exports = {
 | |
|     isEqualSelectors: isEqualSelectors,
 | |
|     isEqualDeclarations: isEqualDeclarations,
 | |
|     compareDeclarations: compareDeclarations,
 | |
|     addSelectors: addSelectors,
 | |
|     hasSimilarSelectors: hasSimilarSelectors,
 | |
|     unsafeToSkipNode: unsafeToSkipNode
 | |
| };
 |