npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jpbm135/bigodin

v0.5.1

Published

Secure Handlebars/Mustache templating for user-provided templates with async helpers support and human-friendly parsing errors

Readme

Bigodin

Secure Handlebars/Mustache templating for user-provided templates, with async helpers and human-friendly parse errors. Templates are parsed into a JSON AST and interpreted at runtime — never compiled to JavaScript — so it is safe to evaluate templates submitted by end users.

Bigodin is a fork of Bigodon that drops unnecessary features and grows the supported subset of the Mustache spec, aiming to be a drop-in replacement for Mustache in user-provided template scenarios.

Installation

yarn add @jpbm135/bigodin
# or
npm install @jpbm135/bigodin

Types are bundled. Node ≥ 18 required.

Quick start

const { compile } = require('@jpbm135/bigodin');

async function main() {
    const template = compile('Hello, {{name}}!');
    const result = await template({ name: 'George' });
    console.log(result); // Hello, George!
}

main().catch(console.error);

Split parsing from execution (e.g. cache the AST in Redis, parse in one service and run in another):

const { parse, run } = require('@jpbm135/bigodin');

const ast = parse('Hello, {{name}}!'); // plain JSON — safe to persist

// later, possibly in another process:
const result = await run(ast, { name: 'George' });

Features

Handlebars-style template syntax:

  • Dot-path access inside mustaches ({{foo.bar}})
  • Literal arguments ({{helper 5 "hi" true}})
  • Comments ({{! ... }})
  • Nested expressions ({{outer (inner data.first data.second)}})
  • Blocks and inverted blocks ({{#list}}…{{/list}}, {{^list}}…{{/list}})
  • {{else}} and chained {{else if}}
  • Iteration variables (@index, @key, @first, @last)
  • Block params ({{#each items as |item index|}})
  • Whitespace control ({{~ ~}})
  • Context navigation with $parent, $root, $this
  • Variable assignment ({{= $foo "bar"}}) within a template

What sets Bigodin apart:

  • Async helpersawait requests, database calls, file IO, etc. directly from a helper.
  • Safe by construction — no codegen, no eval, no Function constructor; templates are walked over a JSON AST.
  • Execution limitsmaxExecutionMillis and halt() let you bound runtime on hostile input.
  • Better error messages — parser combinators surface line/column and what was expected.
  • Minimal core — only the block primitives ship by default (if, unless, with, each, return); add your own with addHelper.
  • Persistable AST — versioned JSON; old ASTs fail loudly when the runner has moved on.

Mustache spec compatibility

Bigodin is a Handlebars-flavored superset and is not a drop-in Mustache implementation. Against the official mustache/spec suite, 103 / 110 attempted tests currently pass (94%); the remaining 84 spec tests live in 5 deliberately-skipped feature files (partials, dynamic-names, set-delimiters, inheritance, lambdas) and 4 individual tests are skipped because they require auto-walking the context stack — Bigodin uses Handlebars-style strict scoping (use $parent/$root to walk up explicitly).

Detailed per-feature breakdowns — including failing test names, root-cause analysis, and proposed implementations — live in mustache-compat/.

| Feature | Status | Notes | | ---------------------------------------- | ------------- | ----- | | Variable interpolation {{x}} | Supported | Output is never HTML-escaped by default — register an escape helper if needed | | Sections {{#x}}…{{/x}} | Supported | Empty arrays falsy on negated branch; truthy scalars do not push as context (Handlebars-style); use $parent/$root to walk the context stack | | Inverted sections {{^x}}…{{/x}} | Supported | Empty arrays correctly treated as falsy | | Comments {{! … }} | Supported | Standalone-line whitespace is stripped | | Triple mustache {{{x}}} | Supported | Output is identical to {{x}} (Bigodin never HTML-escapes by default) | | Ampersand {{&x}} | Supported | Output is identical to {{x}} | | Standalone-line whitespace stripping | Supported | Applied to comments and section open/close tags — see standalone-line-whitespace.md | | Implicit iterator {{.}} | Supported | Resolves to current context (alias of {{$this}}) — see implicit-iterator.md | | Block heads with literal-named keys | Supported | {{#null}} / {{#true}} / {{#false}} / {{#undefined}} look up the matching key in context | | HTML Escaping for {{x}} | Not supported | Bigodin emits raw output; register an escape helper if needed | | Auto context-stack walk on missing keys | Not supported | Bigodin uses strict scoping — use $parent/$root to walk explicitly | | Set Delimiters {{=<% %>=}} | Not planned | See set-delimiters.md | | Partials {{>name}} | Not planned | See partials.md | | Dynamic names {{*name}} (optional) | Not planned | Depends on partials — see dynamic-names.md | | Inheritance {{<p}}{{$b}}… (optional) | Not planned | $ collides with Bigodin's variable syntax — see inheritance.md | | Lambdas (optional) | Not supported | Bigodin's helper API (addHelper) is the recommended alternative — see lambdas.md |

Run yarn test:spec to execute the full Mustache spec suite locally (it clones mustache/spec into test/mustache/ on first run).

Known limitations / not supported

Things Bigodin does not do, by design or because they are out of scope. Read this before reaching for a workaround.

Mustache features

  • No HTML escaping by default. {{x}}, {{{x}}}, and {{&x}} all emit raw output. If you render to HTML, register an escape helper and call it explicitly (or wrap your template in one).
  • No automatic context-stack walking. A missing key resolves to undefined, not the parent context. Walk up explicitly with $parent / $root.
  • No partials ({{>name}}), set-delimiters ({{=<% %>=}}), dynamic names ({{*name}}), or template inheritance ({{<p}}{{$b}}…). See mustache-compat/ for rationale.
  • No Mustache lambdas. Functions placed in the rendering context are not invoked. Use addHelper instead — that is the supported extension point.

Runtime / API

  • Templates are interpreted, never compiled. You cannot get a JavaScript function out of a template; this is the security guarantee, not an oversight.
  • Helpers must be registered ahead of time via addHelper (or the extraHelpers argument to run). Templates cannot define their own helpers, import code, or read files.
  • Module-level parse/run/compile exports do not carry custom helpers. addHelper only mutates the instance it is called on — instantiate new Bigodin() if you need a registry of your own.
  • Only one runtime dependency (pierrejs). New runtime deps are scrutinized; the value prop is "safe to run on user input".

Security boundaries

  • Helper names matching __proto__, constructor, prototype, etc. are rejected — registering or looking them up will throw. This is intentional anti-prototype-pollution behavior; do not work around it.
  • The data channel on Execution is helper-only. Templates cannot read it; helpers can mutate it via this.data to share side-channel state.
  • The context is deep-cloned before each run: your input object is never mutated, prototypes are stripped, and templates read only own, enumerable, non-function properties (so Error.stack and other non-enumerable data stay out of output). Value-typed objects (Date, RegExp, URL, Map, Set, typed arrays) are preserved by value for helpers while their methods stay hidden from templates; Buffer is downgraded to Uint8Array. See the context clone.

If you need one of the unsupported Mustache features, open an issue — most "Not planned" entries have a design note in mustache-compat/ explaining the tradeoff.