Intro
This is an experiment in using a syntax like mustache / handlebars templates as a data storage format. (What I would call "reverse templating" -- but I see people already using that term to mean something else.) That is, instead of render content from an object into a template, extract content out of a template-like document into a key-value hash object. Why this instead of something like JSON? Easier to read and edit, multiline, basically no escaping. And YAML? That was the closest existing thing I could think of, but I don't like that indentation is significant and I prefer a more straightforward way to indicate whether or not the content should be HTML-escaped.
"Data" storage really means content storage. The prototypical use case is to store multiple snippets of HTML (or similar content) in a file. For example, multiple chunks of content that correspond to the placeholders in a template representing a page can be stored in a single, easily readable and editable text file.
Example
Input:
{{{{content key="section_id"}}}}about{{{{/content}}}} {{{{content key="head"}}}}<link rel="stylesheet" href="about.css" media="all" />{{{{/content}}}} {{{{content key="primary"}}}} <p>This is some content.</p> {{{{/content}}}}
Output:
section_id: 'about' head: '<link rel="stylesheet" href="about.css" media="all" />\n' primary: '\n<p>\nThis is some content.\n</p>\n\n'
Design
The original idea was to use a format like this:
Input:
{{a}}<p>{{/a}}or{{#a}}<p>{{/a}}
Output:
a: '<p>'
Input:
{{{a}}}<p>{{{/a}}}or{{{#a}}}<p>{{{/a}}}
Output:
a: '<p>'
But then I realized I could get Handlebars to do the heavy lifting of implementing this by using its raw block helper syntax:
Input:
{{{{content key="a"}}}}<p>{{{{/content}}}}
Output:
a: '<p>'
Input:
{{{{content key="a" escape="html"}}}}<p>{{{{/content}}}}
Output:
a: '<p>'
This even handles embedding Handlebars templates within the snippets. (With the caveat that Handlebars does not currently support nesting raw blocks. See wycats/handlebars.js#1056.) It's unfortunate that it requires so many {{{{
chars, and there may be undesirable performance implications, but it's great for a proof of concept.
Input
This will process input like the following:
{!-- Sets a property named `a`. In other words, targetObject.a will equal "A".--}{{{{content key="a"}}}}A{{{/content}}}} {!-- Sets a property of `a` named `b`. In other words, targetObject.a.b will equal "B".--}{{{{content path="a.b"}}}}B{{{/content}}}} {!-- Will HTML-escape the value.--}{{{{content key="a" escape="html"}}}}A&B{{{/content}}}}
Usage
$ npm install stache-backwards
var stache_back = handlebars data; data = stache_back;
API
/** * Extracts content from a template. * * @param object opts Options * @param object|undefined opts.handlebars Instance of handlebars to use. * @param string|function opts.template Template to extract from. String or * return value of handlebars.compile(). * @param object|undefined opts.target Object to populate with content. * @param string|undefined opts.blockName Name of the handlebars block (helper). * @return object Hash of the content. */handlebars