helpers.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.uniqueSort = exports.compareDocumentPosition = exports.removeSubsets = void 0;
  4. var domhandler_1 = require("domhandler");
  5. /**
  6. * Given an array of nodes, remove any member that is contained by another.
  7. *
  8. * @param nodes Nodes to filter.
  9. * @returns Remaining nodes that aren't subtrees of each other.
  10. */
  11. function removeSubsets(nodes) {
  12. var idx = nodes.length;
  13. /*
  14. * Check if each node (or one of its ancestors) is already contained in the
  15. * array.
  16. */
  17. while (--idx >= 0) {
  18. var node = nodes[idx];
  19. /*
  20. * Remove the node if it is not unique.
  21. * We are going through the array from the end, so we only
  22. * have to check nodes that preceed the node under consideration in the array.
  23. */
  24. if (idx > 0 && nodes.lastIndexOf(node, idx - 1) >= 0) {
  25. nodes.splice(idx, 1);
  26. continue;
  27. }
  28. for (var ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
  29. if (nodes.includes(ancestor)) {
  30. nodes.splice(idx, 1);
  31. break;
  32. }
  33. }
  34. }
  35. return nodes;
  36. }
  37. exports.removeSubsets = removeSubsets;
  38. /**
  39. * Compare the position of one node against another node in any other document.
  40. * The return value is a bitmask with the following values:
  41. *
  42. * Document order:
  43. * > There is an ordering, document order, defined on all the nodes in the
  44. * > document corresponding to the order in which the first character of the
  45. * > XML representation of each node occurs in the XML representation of the
  46. * > document after expansion of general entities. Thus, the document element
  47. * > node will be the first node. Element nodes occur before their children.
  48. * > Thus, document order orders element nodes in order of the occurrence of
  49. * > their start-tag in the XML (after expansion of entities). The attribute
  50. * > nodes of an element occur after the element and before its children. The
  51. * > relative order of attribute nodes is implementation-dependent./
  52. *
  53. * Source:
  54. * http://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-document-order
  55. *
  56. * @param nodeA The first node to use in the comparison
  57. * @param nodeB The second node to use in the comparison
  58. * @returns A bitmask describing the input nodes' relative position.
  59. *
  60. * See http://dom.spec.whatwg.org/#dom-node-comparedocumentposition for
  61. * a description of these values.
  62. */
  63. function compareDocumentPosition(nodeA, nodeB) {
  64. var aParents = [];
  65. var bParents = [];
  66. if (nodeA === nodeB) {
  67. return 0;
  68. }
  69. var current = (0, domhandler_1.hasChildren)(nodeA) ? nodeA : nodeA.parent;
  70. while (current) {
  71. aParents.unshift(current);
  72. current = current.parent;
  73. }
  74. current = (0, domhandler_1.hasChildren)(nodeB) ? nodeB : nodeB.parent;
  75. while (current) {
  76. bParents.unshift(current);
  77. current = current.parent;
  78. }
  79. var maxIdx = Math.min(aParents.length, bParents.length);
  80. var idx = 0;
  81. while (idx < maxIdx && aParents[idx] === bParents[idx]) {
  82. idx++;
  83. }
  84. if (idx === 0) {
  85. return 1 /* DISCONNECTED */;
  86. }
  87. var sharedParent = aParents[idx - 1];
  88. var siblings = sharedParent.children;
  89. var aSibling = aParents[idx];
  90. var bSibling = bParents[idx];
  91. if (siblings.indexOf(aSibling) > siblings.indexOf(bSibling)) {
  92. if (sharedParent === nodeB) {
  93. return 4 /* FOLLOWING */ | 16 /* CONTAINED_BY */;
  94. }
  95. return 4 /* FOLLOWING */;
  96. }
  97. if (sharedParent === nodeA) {
  98. return 2 /* PRECEDING */ | 8 /* CONTAINS */;
  99. }
  100. return 2 /* PRECEDING */;
  101. }
  102. exports.compareDocumentPosition = compareDocumentPosition;
  103. /**
  104. * Sort an array of nodes based on their relative position in the document and
  105. * remove any duplicate nodes. If the array contains nodes that do not belong
  106. * to the same document, sort order is unspecified.
  107. *
  108. * @param nodes Array of DOM nodes.
  109. * @returns Collection of unique nodes, sorted in document order.
  110. */
  111. function uniqueSort(nodes) {
  112. nodes = nodes.filter(function (node, i, arr) { return !arr.includes(node, i + 1); });
  113. nodes.sort(function (a, b) {
  114. var relative = compareDocumentPosition(a, b);
  115. if (relative & 2 /* PRECEDING */) {
  116. return -1;
  117. }
  118. else if (relative & 4 /* FOLLOWING */) {
  119. return 1;
  120. }
  121. return 0;
  122. });
  123. return nodes;
  124. }
  125. exports.uniqueSort = uniqueSort;