| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 | var pkg = require('../package.json')var api = require('./api.js')var parser = require('posthtml-parser')var render = require('posthtml-render')/** * @author Ivan Voischev (@voischev), *         Anton Winogradov (@awinogradov), *         Alexej Yaroshevich (@zxqfox), *         Vasiliy (@Yeti-or) * * @requires api * @requires posthtml-parser * @requires posthtml-render * * @constructor PostHTML * @param {Array} plugins - An array of PostHTML plugins */function PostHTML (plugins) {/** * PostHTML Instance * * @prop plugins * @prop options */  this.version = pkg.version  this.name = pkg.name  this.plugins = typeof plugins === 'function' ? [plugins] : plugins || []}/** * @requires posthtml-parser * * @param   {String} html - Input (HTML) * @returns {Array}  tree - PostHTMLTree (JSON) */PostHTML.parser = parser/** * @requires posthtml-render * * @param   {Array}  tree - PostHTMLTree (JSON) * @returns {String} html - HTML */PostHTML.render = render/*** @this posthtml* @param   {Function} plugin - A PostHTML plugin* @returns {Constructor} - this(PostHTML)** **Usage*** ```js* ph.use((tree) => { tag: 'div', content: tree })*   .process('<html>..</html>', {})*   .then((result) => result))* ```*/PostHTML.prototype.use = function () {  [].push.apply(this.plugins, arguments)  return this}/** * @param   {String} html - Input (HTML) * @param   {?Object} options - PostHTML Options * @returns {Object<{html: String, tree: PostHTMLTree}>} - Sync Mode * @returns {Promise<{html: String, tree: PostHTMLTree}>} - Async Mode (default) * * **Usage** * * **Sync** * ```js * ph.process('<html>..</html>', { sync: true }).html * ``` * * **Async** * ```js * ph.process('<html>..</html>', {}).then((result) => result)) * ``` */PostHTML.prototype.process = function (tree, options) {  /**   * ## PostHTML Options   *   * @type {Object}   * @prop {?Boolean} options.sync - enables sync mode, plugins will run synchronously, throws an error when used with async plugins   * @prop {?Function} options.parser - use custom parser, replaces default (posthtml-parser)   * @prop {?Function} options.render - use custom render, replaces default (posthtml-render)   * @prop {?Boolean} options.skipParse - disable parsing   */  options = options || {}  if (options.parser) parser = options.parser  if (options.render) render = options.render  tree = options.skipParse ? tree : parser(tree)  tree.options = options  tree.processor = this  // sync mode  if (options.sync === true) {    this.plugins.forEach(function (plugin) {      apiExtend(tree)      var result      if (plugin.length === 2 || isPromise(result = plugin(tree))) {        throw new Error(          'Can’t process contents in sync mode because of async plugin: ' + plugin.name        )      }      // return the previous tree unless result is fulfilled      tree = result || tree    })    return lazyResult(render, tree)  }  // async mode  var i = 0  var next = function (result, cb) {    // all plugins called    if (this.plugins.length <= i) {      cb(null, result)      return    }    // little helper to go to the next iteration    function _next (res) {      return next(res || result, cb)    }    // (re)extend the object    apiExtend(result)    // call next    var plugin = this.plugins[i++]    if (plugin.length === 2) {      plugin(result, function (err, res) {        if (err) return cb(err)        _next(res)      })      return    }    // sync and promised plugins    var err = null    var res = tryCatch(function () {      return plugin(result)    }, function (err) {      return err    })    if (err) {      cb(err)      return    }    if (isPromise(res)) {      res.then(_next).catch(cb)      return    }    _next(res)  }.bind(this)  return new Promise(function (resolve, reject) {    next(tree, function (err, tree) {      if (err) reject(err)      else resolve(lazyResult(render, tree))    })  })}/** * @exports posthtml * * @param  {Array} plugins * @return {Function} posthtml * * **Usage** * ```js * import posthtml from 'posthtml' * import plugin from 'posthtml-plugin' * * const ph = posthtml([ plugin() ]) * ``` */module.exports = function (plugins) {  return new PostHTML(plugins)}/** * Checks if parameter is a Promise (or thenable) object. * * @private * * @param   {*} promise - Target `{}` to test * @returns {Boolean} */function isPromise (promise) {  return !!promise && typeof promise.then === 'function'}/** * Simple try/catch helper, if exists, returns result * * @private * * @param   {Function} tryFn - try block * @param   {Function} catchFn - catch block * @returns {?*} */function tryCatch (tryFn, catchFn) {  try {    return tryFn()  } catch (err) {    catchFn(err)  }}/** * Extends the PostHTMLTree with the Tree API * * @private * * @param   {Array} tree - PostHTMLTree * @returns {Array} tree - PostHTMLTree with API */function apiExtend (tree) {  tree.walk = api.walk  tree.match = api.match}/** * Wraps the PostHTMLTree within an object using a getter to render HTML on demand. * * @private * * @param   {Function} render * @param   {Array}    tree * @returns {Object<{html: String, tree: Array}>} */function lazyResult (render, tree) {  return {    get html () {      return render(tree, tree.options)    },    tree: tree  }}
 |