JavaScript AST templating
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


JavaScript AST templates written with JavaScript

NPM version Build status Dependency Status devDependency Status Coverage Status Code Climate Dependency Status


JavaScript templating is often done through string based template engines.

I wanted to try using AST trees directly instead, it has some advantages:

  • templates remain valid JavaScript. You can just test it by running node my.tpl.js.
  • your linter/syntax highlighter, auto-completer just works,
  • i had fun coding it :p

Since JavaScript identifiers syntax accepts some Emojis, we can add some extra informations right into them to bring some logic in.

Disclaimer: This module is just an experiment, use it at your own risks.


const asttpl = require('asttpl');

// Here we repeat the property assignation
// for each methods
// The repeat transformation create a context in
// which the object it currently iterates on
// can provide values to subtree of the AST
// see the transformations section for more details
const template = `
module.exports = {
  𐅙repeat𐅙methods𐅙name: 𐅙literal𐅙name𐅂upper

// Filters may be set to templated values
const filters = {
  upper: str => str.toUpperCase()

const data = {
  methods: [{
    name: 'get'
  }, {
    name: 'put'

// Template values are picked into the data
// variable but you can provide several sources
// for templating, this is why the third argument
// is an array
assert.equal(asttpl({ filters }, template, [data])`
module.exports = {
  get: 'GET',
  put: 'PUT',


This is just a simple summary but you should look at the tests to see how it really works.

Variable replacement

Pattern: 𐅙variable𐅙${path}𐅂${filter1}𐅂${filter2}𐅂${filterN} Usage:

  • function names
  • variables declarations
  • variables lookups
  • property names

Replace a variable name by its matched value after applying it given filters if any. Changing:

let 𐅙variable𐅙myPath𐅂myFilter;


let myShinyNewName;

Literal replacement

Pattern: 𐅙literal𐅙${path}𐅂${filter1}𐅂${filter2}𐅂${filterN} Usage:

  • variables lookups

Change a variable by a literal with its matched value. Changing:

const myConstant = 𐅙literal𐅙myPath𐅂myFilter;


const myConstant = 'myGeneratedValue';


Pattern: 𐅙repeat𐅙${entriesPath}𐅂${filter1}𐅂${...filterN}``𐅙${namePath}𐅂${filter1}𐅂${...filterN} Usage:

  • variables declarations
  • functions declarations
  • object patterns

Repeat functions/variable/properties declarations. Changing:

const myConstant = {
  𐅙repeat𐅙myEntriesPath𐅂myFilter𐅙myNamePath𐅂myFilter: 𐅙literal𐅙myRelativePath


const myConstant = {
  myProp1: 'myRelativeValue1',
  myProp2: 'myRelativeValue2',
  myProp3: 'myRelativeValue3'

Custom transformations

Pattern: 𐅙transform𐅙${transformationName}𐅙${path} Usage:

  • any identifier

Apply custom transformationName to the identifier and the path resolved values.

Template values picker

Values used for templates are picked with miniquery. Refer to its documentation for more details.

The following path characters had to be mapped in order to keep syntactically valid templates:

  • the path separator . becomes 𐅞,
  • the wildcard * becomes 𐅆,
  • the array items matcher # becomes 𐅅,
  • the object properties matcher @ becomes 𐅄.


compileTpl(context, template, valuesStack) ⇒ String

Compile an run a template

Kind: global function
Returns: String - The templating result

Param Type Description
context Object Context (destructured)
context.transformations Object Map for template transformations
context.filters Object Map for filter filters
context.recastOptions Object Recast options object
template String The actual template
valuesStack Array.<Object> The values to fill the template