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 🙏

© 2024 – Pkg Stats / Ryan Hefner

ustache

v1.0.3

Published

lightweight mustache-compatible template engine with benfits

Downloads

7

Readme

ustache

mustache templates w/ a micro ES6 core

A 2kb template engine that does 80% of what mustache does, and with extra declarative-view features.

Contents

Design

A RegExp-based transpiler with imports constructs an ES6 template string that evaluates the embeded exressions. It's only about 50 lines of code, making it easy to fork for customized applications. It's written with as few moving peices as possible, with an eye towards customization without complication. - top

Usage

(a string template) to return a function that returns an HTML string when passed an object:

var fnRender = ustache(strTemplate),
strOutput = fnRender(objData);

(a string template and object of data) to invoke immediately:

strOutput=ustache(strTemplate, object);

(a string template, object of data, and object of imports (partials) ) :

strOutput = ustache(strTemplate, objData, objImports); fnRender = ustache(strTemplate, null, objImports); top

Compared to Mustache, Handlebars, and Hogan

ustache is congruent with Mustache/Hogan, with many added features. It's not logic-less (JS expressions can be used mid-template). ustache needs pure functions, so it uses this in front of plain injections (see below). Those injections are also not HTML escaped by default like Mustache. you can both prefix this and HTML escape injections using the {{=name}} tag.

Mustache also differs with minor features: it's hoisting of context, allowing lambdas in data (functions that return functions), iterating the whole data argument as an array using {{#.}}{{.}}{{/.}}, allowing non-valid property identifiers like {{#person?}}, imports importing imports, and allowing custom delimters, none of which ustache supports. Despite the limits, ustache passes about 3/4 of Mustache's unit tests, with the failing ones mainly relate to auto-escaping and hoisting plus the above-noted differences on seldom-used features.

Handlebars shares many capabilities with ustache, but ustache syntax is more explict on the closing tags, ex. {{/title}}{{/comments}} instead of {{/if}}{{/each}}. ustache is also the only mustache engine (afaik) that uses ES6 template strings instead of a full-blown parser. top

Syntax Features

You can use normal Mustche syntax, with a few exceptions and many additions. See the mustache.js project for basic examples, review the unit tests, run them live, or keep reading.

Injection

{{this.name}} | @name | {{=name}} | {{this.sub.name.prop}} | {{this.user['name']}} | {{this.name.bold()}} Inserts the value of the named path. Unlike Mustache, you can use bracket notation and invoke methods inline, even passing arguments to methods via primitives or early-run imports. You can perform calculations mid-expression using virtually any valid javascript expression. You can reach not only in-scope variables, but globals like Math.random() as well. Also keep in mind that you can use ES6 template strings to inject dynamic values into the template before it executes. ex: ustache("Hello {{=name}}", {name: "Fred"}) == "Hello Fred"; ex: ustache("Hello <b>{{this.name}}</b>", {name:"Fred"}) == "Hello <b>Fred</b>"; ex: ustache("Hello @name", {name:"Fred".bold()}) == "Hello <b>Fred</b>"; ex: ustache("Hello {{this.name.bold()}}", {name:"Fred"}) == "Hello <b>Fred</b>"; ex: ustache("Hello {{=name}}", {name:"Fred".bold()}) == "Hello &lt;b&gt;Fred&lt;&#x2F;b&gt;"; ex: ustache("Random Number: {{1/Math.random()}}", {}); // yes, expressions work! top

Imports

{{>name}} Imports use the same syntax, but work slightly differently than Mustache's partials. Whereas Mustache partials are executed in-flow and with surrounding context, ustache imports run globally just prior to templating. Global (flat) processing executes much faster than Mustache's, but also means that ustache imports cannot import other imports. All imported values should be direct properties of the imports object (no nested sub-objects). As they execute, imports simply replace literal text, with no consideration of context or validity. This is a good thing because you can inject template code, and it will get executed as though it were hard-coded, providing a macro-like stage of code execution. top

Looping

{{#arr}} Array Iteration

{{#users}} Iterates data Arrays and repeats their content for each element in the Array. Due to the simplicity of the engine, there is on one restriction on nested looping: you cannont have a duplicated property name iterated on different nested levels; eg. {users:{users:[1,2,3]}} is no good. Note that # tags also provide other capabilities: they acti like switches if fed a boolean, and they drill into nested data objects if they point to an object. ex: ustache("{{#numbers}}#{{/numbers}}", {numbers:[11,22,33]}) == "###"; ex: ustache("{{#numbers}}{{.}} {{/numbers}}", {numbers:[11,22,33]}) == "11 22 33 "; ex: ustache("{{#numbers}}{{.}}{{SEP}}, {{/SEP}}{{/numbers}}", {numbers:[11,22,33]}) == "11, 22, 33"; ex: ustache("{{#numbers}}{{INDEX}}:{{.}} {{/numbers}}", {numbers:[11,22,33]}) == "1:11 2:22 3:33 "; ex: ustache("{{#numbers}}{{INDEX}}:{{.}}{{SEP}}, {{/SEP}}{{/numbers}}", {numbers:[11,22,33]}) == "1:11, 2:22, 3:33"; ex: ustache("{{#numbers}}{{ (this.i%2) ? this.i : ''}}{{/numbers}}", {numbers:[{i:11},{i:22},{i:33}]}) == "1133"; top

{{$obj}} Object Iteration

Iterates over objects using a placeholder KEY name within the section tag. Inside the section KEY will equal the name of the object property's key and . will equal the property value. ex: ustache('{{$a}}{{KEY}}: {{.}} {{/a}}', {a:{b:1,c:5}}) == "b: 1 c: 5 ";

Conditionals

{{#total}} | {{^total}} | {{#section}} Same are mustache, if the target property is non falsy, the contents are included.

{{?total>0}} | {{?section=="home"}} This is a big piece of functionality missing from Mustache.js, and can be quite helpful when constructing views. If the expression returns falsy, the contents are ommited. If the expression is truthy, the contents are included/executed. This can help add "active" classes to navigation and show/hide sections content according to task/location/time/etc. Logic in the template allow declarative view definition and eliminates the need for DOM-binding to achieve view updates. ex: ustache("i is {{?i > 5}}big{{/i > 5}}{{?i<6}}small{{/i<6}}", {i: 2}) == "i is small"; ex: ustache("i is {{?i > 5}}big{{/i > 5}}{{?i<6}}small{{/i<6}}", {i: 9}) == "i is big"; top

Razor Syntax

@lname, @fname | @#users @INDEX: @name @/users "Inspired" by MS's VS/MVC razor templates, this alternative syntax can keep visual boilerplate costs down. You can use it for injection, looping, and conditionals, but the allowed characters are more restricted that the traditional {{}} delimiters (\w\.$|) , so it's not the best choice for complex logic. Lastly, it avoids mistaking email addresses for tokens by insisting upon a non-wordy char to the left of the @. ex: ustache("Hello @name", {name: "Fred"}) == "Hello Fred"; ex: ustache("Chars: @name.length", {name: "Fred"}) == "Chars: 4"; ex: ustache("Hello @user.name", { user: {name: "Fred"} }) == "Hello Fred"; top

{{|path}} else syntax

{{|path}} turns into {{/path}}{{^path}}, for simpler else handling of regular mustache conditionals. ex: ustache("{{#i}}yes{{|i}}no{{/i}}", {i: 9}) == "yes"; ex: ustache("{{#i}}yes{{|i}}no{{/i}}", {i: 0}) == "no"; top

{{INDEX}}

Simple "contstant" that returns the current index when iterating an Array. ex: ustache("{{#numbers}}{{INDEX}}:{{.}} {{/numbers}}", {numbers:[11,22,33]}) == "1:11 2:22 3:33 " top

{{SEP}} mini-section

Simple "constant" that returns the enclosed block for every value except for the last. ex: ustache("{{#numbers}}{{.}}{{SEP}}, {{/SEP}}{{/numbers}}", {numbers:[11,22,33]}) == "11, 22, 33"; top

{{__.key}} root syntax

{{__.key}} reaches key on the data object given to ustache, bypassing local conflicts. ex: ustache('{{#b}}{{a}}|{{__.a}} {{/b}}', {a:123, b:[{a:1}]} ) == "1|123 "; top

{{SCOPE}} state object

SCOPE is a maleable internal object available to templates. You can use it to store view state like scroll positions, checkboxes options, active section, etc. The object is auto-created or passed during the initial call to ustache(), and inherited by imports and all code in the template, allowing templates to act more like components. You can reach this object as SCOPE from any injection, section, or conditional template tag. ex: ustache("{{SCOPE.nick=this.name.bold(),''}} Hello {{SCOPE.nick}}", {name:"Fred"}) == " Hello <b>Fred</b>"; see SCOPE used to make simple components at an online SCOPE demo


top