text: 'use strict';
  /**
   * @module cheerio/static
   * @ignore
   */
  var defaultOptions = require('./options').default;
  var flattenOptions = require('./options').flatten;
  var select = require('cheerio-select').select;
  var renderWithParse5 = require('./parsers/parse5').render;
  var renderWithHtmlparser2 = require('./parsers/htmlparser2').render;
  var parse = require('./parse');
  
  /**
   * Create a querying function, bound to a document created from the provided
   * markup. Note that similar to web browser contexts, this operation may
   * introduce `<html>`, `<head>`, and `<body>` elements; set `isDocument` to
   * `false` to switch to fragment mode and disable this.
   *
   * See the README section titled "Loading" for additional usage information.
   *
   * @param {string} content - Markup to be loaded.
   * @param {object} [options] - Options for the created instance.
   * @param {boolean} [isDocument] - Allows parser to be switched to fragment mode.
   * @returns {Cheerio} - The loaded document.
   */
  exports.load = function (content, options, isDocument) {
    if (content === null || content === undefined) {
      throw new Error('cheerio.load() expects a string');
    }
  
    var Cheerio = require('./cheerio');
  
    options = Object.assign({}, defaultOptions, flattenOptions(options));
  
    if (typeof isDocument === 'undefined') isDocument = true;
  
    var root = parse(content, options, isDocument);
  
    function initialize(selector, context, r, opts) {
      if (!(this instanceof initialize)) {
        return new initialize(selector, context, r, opts);
      }
      opts = Object.assign({}, options, opts);
      return Cheerio.call(this, selector, context, r || root, opts);
    }
  
    // Ensure that selections created by the "loaded" `initialize` function are
    // true Cheerio instances.
    initialize.prototype = Object.create(Cheerio.prototype);
    initialize.prototype.constructor = initialize;
  
    // Mimic jQuery's prototype alias for plugin authors.
    initialize.fn = initialize.prototype;
  
    // Keep a reference to the top-level scope so we can chain methods that implicitly
    // resolve selectors; e.g. $("<span>").(".bar"), which otherwise loses ._root
    initialize.prototype._originalRoot = root;
  
    // Add in the static methods
    Object.assign(initialize, exports);
  
    // Add in the root
    initialize._root = root;
    // store options
    initialize._options = options;
  
    return initialize;
  };
  
  /**
   * Helper function to render a DOM.
   *
   * @param {Cheerio} that - Cheerio instance to render.
   * @param {Node[] | undefined} dom - The DOM to render. Defaults to `that`'s root.
   * @param {object} options - Options for rendering.
   * @returns {string} The rendered document.
   */
  function render(that, dom, options) {
    if (!dom) {
      if (that._root && that._root.children) {
        dom = that._root.children;
      } else {
        return '';
      }
    } else if (typeof dom === 'string') {
      dom = select(dom, that._root, options);
    }
  
    return options.xmlMode || options._useHtmlParser2
      ? renderWithHtmlparser2(dom, options)
      : renderWithParse5(dom);
  }
  
  /**
   * Renders the document.
   *
   * @param {string | Cheerio | Node | object} [dom] - Element to render.
   * @param {object} [options] - Options for the renderer.
   * @returns {string} The rendered document.
   */
  exports.html = function (dom, options) {
    // be flexible about parameters, sometimes we call html(),
    // with options as only parameter
    // check dom argument for dom element specific properties
    // assume there is no 'length' or 'type' properties in the options object
    if (
      Object.prototype.toString.call(dom) === '[object Object]' &&
      !options &&
      !('length' in dom) &&
      !('type' in dom)
    ) {
      options = dom;
      dom = undefined;
    }
  
    // Sometimes `$.html()` is used without preloading html,
    // so fallback non-existing options to the default ones.
    options = Object.assign(
      {},
      defaultOptions,
      this ? this._options : {},
      flattenOptions(options || {})
    );
  
    return render(this, dom, options);
  };
  
  /**
   * Render the document as XML.
   *
   * @param {string | Cheerio | Node} [dom] - Element to render.
   * @returns {string} THe rendered document.
   */
  exports.xml = function (dom) {
    var options = Object.assign({}, this._options, { xmlMode: true });
  
    return render(this, dom, options);
  };
  
  /**
   * Render the document as text.
   *
   * @param {Cheerio | Node[]} [elems] - Elements to render.
   * @returns {string} The rendered document.
   */
  exports.text = function (elems) {
    if (!elems) {
      elems = this.root();
    }
  
    var ret = '';
    var len = elems.length;
  
    for (var i = 0; i < len; i++) {
      var elem = elems[i];
      if (elem.type === 'text') ret += elem.data;
      else if (
        elem.children &&
        elem.type !== 'comment' &&
        elem.tagName !== 'script' &&
        elem.tagName !== 'style'
      ) {
        ret += exports.text(elem.children);
      }
    }
  
    return ret;
  };
  
  /**
   * Parses a string into an array of DOM nodes. The `context` argument has no
   * meaning for Cheerio, but it is maintained for API compatibility with jQuery.
   *
   * @param {string} data - Markup that will be parsed.
   * @param {any | boolean} [context] - Will be ignored. If it is a boolean it
   *     will be used as the value of `keepScripts`.
   * @param {boolean} [keepScripts] - If false all scripts will be removed.
   * @see {@link https://api.jquery.com/jQuery.parseHTML/}
   *
   * @alias Cheerio.parseHTML
   * @returns {Node[]} The parsed DOM.
   */
  exports.parseHTML = function (data, context, keepScripts) {
    if (!data || typeof data !== 'string') {
      return null;
    }
  
    if (typeof context === 'boolean') {
      keepScripts = context;
    }
  
    var parsed = this.load(data, defaultOptions, false);
    if (!keepScripts) {
      parsed('script').remove();
    }
  
    // The `children` array is used by Cheerio internally to group elements that
    // share the same parents. When nodes created through `parseHTML` are
    // inserted into previously-existing DOM structures, they will be removed
    // from the `children` array. The results of `parseHTML` should remain
    // constant across these operations, so a shallow copy should be returned.
    return parsed.root()[0].children.slice();
  };
  
  /**
   * Sometimes you need to work with the top-level root element. To query it, you
   * can use `$.root()`.
   *
   * @example
   *   $.root().append('<ul id="vegetables"></ul>').html();
   *   //=> <ul id="fruits">...</ul><ul id="vegetables"></ul>
   *
   * @alias Cheerio.root
   * @returns {Cheerio} Cheerio instance wrapping the root node.
   */
  exports.root = function () {
    return this(this._root);
  };
  
  /**
   * Checks to see if the `contained` DOM element is a descendant of the
   * `container` DOM element.
   *
   * @param {Node} container - Potential parent node.
   * @param {Node} contained - Potential child node.
   * @see {@link https://api.jquery.com/jQuery.contains/}
   *
   * @alias Cheerio.contains
   * @returns {boolean} Indicates if the nodes contain one another.
   */
  exports.contains = function (container, contained) {
    // According to the jQuery API, an element does not "contain" itself
    if (contained === container) {
      return false;
    }
  
    // Step up the descendants, stopping when the root element is reached
    // (signaled by `.parent` returning a reference to the same object)
    while (contained && contained !== contained.parent) {
      contained = contained.parent;
      if (contained === container) {
        return true;
      }
    }
  
    return false;
  };
  
  /**
   * $.merge().
   *
   * @param {Array | Cheerio} arr1 - First array.
   * @param {Array | Cheerio} arr2 - Second array.
   * @see {@link https://api.jquery.com/jQuery.merge/}
   *
   * @alias Cheerio.merge
   * @returns {Array | Cheerio} `arr1`, with elements of `arr2` inserted.
   */
  exports.merge = function (arr1, arr2) {
    if (!isArrayLike(arr1) || !isArrayLike(arr2)) {
      return;
    }
    var newLength = arr1.length + arr2.length;
    for (var i = 0; i < arr2.length; i++) {
      arr1[i + arr1.length] = arr2[i];
    }
    arr1.length = newLength;
    return arr1;
  };
  
  /**
   * @param {any} item - Item to check.
   * @returns {boolean} Indicates if the item is array-like.
   */
  function isArrayLike(item) {
    if (Array.isArray(item)) {
      return true;
    }
  
    if (
      typeof item !== 'object' ||
      !Object.prototype.hasOwnProperty.call(item, 'length') ||
      typeof item.length !== 'number' ||
      item.length < 0
    ) {
      return false;
    }
  
    for (var i = 0; i < item.length; i++) {
      if (!(i in item)) {
        return false;
      }
    }
    return true;
  }
  