traversing.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. "use strict";
  2. /**
  3. * Methods for traversing the DOM structure.
  4. *
  5. * @module cheerio/traversing
  6. */
  7. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  8. if (k2 === undefined) k2 = k;
  9. var desc = Object.getOwnPropertyDescriptor(m, k);
  10. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  11. desc = { enumerable: true, get: function() { return m[k]; } };
  12. }
  13. Object.defineProperty(o, k2, desc);
  14. }) : (function(o, m, k, k2) {
  15. if (k2 === undefined) k2 = k;
  16. o[k2] = m[k];
  17. }));
  18. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  19. Object.defineProperty(o, "default", { enumerable: true, value: v });
  20. }) : function(o, v) {
  21. o["default"] = v;
  22. });
  23. var __importStar = (this && this.__importStar) || function (mod) {
  24. if (mod && mod.__esModule) return mod;
  25. var result = {};
  26. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  27. __setModuleDefault(result, mod);
  28. return result;
  29. };
  30. var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
  31. if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
  32. if (ar || !(i in from)) {
  33. if (!ar) ar = Array.prototype.slice.call(from, 0, i);
  34. ar[i] = from[i];
  35. }
  36. }
  37. return to.concat(ar || Array.prototype.slice.call(from));
  38. };
  39. Object.defineProperty(exports, "__esModule", { value: true });
  40. exports.addBack = exports.add = exports.end = exports.slice = exports.index = exports.toArray = exports.get = exports.eq = exports.last = exports.first = exports.has = exports.not = exports.is = exports.filterArray = exports.filter = exports.map = exports.each = exports.contents = exports.children = exports.siblings = exports.prevUntil = exports.prevAll = exports.prev = exports.nextUntil = exports.nextAll = exports.next = exports.closest = exports.parentsUntil = exports.parents = exports.parent = exports.find = void 0;
  41. var domhandler_1 = require("domhandler");
  42. var select = __importStar(require("cheerio-select"));
  43. var utils_js_1 = require("../utils.js");
  44. var static_js_1 = require("../static.js");
  45. var domutils_1 = require("domutils");
  46. var reSiblingSelector = /^\s*[~+]/;
  47. /**
  48. * Get the descendants of each element in the current set of matched elements,
  49. * filtered by a selector, jQuery object, or element.
  50. *
  51. * @category Traversing
  52. * @example
  53. *
  54. * ```js
  55. * $('#fruits').find('li').length;
  56. * //=> 3
  57. * $('#fruits').find($('.apple')).length;
  58. * //=> 1
  59. * ```
  60. *
  61. * @param selectorOrHaystack - Element to look for.
  62. * @returns The found elements.
  63. * @see {@link https://api.jquery.com/find/}
  64. */
  65. function find(selectorOrHaystack) {
  66. var _a;
  67. if (!selectorOrHaystack) {
  68. return this._make([]);
  69. }
  70. var context = this.toArray();
  71. if (typeof selectorOrHaystack !== 'string') {
  72. var haystack = (0, utils_js_1.isCheerio)(selectorOrHaystack)
  73. ? selectorOrHaystack.toArray()
  74. : [selectorOrHaystack];
  75. return this._make(haystack.filter(function (elem) { return context.some(function (node) { return (0, static_js_1.contains)(node, elem); }); }));
  76. }
  77. var elems = reSiblingSelector.test(selectorOrHaystack)
  78. ? context
  79. : this.children().toArray();
  80. var options = {
  81. context: context,
  82. root: (_a = this._root) === null || _a === void 0 ? void 0 : _a[0],
  83. // Pass options that are recognized by `cheerio-select`
  84. xmlMode: this.options.xmlMode,
  85. lowerCaseTags: this.options.lowerCaseTags,
  86. lowerCaseAttributeNames: this.options.lowerCaseAttributeNames,
  87. pseudos: this.options.pseudos,
  88. quirksMode: this.options.quirksMode,
  89. };
  90. return this._make(select.select(selectorOrHaystack, elems, options));
  91. }
  92. exports.find = find;
  93. /**
  94. * Creates a matcher, using a particular mapping function. Matchers provide a
  95. * function that finds elements using a generating function, supporting filtering.
  96. *
  97. * @private
  98. * @param matchMap - Mapping function.
  99. * @returns - Function for wrapping generating functions.
  100. */
  101. function _getMatcher(matchMap) {
  102. return function (fn) {
  103. var postFns = [];
  104. for (var _i = 1; _i < arguments.length; _i++) {
  105. postFns[_i - 1] = arguments[_i];
  106. }
  107. return function (selector) {
  108. var _a;
  109. var matched = matchMap(fn, this);
  110. if (selector) {
  111. matched = filterArray(matched, selector, this.options.xmlMode, (_a = this._root) === null || _a === void 0 ? void 0 : _a[0]);
  112. }
  113. return this._make(
  114. // Post processing is only necessary if there is more than one element.
  115. this.length > 1 && matched.length > 1
  116. ? postFns.reduce(function (elems, fn) { return fn(elems); }, matched)
  117. : matched);
  118. };
  119. };
  120. }
  121. /** Matcher that adds multiple elements for each entry in the input. */
  122. var _matcher = _getMatcher(function (fn, elems) {
  123. var _a;
  124. var ret = [];
  125. for (var i = 0; i < elems.length; i++) {
  126. var value = fn(elems[i]);
  127. ret.push(value);
  128. }
  129. return (_a = new Array()).concat.apply(_a, ret);
  130. });
  131. /** Matcher that adds at most one element for each entry in the input. */
  132. var _singleMatcher = _getMatcher(function (fn, elems) {
  133. var ret = [];
  134. for (var i = 0; i < elems.length; i++) {
  135. var value = fn(elems[i]);
  136. if (value !== null) {
  137. ret.push(value);
  138. }
  139. }
  140. return ret;
  141. });
  142. /**
  143. * Matcher that supports traversing until a condition is met.
  144. *
  145. * @returns A function usable for `*Until` methods.
  146. */
  147. function _matchUntil(nextElem) {
  148. var postFns = [];
  149. for (var _i = 1; _i < arguments.length; _i++) {
  150. postFns[_i - 1] = arguments[_i];
  151. }
  152. // We use a variable here that is used from within the matcher.
  153. var matches = null;
  154. var innerMatcher = _getMatcher(function (nextElem, elems) {
  155. var matched = [];
  156. (0, utils_js_1.domEach)(elems, function (elem) {
  157. for (var next_1; (next_1 = nextElem(elem)); elem = next_1) {
  158. // FIXME: `matched` might contain duplicates here and the index is too large.
  159. if (matches === null || matches === void 0 ? void 0 : matches(next_1, matched.length))
  160. break;
  161. matched.push(next_1);
  162. }
  163. });
  164. return matched;
  165. }).apply(void 0, __spreadArray([nextElem], postFns, false));
  166. return function (selector, filterSelector) {
  167. var _this = this;
  168. // Override `matches` variable with the new target.
  169. matches =
  170. typeof selector === 'string'
  171. ? function (elem) { return select.is(elem, selector, _this.options); }
  172. : selector
  173. ? getFilterFn(selector)
  174. : null;
  175. var ret = innerMatcher.call(this, filterSelector);
  176. // Set `matches` to `null`, so we don't waste memory.
  177. matches = null;
  178. return ret;
  179. };
  180. }
  181. function _removeDuplicates(elems) {
  182. return Array.from(new Set(elems));
  183. }
  184. /**
  185. * Get the parent of each element in the current set of matched elements,
  186. * optionally filtered by a selector.
  187. *
  188. * @category Traversing
  189. * @example
  190. *
  191. * ```js
  192. * $('.pear').parent().attr('id');
  193. * //=> fruits
  194. * ```
  195. *
  196. * @param selector - If specified filter for parent.
  197. * @returns The parents.
  198. * @see {@link https://api.jquery.com/parent/}
  199. */
  200. exports.parent = _singleMatcher(function (_a) {
  201. var parent = _a.parent;
  202. return (parent && !(0, domhandler_1.isDocument)(parent) ? parent : null);
  203. }, _removeDuplicates);
  204. /**
  205. * Get a set of parents filtered by `selector` of each element in the current
  206. * set of match elements.
  207. *
  208. * @category Traversing
  209. * @example
  210. *
  211. * ```js
  212. * $('.orange').parents().length;
  213. * //=> 2
  214. * $('.orange').parents('#fruits').length;
  215. * //=> 1
  216. * ```
  217. *
  218. * @param selector - If specified filter for parents.
  219. * @returns The parents.
  220. * @see {@link https://api.jquery.com/parents/}
  221. */
  222. exports.parents = _matcher(function (elem) {
  223. var matched = [];
  224. while (elem.parent && !(0, domhandler_1.isDocument)(elem.parent)) {
  225. matched.push(elem.parent);
  226. elem = elem.parent;
  227. }
  228. return matched;
  229. }, domutils_1.uniqueSort, function (elems) { return elems.reverse(); });
  230. /**
  231. * Get the ancestors of each element in the current set of matched elements, up
  232. * to but not including the element matched by the selector, DOM node, or cheerio object.
  233. *
  234. * @category Traversing
  235. * @example
  236. *
  237. * ```js
  238. * $('.orange').parentsUntil('#food').length;
  239. * //=> 1
  240. * ```
  241. *
  242. * @param selector - Selector for element to stop at.
  243. * @param filterSelector - Optional filter for parents.
  244. * @returns The parents.
  245. * @see {@link https://api.jquery.com/parentsUntil/}
  246. */
  247. exports.parentsUntil = _matchUntil(function (_a) {
  248. var parent = _a.parent;
  249. return (parent && !(0, domhandler_1.isDocument)(parent) ? parent : null);
  250. }, domutils_1.uniqueSort, function (elems) { return elems.reverse(); });
  251. /**
  252. * For each element in the set, get the first element that matches the selector
  253. * by testing the element itself and traversing up through its ancestors in the DOM tree.
  254. *
  255. * @category Traversing
  256. * @example
  257. *
  258. * ```js
  259. * $('.orange').closest();
  260. * //=> []
  261. *
  262. * $('.orange').closest('.apple');
  263. * // => []
  264. *
  265. * $('.orange').closest('li');
  266. * //=> [<li class="orange">Orange</li>]
  267. *
  268. * $('.orange').closest('#fruits');
  269. * //=> [<ul id="fruits"> ... </ul>]
  270. * ```
  271. *
  272. * @param selector - Selector for the element to find.
  273. * @returns The closest nodes.
  274. * @see {@link https://api.jquery.com/closest/}
  275. */
  276. function closest(selector) {
  277. var _a;
  278. var set = [];
  279. if (!selector) {
  280. return this._make(set);
  281. }
  282. var selectOpts = {
  283. xmlMode: this.options.xmlMode,
  284. root: (_a = this._root) === null || _a === void 0 ? void 0 : _a[0],
  285. };
  286. var selectFn = typeof selector === 'string'
  287. ? function (elem) { return select.is(elem, selector, selectOpts); }
  288. : getFilterFn(selector);
  289. (0, utils_js_1.domEach)(this, function (elem) {
  290. while (elem && (0, utils_js_1.isTag)(elem)) {
  291. if (selectFn(elem, 0)) {
  292. // Do not add duplicate elements to the set
  293. if (!set.includes(elem)) {
  294. set.push(elem);
  295. }
  296. break;
  297. }
  298. elem = elem.parent;
  299. }
  300. });
  301. return this._make(set);
  302. }
  303. exports.closest = closest;
  304. /**
  305. * Gets the next sibling of the first selected element, optionally filtered by a selector.
  306. *
  307. * @category Traversing
  308. * @example
  309. *
  310. * ```js
  311. * $('.apple').next().hasClass('orange');
  312. * //=> true
  313. * ```
  314. *
  315. * @param selector - If specified filter for sibling.
  316. * @returns The next nodes.
  317. * @see {@link https://api.jquery.com/next/}
  318. */
  319. exports.next = _singleMatcher(function (elem) { return (0, domutils_1.nextElementSibling)(elem); });
  320. /**
  321. * Gets all the following siblings of the first selected element, optionally
  322. * filtered by a selector.
  323. *
  324. * @category Traversing
  325. * @example
  326. *
  327. * ```js
  328. * $('.apple').nextAll();
  329. * //=> [<li class="orange">Orange</li>, <li class="pear">Pear</li>]
  330. * $('.apple').nextAll('.orange');
  331. * //=> [<li class="orange">Orange</li>]
  332. * ```
  333. *
  334. * @param selector - If specified filter for siblings.
  335. * @returns The next nodes.
  336. * @see {@link https://api.jquery.com/nextAll/}
  337. */
  338. exports.nextAll = _matcher(function (elem) {
  339. var matched = [];
  340. while (elem.next) {
  341. elem = elem.next;
  342. if ((0, utils_js_1.isTag)(elem))
  343. matched.push(elem);
  344. }
  345. return matched;
  346. }, _removeDuplicates);
  347. /**
  348. * Gets all the following siblings up to but not including the element matched
  349. * by the selector, optionally filtered by another selector.
  350. *
  351. * @category Traversing
  352. * @example
  353. *
  354. * ```js
  355. * $('.apple').nextUntil('.pear');
  356. * //=> [<li class="orange">Orange</li>]
  357. * ```
  358. *
  359. * @param selector - Selector for element to stop at.
  360. * @param filterSelector - If specified filter for siblings.
  361. * @returns The next nodes.
  362. * @see {@link https://api.jquery.com/nextUntil/}
  363. */
  364. exports.nextUntil = _matchUntil(function (el) { return (0, domutils_1.nextElementSibling)(el); }, _removeDuplicates);
  365. /**
  366. * Gets the previous sibling of the first selected element optionally filtered
  367. * by a selector.
  368. *
  369. * @category Traversing
  370. * @example
  371. *
  372. * ```js
  373. * $('.orange').prev().hasClass('apple');
  374. * //=> true
  375. * ```
  376. *
  377. * @param selector - If specified filter for siblings.
  378. * @returns The previous nodes.
  379. * @see {@link https://api.jquery.com/prev/}
  380. */
  381. exports.prev = _singleMatcher(function (elem) { return (0, domutils_1.prevElementSibling)(elem); });
  382. /**
  383. * Gets all the preceding siblings of the first selected element, optionally
  384. * filtered by a selector.
  385. *
  386. * @category Traversing
  387. * @example
  388. *
  389. * ```js
  390. * $('.pear').prevAll();
  391. * //=> [<li class="orange">Orange</li>, <li class="apple">Apple</li>]
  392. *
  393. * $('.pear').prevAll('.orange');
  394. * //=> [<li class="orange">Orange</li>]
  395. * ```
  396. *
  397. * @param selector - If specified filter for siblings.
  398. * @returns The previous nodes.
  399. * @see {@link https://api.jquery.com/prevAll/}
  400. */
  401. exports.prevAll = _matcher(function (elem) {
  402. var matched = [];
  403. while (elem.prev) {
  404. elem = elem.prev;
  405. if ((0, utils_js_1.isTag)(elem))
  406. matched.push(elem);
  407. }
  408. return matched;
  409. }, _removeDuplicates);
  410. /**
  411. * Gets all the preceding siblings up to but not including the element matched
  412. * by the selector, optionally filtered by another selector.
  413. *
  414. * @category Traversing
  415. * @example
  416. *
  417. * ```js
  418. * $('.pear').prevUntil('.apple');
  419. * //=> [<li class="orange">Orange</li>]
  420. * ```
  421. *
  422. * @param selector - Selector for element to stop at.
  423. * @param filterSelector - If specified filter for siblings.
  424. * @returns The previous nodes.
  425. * @see {@link https://api.jquery.com/prevUntil/}
  426. */
  427. exports.prevUntil = _matchUntil(function (el) { return (0, domutils_1.prevElementSibling)(el); }, _removeDuplicates);
  428. /**
  429. * Get the siblings of each element (excluding the element) in the set of
  430. * matched elements, optionally filtered by a selector.
  431. *
  432. * @category Traversing
  433. * @example
  434. *
  435. * ```js
  436. * $('.pear').siblings().length;
  437. * //=> 2
  438. *
  439. * $('.pear').siblings('.orange').length;
  440. * //=> 1
  441. * ```
  442. *
  443. * @param selector - If specified filter for siblings.
  444. * @returns The siblings.
  445. * @see {@link https://api.jquery.com/siblings/}
  446. */
  447. exports.siblings = _matcher(function (elem) {
  448. return (0, domutils_1.getSiblings)(elem).filter(function (el) { return (0, utils_js_1.isTag)(el) && el !== elem; });
  449. }, domutils_1.uniqueSort);
  450. /**
  451. * Gets the element children of each element in the set of matched elements.
  452. *
  453. * @category Traversing
  454. * @example
  455. *
  456. * ```js
  457. * $('#fruits').children().length;
  458. * //=> 3
  459. *
  460. * $('#fruits').children('.pear').text();
  461. * //=> Pear
  462. * ```
  463. *
  464. * @param selector - If specified filter for children.
  465. * @returns The children.
  466. * @see {@link https://api.jquery.com/children/}
  467. */
  468. exports.children = _matcher(function (elem) { return (0, domutils_1.getChildren)(elem).filter(utils_js_1.isTag); }, _removeDuplicates);
  469. /**
  470. * Gets the children of each element in the set of matched elements, including
  471. * text and comment nodes.
  472. *
  473. * @category Traversing
  474. * @example
  475. *
  476. * ```js
  477. * $('#fruits').contents().length;
  478. * //=> 3
  479. * ```
  480. *
  481. * @returns The children.
  482. * @see {@link https://api.jquery.com/contents/}
  483. */
  484. function contents() {
  485. var elems = this.toArray().reduce(function (newElems, elem) {
  486. return (0, domhandler_1.hasChildren)(elem) ? newElems.concat(elem.children) : newElems;
  487. }, []);
  488. return this._make(elems);
  489. }
  490. exports.contents = contents;
  491. /**
  492. * Iterates over a cheerio object, executing a function for each matched
  493. * element. When the callback is fired, the function is fired in the context of
  494. * the DOM element, so `this` refers to the current element, which is equivalent
  495. * to the function parameter `element`. To break out of the `each` loop early,
  496. * return with `false`.
  497. *
  498. * @category Traversing
  499. * @example
  500. *
  501. * ```js
  502. * const fruits = [];
  503. *
  504. * $('li').each(function (i, elem) {
  505. * fruits[i] = $(this).text();
  506. * });
  507. *
  508. * fruits.join(', ');
  509. * //=> Apple, Orange, Pear
  510. * ```
  511. *
  512. * @param fn - Function to execute.
  513. * @returns The instance itself, useful for chaining.
  514. * @see {@link https://api.jquery.com/each/}
  515. */
  516. function each(fn) {
  517. var i = 0;
  518. var len = this.length;
  519. while (i < len && fn.call(this[i], i, this[i]) !== false)
  520. ++i;
  521. return this;
  522. }
  523. exports.each = each;
  524. /**
  525. * Pass each element in the current matched set through a function, producing a
  526. * new Cheerio object containing the return values. The function can return an
  527. * individual data item or an array of data items to be inserted into the
  528. * resulting set. If an array is returned, the elements inside the array are
  529. * inserted into the set. If the function returns null or undefined, no element
  530. * will be inserted.
  531. *
  532. * @category Traversing
  533. * @example
  534. *
  535. * ```js
  536. * $('li')
  537. * .map(function (i, el) {
  538. * // this === el
  539. * return $(this).text();
  540. * })
  541. * .toArray()
  542. * .join(' ');
  543. * //=> "apple orange pear"
  544. * ```
  545. *
  546. * @param fn - Function to execute.
  547. * @returns The mapped elements, wrapped in a Cheerio collection.
  548. * @see {@link https://api.jquery.com/map/}
  549. */
  550. function map(fn) {
  551. var elems = [];
  552. for (var i = 0; i < this.length; i++) {
  553. var el = this[i];
  554. var val = fn.call(el, i, el);
  555. if (val != null) {
  556. elems = elems.concat(val);
  557. }
  558. }
  559. return this._make(elems);
  560. }
  561. exports.map = map;
  562. /**
  563. * Creates a function to test if a filter is matched.
  564. *
  565. * @param match - A filter.
  566. * @returns A function that determines if a filter has been matched.
  567. */
  568. function getFilterFn(match) {
  569. if (typeof match === 'function') {
  570. return function (el, i) { return match.call(el, i, el); };
  571. }
  572. if ((0, utils_js_1.isCheerio)(match)) {
  573. return function (el) { return Array.prototype.includes.call(match, el); };
  574. }
  575. return function (el) {
  576. return match === el;
  577. };
  578. }
  579. function filter(match) {
  580. var _a;
  581. return this._make(filterArray(this.toArray(), match, this.options.xmlMode, (_a = this._root) === null || _a === void 0 ? void 0 : _a[0]));
  582. }
  583. exports.filter = filter;
  584. function filterArray(nodes, match, xmlMode, root) {
  585. return typeof match === 'string'
  586. ? select.filter(match, nodes, { xmlMode: xmlMode, root: root })
  587. : nodes.filter(getFilterFn(match));
  588. }
  589. exports.filterArray = filterArray;
  590. /**
  591. * Checks the current list of elements and returns `true` if _any_ of the
  592. * elements match the selector. If using an element or Cheerio selection,
  593. * returns `true` if _any_ of the elements match. If using a predicate function,
  594. * the function is executed in the context of the selected element, so `this`
  595. * refers to the current element.
  596. *
  597. * @category Attributes
  598. * @param selector - Selector for the selection.
  599. * @returns Whether or not the selector matches an element of the instance.
  600. * @see {@link https://api.jquery.com/is/}
  601. */
  602. function is(selector) {
  603. var nodes = this.toArray();
  604. return typeof selector === 'string'
  605. ? select.some(nodes.filter(utils_js_1.isTag), selector, this.options)
  606. : selector
  607. ? nodes.some(getFilterFn(selector))
  608. : false;
  609. }
  610. exports.is = is;
  611. /**
  612. * Remove elements from the set of matched elements. Given a Cheerio object that
  613. * represents a set of DOM elements, the `.not()` method constructs a new
  614. * Cheerio object from a subset of the matching elements. The supplied selector
  615. * is tested against each element; the elements that don't match the selector
  616. * will be included in the result.
  617. *
  618. * The `.not()` method can take a function as its argument in the same way that
  619. * `.filter()` does. Elements for which the function returns `true` are excluded
  620. * from the filtered set; all other elements are included.
  621. *
  622. * @category Traversing
  623. * @example <caption>Selector</caption>
  624. *
  625. * ```js
  626. * $('li').not('.apple').length;
  627. * //=> 2
  628. * ```
  629. *
  630. * @example <caption>Function</caption>
  631. *
  632. * ```js
  633. * $('li').not(function (i, el) {
  634. * // this === el
  635. * return $(this).attr('class') === 'orange';
  636. * }).length; //=> 2
  637. * ```
  638. *
  639. * @param match - Value to look for, following the rules above.
  640. * @param container - Optional node to filter instead.
  641. * @returns The filtered collection.
  642. * @see {@link https://api.jquery.com/not/}
  643. */
  644. function not(match) {
  645. var nodes = this.toArray();
  646. if (typeof match === 'string') {
  647. var matches_1 = new Set(select.filter(match, nodes, this.options));
  648. nodes = nodes.filter(function (el) { return !matches_1.has(el); });
  649. }
  650. else {
  651. var filterFn_1 = getFilterFn(match);
  652. nodes = nodes.filter(function (el, i) { return !filterFn_1(el, i); });
  653. }
  654. return this._make(nodes);
  655. }
  656. exports.not = not;
  657. /**
  658. * Filters the set of matched elements to only those which have the given DOM
  659. * element as a descendant or which have a descendant that matches the given
  660. * selector. Equivalent to `.filter(':has(selector)')`.
  661. *
  662. * @category Traversing
  663. * @example <caption>Selector</caption>
  664. *
  665. * ```js
  666. * $('ul').has('.pear').attr('id');
  667. * //=> fruits
  668. * ```
  669. *
  670. * @example <caption>Element</caption>
  671. *
  672. * ```js
  673. * $('ul').has($('.pear')[0]).attr('id');
  674. * //=> fruits
  675. * ```
  676. *
  677. * @param selectorOrHaystack - Element to look for.
  678. * @returns The filtered collection.
  679. * @see {@link https://api.jquery.com/has/}
  680. */
  681. function has(selectorOrHaystack) {
  682. var _this = this;
  683. return this.filter(typeof selectorOrHaystack === 'string'
  684. ? // Using the `:has` selector here short-circuits searches.
  685. ":has(".concat(selectorOrHaystack, ")")
  686. : function (_, el) { return _this._make(el).find(selectorOrHaystack).length > 0; });
  687. }
  688. exports.has = has;
  689. /**
  690. * Will select the first element of a cheerio object.
  691. *
  692. * @category Traversing
  693. * @example
  694. *
  695. * ```js
  696. * $('#fruits').children().first().text();
  697. * //=> Apple
  698. * ```
  699. *
  700. * @returns The first element.
  701. * @see {@link https://api.jquery.com/first/}
  702. */
  703. function first() {
  704. return this.length > 1 ? this._make(this[0]) : this;
  705. }
  706. exports.first = first;
  707. /**
  708. * Will select the last element of a cheerio object.
  709. *
  710. * @category Traversing
  711. * @example
  712. *
  713. * ```js
  714. * $('#fruits').children().last().text();
  715. * //=> Pear
  716. * ```
  717. *
  718. * @returns The last element.
  719. * @see {@link https://api.jquery.com/last/}
  720. */
  721. function last() {
  722. return this.length > 0 ? this._make(this[this.length - 1]) : this;
  723. }
  724. exports.last = last;
  725. /**
  726. * Reduce the set of matched elements to the one at the specified index. Use
  727. * `.eq(-i)` to count backwards from the last selected element.
  728. *
  729. * @category Traversing
  730. * @example
  731. *
  732. * ```js
  733. * $('li').eq(0).text();
  734. * //=> Apple
  735. *
  736. * $('li').eq(-1).text();
  737. * //=> Pear
  738. * ```
  739. *
  740. * @param i - Index of the element to select.
  741. * @returns The element at the `i`th position.
  742. * @see {@link https://api.jquery.com/eq/}
  743. */
  744. function eq(i) {
  745. var _a;
  746. i = +i;
  747. // Use the first identity optimization if possible
  748. if (i === 0 && this.length <= 1)
  749. return this;
  750. if (i < 0)
  751. i = this.length + i;
  752. return this._make((_a = this[i]) !== null && _a !== void 0 ? _a : []);
  753. }
  754. exports.eq = eq;
  755. function get(i) {
  756. if (i == null) {
  757. return this.toArray();
  758. }
  759. return this[i < 0 ? this.length + i : i];
  760. }
  761. exports.get = get;
  762. /**
  763. * Retrieve all the DOM elements contained in the jQuery set as an array.
  764. *
  765. * @example
  766. *
  767. * ```js
  768. * $('li').toArray();
  769. * //=> [ {...}, {...}, {...} ]
  770. * ```
  771. *
  772. * @returns The contained items.
  773. */
  774. function toArray() {
  775. return Array.prototype.slice.call(this);
  776. }
  777. exports.toArray = toArray;
  778. /**
  779. * Search for a given element from among the matched elements.
  780. *
  781. * @category Traversing
  782. * @example
  783. *
  784. * ```js
  785. * $('.pear').index();
  786. * //=> 2 $('.orange').index('li');
  787. * //=> 1
  788. * $('.apple').index($('#fruit, li'));
  789. * //=> 1
  790. * ```
  791. *
  792. * @param selectorOrNeedle - Element to look for.
  793. * @returns The index of the element.
  794. * @see {@link https://api.jquery.com/index/}
  795. */
  796. function index(selectorOrNeedle) {
  797. var $haystack;
  798. var needle;
  799. if (selectorOrNeedle == null) {
  800. $haystack = this.parent().children();
  801. needle = this[0];
  802. }
  803. else if (typeof selectorOrNeedle === 'string') {
  804. $haystack = this._make(selectorOrNeedle);
  805. needle = this[0];
  806. }
  807. else {
  808. // eslint-disable-next-line @typescript-eslint/no-this-alias
  809. $haystack = this;
  810. needle = (0, utils_js_1.isCheerio)(selectorOrNeedle)
  811. ? selectorOrNeedle[0]
  812. : selectorOrNeedle;
  813. }
  814. return Array.prototype.indexOf.call($haystack, needle);
  815. }
  816. exports.index = index;
  817. /**
  818. * Gets the elements matching the specified range (0-based position).
  819. *
  820. * @category Traversing
  821. * @example
  822. *
  823. * ```js
  824. * $('li').slice(1).eq(0).text();
  825. * //=> 'Orange'
  826. *
  827. * $('li').slice(1, 2).length;
  828. * //=> 1
  829. * ```
  830. *
  831. * @param start - A position at which the elements begin to be selected. If
  832. * negative, it indicates an offset from the end of the set.
  833. * @param end - A position at which the elements stop being selected. If
  834. * negative, it indicates an offset from the end of the set. If omitted, the
  835. * range continues until the end of the set.
  836. * @returns The elements matching the specified range.
  837. * @see {@link https://api.jquery.com/slice/}
  838. */
  839. function slice(start, end) {
  840. return this._make(Array.prototype.slice.call(this, start, end));
  841. }
  842. exports.slice = slice;
  843. /**
  844. * End the most recent filtering operation in the current chain and return the
  845. * set of matched elements to its previous state.
  846. *
  847. * @category Traversing
  848. * @example
  849. *
  850. * ```js
  851. * $('li').eq(0).end().length;
  852. * //=> 3
  853. * ```
  854. *
  855. * @returns The previous state of the set of matched elements.
  856. * @see {@link https://api.jquery.com/end/}
  857. */
  858. function end() {
  859. var _a;
  860. return (_a = this.prevObject) !== null && _a !== void 0 ? _a : this._make([]);
  861. }
  862. exports.end = end;
  863. /**
  864. * Add elements to the set of matched elements.
  865. *
  866. * @category Traversing
  867. * @example
  868. *
  869. * ```js
  870. * $('.apple').add('.orange').length;
  871. * //=> 2
  872. * ```
  873. *
  874. * @param other - Elements to add.
  875. * @param context - Optionally the context of the new selection.
  876. * @returns The combined set.
  877. * @see {@link https://api.jquery.com/add/}
  878. */
  879. function add(other, context) {
  880. var selection = this._make(other, context);
  881. var contents = (0, domutils_1.uniqueSort)(__spreadArray(__spreadArray([], this.get(), true), selection.get(), true));
  882. return this._make(contents);
  883. }
  884. exports.add = add;
  885. /**
  886. * Add the previous set of elements on the stack to the current set, optionally
  887. * filtered by a selector.
  888. *
  889. * @category Traversing
  890. * @example
  891. *
  892. * ```js
  893. * $('li').eq(0).addBack('.orange').length;
  894. * //=> 2
  895. * ```
  896. *
  897. * @param selector - Selector for the elements to add.
  898. * @returns The combined set.
  899. * @see {@link https://api.jquery.com/addBack/}
  900. */
  901. function addBack(selector) {
  902. return this.prevObject
  903. ? this.add(selector ? this.prevObject.filter(selector) : this.prevObject)
  904. : this;
  905. }
  906. exports.addBack = addBack;
  907. //# sourceMappingURL=traversing.js.map