Simple json template language
JavaScript
Latest commit 554871c Aug 10, 2013 @camshaft Add logging metadata
Permalink
Failed to load latest commit information.
lib Add logging metadata Aug 11, 2013
test Alias reduce and collect Aug 11, 2013
.gitignore Add component json Aug 10, 2013
.travis.yml Release 0.1.0 Aug 10, 2013
LICENSE Initial commit Aug 10, 2013
Makefile Add component json Aug 10, 2013
README.md
component.json Release 0.1.2 Aug 11, 2013
index.js
package.json Release 0.1.2 Aug 11, 2013

README.md

jsont Build Status

Simple json template language

Installation

$ npm install jsont
$ component install CamShaft/jsont

Features

  • Simple
  • Valid JSON
  • Extensible
  • Auto-parallelization of templated properties

Example

Input:

{
  "name": "`user.firstName`",
  "birthday": "`user.birthday | date:'MMMM Do'`",
  "addresses": "`user.addresses | map | partial:address`"
}

Output:

{
  "name": "Cameron",
  "birthday": "September 19th",
  "addresses": [
    {
      "street": "123 Fake Street",
      "city": "Nowhere",
      "country": "USA"
    },
    {
      "street": "Broadway Street",
      "city": "NY",
      "country": "USA"
    }
  ]
}

Usage

var jsont = require('jsont')();

var template = require('./my-template.json');

var options = {};

jsont.render(template, options, function(err, out) {
  console.log(out);
});

Helpers

You can easily extend jsont by calling use:

var jsont = require('jsont')();

jsont.use('reverse', function(input, next) {
  next(null, input.split("").reverse().join(""));
});

In your template you can then call the helper by piping data to it:

{
  "reversed-name": "'Cameron' | reverse"
}

Out comes:

{
  "reversed-name": "noremaC"
}

You can also pass arguments and chain helpers

{
  "list": "'1,2,3,4,5' | split:',' | map | to-int"
}
jsont.use('split', function(input, separator, next) {
  next(null, input.split(separator));
});

jsont.use('to-int', function(input, next) {
  next(null, parseInt(input));
});

And we get:

{
  "list": [
    1,
    2,
    3,
    4,
    5
  ]
}

Parallelization

Since helpers are all asynchronous behind the scenes we get parallelization in a simple form:

var api = require('./api');

jsont.use('user-likes', function(user, next) {
  if (typeof user !== 'object') user = {id: user};

  api.likes(user.id, function(err, likes) {
    if (err) return next(err);

    user.likes = likes;
    next(null, user);
  });
});

jsont.use('user-followers', function(id, next) {
  api.followers(id, next);
});

jsont.use('user', function(id, next) {
  api.get(id, function(err, user) {
    if (err) return next(err);

    user.id = id;
    next(null, user);
  });
});

jsont.use('length', function(user, property, position, next) {
  if (typeof position === 'function') return position(null, user[property].length);
  user[position] = user[property].length;
  next(null, user);
});

jsont.renderFile('user-profile.json', {id: 0}, function(err, out) {
  console.log(out);
});
{
  "id": "`id`",
  "likes": "`id | user-likes | length:likes`",
  "followers": "`id | user-followers | map | user | user-likes | length:likes,likes`"
}

Everything gets put on the event loop and renders as responses come back.

{
  "id": "1",
  "likes": 4,
  "followers": [
    {
      "id": "2",
      "name": "Scott",
      "likes": 3
    },
    {
      "id": "3",
      "name": "Dave",
      "likes": 2
    }
  ]
}

Tests

$ npm test

TODO

  • Create a richer evaluator to do something like:

    {
      "user": "`{id: id, name: name} | my-helper`"
    }
  • Cache compiled templates using the filename option
  • Expose concurrency settings
  • Allow option to configure escape character