static.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import { textContent } from 'domutils';
  2. import { flattenOptions as flattenOptions, } from './options.js';
  3. /**
  4. * Helper function to render a DOM.
  5. *
  6. * @param that - Cheerio instance to render.
  7. * @param dom - The DOM to render. Defaults to `that`'s root.
  8. * @param options - Options for rendering.
  9. * @returns The rendered document.
  10. */
  11. function render(that, dom, options) {
  12. if (!that)
  13. return '';
  14. return that(dom !== null && dom !== void 0 ? dom : that._root.children, null, undefined, options).toString();
  15. }
  16. /**
  17. * Checks if a passed object is an options object.
  18. *
  19. * @param dom - Object to check if it is an options object.
  20. * @param options - Options object.
  21. * @returns Whether the object is an options object.
  22. */
  23. function isOptions(dom, options) {
  24. return (!options &&
  25. typeof dom === 'object' &&
  26. dom != null &&
  27. !('length' in dom) &&
  28. !('type' in dom));
  29. }
  30. export function html(dom, options) {
  31. /*
  32. * Be flexible about parameters, sometimes we call html(),
  33. * with options as only parameter
  34. * check dom argument for dom element specific properties
  35. * assume there is no 'length' or 'type' properties in the options object
  36. */
  37. const toRender = isOptions(dom) ? ((options = dom), undefined) : dom;
  38. /*
  39. * Sometimes `$.html()` is used without preloading html,
  40. * so fallback non-existing options to the default ones.
  41. */
  42. const opts = {
  43. ...this === null || this === void 0 ? void 0 : this._options,
  44. ...flattenOptions(options),
  45. };
  46. return render(this, toRender, opts);
  47. }
  48. /**
  49. * Render the document as XML.
  50. *
  51. * @category Static
  52. * @param dom - Element to render.
  53. * @returns THe rendered document.
  54. */
  55. export function xml(dom) {
  56. const options = { ...this._options, xmlMode: true };
  57. return render(this, dom, options);
  58. }
  59. /**
  60. * Render the document as text.
  61. *
  62. * This returns the `textContent` of the passed elements. The result will
  63. * include the contents of `<script>` and `<style>` elements. To avoid this, use
  64. * `.prop('innerText')` instead.
  65. *
  66. * @category Static
  67. * @param elements - Elements to render.
  68. * @returns The rendered document.
  69. */
  70. export function text(elements) {
  71. const elems = elements !== null && elements !== void 0 ? elements : (this ? this.root() : []);
  72. let ret = '';
  73. for (let i = 0; i < elems.length; i++) {
  74. ret += textContent(elems[i]);
  75. }
  76. return ret;
  77. }
  78. export function parseHTML(data, context, keepScripts = typeof context === 'boolean' ? context : false) {
  79. if (!data || typeof data !== 'string') {
  80. return null;
  81. }
  82. if (typeof context === 'boolean') {
  83. keepScripts = context;
  84. }
  85. const parsed = this.load(data, this._options, false);
  86. if (!keepScripts) {
  87. parsed('script').remove();
  88. }
  89. /*
  90. * The `children` array is used by Cheerio internally to group elements that
  91. * share the same parents. When nodes created through `parseHTML` are
  92. * inserted into previously-existing DOM structures, they will be removed
  93. * from the `children` array. The results of `parseHTML` should remain
  94. * constant across these operations, so a shallow copy should be returned.
  95. */
  96. return [...parsed.root()[0].children];
  97. }
  98. /**
  99. * Sometimes you need to work with the top-level root element. To query it, you
  100. * can use `$.root()`.
  101. *
  102. * @category Static
  103. * @example
  104. *
  105. * ```js
  106. * $.root().append('<ul id="vegetables"></ul>').html();
  107. * //=> <ul id="fruits">...</ul><ul id="vegetables"></ul>
  108. * ```
  109. *
  110. * @returns Cheerio instance wrapping the root node.
  111. * @alias Cheerio.root
  112. */
  113. export function root() {
  114. return this(this._root);
  115. }
  116. /**
  117. * Checks to see if the `contained` DOM element is a descendant of the
  118. * `container` DOM element.
  119. *
  120. * @category Static
  121. * @param container - Potential parent node.
  122. * @param contained - Potential child node.
  123. * @returns Indicates if the nodes contain one another.
  124. * @alias Cheerio.contains
  125. * @see {@link https://api.jquery.com/jQuery.contains/}
  126. */
  127. export function contains(container, contained) {
  128. // According to the jQuery API, an element does not "contain" itself
  129. if (contained === container) {
  130. return false;
  131. }
  132. /*
  133. * Step up the descendants, stopping when the root element is reached
  134. * (signaled by `.parent` returning a reference to the same object)
  135. */
  136. let next = contained;
  137. while (next && next !== next.parent) {
  138. next = next.parent;
  139. if (next === container) {
  140. return true;
  141. }
  142. }
  143. return false;
  144. }
  145. /**
  146. * Extract multiple values from a document, and store them in an object.
  147. *
  148. * @category Static
  149. * @param map - An object containing key-value pairs. The keys are the names of
  150. * the properties to be created on the object, and the values are the
  151. * selectors to be used to extract the values.
  152. * @returns An object containing the extracted values.
  153. */
  154. export function extract(map) {
  155. return this.root().extract(map);
  156. }
  157. /**
  158. * $.merge().
  159. *
  160. * @category Static
  161. * @param arr1 - First array.
  162. * @param arr2 - Second array.
  163. * @returns `arr1`, with elements of `arr2` inserted.
  164. * @alias Cheerio.merge
  165. * @see {@link https://api.jquery.com/jQuery.merge/}
  166. */
  167. export function merge(arr1, arr2) {
  168. if (!isArrayLike(arr1) || !isArrayLike(arr2)) {
  169. return;
  170. }
  171. let newLength = arr1.length;
  172. const len = +arr2.length;
  173. for (let i = 0; i < len; i++) {
  174. arr1[newLength++] = arr2[i];
  175. }
  176. arr1.length = newLength;
  177. return arr1;
  178. }
  179. /**
  180. * Checks if an object is array-like.
  181. *
  182. * @category Static
  183. * @param item - Item to check.
  184. * @returns Indicates if the item is array-like.
  185. */
  186. function isArrayLike(item) {
  187. if (Array.isArray(item)) {
  188. return true;
  189. }
  190. if (typeof item !== 'object' ||
  191. item === null ||
  192. !('length' in item) ||
  193. typeof item.length !== 'number' ||
  194. item.length < 0) {
  195. return false;
  196. }
  197. for (let i = 0; i < item.length; i++) {
  198. if (!(i in item)) {
  199. return false;
  200. }
  201. }
  202. return true;
  203. }
  204. //# sourceMappingURL=static.js.map