Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

regenerate browserfiles

  • Loading branch information...
commit 814ddc2c5f6da0197cca0dcb4f1cb5c2e0860ed8 1 parent 7023c6e
@jlongster authored
View
2  Makefile
@@ -5,4 +5,4 @@ test:
browserfiles:
./bin/bundle browser/nunjucks-dev.js
SLIM=1 ./bin/bundle browser/nunjucks.js
- cd browser && uglifyjs nunjucks.js > nunjucks-min.js
+ cd browser && ../node_modules/.bin/uglifyjs nunjucks.js > nunjucks-min.js
View
314 browser/nunjucks-dev.js
@@ -65,29 +65,55 @@ var ObjProto = Object.prototype;
var exports = modules['lib'] = {};
+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);
+
+ // 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;
+ }
+
+ throw e;
+ }
+}
+
exports.TemplateError = function(message, lineno, colno) {
- var self = this;
+ var err = this;
if (message instanceof Error) { // for casting regular js errors
- self = message;
+ err = message;
message = message.name + ": " + message.message;
} else {
- Error.captureStackTrace(self);
+ Error.captureStackTrace(err);
}
- self.name = "Template render error";
- self.message = message;
- self.lineno = lineno;
- self.colno = colno;
- self.firstUpdate = true;
+ err.name = "Template render error";
+ err.message = message;
+ err.lineno = lineno;
+ err.colno = colno;
+ err.firstUpdate = true;
- self.Update = function(path) {
+ err.Update = function(path) {
var message = "(" + (path || "unknown path") + ")";
// only show lineno + colno next to path of template
// where error occurred
- if (this.firstUpdate && this.lineno && this.colno) {
- message += ' [Line ' + this.lineno + ', Column ' + this.colno + ']';
+ 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 ';
@@ -99,10 +125,11 @@ exports.TemplateError = function(message, lineno, colno) {
this.firstUpdate = false;
return this;
};
- return self;
+
+ return err;
};
-exports.TemplateError.prototype = Error.prototype;
+exports.TemplateError.prototype = Error.prototype;
exports.isFunction = function(obj) {
return ObjProto.toString.call(obj) == '[object Function]';
@@ -445,10 +472,9 @@ modules['nodes'] = {
CompareOperand: CompareOperand,
printNodes: printNodes
-};
-})();
+};})();
(function() {
-
+var lib = modules["lib"];
var Object = modules["object"];
// Frames keep track of scoping both at compile-time and run-time so
@@ -588,6 +614,15 @@ function contextOrFrameLookup(context, frame, name) {
frame.lookup(name);
}
+function handleError(error, lineno, colno) {
+ if(error.lineno) {
+ throw error;
+ }
+ else {
+ throw new lib.TemplateError(error, lineno, colno);
+ }
+}
+
modules['runtime'] = {
Frame: Frame,
makeMacro: makeMacro,
@@ -595,7 +630,9 @@ modules['runtime'] = {
numArgs: numArgs,
suppressValue: suppressValue,
suppressLookupValue: suppressLookupValue,
- contextOrFrameLookup: contextOrFrameLookup
+ contextOrFrameLookup: contextOrFrameLookup,
+ handleError: handleError,
+ isArray: lib.isArray
};
})();
(function() {
@@ -675,7 +712,8 @@ Tokenizer.prototype.nextToken = function() {
// We hit some whitespace
return token(TOKEN_WHITESPACE, tok, lineno, colno);
}
- else if((tok = this._extractString(BLOCK_END))) {
+ else if((tok = this._extractString(BLOCK_END)) ||
+ (tok = this._extractString('-' + BLOCK_END))) {
// Special check for the block end tag
//
// It is a requirement that start and end tags are composed of
@@ -756,7 +794,8 @@ Tokenizer.prototype.nextToken = function() {
if(this.is_finished()) {
return null;
}
- else if((tok = this._extractString(BLOCK_START))) {
+ else if((tok = this._extractString(BLOCK_START + '-')) ||
+ (tok = this._extractString(BLOCK_START))) {
this.in_code = true;
return token(TOKEN_BLOCK_START, tok, lineno, colno);
}
@@ -1023,6 +1062,7 @@ var Parser = Object.extend({
this.tokens = tokens;
this.peeked = null;
this.breakOnBlocks = null;
+ this.dropLeadingWhitespace = false;
},
nextToken: function (withWhitespace) {
@@ -1126,7 +1166,14 @@ var Parser = Object.extend({
name = this.nextToken().value;
}
- if(!this.skip(lexer.TOKEN_BLOCK_END)) {
+ var tok = this.nextToken();
+
+ if(tok.type == lexer.TOKEN_BLOCK_END) {
+ if(tok.value.charAt(0) === '-') {
+ this.dropLeadingWhitespace = true;
+ }
+ }
+ else {
this.fail("expected block end in " + name + " statement");
}
},
@@ -1151,12 +1198,17 @@ var Parser = Object.extend({
this.fail('parseFor: variable name expected for loop');
}
- if(this.skip(lexer.TOKEN_COMMA)) {
+ var type = this.peekToken().type;
+ if(type == lexer.TOKEN_COMMA) {
// key/value iteration
var key = node.name;
node.name = new nodes.Array(key.lineno, key.colno);
node.name.addChild(key);
- node.name.addChild(this.parsePrimary());
+
+ while(this.skip(lexer.TOKEN_COMMA)) {
+ var prim = this.parsePrimary();
+ node.name.addChild(prim);
+ }
}
if(!this.skipSymbol('in')) {
@@ -1241,14 +1293,21 @@ var Parser = Object.extend({
var names = node.names;
while(1) {
- var type = this.peekToken().type;
- if(type == lexer.TOKEN_BLOCK_END) {
+ var nextTok = this.peekToken();
+ if(nextTok.type == lexer.TOKEN_BLOCK_END) {
if(!names.children.length) {
this.fail('parseFrom: Expected at least one import name',
fromTok.lineno,
fromTok.colno);
}
+ // Since we are manually advancing past the block end,
+ // need to keep track of whitespace control (normally
+ // this is done in `advanceAfterBlockEnd`
+ if(nextTok.value.charAt(0) == '-') {
+ this.dropLeadingWhitespace = true;
+ }
+
this.nextToken();
break;
}
@@ -1939,11 +1998,32 @@ var Parser = Object.extend({
while((tok = this.nextToken())) {
if(tok.type == lexer.TOKEN_DATA) {
+ var data = tok.value;
+ var nextToken = this.peekToken();
+ var nextVal = nextToken && nextToken.value;
+
+ // If the last token has "-" we need to trim the
+ // leading whitespace of the data. This is marked with
+ // the `dropLeadingWhitespace` variable.
+ if(this.dropLeadingWhitespace) {
+ // TODO: this could be optimized (don't use regex)
+ data = data.replace(/^\s*/, '');
+ this.dropLeadingWhitespace = false;
+ }
+
+ // Same for the succeding block start token
+ if(nextToken &&
+ nextToken.type == lexer.TOKEN_BLOCK_START &&
+ nextVal.charAt(nextVal.length - 1) == '-') {
+ // TODO: this could be optimized (don't use regex)
+ data = data.replace(/\s*$/, '');
+ }
+
buf.push(new nodes.Output(tok.lineno,
tok.colno,
[new nodes.TemplateData(tok.lineno,
tok.colno,
- tok.value)]));
+ data)]));
}
else if(tok.type == lexer.TOKEN_BLOCK_START) {
var n = this.parseStatement();
@@ -1976,15 +2056,15 @@ var Parser = Object.extend({
}
});
-var util = modules["util"];
+// var util = modules["util"];
-// var l = lexer.lex('{% set x = 3 %}');
+// var l = lexer.lex('{%- if x -%}\n hello {% endif %}');
// var t;
// while((t = l.nextToken())) {
// console.log(util.inspect(t));
// }
-// var p = new Parser(lexer.lex('{% raw %}hello{% endraw %}'));
+// var p = new Parser(lexer.lex('{% from x import y -%}\n hi \n'));
// var n = p.parse();
// nodes.printNodes(n);
@@ -2061,7 +2141,10 @@ var Compiler = Object.extend({
emitFuncBegin: function(name) {
this.buffer = 'output';
this.emitLine('function ' + name + '(env, context, frame, runtime) {');
+ this.emitLine('var lineno = null;');
+ this.emitLine('var colno = null;');
this.emitLine('var ' + this.buffer + ' = "";');
+ this.emitLine('try {');
},
emitFuncEnd: function(noReturn) {
@@ -2069,6 +2152,9 @@ var Compiler = Object.extend({
this.emitLine('return ' + this.buffer + ';');
}
+ this.emitLine('} catch (e) {');
+ this.emitLine(' runtime.handleError(e, lineno, colno);');
+ this.emitLine('}');
this.emitLine('}');
this.buffer = null;
},
@@ -2172,9 +2258,8 @@ var Compiler = Object.extend({
this.emit(v);
}
else {
- this.emit('runtime.suppressValue(' +
- 'runtime.contextOrFrameLookup(' +
- 'context, frame, "' + name + '"))');
+ this.emit('runtime.contextOrFrameLookup(' +
+ 'context, frame, "' + name + '")');
}
},
@@ -2267,10 +2352,20 @@ var Compiler = Object.extend({
},
compileFunCall: function(node, frame) {
+ // Keep track of line/col info at runtime by settings
+ // variables within an expression. An expression in javascript
+ // like (x, y, z) returns the last value, and x and y can be
+ // anything
+ this.emit('(lineno = ' + node.lineno +
+ ', colno = ' + node.colno + ', ');
+
this.emit('(');
this._compileExpression(node.name, frame);
this.emit(')');
+
this._compileAggregate(node.args, frame, '(', ')');
+
+ this.emit(')');
},
compileFilter: function(node, frame) {
@@ -2341,7 +2436,45 @@ var Compiler = Object.extend({
this.emitLine(';');
if(node.name instanceof nodes.Array) {
- // key/value iteration
+ // key/value iteration. the user could have passed a dict
+ // amd two elements to be unpacked - "for k,v in { a: b }"
+ // or they could have passed an array of arrays -
+ // for a,b,c in [[a,b,c],[c,d,e]] where the number of
+ // elements to be unpacked is variable.
+ //
+ // we cant known in advance which has been passed so we
+ // have to emit code that handles both cases
+ this.emitLine('var ' + i + ';');
+
+ // did they pass an array of tuples or a dict?
+ this.emitLine('if (runtime.isArray(' + arr + ')) {');
+
+ // array of tuples
+ this.emitLine('for (' + i + '=0; ' + i + ' < ' + arr + '.length; '
+ + i + '++) {');
+
+ // create one frame var for each element in the unpacking expr
+ for (var u=0; u < node.name.children.length; u++) {
+ var tid = this.tmpid();
+ this.emitLine('var ' + tid + ' = ' + arr + '[' + i + '][' + u + ']');
+ this.emitLine('frame.set("' + node.name.children[u].value
+ + '", ' + arr + '[' + i + '][' + u + ']' + ');');
+ frame.set(node.name.children[u].value, tid);
+ }
+
+ this.emitLine('frame.set("loop.index", ' + i + ' + 1);');
+ this.emitLine('frame.set("loop.index0", ' + i + ');');
+ this.emitLine('frame.set("loop.first", ' + i + ' === 0);');
+
+ this.compile(node.body, frame);
+
+ this.emitLine('}'); // end for
+
+ this.emitLine('} else {');
+
+ // caller passed a dict
+ this.emitLine(i + ' = -1;');
+
var key = node.name.children[0];
var val = node.name.children[1];
var k = this.tmpid();
@@ -2350,7 +2483,6 @@ var Compiler = Object.extend({
frame.set(key.value, k);
frame.set(val.value, v);
- this.emitLine('var ' + i + ' = -1;');
this.emitLine('for(var ' + k + ' in ' + arr + ') {');
this.emitLine(i + '++;');
this.emitLine('var ' + v + ' = ' + arr + '[' + k + '];');
@@ -2359,6 +2491,11 @@ var Compiler = Object.extend({
this.emitLine('frame.set("loop.index", ' + i + ' + 1);');
this.emitLine('frame.set("loop.index0", ' + i + ');');
this.emitLine('frame.set("loop.first", ' + i + ' === 0);');
+ this.compile(node.body, frame);
+
+ this.emitLine('}'); // end for
+
+ this.emitLine('}'); // end if
}
else {
var v = this.tmpid();
@@ -2377,10 +2514,12 @@ var Compiler = Object.extend({
this.emitLine('frame.set("loop.first", ' + i + ' === 0);');
this.emitLine('frame.set("loop.last", ' + i + ' === ' + arr + '.length - 1);');
this.emitLine('frame.set("loop.length", ' + arr + '.length);');
+
+ this.compile(node.body, frame);
+
+ this.emitLine('}');
}
- this.compile(node.body, frame);
- this.emitLine('}');
this.emitLine('frame = frame.pop();');
},
@@ -2577,9 +2716,9 @@ var Compiler = Object.extend({
},
compileOutput: function(node, frame) {
- this.emit(this.buffer + ' += ');
+ this.emit(this.buffer + ' += runtime.suppressValue(');
this._compileChildren(node, frame);
- this.emit(';\n');
+ this.emit(');\n');
},
compileRoot: function(node, frame) {
@@ -2606,12 +2745,12 @@ var Compiler = Object.extend({
this.emitLine('var l_super = context.getSuper(env, ' +
'"' + name + '", ' +
'b_' + name + ', ' +
+ 'frame, ' +
'runtime);');
var tmpFrame = new Frame();
tmpFrame.set('super', 'l_super');
this.compile(block.body, tmpFrame);
-
this.emitFuncEnd();
}
@@ -2637,13 +2776,15 @@ var Compiler = Object.extend({
},
getCode: function() {
- return this.codebuf.join("");
+ return this.codebuf.join('');
}
});
// var fs = modules["fs"];
// var c = new Compiler();
-// var src = '{% raw %}hello{% endraw %}';
+// //var src = '{{ foo({a:1}) }}';
+// var src = '{% extends "base.html" %}' +
+// '{% block block1 %}{{ super() }}BAR{% endblock %}';
// var ns = parser.parse(src);
// nodes.printNodes(ns);
@@ -2716,10 +2857,50 @@ var filters = {
return pre + str + post;
},
- default: function(val, def) {
+ '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) {
+ // deliberately include properties from the object's prototype
+ 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) {
return str.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
@@ -2946,17 +3127,19 @@ var filters = {
return str.match(/\w+/g).length;
},
- float: function(val, def) {
- return parseFloat(val) || def;
+ 'float': function(val, def) {
+ var res = parseFloat(val);
+ return isNaN(res) ? def : res;
},
- int: function(val, def) {
- return parseInt(val) || def;
+ 'int': function(val, def) {
+ var res = parseInt(val, 10);
+ return isNaN(res) ? def : res;
}
};
// Aliases
-filters.d = filters.default;
+filters.d = filters['default'];
filters.e = filters.escape;
modules['filters'] = filters;
@@ -3008,8 +3191,7 @@ var HttpLoader = Object.extend({
modules['web-loaders'] = {
HttpLoader: HttpLoader
-};
-})();
+};})();
(function() {
if(typeof window === 'undefined') {
modules['loaders'] = modules["node-loaders"];
@@ -3058,27 +3240,6 @@ var Environment = Object.extend({
this.cache = {};
},
- tryTemplate: function(path, func) {
- try {
- return func();
- } catch (e) {
- if (!e.Update) {
- // not one of ours, cast it
- e = lib.TemplateError(e);
- }
- e.Update(path);
-
- // Unless they marked the dev flag, show them a trace from here
- if (!this.dev) {
- var old = e;
- e = new Error(old.message);
- e.name = old.name;
- }
-
- throw e;
- }
- },
-
addFilter: function(name, func) {
this.filters[name] = func;
},
@@ -3231,7 +3392,7 @@ var Context = Object.extend({
return this.blocks[name][0];
},
- getSuper: function(env, name, block) {
+ getSuper: function(env, name, block, frame, runtime) {
var idx = (this.blocks[name] || []).indexOf(block);
var blk = this.blocks[name][idx + 1];
var context = this;
@@ -3241,7 +3402,7 @@ var Context = Object.extend({
throw new Error('no super block available for "' + name + '"');
}
- return blk(env, context);
+ return blk(env, context, frame, runtime);
};
},
@@ -3281,9 +3442,10 @@ var Template = Object.extend({
this.upToDate = upToDate || function() { return false; };
if(eagerCompile) {
- var self = this;
- this.env.tryTemplate(this.path, function() { self._compile(); });
- self = null;
+ var _this = this;
+ lib.withPrettyErrors(this.path,
+ this.env.dev,
+ function() { _this._compile(); });
}
else {
this.compiled = false;
@@ -3305,7 +3467,8 @@ var Template = Object.extend({
frame || new Frame(),
runtime);
};
- return this.env.tryTemplate(this.path, render);
+
+ return lib.withPrettyErrors(this.path, this.env.dev, render);
},
isUpToDate: function() {
@@ -3396,7 +3559,6 @@ if(loaders) {
window.nunjucks.compiler = compiler;
window.nunjucks.parser = parser;
window.nunjucks.lexer = lexer;
-
window.nunjucks.require =
function(name) { return modules[name]; };
View
2  browser/nunjucks-min.js
@@ -1 +1 @@
-(function(){var a={};(function(){function b(a,c,d){var e=Object.create(a.prototype),f=/xyz/.test(function(){xyz})?/\bparent\b/:/.*/;d=d||{};for(var g in d){var h=d[g],i=e[g];typeof i=="function"&&typeof h=="function"&&f.test(h)?e[g]=function(a,b){return function(){var c=this.parent;this.parent=b;var d=a.apply(this,arguments);return this.parent=c,d}}(h,i):e[g]=h}e.typename=c;var j=function(){e.init&&e.init.apply(this,arguments)};return j.prototype=e,j.prototype.constructor=j,j.extend=function(a,c){return typeof a=="object"&&(c=a,a="anonymous"),b(j,a,c)},j}a.object=b(Object,"Object",{})})(),function(){var b=Array.prototype,c=Object.prototype,d=a.lib={};d.TemplateError=function(a,b,c){var d=this;return a instanceof Error?(d=a,a=a.name+": "+a.message):Error.captureStackTrace(d),d.name="Template render error",d.message=a,d.lineno=b,d.colno=c,d.firstUpdate=!0,d.Update=function(a){var b="("+(a||"unknown path")+")";return this.firstUpdate&&this.lineno&&this.colno&&(b+=" [Line "+this.lineno+", Column "+this.colno+"]"),b+="\n ",this.firstUpdate&&(b+=" "),this.message=b+(this.message||""),this.firstUpdate=!1,this},d},d.TemplateError.prototype=Error.prototype,d.isFunction=function(a){return c.toString.call(a)=="[object Function]"},d.isArray=Array.isArray||function(a){return c.toString.call(a)=="[object Array]"},d.isString=function(a){return c.toString.call(a)=="[object String]"},d.isObject=function(a){return a===Object(a)},d.groupBy=function(a,b){var c={},e=d.isFunction(b)?b:function(a){return a[b]};for(var f=0;f<a.length;f++){var g=a[f],h=e(g,f);(c[h]||(c[h]=[])).push(g)}return c},d.toArray=function(a){return Array.prototype.slice.call(a)},d.without=function(a){var b=[];if(!a)return b;var c=-1,e=a.length,f=d.toArray(arguments).slice(1);while(++c<e)f.indexOf(a[c])===-1&&b.push(a[c]);return b},d.extend=function(a,b){for(var c in b)a[c]=b[c];return a},d.repeat=function(a,b){var c="";for(var d=0;d<b;d++)c+=a;return c},d.each=function(a,c,d){if(a==null)return;if(b.each&&a.each==b.each)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++)c.call(d,a[e],e,a)},d.map=function(a,c){var d=[];if(a==null)return d;if(b.map&&a.map===b.map)return a.map(c);for(var e=0;e<a.length;e++)d[d.length]=c(a[e],e);return a.length===+a.length&&(d.length=a.length),d}}(),function(){var b=a.lib,c={abs:function(a){return Math.abs(a)},batch:function(a,b,c){var d=[],e=[];for(var f=0;f<a.length;f++)f%b===0&&e.length&&(d.push(e),e=[]),e.push(a[f]);if(e.length){if(c)for(var f=e.length;f<b;f++)e.push(c);d.push(e)}return d},capitalize:function(a){return a=a.toLowerCase(),a[0].toUpperCase()+a.slice(1)},center:function(a,c){c=c||80;if(a.length>=c)return a;var d=c-a.length,e=b.repeat(" ",d/2-d%2),f=b.repeat(" ",d/2);return e+a+f},"default":function(a,b){return a?a:b},escape:function(a){return a.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&#39;").replace(/</g,"&lt;").replace(/>/g,"&gt;")},first:function(a){return a[0]},groupby:function(a,c){return b.groupBy(a,c)},indent:function(a,c,d){c=c||4;var e="",f=a.split("\n"),g=b.repeat(" ",c);for(var h=0;h<f.length;h++)h==0&&!d?e+=f[h]+"\n":e+=g+f[h]+"\n";return e},join:function(a,c,d){return c=c||"",d&&(a=b.map(a,function(a){return a[d]})),a.join(c)},last:function(a){return a[a.length-1]},length:function(a){return a.length},list:function(a){if(b.isString(a))return a.split("");if(b.isObject(a)){var c=[];if(Object.keys)c=Object.keys(a);else for(var d in a)c.push(d);return b.map(c,function(b){return{key:b,value:a[b]}})}throw new b.TemplateError("list filter: type not iterable")},lower:function(a){return a.toLowerCase()},random:function(a){var b=Math.floor(Math.random()*a.length);return b==a.length&&b--,a[b]},replace:function(a,b,c,d){var e=a,f=e,g=1;e=e.replace(b,c);while(f!=e){if(g>=d)break;f=e,e=e.replace(b,c),g++}return e},reverse:function(a){var d;return b.isString(a)?d=c.list(a):d=b.map(a,function(a){return a}),d.reverse(),b.isString(a)?d.join(""):d},round:function(a,b,c){b=b||0;var d=Math.pow(10,b),e;return c=="ceil"?e=Math.ceil:c=="floor"?e=Math.floor:e=Math.round,e(a*d)/d},slice:function(a,b,c){var d=Math.floor(a.length/b),e=a.length%b,f=0,g=[];for(var h=0;h<b;h++){var i=f+h*d;h<e&&f++;var j=f+(h+1)*d,k=a.slice(i,j);c&&h>=e&&k.push(c),g.push(k)}return g},sort:function(a,c,d,e){return a=b.map(a,function(a){return a}),a.sort(function(a,f){var g,h;return e?(g=a[e],h=f[e]):(g=a,h=f),!d&&b.isString(g)&&b.isString(h)&&(g=g.toLowerCase(),h=h.toLowerCase()),g<h?c?1:-1:g>h?c?-1:1:0}),a},string:function(a){return a.toString()},title:function(a){return a.toUpperCase()},trim:function(a){return a.replace(/^\s*|\s*$/g,"")},upper:function(a){return a.toUpperCase()},wordcount:function(a){return a.match(/\w+/g).length},"float":function(a,b){return parseFloat(a)||b},"int":function(a,b){return parseInt(a)||b}};c.d=c.default,c.e=c.escape,a.filters=c}(),function(){function d(a,b,c){return function(){var d=g(arguments),e,h=f(arguments);if(d>a.length){e=Array.prototype.slice.call(arguments,0,a.length);var i=Array.prototype.slice.call(arguments,e.length,d);for(var j=0;j<i.length;j++)j<b.length&&(h[b[j]]=i[j]);e.push(h)}else if(d<a.length){e=Array.prototype.slice.call(arguments,0,d);for(var j=d;j<a.length;j++){var k=a[j];e.push(h[k]),delete h[k]}e.push(h)}else e=arguments;return c.apply(this,e)}}function e(a){return a.__keywords=!0,a}function f(a){return a.length&&a[a.length-1].__keywords?a[a.length-1]:{}}function g(a){return a.length===0?0:a[a.length-1].__keywords?a.length-1:a.length}function h(a){return a!==undefined&&a!==null?a:""}function i(a,b){return a=a||{},b=a[b],typeof b=="function"?function(){return h(b.apply(a,arguments))}:h(b)}function j(a,b,c){var d=a.lookup(c);return d!==undefined&&d!==null?d:b.lookup(c)}var b=a.object,c=b.extend({init:function(a){this.variables={},this.parent=a},set:function(a,b){var c=a.split("."),d=this.variables;for(var e=0;e<c.length-1;e++){var f=c[e];d[f]||(d[f]={}),d=d[f]}d[c[c.length-1]]=b},lookup:function(a){var b=this.parent,c=this.variables[a];return c!==undefined&&c!==null?c:b&&b.lookup(a)},push:function(){return new c(this)},pop:function(){return this.parent}});a.runtime={Frame:c,makeMacro:d,makeKeywordArgs:e,numArgs:g,suppressValue:h,suppressLookupValue:i,contextOrFrameLookup:j}}(),function(){var b=a.lib,c=a.object,d=a.lexer,e=a.compiler,f=a.filters,g=a.loaders,h=a.runtime,i=h.Frame,j=c.extend({init:function(a,c,e){this.dev=e,a?this.loaders=b.isArray(a)?a:[a]:g.FileSystemLoader?this.loaders=[new g.FileSystemLoader]:this.loaders=[new g.HttpLoader("/views")],c&&d.setTags(c),this.filters=f,this.cache={}},tryTemplate:function(a,c){try{return c()}catch(d){d.Update||(d=b.TemplateError(d)),d.Update(a);if(!this.dev){var e=d;d=new Error(e.message),d.name=e.name}throw d}},addFilter:function(a,b){this.filters[a]=b},getFilter:function(a){if(!this.filters[a])throw new Error("filter not found: "+a);return this.filters[a]},getTemplate:function(a,b){var c=null,d=this.cache[a],e;if(typeof a!="string")throw new Error("template names must be a string: "+a);if(!d||!d.isUpToDate()){for(var f=0;f<this.loaders.length;f++)if(c=this.loaders[f].getSource(a))break;if(!c)throw new Error("template not found: "+a);this.cache[a]=new l(c.src,this,c.path,c.upToDate,b)}return this.cache[a]},registerPrecompiled:function(a){for(var b in a)this.cache[b]=new l({type:"code",obj:a[b]},this,b,function(){return!0},!0)},express:function(c){var d=this;if(c.render)c.render=function(a,c,e){var f={};b.isFunction(c)&&(e=c,c={}),f=b.extend(f,this.locals),c._locals&&(f=b.extend(f,c._locals)),f=b.extend(f,c);var g=d.render(a,f);e(null,g)};else{var e=a.http,f=e.ServerResponse.prototype;f._render=function(a,c,e){var f=this.app,g={};this._locals&&(g=b.extend(g,this._locals)),c&&(g=b.extend(g,c),c.locals&&(g=b.extend(g,c.locals))),g=b.extend(g,f._locals);var h=d.render(a,g);e?e(null,h):this.send(h)}}},render:function(a,b){return this.getTemplate(a).render(b)}}),k=c.extend({init:function(a,b){this.ctx=a,this.blocks={},this.exported=[];for(var c in b)this.addBlock(c,b[c])},lookup:function(a){return this.ctx[a]},setVariable:function(a,b){this.ctx[a]=b},getVariables:function(){return this.ctx},addBlock:function(a,b){this.blocks[a]=this.blocks[a]||[],this.blocks[a].push(b)},getBlock:function(a){if(!this.blocks[a])throw new Error('unknown block "'+a+'"');return this.blocks[a][0]},getSuper:function(a,b,c){var d=(this.blocks[b]||[]).indexOf(c),e=this.blocks[b][d+1],f=this;return function(){if(d==-1||!e)throw new Error('no super block available for "'+b+'"');return e(a,f)}},addExport:function(a){this.exported.push(a)},getExported:function(){var a={};for(var b=0;b<this.exported.length;b++){var c=this.exported[b];a[c]=this.ctx[c]}return a}}),l=c.extend({init:function(a,c,d,e,f){this.env=c||new j;if(b.isObject(a))switch(a.type){case"code":this.tmplProps=a.obj;break;case"string":this.tmplStr=a.obj}else{if(!b.isString(a))throw new Error("src must be a string or an object describing the source");this.tmplStr=a}this.path=d,this.upToDate=e||function(){return!1};if(f){var g=this;this.env.tryTemplate(this.path,function(){g._compile()}),g=null}else this.compiled=!1},render:function(a,b){var c=this,d=function(){c.compiled||c._compile();var d=new k(a||{},c.blocks);return c.rootRenderFunc(c.env,d,b||new i,h)};return this.env.tryTemplate(this.path,d)},isUpToDate:function(){return this.upToDate()},getExported:function(){this.compiled||this._compile();var a=new k({},this.blocks);return this.rootRenderFunc(this.env,a,new i,h),a.getExported()},_compile:function(){var a;if(this.tmplProps)a=this.tmplProps;else{var b=new Function(e.compile(this.tmplStr,this.env));a=b()}this.blocks=this._getBlocks(a),this.rootRenderFunc=a.root,this.compiled=!0},_getBlocks:function(a){var b={};for(var c in a)c.slice(0,2)=="b_"&&(b[c.slice(2)]=a[c]);return b}});a.environment={Environment:j,Template:l}}();var b=a.environment,c=a.compiler,d=a.parser,e=a.lexer,f=a.loaders;window.nunjucks={},window.nunjucks.Environment=b.Environment,window.nunjucks.Template=b.Template,f&&(f.FileSystemLoader?window.nunjucks.FileSystemLoader=f.FileSystemLoader:window.nunjucks.HttpLoader=f.HttpLoader),window.nunjucks.compiler=c,window.nunjucks.parser=d,window.nunjucks.lexer=e,window.nunjucks.require=function(b){return a[b]}})();
+(function(){var modules={};(function(){function extend(cls,name,props){var prototype=Object.create(cls.prototype);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(){var ArrayProto=Array.prototype;var ObjProto=Object.prototype;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{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.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 obj===Object(obj)};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(contains.indexOf(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}})();(function(){var lib=modules["lib"];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){str=str.toLowerCase();return str[0].toUpperCase()+str.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 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){return str.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&#39;").replace(/</g,"&lt;").replace(/>/g,"&gt;")},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 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.length},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{throw new lib.TemplateError("list filter: type not iterable")}},lower:function(str){return str.toLowerCase()},random:function(arr){var i=Math.floor(Math.random()*arr.length);if(i==arr.length){i--}return arr[i]},replace:function(str,old,new_,maxCount){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 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 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 obj.toString()},title:function(str){return str.toUpperCase()},trim:function(str){return str.replace(/^\s*|\s*$/g,"")},upper:function(str){return str.toUpperCase()},wordcount:function(str){return str.match(/\w+/g).length},"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(){var lib=modules["lib"];var Object=modules["object"];var Frame=Object.extend({init:function(parent){this.variables={};this.parent=parent},set:function(name,val){var parts=name.split(".");var obj=this.variables;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},lookup:function(name){var p=this.parent;var val=this.variables[name];if(val!==undefined&&val!==null){return val}return p&&p.lookup(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){if(args.length&&args[args.length-1].__keywords){return args[args.length-1]}return{}}function numArgs(args){if(args.length===0){return 0}else if(args[args.length-1].__keywords){return args.length-1}else{return args.length}}function suppressValue(val){return val!==undefined&&val!==null?val:""}function suppressLookupValue(obj,val){obj=obj||{};val=obj[val];if(typeof val==="function"){return function(){return suppressValue(val.apply(obj,arguments))}}else{return suppressValue(val)}}function contextOrFrameLookup(context,frame,name){var val=context.lookup(name);return val!==undefined&&val!==null?val:frame.lookup(name)}function handleError(error,lineno,colno){if(error.lineno){throw error}else{throw new lib.TemplateError(error,lineno,colno)}}modules["runtime"]={Frame:Frame,makeMacro:makeMacro,makeKeywordArgs:makeKeywordArgs,numArgs:numArgs,suppressValue:suppressValue,suppressLookupValue:suppressLookupValue,contextOrFrameLookup:contextOrFrameLookup,handleError:handleError,isArray:lib.isArray}})();(function(){var lib=modules["lib"];var Object=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 Frame=runtime.Frame;var Environment=Object.extend({init:function(loaders,tags,dev){this.dev=dev;if(!loaders){if(builtin_loaders.FileSystemLoader){this.loaders=[new builtin_loaders.FileSystemLoader]}else{this.loaders=[new builtin_loaders.HttpLoader("/views")]}}else{this.loaders=lib.isArray(loaders)?loaders:[loaders]}if(tags){lexer.setTags(tags)}this.filters=builtin_filters;this.cache={}},addFilter:function(name,func){this.filters[name]=func},getFilter:function(name){if(!this.filters[name]){throw new Error("filter not found: "+name)}return this.filters[name]},getTemplate:function(name,eagerCompile){var info=null;var tmpl=this.cache[name];var upToDate;if(typeof name!=="string"){throw new Error("template names must be a string: "+name)}if(!tmpl||!tmpl.isUpToDate()){for(var i=0;i<this.loaders.length;i++){if(info=this.loaders[i].getSource(name)){break}}if(!info){throw new Error("template not found: "+name)}this.cache[name]=new Template(info.src,this,info.path,info.upToDate,eagerCompile)}return this.cache[name]},registerPrecompiled:function(templates){for(var name in templates){this.cache[name]=new Template({type:"code",obj:templates[name]},this,name,function(){return true},true)}},express:function(app){var env=this;if(app.render){app.render=function(name,ctx,k){var context={};if(lib.isFunction(ctx)){k=ctx;ctx={}}context=lib.extend(context,this.locals);if(ctx._locals){context=lib.extend(context,ctx._locals)}context=lib.extend(context,ctx);var res=env.render(name,context);k(null,res)}}else{var http=modules["http"];var res=http.ServerResponse.prototype;res._render=function(name,ctx,k){var app=this.app;var context={};if(this._locals){context=lib.extend(context,this._locals)}if(ctx){context=lib.extend(context,ctx);if(ctx.locals){context=lib.extend(context,ctx.locals)}}context=lib.extend(context,app._locals);var str=env.render(name,context);if(k){k(null,str)}else{this.send(str)}}}},render:function(name,ctx){return this.getTemplate(name).render(ctx)}});var Context=Object.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){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){var idx=(this.blocks[name]||[]).indexOf(block);var blk=this.blocks[name][idx+1];var context=this;return function(){if(idx==-1||!blk){throw new Error('no super block available for "'+name+'"')}return blk(env,context,frame,runtime)}},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=Object.extend({init:function(src,env,path,upToDate,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;this.upToDate=upToDate||function(){return false};if(eagerCompile){var _this=this;lib.withPrettyErrors(this.path,this.env.dev,function(){_this._compile()})}else{this.compiled=false}},render:function(ctx,frame){var self=this;var render=function(){if(!self.compiled){self._compile()}var context=new Context(ctx||{},self.blocks);return self.rootRenderFunc(self.env,context,frame||new Frame,runtime)};return lib.withPrettyErrors(this.path,this.env.dev,render)},isUpToDate:function(){return this.upToDate()},getExported:function(){if(!this.compiled){this._compile()}var context=new Context({},this.blocks);this.rootRenderFunc(this.env,context,new Frame,runtime);return context.getExported()},_compile:function(){var props;if(this.tmplProps){props=this.tmplProps}else{var func=new Function(compiler.compile(this.tmplStr,this.env));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 env=modules["environment"];var compiler=modules["compiler"];var parser=modules["parser"];var lexer=modules["lexer"];var loaders=modules["loaders"];window.nunjucks={};window.nunjucks.Environment=env.Environment;window.nunjucks.Template=env.Template;if(loaders){if(loaders.FileSystemLoader){window.nunjucks.FileSystemLoader=loaders.FileSystemLoader}else{window.nunjucks.HttpLoader=loaders.HttpLoader}}window.nunjucks.compiler=compiler;window.nunjucks.parser=parser;window.nunjucks.lexer=lexer;window.nunjucks.require=function(name){return modules[name]}})();
View
158 browser/nunjucks.js
@@ -65,29 +65,55 @@ var ObjProto = Object.prototype;
var exports = modules['lib'] = {};
+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);
+
+ // 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;
+ }
+
+ throw e;
+ }
+}
+
exports.TemplateError = function(message, lineno, colno) {
- var self = this;
+ var err = this;
if (message instanceof Error) { // for casting regular js errors
- self = message;
+ err = message;
message = message.name + ": " + message.message;
} else {
- Error.captureStackTrace(self);
+ Error.captureStackTrace(err);
}
- self.name = "Template render error";
- self.message = message;
- self.lineno = lineno;
- self.colno = colno;
- self.firstUpdate = true;
+ err.name = "Template render error";
+ err.message = message;
+ err.lineno = lineno;
+ err.colno = colno;
+ err.firstUpdate = true;
- self.Update = function(path) {
+ err.Update = function(path) {
var message = "(" + (path || "unknown path") + ")";
// only show lineno + colno next to path of template
// where error occurred
- if (this.firstUpdate && this.lineno && this.colno) {
- message += ' [Line ' + this.lineno + ', Column ' + this.colno + ']';
+ 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 ';
@@ -99,10 +125,11 @@ exports.TemplateError = function(message, lineno, colno) {
this.firstUpdate = false;
return this;
};
- return self;
+
+ return err;
};
-exports.TemplateError.prototype = Error.prototype;
+exports.TemplateError.prototype = Error.prototype;
exports.isFunction = function(obj) {
return ObjProto.toString.call(obj) == '[object Function]';
@@ -256,10 +283,50 @@ var filters = {
return pre + str + post;
},
- default: function(val, def) {
+ '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) {
+ // deliberately include properties from the object's prototype
+ 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) {
return str.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
@@ -486,23 +553,25 @@ var filters = {
return str.match(/\w+/g).length;
},
- float: function(val, def) {
- return parseFloat(val) || def;
+ 'float': function(val, def) {
+ var res = parseFloat(val);
+ return isNaN(res) ? def : res;
},
- int: function(val, def) {
- return parseInt(val) || def;
+ 'int': function(val, def) {
+ var res = parseInt(val, 10);
+ return isNaN(res) ? def : res;
}
};
// Aliases
-filters.d = filters.default;
+filters.d = filters['default'];
filters.e = filters.escape;
modules['filters'] = filters;
})();
(function() {
-
+var lib = modules["lib"];
var Object = modules["object"];
// Frames keep track of scoping both at compile-time and run-time so
@@ -642,6 +711,15 @@ function contextOrFrameLookup(context, frame, name) {
frame.lookup(name);
}
+function handleError(error, lineno, colno) {
+ if(error.lineno) {
+ throw error;
+ }
+ else {
+ throw new lib.TemplateError(error, lineno, colno);
+ }
+}
+
modules['runtime'] = {
Frame: Frame,
makeMacro: makeMacro,
@@ -649,7 +727,9 @@ modules['runtime'] = {
numArgs: numArgs,
suppressValue: suppressValue,
suppressLookupValue: suppressLookupValue,
- contextOrFrameLookup: contextOrFrameLookup
+ contextOrFrameLookup: contextOrFrameLookup,
+ handleError: handleError,
+ isArray: lib.isArray
};
})();
(function() {
@@ -692,27 +772,6 @@ var Environment = Object.extend({
this.cache = {};
},
- tryTemplate: function(path, func) {
- try {
- return func();
- } catch (e) {
- if (!e.Update) {
- // not one of ours, cast it
- e = lib.TemplateError(e);
- }
- e.Update(path);
-
- // Unless they marked the dev flag, show them a trace from here
- if (!this.dev) {
- var old = e;
- e = new Error(old.message);
- e.name = old.name;
- }
-
- throw e;
- }
- },
-
addFilter: function(name, func) {
this.filters[name] = func;
},
@@ -865,7 +924,7 @@ var Context = Object.extend({
return this.blocks[name][0];
},
- getSuper: function(env, name, block) {
+ getSuper: function(env, name, block, frame, runtime) {
var idx = (this.blocks[name] || []).indexOf(block);
var blk = this.blocks[name][idx + 1];
var context = this;
@@ -875,7 +934,7 @@ var Context = Object.extend({
throw new Error('no super block available for "' + name + '"');
}
- return blk(env, context);
+ return blk(env, context, frame, runtime);
};
},
@@ -915,9 +974,10 @@ var Template = Object.extend({
this.upToDate = upToDate || function() { return false; };
if(eagerCompile) {
- var self = this;
- this.env.tryTemplate(this.path, function() { self._compile(); });
- self = null;
+ var _this = this;
+ lib.withPrettyErrors(this.path,
+ this.env.dev,
+ function() { _this._compile(); });
}
else {
this.compiled = false;
@@ -939,7 +999,8 @@ var Template = Object.extend({
frame || new Frame(),
runtime);
};
- return this.env.tryTemplate(this.path, render);
+
+ return lib.withPrettyErrors(this.path, this.env.dev, render);
},
isUpToDate: function() {
@@ -1030,7 +1091,6 @@ if(loaders) {
window.nunjucks.compiler = compiler;
window.nunjucks.parser = parser;
window.nunjucks.lexer = lexer;
-
window.nunjucks.require =
function(name) { return modules[name]; };
View
3  package.json
@@ -8,7 +8,8 @@
},
"devDependencies": {
"should": "*",
- "mocha": "*"
+ "mocha": "*",
+ "uglify-js": "*"
},
"engines": {
"node": "*"
Please sign in to comment.
Something went wrong with that request. Please try again.