Skip to content

Instantly share code, notes, and snippets.

@obenjiro
Last active August 29, 2015 13:59
Show Gist options
  • Save obenjiro/10993113 to your computer and use it in GitHub Desktop.
Save obenjiro/10993113 to your computer and use it in GitHub Desktop.
Shortest template engine with JavaScript support and escaping
//this is data // noprotect
var context = {
keys:[0,1,2,3,null],
key:"<b>test</b>"
};
//this is template
function _template(){
for (var i=0; i < context.keys.length; i++) {
div.b;
if (context.keys[i] === 0) {
span.raw('zero').span;
} else {
partial(_item, context.keys[i]);
}
span.raw(", index: " + i).span;
div.e;
}
with (context){
div.key.div;
}
}
//this is also a template but it will be called as a sub template
function _item(){
span['class="red"'].
context!==null?context:'null value'
.span;
}
//this is an "engine"
function render(_template_, context, logger, escape){
var result, r = "",
div = span = {},
raw = function(t){return t;}
escape == null && (escape = true);
function partial(tmp, ctx) { return render(tmp, ctx, logger, false); }
escape && (context = JSON.parse(JSON.stringify(context)
.replace(/</g,'&lt;')
.replace(/>/g,'&gt;')));
result = _template_.toString()
.replace(/function (\w+)\(\){/,'(function $1(){')
.replace(/\}$/, '})()')
.replace('partial(', 'r+=partial(')
.replace(/(div|span)\.b/g, 'r+="<$1>";')
.replace(/(div|span)\.e/g, 'r+="</$1>";')
.replace(/(div|span)(?:\['([^.']+)'\])?\./g,"r+='<$1 $2>'+(")
.replace(/\.(div|span)/g,')+"</$1>"')
;
logger&&logger(result); eval(result);
return r;
}
function compile(_template_){
var result, r = "", ms,
div = span = {},
raw = function(t){return t;}
result = _template_.toString()
.replace(/function (\w+)\(\){/,'(function $1(){')
.replace(/\}$/, '})()')
.replace('partial(', 'partial(')
.replace(/(div|span)\.b/g, 'r+="<$1>";')
.replace(/(div|span)\.e/g, 'r+="</$1>";')
.replace(/(div|span)(?:\['([^.']+)'\])?\./g,"r+='<$1 $2>'+(")
.replace(/\.(div|span)/g,')+"</$1>"')
;
var z =0;
while (ms = result.match(/partial\([_\w\d\.]+/g)) {
if (z > 100) break;
for (var i=0; i<ms.length; i++) {
var tn = ms[i].replace('partial(','');
var com = compile(eval(tn), context);
result = result.replace(tn, com.replace('})()','})'));
z++;
}
}
return result;
}
function run(result, context, escape){
var result, r = "",
div = span = {},
raw = function(t){return t;}
escape == null && (escape = true);
escape && (context = JSON.parse(JSON.stringify(context)
.replace(/</g,'&lt;')
.replace(/>/g,'&gt;')));
function partial(fn, ctx) {
var oldCtx = context;
context = ctx;
fn();
context = oldCtx;
}
eval(result)
return r;
}
var ct = compile(_template);
console.time('templates render time');
//calling our render function
for(var i =0; i < 1000; i++) {// noprotect
var res = run(ct, context);
//var res = run(compile(_template), context);
//var res = render(_template, context);
}
console.timeEnd('templates render time');
document.body.innerHTML = res;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment