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. // if declarations1 has overriding declaration, this is not a difference
  48. // but take in account !important - prev should be equal or greater than follow
  49. if (hasOwnProperty.call(fingerprints, data.fingerprint) &&
  50. Number(fingerprints[data.fingerprint]) >= Number(data.important)) {
  51. result.ne2overrided.push(data);
  52. } else {
  53. result.ne2.push(data);
  54. }
  55. }
  56. }
  57. return result;
  58. }
  59. function addSelectors(dest, source) {
  60. source.each(function(sourceData) {
  61. var newStr = sourceData.id;
  62. var cursor = dest.head;
  63. while (cursor) {
  64. var nextStr = cursor.data.id;
  65. if (nextStr === newStr) {
  66. return;
  67. }
  68. if (nextStr > newStr) {
  69. break;
  70. }
  71. cursor = cursor.next;
  72. }
  73. dest.insert(dest.createItem(sourceData), cursor);
  74. });
  75. return dest;
  76. }
  77. // check if simpleselectors has no equal specificity and element selector
  78. function hasSimilarSelectors(selectors1, selectors2) {
  79. var cursor1 = selectors1.head;
  80. while (cursor1 !== null) {
  81. var cursor2 = selectors2.head;
  82. while (cursor2 !== null) {
  83. if (cursor1.data.compareMarker === cursor2.data.compareMarker) {
  84. return true;
  85. }
  86. cursor2 = cursor2.next;
  87. }
  88. cursor1 = cursor1.next;
  89. }
  90. return false;
  91. }
  92. // test node can't to be skipped
  93. function unsafeToSkipNode(node) {
  94. switch (node.type) {
  95. case 'Rule':
  96. // unsafe skip ruleset with selector similarities
  97. return hasSimilarSelectors(node.prelude.children, this);
  98. case 'Atrule':
  99. // can skip at-rules with blocks
  100. if (node.block) {
  101. // unsafe skip at-rule if block contains something unsafe to skip
  102. return node.block.children.some(unsafeToSkipNode, this);
  103. }
  104. break;
  105. case 'Declaration':
  106. return false;
  107. }
  108. // unsafe by default
  109. return true;
  110. }
  111. module.exports = {
  112. isEqualSelectors: isEqualSelectors,
  113. isEqualDeclarations: isEqualDeclarations,
  114. compareDeclarations: compareDeclarations,
  115. addSelectors: addSelectors,
  116. hasSimilarSelectors: hasSimilarSelectors,
  117. unsafeToSkipNode: unsafeToSkipNode
  118. };