0.0.4 • Published 5 months ago

ts-mustache v0.0.4

Weekly downloads
-
License
ISC
Repository
-
Last release
5 months ago

ts-mustache

Mustache is a pretty good templating libary, but it doesn't play well with TypeScript. ts-mustache makes it better, adding:

  1. type inference from existing Mustache templates
  2. facilities for declaring types and rendering templates

Test

$ npm i
$ npm test

Usage

import { DefaultLoader, Declarer, Renderer } from 'ts-mustache'

const loader = new DefaultLoader({
  dir: './templates',
})

// Generate typedefs
const declarer = new Declarer(loader)
declarer.declare()
  .then(types => fs.writeFileSync('./mustacheTypes.ts', types)

CLI

The same behavior is also available via a small CLI:

ts-mustache --dir=./templates -o ./templates/types.ts

Rendering typed templates

Once types exist in a TemplateMap, the Renderer class provides a convenient way to use them:

import { TemplateMap } from './mustacheTypes'

const loader = new DefaultLoader<TemplateMap>({
  dir: './templates',
})

const renderer = new Renderer<TemplateMap>(loader)

renderer.render('post', { title: 'Foobar' })
  .then(rendered => console.log(rendered))

Philosophy

Mustache goes to heroic efforts to resolve and/or handle missing data at runtime, recursing through previously-seen context to attempt to fill in references with something. Further, a template like {{ name }} implies that a variable called name is expected, but nothing about its type (integer? string? vegetable? mineral?) or nullability. Clearly, indeterminate behavior makes inference a challenge.

The Declarer class in this library attempts an imperfect balancing act between overly-restrictive and so-broad-as-to-be-functionally-useless type declarations based on the Mustache spec and common usage patterns seen in the wild.

Using ts-mustache with an existing template library is likely to turn up some cases where types can't be neatly inferred.

{{#items.length}}
<ul>
  {{#items}}
  <li>{{name}}</li>
  {{/items}}
</ul>
{{/items.length}}

A JavaScript programmer will easily recognize that the {{ items }} referenced in the template likely correspond to an array, and that the template is using type coercion from items.length to skip rendering an empty array.

This library isn't that smart.

Fortunately, most of these cases can be resolved by tweaking how data are prepared--and type-checking will make these changes relatively safe to enact!

const templateData = {
  arr: items.length ? items : undefined
}
{{#arr}}
<ul>
  {{#items}}
  <li>{{name}}</li>
  {{/items}}
</ul>
{{/arr}}

There are likely many other cases that can/should be resolved by this library, too--if you find one, please submit an issue or pull request!

License

ISC

0.0.3

6 months ago

0.0.4

5 months ago

0.0.2

10 months ago

0.0.1

10 months ago