Skip to content

Instantly share code, notes, and snippets.

@keeyip
Created April 20, 2014 23:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keeyip/11127842 to your computer and use it in GitHub Desktop.
Save keeyip/11127842 to your computer and use it in GitHub Desktop.
Small, fast, compiled templating engine
var tpl = (function() {
var slice = Array.prototype.slice;
function first(xs) {
return xs[0]
}
function rest(xs) {
return slice.call(xs, 1);
}
function flatten(xs) {
var flat = []
if (!xs || !xs[0]) return flat;
var n = xs.length,
x
for (var i=0; i < n; i++) {
x = xs[i];
if (x[0]) {
flat = flat.concat(flatten(x));
break;
}
flat.push(x);
}
return flat;
}
function escapeHtml(str) {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
}
function make_tag(className) {
return {
_type: 'tag',
tagName: 'div',
className: className || '',
children: flatten(rest(arguments))
}
}
function make_input(className) {
return make_tag(className, {
_type: 'input',
className: '',
children: flatten(rest(arguments))
})
}
function make_value(key) {
return {
_type: 'value',
key: key
}
}
function make_text(str) {
return {
_type: 'text',
str: escapeHtml(str)
}
}
function make_html(str) {
return {
_type: 'html',
str: str
}
}
function make_iterator(key) {
return {
_type: 'iterator',
key: key,
children: flatten(rest(arguments))
}
}
function newOptimizer(lambdas) {
return {
lambdas: lambdas,
js: [],
currentJsString: '',
concat: function(str) {
this.currentJsString += str;
},
flushCurrentJsString: function() {
if (this.js.length) this.js.push('+')
if (this.currentJsString) this.js.push(JSON.stringify(this.currentJsString))
this.currentJsString = '';
},
next: function(str) {
this.flushCurrentJsString();
if (str) {
if (this.js.length > 0) this.js.push('+');
this.js.push(str);
}
},
newLambda: function(str) {
this.lambdas.push(str);
return 'lambda' + this.lambdas.length;
},
finalizeLambdas: function() {
if (this.lambdas.length === 0) return '';
return 'var ' + this.lambdas.map(function(lambdaStr, i) {
var lambdaName = 'lambda' + (i+1);
return lambdaName + '=' + lambdaStr;
}).join(',') + ';\n';
},
toFunction: function(decls) {
return new Function('data', (decls||'') + 'return ' + this.js.join(' '));
}
}
}
function compile(node) {
var optimizer = newOptimizer([]);
_compile(node, optimizer);
optimizer.flushCurrentJsString();
return optimizer.toFunction(optimizer.finalizeLambdas());
}
var COMPILE = {
tag: function(node, optimizer) {
var openTag = '<' + node.tagName + ' class="'+node.className+'">';
var closeTag = '</' + node.tagName + '>';
optimizer.concat(openTag);
var n = node.children.length;
for(var i=0; i < n; i++) {
_compile(node.children[i], optimizer);
}
optimizer.concat(closeTag);
},
value: function(node, optimizer) {
optimizer.next(escapeHtml('data["'+node.key+'"]'));
},
input: function(node, optimizer) {
optimizer.concat('<input class="'+node.className+'" value="')
var s = newOptimizer(optimizer.lambdas);
var n = node.children.length;
for(var i=0; i < n; i++) {
_compile(node.children[i], s);
}
s.flushCurrentJsString();
var lambdaName = optimizer.newLambda(s.toFunction().toString());
optimizer.next(lambdaName + '(data)');
optimizer.concat('"/>')
},
text: function(node, optimizer) {
optimizer.concat(node.str)
},
html: function(node, optimizer) {
optimizer.concat(node.str)
},
iterator: function(node, optimizer) {
var buffer = ['data["'+node.key+'"].map('];
var s = newOptimizer(optimizer.lambdas);
var n = node.children.length;
for(var i=0; i < n; i++) {
_compile(node.children[i], s);
}
s.flushCurrentJsString();
var lambdaName = optimizer.newLambda(s.toFunction().toString());
buffer.push(lambdaName);
buffer.push(').join("")');
optimizer.next(buffer.join(''))
}
}
function _compile(node, optimizer) {
COMPILE[node._type](node, optimizer);
}
return {
make_text: make_text,
make_tag: make_tag,
make_input: make_input,
make_value: make_value,
make_html: make_html,
make_iterator: make_iterator,
compile: compile
}
})();
/*
var h = tpl.make_tag,
t = tpl.make_text,
v = tpl.make_value,
each = tpl.make_iterator;
var gridTemplate =
h("grid",
h("row header",
h("cell", t("NAME"))),
each('rows',
h("row",
h("cell", v("name")))));
var f = tpl.compile(gridTemplate);
f
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment