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

villain-mustache

v0.4.1

Published

A lightweight and incomplete mustache implementation for generating labels. It only implements {{var/function}}, {{!comment}}, and {{#if var/function}} (elsif, else, endif) blocks.

Readme

villain-mustache

A lightweight and incomplete mustache implementation for generating labels. It only implements {{var/function}}, {{!comment}}, and {{#if var/function}} (else if, else) blocks.

[TOC]

Why

Worst villains, even if tiny, can achieve enormous things. Even if their moustache looks ridiculous: villain moustache

When dealing with internationalization, you might end up with lots of labels, and in most cases they will include variables and conditions, or else end being split up into their components.

This library allows you to have this:

{
	"label1": "Welcome, {{user.name}}!",
    "label2": "You have {{#if user.tasks}}{{user.tasks}}{{else}}no{{/if}} new task{{#if plural}}s{{/if}}."
}

You could of course install a full mustache/handlebars, precompile each label separately, and even hit your head against the wall, but I'd prefer if you wouldn't have to.

Note: It is a bad idea, however, to use this library to take care of pluralization, numbers, dates, and other localization issues that can be solved by other libraries (e.g. i18n).

How

Install it:

npm i villain-mustache --save

Enjoy it:

var villainMustache = require('villain-mustache')

var label = "You have {{#if user.tasks}}{{user.tasks}}{{else}}no{{/if}} new task{{#if plural}}s{{/if}}.";
var context = {
	user: {
    	name: "Gandalf",
        tasks: function() {
            return 9;
        }
    },
    plural: true
};

console.log(villainMustache(label, context));
// You have 9 new tasks.

Test it:

npm i
npm test

Benchmark it against Handlebars:

npm i
npm run benchmark

Spoiler: It is slower than precompiled Handlebars, but way faster than compiling. If performance is key to you, and you have no problem storing the precompiled labels, you should stick with Handlebars.

Allowed Mustaches

{{var}}

Renders the contents of the variable. If it is not a string, node.js's util.inspect(var) will be used.

{{func}}

Calls the function and renders its return value. Parameters are not allowed. If the return value is not a string, node.js's util.inspect(var) will be used.

{{#if cond}}...{{/if}}

Renders the block contents as one would expect an if block to behave. Full form is:

{{#if var}}...[{{else if var2}}...]*[{{else}}]?...{{/if}}

The condition is considered true if and only if:

  • It is a non function variable with a truthy value, or
  • It is a function that returns a truthy value.

{{!comment to be ignored}}

Ignores the contents of the mustache. It's not a block.

Additional Options

The method can be called with an additional configuration parameter:

villainMustache(label, context, configuration);

This configuration is an object that contains the desired customized options. The default options are:

configuration: {
	warningOutput: (message) => {console.warn(message)}
}

Any option that is not present in the default configuration will be ignored.

The Entrails

It consists of a simple and small interpreter that:

  • Parses the label into tokens
  • For each generated token:
    • It executes the token, and
    • Updates the current state in a pile

Its grammar is:

expr => (cond | var | atom)*
cond => if expr (elsif expr)* (else expr)? endif

if => /{{#if \w+}}/
elsif => /{{else if \w+}}/
else => /{{else}}/
endif => /{{/if}}/

var => /{{[\w\._$]+}}/
atom => /.*?/
comment => /{{!.*?}}/