| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 | const SINGLE_TAGS = [  'area',  'base',  'br',  'col',  'command',  'embed',  'hr',  'img',  'input',  'keygen',  'link',  'menuitem',  'meta',  'param',  'source',  'track',  'wbr'];const ATTRIBUTE_QUOTES_REQUIRED = /[\t\n\f\r "'`=<>]/;/** Render PostHTML Tree to HTML * * @param  {Array|Object} tree PostHTML Tree @param  {Object} options Options * * @return {String} HTML */function render(tree, options) {  /** Options   *   * @type {Object}   *   * @prop {Array<String|RegExp>} singleTags  Custom single tags (selfClosing)   * @prop {String} closingSingleTag Closing format for single tag @prop   * @prop {Boolean} quoteAllAttributes If all attributes should be quoted.   * Otherwise attributes will be unquoted when allowed.   * @prop {Boolean} replaceQuote Replaces quotes in attribute values with `"e;`   *   * Formats:   *   * ``` tag: `<br></br>` ```, slash: `<br />` ```, ```default: `<br>` ```   */  options = options || {};  const singleTags = options.singleTags ? SINGLE_TAGS.concat(options.singleTags) : SINGLE_TAGS;  const singleRegExp = singleTags.filter(tag => {    return tag instanceof RegExp;  });  const {closingSingleTag} = options;  let {quoteAllAttributes} = options;  if (quoteAllAttributes === undefined) {    quoteAllAttributes = true;  }  let {replaceQuote} = options;  if (replaceQuote === undefined) {    replaceQuote = true;  }  let {quoteStyle} = options;  if (quoteStyle === undefined) {    quoteStyle = 2;  }  return html(tree);  /** @private */  function isSingleTag(tag) {    if (singleRegExp.length > 0) {      return singleRegExp.some(reg => reg.test(tag));    }    if (!singleTags.includes(tag)) {      return false;    }    return true;  }  /** @private */  function attrs(object) {    let attr = '';    for (const key in object) {      if (typeof object[key] === 'string') {        if (quoteAllAttributes || object[key].match(ATTRIBUTE_QUOTES_REQUIRED)) {          let attrValue = object[key];          if (replaceQuote) {            attrValue = object[key].replace(/"/g, '"');          }          attr += makeAttr(key, attrValue, quoteStyle);        } else if (object[key] === '') {          attr += ' ' + key;        } else {          attr += ' ' + key + '=' + object[key];        }      } else if (object[key] === true) {        attr += ' ' + key;      } else if (typeof object[key] === 'number') {        attr += makeAttr(key, object[key], quoteStyle);      }    }    return attr;  }  /** @private */  function traverse(tree, cb) {    if (tree !== undefined) {      for (let i = 0, {length} = tree; i < length; i++) {        traverse(cb(tree[i]), cb);      }    }  }  /** @private */  function makeAttr(key, attrValue, quoteStyle = 1) {    if (quoteStyle === 1) {      // Single Quote      return ` ${key}='${attrValue}'`;    }    if (quoteStyle === 2) {      // Double Quote      return ` ${key}="${attrValue}"`;    }    // Smart Quote    if (attrValue.includes('"')) {      return ` ${key}='${attrValue}'`;    }    return ` ${key}="${attrValue}"`;  }  /**   * HTML Stringifier   *   * @param  {Array|Object} tree PostHTML Tree   *   * @return {String} result HTML   */  function html(tree) {    let result = '';    if (!Array.isArray(tree)) {      tree = [tree];    }    traverse(tree, node => {      // Undefined, null, '', [], NaN      if (node === undefined ||        node === null ||        node === false ||        node.length === 0 ||        Number.isNaN(node)) {        return;      }      // Treat as new root tree if node is an array      if (Array.isArray(node)) {        result += html(node);        return;      }      if (typeof node === 'string' || typeof node === 'number') {        result += node;        return;      }      // Skip node      if (node.tag === false) {        result += html(node.content);        return;      }      const tag = node.tag || 'div';      result += '<' + tag;      if (node.attrs) {        result += attrs(node.attrs);      }      if (isSingleTag(tag)) {        switch (closingSingleTag) {          case 'tag':            result += '></' + tag + '>';            break;          case 'slash':            result += ' />';            break;          default:            result += '>';        }        result += html(node.content);      } else {        result += '>' + html(node.content) + '</' + tag + '>';      }    });    return result;  }}/** * @module posthtml-render * * @version 1.1.5 * @license MIT */module.exports = render;
 |