Skip to content

Instantly share code, notes, and snippets.

@lujjjh
Last active January 16, 2017 13:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lujjjh/a49b416c89426d3a4ca44234f4177a83 to your computer and use it in GitHub Desktop.
Save lujjjh/a49b416c89426d3a4ca44234f4177a83 to your computer and use it in GitHub Desktop.
Another template "engine" for JavaScript
function compile(template) {
function expandFilter(expr) { return expr.replace(/^(.+?)(?:|(\|[^()]+))?$/, function ($0, expr, filters) {
if (!filters) return expr;
filters = filters.split(/\s*\|\s*/g).reverse();
return filters.join('(') + '(' + expr + filters.map(function () { return ')'; }).join('');
}); }
return new Function(
'with(this){with(arguments[0]){var out="' +
template.replace(/\\([@{}\\])|\{\{\s*([^]+?)\s*\}\}|^\s*@\s*(.+)|([^])/gm,
function ($0, escaped, expr, stat, ch) {
return expr ? '"+((' + expandFilter(expr) + ')+"").replace(/&/,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")+"' :
stat ? '";' + stat + ';out+="' :
(ch || escaped).replace(/["\\]/g, '\\$&').replace(/[\r\n]/g, '\\n');
}) +
'";return out;}}'
);
}
let ctx = {
upper: Function.prototype.call.bind(''.toUpperCase),
lower: Function.prototype.call.bind(''.toLowerCase)
};
console.log(compile(`
<h1>{{ title }}</h1>
@ for (let feature of features) {
<dl>
<dt>{{ upper(feature.name) }}</dt>
<dd>{{ feature.desc | lower }}</dd>
</dl>
@ }
\\@That \\\\ I won't be \\{{ parsed }}.
`).call(ctx, {
title: 'micro.template.js<script>alert("XSS!!!");</script>',
features: [
{ name: 'Lightweight & Lightweight', desc: '533 bytes (uglified)' },
{ name: '...', desc: 'However...I have no idea why I have to use this' }
]
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment