Skip to content
Browse files

Add Last-Modified and Content-Length headers support to compiler midd…

…leware. Add usage example of compiler middleware.
  • Loading branch information...
1 parent fc11416 commit f9fe0be868294363e70a665c7b290463b12eaebd @baryshev committed Jan 27, 2013
Showing with 654 additions and 639 deletions.
  1. +2 −2 ect.min.js
  2. +10 −0 examples/compiler.js
  3. +641 −636 lib/ect.js
  4. +1 −1 package.json
View
4 ect.min.js
@@ -1,5 +1,5 @@
/*!
- * ECT CoffeeScript template engine v0.4.6
+ * ECT CoffeeScript template engine v0.4.7
* https://github.com/baryshev/ect
*
* Copyright 2012, Vadim M. Baryshev <vadimbaryshev@gmail.com>
@@ -16,4 +16,4 @@
* Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
* Released under the MIT license
*/
-(function(){"use strict";var fs,path,CoffeeScript,ECT=function(options){if(!(this instanceof ECT))return new ECT(options);var ect=this;this.options={open:"<%",close:"%>",ext:"",cache:!0,watch:!1,root:""};var trimExp=/^[ \t]+|[ \t]+$/g,newlineExp=/\n/g,cache={},watchers={},indentChars={":":":",">":">"},escapeExp=/[&<>"]/,escapeAmpExp=/&/g,escapeLtExp=/</g,escapeGtExp=/>/g,escapeQuotExp=/"/g,regExpEscape=function(e){return String(e).replace(/([.*+?\^=!:${}()|\[\]\/\\])/g,"\\$1")},parse=function(template){var lineNo=1,bufferStack=["__ectOutput"],bufferStackPointer=0,buffer=bufferStack[bufferStackPointer]+" = '",matches=template.split(new RegExp(regExpEscape(ect.options.open)+"((?:.|[\r\n])+?)(?:"+regExpEscape(ect.options.close)+"|$)")),output,text,command,line,prefix,postfix,newline,indentChar,indentation="",indent=!1,indentStack=[],indentStackPointer=-1,baseIndent,lines,j;for(var i=0;i<matches.length;i++){text=matches[i],command="";if(i%2===1){line="__ectFileInfo.line = "+lineNo;switch(text.charAt(0)){case"=":prefix="' + ("+line+"\n'') + __ectTemplateContext.escape(",postfix=") + '",newline="",text=text.substr(1),output="escaped";break;case"-":prefix="' + ("+line+"\n'') + ((",postfix=") ? '') + '",newline="",text=text.substr(1),output="unescaped";break;default:prefix="'\n"+line,postfix="\n"+bufferStack[bufferStackPointer]+" += '",newline="\n",output="none"}text=text.replace(trimExp,""),command=text.split(/[^a-z]+/)[0];if(indentChar=indentChars[text.charAt(text.length-1)])text=text.replace(/:$/,"").replace(trimExp,""),indentChar===">"&&(/[$a-z_][0-9a-z_$]*[^=]+(-|=)>/i.test(text.replace(/'.*'|".*"/,""))&&(indentStack.push("capture_output_"+output),indentStackPointer++),bufferStack.push("__ectFunction"+bufferStackPointer),bufferStackPointer++,postfix="\n"+bufferStack[bufferStackPointer]+" = '",command="function"),indentStack.push(command),indentStackPointer++,indent=!0;switch(command){case"include":output==="none"&&(prefix="' + ("+line+"\n'') + (",postfix=") + '"),buffer+=prefix.replace(newlineExp,"\n"+indentation)+text+postfix.replace(newlineExp,"\n"+indentation);break;case"block":bufferStack.push("__ectTemplateContext.blocks['"+text.replace(/block\s+('|")([^'"]+)('|").*/,"$2")+"']"),bufferStackPointer++,prefix="'\n",postfix="\n"+bufferStack[bufferStackPointer]+" += '",text="if "+text,buffer+=prefix.replace(newlineExp,"\n"+indentation)+text,indent&&(indentation+=" ",indent=!1),buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"content":output==="none"&&(prefix="' + ("+line+"\n'') + (",postfix=") + '"),text==="content"&&(text="content()"),buffer+=prefix.replace(newlineExp,"\n"+indentation)+text+postfix.replace(newlineExp,"\n"+indentation);break;case"end":prefix="'";switch(indentStack[indentStackPointer]){case"block":bufferStack.pop(),bufferStackPointer--,prefix="'",postfix="\n"+bufferStack[bufferStackPointer]+" += '",buffer+=prefix.replace(newlineExp,"\n"+indentation),indentation=indentation.substr(2),buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"when":postfix="\n"+bufferStack[bufferStackPointer]+" += ''",buffer+=prefix.replace(newlineExp,"\n"+indentation)+postfix.replace(newlineExp,"\n"+indentation),indentation=indentation.substr(2);break;case"function":prefix="'\n"+bufferStack[bufferStackPointer],buffer+=prefix.replace(newlineExp,"\n"+indentation),indentation=indentation.substr(2),bufferStack.pop(),bufferStackPointer--,postfix="\n"+bufferStack[bufferStackPointer]+" += '";switch(indentStack[indentStackPointer-1]){case"capture_output_escaped":indentStack.pop(),indentStackPointer--,buffer+=")";break;case"capture_output_unescaped":indentStack.pop(),indentStackPointer--,buffer+=") ? '')";break;case"capture_output_none":indentStack.pop(),indentStackPointer--}buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"switch":prefix="\n"+line;default:indentStack[indentStackPointer-1]==="switch"&&(postfix=""),indentation=indentation.substr(2),buffer+=prefix.replace(newlineExp,"\n"+indentation)+postfix.replace(newlineExp,"\n"+indentation)}indentStack.pop(),indentStackPointer--;break;case"else":indentStack[indentStackPointer-1]==="switch"?prefix="":prefix="'",buffer+=prefix.replace(newlineExp,"\n"+indentation);if(indentStack[indentStackPointer-1]==="if"||indentStack[indentStackPointer-1]==="else")indentStack.splice(-2,1),indentStackPointer--,indentation=indentation.substr(2);buffer+=(newline.length?newline+indentation:"")+text,indent&&(indentation+=" ",indent=!1),buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"switch":buffer+=prefix.replace(newlineExp,"\n"+indentation)+(newline.length?newline+indentation:"")+text,indent&&(indentation+=" ",indent=!1);break;case"when":buffer+=(newline.length?newline+indentation:"")+text,indent&&(indentation+=" ",indent=!1),buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"extend":text="__ectExtended = true\n__ectParent = "+text.replace(/extend\s+/,"");default:if(/\n/.test(text)){lines=text.split(/\n/),buffer+=prefix.replace(newlineExp,"\n"+indentation);for(j=0;j<lines.length;j++){if(/^\s*$/.test(lines[j]))continue;typeof baseIndent=="undefined"&&(baseIndent=new RegExp("^"+lines[j].substr(0,lines[j].search(/[^\s]/)))),buffer+=(newline.length?newline+indentation:"")+lines[j].replace(baseIndent,"")}lines=undefined,baseIndent=undefined}else buffer+=prefix.replace(newlineExp,"\n"+indentation)+(newline.length?newline+indentation:"")+text;indent&&(indentation+=" ",indent=!1),buffer+=postfix.replace(newlineExp,"\n"+indentation)}}else indentStack[indentStackPointer]!=="switch"&&(buffer+=text.replace(/[\\']/g,"\\$&").replace(/\r/g,"").replace(newlineExp,"\\n").replace(/^\\n/,""));lineNo+=text.split(newlineExp).length-1}return buffer+="'\nif not __ectExtended\n return __ectOutput\nelse\n __ectContainer = __ectTemplateContext.load __ectParent\n __ectFileInfo.file = __ectContainer.file\n __ectFileInfo.line = 1\n __ectTemplateContext.childContent = __ectOutput\n return __ectContainer.compiled.call(this, __ectTemplateContext, __ectFileInfo, include, content, block)",buffer="__ectExtended = false\n"+buffer,eval("(function __ectTemplate(__ectTemplateContext, __ectFileInfo, include, content, block) {\n"+CoffeeScript.compile(buffer,{bare:!0})+"});")},read=function(file){if(Object.prototype.toString.call(ect.options.root)==="[object Object]"){var data=eval("(ect.options.root."+file+")");if(Object.prototype.toString.call(data)==="[object String]")return data;throw new Error("Failed to load template "+file)}try{return fs.readFileSync(file,"utf8")}catch(e){throw new Error("Failed to load template "+file)}},TemplateContext=function(e){this.blocks={},this.data=e||{},this.childContent=""};TemplateContext.prototype.escape=function(e){if(e==null)return"";var t=e.toString();return escapeExp.test(t)?t.replace(escapeAmpExp,"&#38;").replace(escapeLtExp,"&#60;").replace(escapeGtExp,"&#62;").replace(escapeQuotExp,"&#34;"):t},TemplateContext.prototype.block=function(e){return this.blocks[e]||(this.blocks[e]=""),!this.blocks[e].length},TemplateContext.prototype.content=function(e){return e&&e.length?this.blocks[e]?this.blocks[e]:"":this.childContent},TemplateContext.prototype.load=function(template){var file,compiled,container,data;if(ect.options.cache&&cache[template])return cache[template];var extExp=new RegExp(ect.options.ext+"$");Object.prototype.toString.call(ect.options.root)==="[object String]"?typeof process!="undefined"&&process.platform==="win32"?file=path.normalize((ect.options.root.length&&template.charAt(0)!=="/"&&template.charAt(0)!=="\\"&&!/^[a-zA-Z]:/.test(template)?ect.options.root+"/":"")+template.replace(extExp,"")+ect.options.ext):file=path.normalize((ect.options.root.length&&template.charAt(0)!=="/"?ect.options.root+"/":"")+template.replace(extExp,"")+ect.options.ext):file=template,data=read(file);if(data.substr(0,24)==="(function __ectTemplate(")try{compiled=eval(data)}catch(e){throw e.message=e.message+" in "+file,e}else try{compiled=parse(data)}catch(e){throw e.message=e.message.replace(/ on line \d+/,"")+" in "+file,e}return container={file:file,compiled:compiled,source:compiled.toString(),gzip:null},ect.options.cache&&(cache[template]=container),ect.options.watch&&(watchers[file]=fs.watch(file,function(){watchers[file].close(),delete watchers[file],delete cache[template]})),container},TemplateContext.prototype.render=function(e,t){var n=this,r=this.load(e),i={file:r.file,line:1};try{return r.compiled.call(t||this.data,this,i,function(){return n.render.apply(n,arguments)},function(){return n.content.apply(n,arguments)},function(){return n.block.apply(n,arguments)})}catch(s){throw/ in /.test(s.message)||(s.message=s.message+" in "+i.file+" on line "+i.line),s}},this.configure=function(e){e=e||{};for(var t in e)this.options[t]=e[t]},this.render=function(e,t,n){var r=new TemplateContext(t);return r.render(e)},this.render=function(e,t,n){var r;if(typeof arguments[arguments.length-1]!="function")return r=new TemplateContext(t),r.render(e);arguments.length===2&&(n=t,t={}),r=new TemplateContext(t);try{n(undefined,r.render(e))}catch(i){n(i)}},typeof module!="undefined"&&module.exports&&(this.compiler=function(e){var t=require("zlib");e=e||{},e.root=e.root||"/",e.root="/"+e.root.replace(/^\//,""),e.root=e.root.replace(/\/$/,"")+"/";var n=new RegExp("^"+e.root);return function(r,i,s){if(r.url.substr(0,e.root.length)===e.root){var o=r.url.replace(n,"");try{var u=new TemplateContext,a=u.load(o);i.setHeader("Content-Type","application/x-javascript; charset=utf-8"),e.gzip?(i.setHeader("Content-Encoding","gzip"),a.gzip===null?t.gzip(a.source,function(e,t){e?s(e):(a.gzip=t,i.end(a.gzip))}):i.end(a.gzip)):i.end(a.source)}catch(f){s(f)}}else s()}}),this.configure(options)};if(typeof module!="undefined"&&module.exports)fs=require("fs"),path=require("path"),CoffeeScript=require("coffee-script"),module.exports=ECT;else{Array.prototype.filter||(Array.prototype.filter=function(e,t){var n=this.length,r=[],i,s;if(typeof e!="function")throw new TypeError;for(i=0;i<n;i++)i in this&&(s=this[i],e.call(t,s,i,this)&&r.push(s));return r});var split;split=split||function(e){var t=String.prototype.split,n=/()??/.exec("")[1]===e,r;return r=function(r,i,s){if(Object.prototype.toString.call(i)!=="[object RegExp]")return t.call(r,i,s);var o=[],u=(i.ignoreCase?"i":"")+(i.multiline?"m":"")+(i.extended?"x":"")+(i.sticky?"y":""),a=0,i=new RegExp(i.source,u+"g"),f,l,c,h;r+="",n||(f=new RegExp("^"+i.source+"$(?!\\s)",u)),s=s===e?-1>>>0:s>>>0;while(l=i.exec(r)){c=l.index+l[0].length;if(c>a){o.push(r.slice(a,l.index)),!n&&l.length>1&&l[0].replace(f,function(){for(var t=1;t<arguments.length-2;t++)arguments[t]===e&&(l[t]=e)}),l.length>1&&l.index<r.length&&Array.prototype.push.apply(o,l.slice(1)),h=l[0].length,a=c;if(o.length>=s)break}i.lastIndex===l.index&&i.lastIndex++}return a===r.length?(h||!i.test(""))&&o.push(""):o.push(r.slice(a)),o.length>s?o.slice(0,s):o},String.prototype.split=function(e,t){return r(this,e,t)},r}(),window.ECT=ECT,CoffeeScript=window.CoffeeScript,path=function(){var e=function(e,t){var n=0,r,i;for(r=e.length-1;r>=0;r--)i=e[r],i==="."?e.splice(r,1):i===".."?(e.splice(r,1),n++):n&&(e.splice(r,1),n--);if(t)while(n)e.unshift(".."),n--;return e},t=function(t){var n=t.charAt(0)==="/",r=t.slice(-1)==="/";return t=e(t.split("/").filter(function(e){return!!e}),!n).join("/"),!t&&!n&&(t="."),t&&r&&(t+="/"),(n?"/":"")+t};return{normalize:t}}(),fs=function(){var e=function(e,t){var n;window.XMLHttpRequest?(n=new XMLHttpRequest,n.overrideMimeType&&n.overrideMimeType("text/html")):n=new ActiveXObject("Microsoft.XMLHTTP");if(n){n.open("GET",e,!1),n.send(null);if(n.status!==0&&(n.status<200||n.status>399))throw new Error("Failed to load template "+e);return n.responseText}throw new Error("Failed to load template "+e)},t=function(){};return{readFileSync:e,watch:t}}()}})();
+(function(){"use strict";var fs,path,CoffeeScript,ECT=function(options){if(!(this instanceof ECT))return new ECT(options);var ect=this;this.options={open:"<%",close:"%>",ext:"",cache:!0,watch:!1,root:""};var trimExp=/^[ \t]+|[ \t]+$/g,newlineExp=/\n/g,cache={},watchers={},indentChars={":":":",">":">"},escapeExp=/[&<>"]/,escapeAmpExp=/&/g,escapeLtExp=/</g,escapeGtExp=/>/g,escapeQuotExp=/"/g,regExpEscape=function(e){return String(e).replace(/([.*+?\^=!:${}()|\[\]\/\\])/g,"\\$1")},parse=function(template){var lineNo=1,bufferStack=["__ectOutput"],bufferStackPointer=0,buffer=bufferStack[bufferStackPointer]+" = '",matches=template.split(new RegExp(regExpEscape(ect.options.open)+"((?:.|[\r\n])+?)(?:"+regExpEscape(ect.options.close)+"|$)")),output,text,command,line,prefix,postfix,newline,indentChar,indentation="",indent=!1,indentStack=[],indentStackPointer=-1,baseIndent,lines,j;for(var i=0;i<matches.length;i++){text=matches[i],command="";if(i%2===1){line="__ectFileInfo.line = "+lineNo;switch(text.charAt(0)){case"=":prefix="' + ("+line+"\n'') + __ectTemplateContext.escape(",postfix=") + '",newline="",text=text.substr(1),output="escaped";break;case"-":prefix="' + ("+line+"\n'') + ((",postfix=") ? '') + '",newline="",text=text.substr(1),output="unescaped";break;default:prefix="'\n"+line,postfix="\n"+bufferStack[bufferStackPointer]+" += '",newline="\n",output="none"}text=text.replace(trimExp,""),command=text.split(/[^a-z]+/)[0];if(indentChar=indentChars[text.charAt(text.length-1)])text=text.replace(/:$/,"").replace(trimExp,""),indentChar===">"&&(/[$a-z_][0-9a-z_$]*[^=]+(-|=)>/i.test(text.replace(/'.*'|".*"/,""))&&(indentStack.push("capture_output_"+output),indentStackPointer++),bufferStack.push("__ectFunction"+bufferStackPointer),bufferStackPointer++,postfix="\n"+bufferStack[bufferStackPointer]+" = '",command="function"),indentStack.push(command),indentStackPointer++,indent=!0;switch(command){case"include":output==="none"&&(prefix="' + ("+line+"\n'') + (",postfix=") + '"),buffer+=prefix.replace(newlineExp,"\n"+indentation)+text+postfix.replace(newlineExp,"\n"+indentation);break;case"block":bufferStack.push("__ectTemplateContext.blocks['"+text.replace(/block\s+('|")([^'"]+)('|").*/,"$2")+"']"),bufferStackPointer++,prefix="'\n",postfix="\n"+bufferStack[bufferStackPointer]+" += '",text="if "+text,buffer+=prefix.replace(newlineExp,"\n"+indentation)+text,indent&&(indentation+=" ",indent=!1),buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"content":output==="none"&&(prefix="' + ("+line+"\n'') + (",postfix=") + '"),text==="content"&&(text="content()"),buffer+=prefix.replace(newlineExp,"\n"+indentation)+text+postfix.replace(newlineExp,"\n"+indentation);break;case"end":prefix="'";switch(indentStack[indentStackPointer]){case"block":bufferStack.pop(),bufferStackPointer--,prefix="'",postfix="\n"+bufferStack[bufferStackPointer]+" += '",buffer+=prefix.replace(newlineExp,"\n"+indentation),indentation=indentation.substr(2),buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"when":postfix="\n"+bufferStack[bufferStackPointer]+" += ''",buffer+=prefix.replace(newlineExp,"\n"+indentation)+postfix.replace(newlineExp,"\n"+indentation),indentation=indentation.substr(2);break;case"function":prefix="'\n"+bufferStack[bufferStackPointer],buffer+=prefix.replace(newlineExp,"\n"+indentation),indentation=indentation.substr(2),bufferStack.pop(),bufferStackPointer--,postfix="\n"+bufferStack[bufferStackPointer]+" += '";switch(indentStack[indentStackPointer-1]){case"capture_output_escaped":indentStack.pop(),indentStackPointer--,buffer+=")";break;case"capture_output_unescaped":indentStack.pop(),indentStackPointer--,buffer+=") ? '')";break;case"capture_output_none":indentStack.pop(),indentStackPointer--}buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"switch":prefix="\n"+line;default:indentStack[indentStackPointer-1]==="switch"&&(postfix=""),indentation=indentation.substr(2),buffer+=prefix.replace(newlineExp,"\n"+indentation)+postfix.replace(newlineExp,"\n"+indentation)}indentStack.pop(),indentStackPointer--;break;case"else":indentStack[indentStackPointer-1]==="switch"?prefix="":prefix="'",buffer+=prefix.replace(newlineExp,"\n"+indentation);if(indentStack[indentStackPointer-1]==="if"||indentStack[indentStackPointer-1]==="else")indentStack.splice(-2,1),indentStackPointer--,indentation=indentation.substr(2);buffer+=(newline.length?newline+indentation:"")+text,indent&&(indentation+=" ",indent=!1),buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"switch":buffer+=prefix.replace(newlineExp,"\n"+indentation)+(newline.length?newline+indentation:"")+text,indent&&(indentation+=" ",indent=!1);break;case"when":buffer+=(newline.length?newline+indentation:"")+text,indent&&(indentation+=" ",indent=!1),buffer+=postfix.replace(newlineExp,"\n"+indentation);break;case"extend":text="__ectExtended = true\n__ectParent = "+text.replace(/extend\s+/,"");default:if(/\n/.test(text)){lines=text.split(/\n/),buffer+=prefix.replace(newlineExp,"\n"+indentation);for(j=0;j<lines.length;j++){if(/^\s*$/.test(lines[j]))continue;typeof baseIndent=="undefined"&&(baseIndent=new RegExp("^"+lines[j].substr(0,lines[j].search(/[^\s]/)))),buffer+=(newline.length?newline+indentation:"")+lines[j].replace(baseIndent,"")}lines=undefined,baseIndent=undefined}else buffer+=prefix.replace(newlineExp,"\n"+indentation)+(newline.length?newline+indentation:"")+text;indent&&(indentation+=" ",indent=!1),buffer+=postfix.replace(newlineExp,"\n"+indentation)}}else indentStack[indentStackPointer]!=="switch"&&(buffer+=text.replace(/[\\']/g,"\\$&").replace(/\r/g,"").replace(newlineExp,"\\n").replace(/^\\n/,""));lineNo+=text.split(newlineExp).length-1}return buffer+="'\nif not __ectExtended\n return __ectOutput\nelse\n __ectContainer = __ectTemplateContext.load __ectParent\n __ectFileInfo.file = __ectContainer.file\n __ectFileInfo.line = 1\n __ectTemplateContext.childContent = __ectOutput\n return __ectContainer.compiled.call(this, __ectTemplateContext, __ectFileInfo, include, content, block)",buffer="__ectExtended = false\n"+buffer,eval("(function __ectTemplate(__ectTemplateContext, __ectFileInfo, include, content, block) {\n"+CoffeeScript.compile(buffer,{bare:!0})+"});")},read=function(file){if(Object.prototype.toString.call(ect.options.root)==="[object Object]"){var data=eval("(ect.options.root."+file+")");if(Object.prototype.toString.call(data)==="[object String]")return data;throw new Error("Failed to load template "+file)}try{return fs.readFileSync(file,"utf8")}catch(e){throw new Error("Failed to load template "+file)}},TemplateContext=function(e){this.blocks={},this.data=e||{},this.childContent=""};TemplateContext.prototype.escape=function(e){if(e==null)return"";var t=e.toString();return escapeExp.test(t)?t.replace(escapeAmpExp,"&#38;").replace(escapeLtExp,"&#60;").replace(escapeGtExp,"&#62;").replace(escapeQuotExp,"&#34;"):t},TemplateContext.prototype.block=function(e){return this.blocks[e]||(this.blocks[e]=""),!this.blocks[e].length},TemplateContext.prototype.content=function(e){return e&&e.length?this.blocks[e]?this.blocks[e]:"":this.childContent},TemplateContext.prototype.load=function(template){var file,compiled,container,data;if(ect.options.cache&&cache[template])return cache[template];var extExp=new RegExp(ect.options.ext+"$");Object.prototype.toString.call(ect.options.root)==="[object String]"?typeof process!="undefined"&&process.platform==="win32"?file=path.normalize((ect.options.root.length&&template.charAt(0)!=="/"&&template.charAt(0)!=="\\"&&!/^[a-zA-Z]:/.test(template)?ect.options.root+"/":"")+template.replace(extExp,"")+ect.options.ext):file=path.normalize((ect.options.root.length&&template.charAt(0)!=="/"?ect.options.root+"/":"")+template.replace(extExp,"")+ect.options.ext):file=template,data=read(file);if(data.substr(0,24)==="(function __ectTemplate(")try{compiled=eval(data)}catch(e){throw e.message=e.message+" in "+file,e}else try{compiled=parse(data)}catch(e){throw e.message=e.message.replace(/ on line \d+/,"")+" in "+file,e}return container={file:file,compiled:compiled,source:compiled.toString(),lastModified:(new Date).toUTCString(),gzip:null},ect.options.cache&&(cache[template]=container),ect.options.watch&&(watchers[file]=fs.watch(file,function(){watchers[file].close(),delete watchers[file],delete cache[template]})),container},TemplateContext.prototype.render=function(e,t){var n=this,r=this.load(e),i={file:r.file,line:1};try{return r.compiled.call(t||this.data,this,i,function(){return n.render.apply(n,arguments)},function(){return n.content.apply(n,arguments)},function(){return n.block.apply(n,arguments)})}catch(s){throw/ in /.test(s.message)||(s.message=s.message+" in "+i.file+" on line "+i.line),s}},this.configure=function(e){e=e||{};for(var t in e)this.options[t]=e[t]},this.render=function(e,t,n){var r=new TemplateContext(t);return r.render(e)},this.render=function(e,t,n){var r;if(typeof arguments[arguments.length-1]!="function")return r=new TemplateContext(t),r.render(e);arguments.length===2&&(n=t,t={}),r=new TemplateContext(t);try{n(undefined,r.render(e))}catch(i){n(i)}},typeof module!="undefined"&&module.exports&&(this.compiler=function(e){var t=require("zlib");e=e||{},e.root=e.root||"/",e.root="/"+e.root.replace(/^\//,""),e.root=e.root.replace(/\/$/,"")+"/";var n=new RegExp("^"+e.root);return function(r,i,s){if(r.method!=="GET"&&r.method!=="HEAD")return s();if(!e.root||r.url.substr(0,e.root.length)===e.root){var o=r.url.replace(n,"");try{var u=new TemplateContext,a=u.load(o);i.setHeader("Content-Type","application/x-javascript; charset=utf-8"),i.setHeader("Last-Modified",a.lastModified),e.gzip?(i.setHeader("Content-Encoding","gzip"),a.gzip===null?t.gzip(a.source,function(e,t){e?s(e):(a.gzip=t,i.end(a.gzip))}):i.end(a.gzip)):(i.setHeader("Content-Length",a.source.length),i.end(a.source))}catch(f){s(f)}}else s()}}),this.configure(options)};if(typeof module!="undefined"&&module.exports)fs=require("fs"),path=require("path"),CoffeeScript=require("coffee-script"),module.exports=ECT;else{Array.prototype.filter||(Array.prototype.filter=function(e,t){var n=this.length,r=[],i,s;if(typeof e!="function")throw new TypeError;for(i=0;i<n;i++)i in this&&(s=this[i],e.call(t,s,i,this)&&r.push(s));return r});var split;split=split||function(e){var t=String.prototype.split,n=/()??/.exec("")[1]===e,r;return r=function(r,i,s){if(Object.prototype.toString.call(i)!=="[object RegExp]")return t.call(r,i,s);var o=[],u=(i.ignoreCase?"i":"")+(i.multiline?"m":"")+(i.extended?"x":"")+(i.sticky?"y":""),a=0,i=new RegExp(i.source,u+"g"),f,l,c,h;r+="",n||(f=new RegExp("^"+i.source+"$(?!\\s)",u)),s=s===e?-1>>>0:s>>>0;while(l=i.exec(r)){c=l.index+l[0].length;if(c>a){o.push(r.slice(a,l.index)),!n&&l.length>1&&l[0].replace(f,function(){for(var t=1;t<arguments.length-2;t++)arguments[t]===e&&(l[t]=e)}),l.length>1&&l.index<r.length&&Array.prototype.push.apply(o,l.slice(1)),h=l[0].length,a=c;if(o.length>=s)break}i.lastIndex===l.index&&i.lastIndex++}return a===r.length?(h||!i.test(""))&&o.push(""):o.push(r.slice(a)),o.length>s?o.slice(0,s):o},String.prototype.split=function(e,t){return r(this,e,t)},r}(),window.ECT=ECT,CoffeeScript=window.CoffeeScript,path=function(){var e=function(e,t){var n=0,r,i;for(r=e.length-1;r>=0;r--)i=e[r],i==="."?e.splice(r,1):i===".."?(e.splice(r,1),n++):n&&(e.splice(r,1),n--);if(t)while(n)e.unshift(".."),n--;return e},t=function(t){var n=t.charAt(0)==="/",r=t.slice(-1)==="/";return t=e(t.split("/").filter(function(e){return!!e}),!n).join("/"),!t&&!n&&(t="."),t&&r&&(t+="/"),(n?"/":"")+t};return{normalize:t}}(),fs=function(){var e=function(e,t){var n;window.XMLHttpRequest?(n=new XMLHttpRequest,n.overrideMimeType&&n.overrideMimeType("text/html")):n=new ActiveXObject("Microsoft.XMLHTTP");if(n){n.open("GET",e,!1),n.send(null);if(n.status!==0&&(n.status<200||n.status>399))throw new Error("Failed to load template "+e);return n.responseText}throw new Error("Failed to load template "+e)},t=function(){};return{readFileSync:e,watch:t}}()}})();
View
10 examples/compiler.js
@@ -0,0 +1,10 @@
+var http = require('http');
+var connect = require('connect');
+var app = connect();
+var server = http.createServer(app);
+
+var ECT = require('./../index');
+var renderer = ECT({ root : __dirname + '/view', ext : '.html', watch: true });
+app.use('/views', renderer.compiler({ gzip: true }));
+
+server.listen(3000);
View
1,277 lib/ect.js
@@ -1,637 +1,642 @@
-/*!
- * ECT CoffeeScript template engine v0.4.6
- * https://github.com/baryshev/ect
- *
- * Copyright 2012, Vadim M. Baryshev <vadimbaryshev@gmail.com>
- * Licensed under the MIT license
- * https://github.com/baryshev/ect/LICENSE
- *
- * Includes parts of node
- * https://github.com/joyent/node
- * Copyright Joyent, Inc. and other Node contributors
- * Released under the MIT license
- *
- * Includes Cross-Browser Split 1.1.1
- * http://xregexp.com/
- * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
- * Released under the MIT license
- */
-(function () {
- 'use strict';
- var fs;
- var path;
- var CoffeeScript;
-
- var ECT = function (options) {
- if (!(this instanceof ECT)) {
- return new ECT(options);
- }
- var ect = this;
-
- this.options = {
- open : '<%',
- close : '%>',
- ext : '',
- cache : true,
- watch : false,
- root : ''
- };
-
- var
- trimExp = /^[ \t]+|[ \t]+$/g,
- newlineExp = /\n/g,
- cache = {},
- watchers = {},
- indentChars = { ':' : ':', '>' : '>' },
- escapeExp = /[&<>"]/,
- escapeAmpExp = /&/g,
- escapeLtExp = /</g,
- escapeGtExp = />/g,
- escapeQuotExp = /"/g,
- regExpEscape = function (str) {
- return String(str).replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1');
- },
-
- parse = function (template) {
- var
- lineNo = 1,
- bufferStack = [ '__ectOutput' ], bufferStackPointer = 0,
- buffer = bufferStack[bufferStackPointer] + ' = \'',
- matches = template.split(new RegExp(regExpEscape(ect.options.open) + '((?:.|[\r\n])+?)(?:' + regExpEscape(ect.options.close) + '|$)')),
- output, text, command, line,
- prefix, postfix, newline,
- indentChar, indentation = '', indent = false, indentStack = [], indentStackPointer = -1, baseIndent, lines, j;
-
- for (var i = 0; i < matches.length; i++) {
- text = matches[i];
- command = '';
- if (i % 2 === 1) {
- line = '__ectFileInfo.line = ' + lineNo;
- switch (text.charAt(0)) {
- case '=':
- prefix = '\' + (' + line + '\n\'\') + __ectTemplateContext.escape(';
- postfix = ') + \'';
- newline = '';
- text = text.substr(1);
- output = 'escaped';
- break;
- case '-':
- prefix = '\' + (' + line + '\n\'\') + ((';
- postfix = ') ? \'\') + \'';
- newline = '';
- text = text.substr(1);
- output = 'unescaped';
- break;
- default:
- prefix = '\'\n' + line;
- postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
- newline = '\n';
- output = 'none';
- }
- text = text.replace(trimExp, '');
-
- command = text.split(/[^a-z]+/)[0];
- if ((indentChar = indentChars[text.charAt(text.length - 1)])) {
- text = text.replace(/:$/, '').replace(trimExp, '');
- if (indentChar === '>') {
- if (/[$a-z_][0-9a-z_$]*[^=]+(-|=)>/i.test(text.replace(/'.*'|".*"/, ''))) {
- indentStack.push('capture_output_' + output);
- indentStackPointer++;
- }
- bufferStack.push('__ectFunction' + bufferStackPointer);
- bufferStackPointer++;
- postfix = '\n' + bufferStack[bufferStackPointer] + ' = \'';
- command = 'function';
- }
- indentStack.push(command);
- indentStackPointer++;
- indent = true;
- }
- switch (command) {
- case 'include' :
- if (output === 'none') {
- prefix = '\' + (' + line + '\n\'\') + (';
- postfix = ') + \'';
- }
- buffer += prefix.replace(newlineExp, '\n' + indentation) + text + postfix.replace(newlineExp, '\n' + indentation);
- break;
- case 'block' :
- bufferStack.push('__ectTemplateContext.blocks[\'' + text.replace(/block\s+('|")([^'"]+)('|").*/, '$2') + '\']');
- bufferStackPointer++;
- prefix = '\'\n';
- postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
- text = 'if ' + text;
- buffer += prefix.replace(newlineExp, '\n' + indentation) + text;
- if (indent) {
- indentation += ' ';
- indent = false;
- }
- buffer += postfix.replace(newlineExp, '\n' + indentation);
- break;
- case 'content' :
- if (output === 'none') {
- prefix = '\' + (' + line + '\n\'\') + (';
- postfix = ') + \'';
- }
- if (text === 'content') {
- text = 'content()'
- }
- buffer += prefix.replace(newlineExp, '\n' + indentation) + text + postfix.replace(newlineExp, '\n' + indentation);
- break;
- case 'end' :
- prefix = '\'';
- switch (indentStack[indentStackPointer]) {
- case 'block' :
- bufferStack.pop();
- bufferStackPointer--;
- prefix = '\'';
- postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
- buffer += prefix.replace(newlineExp, '\n' + indentation);
- indentation = indentation.substr(2);
- buffer += postfix.replace(newlineExp, '\n' + indentation);
- break;
- case 'when' :
- postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'\'';
- buffer += prefix.replace(newlineExp, '\n' + indentation) + postfix.replace(newlineExp, '\n' + indentation);
- indentation = indentation.substr(2);
- break;
- case 'function' :
- prefix = '\'\n' + bufferStack[bufferStackPointer];
- buffer += prefix.replace(newlineExp, '\n' + indentation);
- indentation = indentation.substr(2);
- bufferStack.pop();
- bufferStackPointer--;
- postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
- switch (indentStack[indentStackPointer - 1]) {
- case 'capture_output_escaped' :
- indentStack.pop();
- indentStackPointer--;
- buffer += ')';
- break;
- case 'capture_output_unescaped' :
- indentStack.pop();
- indentStackPointer--;
- buffer += ') ? \'\')';
- break;
- case 'capture_output_none' :
- indentStack.pop();
- indentStackPointer--;
- break;
- }
- buffer += postfix.replace(newlineExp, '\n' + indentation);
- break;
- case 'switch' :
- prefix = '\n' + line;
- default :
- if (indentStack[indentStackPointer - 1] === 'switch') {
- postfix = '';
- }
- indentation = indentation.substr(2);
- buffer += prefix.replace(newlineExp, '\n' + indentation) + postfix.replace(newlineExp, '\n' + indentation);
- }
- indentStack.pop();
- indentStackPointer--;
- break;
- case 'else' :
- if (indentStack[indentStackPointer - 1] === 'switch') {
- prefix = '';
- } else {
- prefix = '\'';
- }
- buffer += prefix.replace(newlineExp, '\n' + indentation);
- if (indentStack[indentStackPointer - 1] === 'if' || indentStack[indentStackPointer - 1] === 'else') {
- indentStack.splice(-2, 1);
- indentStackPointer--;
- indentation = indentation.substr(2);
- }
- buffer += (newline.length ? newline + indentation : '') + text;
- if (indent) {
- indentation += ' ';
- indent = false;
- }
- buffer += postfix.replace(newlineExp, '\n' + indentation);
- break;
- case 'switch' :
- buffer += prefix.replace(newlineExp, '\n' + indentation) + (newline.length ? newline + indentation : '') + text;
- if (indent) {
- indentation += ' ';
- indent = false;
- }
- break;
- case 'when' :
- buffer += (newline.length ? newline + indentation : '') + text;
- if (indent) {
- indentation += ' ';
- indent = false;
- }
- buffer += postfix.replace(newlineExp, '\n' + indentation);
- break;
- case 'extend' :
- text = '__ectExtended = true\n__ectParent = ' + text.replace(/extend\s+/, '');
- default :
- if (/\n/.test(text)) {
- lines = text.split(/\n/);
- buffer += prefix.replace(newlineExp, '\n' + indentation);
- for (j = 0; j < lines.length; j++) {
- if (/^\s*$/.test(lines[j])) {
- continue;
- }
- if (typeof baseIndent === 'undefined') {
- baseIndent = new RegExp('^' + lines[j].substr(0, lines[j].search(/[^\s]/)));
- }
- buffer += (newline.length ? newline + indentation : '') + lines[j].replace(baseIndent, '');
- }
- lines = undefined;
- baseIndent = undefined;
- } else {
- buffer += prefix.replace(newlineExp, '\n' + indentation) + (newline.length ? newline + indentation : '') + text;
- }
- if (indent) {
- indentation += ' ';
- indent = false;
- }
- buffer += postfix.replace(newlineExp, '\n' + indentation);
- break;
- }
- } else {
- if (indentStack[indentStackPointer] !== 'switch') {
- buffer += text.replace(/[\\']/g, '\\$&').replace(/\r/g, '').replace(newlineExp, '\\n').replace(/^\\n/, '');
- }
- }
- lineNo += text.split(newlineExp).length - 1;
- }
- buffer += '\'\nif not __ectExtended\n return __ectOutput\nelse\n __ectContainer = __ectTemplateContext.load __ectParent\n __ectFileInfo.file = __ectContainer.file\n __ectFileInfo.line = 1\n __ectTemplateContext.childContent = __ectOutput\n return __ectContainer.compiled.call(this, __ectTemplateContext, __ectFileInfo, include, content, block)';
- buffer = '__ectExtended = false\n' + buffer;
-
- return eval('(function __ectTemplate(__ectTemplateContext, __ectFileInfo, include, content, block) {\n' + CoffeeScript.compile(buffer, { bare : true }) + '});');
- },
-
- read = function (file) {
- if (Object.prototype.toString.call(ect.options.root) === '[object Object]') {
- var data = eval('(ect.options.root.' + file + ')');
- if (Object.prototype.toString.call(data) === '[object String]') {
- return data;
- } else {
- throw new Error ('Failed to load template ' + file);
- }
- } else {
- try {
- return fs.readFileSync(file, 'utf8');
- } catch (e) {
- throw new Error ('Failed to load template ' + file);
- }
- }
- };
-
- var TemplateContext = function (data) {
- this.blocks = {};
- this.data = data || {};
- this.childContent = '';
- };
-
- TemplateContext.prototype.escape = function (text) {
- if (text == null) {
- return '';
- }
- var result = text.toString();
- if (!escapeExp.test(result)) {
- return result;
- }
- return result.replace(escapeAmpExp, '&#38;').replace(escapeLtExp, '&#60;').replace(escapeGtExp, '&#62;').replace(escapeQuotExp, '&#34;');
- };
-
- TemplateContext.prototype.block = function (name) {
- if (!this.blocks[name]) { this.blocks[name] = ''; }
- return !this.blocks[name].length;
- };
-
- TemplateContext.prototype.content = function (block) {
- if (block && block.length) {
- if (!this.blocks[block]) { return ''; }
- return this.blocks[block];
- } else {
- return this.childContent;
- }
- };
-
- TemplateContext.prototype.load = function (template) {
- var file, compiled, container, data;
-
- if (ect.options.cache && cache[template]) {
- return cache[template];
- } else {
- var extExp = new RegExp(ect.options.ext + '$');
- if (Object.prototype.toString.call(ect.options.root) === '[object String]') {
- if (typeof process !== 'undefined' && process.platform === 'win32') {
- file = path.normalize((ect.options.root.length && template.charAt(0) !== '/' && template.charAt(0) !== '\\' && !/^[a-zA-Z]:/.test(template) ? (ect.options.root + '/') : '') + template.replace(extExp, '') + ect.options.ext);
- } else {
- file = path.normalize((ect.options.root.length && template.charAt(0) !== '/' ? (ect.options.root + '/') : '') + template.replace(extExp, '') + ect.options.ext);
- }
- } else {
- file = template;
- }
-
- data = read(file);
- if (data.substr(0, 24) === '(function __ectTemplate(') {
- try {
- compiled = eval(data);
- } catch (e) {
- e.message = e.message + ' in ' + file;
- throw e;
- }
- } else {
- try {
- compiled = parse(data);
- } catch (e) {
- e.message = e.message.replace(/ on line \d+/, '') + ' in ' + file;
- throw e;
- }
- }
- container = { file : file, compiled : compiled, source : compiled.toString(), gzip : null };
- if (ect.options.cache) {
- cache[template] = container;
- }
- if (ect.options.watch) {
- watchers[file] = fs.watch(file, function () {
- watchers[file].close();
- delete (watchers[file]);
- delete (cache[template]);
- });
- }
- return container;
- }
- };
-
- TemplateContext.prototype.render = function (template, data) {
- var that = this;
-
- var container = this.load(template);
- var fileInfo = { file : container.file, line : 1 };
-
- try {
- return container.compiled.call(
- data || this.data,
- this,
- fileInfo,
- function() { return that.render.apply(that, arguments); },
- function() { return that.content.apply(that, arguments); },
- function() { return that.block.apply(that, arguments); }
- );
- } catch (e) {
- if (!/ in /.test(e.message)) {
- e.message = e.message + ' in ' + fileInfo.file + ' on line ' + fileInfo.line;
- }
- throw e;
- }
- };
-
- this.configure = function (options) {
- options = options || {};
- for (var option in options) {
- this.options[option] = options[option];
- }
- };
-
- this.render = function (template, data, callback) {
- var context = new TemplateContext(data);
- return context.render(template);
- };
-
- this.render = function (template, data, callback) {
- var context;
- if (typeof arguments[arguments.length - 1] === 'function') {
- if (arguments.length === 2) {
- callback = data;
- data = {};
- }
- context = new TemplateContext(data);
- try {
- callback(undefined, context.render(template));
- } catch (e) {
- callback(e);
- }
- } else {
- context = new TemplateContext(data);
- return context.render(template);
- }
- };
-
- if (typeof module !== 'undefined' && module.exports) {
- this.compiler = function (options) {
- var zlib = require('zlib');
- options = options || {};
- options.root = options.root || '/';
- options.root = '/' + options.root.replace(/^\//, '');
- options.root = options.root.replace(/\/$/, '') + '/';
- var rootExp = new RegExp('^' + options.root);
- return function (req, res, next) {
- if (req.url.substr(0, options.root.length) === options.root) {
- var template = req.url.replace(rootExp, '');
- try {
- var context = new TemplateContext();
- var container = context.load(template);
- res.setHeader('Content-Type', 'application/x-javascript; charset=utf-8');
- if (options.gzip) {
- res.setHeader('Content-Encoding', 'gzip');
- if (container.gzip === null) {
- zlib.gzip(container.source, function (err, buffer) {
- if (!err) {
- container.gzip = buffer;
- res.end(container.gzip);
- } else {
- next(err);
- }
- });
- } else {
- res.end(container.gzip);
- }
- } else {
- res.end(container.source);
- }
- } catch (e) {
- next(e);
- }
- } else {
- next();
- }
- }
- };
- }
-
- this.configure(options);
- };
-
- if (typeof module !== 'undefined' && module.exports) {
- fs = require('fs');
- path = require('path');
- CoffeeScript = require('coffee-script');
- module.exports = ECT;
- } else {
- if (!Array.prototype.filter) {
- Array.prototype.filter = function (fun, thisp) {
- var
- len = this.length,
- res = [],
- i,
- val;
- if (typeof fun !== 'function') { throw new TypeError(); }
- for (i = 0; i < len; i++) {
- if (i in this) {
- val = this[i];
- if (fun.call(thisp, val, i, this)) { res.push(val); }
- }
- }
- return res;
- };
- }
-
- var split;
-
- split = split || function (undef) {
-
- var nativeSplit = String.prototype.split,
- compliantExecNpcg = /()??/.exec('')[1] === undef,
- self;
-
- self = function (str, separator, limit) {
- if (Object.prototype.toString.call(separator) !== '[object RegExp]') {
- return nativeSplit.call(str, separator, limit);
- }
- var output = [],
- flags = (separator.ignoreCase ? 'i' : '') +
- (separator.multiline ? 'm' : '') +
- (separator.extended ? 'x' : '') +
- (separator.sticky ? 'y' : ''),
- lastLastIndex = 0,
- separator = new RegExp(separator.source, flags + 'g'),
- separator2, match, lastIndex, lastLength;
- str += '';
- if (!compliantExecNpcg) {
- separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
- }
- limit = limit === undef ? -1 >>> 0 :
- limit >>> 0;
- while (match = separator.exec(str)) {
- lastIndex = match.index + match[0].length;
- if (lastIndex > lastLastIndex) {
- output.push(str.slice(lastLastIndex, match.index));
- if (!compliantExecNpcg && match.length > 1) {
- match[0].replace(separator2, function () {
- for (var i = 1; i < arguments.length - 2; i++) {
- if (arguments[i] === undef) {
- match[i] = undef;
- }
- }
- });
- }
- if (match.length > 1 && match.index < str.length) {
- Array.prototype.push.apply(output, match.slice(1));
- }
- lastLength = match[0].length;
- lastLastIndex = lastIndex;
- if (output.length >= limit) {
- break;
- }
- }
- if (separator.lastIndex === match.index) {
- separator.lastIndex++;
- }
- }
- if (lastLastIndex === str.length) {
- if (lastLength || !separator.test('')) {
- output.push('');
- }
- }
- else {
- output.push(str.slice(lastLastIndex));
- }
- return output.length > limit ? output.slice(0, limit) : output;
- };
-
- String.prototype.split = function (separator, limit) {
- return self(this, separator, limit);
- };
-
- return self;
- }();
-
- window.ECT = ECT;
- CoffeeScript = window.CoffeeScript;
-
- path = (function () {
- var
- normalizeArray = function (parts, allowAboveRoot) {
- var up = 0, i, last;
- for (i = parts.length - 1; i >= 0; i--) {
- last = parts[i];
- if (last === '.') {
- parts.splice(i, 1);
- } else if (last === '..') {
- parts.splice(i, 1);
- up++;
- } else if (up) {
- parts.splice(i, 1);
- up--;
- }
- }
- if (allowAboveRoot) {
- while (up) {
- parts.unshift('..');
- up--;
- }
- }
- return parts;
- },
-
- normalize = function (path) {
- var
- isAbsolute = path.charAt(0) === '/',
- trailingSlash = path.slice(-1) === '/';
- path = normalizeArray(path.split('/').filter(function (p) {
- return !!p;
- }), !isAbsolute).join('/');
- if (!path && !isAbsolute) {
- path = '.';
- }
- if (path && trailingSlash) {
- path += '/';
- }
- return (isAbsolute ? '/' : '') + path;
- };
-
- return {
- normalize: normalize
- };
- }());
-
- fs = (function () {
- var
- readFileSync = function (file, encoding) {
- var AJAX;
- if (window.XMLHttpRequest) {
- AJAX = new XMLHttpRequest();
- if (AJAX.overrideMimeType) { AJAX.overrideMimeType('text/html'); }
- } else {
- AJAX = new ActiveXObject('Microsoft.XMLHTTP');
- }
- if (AJAX) {
- AJAX.open('GET', file, false);
- AJAX.send(null);
- if (AJAX.status !== 0 && (AJAX.status < 200 || AJAX.status > 399)) {
- throw new Error ('Failed to load template ' + file);
- }
- return AJAX.responseText;
- } else {
- throw new Error ('Failed to load template ' + file);
- }
- },
- watch = function () {};
-
- return {
- readFileSync: readFileSync,
- watch: watch
- };
- }());
-
- }
+/*!
+ * ECT CoffeeScript template engine v0.4.7
+ * https://github.com/baryshev/ect
+ *
+ * Copyright 2012, Vadim M. Baryshev <vadimbaryshev@gmail.com>
+ * Licensed under the MIT license
+ * https://github.com/baryshev/ect/LICENSE
+ *
+ * Includes parts of node
+ * https://github.com/joyent/node
+ * Copyright Joyent, Inc. and other Node contributors
+ * Released under the MIT license
+ *
+ * Includes Cross-Browser Split 1.1.1
+ * http://xregexp.com/
+ * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
+ * Released under the MIT license
+ */
+(function () {
+ 'use strict';
+ var fs;
+ var path;
+ var CoffeeScript;
+
+ var ECT = function (options) {
+ if (!(this instanceof ECT)) {
+ return new ECT(options);
+ }
+ var ect = this;
+
+ this.options = {
+ open : '<%',
+ close : '%>',
+ ext : '',
+ cache : true,
+ watch : false,
+ root : ''
+ };
+
+ var
+ trimExp = /^[ \t]+|[ \t]+$/g,
+ newlineExp = /\n/g,
+ cache = {},
+ watchers = {},
+ indentChars = { ':' : ':', '>' : '>' },
+ escapeExp = /[&<>"]/,
+ escapeAmpExp = /&/g,
+ escapeLtExp = /</g,
+ escapeGtExp = />/g,
+ escapeQuotExp = /"/g,
+ regExpEscape = function (str) {
+ return String(str).replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1');
+ },
+
+ parse = function (template) {
+ var
+ lineNo = 1,
+ bufferStack = [ '__ectOutput' ], bufferStackPointer = 0,
+ buffer = bufferStack[bufferStackPointer] + ' = \'',
+ matches = template.split(new RegExp(regExpEscape(ect.options.open) + '((?:.|[\r\n])+?)(?:' + regExpEscape(ect.options.close) + '|$)')),
+ output, text, command, line,
+ prefix, postfix, newline,
+ indentChar, indentation = '', indent = false, indentStack = [], indentStackPointer = -1, baseIndent, lines, j;
+
+ for (var i = 0; i < matches.length; i++) {
+ text = matches[i];
+ command = '';
+ if (i % 2 === 1) {
+ line = '__ectFileInfo.line = ' + lineNo;
+ switch (text.charAt(0)) {
+ case '=':
+ prefix = '\' + (' + line + '\n\'\') + __ectTemplateContext.escape(';
+ postfix = ') + \'';
+ newline = '';
+ text = text.substr(1);
+ output = 'escaped';
+ break;
+ case '-':
+ prefix = '\' + (' + line + '\n\'\') + ((';
+ postfix = ') ? \'\') + \'';
+ newline = '';
+ text = text.substr(1);
+ output = 'unescaped';
+ break;
+ default:
+ prefix = '\'\n' + line;
+ postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
+ newline = '\n';
+ output = 'none';
+ }
+ text = text.replace(trimExp, '');
+
+ command = text.split(/[^a-z]+/)[0];
+ if ((indentChar = indentChars[text.charAt(text.length - 1)])) {
+ text = text.replace(/:$/, '').replace(trimExp, '');
+ if (indentChar === '>') {
+ if (/[$a-z_][0-9a-z_$]*[^=]+(-|=)>/i.test(text.replace(/'.*'|".*"/, ''))) {
+ indentStack.push('capture_output_' + output);
+ indentStackPointer++;
+ }
+ bufferStack.push('__ectFunction' + bufferStackPointer);
+ bufferStackPointer++;
+ postfix = '\n' + bufferStack[bufferStackPointer] + ' = \'';
+ command = 'function';
+ }
+ indentStack.push(command);
+ indentStackPointer++;
+ indent = true;
+ }
+ switch (command) {
+ case 'include' :
+ if (output === 'none') {
+ prefix = '\' + (' + line + '\n\'\') + (';
+ postfix = ') + \'';
+ }
+ buffer += prefix.replace(newlineExp, '\n' + indentation) + text + postfix.replace(newlineExp, '\n' + indentation);
+ break;
+ case 'block' :
+ bufferStack.push('__ectTemplateContext.blocks[\'' + text.replace(/block\s+('|")([^'"]+)('|").*/, '$2') + '\']');
+ bufferStackPointer++;
+ prefix = '\'\n';
+ postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
+ text = 'if ' + text;
+ buffer += prefix.replace(newlineExp, '\n' + indentation) + text;
+ if (indent) {
+ indentation += ' ';
+ indent = false;
+ }
+ buffer += postfix.replace(newlineExp, '\n' + indentation);
+ break;
+ case 'content' :
+ if (output === 'none') {
+ prefix = '\' + (' + line + '\n\'\') + (';
+ postfix = ') + \'';
+ }
+ if (text === 'content') {
+ text = 'content()'
+ }
+ buffer += prefix.replace(newlineExp, '\n' + indentation) + text + postfix.replace(newlineExp, '\n' + indentation);
+ break;
+ case 'end' :
+ prefix = '\'';
+ switch (indentStack[indentStackPointer]) {
+ case 'block' :
+ bufferStack.pop();
+ bufferStackPointer--;
+ prefix = '\'';
+ postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
+ buffer += prefix.replace(newlineExp, '\n' + indentation);
+ indentation = indentation.substr(2);
+ buffer += postfix.replace(newlineExp, '\n' + indentation);
+ break;
+ case 'when' :
+ postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'\'';
+ buffer += prefix.replace(newlineExp, '\n' + indentation) + postfix.replace(newlineExp, '\n' + indentation);
+ indentation = indentation.substr(2);
+ break;
+ case 'function' :
+ prefix = '\'\n' + bufferStack[bufferStackPointer];
+ buffer += prefix.replace(newlineExp, '\n' + indentation);
+ indentation = indentation.substr(2);
+ bufferStack.pop();
+ bufferStackPointer--;
+ postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
+ switch (indentStack[indentStackPointer - 1]) {
+ case 'capture_output_escaped' :
+ indentStack.pop();
+ indentStackPointer--;
+ buffer += ')';
+ break;
+ case 'capture_output_unescaped' :
+ indentStack.pop();
+ indentStackPointer--;
+ buffer += ') ? \'\')';
+ break;
+ case 'capture_output_none' :
+ indentStack.pop();
+ indentStackPointer--;
+ break;
+ }
+ buffer += postfix.replace(newlineExp, '\n' + indentation);
+ break;
+ case 'switch' :
+ prefix = '\n' + line;
+ default :
+ if (indentStack[indentStackPointer - 1] === 'switch') {
+ postfix = '';
+ }
+ indentation = indentation.substr(2);
+ buffer += prefix.replace(newlineExp, '\n' + indentation) + postfix.replace(newlineExp, '\n' + indentation);
+ }
+ indentStack.pop();
+ indentStackPointer--;
+ break;
+ case 'else' :
+ if (indentStack[indentStackPointer - 1] === 'switch') {
+ prefix = '';
+ } else {
+ prefix = '\'';
+ }
+ buffer += prefix.replace(newlineExp, '\n' + indentation);
+ if (indentStack[indentStackPointer - 1] === 'if' || indentStack[indentStackPointer - 1] === 'else') {
+ indentStack.splice(-2, 1);
+ indentStackPointer--;
+ indentation = indentation.substr(2);
+ }
+ buffer += (newline.length ? newline + indentation : '') + text;
+ if (indent) {
+ indentation += ' ';
+ indent = false;
+ }
+ buffer += postfix.replace(newlineExp, '\n' + indentation);
+ break;
+ case 'switch' :
+ buffer += prefix.replace(newlineExp, '\n' + indentation) + (newline.length ? newline + indentation : '') + text;
+ if (indent) {
+ indentation += ' ';
+ indent = false;
+ }
+ break;
+ case 'when' :
+ buffer += (newline.length ? newline + indentation : '') + text;
+ if (indent) {
+ indentation += ' ';
+ indent = false;
+ }
+ buffer += postfix.replace(newlineExp, '\n' + indentation);
+ break;
+ case 'extend' :
+ text = '__ectExtended = true\n__ectParent = ' + text.replace(/extend\s+/, '');
+ default :
+ if (/\n/.test(text)) {
+ lines = text.split(/\n/);
+ buffer += prefix.replace(newlineExp, '\n' + indentation);
+ for (j = 0; j < lines.length; j++) {
+ if (/^\s*$/.test(lines[j])) {
+ continue;
+ }
+ if (typeof baseIndent === 'undefined') {
+ baseIndent = new RegExp('^' + lines[j].substr(0, lines[j].search(/[^\s]/)));
+ }
+ buffer += (newline.length ? newline + indentation : '') + lines[j].replace(baseIndent, '');
+ }
+ lines = undefined;
+ baseIndent = undefined;
+ } else {
+ buffer += prefix.replace(newlineExp, '\n' + indentation) + (newline.length ? newline + indentation : '') + text;
+ }
+ if (indent) {
+ indentation += ' ';
+ indent = false;
+ }
+ buffer += postfix.replace(newlineExp, '\n' + indentation);
+ break;
+ }
+ } else {
+ if (indentStack[indentStackPointer] !== 'switch') {
+ buffer += text.replace(/[\\']/g, '\\$&').replace(/\r/g, '').replace(newlineExp, '\\n').replace(/^\\n/, '');
+ }
+ }
+ lineNo += text.split(newlineExp).length - 1;
+ }
+ buffer += '\'\nif not __ectExtended\n return __ectOutput\nelse\n __ectContainer = __ectTemplateContext.load __ectParent\n __ectFileInfo.file = __ectContainer.file\n __ectFileInfo.line = 1\n __ectTemplateContext.childContent = __ectOutput\n return __ectContainer.compiled.call(this, __ectTemplateContext, __ectFileInfo, include, content, block)';
+ buffer = '__ectExtended = false\n' + buffer;
+
+ return eval('(function __ectTemplate(__ectTemplateContext, __ectFileInfo, include, content, block) {\n' + CoffeeScript.compile(buffer, { bare : true }) + '});');
+ },
+
+ read = function (file) {
+ if (Object.prototype.toString.call(ect.options.root) === '[object Object]') {
+ var data = eval('(ect.options.root.' + file + ')');
+ if (Object.prototype.toString.call(data) === '[object String]') {
+ return data;
+ } else {
+ throw new Error ('Failed to load template ' + file);
+ }
+ } else {
+ try {
+ return fs.readFileSync(file, 'utf8');
+ } catch (e) {
+ throw new Error ('Failed to load template ' + file);
+ }
+ }
+ };
+
+ var TemplateContext = function (data) {
+ this.blocks = {};
+ this.data = data || {};
+ this.childContent = '';
+ };
+
+ TemplateContext.prototype.escape = function (text) {
+ if (text == null) {
+ return '';
+ }
+ var result = text.toString();
+ if (!escapeExp.test(result)) {
+ return result;
+ }
+ return result.replace(escapeAmpExp, '&#38;').replace(escapeLtExp, '&#60;').replace(escapeGtExp, '&#62;').replace(escapeQuotExp, '&#34;');
+ };
+
+ TemplateContext.prototype.block = function (name) {
+ if (!this.blocks[name]) { this.blocks[name] = ''; }
+ return !this.blocks[name].length;
+ };
+
+ TemplateContext.prototype.content = function (block) {
+ if (block && block.length) {
+ if (!this.blocks[block]) { return ''; }
+ return this.blocks[block];
+ } else {
+ return this.childContent;
+ }
+ };
+
+ TemplateContext.prototype.load = function (template) {
+ var file, compiled, container, data;
+
+ if (ect.options.cache && cache[template]) {
+ return cache[template];
+ } else {
+ var extExp = new RegExp(ect.options.ext + '$');
+ if (Object.prototype.toString.call(ect.options.root) === '[object String]') {
+ if (typeof process !== 'undefined' && process.platform === 'win32') {
+ file = path.normalize((ect.options.root.length && template.charAt(0) !== '/' && template.charAt(0) !== '\\' && !/^[a-zA-Z]:/.test(template) ? (ect.options.root + '/') : '') + template.replace(extExp, '') + ect.options.ext);
+ } else {
+ file = path.normalize((ect.options.root.length && template.charAt(0) !== '/' ? (ect.options.root + '/') : '') + template.replace(extExp, '') + ect.options.ext);
+ }
+ } else {
+ file = template;
+ }
+
+ data = read(file);
+ if (data.substr(0, 24) === '(function __ectTemplate(') {
+ try {
+ compiled = eval(data);
+ } catch (e) {
+ e.message = e.message + ' in ' + file;
+ throw e;
+ }
+ } else {
+ try {
+ compiled = parse(data);
+ } catch (e) {
+ e.message = e.message.replace(/ on line \d+/, '') + ' in ' + file;
+ throw e;
+ }
+ }
+ container = { file : file, compiled : compiled, source : compiled.toString(), lastModified: new Date().toUTCString(), gzip : null };
+ if (ect.options.cache) {
+ cache[template] = container;
+ }
+ if (ect.options.watch) {
+ watchers[file] = fs.watch(file, function () {
+ watchers[file].close();
+ delete (watchers[file]);
+ delete (cache[template]);
+ });
+ }
+ return container;
+ }
+ };
+
+ TemplateContext.prototype.render = function (template, data) {
+ var that = this;
+
+ var container = this.load(template);
+ var fileInfo = { file : container.file, line : 1 };
+
+ try {
+ return container.compiled.call(
+ data || this.data,
+ this,
+ fileInfo,
+ function() { return that.render.apply(that, arguments); },
+ function() { return that.content.apply(that, arguments); },
+ function() { return that.block.apply(that, arguments); }
+ );
+ } catch (e) {
+ if (!/ in /.test(e.message)) {
+ e.message = e.message + ' in ' + fileInfo.file + ' on line ' + fileInfo.line;
+ }
+ throw e;
+ }
+ };
+
+ this.configure = function (options) {
+ options = options || {};
+ for (var option in options) {
+ this.options[option] = options[option];
+ }
+ };
+
+ this.render = function (template, data, callback) {
+ var context = new TemplateContext(data);
+ return context.render(template);
+ };
+
+ this.render = function (template, data, callback) {
+ var context;
+ if (typeof arguments[arguments.length - 1] === 'function') {
+ if (arguments.length === 2) {
+ callback = data;
+ data = {};
+ }
+ context = new TemplateContext(data);
+ try {
+ callback(undefined, context.render(template));
+ } catch (e) {
+ callback(e);
+ }
+ } else {
+ context = new TemplateContext(data);
+ return context.render(template);
+ }
+ };
+
+ if (typeof module !== 'undefined' && module.exports) {
+ this.compiler = function (options) {
+ var zlib = require('zlib');
+ options = options || {};
+ options.root = options.root || '/';
+ options.root = '/' + options.root.replace(/^\//, '');
+ options.root = options.root.replace(/\/$/, '') + '/';
+ var rootExp = new RegExp('^' + options.root);
+ return function (req, res, next) {
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
+ return next();
+ }
+ if (!options.root || req.url.substr(0, options.root.length) === options.root) {
+ var template = req.url.replace(rootExp, '');
+ try {
+ var context = new TemplateContext();
+ var container = context.load(template);
+ res.setHeader('Content-Type', 'application/x-javascript; charset=utf-8');
+ res.setHeader('Last-Modified', container.lastModified);
+ if (options.gzip) {
+ res.setHeader('Content-Encoding', 'gzip');
+ if (container.gzip === null) {
+ zlib.gzip(container.source, function (err, buffer) {
+ if (!err) {
+ container.gzip = buffer;
+ res.end(container.gzip);
+ } else {
+ next(err);
+ }
+ });
+ } else {
+ res.end(container.gzip);
+ }
+ } else {
+ res.setHeader('Content-Length', container.source.length);
+ res.end(container.source);
+ }
+ } catch (e) {
+ next(e);
+ }
+ } else {
+ next();
+ }
+ }
+ };
+ }
+
+ this.configure(options);
+ };
+
+ if (typeof module !== 'undefined' && module.exports) {
+ fs = require('fs');
+ path = require('path');
+ CoffeeScript = require('coffee-script');
+ module.exports = ECT;
+ } else {
+ if (!Array.prototype.filter) {
+ Array.prototype.filter = function (fun, thisp) {
+ var
+ len = this.length,
+ res = [],
+ i,
+ val;
+ if (typeof fun !== 'function') { throw new TypeError(); }
+ for (i = 0; i < len; i++) {
+ if (i in this) {
+ val = this[i];
+ if (fun.call(thisp, val, i, this)) { res.push(val); }
+ }
+ }
+ return res;
+ };
+ }
+
+ var split;
+
+ split = split || function (undef) {
+
+ var nativeSplit = String.prototype.split,
+ compliantExecNpcg = /()??/.exec('')[1] === undef,
+ self;
+
+ self = function (str, separator, limit) {
+ if (Object.prototype.toString.call(separator) !== '[object RegExp]') {
+ return nativeSplit.call(str, separator, limit);
+ }
+ var output = [],
+ flags = (separator.ignoreCase ? 'i' : '') +
+ (separator.multiline ? 'm' : '') +
+ (separator.extended ? 'x' : '') +
+ (separator.sticky ? 'y' : ''),
+ lastLastIndex = 0,
+ separator = new RegExp(separator.source, flags + 'g'),
+ separator2, match, lastIndex, lastLength;
+ str += '';
+ if (!compliantExecNpcg) {
+ separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
+ }
+ limit = limit === undef ? -1 >>> 0 :
+ limit >>> 0;
+ while (match = separator.exec(str)) {
+ lastIndex = match.index + match[0].length;
+ if (lastIndex > lastLastIndex) {
+ output.push(str.slice(lastLastIndex, match.index));
+ if (!compliantExecNpcg && match.length > 1) {
+ match[0].replace(separator2, function () {
+ for (var i = 1; i < arguments.length - 2; i++) {
+ if (arguments[i] === undef) {
+ match[i] = undef;
+ }
+ }
+ });
+ }
+ if (match.length > 1 && match.index < str.length) {
+ Array.prototype.push.apply(output, match.slice(1));
+ }
+ lastLength = match[0].length;
+ lastLastIndex = lastIndex;
+ if (output.length >= limit) {
+ break;
+ }
+ }
+ if (separator.lastIndex === match.index) {
+ separator.lastIndex++;
+ }
+ }
+ if (lastLastIndex === str.length) {
+ if (lastLength || !separator.test('')) {
+ output.push('');
+ }
+ }
+ else {
+ output.push(str.slice(lastLastIndex));
+ }
+ return output.length > limit ? output.slice(0, limit) : output;
+ };
+
+ String.prototype.split = function (separator, limit) {
+ return self(this, separator, limit);
+ };
+
+ return self;
+ }();
+
+ window.ECT = ECT;
+ CoffeeScript = window.CoffeeScript;
+
+ path = (function () {
+ var
+ normalizeArray = function (parts, allowAboveRoot) {
+ var up = 0, i, last;
+ for (i = parts.length - 1; i >= 0; i--) {
+ last = parts[i];
+ if (last === '.') {
+ parts.splice(i, 1);
+ } else if (last === '..') {
+ parts.splice(i, 1);
+ up++;
+ } else if (up) {
+ parts.splice(i, 1);
+ up--;
+ }
+ }
+ if (allowAboveRoot) {
+ while (up) {
+ parts.unshift('..');
+ up--;
+ }
+ }
+ return parts;
+ },
+
+ normalize = function (path) {
+ var
+ isAbsolute = path.charAt(0) === '/',
+ trailingSlash = path.slice(-1) === '/';
+ path = normalizeArray(path.split('/').filter(function (p) {
+ return !!p;
+ }), !isAbsolute).join('/');
+ if (!path && !isAbsolute) {
+ path = '.';
+ }
+ if (path && trailingSlash) {
+ path += '/';
+ }
+ return (isAbsolute ? '/' : '') + path;
+ };
+
+ return {
+ normalize: normalize
+ };
+ }());
+
+ fs = (function () {
+ var
+ readFileSync = function (file, encoding) {
+ var AJAX;
+ if (window.XMLHttpRequest) {
+ AJAX = new XMLHttpRequest();
+ if (AJAX.overrideMimeType) { AJAX.overrideMimeType('text/html'); }
+ } else {
+ AJAX = new ActiveXObject('Microsoft.XMLHTTP');
+ }
+ if (AJAX) {
+ AJAX.open('GET', file, false);
+ AJAX.send(null);
+ if (AJAX.status !== 0 && (AJAX.status < 200 || AJAX.status > 399)) {
+ throw new Error ('Failed to load template ' + file);
+ }
+ return AJAX.responseText;
+ } else {
+ throw new Error ('Failed to load template ' + file);
+ }
+ },
+ watch = function () {};
+
+ return {
+ readFileSync: readFileSync,
+ watch: watch
+ };
+ }());
+
+ }
}());
View
2 package.json
@@ -1,6 +1,6 @@
{
"name" : "ect",
- "version" : "0.4.6",
+ "version" : "0.4.7",
"description" : "CoffeeScript template engine",
"keywords": [ "template", "coffeescript" ],
"author" : "Vadim M. Baryshev <vadimbaryshev@gmail.com>",

0 comments on commit f9fe0be

Please sign in to comment.
Something went wrong with that request. Please try again.