querying.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { isTag, hasChildren } from "domhandler";
  2. /**
  3. * Search a node and its children for nodes passing a test function.
  4. *
  5. * @category Querying
  6. * @param test Function to test nodes on.
  7. * @param node Node to search. Will be included in the result set if it matches.
  8. * @param recurse Also consider child nodes.
  9. * @param limit Maximum number of nodes to return.
  10. * @returns All nodes passing `test`.
  11. */
  12. export function filter(test, node, recurse = true, limit = Infinity) {
  13. if (!Array.isArray(node))
  14. node = [node];
  15. return find(test, node, recurse, limit);
  16. }
  17. /**
  18. * Search an array of node and its children for nodes passing a test function.
  19. *
  20. * @category Querying
  21. * @param test Function to test nodes on.
  22. * @param nodes Array of nodes to search.
  23. * @param recurse Also consider child nodes.
  24. * @param limit Maximum number of nodes to return.
  25. * @returns All nodes passing `test`.
  26. */
  27. export function find(test, nodes, recurse, limit) {
  28. const result = [];
  29. for (const elem of nodes) {
  30. if (test(elem)) {
  31. result.push(elem);
  32. if (--limit <= 0)
  33. break;
  34. }
  35. if (recurse && hasChildren(elem) && elem.children.length > 0) {
  36. const children = find(test, elem.children, recurse, limit);
  37. result.push(...children);
  38. limit -= children.length;
  39. if (limit <= 0)
  40. break;
  41. }
  42. }
  43. return result;
  44. }
  45. /**
  46. * Finds the first element inside of an array that matches a test function.
  47. *
  48. * @category Querying
  49. * @param test Function to test nodes on.
  50. * @param nodes Array of nodes to search.
  51. * @returns The first node in the array that passes `test`.
  52. * @deprecated Use `Array.prototype.find` directly.
  53. */
  54. export function findOneChild(test, nodes) {
  55. return nodes.find(test);
  56. }
  57. /**
  58. * Finds one element in a tree that passes a test.
  59. *
  60. * @category Querying
  61. * @param test Function to test nodes on.
  62. * @param nodes Array of nodes to search.
  63. * @param recurse Also consider child nodes.
  64. * @returns The first child node that passes `test`.
  65. */
  66. export function findOne(test, nodes, recurse = true) {
  67. let elem = null;
  68. for (let i = 0; i < nodes.length && !elem; i++) {
  69. const checked = nodes[i];
  70. if (!isTag(checked)) {
  71. continue;
  72. }
  73. else if (test(checked)) {
  74. elem = checked;
  75. }
  76. else if (recurse && checked.children.length > 0) {
  77. elem = findOne(test, checked.children, true);
  78. }
  79. }
  80. return elem;
  81. }
  82. /**
  83. * @category Querying
  84. * @param test Function to test nodes on.
  85. * @param nodes Array of nodes to search.
  86. * @returns Whether a tree of nodes contains at least one node passing the test.
  87. */
  88. export function existsOne(test, nodes) {
  89. return nodes.some((checked) => isTag(checked) &&
  90. (test(checked) ||
  91. (checked.children.length > 0 &&
  92. existsOne(test, checked.children))));
  93. }
  94. /**
  95. * Search and array of nodes and its children for elements passing a test function.
  96. *
  97. * Same as `find`, but limited to elements and with less options, leading to reduced complexity.
  98. *
  99. * @category Querying
  100. * @param test Function to test nodes on.
  101. * @param nodes Array of nodes to search.
  102. * @returns All nodes passing `test`.
  103. */
  104. export function findAll(test, nodes) {
  105. var _a;
  106. const result = [];
  107. const stack = nodes.filter(isTag);
  108. let elem;
  109. while ((elem = stack.shift())) {
  110. const children = (_a = elem.children) === null || _a === void 0 ? void 0 : _a.filter(isTag);
  111. if (children && children.length > 0) {
  112. stack.unshift(...children);
  113. }
  114. if (test(elem))
  115. result.push(elem);
  116. }
  117. return result;
  118. }
  119. //# sourceMappingURL=querying.js.map