All files / src mustache.ts

90% Statements 18/20
50% Branches 2/4
100% Functions 8/8
88.88% Lines 16/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109  2x   22x                                                                                             2x       20x           20x   20x 59x       194x     60x         59x                                   2x           1x 1x 1x     1x 1x      
import { DefaultState } from "./utils/state"
import Mustache from "mustache"
 
export { defaultMustacheTemplate } from "./defaults/_generated"
 
type Options = {
  /**
   * Mustache helpers to extend template functionality.
   */
  helpers?: object
}
 
/**
 * Render a Mustache template into a container
 *
 * @param template Mustache template
 * @param options Options object.
 * @returns Render function
 * @group Autocomplete
 * @category Mustache
/**
 * @example
 * ```js
 * import { fromMustacheTemplate } from "@nosto/autocomplete/mustache";
 *
 * const render = fromMustacheTemplate(`
 *   <div>
 *      <h1>{{title}}</h1>
 *     <ul>
 *      {{#products}}
 *       <li>{{name}}</li>
 *     {{/products}}
 *    </ul>
 *   </div>
 *   `, {
 *    helpers: {
 *     toJson: function () {
 *      return JSON.stringify(this)
 *    }});
 *
 * render(document.getElementById("container"), {
 *   title: "My Title",
 *   products: [
 *     { name: "Product 1" },
 *     { name: "Product 2" },
 *     { name: "Product 3" }
 *   ]
 * });
 * ```
 */
export function fromMustacheTemplate<State extends object = DefaultState>(
  template: string,
  options?: Options
) {
  Iif (Mustache === undefined) {
    throw new Error(
      "Mustache is not defined. Please include the Mustache dependency or library in your page."
    )
  }
 
  const { helpers } = options || {}
 
  return (container: HTMLElement, state: State) => {
    container.innerHTML = Mustache.render(template, {
      ...state,
      imagePlaceholder: "https://cdn.nosto.com/nosto/9/mock",
      toJson: function () {
        return JSON.stringify(this)
      },
      showListPrice: function () {
        return this.listPrice !== this.price
      },
      ...helpers,
    })
 
    return Promise.resolve(undefined)
  }
}
 
/**
 * Load a remote Mustache template and render it into a container
 *
 * @param url Remote Mustache template URL
 * @returns Render function
 * @group Autocomplete
 * @category Mustache
 * @example
 * ```js
 * import { fromRemoteMustacheTemplate } from "@nosto/autocomplete/mustache";
 *
 * const render = fromRemoteMustacheTemplate("https://example.com/template.mustache");
 * ```
 */
export function fromRemoteMustacheTemplate<State extends object = DefaultState>(
  url: string,
  options?: {
    helpers?: object
  }
): (container: HTMLElement, state: State) => PromiseLike<void> {
  return async (container, state) => {
    const response = await fetch(url)
    Iif (!response.ok) {
      throw new Error(`Failed to fetch remote mustache template: ${response.statusText}`)
    }
    const template = await response.text()
    await fromMustacheTemplate(template, options)(container, state)
  }
}