querying.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.findAll = exports.existsOne = exports.findOne = exports.findOneChild = exports.find = exports.filter = void 0;
  4. var domhandler_1 = require("domhandler");
  5. /**
  6. * Search a node and its children for nodes passing a test function. If `node` is not an array, it will be wrapped in one.
  7. *
  8. * @category Querying
  9. * @param test Function to test nodes on.
  10. * @param node Node to search. Will be included in the result set if it matches.
  11. * @param recurse Also consider child nodes.
  12. * @param limit Maximum number of nodes to return.
  13. * @returns All nodes passing `test`.
  14. */
  15. function filter(test, node, recurse, limit) {
  16. if (recurse === void 0) { recurse = true; }
  17. if (limit === void 0) { limit = Infinity; }
  18. return find(test, Array.isArray(node) ? node : [node], recurse, limit);
  19. }
  20. exports.filter = filter;
  21. /**
  22. * Search an array of nodes and their children for nodes passing a test function.
  23. *
  24. * @category Querying
  25. * @param test Function to test nodes on.
  26. * @param nodes Array of nodes to search.
  27. * @param recurse Also consider child nodes.
  28. * @param limit Maximum number of nodes to return.
  29. * @returns All nodes passing `test`.
  30. */
  31. function find(test, nodes, recurse, limit) {
  32. var result = [];
  33. /** Stack of the arrays we are looking at. */
  34. var nodeStack = [nodes];
  35. /** Stack of the indices within the arrays. */
  36. var indexStack = [0];
  37. for (;;) {
  38. // First, check if the current array has any more elements to look at.
  39. if (indexStack[0] >= nodeStack[0].length) {
  40. // If we have no more arrays to look at, we are done.
  41. if (indexStack.length === 1) {
  42. return result;
  43. }
  44. // Otherwise, remove the current array from the stack.
  45. nodeStack.shift();
  46. indexStack.shift();
  47. // Loop back to the start to continue with the next array.
  48. continue;
  49. }
  50. var elem = nodeStack[0][indexStack[0]++];
  51. if (test(elem)) {
  52. result.push(elem);
  53. if (--limit <= 0)
  54. return result;
  55. }
  56. if (recurse && (0, domhandler_1.hasChildren)(elem) && elem.children.length > 0) {
  57. /*
  58. * Add the children to the stack. We are depth-first, so this is
  59. * the next array we look at.
  60. */
  61. indexStack.unshift(0);
  62. nodeStack.unshift(elem.children);
  63. }
  64. }
  65. }
  66. exports.find = find;
  67. /**
  68. * Finds the first element inside of an array that matches a test function. This is an alias for `Array.prototype.find`.
  69. *
  70. * @category Querying
  71. * @param test Function to test nodes on.
  72. * @param nodes Array of nodes to search.
  73. * @returns The first node in the array that passes `test`.
  74. * @deprecated Use `Array.prototype.find` directly.
  75. */
  76. function findOneChild(test, nodes) {
  77. return nodes.find(test);
  78. }
  79. exports.findOneChild = findOneChild;
  80. /**
  81. * Finds one element in a tree that passes a test.
  82. *
  83. * @category Querying
  84. * @param test Function to test nodes on.
  85. * @param nodes Node or array of nodes to search.
  86. * @param recurse Also consider child nodes.
  87. * @returns The first node that passes `test`.
  88. */
  89. function findOne(test, nodes, recurse) {
  90. if (recurse === void 0) { recurse = true; }
  91. var elem = null;
  92. for (var i = 0; i < nodes.length && !elem; i++) {
  93. var node = nodes[i];
  94. if (!(0, domhandler_1.isTag)(node)) {
  95. continue;
  96. }
  97. else if (test(node)) {
  98. elem = node;
  99. }
  100. else if (recurse && node.children.length > 0) {
  101. elem = findOne(test, node.children, true);
  102. }
  103. }
  104. return elem;
  105. }
  106. exports.findOne = findOne;
  107. /**
  108. * Checks if a tree of nodes contains at least one node passing a test.
  109. *
  110. * @category Querying
  111. * @param test Function to test nodes on.
  112. * @param nodes Array of nodes to search.
  113. * @returns Whether a tree of nodes contains at least one node passing the test.
  114. */
  115. function existsOne(test, nodes) {
  116. return nodes.some(function (checked) {
  117. return (0, domhandler_1.isTag)(checked) &&
  118. (test(checked) || existsOne(test, checked.children));
  119. });
  120. }
  121. exports.existsOne = existsOne;
  122. /**
  123. * Search an array of nodes and their children for elements passing a test function.
  124. *
  125. * Same as `find`, but limited to elements and with less options, leading to reduced complexity.
  126. *
  127. * @category Querying
  128. * @param test Function to test nodes on.
  129. * @param nodes Array of nodes to search.
  130. * @returns All nodes passing `test`.
  131. */
  132. function findAll(test, nodes) {
  133. var result = [];
  134. var nodeStack = [nodes];
  135. var indexStack = [0];
  136. for (;;) {
  137. if (indexStack[0] >= nodeStack[0].length) {
  138. if (nodeStack.length === 1) {
  139. return result;
  140. }
  141. // Otherwise, remove the current array from the stack.
  142. nodeStack.shift();
  143. indexStack.shift();
  144. // Loop back to the start to continue with the next array.
  145. continue;
  146. }
  147. var elem = nodeStack[0][indexStack[0]++];
  148. if (!(0, domhandler_1.isTag)(elem))
  149. continue;
  150. if (test(elem))
  151. result.push(elem);
  152. if (elem.children.length > 0) {
  153. indexStack.unshift(0);
  154. nodeStack.unshift(elem.children);
  155. }
  156. }
  157. }
  158. exports.findAll = findAll;
  159. //# sourceMappingURL=querying.js.map