Skip to content

Instantly share code, notes, and snippets.

@kirbysayshi
Last active October 9, 2015 00:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kirbysayshi/3411585 to your computer and use it in GitHub Desktop.
Save kirbysayshi/3411585 to your computer and use it in GitHub Desktop.
Mini, micro, pico vash. The difference between them: mini supports interpolation and explicit expressions, micro only support interpolation. The both implicitely iterate.

For MUCH more information, visit http://kirbysayshi.com/2012/08/30/mini-micro-pico-vash.html

Mini supports stuff like:

@it.Do
@it.realize()

And knows the difference between

"@it.everyone[0]" // quotes are content
"@it.everyone("param")" // inner quotes are expression, outer quotes content
"@it.everyone('param').go" // as deep as it needs!
@it.model. // last period is content, not expression
@it.model[] // brackets are empty, invalid property index, thus are content!

Mini supports explicit expressions ( arbitrary JS that returns a value for output )

@( it.what === false ? 'yeah' : 'what' )
@( (it.what === true) ? 'explicit' : "bad" ) // any number of nested parenthesis
@( it.func() && it.another.property )

If a literal @ is needed, then just double it up:

This is a literal @@. 
// outputs: This is a literal @.

Finally, if a model passed to the compiled function is an array, the template will be called with each element of the array as the model, and the total output returned. Implicit iteration!

Pico only supports simple @property.something expressions of arbitrary depth, and does not HTML encode.

A few silly jsperfs:

window.vashmicro=function(){var g=/(@([a-zA-Z]+(?:(?:[.]+(?!\s|$|"|'|\?))|(?:\[[a-zA-Z0-9'".()=?:]+\])|(?:\([a-zA-Z0-9'".() =?:]*\)))*)+)/g,h=/@(it)|\.([a-zA-Z_]+[a-zA-Z0-9_]*)|\[['"]?([a-zA-Z0-9'".() =?:]+)['"]?\]|\(['"]?([a-zA-Z0-9'".() =?:]*?)['"]?\)/g,f=/(?:vash|html)\.raw/g,i=/[&<>"\'`]/g,j={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},k=function(b){return j[b]},l=/@@/g;return{compile:function(b){return function(c){var d,e="";c instanceof Array||(c=[c]);for(d=0;d< c.length;d++)e+=b.replace(l,"__VESC__").replace(g,function(b){var a=c[d];b.replace(f,"").replace(h,function(b,c,d,e,f){a=d?a[d]:e?a[e]:f?a(f):c?a:a()});return f.test(b)?a.replace(i,k):a}).replace("__VESC__","@");return e}}}}();
// INTERPOLATION: true
// BLOCKS: false
// IGNORES INTERPOLATED KEYWORDS: false
// EXPLICIT EXPRESSIONS: false
// IMPLICIT INTERATION: true
// HTML ESCAPES: true
// AT BLOCKS: false
// AT ESCAPES: true
// CACHED FUNCS: false
// RUNTIME MANUAL LOOKUP: true
window['vashmicro'] = (function(){
var reExp = /(@([a-zA-Z]+(?:(?:[.]+(?!\s|$|"|'|\?))|(?:\[[a-zA-Z0-9'".()=?:]+\])|(?:\([a-zA-Z0-9'".() =?:]*\)))*)+)/g
,reProp = /@(it)|\.([a-zA-Z_]+[a-zA-Z0-9_]*)|\[['"]?([a-zA-Z0-9'".() =?:]+)['"]?\]|\(['"]?([a-zA-Z0-9'".() =?:]*?)['"]?\)/g
,reRaw = /(?:vash|html)\.raw/g
,reHtmlEscape = /[&<>"\'`]/g
,htmlChars = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#x27;", "`": "&#x60;" }
,htmlEscaper = function(m){ return htmlChars[m] }
,reEsc = /@@/g
,esc = '__VESC__'
var lookup = function(str, model){
str
.replace(reRaw, '')
.replace(reProp, function(ma, mo, i, b, p){
model = i ? model[i] : b ? model[b] : p ? model(p) : mo ? model : model();
});
return reRaw.test( str )
? model.replace(reHtmlEscape, htmlEscaper)
: model;
}
return {
'compile': function(str){ return function(model){
var i, all = '';
if( !(model instanceof Array) ) model = [model];
for( i = 0; i < model.length; i++ ){
all += str.replace(reEsc, esc).replace(reExp, function(match){
return lookup(match, model[i]);
}).replace(esc, '@')
}
return all;
} }
}
}());
(function(a){var b=/@(\!?(?:[a-zA-Z]+(?:(?:[.]+(?!\s|$|"|'|\?))|(?:\[[a-zA-Z0-9'".(){}=?:]+\])|(?:\([a-zA-Z0-9'".(){} =?:]*\)))*)+)|@(\!?\(.*?\))@/g,c=/(?:(?:vash|html)\.raw|^\!)/g,d=a.LIB={},e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},f=function(a){return e[a]},g=/[&<>"'`]/g,h=/@@/g,i=/__VESC__/g,j="__VESC__",k=function(a,b){var e=(d[a]||(d[a]=Function("it","return "+a.replace(c,""))))(b);return c.test(a)?e.replace(g,f):e};a.compile=function(a){var c="",d=0;return a=a.replace(/(\()|(\))/g,function(a,b,e,f,g){return g[f-1]=="@"&&(c+=0),d+=a=="("?1:-1,!d&&c.length&&(c=c.slice(0,-1),a+="@"),a}),a=a.replace(h,j),function(c){var d,e="";for(c.splice||(c=[c]),d=0;c.length>d;d++)e+=a.replace(b,function(a,b,e){return k(b||e,c[d])}).replace(i,"@");return e}}})(window.vashmini={})
// INTERPOLATION: true
// BLOCKS: false
// IGNORES INTERPOLATED KEYWORDS: false
// EXPLICIT EXPRESSIONS: true, nested
// IMPLICIT INTERATION: true
// HTML ESCAPES: true
// AT BLOCKS: false
// AT ESCAPES: true
// CACHED FUNCS: true
// RUNTIME MANUAL LOOKUP: false
(function(exports){
var reExp = /@(\!?(?:[a-zA-Z]+(?:(?:[.]+(?!\s|$|"|'|\?))|(?:\[[a-zA-Z0-9'".(){}=?:]+\])|(?:\([a-zA-Z0-9'".(){} =?:]*\)))*)+)|@(\!?\(.*?\))@/g
,reRaw = /(?:(?:vash|html)\.raw|^\!)/g
,LIB = exports['LIB'] = {}
,htmlChars = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#x27;", "`": "&#x60;" }
,htmlReplacer = function(m){ return htmlChars[m]; }
,reHtml = /[&<>"'`]/g
,reEsc = /@@/g
,reEscaped = /__VESC__/g
,esc = '__VESC__'
var lookup = function(str, model){
var ret = (
LIB[str]
||
( LIB[str] = Function('it', 'return ' + str.replace(reRaw, '')) )
)(model);
return reRaw.test(str)
? ret.replace(reHtml, htmlReplacer)
: ret;
}
exports['compile'] = function(str){
var opens = ''
,count = 0
,pidx = 0;
str = str.replace( /(\()|(\))/g, function(m, left, right, idx, str){
if(str[idx-1] == '@') { opens += 0; }
count += m == '(' ? 1 : -1;
if(!count && opens.length){ opens = opens.slice(0,-1); m += '@'; }
return m
})
str = str.replace(reEsc, esc);
return function(model){
var j, all = '';
if( !model.splice ) model = [model];
for( j = 0; j < model.length; j++ ){
all += str.replace(reExp, function(m, i, e){
return lookup(i || e, model[j]);
}).replace(reEscaped, '@');
}
return all;
}
}
}( (window['vashmini'] = {}) ));
window.vashpico=function(){var a=/(@)(!)?(it\.)?([a-zA-Z_0-9$]+\.?[a-zA-Z_0-9$]+)+/g,b={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},c=function(a){return b[a]},d=/[&<>"'`]/g;return{compile:function(b){return b=b.replace(/@@/g,"_VE_"),function(e){var f;return b.replace(a,function(a,b,g,h,i){return f=e,i.replace(/[^.]+/g,function(a){if("undefined"==typeof f[a])throw Error("Could not resolve `"+a+"`");f=f[a]}),g?f:(""+f).replace(d,c)}).replace(/_VE_/g,"@")}}}}();
// INTERPOLATION: limited to .property lookups
// BLOCKS: false
// IGNORES INTERPOLATED KEYWORDS: false
// EXPLICIT EXPRESSIONS: false
// IMPLICIT INTERATION: false
// HTML ESCAPES: true
// AT BLOCKS: false
// AT ESCAPES: true
// CACHED FUNCS: false
// RUNTIME MANUAL LOOKUP: limited to .property
window['vashpico'] = (function(){
var reExp = /(@)(!)?(it\.)?([a-zA-Z_0-9$]+\.?[a-zA-Z_0-9$]+)+/g
,htmlChars = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#x27;", "`": "&#x60;" }
,htmlReplacer = function(m){ return htmlChars[m]; }
,reHtml = /[&<>"'`]/g
return {
'compile': function(str){
str = str.replace(/@@/g, '_VE_');
return function(model){
var m;
return str
.replace(reExp, function(match, at, raw, it, pstr){
m = model
pstr.replace(/[^.]+/g, function(p){
if( typeof m[p] === 'undefined' ) {
throw Error('Could not resolve `' + p + '`')
}
m = m[p];
})
return raw
? m
: ('' + m).replace( reHtml, htmlReplacer );
})
.replace(/_VE_/g, '@')
}
}
}
}());
// INTERPOLATION: true
// BLOCKS: false
// IGNORES INTERPOLATED KEYWORDS: false
// EXPLICIT EXPRESSIONS: false
// IMPLICIT INTERATION: true
// HTML ESCAPES: false
// AT BLOCKS: false
// AT ESCAPES: true
// CACHED FUNCS: false
// RUNTIME MANUAL LOOKUP: false
window['vashzepto'] = (function(){
var reExp = /(@)([a-zA-Z_0-9$]+)/g
, esc = '_VE_'
return function(str){
return function(model){
if( !(model.splice) ) model = [model];
for(var i = 0, all = ''; i < model.length; i++ ){
all += str
.replace(/@@/g, esc)
.replace(reExp, function(match, at, iden){
return model[i][iden];
})
.replace(esc, '@')
}
return all;
}
}
}());
window.vashzepto=function(){var a=/(@)([a-zA-Z_0-9$]+)/g,b="_VE_";return function(c){return function(d){d.splice||(d=[d]);for(var e=0,f="";e<d.length;e++)f+=c.replace(/@@/g,b).replace(a,function(a,b,c){return d[e][c]}).replace(b,"@");return f}}}();
var vstr=function(){var a=/@\!?((?:[a-zA-Z]+(?:(?:[.]+(?!\s|$|"|'|\?))|(?:\[[a-zA-Z0-9'".()=?:]+\])|(?:\([a-zA-Z0-9'".(){} =?:]*\)))*)+)|@\!?(\(.*?\))@/g,b=/(["'])/gi,c=/[\n\r]/gi,d=/\\(["'])/gi,e=/\\[\n\r]/gi,f=/(\()|(\))/g,g=/VEXP\([\s\S]+?\)VEXP/g,h=/VRAW\([\s\S]+?\)VRAW/g,i=/\)VMKPCVMKPO\(/g,j=/VMKPO\(([\s\S]*?)\)VMKPC/g,k=/VRAW\(/g,l=/\)VEXPVEXP\(/g,m=/\)(VEXP|VRAW)/g,n=/VEXP\(/g,o=/\)VMKPC/g,p=/VMKPO\(/g,q={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},r=function(a){return q[a]},s=/[&<>"'`]/g,t=function(a){return(a&&a.charCodeAt?a:"").replace(s,r)},u=function(a){var b="",c=0;return a.replace(f,function(a,d,e,f,g){return(g[f-1]=="@"||g[f-2]=="@"&&g[f-1]=="!")&&(b+=0),c+=a=="("?1:-1,!c&&b.length&&(b=b.slice(0,-1),a+="@"),a})},v=function(a){return a.replace(b,"\\$1").replace(c,"\\n")},w=function(a){return a.replace(d,"$1").replace(e,"\n")},x=function(a){return")VMKPC"+a+"VMKPO("},y=function(a,b){return"VMKPO("+b+")VMKPC"},z=function(a,b,c){return(a[1]==="!"?"VRAW(":"VEXP(")+w(b||c)+(a[1]==="!"?")VRAW":")VEXP")};return tpl=function(b,c){c=c||{},c.modelName=c.modelName||"it",b=v(b),b=u(b).replace(a,z).replace(g,x).replace(h,x).replace(i,"").replace(j,y).replace(k,"(").replace(l,") + (").replace(m,")").replace(n,"__vesc(").replace(o,"' + ").replace(p," + '"),b="return '"+b+"'";var d=Function(c.modelName,"__vesc",b),e=function(a,b){b=b||{};var c="";if(b.iterate!==!1&&a.splice)for(var e=0;a.length>e;e++)c+=d(a[e],t);else c=d(a,t);return c};return e.toString=function(){return d+""},e}}()
// INTERPOLATION: true
// BLOCKS: false
// IGNORES INTERPOLATED KEYWORDS: false
// EXPLICIT EXPRESSIONS: true, nested
// IMPLICIT INTERATION: true
// HTML ESCAPES: true
// AT BLOCKS: false
// AT ESCAPES: false
// CACHED FUNCS: false
// RUNTIME MANUAL LOOKUP: false
var vstr = (function(){
var reExp = /@\!?((?:[a-zA-Z]+(?:(?:[.]+(?!\s|$|"|'|\?))|(?:\[[a-zA-Z0-9'".()=?:]+\])|(?:\([a-zA-Z0-9'".(){} =?:]*\)))*)+)|@\!?(\(.*?\))@/g
,reQuote = /(["'])/gi
,reLineBreak = /[\n\r]/gi
,reEscQuote = /\\(["'])/gi
,reEscLineBreak = /\\[\n\r]/gi
,reParens = /(\()|(\))/g
,reWrappedExp = /VEXP\([\s\S]+?\)VEXP/g
,reWrappedRawExp = /VRAW\([\s\S]+?\)VRAW/g
,reConcatMkp = /\)VMKPCVMKPO\(/g
,reWrappedMkp = /VMKPO\(([\s\S]*?)\)VMKPC/g
,reRawOpen = /VRAW\(/g
,reConcatExp = /\)VEXPVEXP\(/g
,reRawOrExpClose = /\)(VEXP|VRAW)/g
,reExpOpen = /VEXP\(/g
,reMkpClose = /\)VMKPC/g
,reMkpOpen = /VMKPO\(/g
var htmlChars = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#x27;", "`": "&#x60;" }
,htmlReplacer = function(m){ return htmlChars[m]; }
,reHtml = /[&<>"'`]/g
,htmlEscape = function( str ){
return (str && str.charCodeAt ? str : '').replace( reHtml, htmlReplacer );
}
var delineateExplicit = function( str ){
var opens = ''
,count = 0
,pidx = 0;
return str.replace( reParens, function(m, left, right, idx, str){
if(str[idx-1] == '@' || (str[idx-2] == '@' && str[idx-1] == '!') ) { opens += 0; }
count += m == '(' ? 1 : -1;
if(!count && opens.length){ opens = opens.slice(0,-1); m += '@'; }
return m
});
}
var evalEscape = function( str ){
return str.replace(reQuote, '\\$1').replace(reLineBreak, '\\n')
}
var evalUnescape = function( str ){
return str.replace(reEscQuote, '$1').replace(reEscLineBreak, '\n')
}
var reHandleMarkupBorder = function( str ){ return ')VMKPC' + str + 'VMKPO('; }
var reHandleMarkupWrap = function(m, mkp){ return 'VMKPO(' + mkp + ')VMKPC'; }
var reHandleExpWrap = function(m, i, e){
return ( m[1] === '!' ? 'VRAW(' : 'VEXP(' )
+ evalUnescape(i || e)
+ ( m[1] === '!' ? ')VRAW' : ')VEXP' )
}
return tpl = function( str, opts ){
opts = opts || {};
opts['modelName'] = opts.modelName || 'it';
str = evalEscape( str )
str = delineateExplicit( str )
.replace(reExp, reHandleExpWrap)
.replace( reWrappedExp, reHandleMarkupBorder)
.replace( reWrappedRawExp, reHandleMarkupBorder)
.replace( reConcatMkp, '')
.replace( reWrappedMkp, reHandleMarkupWrap)
.replace( reRawOpen, '(')
.replace( reConcatExp, ') + (')
.replace( reRawOrExpClose, ')')
.replace( reExpOpen, '__vesc(')
.replace( reMkpClose, '\' + ')
.replace( reMkpOpen, ' + \'')
str = 'return \'' + str + '\''
var f = new Function(opts.modelName, '__vesc', str)
var linked = function tpl(model, opts){
opts = opts || {};
var all = '';
if( opts.iterate !== false && model.splice ){
for(var i = 0; i < model.length; i++)
all += f( model[i], htmlEscape );
} else {
all = f( model, htmlEscape );
}
return all;
}
linked.toString = function(){ return f.toString() }
return linked;
}
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment