Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nunjucks

Package Overview
Dependencies
Maintainers
2
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nunjucks - npm Package Compare versions

Comparing version 1.3.4 to 2.0.0

.jshintignore

1

bower.json
{
"name": "nunjucks",
"version": "1.3.1",
"main": "browser/nunjucks.min.js",

@@ -5,0 +4,0 @@ "ignore": [

@@ -1,3 +0,2 @@

// Browser bundle of nunjucks 1.3.3 (slim, only works with precompiled templates)
(function(){var modules={};(function(){"use strict";function extend(cls,name,props){var F=function(){};F.prototype=cls.prototype;var prototype=new F;var fnTest=/xyz/.test(function(){xyz})?/\bparent\b/:/.*/;props=props||{};for(var k in props){var src=props[k];var parent=prototype[k];if(typeof parent==="function"&&typeof src==="function"&&fnTest.test(src)){prototype[k]=function(src,parent){return function(){var tmp=this.parent;this.parent=parent;var res=src.apply(this,arguments);this.parent=tmp;return res}}(src,parent)}else{prototype[k]=src}}prototype.typename=name;var new_cls=function(){if(prototype.init){prototype.init.apply(this,arguments)}};new_cls.prototype=prototype;new_cls.prototype.constructor=new_cls;new_cls.extend=function(name,props){if(typeof name==="object"){props=name;name="anonymous"}return extend(new_cls,name,props)};return new_cls}modules["object"]=extend(Object,"Object",{})})();(function(){"use strict";var ArrayProto=Array.prototype;var ObjProto=Object.prototype;var escapeMap={"&":"&amp;",'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;"};var escapeRegex=/[&"'<>]/g;var lookupEscape=function(ch){return escapeMap[ch]};var exports=modules["lib"]={};exports.withPrettyErrors=function(path,withInternals,func){try{return func()}catch(e){if(!e.Update){e=new exports.TemplateError(e)}e.Update(path);if(!withInternals){var old=e;e=new Error(old.message);e.name=old.name}throw e}};exports.TemplateError=function(message,lineno,colno){var err=this;if(message instanceof Error){err=message;message=message.name+": "+message.message}else{if(Error.captureStackTrace){Error.captureStackTrace(err)}}err.name="Template render error";err.message=message;err.lineno=lineno;err.colno=colno;err.firstUpdate=true;err.Update=function(path){var message="("+(path||"unknown path")+")";if(this.firstUpdate){if(this.lineno&&this.colno){message+=" [Line "+this.lineno+", Column "+this.colno+"]"}else if(this.lineno){message+=" [Line "+this.lineno+"]"}}message+="\n ";if(this.firstUpdate){message+=" "}this.message=message+(this.message||"");this.firstUpdate=false;return this};return err};exports.TemplateError.prototype=Error.prototype;exports.escape=function(val){return val.replace(escapeRegex,lookupEscape)};exports.isFunction=function(obj){return ObjProto.toString.call(obj)==="[object Function]"};exports.isArray=Array.isArray||function(obj){return ObjProto.toString.call(obj)==="[object Array]"};exports.isString=function(obj){return ObjProto.toString.call(obj)==="[object String]"};exports.isObject=function(obj){return ObjProto.toString.call(obj)==="[object Object]"};exports.groupBy=function(obj,val){var result={};var iterator=exports.isFunction(val)?val:function(obj){return obj[val]};for(var i=0;i<obj.length;i++){var value=obj[i];var key=iterator(value,i);(result[key]||(result[key]=[])).push(value)}return result};exports.toArray=function(obj){return Array.prototype.slice.call(obj)};exports.without=function(array){var result=[];if(!array){return result}var index=-1,length=array.length,contains=exports.toArray(arguments).slice(1);while(++index<length){if(exports.indexOf(contains,array[index])===-1){result.push(array[index])}}return result};exports.extend=function(obj,obj2){for(var k in obj2){obj[k]=obj2[k]}return obj};exports.repeat=function(char_,n){var str="";for(var i=0;i<n;i++){str+=char_}return str};exports.each=function(obj,func,context){if(obj==null){return}if(ArrayProto.each&&obj.each===ArrayProto.each){obj.forEach(func,context)}else if(obj.length===+obj.length){for(var i=0,l=obj.length;i<l;i++){func.call(context,obj[i],i,obj)}}};exports.map=function(obj,func){var results=[];if(obj==null){return results}if(ArrayProto.map&&obj.map===ArrayProto.map){return obj.map(func)}for(var i=0;i<obj.length;i++){results[results.length]=func(obj[i],i)}if(obj.length===+obj.length){results.length=obj.length}return results};exports.asyncIter=function(arr,iter,cb){var i=-1;function next(){i++;if(i<arr.length){iter(arr[i],i,next,cb)}else{cb()}}next()};exports.asyncFor=function(obj,iter,cb){var keys=exports.keys(obj);var len=keys.length;var i=-1;function next(){i++;var k=keys[i];if(i<len){iter(k,obj[k],i,len,next)}else{cb()}}next()};exports.indexOf=Array.prototype.indexOf?function(arr,searchElement,fromIndex){return Array.prototype.indexOf.call(arr,searchElement,fromIndex)}:function(arr,searchElement,fromIndex){var length=this.length>>>0;fromIndex=+fromIndex||0;if(Math.abs(fromIndex)===Infinity){fromIndex=0}if(fromIndex<0){fromIndex+=length;if(fromIndex<0){fromIndex=0}}for(;fromIndex<length;fromIndex++){if(arr[fromIndex]===searchElement){return fromIndex}}return-1};if(!Array.prototype.map){Array.prototype.map=function(){throw new Error("map is unimplemented for this js engine")}}exports.keys=function(obj){if(Object.prototype.keys){return obj.keys()}else{var keys=[];for(var k in obj){if(obj.hasOwnProperty(k)){keys.push(k)}}return keys}}})();(function(){"use strict";var lib=modules["lib"];var Obj=modules["object"];var Frame=Obj.extend({init:function(parent){this.variables={};this.parent=parent},set:function(name,val,resolveUp){var parts=name.split(".");var obj=this.variables;var frame=this;if(resolveUp){if(frame=this.resolve(parts[0])){frame.set(name,val);return}frame=this}for(var i=0;i<parts.length-1;i++){var id=parts[i];if(!obj[id]){obj[id]={}}obj=obj[id]}obj[parts[parts.length-1]]=val},get:function(name){var val=this.variables[name];if(val!==undefined&&val!==null){return val}return null},lookup:function(name){var p=this.parent;var val=this.variables[name];if(val!==undefined&&val!==null){return val}return p&&p.lookup(name)},resolve:function(name){var p=this.parent;var val=this.variables[name];if(val!==undefined&&val!==null){return this}return p&&p.resolve(name)},push:function(){return new Frame(this)},pop:function(){return this.parent}});function makeMacro(argNames,kwargNames,func){return function(){var argCount=numArgs(arguments);var args;var kwargs=getKeywordArgs(arguments);if(argCount>argNames.length){args=Array.prototype.slice.call(arguments,0,argNames.length);var vals=Array.prototype.slice.call(arguments,args.length,argCount);for(var i=0;i<vals.length;i++){if(i<kwargNames.length){kwargs[kwargNames[i]]=vals[i]}}args.push(kwargs)}else if(argCount<argNames.length){args=Array.prototype.slice.call(arguments,0,argCount);for(var i=argCount;i<argNames.length;i++){var arg=argNames[i];args.push(kwargs[arg]);delete kwargs[arg]}args.push(kwargs)}else{args=arguments}return func.apply(this,args)}}function makeKeywordArgs(obj){obj.__keywords=true;return obj}function getKeywordArgs(args){var len=args.length;if(len){var lastArg=args[len-1];if(lastArg&&lastArg.hasOwnProperty("__keywords")){return lastArg}}return{}}function numArgs(args){var len=args.length;if(len===0){return 0}var lastArg=args[len-1];if(lastArg&&lastArg.hasOwnProperty("__keywords")){return len-1}else{return len}}function SafeString(val){if(typeof val!=="string"){return val}this.val=val}SafeString.prototype=Object.create(String.prototype);SafeString.prototype.valueOf=function(){return this.val};SafeString.prototype.toString=function(){return this.val};function copySafeness(dest,target){if(dest instanceof SafeString){return new SafeString(target)}return target.toString()}function markSafe(val){var type=typeof val;if(type==="string"){return new SafeString(val)}else if(type!=="function"){return val}else{return function(){var ret=val.apply(this,arguments);if(typeof ret==="string"){return new SafeString(ret)}return ret}}}function suppressValue(val,autoescape){val=val!==undefined&&val!==null?val:"";if(autoescape&&typeof val==="string"){val=lib.escape(val)}return val}function memberLookup(obj,val){obj=obj||{};if(typeof obj[val]==="function"){return function(){return obj[val].apply(obj,arguments)}}return obj[val]}function callWrap(obj,name,args){if(!obj){throw new Error("Unable to call `"+name+"`, which is undefined or falsey")}else if(typeof obj!=="function"){throw new Error("Unable to call `"+name+"`, which is not a function")}return obj.apply(this,args)}function contextOrFrameLookup(context,frame,name){var val=frame.lookup(name);return val!==undefined&&val!==null?val:context.lookup(name)}function handleError(error,lineno,colno){if(error.lineno){return error}else{return new lib.TemplateError(error,lineno,colno)}}function asyncEach(arr,dimen,iter,cb){if(lib.isArray(arr)){var len=arr.length;lib.asyncIter(arr,function(item,i,next){switch(dimen){case 1:iter(item,i,len,next);break;case 2:iter(item[0],item[1],i,len,next);break;case 3:iter(item[0],item[1],item[2],i,len,next);break;default:item.push(i,next);iter.apply(this,item)}},cb)}else{lib.asyncFor(arr,function(key,val,i,len,next){iter(key,val,i,len,next)},cb)}}function asyncAll(arr,dimen,func,cb){var finished=0;var len;var outputArr;function done(i,output){finished++;outputArr[i]=output;if(finished===len){cb(null,outputArr.join(""))}}if(lib.isArray(arr)){len=arr.length;outputArr=new Array(len);if(len===0){cb(null,"")}else{for(var i=0;i<arr.length;i++){var item=arr[i];switch(dimen){case 1:func(item,i,len,done);break;case 2:func(item[0],item[1],i,len,done);break;case 3:func(item[0],item[1],item[2],i,len,done);break;default:item.push(i,done);func.apply(this,item)}}}}else{var keys=lib.keys(arr);len=keys.length;outputArr=new Array(len);if(len===0){cb(null,"")}else{for(var i=0;i<keys.length;i++){var k=keys[i];func(k,arr[k],i,len,done)}}}}modules["runtime"]={Frame:Frame,makeMacro:makeMacro,makeKeywordArgs:makeKeywordArgs,numArgs:numArgs,suppressValue:suppressValue,memberLookup:memberLookup,contextOrFrameLookup:contextOrFrameLookup,callWrap:callWrap,handleError:handleError,isArray:lib.isArray,keys:lib.keys,SafeString:SafeString,copySafeness:copySafeness,markSafe:markSafe,asyncEach:asyncEach,asyncAll:asyncAll}})();(function(){"use strict";var path=modules["path"];var Obj=modules["object"];var lib=modules["lib"];var Loader=Obj.extend({on:function(name,func){this.listeners=this.listeners||{};this.listeners[name]=this.listeners[name]||[];this.listeners[name].push(func)},emit:function(name){var args=Array.prototype.slice.call(arguments,1);if(this.listeners&&this.listeners[name]){lib.each(this.listeners[name],function(listener){listener.apply(null,args)})}},resolve:function(from,to){return path.resolve(path.dirname(from),to)},isRelative:function(filename){return filename.indexOf("./")===0||filename.indexOf("../")===0}});modules["loader"]=Loader})();(function(){"use strict";var Loader=modules["loader"];var WebLoader=Loader.extend({init:function(baseURL,neverUpdate){this.precompiled=window.nunjucksPrecompiled||{};this.baseURL=baseURL||"";this.neverUpdate=neverUpdate},getSource:function(name){if(this.precompiled[name]){return{src:{type:"code",obj:this.precompiled[name]},path:name}}else{var src=this.fetch(this.baseURL+"/"+name);if(!src){return null}return{src:src,path:name,noCache:!this.neverUpdate}}},fetch:function(url,callback){var ajax;var loading=true;var src;if(window.XMLHttpRequest){ajax=new XMLHttpRequest}else if(window.ActiveXObject){ajax=new ActiveXObject("Microsoft.XMLHTTP")}ajax.onreadystatechange=function(){if(ajax.readyState===4&&(ajax.status===0||ajax.status===200)&&loading){loading=false;src=ajax.responseText}};url+=(url.indexOf("?")===-1?"?":"&")+"s="+(new Date).getTime();ajax.open("GET",url,false);ajax.send();return src}});modules["web-loaders"]={WebLoader:WebLoader}})();(function(){if(typeof window==="undefined"||window!==this){modules["loaders"]=modules["node-loaders"]}else{modules["loaders"]=modules["web-loaders"]}})();(function(){"use strict";var lib=modules["lib"];var r=modules["runtime"];var filters={abs:function(n){return Math.abs(n)},batch:function(arr,linecount,fill_with){var res=[];var tmp=[];for(var i=0;i<arr.length;i++){if(i%linecount===0&&tmp.length){res.push(tmp);tmp=[]}tmp.push(arr[i])}if(tmp.length){if(fill_with){for(var i=tmp.length;i<linecount;i++){tmp.push(fill_with)}}res.push(tmp)}return res},capitalize:function(str){var ret=str.toLowerCase();return r.copySafeness(str,ret.charAt(0).toUpperCase()+ret.slice(1))},center:function(str,width){width=width||80;if(str.length>=width){return str}var spaces=width-str.length;var pre=lib.repeat(" ",spaces/2-spaces%2);var post=lib.repeat(" ",spaces/2);return r.copySafeness(str,pre+str+post)},"default":function(val,def){return val?val:def},dictsort:function(val,case_sensitive,by){if(!lib.isObject(val)){throw new lib.TemplateError("dictsort filter: val must be an object")}var array=[];for(var k in val){array.push([k,val[k]])}var si;if(by===undefined||by==="key"){si=0}else if(by==="value"){si=1}else{throw new lib.TemplateError("dictsort filter: You can only sort by either key or value")}array.sort(function(t1,t2){var a=t1[si];var b=t2[si];if(!case_sensitive){if(lib.isString(a)){a=a.toUpperCase()}if(lib.isString(b)){b=b.toUpperCase()}}return a>b?1:a===b?0:-1});return array},escape:function(str){if(typeof str==="string"||str instanceof r.SafeString){return lib.escape(str)}return str},safe:function(str){return r.markSafe(str)},first:function(arr){return arr[0]},groupby:function(arr,attr){return lib.groupBy(arr,attr)},indent:function(str,width,indentfirst){width=width||4;var res="";var lines=str.split("\n");var sp=lib.repeat(" ",width);for(var i=0;i<lines.length;i++){if(i===0&&!indentfirst){res+=lines[i]+"\n"}else{res+=sp+lines[i]+"\n"}}return r.copySafeness(str,res)},join:function(arr,del,attr){del=del||"";if(attr){arr=lib.map(arr,function(v){return v[attr]})}return arr.join(del)},last:function(arr){return arr[arr.length-1]},length:function(arr){return arr!==undefined?arr.length:0},list:function(val){if(lib.isString(val)){return val.split("")}else if(lib.isObject(val)){var keys=[];if(Object.keys){keys=Object.keys(val)}else{for(var k in val){keys.push(k)}}return lib.map(keys,function(k){return{key:k,value:val[k]}})}else if(lib.isArray(val)){return val}else{throw new lib.TemplateError("list filter: type not iterable")}},lower:function(str){return str.toLowerCase()},random:function(arr){return arr[Math.floor(Math.random()*arr.length)]},rejectattr:function(arr,attr){return arr.filter(function(item){return!item[attr]})},selectattr:function(arr,attr){return arr.filter(function(item){return!!item[attr]})},replace:function(str,old,new_,maxCount){if(old instanceof RegExp){return str.replace(old,new_)}var res=str;var last=res;var count=1;res=res.replace(old,new_);while(last!==res){if(count>=maxCount){break}last=res;res=res.replace(old,new_);count++}return r.copySafeness(str,res)},reverse:function(val){var arr;if(lib.isString(val)){arr=filters.list(val)}else{arr=lib.map(val,function(v){return v})}arr.reverse();if(lib.isString(val)){return r.copySafeness(val,arr.join(""))}return arr},round:function(val,precision,method){precision=precision||0;var factor=Math.pow(10,precision);var rounder;if(method==="ceil"){rounder=Math.ceil}else if(method==="floor"){rounder=Math.floor}else{rounder=Math.round}return rounder(val*factor)/factor},slice:function(arr,slices,fillWith){var sliceLength=Math.floor(arr.length/slices);var extra=arr.length%slices;var offset=0;var res=[];for(var i=0;i<slices;i++){var start=offset+i*sliceLength;if(i<extra){offset++}var end=offset+(i+1)*sliceLength;var slice=arr.slice(start,end);if(fillWith&&i>=extra){slice.push(fillWith)}res.push(slice)}return res},sort:function(arr,reverse,caseSens,attr){arr=lib.map(arr,function(v){return v});arr.sort(function(a,b){var x,y;if(attr){x=a[attr];y=b[attr]}else{x=a;y=b}if(!caseSens&&lib.isString(x)&&lib.isString(y)){x=x.toLowerCase();y=y.toLowerCase()}if(x<y){return reverse?1:-1}else if(x>y){return reverse?-1:1}else{return 0}});return arr},string:function(obj){return r.copySafeness(obj,obj)},title:function(str){var words=str.split(" ");for(var i=0;i<words.length;i++){words[i]=filters.capitalize(words[i])}return r.copySafeness(str,words.join(" "))},trim:function(str){return r.copySafeness(str,str.replace(/^\s*|\s*$/g,""))},truncate:function(input,length,killwords,end){var orig=input;length=length||255;if(input.length<=length)return input;if(killwords){input=input.substring(0,length)}else{var idx=input.lastIndexOf(" ",length);if(idx===-1){idx=length}input=input.substring(0,idx)}input+=end!==undefined&&end!==null?end:"...";return r.copySafeness(orig,input)},upper:function(str){return str.toUpperCase()},urlencode:function(obj){var enc=encodeURIComponent;if(lib.isString(obj)){return enc(obj)}else{var parts;if(lib.isArray(obj)){parts=obj.map(function(item){return enc(item[0])+"="+enc(item[1])})}else{parts=[];for(var k in obj){if(obj.hasOwnProperty(k)){parts.push(enc(k)+"="+enc(obj[k]))}}}return parts.join("&")}},urlize:function(str,length,nofollow){if(isNaN(length))length=Infinity;var noFollowAttr=nofollow===true?' rel="nofollow"':"";var puncRE=/^(?:\(|<|&lt;)?(.*?)(?:\.|,|\)|\n|&gt;)?$/;var emailRE=/^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i;var httpHttpsRE=/^https?:\/\/.*$/;var wwwRE=/^www\./;var tldRE=/\.(?:org|net|com)(?:\:|\/|$)/;var words=str.split(/\s+/).filter(function(word){return word&&word.length}).map(function(word){var matches=word.match(puncRE);var possibleUrl=matches&&matches[1]||word;if(httpHttpsRE.test(possibleUrl))return'<a href="'+possibleUrl+'"'+noFollowAttr+">"+possibleUrl.substr(0,length)+"</a>";if(wwwRE.test(possibleUrl))return'<a href="http://'+possibleUrl+'"'+noFollowAttr+">"+possibleUrl.substr(0,length)+"</a>";if(emailRE.test(possibleUrl))return'<a href="mailto:'+possibleUrl+'">'+possibleUrl+"</a>";if(tldRE.test(possibleUrl))return'<a href="http://'+possibleUrl+'"'+noFollowAttr+">"+possibleUrl.substr(0,length)+"</a>";return word});return words.join(" ")},wordcount:function(str){var words=str?str.match(/\w+/g):null;return words?words.length:null},"float":function(val,def){var res=parseFloat(val);return isNaN(res)?def:res},"int":function(val,def){var res=parseInt(val,10);return isNaN(res)?def:res}};filters.d=filters["default"];filters.e=filters.escape;modules["filters"]=filters})();(function(){"use strict";function cycler(items){var index=-1;return{current:null,reset:function(){index=-1;this.current=null},next:function(){index++;if(index>=items.length){index=0}this.current=items[index];return this.current}}}function joiner(sep){sep=sep||",";var first=true;return function(){var val=first?"":sep;first=false;return val}}var globals={range:function(start,stop,step){if(!stop){stop=start;start=0;step=1}else if(!step){step=1}var arr=[];for(var i=start;i<stop;i+=step){arr.push(i)}return arr},cycler:function(){return cycler(Array.prototype.slice.call(arguments))},joiner:function(sep){return joiner(sep)}};modules["globals"]=globals})();(function(){"use strict";var path=modules["path"];var lib=modules["lib"];var Obj=modules["object"];var lexer=modules["lexer"];var compiler=modules["compiler"];var builtin_filters=modules["filters"];var builtin_loaders=modules["loaders"];var runtime=modules["runtime"];var globals=modules["globals"];var Frame=runtime.Frame;var Environment=Obj.extend({init:function(loaders,opts){var opts=this.opts=opts||{};this.opts.dev=!!opts.dev;this.opts.autoescape=!!opts.autoescape;this.opts.trimBlocks=!!opts.trimBlocks;this.opts.lstripBlocks=!!opts.lstripBlocks;if(!loaders){if(builtin_loaders.FileSystemLoader){this.loaders=[new builtin_loaders.FileSystemLoader("views")]}else{this.loaders=[new builtin_loaders.WebLoader("/views")]}}else{this.loaders=lib.isArray(loaders)?loaders:[loaders]}this.initCache();this.filters={};this.asyncFilters=[];this.extensions={};this.extensionsList=[];for(var name in builtin_filters){this.addFilter(name,builtin_filters[name])}},initCache:function(){lib.each(this.loaders,function(loader){loader.cache={};if(typeof loader.on==="function"){loader.on("update",function(template){loader.cache[template]=null})}})},addExtension:function(name,extension){extension._name=name;this.extensions[name]=extension;this.extensionsList.push(extension)},getExtension:function(name){return this.extensions[name]},addGlobal:function(name,value){globals[name]=value},addFilter:function(name,func,async){var wrapped=func;if(async){this.asyncFilters.push(name)}this.filters[name]=wrapped},getFilter:function(name){if(!this.filters[name]){throw new Error("filter not found: "+name)}return this.filters[name]},resolveTemplate:function(loader,parentName,filename){var isRelative=loader.isRelative&&parentName?loader.isRelative(filename):false;return isRelative&&loader.resolve?loader.resolve(parentName,filename):filename},getTemplate:function(name,eagerCompile,parentName,cb){var that=this;var tmpl=null;if(name&&name.raw){name=name.raw}if(lib.isFunction(parentName)){cb=parentName;parentName=null;eagerCompile=eagerCompile||false}if(lib.isFunction(eagerCompile)){cb=eagerCompile;eagerCompile=false}if(typeof name!=="string"){throw new Error("template names must be a string: "+name)}for(var i=0;i<this.loaders.length;i++){var _name=this.resolveTemplate(this.loaders[i],parentName,name);tmpl=this.loaders[i].cache[_name];if(tmpl)break}if(tmpl){if(eagerCompile){tmpl.compile()}if(cb){cb(null,tmpl)}else{return tmpl}}else{var syncResult;lib.asyncIter(this.loaders,function(loader,i,next,done){function handle(src){if(src){src.loader=loader;done(src)}else{next()}}name=that.resolveTemplate(loader,parentName,name);if(loader.async){loader.getSource(name,function(err,src){if(err){throw err}handle(src)})}else{handle(loader.getSource(name))}},function(info){if(!info){var err=new Error("template not found: "+name);if(cb){cb(err)}else{throw err}}else{var tmpl=new Template(info.src,this,info.path,eagerCompile);if(!info.noCache){info.loader.cache[name]=tmpl}if(cb){cb(null,tmpl)}else{syncResult=tmpl}}}.bind(this));return syncResult}},express:function(app){var env=this;function NunjucksView(name,opts){this.name=name;this.path=name;this.defaultEngine=opts.defaultEngine;this.ext=path.extname(name);if(!this.ext&&!this.defaultEngine)throw new Error("No default engine was specified and no extension was provided.");if(!this.ext)this.name+=this.ext=("."!==this.defaultEngine[0]?".":"")+this.defaultEngine}NunjucksView.prototype.render=function(opts,cb){env.render(this.name,opts,cb)};app.set("view",NunjucksView)},render:function(name,ctx,cb){if(lib.isFunction(ctx)){cb=ctx;ctx=null}var syncResult=null;this.getTemplate(name,function(err,tmpl){if(err&&cb){cb(err)}else if(err){throw err}else{tmpl.render(ctx,cb||function(err,res){if(err){throw err}syncResult=res})}});return syncResult},renderString:function(src,ctx,opts,cb){if(lib.isFunction(opts)){cb=opts;opts={}}opts=opts||{};var tmpl=new Template(src,this,opts.path);return tmpl.render(ctx,cb)}});var Context=Obj.extend({init:function(ctx,blocks){this.ctx=ctx;this.blocks={};this.exported=[];for(var name in blocks){this.addBlock(name,blocks[name])}},lookup:function(name){if(name in globals&&!(name in this.ctx)){return globals[name]}else{return this.ctx[name]}},setVariable:function(name,val){this.ctx[name]=val},getVariables:function(){return this.ctx},addBlock:function(name,block){this.blocks[name]=this.blocks[name]||[];this.blocks[name].push(block)},getBlock:function(name){if(!this.blocks[name]){throw new Error('unknown block "'+name+'"')}return this.blocks[name][0]},getSuper:function(env,name,block,frame,runtime,cb){var idx=lib.indexOf(this.blocks[name]||[],block);var blk=this.blocks[name][idx+1];var context=this;if(idx===-1||!blk){throw new Error('no super block available for "'+name+'"')}blk(env,context,frame,runtime,cb)},addExport:function(name){this.exported.push(name)},getExported:function(){var exported={};for(var i=0;i<this.exported.length;i++){var name=this.exported[i];exported[name]=this.ctx[name]}return exported}});var Template=Obj.extend({init:function(src,env,path,eagerCompile){this.env=env||new Environment;if(lib.isObject(src)){switch(src.type){case"code":this.tmplProps=src.obj;break;case"string":this.tmplStr=src.obj;break}}else if(lib.isString(src)){this.tmplStr=src}else{throw new Error("src must be a string or an object describing "+"the source")}this.path=path;if(eagerCompile){lib.withPrettyErrors(this.path,this.env.dev,this._compile.bind(this))}else{this.compiled=false}},render:function(ctx,frame,cb){if(typeof ctx==="function"){cb=ctx;ctx={}}else if(typeof frame==="function"){cb=frame;frame=null}return lib.withPrettyErrors(this.path,this.env.dev,function(){try{this.compile()}catch(e){if(cb)return cb(e);else throw e}var context=new Context(ctx||{},this.blocks);var syncResult=null;this.rootRenderFunc(this.env,context,frame||new Frame,runtime,cb||function(err,res){if(err){throw err}syncResult=res});return syncResult}.bind(this))},getExported:function(ctx,frame,cb){if(typeof ctx==="function"){cb=ctx;ctx={}}if(typeof frame==="function"){cb=frame;frame=null}try{this.compile()}catch(e){if(cb)return cb(e);else throw e}var context=new Context(ctx||{},this.blocks);this.rootRenderFunc(this.env,context,frame||new Frame,runtime,function(){cb(null,context.getExported())})},compile:function(){if(!this.compiled){this._compile()}},_compile:function(){var props;if(this.tmplProps){props=this.tmplProps}else{var source=compiler.compile(this.tmplStr,this.env.asyncFilters,this.env.extensionsList,this.path,this.env.opts);var func=new Function(source);props=func()}this.blocks=this._getBlocks(props);this.rootRenderFunc=props.root;this.compiled=true},_getBlocks:function(props){var blocks={};for(var k in props){if(k.slice(0,2)==="b_"){blocks[k.slice(2)]=props[k]}}return blocks}});modules["environment"]={Environment:Environment,Template:Template}})();var nunjucks;var lib=modules["lib"];var env=modules["environment"];var compiler=modules["compiler"];var parser=modules["parser"];var lexer=modules["lexer"];var runtime=modules["runtime"];var Loader=modules["loader"];var loaders=modules["loaders"];var precompile=modules["precompile"];nunjucks={};nunjucks.Environment=env.Environment;nunjucks.Template=env.Template;nunjucks.Loader=Loader;nunjucks.FileSystemLoader=loaders.FileSystemLoader;nunjucks.WebLoader=loaders.WebLoader;nunjucks.compiler=compiler;nunjucks.parser=parser;nunjucks.lexer=lexer;nunjucks.runtime=runtime;var e;nunjucks.configure=function(templatesPath,opts){opts=opts||{};if(lib.isObject(templatesPath)){opts=templatesPath;templatesPath=null}var noWatch="watch"in opts?!opts.watch:false;var loader=loaders.FileSystemLoader||loaders.WebLoader;e=new env.Environment(new loader(templatesPath,noWatch),opts);if(opts&&opts.express){e.express(opts.express)}return e};nunjucks.compile=function(src,env,path,eagerCompile){if(!e){nunjucks.configure()}return new nunjucks.Template(src,env,path,eagerCompile)};nunjucks.render=function(name,ctx,cb){if(!e){nunjucks.configure()}return e.render(name,ctx,cb)};nunjucks.renderString=function(src,ctx,cb){if(!e){nunjucks.configure()}return e.renderString(src,ctx,cb)};if(precompile){nunjucks.precompile=precompile.precompile;nunjucks.precompileString=precompile.precompileString}nunjucks.require=function(name){return modules[name]};if(typeof define==="function"&&define.amd){define(function(){return nunjucks})}else{window.nunjucks=nunjucks;if(typeof module!=="undefined")module.exports=nunjucks}})();
/*! Browser bundle of nunjucks 2.0.0 (slim, only works with precompiled templates) */
var nunjucks=function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return t[n].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){"use strict";var n=r(1),i=r(2),o=r(11),s=r(3),u=r(3);t.exports={},t.exports.Environment=i.Environment,t.exports.Template=i.Template,t.exports.Loader=o,t.exports.FileSystemLoader=s.FileSystemLoader,t.exports.PrecompiledLoader=s.PrecompiledLoader,t.exports.WebLoader=s.WebLoader,t.exports.compiler=r(3),t.exports.parser=r(3),t.exports.lexer=r(3),t.exports.runtime=r(8),t.exports.lib=n,t.exports.installJinjaCompat=r(12);var a;t.exports.configure=function(t,e){e=e||{},n.isObject(t)&&(e=t,t=null);var r;return s.FileSystemLoader?r=new s.FileSystemLoader(t,{watch:e.watch,noCache:e.noCache}):s.WebLoader&&(r=new s.WebLoader(t,{useCache:e.web&&e.web.useCache,async:e.web&&e.web.async})),a=new i.Environment(r,e),e&&e.express&&a.express(e.express),a},t.exports.compile=function(e,r,n,i){return a||t.exports.configure(),new t.exports.Template(e,r,n,i)},t.exports.render=function(e,r,n){return a||t.exports.configure(),a.render(e,r,n)},t.exports.renderString=function(e,r,n){return a||t.exports.configure(),a.renderString(e,r,n)},u&&(t.exports.precompile=u.precompile,t.exports.precompileString=u.precompileString)},function(t,e){"use strict";var r=Array.prototype,n=Object.prototype,i={"&":"&amp;",'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;"},o=/[&"'<>]/g,s=function(t){return i[t]},e=t.exports={};e.prettifyError=function(t,r,n){if(n.Update||(n=new e.TemplateError(n)),n.Update(t),!r){var i=n;n=new Error(i.message),n.name=i.name}return n},e.TemplateError=function(t,e,r){var n=this;return t instanceof Error?(n=t,t=t.name+": "+t.message):Error.captureStackTrace&&Error.captureStackTrace(n),n.name="Template render error",n.message=t,n.lineno=e,n.colno=r,n.firstUpdate=!0,n.Update=function(t){var e="("+(t||"unknown path")+")";return this.firstUpdate&&(this.lineno&&this.colno?e+=" [Line "+this.lineno+", Column "+this.colno+"]":this.lineno&&(e+=" [Line "+this.lineno+"]")),e+="\n ",this.firstUpdate&&(e+=" "),this.message=e+(this.message||""),this.firstUpdate=!1,this},n},e.TemplateError.prototype=Error.prototype,e.escape=function(t){return t.replace(o,s)},e.isFunction=function(t){return"[object Function]"===n.toString.call(t)},e.isArray=Array.isArray||function(t){return"[object Array]"===n.toString.call(t)},e.isString=function(t){return"[object String]"===n.toString.call(t)},e.isObject=function(t){return"[object Object]"===n.toString.call(t)},e.groupBy=function(t,r){for(var n={},i=e.isFunction(r)?r:function(t){return t[r]},o=0;o<t.length;o++){var s=t[o],u=i(s,o);(n[u]||(n[u]=[])).push(s)}return n},e.toArray=function(t){return Array.prototype.slice.call(t)},e.without=function(t){var r=[];if(!t)return r;for(var n=-1,i=t.length,o=e.toArray(arguments).slice(1);++n<i;)-1===e.indexOf(o,t[n])&&r.push(t[n]);return r},e.extend=function(t,e){for(var r in e)t[r]=e[r];return t},e.repeat=function(t,e){for(var r="",n=0;e>n;n++)r+=t;return r},e.each=function(t,e,n){if(null!=t)if(r.each&&t.each===r.each)t.forEach(e,n);else if(t.length===+t.length)for(var i=0,o=t.length;o>i;i++)e.call(n,t[i],i,t)},e.map=function(t,e){var n=[];if(null==t)return n;if(r.map&&t.map===r.map)return t.map(e);for(var i=0;i<t.length;i++)n[n.length]=e(t[i],i);return t.length===+t.length&&(n.length=t.length),n},e.asyncIter=function(t,e,r){function n(){i++,i<t.length?e(t[i],i,n,r):r()}var i=-1;n()},e.asyncFor=function(t,r,n){function i(){u++;var e=o[u];s>u?r(e,t[e],u,s,i):n()}var o=e.keys(t),s=o.length,u=-1;i()},e.indexOf=Array.prototype.indexOf?function(t,e,r){return Array.prototype.indexOf.call(t,e,r)}:function(t,e,r){var n=this.length>>>0;for(r=+r||0,Math.abs(r)===1/0&&(r=0),0>r&&(r+=n,0>r&&(r=0));n>r;r++)if(t[r]===e)return r;return-1},Array.prototype.map||(Array.prototype.map=function(){throw new Error("map is unimplemented for this js engine")}),e.keys=function(t){if(Object.prototype.keys)return t.keys();var e=[];for(var r in t)t.hasOwnProperty(r)&&e.push(r);return e}},function(t,e,r){"use strict";function n(t,e,r){s(function(){t(e,r)})}var i,o=r(3),s=r(4),u=r(1),a=r(6),c=r(3),l=r(7),f=r(3),p=r(8),h=r(9),v=p.Frame;f.PrecompiledLoader=r(10);var d=a.extend({init:function(t,e){e=this.opts=e||{},this.opts.dev=!!e.dev,this.opts.autoescape=null!=e.autoescape?e.autoescape:!0,this.opts.throwOnUndefined=!!e.throwOnUndefined,this.opts.trimBlocks=!!e.trimBlocks,this.opts.lstripBlocks=!!e.lstripBlocks,this.loaders=[],t?this.loaders=u.isArray(t)?t:[t]:f.FileSystemLoader?this.loaders=[new f.FileSystemLoader("views")]:f.WebLoader&&(this.loaders=[new f.WebLoader("/views")]),window.nunjucksPrecompiled&&this.loaders.unshift(new f.PrecompiledLoader(window.nunjucksPrecompiled)),this.initCache(),this.filters={},this.asyncFilters=[],this.extensions={},this.extensionsList=[];for(var r in l)this.addFilter(r,l[r])},initCache:function(){u.each(this.loaders,function(t){t.cache={},"function"==typeof t.on&&t.on("update",function(e){t.cache[e]=null})})},addExtension:function(t,e){e._name=t,this.extensions[t]=e,this.extensionsList.push(e)},getExtension:function(t){return this.extensions[t]},addGlobal:function(t,e){h[t]=e},getGlobal:function(t){if(!h[t])throw new Error("global not found: "+t);return h[t]},addFilter:function(t,e,r){var n=e;r&&this.asyncFilters.push(t),this.filters[t]=n},getFilter:function(t){if(!this.filters[t])throw new Error("filter not found: "+t);return this.filters[t]},resolveTemplate:function(t,e,r){var n=t.isRelative&&e?t.isRelative(r):!1;return n&&t.resolve?t.resolve(e,r):r},getTemplate:function(t,e,r,n){var o=this,s=null;if(t&&t.raw&&(t=t.raw),u.isFunction(r)&&(n=r,r=null,e=e||!1),u.isFunction(e)&&(n=e,e=!1),"string"!=typeof t)throw new Error("template names must be a string: "+t);for(var a=0;a<this.loaders.length;a++){var c=this.resolveTemplate(this.loaders[a],r,t);if(s=this.loaders[a].cache[c])break}if(!s){var l,f=this,p=function(r){if(r){var o=new i(r.src,f,r.path,e);r.noCache||(r.loader.cache[t]=o),n?n(null,o):l=o}else{var s=new Error("template not found: "+t);if(!n)throw s;n(s)}};return u.asyncIter(this.loaders,function(e,n,i,s){function u(t){t?(t.loader=e,s(t)):i()}t=o.resolveTemplate(e,r,t),e.async?e.getSource(t,function(t,e){if(t)throw t;u(e)}):u(e.getSource(t))},p),l}return e&&s.compile(),n?void n(null,s):s},express:function(t){function e(t,e){if(this.name=t,this.path=t,this.defaultEngine=e.defaultEngine,this.ext=o.extname(t),!this.ext&&!this.defaultEngine)throw new Error("No default engine was specified and no extension was provided.");this.ext||(this.name+=this.ext=("."!==this.defaultEngine[0]?".":"")+this.defaultEngine)}var r=this;e.prototype.render=function(t,e){r.render(this.name,t,e)},t.set("view",e)},render:function(t,e,r){u.isFunction(e)&&(r=e,e=null);var i=null;return this.getTemplate(t,function(t,o){if(t&&r)n(r,t);else{if(t)throw t;i=o.render(e,r)}}),i},renderString:function(t,e,r,n){u.isFunction(r)&&(n=r,r={}),r=r||{};var o=new i(t,this,r.path);return o.render(e,n)}}),g=a.extend({init:function(t,e){this.ctx={};for(var r in t)t.hasOwnProperty(r)&&(this.ctx[r]=t[r]);this.blocks={},this.exported=[];for(var n in e)this.addBlock(n,e[n])},lookup:function(t){return t in h&&!(t in this.ctx)?h[t]:this.ctx[t]},setVariable:function(t,e){this.ctx[t]=e},getVariables:function(){return this.ctx},addBlock:function(t,e){this.blocks[t]=this.blocks[t]||[],this.blocks[t].push(e)},getBlock:function(t){if(!this.blocks[t])throw new Error('unknown block "'+t+'"');return this.blocks[t][0]},getSuper:function(t,e,r,n,i,o){var s=u.indexOf(this.blocks[e]||[],r),a=this.blocks[e][s+1],c=this;if(-1===s||!a)throw new Error('no super block available for "'+e+'"');a(t,c,n,i,o)},addExport:function(t){this.exported.push(t)},getExported:function(){for(var t={},e=0;e<this.exported.length;e++){var r=this.exported[e];t[r]=this.ctx[r]}return t}});i=a.extend({init:function(t,e,r,n){if(this.env=e||new d,u.isObject(t))switch(t.type){case"code":this.tmplProps=t.obj;break;case"string":this.tmplStr=t.obj}else{if(!u.isString(t))throw new Error("src must be a string or an object describing the source");this.tmplStr=t}if(this.path=r,n){var i=this;try{i._compile()}catch(o){throw u.prettifyError(this.path,this.env.dev,o)}}else this.compiled=!1},render:function(t,e,r){"function"==typeof t?(r=t,t={}):"function"==typeof e&&(r=e,e=null);var i=!0;e&&(i=!1);var o=this;try{o.compile()}catch(s){var a=u.prettifyError(this.path,this.env.dev,s);if(r)return n(r,a);throw a}var c=new g(t||{},o.blocks),l=e?e.push():new v;l.topLevel=!0;var f=null;return o.rootRenderFunc(o.env,c,l||new v,p,function(t,e){if(t&&(t=u.prettifyError(o.path,o.env.dev,t)),r)i?n(r,t,e):r(t,e);else{if(t)throw t;f=e}}),f},getExported:function(t,e,r){"function"==typeof t&&(r=t,t={}),"function"==typeof e&&(r=e,e=null);try{this.compile()}catch(n){if(r)return r(n);throw n}var i=e?e.push():new v;i.topLevel=!0;var o=new g(t||{},this.blocks);this.rootRenderFunc(this.env,o,i,p,function(){r(null,o.getExported())})},compile:function(){this.compiled||this._compile()},_compile:function(){var t;if(this.tmplProps)t=this.tmplProps;else{var e=c.compile(this.tmplStr,this.env.asyncFilters,this.env.extensionsList,this.path,this.env.opts),r=new Function(e);t=r()}this.blocks=this._getBlocks(t),this.rootRenderFunc=t.root,this.compiled=!0},_getBlocks:function(t){var e={};for(var r in t)"b_"===r.slice(0,2)&&(e[r.slice(2)]=t[r]);return e}}),t.exports={Environment:d,Template:i}},function(t,e){},function(t,e,r){"use strict";function n(){if(a.length)throw a.shift()}function i(t){var e;e=u.length?u.pop():new o,e.task=t,s(e)}function o(){this.task=null}var s=r(5),u=[],a=[],c=s.makeRequestCallFromTimer(n);t.exports=i,o.prototype.call=function(){try{this.task.call()}catch(t){i.onerror?i.onerror(t):(a.push(t),c())}finally{this.task=null,u[u.length]=this}}},function(t,e){(function(e){"use strict";function r(t){u.length||(s(),a=!0),u[u.length]=t}function n(){for(;c<u.length;){var t=c;if(c+=1,u[t].call(),c>l){for(var e=0,r=u.length-c;r>e;e++)u[e]=u[e+c];u.length-=c,c=0}}u.length=0,c=0,a=!1}function i(t){var e=1,r=new f(t),n=document.createTextNode("");return r.observe(n,{characterData:!0}),function(){e=-e,n.data=e}}function o(t){return function(){function e(){clearTimeout(r),clearInterval(n),t()}var r=setTimeout(e,0),n=setInterval(e,50)}}t.exports=r;var s,u=[],a=!1,c=0,l=1024,f=e.MutationObserver||e.WebKitMutationObserver;s="function"==typeof f?i(n):o(n),r.requestFlush=s,r.makeRequestCallFromTimer=o}).call(e,function(){return this}())},function(t,e){"use strict";function r(t,e,n){var i=function(){};i.prototype=t.prototype;var o=new i,s=/xyz/.test(function(){xyz})?/\bparent\b/:/.*/;n=n||{};for(var u in n){var a=n[u],c=o[u];"function"==typeof c&&"function"==typeof a&&s.test(a)?o[u]=function(t,e){return function(){var r=this.parent;this.parent=e;var n=t.apply(this,arguments);return this.parent=r,n}}(a,c):o[u]=a}o.typename=e;var l=function(){o.init&&o.init.apply(this,arguments)};return l.prototype=o,l.prototype.constructor=l,l.extend=function(t,e){return"object"==typeof t&&(e=t,t="anonymous"),r(l,t,e)},l}t.exports=r(Object,"Object",{})},function(t,e,r){"use strict";function n(t,e){return null===t||void 0===t||t===!1?e:t}var i=r(1),o=r(8),s=!1,u={abs:function(t){return Math.abs(t)},batch:function(t,e,r){var n,i=[],o=[];for(n=0;n<t.length;n++)n%e===0&&o.length&&(i.push(o),o=[]),o.push(t[n]);if(o.length){if(r)for(n=o.length;e>n;n++)o.push(r);i.push(o)}return i},capitalize:function(t){t=n(t,"");var e=t.toLowerCase();return o.copySafeness(t,e.charAt(0).toUpperCase()+e.slice(1))},center:function(t,e){if(t=n(t,""),e=e||80,t.length>=e)return t;var r=e-t.length,s=i.repeat(" ",r/2-r%2),u=i.repeat(" ",r/2);return o.copySafeness(t,s+t+u)},"default":function(t,e,r){return r===!0||r===!1||s||(s=!0,console.log('[nunjucks] Warning: the "default" filter was used without specifying the type of comparison. 2.0 changed the default behavior from boolean (val ? val : def) to strictly undefined, so you should make sure that doesn\'t break anything. Be explicit about this to make this warning go away, or wait until 2.1. See http://mozilla.github.io/nunjucks/templating.html#defaultvalue-default-boolean')),r?t?t:e:void 0!==t?t:e},dictsort:function(t,e,r){if(!i.isObject(t))throw new i.TemplateError("dictsort filter: val must be an object");var n=[];for(var o in t)n.push([o,t[o]]);var s;if(void 0===r||"key"===r)s=0;else{if("value"!==r)throw new i.TemplateError("dictsort filter: You can only sort by either key or value");s=1}return n.sort(function(t,r){var n=t[s],o=r[s];return e||(i.isString(n)&&(n=n.toUpperCase()),i.isString(o)&&(o=o.toUpperCase())),n>o?1:n===o?0:-1}),n},dump:function(t){return JSON.stringify(t)},escape:function(t){return"string"==typeof t||t instanceof o.SafeString?i.escape(t):t},safe:function(t){return o.markSafe(t)},first:function(t){return t[0]},groupby:function(t,e){return i.groupBy(t,e)},indent:function(t,e,r){if(t=n(t,""),""===t)return"";e=e||4;for(var s="",u=t.split("\n"),a=i.repeat(" ",e),c=0;c<u.length;c++)s+=0!==c||r?a+u[c]+"\n":u[c]+"\n";return o.copySafeness(t,s)},join:function(t,e,r){return e=e||"",r&&(t=i.map(t,function(t){return t[r]})),t.join(e)},last:function(t){return t[t.length-1]},length:function(t){var e=n(t,"");return void 0!==e?e.length:0},list:function(t){if(i.isString(t))return t.split("");if(i.isObject(t)){var e=[];if(Object.keys)e=Object.keys(t);else for(var r in t)e.push(r);return i.map(e,function(e){return{key:e,value:t[e]}})}if(i.isArray(t))return t;throw new i.TemplateError("list filter: type not iterable")},lower:function(t){return t=n(t,""),t.toLowerCase()},random:function(t){return t[Math.floor(Math.random()*t.length)]},rejectattr:function(t,e){return t.filter(function(t){return!t[e]})},selectattr:function(t,e){return t.filter(function(t){return!!t[e]})},replace:function(t,e,r,n){var i=t;if(e instanceof RegExp)return t.replace(e,r);"undefined"==typeof n&&(n=-1);var s="";if("number"==typeof e)e+="";else if("string"!=typeof e)return t;if("number"==typeof t&&(t+=""),"string"!=typeof t&&!(t instanceof o.SafeString))return t;if(""===e)return s=r+t.split("").join(r)+r,o.copySafeness(t,s);var u=t.indexOf(e);if(0===n||-1===u)return t;for(var a=0,c=0;u>-1&&(-1===n||n>c);)s+=t.substring(a,u)+r,a=u+e.length,c++,u=t.indexOf(e,a);return a<t.length&&(s+=t.substring(a)),o.copySafeness(i,s)},reverse:function(t){var e;return e=i.isString(t)?u.list(t):i.map(t,function(t){return t}),e.reverse(),i.isString(t)?o.copySafeness(t,e.join("")):e},round:function(t,e,r){e=e||0;var n,i=Math.pow(10,e);return n="ceil"===r?Math.ceil:"floor"===r?Math.floor:Math.round,n(t*i)/i},slice:function(t,e,r){for(var n=Math.floor(t.length/e),i=t.length%e,o=0,s=[],u=0;e>u;u++){var a=o+u*n;i>u&&o++;var c=o+(u+1)*n,l=t.slice(a,c);r&&u>=i&&l.push(r),s.push(l)}return s},sort:function(t,e,r,n){return t=i.map(t,function(t){return t}),t.sort(function(t,o){var s,u;return n?(s=t[n],u=o[n]):(s=t,u=o),!r&&i.isString(s)&&i.isString(u)&&(s=s.toLowerCase(),u=u.toLowerCase()),u>s?e?1:-1:s>u?e?-1:1:0}),t},string:function(t){return o.copySafeness(t,t)},title:function(t){t=n(t,"");for(var e=t.split(" "),r=0;r<e.length;r++)e[r]=u.capitalize(e[r]);return o.copySafeness(t,e.join(" "))},trim:function(t){return o.copySafeness(t,t.replace(/^\s*|\s*$/g,""))},truncate:function(t,e,r,i){var s=t;if(t=n(t,""),e=e||255,t.length<=e)return t;if(r)t=t.substring(0,e);else{var u=t.lastIndexOf(" ",e);-1===u&&(u=e),t=t.substring(0,u)}return t+=void 0!==i&&null!==i?i:"...",o.copySafeness(s,t)},upper:function(t){return t=n(t,""),t.toUpperCase()},urlencode:function(t){var e=encodeURIComponent;if(i.isString(t))return e(t);var r;if(i.isArray(t))r=t.map(function(t){return e(t[0])+"="+e(t[1])});else{r=[];for(var n in t)t.hasOwnProperty(n)&&r.push(e(n)+"="+e(t[n]))}return r.join("&")},urlize:function(t,e,r){isNaN(e)&&(e=1/0);var n=r===!0?' rel="nofollow"':"",i=/^(?:\(|<|&lt;)?(.*?)(?:\.|,|\)|\n|&gt;)?$/,o=/^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i,s=/^https?:\/\/.*$/,u=/^www\./,a=/\.(?:org|net|com)(?:\:|\/|$)/,c=t.split(/\s+/).filter(function(t){return t&&t.length}).map(function(t){var r=t.match(i),c=r&&r[1]||t;return s.test(c)?'<a href="'+c+'"'+n+">"+c.substr(0,e)+"</a>":u.test(c)?'<a href="http://'+c+'"'+n+">"+c.substr(0,e)+"</a>":o.test(c)?'<a href="mailto:'+c+'">'+c+"</a>":a.test(c)?'<a href="http://'+c+'"'+n+">"+c.substr(0,e)+"</a>":t});return c.join(" ")},wordcount:function(t){t=n(t,"");var e=t?t.match(/\w+/g):null;return e?e.length:null},"float":function(t,e){var r=parseFloat(t);return isNaN(r)?e:r},"int":function(t,e){var r=parseInt(t,10);return isNaN(r)?e:r}};u.d=u["default"],u.e=u.escape,t.exports=u},function(t,e,r){"use strict";function n(t,e,r){return function(){var n,i,u=s(arguments),a=o(arguments);if(u>t.length){n=Array.prototype.slice.call(arguments,0,t.length);var c=Array.prototype.slice.call(arguments,n.length,u);for(i=0;i<c.length;i++)i<e.length&&(a[e[i]]=c[i]);n.push(a)}else if(u<t.length){for(n=Array.prototype.slice.call(arguments,0,u),i=u;i<t.length;i++){var l=t[i];n.push(a[l]),delete a[l]}n.push(a)}else n=arguments;return r.apply(this,n)}}function i(t){return t.__keywords=!0,t}function o(t){var e=t.length;if(e){var r=t[e-1];if(r&&r.hasOwnProperty("__keywords"))return r}return{}}function s(t){var e=t.length;if(0===e)return 0;var r=t[e-1];return r&&r.hasOwnProperty("__keywords")?e-1:e}function u(t){return"string"!=typeof t?t:(this.val=t,void(this.length=t.length))}function a(t,e){return t instanceof u?new u(e):e.toString()}function c(t){var e=typeof t;return"string"===e?new u(t):"function"!==e?t:function(){var e=t.apply(this,arguments);return"string"==typeof e?new u(e):e}}function l(t,e){return t=void 0!==t&&null!==t?t:"",e&&"string"==typeof t&&(t=m.escape(t)),t}function f(t,e,r){if(null===t||void 0===t)throw new m.TemplateError("attempted to output null or undefined value",e+1,r+1);return t}function p(t,e){return t=t||{},"function"==typeof t[e]?function(){return t[e].apply(t,arguments)}:t[e]}function h(t,e,r,n){if(!t)throw new Error("Unable to call `"+e+"`, which is undefined or falsey");if("function"!=typeof t)throw new Error("Unable to call `"+e+"`, which is not a function");return t.apply(r,n)}function v(t,e,r){var n=e.lookup(r);return void 0!==n&&null!==n?n:t.lookup(r)}function d(t,e,r){return t.lineno?t:new m.TemplateError(t,e,r)}function g(t,e,r,n){if(m.isArray(t)){var i=t.length;m.asyncIter(t,function(t,n,o){switch(e){case 1:r(t,n,i,o);break;case 2:r(t[0],t[1],n,i,o);break;case 3:r(t[0],t[1],t[2],n,i,o);break;default:t.push(n,o),r.apply(this,t)}},n)}else m.asyncFor(t,function(t,e,n,i,o){r(t,e,n,i,o)},n)}function y(t,e,r,n){function i(t,e){a++,u[t]=e,a===o&&n(null,u.join(""))}var o,s,u,a=0;if(m.isArray(t))if(o=t.length,u=new Array(o),0===o)n(null,"");else for(s=0;s<t.length;s++){var c=t[s];switch(e){case 1:r(c,s,o,i);break;case 2:r(c[0],c[1],s,o,i);break;case 3:r(c[0],c[1],c[2],s,o,i);break;default:c.push(s,i),r.apply(this,c)}}else{var l=m.keys(t);if(o=l.length,u=new Array(o),0===o)n(null,"");else for(s=0;s<l.length;s++){var f=l[s];r(f,t[f],s,o,i)}}}var m=r(1),w=r(6),b=w.extend({init:function(t){this.variables={},this.parent=t,this.topLevel=!1},set:function(t,e,r){var n=t.split("."),i=this.variables,o=this;if(r){if(o=this.resolve(n[0]))return void o.set(t,e);o=this}for(var s=0;s<n.length-1;s++){var u=n[s];i[u]||(i[u]={}),i=i[u]}i[n[n.length-1]]=e},get:function(t){var e=this.variables[t];return void 0!==e&&null!==e?e:null},lookup:function(t){var e=this.parent,r=this.variables[t];return void 0!==r&&null!==r?r:e&&e.lookup(t)},resolve:function(t){var e=this.parent,r=this.variables[t];return void 0!==r&&null!==r?this:e&&e.resolve(t)},push:function(){return new b(this)},pop:function(){return this.parent}});u.prototype=Object.create(String.prototype,{length:{writable:!0,configurable:!0,value:0}}),u.prototype.valueOf=function(){return this.val},u.prototype.toString=function(){return this.val},t.exports={Frame:b,makeMacro:n,makeKeywordArgs:i,numArgs:s,suppressValue:l,ensureDefined:f,memberLookup:p,contextOrFrameLookup:v,callWrap:h,handleError:d,isArray:m.isArray,keys:m.keys,SafeString:u,copySafeness:a,markSafe:c,asyncEach:g,asyncAll:y}},function(t,e){"use strict";function r(t){var e=-1;return{current:null,reset:function(){e=-1,this.current=null},next:function(){return e++,e>=t.length&&(e=0),this.current=t[e],this.current}}}function n(t){t=t||",";var e=!0;return function(){var r=e?"":t;return e=!1,r}}var i={range:function(t,e,r){e?r||(r=1):(e=t,t=0,r=1);for(var n=[],i=t;e>i;i+=r)n.push(i);return n},cycler:function(){return r(Array.prototype.slice.call(arguments))},joiner:function(t){return n(t)}};t.exports=i},function(t,e,r){"use strict";var n=r(11),i=n.extend({init:function(t){this.precompiled=t||{}},getSource:function(t){return this.precompiled[t]?{src:{type:"code",obj:this.precompiled[t]},path:t}:null}});t.exports=i},function(t,e,r){"use strict";var n=r(3),i=r(6),o=r(1),s=i.extend({on:function(t,e){this.listeners=this.listeners||{},this.listeners[t]=this.listeners[t]||[],this.listeners[t].push(e)},emit:function(t){var e=Array.prototype.slice.call(arguments,1);this.listeners&&this.listeners[t]&&o.each(this.listeners[t],function(t){t.apply(null,e)})},resolve:function(t,e){return n.resolve(n.dirname(t),e)},isRelative:function(t){return 0===t.indexOf("./")||0===t.indexOf("../")}});t.exports=s},function(t,e){function r(){"use strict";var t=this.runtime,e=this.lib,r=t.contextOrFrameLookup;t.contextOrFrameLookup=function(t,e,n){var i=r.apply(this,arguments);if(void 0===i)switch(n){case"True":return!0;case"False":return!1;case"None":return null}return i};var n=t.memberLookup,i={pop:function(t){if(void 0===t)return this.pop();if(t>=this.length||0>t)throw new Error("KeyError");return this.splice(t,1)},remove:function(t){for(var e=0;e<this.length;e++)if(this[e]===t)return this.splice(e,1);throw new Error("ValueError")},count:function(t){for(var e=0,r=0;r<this.length;r++)this[r]===t&&e++;return e},index:function(t){var e;if(-1===(e=this.indexOf(t)))throw new Error("ValueError");return e},find:function(t){return this.indexOf(t)},insert:function(t,e){return this.splice(t,0,e)}},o={items:function(){var t=[];for(var e in this)t.push([e,this[e]]);return t},values:function(){var t=[];for(var e in this)t.push(this[e]);return t},keys:function(){var t=[];for(var e in this)t.push(e);return t},get:function(t,e){var r=this[t];return void 0===r&&(r=e),r},has_key:function(t){return this.hasOwnProperty(t)},pop:function(t,e){var r=this[t];if(void 0===r&&void 0!==e)r=e;else{if(void 0===r)throw new Error("KeyError");delete this[t]}return r},popitem:function(){for(var t in this){var e=this[t];return delete this[t],[t,e]}throw new Error("KeyError")},setdefault:function(t,e){return t in this?this[t]:(void 0===e&&(e=null),this[t]=e)},update:function(t){for(var e in t)this[e]=t[e];return null}};o.iteritems=o.items,o.itervalues=o.values,o.iterkeys=o.keys,t.memberLookup=function(t,r,s){return t=t||{},e.isArray(t)&&i.hasOwnProperty(r)?function(){return i[r].apply(t,arguments)}:e.isObject(t)&&o.hasOwnProperty(r)?function(){return o[r].apply(t,arguments)}:n.apply(this,arguments)}}t.exports=r}]);

@@ -0,8 +1,5 @@

'use strict';
var lib = require('./src/lib');
var env = require('./src/environment');
var compiler = require('./src/compiler');
var parser = require('./src/parser');
var lexer = require('./src/lexer');
var runtime = require('./src/runtime');
var Loader = require('./src/loader');

@@ -18,9 +15,13 @@ var loaders = require('./src/loaders');

module.exports.FileSystemLoader = loaders.FileSystemLoader;
module.exports.PrecompiledLoader = loaders.PrecompiledLoader;
module.exports.WebLoader = loaders.WebLoader;
module.exports.compiler = compiler;
module.exports.parser = parser;
module.exports.lexer = lexer;
module.exports.runtime = runtime;
module.exports.compiler = require('./src/compiler');
module.exports.parser = require('./src/parser');
module.exports.lexer = require('./src/lexer');
module.exports.runtime = require('./src/runtime');
module.exports.lib = lib;
module.exports.installJinjaCompat = require('./src/jinja-compat.js');
// A single instance of an environment, since this is so commonly used

@@ -36,6 +37,18 @@

var noWatch = 'watch' in opts ? !opts.watch : false;
var loader = loaders.FileSystemLoader || loaders.WebLoader;
e = new env.Environment(new loader(templatesPath, noWatch), opts);
var TemplateLoader;
if(loaders.FileSystemLoader) {
TemplateLoader = new loaders.FileSystemLoader(templatesPath, {
watch: opts.watch,
noCache: opts.noCache
});
}
else if(loaders.WebLoader) {
TemplateLoader = new loaders.WebLoader(templatesPath, {
useCache: opts.web && opts.web.useCache,
async: opts.web && opts.web.async
});
}
e = new env.Environment(TemplateLoader, opts);
if(opts && opts.express) {

@@ -42,0 +55,0 @@ e.express(opts.express);

@@ -34,8 +34,8 @@

8. Make sure docs are up-to-date. You need to at least copy all the nunjucks*.js files in `browser/` to the [nunjucks-docs repo](https://github.com/mozilla/nunjucks-docs) in the `files` directory. This is where the "download" link points to in the docs. In `nunjucks-docs`, build the docs:
8. Make sure docs are up-to-date. You need to copy all the nunjucks*.js files in `browser/` to the docs. This is where the "download" link points to in the docs. Push (force push if necessary) the build out _site folder onto the `gh-pages` branch of the `nunjucks` repo to get it live.
```
cd path/to/nunjucks-docs && make prod
cp browser/* docs/files
cd docs && make prod
cd _site && git push origin gh-pages (assumes you have setup a git repo in _site pointing to nunjucks)
```
And push (force push if necessary) the build out _site folder onto the `gh-pages` branch of the `nunjucks` repo to get it live.
{
"name": "nunjucks",
"description": "A powerful templating engine with inheritance, asynchronous control, and more (jinja2 inspired)",
"version": "1.3.4",
"author": "James Long <longster@gmail.com>",
"dependencies": {
"optimist": "*",
"chokidar": "~0.12.5"
},
"browser" : "./browser/nunjucks.js",
"devDependencies": {
"expect.js": "*",
"mocha": "*",
"uglify-js": "*",
"express": "4.x",
"supertest": "*",
"istanbul": "0.3.x"
},
"engines": {
"node": "*"
},
"scripts": {
"test": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha -- -b -R tap tests",
"browserfiles": "./bin/bundle browser/nunjucks; SLIM=1 ./bin/bundle browser/nunjucks-slim"
},
"bin": {
"nunjucks-precompile": "./bin/precompile"
},
"main": "index",
"repository": {
"type": "git",
"url": "https://github.com/mozilla/nunjucks.git"
},
"keywords": [
"template",
"templating"
],
"license": [{
"type": "BSD",
"url": "https://github.com/mozilla/nunjucks/blob/master/LICENSE"
}],
"bugs": {
"url": "https://github.com/mozilla/nunjucks/issues"
}
"name": "nunjucks",
"description": "A powerful templating engine with inheritance, asynchronous control, and more (jinja2 inspired)",
"version": "2.0.0",
"author": "James Long <longster@gmail.com>",
"dependencies": {
"asap": "^2.0.3",
"chokidar": "^1.0.0",
"optimist": "*"
},
"browser": "./browser/nunjucks.js",
"devDependencies": {
"expect.js": "*",
"express": "4.x",
"istanbul": "0.3.x",
"jshint": "*",
"mocha": "*",
"node-libs-browser": "^0.4.3",
"supertest": "*",
"uglify-js": "*",
"webpack": "^1.8.11"
},
"engines": {
"node": "*"
},
"scripts": {
"lint": "jshint .",
"test": "jshint . && istanbul cover ./node_modules/mocha/bin/_mocha -- -b -R tap tests",
"browserfiles": "./bin/bundle"
},
"bin": {
"nunjucks-precompile": "./bin/precompile"
},
"main": "index",
"repository": {
"type": "git",
"url": "https://github.com/mozilla/nunjucks.git"
},
"keywords": [
"template",
"templating"
],
"license": "BSD-2-Clause",
"bugs": {
"url": "https://github.com/mozilla/nunjucks/issues"
}
}

@@ -18,5 +18,9 @@ # Nunjucks

## Browser Support
Supported in all modern browsers. For IE8 support, use [es5-shim](https://github.com/es-shims/es5-shim).
## Tests
Run the tests with `make test`.
Run the tests with `npm test`.

@@ -23,0 +27,0 @@ Watch `master` branch's tests running at http://mozilla.github.io/nunjucks/files/tests/browser/.

@@ -7,2 +7,3 @@ 'use strict';

var nodes = require('./nodes');
// jshint -W079
var Object = require('./object');

@@ -32,3 +33,3 @@ var Frame = require('./runtime').Frame;

var Compiler = Object.extend({
init: function(templateName) {
init: function(templateName, throwOnUndefined) {
this.templateName = templateName;

@@ -39,4 +40,5 @@ this.codebuf = [];

this.bufferStack = [];
this.isChild = false;
this.scopeClosers = '';
this.inBlock = false;
this.throwOnUndefined = throwOnUndefined;
},

@@ -133,8 +135,2 @@

_bufferAppend: function(func) {
this.emit(this.buffer + ' += runtime.suppressValue(');
func.call(this);
this.emit(', env.opts.autoescape);\n');
},
_compileChildren: function(node, frame) {

@@ -186,2 +182,3 @@ var children = node.children;

nodes.Add,
nodes.Concat,
nodes.Sub,

@@ -219,7 +216,5 @@ nodes.Mul,

compileCallExtension: function(node, frame, async) {
var name = node.extName;
var args = node.args;
var contentArgs = node.contentArgs;
var autoescape = typeof node.autoescape === 'boolean' ? node.autoescape : true;
var transformedArgs = [];

@@ -303,3 +298,3 @@ if(!async) {

compileLiteral: function(node, frame) {
compileLiteral: function(node) {
if(typeof node.value === 'string') {

@@ -386,2 +381,5 @@ var val = node.value.replace(/\\/g, '\\\\');

compileAdd: binOpEmitter(' + '),
// ensure concatenation instead of addition
// by adding empty string in between
compileConcat: binOpEmitter(' + "" + '),
compileSub: binOpEmitter(' - '),

@@ -438,3 +436,3 @@ compileMul: binOpEmitter(' * '),

this._compileExpression(node.val, frame);
this.emit(', env.opts.autoescape)');
this.emit(')');
},

@@ -472,3 +470,3 @@

// if the lookup fails.
this.emit(', "' + this._getNodeName(node.name).replace(/"/g, '\\"') + '", ');
this.emit(', "' + this._getNodeName(node.name).replace(/"/g, '\\"') + '", context, ');

@@ -543,12 +541,15 @@ this._compileAggregate(node.args, frame, '[', '])');

// We are running this for every var, but it's very
// uncommon to assign to multiple vars anyway
this.emitLine('frame.set("' + name + '", ' + id + ', true);');
// We are running this for every var, but it's very
// uncommon to assign to multiple vars anyway
this.emitLine('if(!frame.parent) {');
this.emitLine('if(frame.topLevel) {');
this.emitLine('context.setVariable("' + name + '", ' + id + ');');
this.emitLine('}');
if(name.charAt(0) !== '_') {
this.emitLine('context.addExport("' + name + '");');
this.emitLine('if(frame.topLevel) {');
this.emitLine('context.addExport("' + name + '", ' + id + ');');
this.emitLine('}');
}
this.emitLine('}');
}, this);

@@ -616,2 +617,3 @@ },

var v;
var i = this.tmpid();

@@ -664,3 +666,3 @@ var len = this.tmpid();

var k = this.tmpid();
var v = this.tmpid();
v = this.tmpid();
frame.set(key.value, k);

@@ -688,3 +690,3 @@ frame.set(val.value, v);

// Generate a typical array iteration
var v = this.tmpid();
v = this.tmpid();
frame.set(node.name.value, v);

@@ -912,3 +914,3 @@

this.emitLine(id + '.getExported(' +
(node.withContext ? 'context.getVariables(), frame.push(), ' : '') +
(node.withContext ? 'context.getVariables(), frame, ' : '') +
this.makeCallback(id));

@@ -936,3 +938,3 @@ this.addScopeLevel();

this.emitLine(importedId + '.getExported(' +
(node.withContext ? 'context.getVariables(), frame.push(), ' : '') +
(node.withContext ? 'context.getVariables(), frame, ' : '') +
this.makeCallback(importedId));

@@ -972,11 +974,25 @@ this.addScopeLevel();

compileBlock: function(node, frame) {
if(!this.isChild) {
var id = this.tmpid();
compileBlock: function(node) {
var id = this.tmpid();
this.emitLine('context.getBlock("' + node.name.value + '")' +
'(env, context, frame, runtime, ' + this.makeCallback(id));
this.emitLine(this.buffer + ' += ' + id + ';');
this.addScopeLevel();
// If we are executing outside a block (creating a top-level
// block), we really don't want to execute its code because it
// will execute twice: once when the child template runs and
// again when the parent template runs. Note that blocks
// within blocks will *always* execute immediately *and*
// wherever else they are invoked (like used in a parent
// template). This may have behavioral differences from jinja
// because blocks can have side effects, but it seems like a
// waste of performance to always execute huge top-level
// blocks twice
if(!this.inBlock) {
this.emit('(parentTemplate ? function(e, c, f, r, cb) { cb(""); } : ');
}
this.emit('context.getBlock("' + node.name.value + '")');
if(!this.inBlock) {
this.emit(')');
}
this.emitLine('(env, context, frame, runtime, ' + this.makeCallback(id));
this.emitLine(this.buffer + ' += ' + id + ';');
this.addScopeLevel();
},

@@ -999,8 +1015,2 @@

compileExtends: function(node, frame) {
if(this.isChild) {
this.fail('compileExtends: cannot extend multiple times',
node.template.lineno,
node.template.colno);
}
var k = this.tmpid();

@@ -1010,4 +1020,9 @@

this._compileExpression(node.template, frame);
this.emitLine(', true, '+this._templateName()+', ' + this.makeCallback('parentTemplate'));
this.emitLine(', true, '+this._templateName()+', ' + this.makeCallback('_parentTemplate'));
// extends is a dynamic tag and can occur within a block like
// `if`, so if this happens we need to capture the parent
// template in the top-level scope
this.emitLine('parentTemplate = _parentTemplate');
this.emitLine('for(var ' + k + ' in parentTemplate.blocks) {');

@@ -1019,3 +1034,2 @@ this.emitLine('context.addBlock(' + k +

this.addScopeLevel();
this.isChild = true;
},

@@ -1033,3 +1047,3 @@

this.emitLine(id + '.render(' +
'context.getVariables(), frame.push(), ' + this.makeCallback(id2));
'context.getVariables(), frame, ' + this.makeCallback(id2));
this.emitLine(this.buffer + ' += ' + id2);

@@ -1057,3 +1071,9 @@ this.addScopeLevel();

this.emit(this.buffer + ' += runtime.suppressValue(');
if(this.throwOnUndefined) {
this.emit('runtime.ensureDefined(');
}
this.compile(children[i], frame);
if(this.throwOnUndefined) {
this.emit(',' + node.lineno + ',' + node.colno + ')');
}
this.emit(', env.opts.autoescape);\n');

@@ -1072,15 +1092,17 @@ }

this.emitFuncBegin('root');
this.emitLine('var parentTemplate = null;');
this._compileChildren(node, frame);
if(this.isChild) {
this.emitLine('parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);');
}
this.emitFuncEnd(this.isChild);
this.emitLine('if(parentTemplate) {');
this.emitLine('parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);');
this.emitLine('} else {');
this.emitLine('cb(null, ' + this.buffer +');');
this.emitLine('}');
this.emitFuncEnd(true);
// When compiling the blocks, they should all act as top-level code
this.isChild = false;
this.inBlock = true;
var blocks = node.findAll(nodes.Block);
for(var i=0; i<blocks.length; i++) {
var block = blocks[i];
var name = block.name.value;
var i, name, block, blocks = node.findAll(nodes.Block);
for (i = 0; i < blocks.length; i++) {
block = blocks[i];
name = block.name.value;

@@ -1095,5 +1117,5 @@ this.emitFuncBegin('b_' + name);

this.emitLine('return {');
for(var i=0; i<blocks.length; i++) {
var block = blocks[i];
var name = 'b_' + block.name.value;
for (i = 0; i < blocks.length; i++) {
block = blocks[i];
name = 'b_' + block.name.value;
this.emitLine(name + ': ' + name + ',');

@@ -1122,3 +1144,5 @@ }

// var c = new Compiler();
// var src = '{% asyncEach i in arr %}{{ i }}{% else %}empty{% endeach %}';
// var src = 'hello {% filter title %}' +
// 'Hello madam how are you' +
// '{% endfilter %}'
// var ast = transformer.transform(parser.parse(src));

@@ -1132,3 +1156,3 @@ // nodes.printNodes(ast);

compile: function(src, asyncFilters, extensions, name, opts) {
var c = new Compiler(name);
var c = new Compiler(name, opts.throwOnUndefined);

@@ -1144,7 +1168,9 @@ // Run the extension preprocessors against the source.

c.compile(transformer.transform(parser.parse(src,
extensions,
opts),
asyncFilters,
name));
c.compile(transformer.transform(
parser.parse(src,
extensions,
opts),
asyncFilters,
name
));
return c.getCode();

@@ -1151,0 +1177,0 @@ },

'use strict';
var path = require('path');
var asap = require('asap');
var lib = require('./lib');
var Obj = require('./object');
var lexer = require('./lexer');
var compiler = require('./compiler');

@@ -13,3 +13,14 @@ var builtin_filters = require('./filters');

var Frame = runtime.Frame;
var Template;
// Unconditionally load in this loader, even if no other ones are
// included (possible in the slim browser build)
builtin_loaders.PrecompiledLoader = require('./precompiled-loader');
// If the user is using the async API, *always* call it
// asynchronously even if the template was synchronous.
function callbackAsap(cb, err, res) {
asap(function() { cb(err, res); });
}
var Environment = Obj.extend({

@@ -23,3 +34,3 @@ init: function(loaders, opts) {

// defaults to false
var opts = this.opts = opts || {};
opts = this.opts = opts || {};
this.opts.dev = !!opts.dev;

@@ -30,15 +41,19 @@

// If false, strings can be manually escaped using the `escape` filter.
// defaults to false
this.opts.autoescape = !!opts.autoescape;
// defaults to true
this.opts.autoescape = opts.autoescape != null ? opts.autoescape : true;
// If true, this will make the system throw errors if trying
// to output a null or undefined value
this.opts.throwOnUndefined = !!opts.throwOnUndefined;
this.opts.trimBlocks = !!opts.trimBlocks;
this.opts.lstripBlocks = !!opts.lstripBlocks;
this.loaders = [];
if(!loaders) {
// The filesystem loader is only available client-side
// The filesystem loader is only available server-side
if(builtin_loaders.FileSystemLoader) {
this.loaders = [new builtin_loaders.FileSystemLoader('views')];
}
else {
else if(builtin_loaders.WebLoader) {
this.loaders = [new builtin_loaders.WebLoader('/views')];

@@ -51,2 +66,11 @@ }

// It's easy to use precompiled templates: just include them
// before you configure nunjucks and this will automatically
// pick it up and use it
if(process.env.IS_BROWSER && window.nunjucksPrecompiled) {
this.loaders.unshift(
new builtin_loaders.PrecompiledLoader(window.nunjucksPrecompiled)
);
}
this.initCache();

@@ -90,2 +114,9 @@ this.filters = {};

getGlobal: function(name) {
if(!globals[name]) {
throw new Error('global not found: ' + name);
}
return globals[name];
},
addFilter: function(name, func, async) {

@@ -154,3 +185,31 @@ var wrapped = func;

var syncResult;
var _this = this;
var createTemplate = function(info) {
if(!info) {
var err = new Error('template not found: ' + name);
if(cb) {
cb(err);
}
else {
throw err;
}
}
else {
var tmpl = new Template(info.src, _this,
info.path, eagerCompile);
if(!info.noCache) {
info.loader.cache[name] = tmpl;
}
if(cb) {
cb(null, tmpl);
}
else {
syncResult = tmpl;
}
}
};
lib.asyncIter(this.loaders, function(loader, i, next, done) {

@@ -179,29 +238,4 @@ function handle(src) {

}
}, function(info) {
if(!info) {
var err = new Error('template not found: ' + name);
if(cb) {
cb(err);
}
else {
throw err;
}
}
else {
var tmpl = new Template(info.src, this,
info.path, eagerCompile);
}, createTemplate);
if(!info.noCache) {
info.loader.cache[name] = tmpl;
}
if(cb) {
cb(null, tmpl);
}
else {
syncResult = tmpl;
}
}
}.bind(this));
return syncResult;

@@ -244,3 +278,3 @@ }

if(err && cb) {
cb(err);
callbackAsap(cb, err);
}

@@ -251,6 +285,3 @@ else if(err) {

else {
tmpl.render(ctx, cb || function(err, res) {
if(err) { throw err; }
syncResult = res;
});
syncResult = tmpl.render(ctx, cb);
}

@@ -276,3 +307,10 @@ });

init: function(ctx, blocks) {
this.ctx = ctx;
// Make a duplicate of ctx
this.ctx = {};
for(var k in ctx) {
if(ctx.hasOwnProperty(k)) {
this.ctx[k] = ctx[k];
}
}
this.blocks = {};

@@ -344,3 +382,3 @@ this.exported = [];

var Template = Obj.extend({
Template = Obj.extend({
init: function (src, env, path, eagerCompile) {

@@ -366,5 +404,9 @@ this.env = env || new Environment();

if(eagerCompile) {
lib.withPrettyErrors(this.path,
this.env.dev,
this._compile.bind(this));
var _this = this;
try {
_this._compile();
}
catch(err) {
throw lib.prettifyError(this.path, this.env.dev, err);
}
}

@@ -376,3 +418,3 @@ else {

render: function(ctx, frame, cb) {
render: function(ctx, parentFrame, cb) {
if (typeof ctx === 'function') {

@@ -382,35 +424,61 @@ cb = ctx;

}
else if (typeof frame === 'function') {
cb = frame;
frame = null;
else if (typeof parentFrame === 'function') {
cb = parentFrame;
parentFrame = null;
}
return lib.withPrettyErrors(this.path, this.env.dev, function() {
var forceAsync = true;
if(parentFrame) {
// If there is a frame, we are being called from internal
// code of another template, and the internal system
// depends on the sync/async nature of the parent template
// to be inherited, so force an async callback
forceAsync = false;
}
// Catch compile errors for async rendering
try {
this.compile();
} catch (e) {
if (cb) return cb(e);
else throw e;
}
var _this = this;
// Catch compile errors for async rendering
try {
_this.compile();
} catch (_err) {
var err = lib.prettifyError(this.path, this.env.dev, _err);
if (cb) return callbackAsap(cb, err);
else throw err;
}
var context = new Context(ctx || {}, this.blocks);
var syncResult = null;
var context = new Context(ctx || {}, _this.blocks);
var frame = parentFrame ? parentFrame.push() : new Frame();
frame.topLevel = true;
var syncResult = null;
this.rootRenderFunc(this.env,
context,
frame || new Frame(),
runtime,
cb || function(err, res) {
if(err) { throw err; }
syncResult = res;
});
_this.rootRenderFunc(
_this.env,
context,
frame || new Frame(),
runtime,
function(err, res) {
if(err) {
err = lib.prettifyError(_this.path, _this.env.dev, err);
}
return syncResult;
}.bind(this));
if(cb) {
if(forceAsync) {
callbackAsap(cb, err, res);
}
else {
cb(err, res);
}
}
else {
if(err) { throw err; }
syncResult = res;
}
}
);
return syncResult;
},
getExported: function(ctx, frame, cb) {
getExported: function(ctx, parentFrame, cb) {
if (typeof ctx === 'function') {

@@ -421,5 +489,5 @@ cb = ctx;

if (typeof frame === 'function') {
cb = frame;
frame = null;
if (typeof parentFrame === 'function') {
cb = parentFrame;
parentFrame = null;
}

@@ -435,2 +503,5 @@

var frame = parentFrame ? parentFrame.push() : new Frame();
frame.topLevel = true;
// Run the rootRenderFunc to populate the context with exported vars

@@ -440,3 +511,3 @@ var context = new Context(ctx || {}, this.blocks);

context,
frame || new Frame(),
frame,
runtime,

@@ -467,2 +538,3 @@ function() {

/* jslint evil: true */
var func = new Function(source);

@@ -490,7 +562,2 @@ props = func();

// test code
// var src = '{% macro foo() %}{% include "include.html" %}{% endmacro %}{{ foo() }}';
// var env = new Environment(new builtin_loaders.FileSystemLoader('../tests/templates', true), { dev: true });
// console.log(env.renderString(src, { name: 'poop' }));
module.exports = {

@@ -497,0 +564,0 @@ Environment: Environment,

@@ -6,2 +6,11 @@ 'use strict';

function normalize(value, defaultValue) {
if(value === null || value === undefined || value === false) {
return defaultValue;
}
return value;
}
var hasWarnedDefault = false;
var filters = {

@@ -13,6 +22,7 @@ abs: function(n) {

batch: function(arr, linecount, fill_with) {
var i;
var res = [];
var tmp = [];
for(var i=0; i<arr.length; i++) {
for(i = 0; i < arr.length; i++) {
if(i % linecount === 0 && tmp.length) {

@@ -28,3 +38,3 @@ res.push(tmp);

if(fill_with) {
for(var i=tmp.length; i<linecount; i++) {
for(i = tmp.length; i < linecount; i++) {
tmp.push(fill_with);

@@ -41,2 +51,3 @@ }

capitalize: function(str) {
str = normalize(str, '');
var ret = str.toLowerCase();

@@ -47,2 +58,3 @@ return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1));

center: function(str, width) {
str = normalize(str, '');
width = width || 80;

@@ -60,4 +72,21 @@

'default': function(val, def) {
return val ? val : def;
'default': function(val, def, bool) {
if(bool !== true && bool !== false && !hasWarnedDefault) {
hasWarnedDefault = true;
console.log(
'[nunjucks] Warning: the "default" filter was used without ' +
'specifying the type of comparison. 2.0 changed the default ' +
'behavior from boolean (val ? val : def) to strictly undefined, ' +
'so you should make sure that doesn\'t break anything. ' +
'Be explicit about this to make this warning go away, or wait until 2.1. ' +
'See http://mozilla.github.io/nunjucks/templating.html#defaultvalue-default-boolean'
);
}
if(bool) {
return val ? val : def;
}
else {
return (val !== undefined) ? val : def;
}
},

@@ -105,2 +134,6 @@

dump: function(obj) {
return JSON.stringify(obj);
},
escape: function(str) {

@@ -127,2 +160,6 @@ if(typeof str === 'string' ||

indent: function(str, width, indentfirst) {
str = normalize(str, '');
if (str === '') return '';
width = width || 4;

@@ -161,4 +198,6 @@ var res = '';

length: function(arr) {
return arr !== undefined ? arr.length : 0;
length: function(val) {
var value = normalize(val, '');
return value !== undefined ? value.length : 0;
},

@@ -196,2 +235,3 @@

lower: function(str) {
str = normalize(str, '');
return str.toLowerCase();

@@ -217,2 +257,4 @@ },

replace: function(str, old, new_, maxCount) {
var originalStr = str;
if (old instanceof RegExp) {

@@ -222,18 +264,64 @@ return str.replace(old, new_);

var res = str;
var last = res;
var count = 1;
res = res.replace(old, new_);
if(typeof maxCount === 'undefined'){
maxCount = -1;
}
while(last !== res) {
if(count >= maxCount) {
break;
}
var res = ''; // Output
last = res;
res = res.replace(old, new_);
// Cast Numbers in the search term to string
if(typeof old === 'number'){
old = old + '';
}
else if(typeof old !== 'string') {
// If it is something other than number or string,
// return the original string
return str;
}
// Cast numbers in the replacement to string
if(typeof str === 'number'){
str = str + '';
}
// If by now, we don't have a string, throw it back
if(typeof str !== 'string' && !(str instanceof r.SafeString)){
return str;
}
// ShortCircuits
if(old === ''){
// Mimic the python behaviour: empty string is replaced
// by replacement e.g. "abc"|replace("", ".") -> .a.b.c.
res = new_ + str.split('').join(new_) + new_;
return r.copySafeness(str, res);
}
var nextIndex = str.indexOf(old);
// if # of replacements to perform is 0, or the string to does
// not contain the old value, return the string
if(maxCount === 0 || nextIndex === -1){
return str;
}
var pos = 0;
var count = 0; // # of replacements made
while(nextIndex > -1 && (maxCount === -1 || count < maxCount)){
// Grab the next chunk of src string and add it with the
// replacement, to the result
res += str.substring(pos, nextIndex) + new_;
// Increment our pointer in the src string
pos = nextIndex + old.length;
count++;
// See if there are any more replacements to be made
nextIndex = str.indexOf(old, pos);
}
return r.copySafeness(str, res);
// We've either reached the end, or done the max # of
// replacements, tack on any remaining string
if(pos < str.length) {
res += str.substring(pos);
}
return r.copySafeness(originalStr, res);
},

@@ -340,2 +428,3 @@

title: function(str) {
str = normalize(str, '');
var words = str.split(' ');

@@ -354,2 +443,3 @@ for(var i = 0; i < words.length; i++) {

var orig = input;
input = normalize(input, '');
length = length || 255;

@@ -376,2 +466,3 @@

upper: function(str) {
str = normalize(str, '');
return str.toUpperCase();

@@ -389,3 +480,3 @@ },

return enc(item[0]) + '=' + enc(item[1]);
})
});
} else {

@@ -423,7 +514,4 @@ parts = [];

var matches = word.match(puncRE);
var possibleUrl = matches && matches[1] || word;
// url that starts with http or https

@@ -453,2 +541,3 @@ if (httpHttpsRE.test(possibleUrl))

wordcount: function(str) {
str = normalize(str, '');
var words = (str) ? str.match(/\w+/g) : null;

@@ -455,0 +544,0 @@ return (words) ? words.length : null;

@@ -65,4 +65,4 @@ 'use strict';

}
}
};
module.exports = globals;

@@ -6,3 +6,3 @@ 'use strict';

var whitespaceChars = ' \n\t\r\u00A0';
var delimChars = '()[]{}%*-+/#,:|.<>=!';
var delimChars = '()[]{}%*-+~/#,:|.<>=!';
var intChars = '0123456789';

@@ -34,2 +34,3 @@

var TOKEN_COLON = 'colon';
var TOKEN_TILDE = 'tilde';
var TOKEN_PIPE = 'pipe';

@@ -174,2 +175,3 @@ var TOKEN_INT = 'int';

case ':': type = TOKEN_COLON; break;
case '~': type = TOKEN_TILDE; break;
case '|': type = TOKEN_PIPE; break;

@@ -301,4 +303,2 @@ default: type = TOKEN_OPERATOR;

var lineno = this.lineno;
var colno = this.colno;
var str = '';

@@ -394,2 +394,14 @@

Tokenizer.prototype._extractRegex = function(regex) {
var matches = this.currentStr().match(regex);
if(!matches) {
return null;
}
// Move forward whatever was matched
this.forwardN(matches[0].length);
return matches;
};
Tokenizer.prototype.is_finished = function() {

@@ -417,2 +429,8 @@ return this.index >= this.len;

Tokenizer.prototype.backN = function(n) {
for(var i=0; i<n; i++) {
this.back();
}
};
Tokenizer.prototype.back = function() {

@@ -437,2 +455,3 @@ this.index--;

// current returns current character
Tokenizer.prototype.current = function() {

@@ -445,2 +464,10 @@ if(!this.is_finished()) {

// currentStr returns what's left of the unparsed string
Tokenizer.prototype.currentStr = function() {
if(!this.is_finished()) {
return this.str.substr(this.index);
}
return '';
};
Tokenizer.prototype.previous = function() {

@@ -472,2 +499,3 @@ return this.str.charAt(this.index-1);

TOKEN_COLON: TOKEN_COLON,
TOKEN_TILDE: TOKEN_TILDE,
TOKEN_PIPE: TOKEN_PIPE,

@@ -474,0 +502,0 @@ TOKEN_INT: TOKEN_INT,

@@ -22,21 +22,19 @@ 'use strict';

exports.withPrettyErrors = function(path, withInternals, func) {
try {
return func();
} catch (e) {
if (!e.Update) {
// not one of ours, cast it
e = new exports.TemplateError(e);
}
e.Update(path);
exports.prettifyError = function(path, withInternals, err) {
// jshint -W022
// http://jslinterrors.com/do-not-assign-to-the-exception-parameter
if (!err.Update) {
// not one of ours, cast it
err = new exports.TemplateError(err);
}
err.Update(path);
// Unless they marked the dev flag, show them a trace from here
if (!withInternals) {
var old = e;
e = new Error(old.message);
e.name = old.name;
}
// Unless they marked the dev flag, show them a trace from here
if (!withInternals) {
var old = err;
err = new Error(old.message);
err.name = old.name;
}
throw e;
}
return err;
};

@@ -280,2 +278,2 @@

}
}
};

@@ -1,6 +0,3 @@

if(typeof window === 'undefined' || window !== this) {
module.exports = require('./node-loaders');
}
else {
module.exports = require('./web-loaders');
}
// This file will automatically be rewired to web-loader.js when
// building for the browser
module.exports = require('./node-loaders');

@@ -8,2 +8,3 @@ 'use strict';

var chokidar = require('chokidar');
var PrecompiledLoader = require('./precompiled-loader.js');

@@ -14,5 +15,14 @@ // Node <0.7.1 compatibility

var FileSystemLoader = Loader.extend({
init: function(searchPaths, noWatch, noCache) {
init: function(searchPaths, opts) {
if(typeof opts === 'boolean') {
console.log(
'[nunjucks] Warning: you passed a boolean as the second ' +
'argument to FileSystemLoader, but it now takes an options ' +
'object. See http://mozilla.github.io/nunjucks/api.html#filesystemloader'
);
}
opts = opts || {};
this.pathsToNames = {};
this.noCache = !!noCache;
this.noCache = !!opts.noCache;

@@ -28,6 +38,7 @@ if(searchPaths) {

if(!noWatch) {
if(opts.watch) {
var _this = this;
// Watch all the templates in the paths and fire an event when
// they change
lib.each(this.searchPaths, function(p) {
lib.each(_this.searchPaths, function(p) {
if(existsSync(p)) {

@@ -38,8 +49,8 @@ var watcher = chokidar.watch(p);

fullname = path.resolve(fullname);
if(event === 'change' && fullname in this.pathsToNames) {
this.emit('update', this.pathsToNames[fullname]);
if(event === 'change' && fullname in _this.pathsToNames) {
_this.emit('update', _this.pathsToNames[fullname]);
}
}.bind(this));
});
}
}.bind(this));
});
}

@@ -76,5 +87,5 @@ },

module.exports = {
FileSystemLoader: FileSystemLoader
FileSystemLoader: FileSystemLoader,
PrecompiledLoader: PrecompiledLoader
};
'use strict';
var util = require('util');
var lib = require('./lib');
// jshint -W079
var Object = require('./object');

@@ -23,3 +23,3 @@

var fields = this.fields;
for(var i=0, l=fields.length; i<l; i++) {
for(var i = 0, l = fields.length; i < l; i++) {
var field = fields[i];

@@ -43,6 +43,7 @@

var i, l;
if(this instanceof NodeList) {
var children = this.children;
for(var i=0, l=children.length; i<l; i++) {
for(i = 0, l = children.length; i < l; i++) {
traverseAndCheck(children[i], type, results);

@@ -54,3 +55,3 @@ }

for(var i=0, l=fields.length; i<l; i++) {
for(i = 0, l = fields.length; i < l; i++) {
traverseAndCheck(this[fields[i]], type, results);

@@ -133,2 +134,3 @@ }

var Add = BinOp.extend('Add');
var Concat = BinOp.extend('Concat');
var Sub = BinOp.extend('Sub');

@@ -147,10 +149,2 @@ var Mul = BinOp.extend('Mul');

var CustomTag = Node.extend('CustomTag', {
init: function(lineno, colno, name) {
this.lineno = lineno;
this.colno = colno;
this.name = name;
}
});
var CallExtension = Node.extend('CallExtension', {

@@ -182,3 +176,3 @@ fields: ['extName', 'prop', 'args', 'contentArgs'],

for(var j=0; j<indent; j++) {
util.print(' ');
process.stdout.write(' ');
}

@@ -189,6 +183,6 @@ }

if(i === lines.length-1) {
util.print(lines[i]);
process.stdout.write(lines[i]);
}
else {
util.puts(lines[i]);
process.stdout.write(lines[i] + '\n');
}

@@ -236,3 +230,3 @@ }

if(props) {
print(util.inspect(props, true, null) + '\n', null, true);
print(JSON.stringify(props, null, 2) + '\n', null, true);
}

@@ -299,2 +293,3 @@ else {

Add: Add,
Concat: Concat,
Sub: Sub,

@@ -301,0 +296,0 @@ Mul: Mul,

@@ -11,2 +11,3 @@ 'use strict';

// jshint undef: false
var fnTest = /xyz/.test(function(){ xyz; }) ? /\bparent\b/ : /.*/;

@@ -22,2 +23,3 @@ props = props || {};

fnTest.test(src)) {
/*jshint -W083 */
prototype[k] = (function (src, parent) {

@@ -24,0 +26,0 @@ return function() {

@@ -5,2 +5,3 @@ 'use strict';

var nodes = require('./nodes');
// jshint -W079
var Object = require('./object');

@@ -96,6 +97,2 @@ var lib = require('./lib');

skipWhitespace: function () {
return this.skip(lexer.TOKEN_WHITESPACE);
},
skipSymbol: function(val) {

@@ -106,4 +103,5 @@ return this.skipValue(lexer.TOKEN_SYMBOL, val);

advanceAfterBlockEnd: function(name) {
var tok;
if(!name) {
var tok = this.peekToken();
tok = this.peekToken();

@@ -122,3 +120,3 @@ if(!tok) {

var tok = this.nextToken();
tok = this.nextToken();

@@ -133,2 +131,4 @@ if(tok && tok.type === lexer.TOKEN_BLOCK_END) {

}
return tok;
},

@@ -417,3 +417,3 @@

parseTemplateRef: function(tagName, nodeType) {
parseTemplateRef: function(tagName, NodeType) {
var tag = this.peekToken();

@@ -424,3 +424,3 @@ if(!this.skipSymbol(tagName)) {

var node = new nodeType(tag.lineno, tag.colno);
var node = new NodeType(tag.lineno, tag.colno);
node.template = this.parseExpression();

@@ -542,2 +542,3 @@

case 'from': return this.parseFrom();
case 'filter': return this.parseFilterStatement();
default:

@@ -559,50 +560,38 @@ if (this.extensions.length) {

parseRaw: function() {
this.advanceAfterBlockEnd();
var blockRegex = /([\s\S]*){%\s*(.*?)\s*(?=%})%}/;
var rawLevel = 1;
var str = '';
var begun = this.peekToken();
var matches = null;
while(1) {
// Passing true gives us all the whitespace tokens as
// well, which are usually ignored.
var tok = this.nextToken(true);
// Skip opening raw token
// Keep this token to track line and column numbers
var begun = this.advanceAfterBlockEnd();
if(!tok) {
this.fail('expected endraw, got end of file');
}
// Exit when there's nothing to match
// or when we've found the matching "endraw" block
while((matches = this.tokens._extractRegex(blockRegex)) && rawLevel > 0) {
var all = matches[0];
var pre = matches[1];
var blockName = matches[2];
if(tok.type === lexer.TOKEN_BLOCK_START) {
// We need to look for the `endraw` block statement,
// which involves a lookahead so carefully keep track
// of whitespace
var ws = null;
var name = this.nextToken(true);
// Adjust rawlevel
if(blockName === 'raw') {
if(name.type === lexer.TOKEN_WHITESPACE) {
ws = name;
name = this.nextToken();
}
rawLevel += 1;
} else if(blockName === 'endraw') {
rawLevel -= 1;
}
if(name.type === lexer.TOKEN_SYMBOL &&
name.value === 'endraw') {
this.advanceAfterBlockEnd(name.value);
break;
}
else {
str += tok.value;
if(ws) {
str += ws.value;
}
str += name.value;
}
// Add to str
if(rawLevel === 0) {
// We want to exclude the last "endraw"
str += pre;
// Move tokenizer to beginning of endraw block
this.tokens.backN(all.length - pre.length);
} else {
str += all;
}
else if(tok.type === lexer.TOKEN_STRING) {
str += '"' + tok.value + '"';
}
else {
str += tok.value;
}
}
var output = new nodes.Output(
return new nodes.Output(
begun.lineno,

@@ -612,8 +601,6 @@ begun.colno,

);
return output;
},
parsePostfix: function(node) {
var tok = this.peekToken();
var lookup, tok = this.peekToken();

@@ -630,3 +617,3 @@ while(tok) {

// Reference
var lookup = this.parseAggregate();
lookup = this.parseAggregate();
if(lookup.children.length > 1) {

@@ -654,3 +641,3 @@ this.fail('invalid index');

// reference
var lookup = new nodes.Literal(val.lineno,
lookup = new nodes.Literal(val.lineno,
val.colno,

@@ -763,3 +750,3 @@ val.value);

var compareOps = ['==', '!=', '<', '>', '<=', '>='];
var expr = this.parseAdd();
var expr = this.parseConcat();
var ops = [];

@@ -776,3 +763,3 @@

tok.colno,
this.parseAdd(),
this.parseConcat(),
tok.value));

@@ -797,2 +784,15 @@ }

// finds the '~' for string concatenation
parseConcat: function(){
var node = this.parseAdd();
while(this.skipValue(lexer.TOKEN_TILDE, '~')) {
var node2 = this.parseAdd();
node = new nodes.Concat(node.lineno,
node.colno,
node,
node2);
}
return node;
},
parseAdd: function() {

@@ -968,29 +968,37 @@ var node = this.parseSub();

parseFilterName: function() {
var tok = this.expect(lexer.TOKEN_SYMBOL);
var name = tok.value;
while(this.skipValue(lexer.TOKEN_OPERATOR, '.')) {
name += '.' + this.expect(lexer.TOKEN_SYMBOL).value;
}
return new nodes.Symbol(tok.lineno, tok.colno, name);
},
parseFilterArgs: function(node) {
if(this.peekToken().type === lexer.TOKEN_LEFT_PAREN) {
// Get a FunCall node and add the parameters to the
// filter
var call = this.parsePostfix(node);
return call.args.children;
}
return [];
},
parseFilter: function(node) {
while(this.skip(lexer.TOKEN_PIPE)) {
var tok = this.expect(lexer.TOKEN_SYMBOL);
var name = tok.value;
var name = this.parseFilterName();
while(this.skipValue(lexer.TOKEN_OPERATOR, '.')) {
name += '.' + this.expect(lexer.TOKEN_SYMBOL).value;
}
node = new nodes.Filter(
tok.lineno,
tok.colno,
new nodes.Symbol(tok.lineno,
tok.colno,
name),
name.lineno,
name.colno,
name,
new nodes.NodeList(
tok.lineno,
tok.colno,
[node])
name.lineno,
name.colno,
[node].concat(this.parseFilterArgs(node))
)
);
if(this.peekToken().type === lexer.TOKEN_LEFT_PAREN) {
// Get a FunCall node and add the parameters to the
// filter
var call = this.parsePostfix(node);
node.args.children = node.args.children.concat(call.args.children);
}
}

@@ -1001,2 +1009,35 @@

parseFilterStatement: function() {
var filterTok = this.peekToken();
if(!this.skipSymbol('filter')) {
this.fail('parseFilterStatement: expected filter');
}
var name = this.parseFilterName();
var args = this.parseFilterArgs(name);
this.advanceAfterBlockEnd(filterTok.value);
var body = this.parseUntilBlocks('endfilter');
this.advanceAfterBlockEnd();
var node = new nodes.Filter(
name.lineno,
name.colno,
name,
new nodes.NodeList(
name.lineno,
name.colno,
// Body is a NodeList with an Output node as a child,
// need to strip those
body.children[0].children.concat(args)
)
);
return new nodes.Output(
name.lineno,
name.colno,
[node]
);
},
parseAggregate: function() {

@@ -1080,3 +1121,2 @@ var tok = this.nextToken();

var kwargs = new nodes.KeywordArgs(tok.lineno, tok.colno);
var kwnames = [];
var checkComma = false;

@@ -1207,3 +1247,5 @@

// var p = new Parser(lexer.lex('{% if not x %}foo{% endif %}'));
// var p = new Parser(lexer.lex('hello {% filter title %}' +
// 'Hello madam how are you' +
// '{% endfilter %}'));
// var n = p.parseAsRoot();

@@ -1210,0 +1252,0 @@ // nodes.printNodes(n);

@@ -8,2 +8,3 @@ 'use strict';

var Environment = require('./environment').Environment;
var precompileGlobal = require('./precompile-global');

@@ -33,10 +34,13 @@ function match(filename, patterns) {

// * exclude: which file/folders to exclude (folders are auto-included, files are auto-excluded)
// * wrapper: function(name, template, opts) {...}
// Customize the output format to store the compiled template.
// By default, templates are stored in a global variable used by the runtime.
// A custom loader will be necessary to load your custom wrapper.
opts = opts || {};
var env = opts.env || new Environment([]);
var asyncFilters = env.asyncFilters;
var extensions = env.extensionsList;
var wrapper = opts.wrapper || precompileGlobal;
var pathStats = fs.existsSync(input) && fs.statSync(input);
var output = '';
var precompiled = [];
var templates = [];

@@ -70,12 +74,14 @@

return _precompile(input,
opts.name,
env,
opts.asFunction);
precompiled.push( _precompile(
input,
opts.name,
env
) );
}
else if(pathStats.isFile()) {
return _precompile(fs.readFileSync(input, 'utf-8'),
opts.name || input,
env,
opts.asFunction);
precompiled.push( _precompile(
fs.readFileSync(input, 'utf-8'),
opts.name || input,
env
) );
}

@@ -89,6 +95,7 @@ else if(pathStats.isDirectory()) {

try {
output += _precompile(fs.readFileSync(templates[i], 'utf-8'),
name,
env,
opts.asFunction);
precompiled.push( _precompile(
fs.readFileSync(templates[i], 'utf-8'),
name,
env
) );
} catch(e) {

@@ -105,8 +112,8 @@ if(opts.force) {

}
}
return output;
}
return wrapper(precompiled, opts);
}
function _precompile(str, name, env, asFunction) {
function _precompile(str, name, env) {
env = env || new Environment([]);

@@ -116,25 +123,16 @@

var extensions = env.extensionsList;
var template;
var out = '(function() {' +
'(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})' +
'["' + name.replace(/\\/g, '/') + '"] = (function() {';
out += lib.withPrettyErrors(
name,
false,
function() {
return compiler.compile(str,
try {
template = compiler.compile(str,
asyncFilters,
extensions,
name);
}
);
out += '})();\n';
if(asFunction) {
out += 'return function(ctx, cb) { return nunjucks.render("' + name + '", ctx, cb); }';
name,
env.opts);
}
catch(err) {
throw lib.prettifyError(name, false, err);
}
out += '})();\n';
return out;
return { name: name, template: template };
}

@@ -145,2 +143,2 @@

precompileString: precompileString
}
};

@@ -13,2 +13,3 @@ 'use strict';

this.parent = parent;
this.topLevel = false;
},

@@ -83,2 +84,3 @@

var kwargs = getKeywordArgs(arguments);
var i;

@@ -91,3 +93,3 @@ if(argCount > argNames.length) {

var vals = Array.prototype.slice.call(arguments, args.length, argCount);
for(var i=0; i<vals.length; i++) {
for(i = 0; i < vals.length; i++) {
if(i < kwargNames.length) {

@@ -103,3 +105,3 @@ kwargs[kwargNames[i]] = vals[i];

for(var i=argCount; i<argNames.length; i++) {
for(i = argCount; i < argNames.length; i++) {
var arg = argNames[i];

@@ -164,5 +166,8 @@

this.val = val;
this.length = val.length;
}
SafeString.prototype = Object.create(String.prototype);
SafeString.prototype = Object.create(String.prototype, {
length: { writable: true, configurable: true, value: 0 }
});
SafeString.prototype.valueOf = function() {

@@ -214,2 +219,13 @@ return this.val;

function ensureDefined(val, lineno, colno) {
if(val === null || val === undefined) {
throw new lib.TemplateError(
'attempted to output null or undefined value',
lineno + 1,
colno + 1
);
}
return val;
}
function memberLookup(obj, val) {

@@ -227,3 +243,3 @@ obj = obj || {};

function callWrap(obj, name, args) {
function callWrap(obj, name, context, args) {
if(!obj) {

@@ -236,3 +252,4 @@ throw new Error('Unable to call `' + name + '`, which is undefined or falsey');

return obj.apply(this, args);
// jshint validthis: true
return obj.apply(context, args);
}

@@ -280,3 +297,3 @@

var finished = 0;
var len;
var len, i;
var outputArr;

@@ -301,3 +318,3 @@

else {
for(var i=0; i<arr.length; i++) {
for(i = 0; i < arr.length; i++) {
var item = arr[i];

@@ -311,2 +328,3 @@

item.push(i, done);
// jshint validthis: true
func.apply(this, item);

@@ -326,3 +344,3 @@ }

else {
for(var i=0; i<keys.length; i++) {
for(i = 0; i < keys.length; i++) {
var k = keys[i];

@@ -341,2 +359,3 @@ func(k, arr[k], i, len, done);

suppressValue: suppressValue,
ensureDefined: ensureDefined,
memberLookup: memberLookup,

@@ -343,0 +362,0 @@ contextOrFrameLookup: contextOrFrameLookup,

@@ -140,2 +140,5 @@ 'use strict';

}
else if(node instanceof nodes.Set) {
return _liftFilters(node, asyncFilters, 'value');
}
else if(node instanceof nodes.For) {

@@ -191,3 +194,4 @@ return _liftFilters(node, asyncFilters, 'arr');

node instanceof nodes.AsyncAll ||
node instanceof nodes.CallExtensionAsync) {
node instanceof nodes.CallExtensionAsync ||
node instanceof nodes.Include) {
async = true;

@@ -227,3 +231,3 @@ // Stop iterating by returning the node

function transform(ast, asyncFilters, name) {
function transform(ast, asyncFilters) {
return cps(ast, asyncFilters || []);

@@ -230,0 +234,0 @@ }

'use strict';
var Loader = require('./loader');
var PrecompiledLoader = require('./precompiled-loader.js');
var WebLoader = Loader.extend({
init: function(baseURL, neverUpdate) {
// It's easy to use precompiled templates: just include them
// before you configure nunjucks and this will automatically
// pick it up and use it
this.precompiled = window.nunjucksPrecompiled || {};
init: function(baseURL, opts) {
this.baseURL = baseURL || '.';
this.baseURL = baseURL || '';
this.neverUpdate = neverUpdate;
// By default, the cache is turned off because there's no way
// to "watch" templates over HTTP, so they are re-downloaded
// and compiled each time. (Remember, PRECOMPILE YOUR
// TEMPLATES in production!)
this.useCache = opts.useCache;
// We default `async` to false so that the simple synchronous
// API can be used when you aren't doing anything async in
// your templates (which is most of the time). This performs a
// sync ajax request, but that's ok because it should *only*
// happen in development. PRECOMPILE YOUR TEMPLATES.
this.async = opts.async;
},
getSource: function(name) {
if(this.precompiled[name]) {
return {
src: { type: 'code',
obj: this.precompiled[name] },
path: name
};
}
else {
var src = this.fetch(this.baseURL + '/' + name);
if(!src) {
return null;
resolve: function(from, to) { // jshint ignore:line
throw new Error('relative templates not support in the browser yet');
},
getSource: function(name, cb) {
var useCache = this.useCache;
var result;
this.fetch(this.baseURL + '/' + name, function(err, src) {
if(err) {
if(!cb) {
throw err;
}
cb(err);
}
else {
result = { src: src,
path: name,
noCache: !useCache };
if(cb) {
cb(null, result);
}
}
});
return { src: src,
path: name,
noCache: !this.neverUpdate };
}
// if this WebLoader isn't running asynchronously, the
// fetch above would actually run sync and we'll have a
// result here
return result;
},
fetch: function(url, callback) {
fetch: function(url, cb) {
// Only in the browser please
var ajax;
var loading = true;
var src;

@@ -46,2 +63,3 @@ if(window.XMLHttpRequest) { // Mozilla, Safari, ...

else if(window.ActiveXObject) { // IE 8 and older
/* global ActiveXObject */
ajax = new ActiveXObject('Microsoft.XMLHTTP');

@@ -51,5 +69,10 @@ }

ajax.onreadystatechange = function() {
if(ajax.readyState === 4 && (ajax.status === 0 || ajax.status === 200) && loading) {
if(ajax.readyState === 4 && loading) {
loading = false;
src = ajax.responseText;
if(ajax.status === 0 || ajax.status === 200) {
cb(null, ajax.responseText);
}
else {
cb(ajax.responseText);
}
}

@@ -61,8 +84,4 @@ };

// Synchronous because this API shouldn't be used in
// production (pre-load compiled templates instead)
ajax.open('GET', url, false);
ajax.open('GET', url, this.async);
ajax.send();
return src;
}

@@ -72,3 +91,4 @@ });

module.exports = {
WebLoader: WebLoader
WebLoader: WebLoader,
PrecompiledLoader: PrecompiledLoader
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc