Skip to content

Instantly share code, notes, and snippets.

@twolfson
Last active August 29, 2015 13:57
Show Gist options
  • Save twolfson/9657798 to your computer and use it in GitHub Desktop.
Save twolfson/9657798 to your computer and use it in GitHub Desktop.
Reverse template proof of concept
node_modules/
var mustache = require('mustache');
var template = 'hello {{#world}}moon{{/world}}';
var ast = mustache.parse(template);
var content = mustache.render(template, {world: true});
// console.log(ast[1]);
// console.log(content);
// TODO: We should still probably draw out an automata diagram
// But... let's re-invent regular expressions with booleans
// Works well in prolog. I am sure there is a better way to do it.
// ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'] = ['h', 'e', 'l', 'l', 'o', X1, X2, X3, X4, X5]
// TODO: We probably want one of these http://en.wikipedia.org/wiki/Backtracking
// Bleh, not straight forward.
// This says depth first traversal. Let's do that and aim for the first working solution.
// TODO: Relocate into a full repo with tests
// TODO: Since mustache is ambiguous, we should require a schema to get our feet off the ground. It will significantly help with nested info
// DEV: If we were to use regular expressions, we would lose accuracy of re-using variable values
function dfs(content, tokens) {
var i = 0;
var len = tokens.length;
var tokensByName = {};
var meta = {};
// TODO: We should be re-using tokensByName from top-levels (via deep clone)
// TODO: Figure out how the hell to deal with subpaths (maybe getval, setval)
// TODO: We are going to need to use sub-tokensByName as with mustache. Maybe re-use their lookup tooling?
var retObj = {
meta: meta,
tokensByName: tokensByName
};
for (; i < len; i++) {
var token = tokens[i];
var type = token[0];
switch (type) {
case '#': // If/loop
// Treat as `if` for now
// TODO: Recurse but I am out of time
// TODO: This is going to have to stop matching the subcontent at some point
// hello {{moon}} and more
var subtokens = token[4];
var result = dfs(content, subtokens);
// If the content matched, save our boolean as true
if (result) {
tokensByName[token[1]] = true;
// TODO: These actions can probably be abstracted
content = content.slice(result.meta.length);
meta.length = (meta.length || 0) + result.meta.length;
// Otherwise, mark the boolean as false
// DEV: This will fail on future steps if it is not `false` either
} else {
tokensByName[token[1]] = false;
}
break;
case 'text': // Text
// Slice the next snippet of text
var expectedText = token[1];
var actualText = content.slice(0, expectedText.length);
// If it does not match, reject it
if (actualText !== expectedText) {
return false;
} else {
meta.length = (meta.length || 0) + expectedText.length;
content = content.slice(expectedText.length);
}
break;
}
}
return retObj;
}
console.log('result ', dfs(content, ast));
{
"name": "gist-reverse-template-poc",
"description": "The best project ever.",
"version": "0.1.0",
"homepage": "https://github.com/todd/gist-reverse-template-poc",
"author": {
"name": "Todd Wolfson",
"email": "todd@twolfson.com",
"url": "http://twolfson.com/"
},
"repository": {
"type": "git",
"url": "git://github.com/todd/gist-reverse-template-poc.git"
},
"bugs": {
"url": "https://github.com/todd/gist-reverse-template-poc/issues"
},
"licenses": [
{
"type": "UNLICENSE",
"url": "https://github.com/todd/gist-reverse-template-poc/blob/master/UNLICENSE"
}
],
"main": "index",
"engines": {
"node": ">= 0.8.0"
},
"scripts": {
"test": "echo \"No tests =(\" 1>&2 && exit 1"
},
"dependencies": {
"mustache": "~0.8.1"
},
"devDependencies": {},
"keywords": [],
"private": true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment