HEX
Server: Apache
System: Linux webd004.cluster130.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64
User: frenchy (106757)
PHP: 7.4.33
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/frenchy/www/french-american.org/current/node_modules/promised-handlebars/index.js
/*!
 * promised-handlebars <https://github.com/nknapp/promised-handlebars>
 *
 * Copyright (c) 2015 Nils Knappmeier.
 * Released under the MIT license.
 */

'use strict'

var deepAplus = require('deep-aplus')
var createMarkers = require('./lib/markers')
var utils = require('./lib/utils')

// Basic utility functions
var values = utils.values
var wrap = utils.wrap
var mapValues = utils.mapValues
var anyApplies = utils.anyApplies
var isPromiseAlike = utils.isPromiseAlike

module.exports = promisedHandlebars

/**
 * Returns a new Handlebars instance that
 * * allows helpers to return promises
 * * creates `compiled` templates that always
 *   return a promise for the resulting string.
 *   The promise is fulfilled after all helper-promsises
 *   are resolved.
 *
 * @param {Handlebars} Handlebars the Handlebars engine to wrap
 * @param {object=} options optional parameters
 * @param {string=} options.placeholder the placeholder to be used in the template-output before inserting
 *   the promised results. This placeholder may not occur in the template or any partial. Neither
 *   my any helper generate the placeholder in to the result. Errors or wrong replacement will
 *   happen otherwise.
 * @param {Promise=} options.Promise the promise implementation to use. Defaults to global.Promise
 * @returns {Handlebars} a modified Handlebars object
 */
function promisedHandlebars (Handlebars, options) {
  options = options || {}
  options.placeholder = options.placeholder || '\u0001'

  var Promise = options.Promise || global.Promise
  if (!Promise) {
    throw new Error('promised-handlebars: Promise is undefined. Please specify options.Promise or set global.Promise.')
  }

  var deep = deepAplus(Promise)
  var Markers = createMarkers(Promise)

  var engine = Handlebars.create()
  var markers = null

  // Wrap `registerHelper` with a custom function
  engine.registerHelper = wrap(engine.registerHelper, function registerHelperWrapper (oldRegisterHelper, args) {
    if (typeof args[0] === 'string' && typeof args[1] === 'function') {
      var name = args[0]
      var helper = args[1]
      // Called like "registerHelper(name, helper)"
      oldRegisterHelper.call(engine, name, wrap(helper, helperWrapper))
    } else if (args.length === 1 && typeof args[0] === 'object') {
      // Called like "registerHelper({ name: helper })
      oldRegisterHelper.call(engine, mapValues(args[0], function (helper) {
        return wrap(helper, helperWrapper)
      }))
    }
  })
  // Re-register all built-in-helpers to ensure that their methods are wrapped
  engine.registerHelper(engine.helpers)

  // Wrap the `compile` function, so that it wraps the compiled-template
  // with `prepareAndResolveMarkers`
  engine.compile = wrap(engine.compile, function compileWrapper (oldCompile, args) {
    var fn = oldCompile.apply(engine, args)
    return wrap(fn, prepareAndResolveMarkers)
    // Wrap the compiled function
  })

  /**
   * Wrapper for templates, partials and block-helper callbacks
   *
   * 1) the `markers` variable is initialized with a new instance of Markers
   * 2) a promise is returned instead of a string
   * 3) promise placeholder-values are replaced with the promise-results
   *    in the returned promise
   */
  function prepareAndResolveMarkers (fn, args) {
    if (markers) {
      // The Markers-object has already been created for this cycle of the event loop:
      // Just run the wraped function
      return fn.apply(this, args)
    }
    try {
      // No Markers yet. This is the initial call or some call that occured during a promise resolution
      // Create markers, apply the function and resolve placeholders (i.e. promises) created during the
      // function execution
      markers = new Markers(engine, options.placeholder)
      var resultWithPlaceholders = fn.apply(this, args)
      return markers.resolve(resultWithPlaceholders)
    } finally {
      // Reset promises for the next execution run
      markers = null
    }
  }

  /**
   * Wrapper for helper methods:
   * * Call the helper after resolving parameters (if any promises are passed)
   * * Wrap `options.fn` and `options.inverse` to return promises (if needed)
   * * Convert helper results markers if they are promises.
   */
  function helperWrapper (fn, args) {
    var _this = this
    var options = args[args.length - 1]
    var hash = options.hash

    // "fn" and "inverse" return strings. They must be able to handle promises
    // just as the compiled template and partials
    options.fn = options.fn && wrap(options.fn, prepareAndResolveMarkers)
    options.inverse = options.inverse && wrap(options.inverse, prepareAndResolveMarkers)

    // If there are any promises in the helper args or in the hash,
    // the evaluation of the helper cannot start before these promises are resolved.
    var promisesInArgs = anyApplies(args, isPromiseAlike)
    var promisesInHash = anyApplies(values(hash), isPromiseAlike)

    if (!promisesInArgs && !promisesInHash) {
      // No promises in hash or args. Act a normal as possible.
      var result = fn.apply(_this, args)
      return isPromiseAlike(result) ? markers.asMarker(result) : result
    }

    var promise = deep(args).then(function (resolvedArgs) {
      // We need "markers", because we are in a new event-loop-cycle now.
      return prepareAndResolveMarkers(function () {
        return fn.apply(_this, resolvedArgs)
      })
    })
    return markers.asMarker(promise)
  }

  engine.Promise = Promise

  return engine
}