utils.js 3.9 KB

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