index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. "use strict";
  2. var __assign = (this && this.__assign) || function () {
  3. __assign = Object.assign || function(t) {
  4. for (var s, i = 1, n = arguments.length; i < n; i++) {
  5. s = arguments[i];
  6. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  7. t[p] = s[p];
  8. }
  9. return t;
  10. };
  11. return __assign.apply(this, arguments);
  12. };
  13. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  14. if (k2 === undefined) k2 = k;
  15. var desc = Object.getOwnPropertyDescriptor(m, k);
  16. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  17. desc = { enumerable: true, get: function() { return m[k]; } };
  18. }
  19. Object.defineProperty(o, k2, desc);
  20. }) : (function(o, m, k, k2) {
  21. if (k2 === undefined) k2 = k;
  22. o[k2] = m[k];
  23. }));
  24. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  25. Object.defineProperty(o, "default", { enumerable: true, value: v });
  26. }) : function(o, v) {
  27. o["default"] = v;
  28. });
  29. var __importStar = (this && this.__importStar) || function (mod) {
  30. if (mod && mod.__esModule) return mod;
  31. var result = {};
  32. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  33. __setModuleDefault(result, mod);
  34. return result;
  35. };
  36. var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
  37. if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
  38. if (ar || !(i in from)) {
  39. if (!ar) ar = Array.prototype.slice.call(from, 0, i);
  40. ar[i] = from[i];
  41. }
  42. }
  43. return to.concat(ar || Array.prototype.slice.call(from));
  44. };
  45. Object.defineProperty(exports, "__esModule", { value: true });
  46. exports.select = exports.filter = exports.some = exports.is = exports.aliases = exports.pseudos = exports.filters = void 0;
  47. var css_what_1 = require("css-what");
  48. var css_select_1 = require("css-select");
  49. var DomUtils = __importStar(require("domutils"));
  50. var boolbase = __importStar(require("boolbase"));
  51. var helpers_js_1 = require("./helpers.js");
  52. var positionals_js_1 = require("./positionals.js");
  53. // Re-export pseudo extension points
  54. var css_select_2 = require("css-select");
  55. Object.defineProperty(exports, "filters", { enumerable: true, get: function () { return css_select_2.filters; } });
  56. Object.defineProperty(exports, "pseudos", { enumerable: true, get: function () { return css_select_2.pseudos; } });
  57. Object.defineProperty(exports, "aliases", { enumerable: true, get: function () { return css_select_2.aliases; } });
  58. var UNIVERSAL_SELECTOR = {
  59. type: css_what_1.SelectorType.Universal,
  60. namespace: null,
  61. };
  62. var SCOPE_PSEUDO = {
  63. type: css_what_1.SelectorType.Pseudo,
  64. name: "scope",
  65. data: null,
  66. };
  67. function is(element, selector, options) {
  68. if (options === void 0) { options = {}; }
  69. return some([element], selector, options);
  70. }
  71. exports.is = is;
  72. function some(elements, selector, options) {
  73. if (options === void 0) { options = {}; }
  74. if (typeof selector === "function")
  75. return elements.some(selector);
  76. var _a = (0, helpers_js_1.groupSelectors)((0, css_what_1.parse)(selector)), plain = _a[0], filtered = _a[1];
  77. return ((plain.length > 0 && elements.some((0, css_select_1._compileToken)(plain, options))) ||
  78. filtered.some(function (sel) { return filterBySelector(sel, elements, options).length > 0; }));
  79. }
  80. exports.some = some;
  81. function filterByPosition(filter, elems, data, options) {
  82. var num = typeof data === "string" ? parseInt(data, 10) : NaN;
  83. switch (filter) {
  84. case "first":
  85. case "lt":
  86. // Already done in `getLimit`
  87. return elems;
  88. case "last":
  89. return elems.length > 0 ? [elems[elems.length - 1]] : elems;
  90. case "nth":
  91. case "eq":
  92. return isFinite(num) && Math.abs(num) < elems.length
  93. ? [num < 0 ? elems[elems.length + num] : elems[num]]
  94. : [];
  95. case "gt":
  96. return isFinite(num) ? elems.slice(num + 1) : [];
  97. case "even":
  98. return elems.filter(function (_, i) { return i % 2 === 0; });
  99. case "odd":
  100. return elems.filter(function (_, i) { return i % 2 === 1; });
  101. case "not": {
  102. var filtered_1 = new Set(filterParsed(data, elems, options));
  103. return elems.filter(function (e) { return !filtered_1.has(e); });
  104. }
  105. }
  106. }
  107. function filter(selector, elements, options) {
  108. if (options === void 0) { options = {}; }
  109. return filterParsed((0, css_what_1.parse)(selector), elements, options);
  110. }
  111. exports.filter = filter;
  112. /**
  113. * Filter a set of elements by a selector.
  114. *
  115. * Will return elements in the original order.
  116. *
  117. * @param selector Selector to filter by.
  118. * @param elements Elements to filter.
  119. * @param options Options for selector.
  120. */
  121. function filterParsed(selector, elements, options) {
  122. if (elements.length === 0)
  123. return [];
  124. var _a = (0, helpers_js_1.groupSelectors)(selector), plainSelectors = _a[0], filteredSelectors = _a[1];
  125. var found;
  126. if (plainSelectors.length) {
  127. var filtered = filterElements(elements, plainSelectors, options);
  128. // If there are no filters, just return
  129. if (filteredSelectors.length === 0) {
  130. return filtered;
  131. }
  132. // Otherwise, we have to do some filtering
  133. if (filtered.length) {
  134. found = new Set(filtered);
  135. }
  136. }
  137. for (var i = 0; i < filteredSelectors.length && (found === null || found === void 0 ? void 0 : found.size) !== elements.length; i++) {
  138. var filteredSelector = filteredSelectors[i];
  139. var missing = found
  140. ? elements.filter(function (e) { return DomUtils.isTag(e) && !found.has(e); })
  141. : elements;
  142. if (missing.length === 0)
  143. break;
  144. var filtered = filterBySelector(filteredSelector, elements, options);
  145. if (filtered.length) {
  146. if (!found) {
  147. /*
  148. * If we haven't found anything before the last selector,
  149. * just return what we found now.
  150. */
  151. if (i === filteredSelectors.length - 1) {
  152. return filtered;
  153. }
  154. found = new Set(filtered);
  155. }
  156. else {
  157. filtered.forEach(function (el) { return found.add(el); });
  158. }
  159. }
  160. }
  161. return typeof found !== "undefined"
  162. ? (found.size === elements.length
  163. ? elements
  164. : // Filter elements to preserve order
  165. elements.filter(function (el) {
  166. return found.has(el);
  167. }))
  168. : [];
  169. }
  170. function filterBySelector(selector, elements, options) {
  171. var _a;
  172. if (selector.some(css_what_1.isTraversal)) {
  173. /*
  174. * Get root node, run selector with the scope
  175. * set to all of our nodes.
  176. */
  177. var root = (_a = options.root) !== null && _a !== void 0 ? _a : (0, helpers_js_1.getDocumentRoot)(elements[0]);
  178. var opts = __assign(__assign({}, options), { context: elements, relativeSelector: false });
  179. selector.push(SCOPE_PSEUDO);
  180. return findFilterElements(root, selector, opts, true, elements.length);
  181. }
  182. // Performance optimization: If we don't have to traverse, just filter set.
  183. return findFilterElements(elements, selector, options, false, elements.length);
  184. }
  185. function select(selector, root, options, limit) {
  186. if (options === void 0) { options = {}; }
  187. if (limit === void 0) { limit = Infinity; }
  188. if (typeof selector === "function") {
  189. return find(root, selector);
  190. }
  191. var _a = (0, helpers_js_1.groupSelectors)((0, css_what_1.parse)(selector)), plain = _a[0], filtered = _a[1];
  192. var results = filtered.map(function (sel) {
  193. return findFilterElements(root, sel, options, true, limit);
  194. });
  195. // Plain selectors can be queried in a single go
  196. if (plain.length) {
  197. results.push(findElements(root, plain, options, limit));
  198. }
  199. if (results.length === 0) {
  200. return [];
  201. }
  202. // If there was only a single selector, just return the result
  203. if (results.length === 1) {
  204. return results[0];
  205. }
  206. // Sort results, filtering for duplicates
  207. return DomUtils.uniqueSort(results.reduce(function (a, b) { return __spreadArray(__spreadArray([], a, true), b, true); }));
  208. }
  209. exports.select = select;
  210. /**
  211. *
  212. * @param root Element(s) to search from.
  213. * @param selector Selector to look for.
  214. * @param options Options for querying.
  215. * @param queryForSelector Query multiple levels deep for the initial selector, even if it doesn't contain a traversal.
  216. */
  217. function findFilterElements(root, selector, options, queryForSelector, totalLimit) {
  218. var filterIndex = selector.findIndex(positionals_js_1.isFilter);
  219. var sub = selector.slice(0, filterIndex);
  220. var filter = selector[filterIndex];
  221. // If we are at the end of the selector, we can limit the number of elements to retrieve.
  222. var partLimit = selector.length - 1 === filterIndex ? totalLimit : Infinity;
  223. /*
  224. * Set the number of elements to retrieve.
  225. * Eg. for :first, we only have to get a single element.
  226. */
  227. var limit = (0, positionals_js_1.getLimit)(filter.name, filter.data, partLimit);
  228. if (limit === 0)
  229. return [];
  230. /*
  231. * Skip `findElements` call if our selector starts with a positional
  232. * pseudo.
  233. */
  234. var elemsNoLimit = sub.length === 0 && !Array.isArray(root)
  235. ? DomUtils.getChildren(root).filter(DomUtils.isTag)
  236. : sub.length === 0
  237. ? (Array.isArray(root) ? root : [root]).filter(DomUtils.isTag)
  238. : queryForSelector || sub.some(css_what_1.isTraversal)
  239. ? findElements(root, [sub], options, limit)
  240. : filterElements(root, [sub], options);
  241. var elems = elemsNoLimit.slice(0, limit);
  242. var result = filterByPosition(filter.name, elems, filter.data, options);
  243. if (result.length === 0 || selector.length === filterIndex + 1) {
  244. return result;
  245. }
  246. var remainingSelector = selector.slice(filterIndex + 1);
  247. var remainingHasTraversal = remainingSelector.some(css_what_1.isTraversal);
  248. if (remainingHasTraversal) {
  249. if ((0, css_what_1.isTraversal)(remainingSelector[0])) {
  250. var type = remainingSelector[0].type;
  251. if (type === css_what_1.SelectorType.Sibling ||
  252. type === css_what_1.SelectorType.Adjacent) {
  253. // If we have a sibling traversal, we need to also look at the siblings.
  254. result = (0, css_select_1.prepareContext)(result, DomUtils, true);
  255. }
  256. // Avoid a traversal-first selector error.
  257. remainingSelector.unshift(UNIVERSAL_SELECTOR);
  258. }
  259. options = __assign(__assign({}, options), {
  260. // Avoid absolutizing the selector
  261. relativeSelector: false,
  262. /*
  263. * Add a custom root func, to make sure traversals don't match elements
  264. * that aren't a part of the considered tree.
  265. */
  266. rootFunc: function (el) { return result.includes(el); } });
  267. }
  268. else if (options.rootFunc && options.rootFunc !== boolbase.trueFunc) {
  269. options = __assign(__assign({}, options), { rootFunc: boolbase.trueFunc });
  270. }
  271. /*
  272. * If we have another filter, recursively call `findFilterElements`,
  273. * with the `recursive` flag disabled. We only have to look for more
  274. * elements when we see a traversal.
  275. *
  276. * Otherwise,
  277. */
  278. return remainingSelector.some(positionals_js_1.isFilter)
  279. ? findFilterElements(result, remainingSelector, options, false, totalLimit)
  280. : remainingHasTraversal
  281. ? // Query existing elements to resolve traversal.
  282. findElements(result, [remainingSelector], options, totalLimit)
  283. : // If we don't have any more traversals, simply filter elements.
  284. filterElements(result, [remainingSelector], options);
  285. }
  286. function findElements(root, sel, options, limit) {
  287. var query = (0, css_select_1._compileToken)(sel, options, root);
  288. return find(root, query, limit);
  289. }
  290. function find(root, query, limit) {
  291. if (limit === void 0) { limit = Infinity; }
  292. var elems = (0, css_select_1.prepareContext)(root, DomUtils, query.shouldTestNextSiblings);
  293. return DomUtils.find(function (node) { return DomUtils.isTag(node) && query(node); }, elems, true, limit);
  294. }
  295. function filterElements(elements, sel, options) {
  296. var els = (Array.isArray(elements) ? elements : [elements]).filter(DomUtils.isTag);
  297. if (els.length === 0)
  298. return els;
  299. var query = (0, css_select_1._compileToken)(sel, options);
  300. return query === boolbase.trueFunc ? els : els.filter(query);
  301. }
  302. //# sourceMappingURL=index.js.map