(Pronounced "you ate" as in "evaluate"...)
var a = 1, b = 2; eval(uate( "${a} + ${b} = ${a + b}" )); // "1 + 2 = 3"
eval(uate( template ))
eval(uate( tag, template ))
template
must be a string containing zero or more ${expr}
clauses which
are evaluated in the local scope.
tag
is optional, and may either be a named function in scope or a string
containing an expression that in the local scope will yield a function e.g.
'console.log'
. The function is called as tag(strings, ...substitutions)
.
The built-in html
function does HTML entity escaping of &<>"'
in substitutions.
The built-in uri
function applies encodeURIComponent to substitutions.
The built-in halfbaked
function yields escaped strings.
var a = 1, b = 2; eval(uate( "${a} + ${b} = ${a + b}" )); // "1 + 2 = 3"
eval(uate( tag, "a${ 42 }b" )); // whatever tag wants
eval(uate( halfbaked, "a\n${42}b" )); // "a\\n42b"
eval(uate( html, "<p>${untrusted_data}</p>" )); // ampersands galore
eval(uate( url, "http://example.com?q=${search}" )); // percents galore
A trivial tag function has this form:
function tag(strings /*, ...substitutions*/) {
var substitutions = [].slice.call(arguments, 1);
var result = strings[0];
for (var i = 0; i < substitutions.length; ++i) {
result += substitutions[i];
result += strings[i + 1];
}
return result;
}
Although it is not very useful in this ES5 hack, strings.raw
is
another array containing escaped versions of the strings.
ES6 Tagged String Templates, designed by Mike Samuel, et. al.
In ES6 you can write:
var a = 1, b = 2; `${a} + ${b} = ${a + b}`; // "1 + 2 = 3"
tag`a${ 42 }b`; // whatever tag wants
String.raw`a\n${42}b`; // "a\\n42b"
safehtml`<p>${untrusted_data}</p>`; // ampersands galore, and more
While it's not obvious in these examples, in ES6 the tag function is able to access the "raw" (unescaped) string fragments which allows it to implement domain specific languages using its own rich syntax. This ES5 version is just a toy.
Tests are included - run them at: https://inexorabletash.github.io/uate/tests.html
- http://tc39wiki.calculist.org/es6/template-strings/
- http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts
- http://wiki.ecmascript.org/doku.php?id=harmony:quasis
Call without eval() to understand how it works.
Here's a smaller (but less capable) version that fits in a tweet:
function uate(s){return(''+s).split(/\${(.*?)}/).map(function(p,i){
return(i%2)?'('+p+')':JSON.stringify(p);}).join('+');}