aboutsummaryrefslogtreecommitdiff
path: root/src/libs/nunjucks.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/nunjucks.js')
-rw-r--r--src/libs/nunjucks.js6692
1 files changed, 6692 insertions, 0 deletions
diff --git a/src/libs/nunjucks.js b/src/libs/nunjucks.js
new file mode 100644
index 0000000..fa4db0a
--- /dev/null
+++ b/src/libs/nunjucks.js
@@ -0,0 +1,6692 @@
+/*! Browser bundle of nunjucks 3.0.0 */
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory();
+ else if(typeof define === 'function' && define.amd)
+ define([], factory);
+ else if(typeof exports === 'object')
+ exports["nunjucks"] = factory();
+ else
+ root["nunjucks"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var env = __webpack_require__(2);
+ var Loader = __webpack_require__(15);
+ var loaders = __webpack_require__(14);
+ var precompile = __webpack_require__(3);
+
+ module.exports = {};
+ module.exports.Environment = env.Environment;
+ module.exports.Template = env.Template;
+
+ module.exports.Loader = Loader;
+ module.exports.FileSystemLoader = loaders.FileSystemLoader;
+ module.exports.PrecompiledLoader = loaders.PrecompiledLoader;
+ module.exports.WebLoader = loaders.WebLoader;
+
+ module.exports.compiler = __webpack_require__(7);
+ module.exports.parser = __webpack_require__(8);
+ module.exports.lexer = __webpack_require__(9);
+ module.exports.runtime = __webpack_require__(12);
+ module.exports.lib = lib;
+ module.exports.nodes = __webpack_require__(10);
+
+ module.exports.installJinjaCompat = __webpack_require__(21);
+
+ // A single instance of an environment, since this is so commonly used
+
+ var e;
+ module.exports.configure = function(templatesPath, opts) {
+ opts = opts || {};
+ if(lib.isObject(templatesPath)) {
+ opts = templatesPath;
+ templatesPath = null;
+ }
+
+ 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) {
+ e.express(opts.express);
+ }
+
+ return e;
+ };
+
+ module.exports.compile = function(src, env, path, eagerCompile) {
+ if(!e) {
+ module.exports.configure();
+ }
+ return new module.exports.Template(src, env, path, eagerCompile);
+ };
+
+ module.exports.render = function(name, ctx, cb) {
+ if(!e) {
+ module.exports.configure();
+ }
+
+ return e.render(name, ctx, cb);
+ };
+
+ module.exports.renderString = function(src, ctx, cb) {
+ if(!e) {
+ module.exports.configure();
+ }
+
+ return e.renderString(src, ctx, cb);
+ };
+
+ if(precompile) {
+ module.exports.precompile = precompile.precompile;
+ module.exports.precompileString = precompile.precompileString;
+ }
+
+
+/***/ },
+/* 1 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ var ArrayProto = Array.prototype;
+ var ObjProto = Object.prototype;
+
+ var escapeMap = {
+ '&': '&',
+ '"': '"',
+ '\'': ''',
+ '<': '&lt;',
+ '>': '&gt;'
+ };
+
+ var escapeRegex = /[&"'<>]/g;
+
+ var lookupEscape = function(ch) {
+ return escapeMap[ch];
+ };
+
+ var exports = module.exports = {};
+
+ 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 = err;
+ err = new Error(old.message);
+ err.name = old.name;
+ }
+
+ return err;
+ };
+
+ exports.TemplateError = function(message, lineno, colno) {
+ var err = this;
+
+ if (message instanceof Error) { // for casting regular js errors
+ err = message;
+ message = message.name + ': ' + message.message;
+
+ try {
+ if(err.name = '') {}
+ }
+ catch(e) {
+ // If we can't set the name of the error object in this
+ // environment, don't use it
+ err = this;
+ }
+ } 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') + ')';
+
+ // only show lineno + colno next to path of template
+ // where error occurred
+ 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();
+ };
+
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Polyfill
+ 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; // Hack to convert object.length to a UInt32
+
+ 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;
+ }
+ };
+
+ exports.inOperator = function (key, val) {
+ if (exports.isArray(val)) {
+ return exports.indexOf(val, key) !== -1;
+ } else if (exports.isObject(val)) {
+ return key in val;
+ } else if (exports.isString(val)) {
+ return val.indexOf(key) !== -1;
+ } else {
+ throw new Error('Cannot use "in" operator to search for "'
+ + key + '" in unexpected types.');
+ }
+ };
+
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var path = __webpack_require__(3);
+ var asap = __webpack_require__(4);
+ var lib = __webpack_require__(1);
+ var Obj = __webpack_require__(6);
+ var compiler = __webpack_require__(7);
+ var builtin_filters = __webpack_require__(13);
+ var builtin_loaders = __webpack_require__(14);
+ var runtime = __webpack_require__(12);
+ var globals = __webpack_require__(17);
+ var waterfall = __webpack_require__(18);
+ 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 = __webpack_require__(16);
+
+ // 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({
+ init: function(loaders, opts) {
+ // The dev flag determines the trace that'll be shown on errors.
+ // If set to true, returns the full trace from the error point,
+ // otherwise will return trace starting from Template.render
+ // (the full trace from within nunjucks may confuse developers using
+ // the library)
+ // defaults to false
+ opts = this.opts = opts || {};
+ this.opts.dev = !!opts.dev;
+
+ // The autoescape flag sets global autoescaping. If true,
+ // every string variable will be escaped by default.
+ // If false, strings can be manually escaped using the `escape` filter.
+ // 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 server-side
+ if(builtin_loaders.FileSystemLoader) {
+ this.loaders = [new builtin_loaders.FileSystemLoader('views')];
+ }
+ else if(builtin_loaders.WebLoader) {
+ this.loaders = [new builtin_loaders.WebLoader('/views')];
+ }
+ }
+ else {
+ this.loaders = lib.isArray(loaders) ? loaders : [loaders];
+ }
+
+ // 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((true) && window.nunjucksPrecompiled) {
+ this.loaders.unshift(
+ new builtin_loaders.PrecompiledLoader(window.nunjucksPrecompiled)
+ );
+ }
+
+ this.initCache();
+
+ this.globals = globals();
+ this.filters = {};
+ this.asyncFilters = [];
+ this.extensions = {};
+ this.extensionsList = [];
+
+ for(var name in builtin_filters) {
+ this.addFilter(name, builtin_filters[name]);
+ }
+ },
+
+ initCache: function() {
+ // Caching and cache busting
+ 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);
+ return this;
+ },
+
+ removeExtension: function(name) {
+ var extension = this.getExtension(name);
+ if (!extension) return;
+
+ this.extensionsList = lib.without(this.extensionsList, extension);
+ delete this.extensions[name];
+ },
+
+ getExtension: function(name) {
+ return this.extensions[name];
+ },
+
+ hasExtension: function(name) {
+ return !!this.extensions[name];
+ },
+
+ addGlobal: function(name, value) {
+ this.globals[name] = value;
+ return this;
+ },
+
+ getGlobal: function(name) {
+ if(typeof this.globals[name] === 'undefined') {
+ throw new Error('global not found: ' + name);
+ }
+ return this.globals[name];
+ },
+
+ addFilter: function(name, func, async) {
+ var wrapped = func;
+
+ if(async) {
+ this.asyncFilters.push(name);
+ }
+ this.filters[name] = wrapped;
+ return this;
+ },
+
+ 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, ignoreMissing, cb) {
+ var that = this;
+ var tmpl = null;
+ if(name && name.raw) {
+ // this fixes autoescape for templates referenced in symbols
+ name = name.raw;
+ }
+
+ if(lib.isFunction(parentName)) {
+ cb = parentName;
+ parentName = null;
+ eagerCompile = eagerCompile || false;
+ }
+
+ if(lib.isFunction(eagerCompile)) {
+ cb = eagerCompile;
+ eagerCompile = false;
+ }
+
+ if (name instanceof Template) {
+ tmpl = name;
+ }
+ else if(typeof name !== 'string') {
+ throw new Error('template names must be a string: ' + name);
+ }
+ else {
+ 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;
+ var _this = this;
+
+ var createTemplate = function(err, info) {
+ if(!info && !err) {
+ if(!ignoreMissing) {
+ err = new Error('template not found: ' + name);
+ }
+ }
+
+ if (err) {
+ if(cb) {
+ cb(err);
+ }
+ else {
+ throw err;
+ }
+ }
+ else {
+ var tmpl;
+ if(info) {
+ tmpl = new Template(info.src, _this,
+ info.path, eagerCompile);
+
+ if(!info.noCache) {
+ info.loader.cache[name] = tmpl;
+ }
+ }
+ else {
+ tmpl = new Template('', _this,
+ '', eagerCompile);
+ }
+
+ if(cb) {
+ cb(null, tmpl);
+ }
+ else {
+ syncResult = tmpl;
+ }
+ }
+ };
+
+ lib.asyncIter(this.loaders, function(loader, i, next, done) {
+ function handle(err, src) {
+ if(err) {
+ done(err);
+ }
+ else if(src) {
+ src.loader = loader;
+ done(null, src);
+ }
+ else {
+ next();
+ }
+ }
+
+ // Resolve name relative to parentName
+ name = that.resolveTemplate(loader, parentName, name);
+
+ if(loader.async) {
+ loader.getSource(name, handle);
+ }
+ else {
+ handle(null, loader.getSource(name));
+ }
+ }, createTemplate);
+
+ 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);
+ app.set('nunjucksEnv', this);
+ return this;
+ },
+
+ render: function(name, ctx, cb) {
+ if(lib.isFunction(ctx)) {
+ cb = ctx;
+ ctx = null;
+ }
+
+ // We support a synchronous API to make it easier to migrate
+ // existing code to async. This works because if you don't do
+ // anything async work, the whole thing is actually run
+ // synchronously.
+ var syncResult = null;
+
+ this.getTemplate(name, function(err, tmpl) {
+ if(err && cb) {
+ callbackAsap(cb, err);
+ }
+ else if(err) {
+ throw err;
+ }
+ else {
+ syncResult = tmpl.render(ctx, cb);
+ }
+ });
+
+ 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);
+ },
+
+ waterfall: waterfall
+ });
+
+ var Context = Obj.extend({
+ init: function(ctx, blocks, env) {
+ // Has to be tied to an environment so we can tap into its globals.
+ this.env = env || new Environment();
+
+ // Make a duplicate of ctx
+ this.ctx = {};
+ for(var k in ctx) {
+ if(ctx.hasOwnProperty(k)) {
+ this.ctx[k] = ctx[k];
+ }
+ }
+
+ this.blocks = {};
+ this.exported = [];
+
+ for(var name in blocks) {
+ this.addBlock(name, blocks[name]);
+ }
+ },
+
+ lookup: function(name) {
+ // This is one of the most called functions, so optimize for
+ // the typical case where the name isn't in the globals
+ if(name in this.env.globals && !(name in this.ctx)) {
+ return this.env.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);
+ return this;
+ },
+
+ 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;
+ }
+ });
+
+ 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) {
+ var _this = this;
+ try {
+ _this._compile();
+ }
+ catch(err) {
+ throw lib.prettifyError(this.path, this.env.opts.dev, err);
+ }
+ }
+ else {
+ this.compiled = false;
+ }
+ },
+
+ render: function(ctx, parentFrame, cb) {
+ if (typeof ctx === 'function') {
+ cb = ctx;
+ ctx = {};
+ }
+ else if (typeof parentFrame === 'function') {
+ cb = parentFrame;
+ parentFrame = null;
+ }
+
+ 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;
+ }
+
+ var _this = this;
+ // Catch compile errors for async rendering
+ try {
+ _this.compile();
+ } catch (_err) {
+ var err = lib.prettifyError(this.path, this.env.opts.dev, _err);
+ if (cb) return callbackAsap(cb, err);
+ else throw err;
+ }
+
+ var context = new Context(ctx || {}, _this.blocks, _this.env);
+ var frame = parentFrame ? parentFrame.push(true) : new Frame();
+ frame.topLevel = true;
+ var syncResult = null;
+
+ _this.rootRenderFunc(
+ _this.env,
+ context,
+ frame || new Frame(),
+ runtime,
+ function(err, res) {
+ if(err) {
+ err = lib.prettifyError(_this.path, _this.env.opts.dev, err);
+ }
+
+ if(cb) {
+ if(forceAsync) {
+ callbackAsap(cb, err, res);
+ }
+ else {
+ cb(err, res);
+ }
+ }
+ else {
+ if(err) { throw err; }
+ syncResult = res;
+ }
+ }
+ );
+
+ return syncResult;
+ },
+
+
+ getExported: function(ctx, parentFrame, cb) {
+ if (typeof ctx === 'function') {
+ cb = ctx;
+ ctx = {};
+ }
+
+ if (typeof parentFrame === 'function') {
+ cb = parentFrame;
+ parentFrame = null;
+ }
+
+ // Catch compile errors for async rendering
+ try {
+ this.compile();
+ } catch (e) {
+ if (cb) return cb(e);
+ else throw e;
+ }
+
+ var frame = parentFrame ? parentFrame.push() : new Frame();
+ frame.topLevel = true;
+
+ // Run the rootRenderFunc to populate the context with exported vars
+ var context = new Context(ctx || {}, this.blocks, this.env);
+ this.rootRenderFunc(this.env,
+ context,
+ frame,
+ runtime,
+ function(err) {
+ if ( err ) {
+ cb(err, null);
+ } else {
+ 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);
+
+ /* jslint evil: true */
+ 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;
+ }
+ });
+
+ module.exports = {
+ Environment: Environment,
+ Template: Template
+ };
+
+
+/***/ },
+/* 3 */
+/***/ function(module, exports) {
+
+
+
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+ "use strict";
+
+ // rawAsap provides everything we need except exception management.
+ var rawAsap = __webpack_require__(5);
+ // RawTasks are recycled to reduce GC churn.
+ var freeTasks = [];
+ // We queue errors to ensure they are thrown in right order (FIFO).
+ // Array-as-queue is good enough here, since we are just dealing with exceptions.
+ var pendingErrors = [];
+ var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
+
+ function throwFirstError() {
+ if (pendingErrors.length) {
+ throw pendingErrors.shift();
+ }
+ }
+
+ /**
+ * Calls a task as soon as possible after returning, in its own event, with priority
+ * over other events like animation, reflow, and repaint. An error thrown from an
+ * event will not interrupt, nor even substantially slow down the processing of
+ * other events, but will be rather postponed to a lower priority event.
+ * @param {{call}} task A callable object, typically a function that takes no
+ * arguments.
+ */
+ module.exports = asap;
+ function asap(task) {
+ var rawTask;
+ if (freeTasks.length) {
+ rawTask = freeTasks.pop();
+ } else {
+ rawTask = new RawTask();
+ }
+ rawTask.task = task;
+ rawAsap(rawTask);
+ }
+
+ // We wrap tasks with recyclable task objects. A task object implements
+ // `call`, just like a function.
+ function RawTask() {
+ this.task = null;
+ }
+
+ // The sole purpose of wrapping the task is to catch the exception and recycle
+ // the task object after its single use.
+ RawTask.prototype.call = function () {
+ try {
+ this.task.call();
+ } catch (error) {
+ if (asap.onerror) {
+ // This hook exists purely for testing purposes.
+ // Its name will be periodically randomized to break any code that
+ // depends on its existence.
+ asap.onerror(error);
+ } else {
+ // In a web browser, exceptions are not fatal. However, to avoid
+ // slowing down the queue of pending tasks, we rethrow the error in a
+ // lower priority turn.
+ pendingErrors.push(error);
+ requestErrorThrow();
+ }
+ } finally {
+ this.task = null;
+ freeTasks[freeTasks.length] = this;
+ }
+ };
+
+
+/***/ },
+/* 5 */
+/***/ function(module, exports) {
+
+ /* WEBPACK VAR INJECTION */(function(global) {"use strict";
+
+ // Use the fastest means possible to execute a task in its own turn, with
+ // priority over other events including IO, animation, reflow, and redraw
+ // events in browsers.
+ //
+ // An exception thrown by a task will permanently interrupt the processing of
+ // subsequent tasks. The higher level `asap` function ensures that if an
+ // exception is thrown by a task, that the task queue will continue flushing as
+ // soon as possible, but if you use `rawAsap` directly, you are responsible to
+ // either ensure that no exceptions are thrown from your task, or to manually
+ // call `rawAsap.requestFlush` if an exception is thrown.
+ module.exports = rawAsap;
+ function rawAsap(task) {
+ if (!queue.length) {
+ requestFlush();
+ flushing = true;
+ }
+ // Equivalent to push, but avoids a function call.
+ queue[queue.length] = task;
+ }
+
+ var queue = [];
+ // Once a flush has been requested, no further calls to `requestFlush` are
+ // necessary until the next `flush` completes.
+ var flushing = false;
+ // `requestFlush` is an implementation-specific method that attempts to kick
+ // off a `flush` event as quickly as possible. `flush` will attempt to exhaust
+ // the event queue before yielding to the browser's own event loop.
+ var requestFlush;
+ // The position of the next task to execute in the task queue. This is
+ // preserved between calls to `flush` so that it can be resumed if
+ // a task throws an exception.
+ var index = 0;
+ // If a task schedules additional tasks recursively, the task queue can grow
+ // unbounded. To prevent memory exhaustion, the task queue will periodically
+ // truncate already-completed tasks.
+ var capacity = 1024;
+
+ // The flush function processes all tasks that have been scheduled with
+ // `rawAsap` unless and until one of those tasks throws an exception.
+ // If a task throws an exception, `flush` ensures that its state will remain
+ // consistent and will resume where it left off when called again.
+ // However, `flush` does not make any arrangements to be called again if an
+ // exception is thrown.
+ function flush() {
+ while (index < queue.length) {
+ var currentIndex = index;
+ // Advance the index before calling the task. This ensures that we will
+ // begin flushing on the next task the task throws an error.
+ index = index + 1;
+ queue[currentIndex].call();
+ // Prevent leaking memory for long chains of recursive calls to `asap`.
+ // If we call `asap` within tasks scheduled by `asap`, the queue will
+ // grow, but to avoid an O(n) walk for every task we execute, we don't
+ // shift tasks off the queue after they have been executed.
+ // Instead, we periodically shift 1024 tasks off the queue.
+ if (index > capacity) {
+ // Manually shift all values starting at the index back to the
+ // beginning of the queue.
+ for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
+ queue[scan] = queue[scan + index];
+ }
+ queue.length -= index;
+ index = 0;
+ }
+ }
+ queue.length = 0;
+ index = 0;
+ flushing = false;
+ }
+
+ // `requestFlush` is implemented using a strategy based on data collected from
+ // every available SauceLabs Selenium web driver worker at time of writing.
+ // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
+
+ // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
+ // have WebKitMutationObserver but not un-prefixed MutationObserver.
+ // Must use `global` instead of `window` to work in both frames and web
+ // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
+ var BrowserMutationObserver = global.MutationObserver || global.WebKitMutationObserver;
+
+ // MutationObservers are desirable because they have high priority and work
+ // reliably everywhere they are implemented.
+ // They are implemented in all modern browsers.
+ //
+ // - Android 4-4.3
+ // - Chrome 26-34
+ // - Firefox 14-29
+ // - Internet Explorer 11
+ // - iPad Safari 6-7.1
+ // - iPhone Safari 7-7.1
+ // - Safari 6-7
+ if (typeof BrowserMutationObserver === "function") {
+ requestFlush = makeRequestCallFromMutationObserver(flush);
+
+ // MessageChannels are desirable because they give direct access to the HTML
+ // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
+ // 11-12, and in web workers in many engines.
+ // Although message channels yield to any queued rendering and IO tasks, they
+ // would be better than imposing the 4ms delay of timers.
+ // However, they do not work reliably in Internet Explorer or Safari.
+
+ // Internet Explorer 10 is the only browser that has setImmediate but does
+ // not have MutationObservers.
+ // Although setImmediate yields to the browser's renderer, it would be
+ // preferrable to falling back to setTimeout since it does not have
+ // the minimum 4ms penalty.
+ // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and
+ // Desktop to a lesser extent) that renders both setImmediate and
+ // MessageChannel useless for the purposes of ASAP.
+ // https://github.com/kriskowal/q/issues/396
+
+ // Timers are implemented universally.
+ // We fall back to timers in workers in most engines, and in foreground
+ // contexts in the following browsers.
+ // However, note that even this simple case requires nuances to operate in a
+ // broad spectrum of browsers.
+ //
+ // - Firefox 3-13
+ // - Internet Explorer 6-9
+ // - iPad Safari 4.3
+ // - Lynx 2.8.7
+ } else {
+ requestFlush = makeRequestCallFromTimer(flush);
+ }
+
+ // `requestFlush` requests that the high priority event queue be flushed as
+ // soon as possible.
+ // This is useful to prevent an error thrown in a task from stalling the event
+ // queue if the exception handled by Node.js’s
+ // `process.on("uncaughtException")` or by a domain.
+ rawAsap.requestFlush = requestFlush;
+
+ // To request a high priority event, we induce a mutation observer by toggling
+ // the text of a text node between "1" and "-1".
+ function makeRequestCallFromMutationObserver(callback) {
+ var toggle = 1;
+ var observer = new BrowserMutationObserver(callback);
+ var node = document.createTextNode("");
+ observer.observe(node, {characterData: true});
+ return function requestCall() {
+ toggle = -toggle;
+ node.data = toggle;
+ };
+ }
+
+ // The message channel technique was discovered by Malte Ubl and was the
+ // original foundation for this library.
+ // http://www.nonblocking.io/2011/06/windownexttick.html
+
+ // Safari 6.0.5 (at least) intermittently fails to create message ports on a
+ // page's first load. Thankfully, this version of Safari supports
+ // MutationObservers, so we don't need to fall back in that case.
+
+ // function makeRequestCallFromMessageChannel(callback) {
+ // var channel = new MessageChannel();
+ // channel.port1.onmessage = callback;
+ // return function requestCall() {
+ // channel.port2.postMessage(0);
+ // };
+ // }
+
+ // For reasons explained above, we are also unable to use `setImmediate`
+ // under any circumstances.
+ // Even if we were, there is another bug in Internet Explorer 10.
+ // It is not sufficient to assign `setImmediate` to `requestFlush` because
+ // `setImmediate` must be called *by name* and therefore must be wrapped in a
+ // closure.
+ // Never forget.
+
+ // function makeRequestCallFromSetImmediate(callback) {
+ // return function requestCall() {
+ // setImmediate(callback);
+ // };
+ // }
+
+ // Safari 6.0 has a problem where timers will get lost while the user is
+ // scrolling. This problem does not impact ASAP because Safari 6.0 supports
+ // mutation observers, so that implementation is used instead.
+ // However, if we ever elect to use timers in Safari, the prevalent work-around
+ // is to add a scroll event listener that calls for a flush.
+
+ // `setTimeout` does not call the passed callback if the delay is less than
+ // approximately 7 in web workers in Firefox 8 through 18, and sometimes not
+ // even then.
+
+ function makeRequestCallFromTimer(callback) {
+ return function requestCall() {
+ // We dispatch a timeout with a specified delay of 0 for engines that
+ // can reliably accommodate that request. This will usually be snapped
+ // to a 4 milisecond delay, but once we're flushing, there's no delay
+ // between events.
+ var timeoutHandle = setTimeout(handleTimer, 0);
+ // However, since this timer gets frequently dropped in Firefox
+ // workers, we enlist an interval handle that will try to fire
+ // an event 20 times per second until it succeeds.
+ var intervalHandle = setInterval(handleTimer, 50);
+
+ function handleTimer() {
+ // Whichever timer succeeds will cancel both timers and
+ // execute the callback.
+ clearTimeout(timeoutHandle);
+ clearInterval(intervalHandle);
+ callback();
+ }
+ };
+ }
+
+ // This is for `asap.js` only.
+ // Its name will be periodically randomized to break any code that depends on
+ // its existence.
+ rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
+
+ // ASAP was originally a nextTick shim included in Q. This was factored out
+ // into this ASAP package. It was later adapted to RSVP which made further
+ // amendments. These decisions, particularly to marginalize MessageChannel and
+ // to capture the MutationObserver implementation in a closure, were integrated
+ // back into ASAP proper.
+ // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 6 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ // A simple class system, more documentation to come
+
+ function extend(cls, name, props) {
+ // This does that same thing as Object.create, but with support for IE8
+ var F = function() {};
+ F.prototype = cls.prototype;
+ var prototype = new F();
+
+ // jshint undef: false
+ 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)) {
+ /*jshint -W083 */
+ prototype[k] = (function (src, parent) {
+ return function() {
+ // Save the current parent method
+ var tmp = this.parent;
+
+ // Set parent to the previous method, call, and restore
+ 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;
+ }
+
+ module.exports = extend(Object, 'Object', {});
+
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var parser = __webpack_require__(8);
+ var transformer = __webpack_require__(11);
+ var nodes = __webpack_require__(10);
+ // jshint -W079
+ var Object = __webpack_require__(6);
+ var Frame = __webpack_require__(12).Frame;
+
+ // These are all the same for now, but shouldn't be passed straight
+ // through
+ var compareOps = {
+ '==': '==',
+ '===': '===',
+ '!=': '!=',
+ '!==': '!==',
+ '<': '<',
+ '>': '>',
+ '<=': '<=',
+ '>=': '>='
+ };
+
+ // A common pattern is to emit binary operators
+ function binOpEmitter(str) {
+ return function(node, frame) {
+ this.compile(node.left, frame);
+ this.emit(str);
+ this.compile(node.right, frame);
+ };
+ }
+
+ var Compiler = Object.extend({
+ init: function(templateName, throwOnUndefined) {
+ this.templateName = templateName;
+ this.codebuf = [];
+ this.lastId = 0;
+ this.buffer = null;
+ this.bufferStack = [];
+ this.scopeClosers = '';
+ this.inBlock = false;
+ this.throwOnUndefined = throwOnUndefined;
+ },
+
+ fail: function (msg, lineno, colno) {
+ if (lineno !== undefined) lineno += 1;
+ if (colno !== undefined) colno += 1;
+
+ throw new lib.TemplateError(msg, lineno, colno);
+ },
+
+ pushBufferId: function(id) {
+ this.bufferStack.push(this.buffer);
+ this.buffer = id;
+ this.emit('var ' + this.buffer + ' = "";');
+ },
+
+ popBufferId: function() {
+ this.buffer = this.bufferStack.pop();
+ },
+
+ emit: function(code) {
+ this.codebuf.push(code);
+ },
+
+ emitLine: function(code) {
+ this.emit(code + '\n');
+ },
+
+ emitLines: function() {
+ lib.each(lib.toArray(arguments), function(line) {
+ this.emitLine(line);
+ }, this);
+ },
+
+ emitFuncBegin: function(name) {
+ this.buffer = 'output';
+ this.scopeClosers = '';
+ this.emitLine('function ' + name + '(env, context, frame, runtime, cb) {');
+ this.emitLine('var lineno = null;');
+ this.emitLine('var colno = null;');
+ this.emitLine('var ' + this.buffer + ' = "";');
+ this.emitLine('try {');
+ },
+
+ emitFuncEnd: function(noReturn) {
+ if(!noReturn) {
+ this.emitLine('cb(null, ' + this.buffer +');');
+ }
+
+ this.closeScopeLevels();
+ this.emitLine('} catch (e) {');
+ this.emitLine(' cb(runtime.handleError(e, lineno, colno));');
+ this.emitLine('}');
+ this.emitLine('}');
+ this.buffer = null;
+ },
+
+ addScopeLevel: function() {
+ this.scopeClosers += '})';
+ },
+
+ closeScopeLevels: function() {
+ this.emitLine(this.scopeClosers + ';');
+ this.scopeClosers = '';
+ },
+
+ withScopedSyntax: function(func) {
+ var scopeClosers = this.scopeClosers;
+ this.scopeClosers = '';
+
+ func.call(this);
+
+ this.closeScopeLevels();
+ this.scopeClosers = scopeClosers;
+ },
+
+ makeCallback: function(res) {
+ var err = this.tmpid();
+
+ return 'function(' + err + (res ? ',' + res : '') + ') {\n' +
+ 'if(' + err + ') { cb(' + err + '); return; }';
+ },
+
+ tmpid: function() {
+ this.lastId++;
+ return 't_' + this.lastId;
+ },
+
+ _templateName: function() {
+ return this.templateName == null? 'undefined' : JSON.stringify(this.templateName);
+ },
+
+ _compileChildren: function(node, frame) {
+ var children = node.children;
+ for(var i=0, l=children.length; i<l; i++) {
+ this.compile(children[i], frame);
+ }
+ },
+
+ _compileAggregate: function(node, frame, startChar, endChar) {
+ if(startChar) {
+ this.emit(startChar);
+ }
+
+ for(var i=0; i<node.children.length; i++) {
+ if(i > 0) {
+ this.emit(',');
+ }
+
+ this.compile(node.children[i], frame);
+ }
+
+ if(endChar) {
+ this.emit(endChar);
+ }
+ },
+
+ _compileExpression: function(node, frame) {
+ // TODO: I'm not really sure if this type check is worth it or
+ // not.
+ this.assertType(
+ node,
+ nodes.Literal,
+ nodes.Symbol,
+ nodes.Group,
+ nodes.Array,
+ nodes.Dict,
+ nodes.FunCall,
+ nodes.Caller,
+ nodes.Filter,
+ nodes.LookupVal,
+ nodes.Compare,
+ nodes.InlineIf,
+ nodes.In,
+ nodes.And,
+ nodes.Or,
+ nodes.Not,
+ nodes.Add,
+ nodes.Concat,
+ nodes.Sub,
+ nodes.Mul,
+ nodes.Div,
+ nodes.FloorDiv,
+ nodes.Mod,
+ nodes.Pow,
+ nodes.Neg,
+ nodes.Pos,
+ nodes.Compare,
+ nodes.NodeList
+ );
+ this.compile(node, frame);
+ },
+
+ assertType: function(node /*, types */) {
+ var types = lib.toArray(arguments).slice(1);
+ var success = false;
+
+ for(var i=0; i<types.length; i++) {
+ if(node instanceof types[i]) {
+ success = true;
+ }
+ }
+
+ if(!success) {
+ this.fail('assertType: invalid type: ' + node.typename,
+ node.lineno,
+ node.colno);
+ }
+ },
+
+ compileCallExtension: function(node, frame, async) {
+ var args = node.args;
+ var contentArgs = node.contentArgs;
+ var autoescape = typeof node.autoescape === 'boolean' ? node.autoescape : true;
+
+ if(!async) {
+ this.emit(this.buffer + ' += runtime.suppressValue(');
+ }
+
+ this.emit('env.getExtension("' + node.extName + '")["' + node.prop + '"](');
+ this.emit('context');
+
+ if(args || contentArgs) {
+ this.emit(',');
+ }
+
+ if(args) {
+ if(!(args instanceof nodes.NodeList)) {
+ this.fail('compileCallExtension: arguments must be a NodeList, ' +
+ 'use `parser.parseSignature`');
+ }
+
+ lib.each(args.children, function(arg, i) {
+ // Tag arguments are passed normally to the call. Note
+ // that keyword arguments are turned into a single js
+ // object as the last argument, if they exist.
+ this._compileExpression(arg, frame);
+
+ if(i !== args.children.length - 1 || contentArgs.length) {
+ this.emit(',');
+ }
+ }, this);
+ }
+
+ if(contentArgs.length) {
+ lib.each(contentArgs, function(arg, i) {
+ if(i > 0) {
+ this.emit(',');
+ }
+
+ if(arg) {
+ var id = this.tmpid();
+
+ this.emitLine('function(cb) {');
+ this.emitLine('if(!cb) { cb = function(err) { if(err) { throw err; }}}');
+ this.pushBufferId(id);
+
+ this.withScopedSyntax(function() {
+ this.compile(arg, frame);
+ this.emitLine('cb(null, ' + id + ');');
+ });
+
+ this.popBufferId();
+ this.emitLine('return ' + id + ';');
+ this.emitLine('}');
+ }
+ else {
+ this.emit('null');
+ }
+ }, this);
+ }
+
+ if(async) {
+ var res = this.tmpid();
+ this.emitLine(', ' + this.makeCallback(res));
+ this.emitLine(this.buffer + ' += runtime.suppressValue(' + res + ', ' + autoescape + ' && env.opts.autoescape);');
+ this.addScopeLevel();
+ }
+ else {
+ this.emit(')');
+ this.emit(', ' + autoescape + ' && env.opts.autoescape);\n');
+ }
+ },
+
+ compileCallExtensionAsync: function(node, frame) {
+ this.compileCallExtension(node, frame, true);
+ },
+
+ compileNodeList: function(node, frame) {
+ this._compileChildren(node, frame);
+ },
+
+ compileLiteral: function(node) {
+ if(typeof node.value === 'string') {
+ var val = node.value.replace(/\\/g, '\\\\');
+ val = val.replace(/"/g, '\\"');
+ val = val.replace(/\n/g, '\\n');
+ val = val.replace(/\r/g, '\\r');
+ val = val.replace(/\t/g, '\\t');
+ this.emit('"' + val + '"');
+ }
+ else if (node.value === null) {
+ this.emit('null');
+ }
+ else {
+ this.emit(node.value.toString());
+ }
+ },
+
+ compileSymbol: function(node, frame) {
+ var name = node.value;
+ var v;
+
+ if((v = frame.lookup(name))) {
+ this.emit(v);
+ }
+ else {
+ this.emit('runtime.contextOrFrameLookup(' +
+ 'context, frame, "' + name + '")');
+ }
+ },
+
+ compileGroup: function(node, frame) {
+ this._compileAggregate(node, frame, '(', ')');
+ },
+
+ compileArray: function(node, frame) {
+ this._compileAggregate(node, frame, '[', ']');
+ },
+
+ compileDict: function(node, frame) {
+ this._compileAggregate(node, frame, '{', '}');
+ },
+
+ compilePair: function(node, frame) {
+ var key = node.key;
+ var val = node.value;
+
+ if(key instanceof nodes.Symbol) {
+ key = new nodes.Literal(key.lineno, key.colno, key.value);
+ }
+ else if(!(key instanceof nodes.Literal &&
+ typeof key.value === 'string')) {
+ this.fail('compilePair: Dict keys must be strings or names',
+ key.lineno,
+ key.colno);
+ }
+
+ this.compile(key, frame);
+ this.emit(': ');
+ this._compileExpression(val, frame);
+ },
+
+ compileInlineIf: function(node, frame) {
+ this.emit('(');
+ this.compile(node.cond, frame);
+ this.emit('?');
+ this.compile(node.body, frame);
+ this.emit(':');
+ if(node.else_ !== null)
+ this.compile(node.else_, frame);
+ else
+ this.emit('""');
+ this.emit(')');
+ },
+
+ compileIn: function(node, frame) {
+ this.emit('runtime.inOperator(');
+ this.compile(node.left, frame);
+ this.emit(',');
+ this.compile(node.right, frame);
+ this.emit(')');
+ },
+
+ compileOr: binOpEmitter(' || '),
+ compileAnd: binOpEmitter(' && '),
+ compileAdd: binOpEmitter(' + '),
+ // ensure concatenation instead of addition
+ // by adding empty string in between
+ compileConcat: binOpEmitter(' + "" + '),
+ compileSub: binOpEmitter(' - '),
+ compileMul: binOpEmitter(' * '),
+ compileDiv: binOpEmitter(' / '),
+ compileMod: binOpEmitter(' % '),
+
+ compileNot: function(node, frame) {
+ this.emit('!');
+ this.compile(node.target, frame);
+ },
+
+ compileFloorDiv: function(node, frame) {
+ this.emit('Math.floor(');
+ this.compile(node.left, frame);
+ this.emit(' / ');
+ this.compile(node.right, frame);
+ this.emit(')');
+ },
+
+ compilePow: function(node, frame) {
+ this.emit('Math.pow(');
+ this.compile(node.left, frame);
+ this.emit(', ');
+ this.compile(node.right, frame);
+ this.emit(')');
+ },
+
+ compileNeg: function(node, frame) {
+ this.emit('-');
+ this.compile(node.target, frame);
+ },
+
+ compilePos: function(node, frame) {
+ this.emit('+');
+ this.compile(node.target, frame);
+ },
+
+ compileCompare: function(node, frame) {
+ this.compile(node.expr, frame);
+
+ for(var i=0; i<node.ops.length; i++) {
+ var n = node.ops[i];
+ this.emit(' ' + compareOps[n.type] + ' ');
+ this.compile(n.expr, frame);
+ }
+ },
+
+ compileLookupVal: function(node, frame) {
+ this.emit('runtime.memberLookup((');
+ this._compileExpression(node.target, frame);
+ this.emit('),');
+ this._compileExpression(node.val, frame);
+ this.emit(')');
+ },
+
+ _getNodeName: function(node) {
+ switch (node.typename) {
+ case 'Symbol':
+ return node.value;
+ case 'FunCall':
+ return 'the return value of (' + this._getNodeName(node.name) + ')';
+ case 'LookupVal':
+ return this._getNodeName(node.target) + '["' +
+ this._getNodeName(node.val) + '"]';
+ case 'Literal':
+ return node.value.toString();
+ default:
+ return '--expression--';
+ }
+ },
+
+ 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('runtime.callWrap(');
+ // Compile it as normal.
+ this._compileExpression(node.name, frame);
+
+ // Output the name of what we're calling so we can get friendly errors
+ // if the lookup fails.
+ this.emit(', "' + this._getNodeName(node.name).replace(/"/g, '\\"') + '", context, ');
+
+ this._compileAggregate(node.args, frame, '[', '])');
+
+ this.emit(')');
+ },
+
+ compileFilter: function(node, frame) {
+ var name = node.name;
+ this.assertType(name, nodes.Symbol);
+ this.emit('env.getFilter("' + name.value + '").call(context, ');
+ this._compileAggregate(node.args, frame);
+ this.emit(')');
+ },
+
+ compileFilterAsync: function(node, frame) {
+ var name = node.name;
+ this.assertType(name, nodes.Symbol);
+
+ var symbol = node.symbol.value;
+ frame.set(symbol, symbol);
+
+ this.emit('env.getFilter("' + name.value + '").call(context, ');
+ this._compileAggregate(node.args, frame);
+ this.emitLine(', ' + this.makeCallback(symbol));
+
+ this.addScopeLevel();
+ },
+
+ compileKeywordArgs: function(node, frame) {
+ var names = [];
+
+ lib.each(node.children, function(pair) {
+ names.push(pair.key.value);
+ });
+
+ this.emit('runtime.makeKeywordArgs(');
+ this.compileDict(node, frame);
+ this.emit(')');
+ },
+
+ compileSet: function(node, frame) {
+ var ids = [];
+
+ // Lookup the variable names for each identifier and create
+ // new ones if necessary
+ lib.each(node.targets, function(target) {
+ var name = target.value;
+ var id = frame.lookup(name);
+
+ if (id === null || id === undefined) {
+ id = this.tmpid();
+
+ // Note: This relies on js allowing scope across
+ // blocks, in case this is created inside an `if`
+ this.emitLine('var ' + id + ';');
+ }
+
+ ids.push(id);
+ }, this);
+
+ if (node.value) {
+ this.emit(ids.join(' = ') + ' = ');
+ this._compileExpression(node.value, frame);
+ this.emitLine(';');
+ }
+ else {
+ this.emit(ids.join(' = ') + ' = ');
+ this.compile(node.body, frame);
+ this.emitLine(';');
+ }
+
+ lib.each(node.targets, function(target, i) {
+ var id = ids[i];
+ var name = target.value;
+
+ // 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);');
+
+ this.emitLine('if(frame.topLevel) {');
+ this.emitLine('context.setVariable("' + name + '", ' + id + ');');
+ this.emitLine('}');
+
+ if(name.charAt(0) !== '_') {
+ this.emitLine('if(frame.topLevel) {');
+ this.emitLine('context.addExport("' + name + '", ' + id + ');');
+ this.emitLine('}');
+ }
+ }, this);
+ },
+
+ compileIf: function(node, frame, async) {
+ this.emit('if(');
+ this._compileExpression(node.cond, frame);
+ this.emitLine(') {');
+
+ this.withScopedSyntax(function() {
+ this.compile(node.body, frame);
+
+ if(async) {
+ this.emit('cb()');
+ }
+ });
+
+ if(node.else_) {
+ this.emitLine('}\nelse {');
+
+ this.withScopedSyntax(function() {
+ this.compile(node.else_, frame);
+
+ if(async) {
+ this.emit('cb()');
+ }
+ });
+ } else if(async) {
+ this.emitLine('}\nelse {');
+ this.emit('cb()');
+ }
+
+ this.emitLine('}');
+ },
+
+ compileIfAsync: function(node, frame) {
+ this.emit('(function(cb) {');
+ this.compileIf(node, frame, true);
+ this.emit('})(' + this.makeCallback());
+ this.addScopeLevel();
+ },
+
+ emitLoopBindings: function(node, arr, i, len) {
+ var bindings = {
+ index: i + ' + 1',
+ index0: i,
+ revindex: len + ' - ' + i,
+ revindex0: len + ' - ' + i + ' - 1',
+ first: i + ' === 0',
+ last: i + ' === ' + len + ' - 1',
+ length: len
+ };
+
+ for (var name in bindings) {
+ this.emitLine('frame.set("loop.' + name + '", ' + bindings[name] + ');');
+ }
+ },
+
+ compileFor: function(node, frame) {
+ // Some of this code is ugly, but it keeps the generated code
+ // as fast as possible. ForAsync also shares some of this, but
+ // not much.
+
+ var v;
+ var i = this.tmpid();
+ var len = this.tmpid();
+ var arr = this.tmpid();
+ frame = frame.push();
+
+ this.emitLine('frame = frame.push();');
+
+ this.emit('var ' + arr + ' = ');
+ this._compileExpression(node.arr, frame);
+ this.emitLine(';');
+
+ this.emit('if(' + arr + ') {');
+
+ // If multiple names are passed, we need to bind them
+ // appropriately
+ if(node.name instanceof nodes.Array) {
+ this.emitLine('var ' + i + ';');
+
+ // The object could be an arroy or object. Note that the
+ // body of the loop is duplicated for each condition, but
+ // we are optimizing for speed over size.
+ this.emitLine('if(runtime.isArray(' + arr + ')) {'); {
+ this.emitLine('var ' + len + ' = ' + arr + '.length;');
+ this.emitLine('for(' + i + '=0; ' + i + ' < ' + arr + '.length; '
+ + i + '++) {');
+
+ // Bind each declared var
+ 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.emitLoopBindings(node, arr, i, len);
+ this.withScopedSyntax(function() {
+ this.compile(node.body, frame);
+ });
+ this.emitLine('}');
+ }
+
+ this.emitLine('} else {'); {
+ // Iterate over the key/values of an object
+ var key = node.name.children[0];
+ var val = node.name.children[1];
+ var k = this.tmpid();
+ v = this.tmpid();
+ frame.set(key.value, k);
+ frame.set(val.value, v);
+
+ this.emitLine(i + ' = -1;');
+ this.emitLine('var ' + len + ' = runtime.keys(' + arr + ').length;');
+ this.emitLine('for(var ' + k + ' in ' + arr + ') {');
+ this.emitLine(i + '++;');
+ this.emitLine('var ' + v + ' = ' + arr + '[' + k + '];');
+ this.emitLine('frame.set("' + key.value + '", ' + k + ');');
+ this.emitLine('frame.set("' + val.value + '", ' + v + ');');
+
+ this.emitLoopBindings(node, arr, i, len);
+ this.withScopedSyntax(function() {
+ this.compile(node.body, frame);
+ });
+ this.emitLine('}');
+ }
+
+ this.emitLine('}');
+ }
+ else {
+ // Generate a typical array iteration
+ v = this.tmpid();
+ frame.set(node.name.value, v);
+
+ this.emitLine('var ' + len + ' = ' + arr + '.length;');
+ this.emitLine('for(var ' + i + '=0; ' + i + ' < ' + arr + '.length; ' +
+ i + '++) {');
+ this.emitLine('var ' + v + ' = ' + arr + '[' + i + '];');
+ this.emitLine('frame.set("' + node.name.value + '", ' + v + ');');
+
+ this.emitLoopBindings(node, arr, i, len);
+
+ this.withScopedSyntax(function() {
+ this.compile(node.body, frame);
+ });
+
+ this.emitLine('}');
+ }
+
+ this.emitLine('}');
+ if (node.else_) {
+ this.emitLine('if (!' + len + ') {');
+ this.compile(node.else_, frame);
+ this.emitLine('}');
+ }
+
+ this.emitLine('frame = frame.pop();');
+ },
+
+ _compileAsyncLoop: function(node, frame, parallel) {
+ // This shares some code with the For tag, but not enough to
+ // worry about. This iterates across an object asynchronously,
+ // but not in parallel.
+
+ var i = this.tmpid();
+ var len = this.tmpid();
+ var arr = this.tmpid();
+ var asyncMethod = parallel ? 'asyncAll' : 'asyncEach';
+ frame = frame.push();
+
+ this.emitLine('frame = frame.push();');
+
+ this.emit('var ' + arr + ' = ');
+ this._compileExpression(node.arr, frame);
+ this.emitLine(';');
+
+ if(node.name instanceof nodes.Array) {
+ this.emit('runtime.' + asyncMethod + '(' + arr + ', ' +
+ node.name.children.length + ', function(');
+
+ lib.each(node.name.children, function(name) {
+ this.emit(name.value + ',');
+ }, this);
+
+ this.emit(i + ',' + len + ',next) {');
+
+ lib.each(node.name.children, function(name) {
+ var id = name.value;
+ frame.set(id, id);
+ this.emitLine('frame.set("' + id + '", ' + id + ');');
+ }, this);
+ }
+ else {
+ var id = node.name.value;
+ this.emitLine('runtime.' + asyncMethod + '(' + arr + ', 1, function(' + id + ', ' + i + ', ' + len + ',next) {');
+ this.emitLine('frame.set("' + id + '", ' + id + ');');
+ frame.set(id, id);
+ }
+
+ this.emitLoopBindings(node, arr, i, len);
+
+ this.withScopedSyntax(function() {
+ var buf;
+ if(parallel) {
+ buf = this.tmpid();
+ this.pushBufferId(buf);
+ }
+
+ this.compile(node.body, frame);
+ this.emitLine('next(' + i + (buf ? ',' + buf : '') + ');');
+
+ if(parallel) {
+ this.popBufferId();
+ }
+ });
+
+ var output = this.tmpid();
+ this.emitLine('}, ' + this.makeCallback(output));
+ this.addScopeLevel();
+
+ if(parallel) {
+ this.emitLine(this.buffer + ' += ' + output + ';');
+ }
+
+ if (node.else_) {
+ this.emitLine('if (!' + arr + '.length) {');
+ this.compile(node.else_, frame);
+ this.emitLine('}');
+ }
+
+ this.emitLine('frame = frame.pop();');
+ },
+
+ compileAsyncEach: function(node, frame) {
+ this._compileAsyncLoop(node, frame);
+ },
+
+ compileAsyncAll: function(node, frame) {
+ this._compileAsyncLoop(node, frame, true);
+ },
+
+ _compileMacro: function(node) {
+ var args = [];
+ var kwargs = null;
+ var funcId = 'macro_' + this.tmpid();
+
+ // Type check the definition of the args
+ lib.each(node.args.children, function(arg, i) {
+ if(i === node.args.children.length - 1 &&
+ arg instanceof nodes.Dict) {
+ kwargs = arg;
+ }
+ else {
+ this.assertType(arg, nodes.Symbol);
+ args.push(arg);
+ }
+ }, this);
+
+ var realNames = lib.map(args, function(n) { return 'l_' + n.value; });
+ realNames.push('kwargs');
+
+ // Quoted argument names
+ var argNames = lib.map(args, function(n) { return '"' + n.value + '"'; });
+ var kwargNames = lib.map((kwargs && kwargs.children) || [],
+ function(n) { return '"' + n.key.value + '"'; });
+
+ // We pass a function to makeMacro which destructures the
+ // arguments so support setting positional args with keywords
+ // args and passing keyword args as positional args
+ // (essentially default values). See runtime.js.
+ var frame = new Frame();
+ this.emitLines(
+ 'var ' + funcId + ' = runtime.makeMacro(',
+ '[' + argNames.join(', ') + '], ',
+ '[' + kwargNames.join(', ') + '], ',
+ 'function (' + realNames.join(', ') + ') {',
+ 'var callerFrame = frame;',
+ 'frame = new runtime.Frame();',
+ 'kwargs = kwargs || {};',
+ 'if (kwargs.hasOwnProperty("caller")) {',
+ 'frame.set("caller", kwargs.caller); }'
+ );
+
+ // Expose the arguments to the template. Don't need to use
+ // random names because the function
+ // will create a new run-time scope for us
+ lib.each(args, function(arg) {
+ this.emitLine('frame.set("' + arg.value + '", ' +
+ 'l_' + arg.value + ');');
+ frame.set(arg.value, 'l_' + arg.value);
+ }, this);
+
+ // Expose the keyword arguments
+ if(kwargs) {
+ lib.each(kwargs.children, function(pair) {
+ var name = pair.key.value;
+ this.emit('frame.set("' + name + '", ' +
+ 'kwargs.hasOwnProperty("' + name + '") ? ' +
+ 'kwargs["' + name + '"] : ');
+ this._compileExpression(pair.value, frame);
+ this.emitLine(');');
+ }, this);
+ }
+
+ var bufferId = this.tmpid();
+ this.pushBufferId(bufferId);
+
+ this.withScopedSyntax(function () {
+ this.compile(node.body, frame);
+ });
+
+ this.emitLine('frame = callerFrame;');
+ this.emitLine('return new runtime.SafeString(' + bufferId + ');');
+ this.emitLine('});');
+ this.popBufferId();
+
+ return funcId;
+ },
+
+ compileMacro: function(node, frame) {
+ var funcId = this._compileMacro(node, frame);
+
+ // Expose the macro to the templates
+ var name = node.name.value;
+ frame.set(name, funcId);
+
+ if(frame.parent) {
+ this.emitLine('frame.set("' + name + '", ' + funcId + ');');
+ }
+ else {
+ if(node.name.value.charAt(0) !== '_') {
+ this.emitLine('context.addExport("' + name + '");');
+ }
+ this.emitLine('context.setVariable("' + name + '", ' + funcId + ');');
+ }
+ },
+
+ compileCaller: function(node, frame) {
+ // basically an anonymous "macro expression"
+ this.emit('(function (){');
+ var funcId = this._compileMacro(node, frame);
+ this.emit('return ' + funcId + ';})()');
+ },
+
+ compileImport: function(node, frame) {
+ var id = this.tmpid();
+ var target = node.target.value;
+
+ this.emit('env.getTemplate(');
+ this._compileExpression(node.template, frame);
+ this.emitLine(', false, '+this._templateName()+', false, ' + this.makeCallback(id));
+ this.addScopeLevel();
+
+ this.emitLine(id + '.getExported(' +
+ (node.withContext ? 'context.getVariables(), frame, ' : '') +
+ this.makeCallback(id));
+ this.addScopeLevel();
+
+ frame.set(target, id);
+
+ if(frame.parent) {
+ this.emitLine('frame.set("' + target + '", ' + id + ');');
+ }
+ else {
+ this.emitLine('context.setVariable("' + target + '", ' + id + ');');
+ }
+ },
+
+ compileFromImport: function(node, frame) {
+ var importedId = this.tmpid();
+
+ this.emit('env.getTemplate(');
+ this._compileExpression(node.template, frame);
+ this.emitLine(', false, '+this._templateName()+', false, ' + this.makeCallback(importedId));
+ this.addScopeLevel();
+
+ this.emitLine(importedId + '.getExported(' +
+ (node.withContext ? 'context.getVariables(), frame, ' : '') +
+ this.makeCallback(importedId));
+ this.addScopeLevel();
+
+ lib.each(node.names.children, function(nameNode) {
+ var name;
+ var alias;
+ var id = this.tmpid();
+
+ if(nameNode instanceof nodes.Pair) {
+ name = nameNode.key.value;
+ alias = nameNode.value.value;
+ }
+ else {
+ name = nameNode.value;
+ alias = name;
+ }
+
+ this.emitLine('if(' + importedId + '.hasOwnProperty("' + name + '")) {');
+ this.emitLine('var ' + id + ' = ' + importedId + '.' + name + ';');
+ this.emitLine('} else {');
+ this.emitLine('cb(new Error("cannot import \'' + name + '\'")); return;');
+ this.emitLine('}');
+
+ frame.set(alias, id);
+
+ if(frame.parent) {
+ this.emitLine('frame.set("' + alias + '", ' + id + ');');
+ }
+ else {
+ this.emitLine('context.setVariable("' + alias + '", ' + id + ');');
+ }
+ }, this);
+ },
+
+ compileBlock: function(node) {
+ var id = this.tmpid();
+
+ // 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();
+ },
+
+ compileSuper: function(node, frame) {
+ var name = node.blockName.value;
+ var id = node.symbol.value;
+
+ this.emitLine('context.getSuper(env, ' +
+ '"' + name + '", ' +
+ 'b_' + name + ', ' +
+ 'frame, runtime, '+
+ this.makeCallback(id));
+ this.emitLine(id + ' = runtime.markSafe(' + id + ');');
+ this.addScopeLevel();
+ frame.set(id, id);
+ },
+
+ compileExtends: function(node, frame) {
+ var k = this.tmpid();
+
+ this.emit('env.getTemplate(');
+ this._compileExpression(node.template, frame);
+ this.emitLine(', true, '+this._templateName()+', false, ' + 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) {');
+ this.emitLine('context.addBlock(' + k +
+ ', parentTemplate.blocks[' + k + ']);');
+ this.emitLine('}');
+
+ this.addScopeLevel();
+ },
+
+ compileInclude: function(node, frame) {
+ var id = this.tmpid();
+ var id2 = this.tmpid();
+
+ this.emitLine('var tasks = [];');
+ this.emitLine('tasks.push(');
+ this.emitLine('function(callback) {');
+ this.emit('env.getTemplate(');
+ this._compileExpression(node.template, frame);
+ this.emitLine(', false, '+this._templateName()+', ' + node.ignoreMissing + ', ' + this.makeCallback(id));
+ this.emitLine('callback(null,' + id + ');});');
+ this.emitLine('});');
+
+ this.emitLine('tasks.push(');
+ this.emitLine('function(template, callback){');
+ this.emitLine('template.render(' +
+ 'context.getVariables(), frame, ' + this.makeCallback(id2));
+ this.emitLine('callback(null,' + id2 + ');});');
+ this.emitLine('});');
+
+ this.emitLine('tasks.push(');
+ this.emitLine('function(result, callback){');
+ this.emitLine(this.buffer + ' += result;');
+ this.emitLine('callback(null);');
+ this.emitLine('});');
+ this.emitLine('env.waterfall(tasks, function(){');
+ this.addScopeLevel();
+ },
+
+ compileTemplateData: function(node, frame) {
+ this.compileLiteral(node, frame);
+ },
+
+ compileCapture: function(node, frame) {
+ this.emitLine('(function() {');
+ this.emitLine('var output = "";');
+ this.withScopedSyntax(function () {
+ this.compile(node.body, frame);
+ });
+ this.emitLine('return output;');
+ this.emitLine('})()');
+ },
+
+ compileOutput: function(node, frame) {
+ var children = node.children;
+ for(var i=0, l=children.length; i<l; i++) {
+ // TemplateData is a special case because it is never
+ // autoescaped, so simply output it for optimization
+ if(children[i] instanceof nodes.TemplateData) {
+ if(children[i].value) {
+ this.emit(this.buffer + ' += ');
+ this.compileLiteral(children[i], frame);
+ this.emitLine(';');
+ }
+ }
+ else {
+ 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');
+ }
+ }
+ },
+
+ compileRoot: function(node, frame) {
+ if(frame) {
+ this.fail('compileRoot: root node can\'t have frame');
+ }
+
+ frame = new Frame();
+
+ this.emitFuncBegin('root');
+ this.emitLine('var parentTemplate = null;');
+ this._compileChildren(node, frame);
+ 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);
+
+ this.inBlock = true;
+
+ var blockNames = [];
+
+ var i, name, block, blocks = node.findAll(nodes.Block);
+ for (i = 0; i < blocks.length; i++) {
+ block = blocks[i];
+ name = block.name.value;
+
+ if (blockNames.indexOf(name) !== -1) {
+ throw new Error('Block "' + name + '" defined more than once.');
+ }
+ blockNames.push(name);
+
+ this.emitFuncBegin('b_' + name);
+
+ var tmpFrame = new Frame();
+ this.emitLine('var frame = frame.push(true);');
+ this.compile(block.body, tmpFrame);
+ this.emitFuncEnd();
+ }
+
+ this.emitLine('return {');
+ for (i = 0; i < blocks.length; i++) {
+ block = blocks[i];
+ name = 'b_' + block.name.value;
+ this.emitLine(name + ': ' + name + ',');
+ }
+ this.emitLine('root: root\n};');
+ },
+
+ compile: function (node, frame) {
+ var _compile = this['compile' + node.typename];
+ if(_compile) {
+ _compile.call(this, node, frame);
+ }
+ else {
+ this.fail('compile: Cannot compile node: ' + node.typename,
+ node.lineno,
+ node.colno);
+ }
+ },
+
+ getCode: function() {
+ return this.codebuf.join('');
+ }
+ });
+
+ // var c = new Compiler();
+ // var src = 'hello {% filter title %}' +
+ // 'Hello madam how are you' +
+ // '{% endfilter %}'
+ // var ast = transformer.transform(parser.parse(src));
+ // nodes.printNodes(ast);
+ // c.compile(ast);
+ // var tmpl = c.getCode();
+ // console.log(tmpl);
+
+ module.exports = {
+ compile: function(src, asyncFilters, extensions, name, opts) {
+ var c = new Compiler(name, opts.throwOnUndefined);
+
+ // Run the extension preprocessors against the source.
+ if(extensions && extensions.length) {
+ for(var i=0; i<extensions.length; i++) {
+ if('preprocess' in extensions[i]) {
+ src = extensions[i].preprocess(src, name);
+ }
+ }
+ }
+
+ c.compile(transformer.transform(
+ parser.parse(src,
+ extensions,
+ opts),
+ asyncFilters,
+ name
+ ));
+ return c.getCode();
+ },
+
+ Compiler: Compiler
+ };
+
+
+/***/ },
+/* 8 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lexer = __webpack_require__(9);
+ var nodes = __webpack_require__(10);
+ // jshint -W079
+ var Object = __webpack_require__(6);
+ var lib = __webpack_require__(1);
+
+ var Parser = Object.extend({
+ init: function (tokens) {
+ this.tokens = tokens;
+ this.peeked = null;
+ this.breakOnBlocks = null;
+ this.dropLeadingWhitespace = false;
+
+ this.extensions = [];
+ },
+
+ nextToken: function (withWhitespace) {
+ var tok;
+
+ if(this.peeked) {
+ if(!withWhitespace && this.peeked.type === lexer.TOKEN_WHITESPACE) {
+ this.peeked = null;
+ }
+ else {
+ tok = this.peeked;
+ this.peeked = null;
+ return tok;
+ }
+ }
+
+ tok = this.tokens.nextToken();
+
+ if(!withWhitespace) {
+ while(tok && tok.type === lexer.TOKEN_WHITESPACE) {
+ tok = this.tokens.nextToken();
+ }
+ }
+
+ return tok;
+ },
+
+ peekToken: function () {
+ this.peeked = this.peeked || this.nextToken();
+ return this.peeked;
+ },
+
+ pushToken: function(tok) {
+ if(this.peeked) {
+ throw new Error('pushToken: can only push one token on between reads');
+ }
+ this.peeked = tok;
+ },
+
+ fail: function (msg, lineno, colno) {
+ if((lineno === undefined || colno === undefined) && this.peekToken()) {
+ var tok = this.peekToken();
+ lineno = tok.lineno;
+ colno = tok.colno;
+ }
+ if (lineno !== undefined) lineno += 1;
+ if (colno !== undefined) colno += 1;
+
+ throw new lib.TemplateError(msg, lineno, colno);
+ },
+
+ skip: function(type) {
+ var tok = this.nextToken();
+ if(!tok || tok.type !== type) {
+ this.pushToken(tok);
+ return false;
+ }
+ return true;
+ },
+
+ expect: function(type) {
+ var tok = this.nextToken();
+ if(tok.type !== type) {
+ this.fail('expected ' + type + ', got ' + tok.type,
+ tok.lineno,
+ tok.colno);
+ }
+ return tok;
+ },
+
+ skipValue: function(type, val) {
+ var tok = this.nextToken();
+ if(!tok || tok.type !== type || tok.value !== val) {
+ this.pushToken(tok);
+ return false;
+ }
+ return true;
+ },
+
+ skipSymbol: function(val) {
+ return this.skipValue(lexer.TOKEN_SYMBOL, val);
+ },
+
+ advanceAfterBlockEnd: function(name) {
+ var tok;
+ if(!name) {
+ tok = this.peekToken();
+
+ if(!tok) {
+ this.fail('unexpected end of file');
+ }
+
+ if(tok.type !== lexer.TOKEN_SYMBOL) {
+ this.fail('advanceAfterBlockEnd: expected symbol token or ' +
+ 'explicit name to be passed');
+ }
+
+ name = this.nextToken().value;
+ }
+
+ tok = this.nextToken();
+
+ if(tok && tok.type === lexer.TOKEN_BLOCK_END) {
+ if(tok.value.charAt(0) === '-') {
+ this.dropLeadingWhitespace = true;
+ }
+ }
+ else {
+ this.fail('expected block end in ' + name + ' statement');
+ }
+
+ return tok;
+ },
+
+ advanceAfterVariableEnd: function() {
+ var tok = this.nextToken();
+
+ if(tok && tok.type === lexer.TOKEN_VARIABLE_END) {
+ this.dropLeadingWhitespace = tok.value.charAt(
+ tok.value.length - this.tokens.tags.VARIABLE_END.length - 1
+ ) === '-';
+ } else {
+ this.pushToken(tok);
+ this.fail('expected variable end');
+ }
+ },
+
+ parseFor: function() {
+ var forTok = this.peekToken();
+ var node;
+ var endBlock;
+
+ if(this.skipSymbol('for')) {
+ node = new nodes.For(forTok.lineno, forTok.colno);
+ endBlock = 'endfor';
+ }
+ else if(this.skipSymbol('asyncEach')) {
+ node = new nodes.AsyncEach(forTok.lineno, forTok.colno);
+ endBlock = 'endeach';
+ }
+ else if(this.skipSymbol('asyncAll')) {
+ node = new nodes.AsyncAll(forTok.lineno, forTok.colno);
+ endBlock = 'endall';
+ }
+ else {
+ this.fail('parseFor: expected for{Async}', forTok.lineno, forTok.colno);
+ }
+
+ node.name = this.parsePrimary();
+
+ if(!(node.name instanceof nodes.Symbol)) {
+ this.fail('parseFor: variable name expected for loop');
+ }
+
+ 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);
+
+ while(this.skip(lexer.TOKEN_COMMA)) {
+ var prim = this.parsePrimary();
+ node.name.addChild(prim);
+ }
+ }
+
+ if(!this.skipSymbol('in')) {
+ this.fail('parseFor: expected "in" keyword for loop',
+ forTok.lineno,
+ forTok.colno);
+ }
+
+ node.arr = this.parseExpression();
+ this.advanceAfterBlockEnd(forTok.value);
+
+ node.body = this.parseUntilBlocks(endBlock, 'else');
+
+ if(this.skipSymbol('else')) {
+ this.advanceAfterBlockEnd('else');
+ node.else_ = this.parseUntilBlocks(endBlock);
+ }
+
+ this.advanceAfterBlockEnd();
+
+ return node;
+ },
+
+ parseMacro: function() {
+ var macroTok = this.peekToken();
+ if(!this.skipSymbol('macro')) {
+ this.fail('expected macro');
+ }
+
+ var name = this.parsePrimary(true);
+ var args = this.parseSignature();
+ var node = new nodes.Macro(macroTok.lineno,
+ macroTok.colno,
+ name,
+ args);
+
+ this.advanceAfterBlockEnd(macroTok.value);
+ node.body = this.parseUntilBlocks('endmacro');
+ this.advanceAfterBlockEnd();
+
+ return node;
+ },
+
+ parseCall: function() {
+ // a call block is parsed as a normal FunCall, but with an added
+ // 'caller' kwarg which is a Caller node.
+ var callTok = this.peekToken();
+ if(!this.skipSymbol('call')) {
+ this.fail('expected call');
+ }
+
+ var callerArgs = this.parseSignature(true) || new nodes.NodeList();
+ var macroCall = this.parsePrimary();
+
+ this.advanceAfterBlockEnd(callTok.value);
+ var body = this.parseUntilBlocks('endcall');
+ this.advanceAfterBlockEnd();
+
+ var callerName = new nodes.Symbol(callTok.lineno,
+ callTok.colno,
+ 'caller');
+ var callerNode = new nodes.Caller(callTok.lineno,
+ callTok.colno,
+ callerName,
+ callerArgs,
+ body);
+
+ // add the additional caller kwarg, adding kwargs if necessary
+ var args = macroCall.args.children;
+ if (!(args[args.length-1] instanceof nodes.KeywordArgs)) {
+ args.push(new nodes.KeywordArgs());
+ }
+ var kwargs = args[args.length - 1];
+ kwargs.addChild(new nodes.Pair(callTok.lineno,
+ callTok.colno,
+ callerName,
+ callerNode));
+
+ return new nodes.Output(callTok.lineno,
+ callTok.colno,
+ [macroCall]);
+ },
+
+ parseWithContext: function() {
+ var tok = this.peekToken();
+
+ var withContext = null;
+
+ if(this.skipSymbol('with')) {
+ withContext = true;
+ }
+ else if(this.skipSymbol('without')) {
+ withContext = false;
+ }
+
+ if(withContext !== null) {
+ if(!this.skipSymbol('context')) {
+ this.fail('parseFrom: expected context after with/without',
+ tok.lineno,
+ tok.colno);
+ }
+ }
+
+ return withContext;
+ },
+
+ parseImport: function() {
+ var importTok = this.peekToken();
+ if(!this.skipSymbol('import')) {
+ this.fail('parseImport: expected import',
+ importTok.lineno,
+ importTok.colno);
+ }
+
+ var template = this.parseExpression();
+
+ if(!this.skipSymbol('as')) {
+ this.fail('parseImport: expected "as" keyword',
+ importTok.lineno,
+ importTok.colno);
+ }
+
+ var target = this.parseExpression();
+
+ var withContext = this.parseWithContext();
+
+ var node = new nodes.Import(importTok.lineno,
+ importTok.colno,
+ template,
+ target,
+ withContext);
+
+ this.advanceAfterBlockEnd(importTok.value);
+
+ return node;
+ },
+
+ parseFrom: function() {
+ var fromTok = this.peekToken();
+ if(!this.skipSymbol('from')) {
+ this.fail('parseFrom: expected from');
+ }
+
+ var template = this.parseExpression();
+
+ if(!this.skipSymbol('import')) {
+ this.fail('parseFrom: expected import',
+ fromTok.lineno,
+ fromTok.colno);
+ }
+
+ var names = new nodes.NodeList(),
+ withContext;
+
+ while(1) {
+ 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;
+ }
+
+ if(names.children.length > 0 && !this.skip(lexer.TOKEN_COMMA)) {
+ this.fail('parseFrom: expected comma',
+ fromTok.lineno,
+ fromTok.colno);
+ }
+
+ var name = this.parsePrimary();
+ if(name.value.charAt(0) === '_') {
+ this.fail('parseFrom: names starting with an underscore ' +
+ 'cannot be imported',
+ name.lineno,
+ name.colno);
+ }
+
+ if(this.skipSymbol('as')) {
+ var alias = this.parsePrimary();
+ names.addChild(new nodes.Pair(name.lineno,
+ name.colno,
+ name,
+ alias));
+ }
+ else {
+ names.addChild(name);
+ }
+
+ withContext = this.parseWithContext();
+ }
+
+ return new nodes.FromImport(fromTok.lineno,
+ fromTok.colno,
+ template,
+ names,
+ withContext);
+ },
+
+ parseBlock: function() {
+ var tag = this.peekToken();
+ if(!this.skipSymbol('block')) {
+ this.fail('parseBlock: expected block', tag.lineno, tag.colno);
+ }
+
+ var node = new nodes.Block(tag.lineno, tag.colno);
+
+ node.name = this.parsePrimary();
+ if(!(node.name instanceof nodes.Symbol)) {
+ this.fail('parseBlock: variable name expected',
+ tag.lineno,
+ tag.colno);
+ }
+
+ this.advanceAfterBlockEnd(tag.value);
+
+ node.body = this.parseUntilBlocks('endblock');
+ this.skipSymbol('endblock');
+ this.skipSymbol(node.name.value);
+
+ var tok = this.peekToken();
+ if(!tok) {
+ this.fail('parseBlock: expected endblock, got end of file');
+ }
+
+ this.advanceAfterBlockEnd(tok.value);
+
+ return node;
+ },
+
+ parseExtends: function() {
+ var tagName = 'extends';
+ var tag = this.peekToken();
+ if(!this.skipSymbol(tagName)) {
+ this.fail('parseTemplateRef: expected '+ tagName);
+ }
+
+ var node = new nodes.Extends(tag.lineno, tag.colno);
+ node.template = this.parseExpression();
+
+ this.advanceAfterBlockEnd(tag.value);
+ return node;
+ },
+
+ parseInclude: function() {
+ var tagName = 'include';
+ var tag = this.peekToken();
+ if(!this.skipSymbol(tagName)) {
+ this.fail('parseInclude: expected '+ tagName);
+ }
+
+ var node = new nodes.Include(tag.lineno, tag.colno);
+ node.template = this.parseExpression();
+
+ if(this.skipSymbol('ignore') && this.skipSymbol('missing')) {
+ node.ignoreMissing = true;
+ }
+
+ this.advanceAfterBlockEnd(tag.value);
+ return node;
+ },
+
+ parseIf: function() {
+ var tag = this.peekToken();
+ var node;
+
+ if(this.skipSymbol('if') || this.skipSymbol('elif') || this.skipSymbol('elseif')) {
+ node = new nodes.If(tag.lineno, tag.colno);
+ }
+ else if(this.skipSymbol('ifAsync')) {
+ node = new nodes.IfAsync(tag.lineno, tag.colno);
+ }
+ else {
+ this.fail('parseIf: expected if, elif, or elseif',
+ tag.lineno,
+ tag.colno);
+ }
+
+ node.cond = this.parseExpression();
+ this.advanceAfterBlockEnd(tag.value);
+
+ node.body = this.parseUntilBlocks('elif', 'elseif', 'else', 'endif');
+ var tok = this.peekToken();
+
+ switch(tok && tok.value) {
+ case 'elseif':
+ case 'elif':
+ node.else_ = this.parseIf();
+ break;
+ case 'else':
+ this.advanceAfterBlockEnd();
+ node.else_ = this.parseUntilBlocks('endif');
+ this.advanceAfterBlockEnd();
+ break;
+ case 'endif':
+ node.else_ = null;
+ this.advanceAfterBlockEnd();
+ break;
+ default:
+ this.fail('parseIf: expected elif, else, or endif, ' +
+ 'got end of file');
+ }
+
+ return node;
+ },
+
+ parseSet: function() {
+ var tag = this.peekToken();
+ if(!this.skipSymbol('set')) {
+ this.fail('parseSet: expected set', tag.lineno, tag.colno);
+ }
+
+ var node = new nodes.Set(tag.lineno, tag.colno, []);
+
+ var target;
+ while((target = this.parsePrimary())) {
+ node.targets.push(target);
+
+ if(!this.skip(lexer.TOKEN_COMMA)) {
+ break;
+ }
+ }
+
+ if(!this.skipValue(lexer.TOKEN_OPERATOR, '=')) {
+ if (!this.skip(lexer.TOKEN_BLOCK_END)) {
+ this.fail('parseSet: expected = or block end in set tag',
+ tag.lineno,
+ tag.colno);
+ }
+ else {
+ node.body = new nodes.Capture(
+ tag.lineno,
+ tag.colno,
+ this.parseUntilBlocks('endset')
+ );
+ node.value = null;
+ this.advanceAfterBlockEnd();
+ }
+ }
+ else {
+ node.value = this.parseExpression();
+ this.advanceAfterBlockEnd(tag.value);
+ }
+
+ return node;
+ },
+
+ parseStatement: function () {
+ var tok = this.peekToken();
+ var node;
+
+ if(tok.type !== lexer.TOKEN_SYMBOL) {
+ this.fail('tag name expected', tok.lineno, tok.colno);
+ }
+
+ if(this.breakOnBlocks &&
+ lib.indexOf(this.breakOnBlocks, tok.value) !== -1) {
+ return null;
+ }
+
+ switch(tok.value) {
+ case 'raw': return this.parseRaw();
+ case 'verbatim': return this.parseRaw('verbatim');
+ case 'if':
+ case 'ifAsync':
+ return this.parseIf();
+ case 'for':
+ case 'asyncEach':
+ case 'asyncAll':
+ return this.parseFor();
+ case 'block': return this.parseBlock();
+ case 'extends': return this.parseExtends();
+ case 'include': return this.parseInclude();
+ case 'set': return this.parseSet();
+ case 'macro': return this.parseMacro();
+ case 'call': return this.parseCall();
+ case 'import': return this.parseImport();
+ case 'from': return this.parseFrom();
+ case 'filter': return this.parseFilterStatement();
+ default:
+ if (this.extensions.length) {
+ for (var i = 0; i < this.extensions.length; i++) {
+ var ext = this.extensions[i];
+ if (lib.indexOf(ext.tags || [], tok.value) !== -1) {
+ return ext.parse(this, nodes, lexer);
+ }
+ }
+ }
+ this.fail('unknown block tag: ' + tok.value, tok.lineno, tok.colno);
+ }
+
+ return node;
+ },
+
+ parseRaw: function(tagName) {
+ tagName = tagName || 'raw';
+ var endTagName = 'end' + tagName;
+ // Look for upcoming raw blocks (ignore all other kinds of blocks)
+ var rawBlockRegex = new RegExp('([\\s\\S]*?){%\\s*(' + tagName + '|' + endTagName + ')\\s*(?=%})%}');
+ var rawLevel = 1;
+ var str = '';
+ var matches = null;
+
+ // Skip opening raw token
+ // Keep this token to track line and column numbers
+ var begun = this.advanceAfterBlockEnd();
+
+ // Exit when there's nothing to match
+ // or when we've found the matching "endraw" block
+ while((matches = this.tokens._extractRegex(rawBlockRegex)) && rawLevel > 0) {
+ var all = matches[0];
+ var pre = matches[1];
+ var blockName = matches[2];
+
+ // Adjust rawlevel
+ if(blockName === tagName) {
+ rawLevel += 1;
+ } else if(blockName === endTagName) {
+ rawLevel -= 1;
+ }
+
+ // 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;
+ }
+ }
+
+ return new nodes.Output(
+ begun.lineno,
+ begun.colno,
+ [new nodes.TemplateData(begun.lineno, begun.colno, str)]
+ );
+ },
+
+ parsePostfix: function(node) {
+ var lookup, tok = this.peekToken();
+
+ while(tok) {
+ if(tok.type === lexer.TOKEN_LEFT_PAREN) {
+ // Function call
+ node = new nodes.FunCall(tok.lineno,
+ tok.colno,
+ node,
+ this.parseSignature());
+ }
+ else if(tok.type === lexer.TOKEN_LEFT_BRACKET) {
+ // Reference
+ lookup = this.parseAggregate();
+ if(lookup.children.length > 1) {
+ this.fail('invalid index');
+ }
+
+ node = new nodes.LookupVal(tok.lineno,
+ tok.colno,
+ node,
+ lookup.children[0]);
+ }
+ else if(tok.type === lexer.TOKEN_OPERATOR && tok.value === '.') {
+ // Reference
+ this.nextToken();
+ var val = this.nextToken();
+
+ if(val.type !== lexer.TOKEN_SYMBOL) {
+ this.fail('expected name as lookup value, got ' + val.value,
+ val.lineno,
+ val.colno);
+ }
+
+ // Make a literal string because it's not a variable
+ // reference
+ lookup = new nodes.Literal(val.lineno,
+ val.colno,
+ val.value);
+
+ node = new nodes.LookupVal(tok.lineno,
+ tok.colno,
+ node,
+ lookup);
+ }
+ else {
+ break;
+ }
+
+ tok = this.peekToken();
+ }
+
+ return node;
+ },
+
+ parseExpression: function() {
+ var node = this.parseInlineIf();
+ return node;
+ },
+
+ parseInlineIf: function() {
+ var node = this.parseOr();
+ if(this.skipSymbol('if')) {
+ var cond_node = this.parseOr();
+ var body_node = node;
+ node = new nodes.InlineIf(node.lineno, node.colno);
+ node.body = body_node;
+ node.cond = cond_node;
+ if(this.skipSymbol('else')) {
+ node.else_ = this.parseOr();
+ } else {
+ node.else_ = null;
+ }
+ }
+
+ return node;
+ },
+
+ parseOr: function() {
+ var node = this.parseAnd();
+ while(this.skipSymbol('or')) {
+ var node2 = this.parseAnd();
+ node = new nodes.Or(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseAnd: function() {
+ var node = this.parseNot();
+ while(this.skipSymbol('and')) {
+ var node2 = this.parseNot();
+ node = new nodes.And(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseNot: function() {
+ var tok = this.peekToken();
+ if(this.skipSymbol('not')) {
+ return new nodes.Not(tok.lineno,
+ tok.colno,
+ this.parseNot());
+ }
+ return this.parseIn();
+ },
+
+ parseIn: function() {
+ var node = this.parseCompare();
+ while(1) {
+ // check if the next token is 'not'
+ var tok = this.nextToken();
+ if (!tok) { break; }
+ var invert = tok.type === lexer.TOKEN_SYMBOL && tok.value === 'not';
+ // if it wasn't 'not', put it back
+ if (!invert) { this.pushToken(tok); }
+ if (this.skipSymbol('in')) {
+ var node2 = this.parseCompare();
+ node = new nodes.In(node.lineno,
+ node.colno,
+ node,
+ node2);
+ if (invert) {
+ node = new nodes.Not(node.lineno,
+ node.colno,
+ node);
+ }
+ }
+ else {
+ // if we'd found a 'not' but this wasn't an 'in', put back the 'not'
+ if (invert) { this.pushToken(tok); }
+ break;
+ }
+ }
+ return node;
+ },
+
+ parseCompare: function() {
+ var compareOps = ['==', '===', '!=', '!==', '<', '>', '<=', '>='];
+ var expr = this.parseConcat();
+ var ops = [];
+
+ while(1) {
+ var tok = this.nextToken();
+
+ if(!tok) {
+ break;
+ }
+ else if(lib.indexOf(compareOps, tok.value) !== -1) {
+ ops.push(new nodes.CompareOperand(tok.lineno,
+ tok.colno,
+ this.parseConcat(),
+ tok.value));
+ }
+ else {
+ this.pushToken(tok);
+ break;
+ }
+ }
+
+ if(ops.length) {
+ return new nodes.Compare(ops[0].lineno,
+ ops[0].colno,
+ expr,
+ ops);
+ }
+ else {
+ return expr;
+ }
+ },
+
+ // 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() {
+ var node = this.parseSub();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '+')) {
+ var node2 = this.parseSub();
+ node = new nodes.Add(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseSub: function() {
+ var node = this.parseMul();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '-')) {
+ var node2 = this.parseMul();
+ node = new nodes.Sub(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseMul: function() {
+ var node = this.parseDiv();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '*')) {
+ var node2 = this.parseDiv();
+ node = new nodes.Mul(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseDiv: function() {
+ var node = this.parseFloorDiv();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '/')) {
+ var node2 = this.parseFloorDiv();
+ node = new nodes.Div(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseFloorDiv: function() {
+ var node = this.parseMod();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '//')) {
+ var node2 = this.parseMod();
+ node = new nodes.FloorDiv(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseMod: function() {
+ var node = this.parsePow();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '%')) {
+ var node2 = this.parsePow();
+ node = new nodes.Mod(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parsePow: function() {
+ var node = this.parseUnary();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '**')) {
+ var node2 = this.parseUnary();
+ node = new nodes.Pow(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseUnary: function(noFilters) {
+ var tok = this.peekToken();
+ var node;
+
+ if(this.skipValue(lexer.TOKEN_OPERATOR, '-')) {
+ node = new nodes.Neg(tok.lineno,
+ tok.colno,
+ this.parseUnary(true));
+ }
+ else if(this.skipValue(lexer.TOKEN_OPERATOR, '+')) {
+ node = new nodes.Pos(tok.lineno,
+ tok.colno,
+ this.parseUnary(true));
+ }
+ else {
+ node = this.parsePrimary();
+ }
+
+ if(!noFilters) {
+ node = this.parseFilter(node);
+ }
+
+ return node;
+ },
+
+ parsePrimary: function (noPostfix) {
+ var tok = this.nextToken();
+ var val;
+ var node = null;
+
+ if(!tok) {
+ this.fail('expected expression, got end of file');
+ }
+ else if(tok.type === lexer.TOKEN_STRING) {
+ val = tok.value;
+ }
+ else if(tok.type === lexer.TOKEN_INT) {
+ val = parseInt(tok.value, 10);
+ }
+ else if(tok.type === lexer.TOKEN_FLOAT) {
+ val = parseFloat(tok.value);
+ }
+ else if(tok.type === lexer.TOKEN_BOOLEAN) {
+ if(tok.value === 'true') {
+ val = true;
+ }
+ else if(tok.value === 'false') {
+ val = false;
+ }
+ else {
+ this.fail('invalid boolean: ' + tok.value,
+ tok.lineno,
+ tok.colno);
+ }
+ }
+ else if(tok.type === lexer.TOKEN_NONE) {
+ val = null;
+ }
+ else if (tok.type === lexer.TOKEN_REGEX) {
+ val = new RegExp(tok.value.body, tok.value.flags);
+ }
+
+ if(val !== undefined) {
+ node = new nodes.Literal(tok.lineno, tok.colno, val);
+ }
+ else if(tok.type === lexer.TOKEN_SYMBOL) {
+ node = new nodes.Symbol(tok.lineno, tok.colno, tok.value);
+
+ if(!noPostfix) {
+ node = this.parsePostfix(node);
+ }
+ }
+ else {
+ // See if it's an aggregate type, we need to push the
+ // current delimiter token back on
+ this.pushToken(tok);
+ node = this.parseAggregate();
+ }
+
+ if(node) {
+ return node;
+ }
+ else {
+ this.fail('unexpected token: ' + tok.value,
+ tok.lineno,
+ tok.colno);
+ }
+ },
+
+ 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 name = this.parseFilterName();
+
+ node = new nodes.Filter(
+ name.lineno,
+ name.colno,
+ name,
+ new nodes.NodeList(
+ name.lineno,
+ name.colno,
+ [node].concat(this.parseFilterArgs(node))
+ )
+ );
+ }
+
+ return node;
+ },
+
+ 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 = new nodes.Capture(
+ name.lineno,
+ name.colno,
+ this.parseUntilBlocks('endfilter')
+ );
+ this.advanceAfterBlockEnd();
+
+ var node = new nodes.Filter(
+ name.lineno,
+ name.colno,
+ name,
+ new nodes.NodeList(
+ name.lineno,
+ name.colno,
+ [body].concat(args)
+ )
+ );
+
+ return new nodes.Output(
+ name.lineno,
+ name.colno,
+ [node]
+ );
+ },
+
+ parseAggregate: function() {
+ var tok = this.nextToken();
+ var node;
+
+ switch(tok.type) {
+ case lexer.TOKEN_LEFT_PAREN:
+ node = new nodes.Group(tok.lineno, tok.colno); break;
+ case lexer.TOKEN_LEFT_BRACKET:
+ node = new nodes.Array(tok.lineno, tok.colno); break;
+ case lexer.TOKEN_LEFT_CURLY:
+ node = new nodes.Dict(tok.lineno, tok.colno); break;
+ default:
+ return null;
+ }
+
+ while(1) {
+ var type = this.peekToken().type;
+ if(type === lexer.TOKEN_RIGHT_PAREN ||
+ type === lexer.TOKEN_RIGHT_BRACKET ||
+ type === lexer.TOKEN_RIGHT_CURLY) {
+ this.nextToken();
+ break;
+ }
+
+ if(node.children.length > 0) {
+ if(!this.skip(lexer.TOKEN_COMMA)) {
+ this.fail('parseAggregate: expected comma after expression',
+ tok.lineno,
+ tok.colno);
+ }
+ }
+
+ if(node instanceof nodes.Dict) {
+ // TODO: check for errors
+ var key = this.parsePrimary();
+
+ // We expect a key/value pair for dicts, separated by a
+ // colon
+ if(!this.skip(lexer.TOKEN_COLON)) {
+ this.fail('parseAggregate: expected colon after dict key',
+ tok.lineno,
+ tok.colno);
+ }
+
+ // TODO: check for errors
+ var value = this.parseExpression();
+ node.addChild(new nodes.Pair(key.lineno,
+ key.colno,
+ key,
+ value));
+ }
+ else {
+ // TODO: check for errors
+ var expr = this.parseExpression();
+ node.addChild(expr);
+ }
+ }
+
+ return node;
+ },
+
+ parseSignature: function(tolerant, noParens) {
+ var tok = this.peekToken();
+ if(!noParens && tok.type !== lexer.TOKEN_LEFT_PAREN) {
+ if(tolerant) {
+ return null;
+ }
+ else {
+ this.fail('expected arguments', tok.lineno, tok.colno);
+ }
+ }
+
+ if(tok.type === lexer.TOKEN_LEFT_PAREN) {
+ tok = this.nextToken();
+ }
+
+ var args = new nodes.NodeList(tok.lineno, tok.colno);
+ var kwargs = new nodes.KeywordArgs(tok.lineno, tok.colno);
+ var checkComma = false;
+
+ while(1) {
+ tok = this.peekToken();
+ if(!noParens && tok.type === lexer.TOKEN_RIGHT_PAREN) {
+ this.nextToken();
+ break;
+ }
+ else if(noParens && tok.type === lexer.TOKEN_BLOCK_END) {
+ break;
+ }
+
+ if(checkComma && !this.skip(lexer.TOKEN_COMMA)) {
+ this.fail('parseSignature: expected comma after expression',
+ tok.lineno,
+ tok.colno);
+ }
+ else {
+ var arg = this.parseExpression();
+
+ if(this.skipValue(lexer.TOKEN_OPERATOR, '=')) {
+ kwargs.addChild(
+ new nodes.Pair(arg.lineno,
+ arg.colno,
+ arg,
+ this.parseExpression())
+ );
+ }
+ else {
+ args.addChild(arg);
+ }
+ }
+
+ checkComma = true;
+ }
+
+ if(kwargs.children.length) {
+ args.addChild(kwargs);
+ }
+
+ return args;
+ },
+
+ parseUntilBlocks: function(/* blockNames */) {
+ var prev = this.breakOnBlocks;
+ this.breakOnBlocks = lib.toArray(arguments);
+
+ var ret = this.parse();
+
+ this.breakOnBlocks = prev;
+ return ret;
+ },
+
+ parseNodes: function () {
+ var tok;
+ var buf = [];
+
+ 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 succeeding block start token
+ if(nextToken &&
+ ((nextToken.type === lexer.TOKEN_BLOCK_START &&
+ nextVal.charAt(nextVal.length - 1) === '-') ||
+ (nextToken.type === lexer.TOKEN_VARIABLE_START &&
+ nextVal.charAt(this.tokens.tags.VARIABLE_START.length)
+ === '-') ||
+ (nextToken.type === lexer.TOKEN_COMMENT &&
+ nextVal.charAt(this.tokens.tags.COMMENT_START.length)
+ === '-'))) {
+ // 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,
+ data)]));
+ }
+ else if(tok.type === lexer.TOKEN_BLOCK_START) {
+ this.dropLeadingWhitespace = false;
+ var n = this.parseStatement();
+ if(!n) {
+ break;
+ }
+ buf.push(n);
+ }
+ else if(tok.type === lexer.TOKEN_VARIABLE_START) {
+ var e = this.parseExpression();
+ this.dropLeadingWhitespace = false;
+ this.advanceAfterVariableEnd();
+ buf.push(new nodes.Output(tok.lineno, tok.colno, [e]));
+ }
+ else if(tok.type === lexer.TOKEN_COMMENT) {
+ this.dropLeadingWhitespace = tok.value.charAt(
+ tok.value.length - this.tokens.tags.COMMENT_END.length - 1
+ ) === '-';
+ } else {
+ // Ignore comments, otherwise this should be an error
+ this.fail('Unexpected token at top-level: ' +
+ tok.type, tok.lineno, tok.colno);
+
+ }
+ }
+
+ return buf;
+ },
+
+ parse: function() {
+ return new nodes.NodeList(0, 0, this.parseNodes());
+ },
+
+ parseAsRoot: function() {
+ return new nodes.Root(0, 0, this.parseNodes());
+ }
+ });
+
+ // var util = require('util');
+
+ // 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('hello {% filter title %}' +
+ // 'Hello madam how are you' +
+ // '{% endfilter %}'));
+ // var n = p.parseAsRoot();
+ // nodes.printNodes(n);
+
+ module.exports = {
+ parse: function(src, extensions, opts) {
+ var p = new Parser(lexer.lex(src, opts));
+ if (extensions !== undefined) {
+ p.extensions = extensions;
+ }
+ return p.parseAsRoot();
+ }
+ };
+
+
+/***/ },
+/* 9 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+
+ var whitespaceChars = ' \n\t\r\u00A0';
+ var delimChars = '()[]{}%*-+~/#,:|.<>=!';
+ var intChars = '0123456789';
+
+ var BLOCK_START = '{%';
+ var BLOCK_END = '%}';
+ var VARIABLE_START = '{{';
+ var VARIABLE_END = '}}';
+ var COMMENT_START = '{#';
+ var COMMENT_END = '#}';
+
+ var TOKEN_STRING = 'string';
+ var TOKEN_WHITESPACE = 'whitespace';
+ var TOKEN_DATA = 'data';
+ var TOKEN_BLOCK_START = 'block-start';
+ var TOKEN_BLOCK_END = 'block-end';
+ var TOKEN_VARIABLE_START = 'variable-start';
+ var TOKEN_VARIABLE_END = 'variable-end';
+ var TOKEN_COMMENT = 'comment';
+ var TOKEN_LEFT_PAREN = 'left-paren';
+ var TOKEN_RIGHT_PAREN = 'right-paren';
+ var TOKEN_LEFT_BRACKET = 'left-bracket';
+ var TOKEN_RIGHT_BRACKET = 'right-bracket';
+ var TOKEN_LEFT_CURLY = 'left-curly';
+ var TOKEN_RIGHT_CURLY = 'right-curly';
+ var TOKEN_OPERATOR = 'operator';
+ var TOKEN_COMMA = 'comma';
+ var TOKEN_COLON = 'colon';
+ var TOKEN_TILDE = 'tilde';
+ var TOKEN_PIPE = 'pipe';
+ var TOKEN_INT = 'int';
+ var TOKEN_FLOAT = 'float';
+ var TOKEN_BOOLEAN = 'boolean';
+ var TOKEN_NONE = 'none';
+ var TOKEN_SYMBOL = 'symbol';
+ var TOKEN_SPECIAL = 'special';
+ var TOKEN_REGEX = 'regex';
+
+ function token(type, value, lineno, colno) {
+ return {
+ type: type,
+ value: value,
+ lineno: lineno,
+ colno: colno
+ };
+ }
+
+ function Tokenizer(str, opts) {
+ this.str = str;
+ this.index = 0;
+ this.len = str.length;
+ this.lineno = 0;
+ this.colno = 0;
+
+ this.in_code = false;
+
+ opts = opts || {};
+
+ var tags = opts.tags || {};
+ this.tags = {
+ BLOCK_START: tags.blockStart || BLOCK_START,
+ BLOCK_END: tags.blockEnd || BLOCK_END,
+ VARIABLE_START: tags.variableStart || VARIABLE_START,
+ VARIABLE_END: tags.variableEnd || VARIABLE_END,
+ COMMENT_START: tags.commentStart || COMMENT_START,
+ COMMENT_END: tags.commentEnd || COMMENT_END
+ };
+
+ this.trimBlocks = !!opts.trimBlocks;
+ this.lstripBlocks = !!opts.lstripBlocks;
+ }
+
+ Tokenizer.prototype.nextToken = function() {
+ var lineno = this.lineno;
+ var colno = this.colno;
+ var tok;
+
+ if(this.in_code) {
+ // Otherwise, if we are in a block parse it as code
+ var cur = this.current();
+
+ if(this.is_finished()) {
+ // We have nothing else to parse
+ return null;
+ }
+ else if(cur === '"' || cur === '\'') {
+ // We've hit a string
+ return token(TOKEN_STRING, this.parseString(cur), lineno, colno);
+ }
+ else if((tok = this._extract(whitespaceChars))) {
+ // We hit some whitespace
+ return token(TOKEN_WHITESPACE, tok, lineno, colno);
+ }
+ else if((tok = this._extractString(this.tags.BLOCK_END)) ||
+ (tok = this._extractString('-' + this.tags.BLOCK_END))) {
+ // Special check for the block end tag
+ //
+ // It is a requirement that start and end tags are composed of
+ // delimiter characters (%{}[] etc), and our code always
+ // breaks on delimiters so we can assume the token parsing
+ // doesn't consume these elsewhere
+ this.in_code = false;
+ if(this.trimBlocks) {
+ cur = this.current();
+ if(cur === '\n') {
+ // Skip newline
+ this.forward();
+ }else if(cur === '\r'){
+ // Skip CRLF newline
+ this.forward();
+ cur = this.current();
+ if(cur === '\n'){
+ this.forward();
+ }else{
+ // Was not a CRLF, so go back
+ this.back();
+ }
+ }
+ }
+ return token(TOKEN_BLOCK_END, tok, lineno, colno);
+ }
+ else if((tok = this._extractString(this.tags.VARIABLE_END)) ||
+ (tok = this._extractString('-' + this.tags.VARIABLE_END))) {
+ // Special check for variable end tag (see above)
+ this.in_code = false;
+ return token(TOKEN_VARIABLE_END, tok, lineno, colno);
+ }
+ else if (cur === 'r' && this.str.charAt(this.index + 1) === '/') {
+ // Skip past 'r/'.
+ this.forwardN(2);
+
+ // Extract until the end of the regex -- / ends it, \/ does not.
+ var regexBody = '';
+ while (!this.is_finished()) {
+ if (this.current() === '/' && this.previous() !== '\\') {
+ this.forward();
+ break;
+ } else {
+ regexBody += this.current();
+ this.forward();
+ }
+ }
+
+ // Check for flags.
+ // The possible flags are according to https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
+ var POSSIBLE_FLAGS = ['g', 'i', 'm', 'y'];
+ var regexFlags = '';
+ while (!this.is_finished()) {
+ var isCurrentAFlag = POSSIBLE_FLAGS.indexOf(this.current()) !== -1;
+ if (isCurrentAFlag) {
+ regexFlags += this.current();
+ this.forward();
+ } else {
+ break;
+ }
+ }
+
+ return token(TOKEN_REGEX, {body: regexBody, flags: regexFlags}, lineno, colno);
+ }
+ else if(delimChars.indexOf(cur) !== -1) {
+ // We've hit a delimiter (a special char like a bracket)
+ this.forward();
+ var complexOps = ['==', '===', '!=', '!==', '<=', '>=', '//', '**'];
+ var curComplex = cur + this.current();
+ var type;
+
+ if(lib.indexOf(complexOps, curComplex) !== -1) {
+ this.forward();
+ cur = curComplex;
+
+ // See if this is a strict equality/inequality comparator
+ if(lib.indexOf(complexOps, curComplex + this.current()) !== -1) {
+ cur = curComplex + this.current();
+ this.forward();
+ }
+ }
+
+ switch(cur) {
+ case '(': type = TOKEN_LEFT_PAREN; break;
+ case ')': type = TOKEN_RIGHT_PAREN; break;
+ case '[': type = TOKEN_LEFT_BRACKET; break;
+ case ']': type = TOKEN_RIGHT_BRACKET; break;
+ case '{': type = TOKEN_LEFT_CURLY; break;
+ case '}': type = TOKEN_RIGHT_CURLY; break;
+ case ',': type = TOKEN_COMMA; break;
+ case ':': type = TOKEN_COLON; break;
+ case '~': type = TOKEN_TILDE; break;
+ case '|': type = TOKEN_PIPE; break;
+ default: type = TOKEN_OPERATOR;
+ }
+
+ return token(type, cur, lineno, colno);
+ }
+ else {
+ // We are not at whitespace or a delimiter, so extract the
+ // text and parse it
+ tok = this._extractUntil(whitespaceChars + delimChars);
+
+ if(tok.match(/^[-+]?[0-9]+$/)) {
+ if(this.current() === '.') {
+ this.forward();
+ var dec = this._extract(intChars);
+ return token(TOKEN_FLOAT, tok + '.' + dec, lineno, colno);
+ }
+ else {
+ return token(TOKEN_INT, tok, lineno, colno);
+ }
+ }
+ else if(tok.match(/^(true|false)$/)) {
+ return token(TOKEN_BOOLEAN, tok, lineno, colno);
+ }
+ else if(tok === 'none') {
+ return token(TOKEN_NONE, tok, lineno, colno);
+ }
+ else if(tok) {
+ return token(TOKEN_SYMBOL, tok, lineno, colno);
+ }
+ else {
+ throw new Error('Unexpected value while parsing: ' + tok);
+ }
+ }
+ }
+ else {
+ // Parse out the template text, breaking on tag
+ // delimiters because we need to look for block/variable start
+ // tags (don't use the full delimChars for optimization)
+ var beginChars = (this.tags.BLOCK_START.charAt(0) +
+ this.tags.VARIABLE_START.charAt(0) +
+ this.tags.COMMENT_START.charAt(0) +
+ this.tags.COMMENT_END.charAt(0));
+
+ if(this.is_finished()) {
+ return null;
+ }
+ else if((tok = this._extractString(this.tags.BLOCK_START + '-')) ||
+ (tok = this._extractString(this.tags.BLOCK_START))) {
+ this.in_code = true;
+ return token(TOKEN_BLOCK_START, tok, lineno, colno);
+ }
+ else if((tok = this._extractString(this.tags.VARIABLE_START + '-')) ||
+ (tok = this._extractString(this.tags.VARIABLE_START))) {
+ this.in_code = true;
+ return token(TOKEN_VARIABLE_START, tok, lineno, colno);
+ }
+ else {
+ tok = '';
+ var data;
+ var in_comment = false;
+
+ if(this._matches(this.tags.COMMENT_START)) {
+ in_comment = true;
+ tok = this._extractString(this.tags.COMMENT_START);
+ }
+
+ // Continually consume text, breaking on the tag delimiter
+ // characters and checking to see if it's a start tag.
+ //
+ // We could hit the end of the template in the middle of
+ // our looping, so check for the null return value from
+ // _extractUntil
+ while((data = this._extractUntil(beginChars)) !== null) {
+ tok += data;
+
+ if((this._matches(this.tags.BLOCK_START) ||
+ this._matches(this.tags.VARIABLE_START) ||
+ this._matches(this.tags.COMMENT_START)) &&
+ !in_comment) {
+ if(this.lstripBlocks &&
+ this._matches(this.tags.BLOCK_START) &&
+ this.colno > 0 &&
+ this.colno <= tok.length) {
+ var lastLine = tok.slice(-this.colno);
+ if(/^\s+$/.test(lastLine)) {
+ // Remove block leading whitespace from beginning of the string
+ tok = tok.slice(0, -this.colno);
+ if(!tok.length) {
+ // All data removed, collapse to avoid unnecessary nodes
+ // by returning next token (block start)
+ return this.nextToken();
+ }
+ }
+ }
+ // If it is a start tag, stop looping
+ break;
+ }
+ else if(this._matches(this.tags.COMMENT_END)) {
+ if(!in_comment) {
+ throw new Error('unexpected end of comment');
+ }
+ tok += this._extractString(this.tags.COMMENT_END);
+ break;
+ }
+ else {
+ // It does not match any tag, so add the character and
+ // carry on
+ tok += this.current();
+ this.forward();
+ }
+ }
+
+ if(data === null && in_comment) {
+ throw new Error('expected end of comment, got end of file');
+ }
+
+ return token(in_comment ? TOKEN_COMMENT : TOKEN_DATA,
+ tok,
+ lineno,
+ colno);
+ }
+ }
+
+ throw new Error('Could not parse text');
+ };
+
+ Tokenizer.prototype.parseString = function(delimiter) {
+ this.forward();
+
+ var str = '';
+
+ while(!this.is_finished() && this.current() !== delimiter) {
+ var cur = this.current();
+
+ if(cur === '\\') {
+ this.forward();
+ switch(this.current()) {
+ case 'n': str += '\n'; break;
+ case 't': str += '\t'; break;
+ case 'r': str += '\r'; break;
+ default:
+ str += this.current();
+ }
+ this.forward();
+ }
+ else {
+ str += cur;
+ this.forward();
+ }
+ }
+
+ this.forward();
+ return str;
+ };
+
+ Tokenizer.prototype._matches = function(str) {
+ if(this.index + str.length > this.len) {
+ return null;
+ }
+
+ var m = this.str.slice(this.index, this.index + str.length);
+ return m === str;
+ };
+
+ Tokenizer.prototype._extractString = function(str) {
+ if(this._matches(str)) {
+ this.index += str.length;
+ return str;
+ }
+ return null;
+ };
+
+ Tokenizer.prototype._extractUntil = function(charString) {
+ // Extract all non-matching chars, with the default matching set
+ // to everything
+ return this._extractMatching(true, charString || '');
+ };
+
+ Tokenizer.prototype._extract = function(charString) {
+ // Extract all matching chars (no default, so charString must be
+ // explicit)
+ return this._extractMatching(false, charString);
+ };
+
+ Tokenizer.prototype._extractMatching = function (breakOnMatch, charString) {
+ // Pull out characters until a breaking char is hit.
+ // If breakOnMatch is false, a non-matching char stops it.
+ // If breakOnMatch is true, a matching char stops it.
+
+ if(this.is_finished()) {
+ return null;
+ }
+
+ var first = charString.indexOf(this.current());
+
+ // Only proceed if the first character doesn't meet our condition
+ if((breakOnMatch && first === -1) ||
+ (!breakOnMatch && first !== -1)) {
+ var t = this.current();
+ this.forward();
+
+ // And pull out all the chars one at a time until we hit a
+ // breaking char
+ var idx = charString.indexOf(this.current());
+
+ while(((breakOnMatch && idx === -1) ||
+ (!breakOnMatch && idx !== -1)) && !this.is_finished()) {
+ t += this.current();
+ this.forward();
+
+ idx = charString.indexOf(this.current());
+ }
+
+ return t;
+ }
+
+ return '';
+ };
+
+ 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() {
+ return this.index >= this.len;
+ };
+
+ Tokenizer.prototype.forwardN = function(n) {
+ for(var i=0; i<n; i++) {
+ this.forward();
+ }
+ };
+
+ Tokenizer.prototype.forward = function() {
+ this.index++;
+
+ if(this.previous() === '\n') {
+ this.lineno++;
+ this.colno = 0;
+ }
+ else {
+ this.colno++;
+ }
+ };
+
+ Tokenizer.prototype.backN = function(n) {
+ for(var i=0; i<n; i++) {
+ this.back();
+ }
+ };
+
+ Tokenizer.prototype.back = function() {
+ this.index--;
+
+ if(this.current() === '\n') {
+ this.lineno--;
+
+ var idx = this.src.lastIndexOf('\n', this.index-1);
+ if(idx === -1) {
+ this.colno = this.index;
+ }
+ else {
+ this.colno = this.index - idx;
+ }
+ }
+ else {
+ this.colno--;
+ }
+ };
+
+ // current returns current character
+ Tokenizer.prototype.current = function() {
+ if(!this.is_finished()) {
+ return this.str.charAt(this.index);
+ }
+ return '';
+ };
+
+ // 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() {
+ return this.str.charAt(this.index-1);
+ };
+
+ module.exports = {
+ lex: function(src, opts) {
+ return new Tokenizer(src, opts);
+ },
+
+ TOKEN_STRING: TOKEN_STRING,
+ TOKEN_WHITESPACE: TOKEN_WHITESPACE,
+ TOKEN_DATA: TOKEN_DATA,
+ TOKEN_BLOCK_START: TOKEN_BLOCK_START,
+ TOKEN_BLOCK_END: TOKEN_BLOCK_END,
+ TOKEN_VARIABLE_START: TOKEN_VARIABLE_START,
+ TOKEN_VARIABLE_END: TOKEN_VARIABLE_END,
+ TOKEN_COMMENT: TOKEN_COMMENT,
+ TOKEN_LEFT_PAREN: TOKEN_LEFT_PAREN,
+ TOKEN_RIGHT_PAREN: TOKEN_RIGHT_PAREN,
+ TOKEN_LEFT_BRACKET: TOKEN_LEFT_BRACKET,
+ TOKEN_RIGHT_BRACKET: TOKEN_RIGHT_BRACKET,
+ TOKEN_LEFT_CURLY: TOKEN_LEFT_CURLY,
+ TOKEN_RIGHT_CURLY: TOKEN_RIGHT_CURLY,
+ TOKEN_OPERATOR: TOKEN_OPERATOR,
+ TOKEN_COMMA: TOKEN_COMMA,
+ TOKEN_COLON: TOKEN_COLON,
+ TOKEN_TILDE: TOKEN_TILDE,
+ TOKEN_PIPE: TOKEN_PIPE,
+ TOKEN_INT: TOKEN_INT,
+ TOKEN_FLOAT: TOKEN_FLOAT,
+ TOKEN_BOOLEAN: TOKEN_BOOLEAN,
+ TOKEN_NONE: TOKEN_NONE,
+ TOKEN_SYMBOL: TOKEN_SYMBOL,
+ TOKEN_SPECIAL: TOKEN_SPECIAL,
+ TOKEN_REGEX: TOKEN_REGEX
+ };
+
+
+/***/ },
+/* 10 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(process) {'use strict';
+
+ var lib = __webpack_require__(1);
+ // jshint -W079
+ var Object = __webpack_require__(6);
+
+ function traverseAndCheck(obj, type, results) {
+ if(obj instanceof type) {
+ results.push(obj);
+ }
+
+ if(obj instanceof Node) {
+ obj.findAll(type, results);
+ }
+ }
+
+ var Node = Object.extend('Node', {
+ init: function(lineno, colno) {
+ this.lineno = lineno;
+ this.colno = colno;
+
+ var fields = this.fields;
+ for(var i = 0, l = fields.length; i < l; i++) {
+ var field = fields[i];
+
+ // The first two args are line/col numbers, so offset by 2
+ var val = arguments[i + 2];
+
+ // Fields should never be undefined, but null. It makes
+ // testing easier to normalize values.
+ if(val === undefined) {
+ val = null;
+ }
+
+ this[field] = val;
+ }
+ },
+
+ findAll: function(type, results) {
+ results = results || [];
+
+ var i, l;
+ if(this instanceof NodeList) {
+ var children = this.children;
+
+ for(i = 0, l = children.length; i < l; i++) {
+ traverseAndCheck(children[i], type, results);
+ }
+ }
+ else {
+ var fields = this.fields;
+
+ for(i = 0, l = fields.length; i < l; i++) {
+ traverseAndCheck(this[fields[i]], type, results);
+ }
+ }
+
+ return results;
+ },
+
+ iterFields: function(func) {
+ lib.each(this.fields, function(field) {
+ func(this[field], field);
+ }, this);
+ }
+ });
+
+ // Abstract nodes
+ var Value = Node.extend('Value', { fields: ['value'] });
+
+ // Concrete nodes
+ var NodeList = Node.extend('NodeList', {
+ fields: ['children'],
+
+ init: function(lineno, colno, nodes) {
+ this.parent(lineno, colno, nodes || []);
+ },
+
+ addChild: function(node) {
+ this.children.push(node);
+ }
+ });
+
+ var Root = NodeList.extend('Root');
+ var Literal = Value.extend('Literal');
+ var Symbol = Value.extend('Symbol');
+ var Group = NodeList.extend('Group');
+ var Array = NodeList.extend('Array');
+ var Pair = Node.extend('Pair', { fields: ['key', 'value'] });
+ var Dict = NodeList.extend('Dict');
+ var LookupVal = Node.extend('LookupVal', { fields: ['target', 'val'] });
+ var If = Node.extend('If', { fields: ['cond', 'body', 'else_'] });
+ var IfAsync = If.extend('IfAsync');
+ var InlineIf = Node.extend('InlineIf', { fields: ['cond', 'body', 'else_'] });
+ var For = Node.extend('For', { fields: ['arr', 'name', 'body', 'else_'] });
+ var AsyncEach = For.extend('AsyncEach');
+ var AsyncAll = For.extend('AsyncAll');
+ var Macro = Node.extend('Macro', { fields: ['name', 'args', 'body'] });
+ var Caller = Macro.extend('Caller');
+ var Import = Node.extend('Import', { fields: ['template', 'target', 'withContext'] });
+ var FromImport = Node.extend('FromImport', {
+ fields: ['template', 'names', 'withContext'],
+
+ init: function(lineno, colno, template, names, withContext) {
+ this.parent(lineno, colno,
+ template,
+ names || new NodeList(), withContext);
+ }
+ });
+ var FunCall = Node.extend('FunCall', { fields: ['name', 'args'] });
+ var Filter = FunCall.extend('Filter');
+ var FilterAsync = Filter.extend('FilterAsync', {
+ fields: ['name', 'args', 'symbol']
+ });
+ var KeywordArgs = Dict.extend('KeywordArgs');
+ var Block = Node.extend('Block', { fields: ['name', 'body'] });
+ var Super = Node.extend('Super', { fields: ['blockName', 'symbol'] });
+ var TemplateRef = Node.extend('TemplateRef', { fields: ['template'] });
+ var Extends = TemplateRef.extend('Extends');
+ var Include = Node.extend('Include', { fields: ['template', 'ignoreMissing'] });
+ var Set = Node.extend('Set', { fields: ['targets', 'value'] });
+ var Output = NodeList.extend('Output');
+ var Capture = Node.extend('Capture', { fields: ['body'] });
+ var TemplateData = Literal.extend('TemplateData');
+ var UnaryOp = Node.extend('UnaryOp', { fields: ['target'] });
+ var BinOp = Node.extend('BinOp', { fields: ['left', 'right'] });
+ var In = BinOp.extend('In');
+ var Or = BinOp.extend('Or');
+ var And = BinOp.extend('And');
+ var Not = UnaryOp.extend('Not');
+ var Add = BinOp.extend('Add');
+ var Concat = BinOp.extend('Concat');
+ var Sub = BinOp.extend('Sub');
+ var Mul = BinOp.extend('Mul');
+ var Div = BinOp.extend('Div');
+ var FloorDiv = BinOp.extend('FloorDiv');
+ var Mod = BinOp.extend('Mod');
+ var Pow = BinOp.extend('Pow');
+ var Neg = UnaryOp.extend('Neg');
+ var Pos = UnaryOp.extend('Pos');
+ var Compare = Node.extend('Compare', { fields: ['expr', 'ops'] });
+ var CompareOperand = Node.extend('CompareOperand', {
+ fields: ['expr', 'type']
+ });
+
+ var CallExtension = Node.extend('CallExtension', {
+ fields: ['extName', 'prop', 'args', 'contentArgs'],
+
+ init: function(ext, prop, args, contentArgs) {
+ this.extName = ext._name || ext;
+ this.prop = prop;
+ this.args = args || new NodeList();
+ this.contentArgs = contentArgs || [];
+ this.autoescape = ext.autoescape;
+ }
+ });
+
+ var CallExtensionAsync = CallExtension.extend('CallExtensionAsync');
+
+ // Print the AST in a nicely formatted tree format for debuggin
+ function printNodes(node, indent) {
+ indent = indent || 0;
+
+ // This is hacky, but this is just a debugging function anyway
+ function print(str, indent, inline) {
+ var lines = str.split('\n');
+
+ for(var i=0; i<lines.length; i++) {
+ if(lines[i]) {
+ if((inline && i > 0) || !inline) {
+ for(var j=0; j<indent; j++) {
+ process.stdout.write(' ');
+ }
+ }
+ }
+
+ if(i === lines.length-1) {
+ process.stdout.write(lines[i]);
+ }
+ else {
+ process.stdout.write(lines[i] + '\n');
+ }
+ }
+ }
+
+ print(node.typename + ': ', indent);
+
+ if(node instanceof NodeList) {
+ print('\n');
+ lib.each(node.children, function(n) {
+ printNodes(n, indent + 2);
+ });
+ }
+ else if(node instanceof CallExtension) {
+ print(node.extName + '.' + node.prop);
+ print('\n');
+
+ if(node.args) {
+ printNodes(node.args, indent + 2);
+ }
+
+ if(node.contentArgs) {
+ lib.each(node.contentArgs, function(n) {
+ printNodes(n, indent + 2);
+ });
+ }
+ }
+ else {
+ var nodes = null;
+ var props = null;
+
+ node.iterFields(function(val, field) {
+ if(val instanceof Node) {
+ nodes = nodes || {};
+ nodes[field] = val;
+ }
+ else {
+ props = props || {};
+ props[field] = val;
+ }
+ });
+
+ if(props) {
+ print(JSON.stringify(props, null, 2) + '\n', null, true);
+ }
+ else {
+ print('\n');
+ }
+
+ if(nodes) {
+ for(var k in nodes) {
+ printNodes(nodes[k], indent + 2);
+ }
+ }
+
+ }
+ }
+
+ // var t = new NodeList(0, 0,
+ // [new Value(0, 0, 3),
+ // new Value(0, 0, 10),
+ // new Pair(0, 0,
+ // new Value(0, 0, 'key'),
+ // new Value(0, 0, 'value'))]);
+ // printNodes(t);
+
+ module.exports = {
+ Node: Node,
+ Root: Root,
+ NodeList: NodeList,
+ Value: Value,
+ Literal: Literal,
+ Symbol: Symbol,
+ Group: Group,
+ Array: Array,
+ Pair: Pair,
+ Dict: Dict,
+ Output: Output,
+ Capture: Capture,
+ TemplateData: TemplateData,
+ If: If,
+ IfAsync: IfAsync,
+ InlineIf: InlineIf,
+ For: For,
+ AsyncEach: AsyncEach,
+ AsyncAll: AsyncAll,
+ Macro: Macro,
+ Caller: Caller,
+ Import: Import,
+ FromImport: FromImport,
+ FunCall: FunCall,
+ Filter: Filter,
+ FilterAsync: FilterAsync,
+ KeywordArgs: KeywordArgs,
+ Block: Block,
+ Super: Super,
+ Extends: Extends,
+ Include: Include,
+ Set: Set,
+ LookupVal: LookupVal,
+ BinOp: BinOp,
+ In: In,
+ Or: Or,
+ And: And,
+ Not: Not,
+ Add: Add,
+ Concat: Concat,
+ Sub: Sub,
+ Mul: Mul,
+ Div: Div,
+ FloorDiv: FloorDiv,
+ Mod: Mod,
+ Pow: Pow,
+ Neg: Neg,
+ Pos: Pos,
+ Compare: Compare,
+ CompareOperand: CompareOperand,
+
+ CallExtension: CallExtension,
+ CallExtensionAsync: CallExtensionAsync,
+
+ printNodes: printNodes
+ };
+
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3)))
+
+/***/ },
+/* 11 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var nodes = __webpack_require__(10);
+ var lib = __webpack_require__(1);
+
+ var sym = 0;
+ function gensym() {
+ return 'hole_' + sym++;
+ }
+
+ // copy-on-write version of map
+ function mapCOW(arr, func) {
+ var res = null;
+
+ for(var i=0; i<arr.length; i++) {
+ var item = func(arr[i]);
+
+ if(item !== arr[i]) {
+ if(!res) {
+ res = arr.slice();
+ }
+
+ res[i] = item;
+ }
+ }
+
+ return res || arr;
+ }
+
+ function walk(ast, func, depthFirst) {
+ if(!(ast instanceof nodes.Node)) {
+ return ast;
+ }
+
+ if(!depthFirst) {
+ var astT = func(ast);
+
+ if(astT && astT !== ast) {
+ return astT;
+ }
+ }
+
+ if(ast instanceof nodes.NodeList) {
+ var children = mapCOW(ast.children, function(node) {
+ return walk(node, func, depthFirst);
+ });
+
+ if(children !== ast.children) {
+ ast = new nodes[ast.typename](ast.lineno, ast.colno, children);
+ }
+ }
+ else if(ast instanceof nodes.CallExtension) {
+ var args = walk(ast.args, func, depthFirst);
+
+ var contentArgs = mapCOW(ast.contentArgs, function(node) {
+ return walk(node, func, depthFirst);
+ });
+
+ if(args !== ast.args || contentArgs !== ast.contentArgs) {
+ ast = new nodes[ast.typename](ast.extName,
+ ast.prop,
+ args,
+ contentArgs);
+ }
+ }
+ else {
+ var props = ast.fields.map(function(field) {
+ return ast[field];
+ });
+
+ var propsT = mapCOW(props, function(prop) {
+ return walk(prop, func, depthFirst);
+ });
+
+ if(propsT !== props) {
+ ast = new nodes[ast.typename](ast.lineno, ast.colno);
+
+ propsT.forEach(function(prop, i) {
+ ast[ast.fields[i]] = prop;
+ });
+ }
+ }
+
+ return depthFirst ? (func(ast) || ast) : ast;
+ }
+
+ function depthWalk(ast, func) {
+ return walk(ast, func, true);
+ }
+
+ function _liftFilters(node, asyncFilters, prop) {
+ var children = [];
+
+ var walked = depthWalk(prop ? node[prop] : node, function(node) {
+ if(node instanceof nodes.Block) {
+ return node;
+ }
+ else if((node instanceof nodes.Filter &&
+ lib.indexOf(asyncFilters, node.name.value) !== -1) ||
+ node instanceof nodes.CallExtensionAsync) {
+ var symbol = new nodes.Symbol(node.lineno,
+ node.colno,
+ gensym());
+
+ children.push(new nodes.FilterAsync(node.lineno,
+ node.colno,
+ node.name,
+ node.args,
+ symbol));
+ return symbol;
+ }
+ });
+
+ if(prop) {
+ node[prop] = walked;
+ }
+ else {
+ node = walked;
+ }
+
+ if(children.length) {
+ children.push(node);
+
+ return new nodes.NodeList(
+ node.lineno,
+ node.colno,
+ children
+ );
+ }
+ else {
+ return node;
+ }
+ }
+
+ function liftFilters(ast, asyncFilters) {
+ return depthWalk(ast, function(node) {
+ if(node instanceof nodes.Output) {
+ return _liftFilters(node, asyncFilters);
+ }
+ else if(node instanceof nodes.Set) {
+ return _liftFilters(node, asyncFilters, 'value');
+ }
+ else if(node instanceof nodes.For) {
+ return _liftFilters(node, asyncFilters, 'arr');
+ }
+ else if(node instanceof nodes.If) {
+ return _liftFilters(node, asyncFilters, 'cond');
+ }
+ else if(node instanceof nodes.CallExtension) {
+ return _liftFilters(node, asyncFilters, 'args');
+ }
+ });
+ }
+
+ function liftSuper(ast) {
+ return walk(ast, function(blockNode) {
+ if(!(blockNode instanceof nodes.Block)) {
+ return;
+ }
+
+ var hasSuper = false;
+ var symbol = gensym();
+
+ blockNode.body = walk(blockNode.body, function(node) {
+ if(node instanceof nodes.FunCall &&
+ node.name.value === 'super') {
+ hasSuper = true;
+ return new nodes.Symbol(node.lineno, node.colno, symbol);
+ }
+ });
+
+ if(hasSuper) {
+ blockNode.body.children.unshift(new nodes.Super(
+ 0, 0, blockNode.name, new nodes.Symbol(0, 0, symbol)
+ ));
+ }
+ });
+ }
+
+ function convertStatements(ast) {
+ return depthWalk(ast, function(node) {
+ if(!(node instanceof nodes.If) &&
+ !(node instanceof nodes.For)) {
+ return;
+ }
+
+ var async = false;
+ walk(node, function(node) {
+ if(node instanceof nodes.FilterAsync ||
+ node instanceof nodes.IfAsync ||
+ node instanceof nodes.AsyncEach ||
+ node instanceof nodes.AsyncAll ||
+ node instanceof nodes.CallExtensionAsync) {
+ async = true;
+ // Stop iterating by returning the node
+ return node;
+ }
+ });
+
+ if(async) {
+ if(node instanceof nodes.If) {
+ return new nodes.IfAsync(
+ node.lineno,
+ node.colno,
+ node.cond,
+ node.body,
+ node.else_
+ );
+ }
+ else if(node instanceof nodes.For) {
+ return new nodes.AsyncEach(
+ node.lineno,
+ node.colno,
+ node.arr,
+ node.name,
+ node.body,
+ node.else_
+ );
+ }
+ }
+ });
+ }
+
+ function cps(ast, asyncFilters) {
+ return convertStatements(liftSuper(liftFilters(ast, asyncFilters)));
+ }
+
+ function transform(ast, asyncFilters) {
+ return cps(ast, asyncFilters || []);
+ }
+
+ // var parser = require('./parser');
+ // var src = 'hello {% foo %}{% endfoo %} end';
+ // var ast = transform(parser.parse(src, [new FooExtension()]), ['bar']);
+ // nodes.printNodes(ast);
+
+ module.exports = {
+ transform: transform
+ };
+
+
+/***/ },
+/* 12 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var Obj = __webpack_require__(6);
+
+ // Frames keep track of scoping both at compile-time and run-time so
+ // we know how to access variables. Block tags can introduce special
+ // variables, for example.
+ var Frame = Obj.extend({
+ init: function(parent, isolateWrites) {
+ this.variables = {};
+ this.parent = parent;
+ this.topLevel = false;
+ // if this is true, writes (set) should never propagate upwards past
+ // this frame to its parent (though reads may).
+ this.isolateWrites = isolateWrites;
+ },
+
+ set: function(name, val, resolveUp) {
+ // Allow variables with dots by automatically creating the
+ // nested structure
+ var parts = name.split('.');
+ var obj = this.variables;
+ var frame = this;
+
+ if(resolveUp) {
+ if((frame = this.resolve(parts[0], true))) {
+ frame.set(name, val);
+ return;
+ }
+ }
+
+ 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) {
+ return val;
+ }
+ return null;
+ },
+
+ lookup: function(name) {
+ var p = this.parent;
+ var val = this.variables[name];
+ if(val !== undefined) {
+ return val;
+ }
+ return p && p.lookup(name);
+ },
+
+ resolve: function(name, forWrite) {
+ var p = (forWrite && this.isolateWrites) ? undefined : this.parent;
+ var val = this.variables[name];
+ if(val !== undefined) {
+ return this;
+ }
+ return p && p.resolve(name);
+ },
+
+ push: function(isolateWrites) {
+ return new Frame(this, isolateWrites);
+ },
+
+ pop: function() {
+ return this.parent;
+ }
+ });
+
+ function makeMacro(argNames, kwargNames, func) {
+ return function() {
+ var argCount = numArgs(arguments);
+ var args;
+ var kwargs = getKeywordArgs(arguments);
+ var i;
+
+ if(argCount > argNames.length) {
+ args = Array.prototype.slice.call(arguments, 0, argNames.length);
+
+ // Positional arguments that should be passed in as
+ // keyword arguments (essentially default values)
+ var vals = Array.prototype.slice.call(arguments, args.length, argCount);
+ for(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(i = argCount; i < argNames.length; i++) {
+ var arg = argNames[i];
+
+ // Keyword arguments that should be passed as
+ // positional arguments, i.e. the caller explicitly
+ // used the name of a positional arg
+ 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;
+ }
+ }
+
+ // A SafeString object indicates that the string should not be
+ // autoescaped. This happens magically because autoescaping only
+ // occurs on primitive string objects.
+ function SafeString(val) {
+ if(typeof val !== 'string') {
+ return val;
+ }
+
+ this.val = val;
+ this.length = val.length;
+ }
+
+ SafeString.prototype = Object.create(String.prototype, {
+ length: { writable: true, configurable: true, value: 0 }
+ });
+ 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 && !(val instanceof SafeString)) {
+ val = lib.escape(val.toString());
+ }
+
+ return 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) {
+ obj = obj || {};
+
+ if(typeof obj[val] === 'function') {
+ return function() {
+ return obj[val].apply(obj, arguments);
+ };
+ }
+
+ return obj[val];
+ }
+
+ function callWrap(obj, name, context, 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');
+ }
+
+ // jshint validthis: true
+ return obj.apply(context, args);
+ }
+
+ function contextOrFrameLookup(context, frame, name) {
+ var val = frame.lookup(name);
+ return (val !== undefined) ?
+ 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, i;
+ 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(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);
+ // jshint validthis: true
+ func.apply(this, item);
+ }
+ }
+ }
+ }
+ else {
+ var keys = lib.keys(arr);
+ len = keys.length;
+ outputArr = new Array(len);
+
+ if(len === 0) {
+ cb(null, '');
+ }
+ else {
+ for(i = 0; i < keys.length; i++) {
+ var k = keys[i];
+ func(k, arr[k], i, len, done);
+ }
+ }
+ }
+ }
+
+ module.exports = {
+ Frame: Frame,
+ makeMacro: makeMacro,
+ makeKeywordArgs: makeKeywordArgs,
+ numArgs: numArgs,
+ suppressValue: suppressValue,
+ ensureDefined: ensureDefined,
+ memberLookup: memberLookup,
+ contextOrFrameLookup: contextOrFrameLookup,
+ callWrap: callWrap,
+ handleError: handleError,
+ isArray: lib.isArray,
+ keys: lib.keys,
+ SafeString: SafeString,
+ copySafeness: copySafeness,
+ markSafe: markSafe,
+ asyncEach: asyncEach,
+ asyncAll: asyncAll,
+ inOperator: lib.inOperator
+ };
+
+
+/***/ },
+/* 13 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var r = __webpack_require__(12);
+
+ function normalize(value, defaultValue) {
+ if(value === null || value === undefined || value === false) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ var filters = {
+ abs: function(n) {
+ return Math.abs(n);
+ },
+
+ batch: function(arr, linecount, fill_with) {
+ var i;
+ var res = [];
+ var tmp = [];
+
+ for(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(i = tmp.length; i < linecount; i++) {
+ tmp.push(fill_with);
+ }
+ }
+
+ res.push(tmp);
+ }
+
+ return res;
+ },
+
+ capitalize: function(str) {
+ str = normalize(str, '');
+ var ret = str.toLowerCase();
+ return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1));
+ },
+
+ center: function(str, width) {
+ str = normalize(str, '');
+ 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, bool) {
+ if(bool) {
+ return val ? val : def;
+ }
+ else {
+ return (val !== undefined) ? 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;
+ },
+
+ dump: function(obj, spaces) {
+ return JSON.stringify(obj, null, spaces);
+ },
+
+ escape: function(str) {
+ if(str instanceof r.SafeString) {
+ return str;
+ }
+ str = (str === null || str === undefined) ? '' : str;
+ return r.markSafe(lib.escape(str.toString()));
+ },
+
+ safe: function(str) {
+ if (str instanceof r.SafeString) {
+ return str;
+ }
+ str = (str === null || str === undefined) ? '' : str;
+ return r.markSafe(str.toString());
+ },
+
+ first: function(arr) {
+ return arr[0];
+ },
+
+ groupby: function(arr, attr) {
+ return lib.groupBy(arr, attr);
+ },
+
+ indent: function(str, width, indentfirst) {
+ str = normalize(str, '');
+
+ if (str === '') return '';
+
+ 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(val) {
+ var value = normalize(val, '');
+
+ if(value !== undefined) {
+ if(
+ (typeof Map === 'function' && value instanceof Map) ||
+ (typeof Set === 'function' && value instanceof Set)
+ ) {
+ // ECMAScript 2015 Maps and Sets
+ return value.size;
+ }
+ if(lib.isObject(value) && !(value instanceof r.SafeString)) {
+ // Objects (besides SafeStrings), non-primative Arrays
+ return Object.keys(value).length;
+ }
+ return value.length;
+ }
+ return 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) {
+ str = normalize(str, '');
+ return str.toLowerCase();
+ },
+
+ nl2br: function(str) {
+ if (str === null || str === undefined) {
+ return '';
+ }
+ return r.copySafeness(str, str.replace(/\r\n|\n/g, '<br />\n'));
+ },
+
+ 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) {
+ var originalStr = str;
+
+ if (old instanceof RegExp) {
+ return str.replace(old, new_);
+ }
+
+ if(typeof maxCount === 'undefined'){
+ maxCount = -1;
+ }
+
+ var res = ''; // Output
+
+ // 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);
+ }
+
+ // 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);
+ },
+
+ reverse: function(val) {
+ var arr;
+ if(lib.isString(val)) {
+ arr = filters.list(val);
+ }
+ else {
+ // Copy it
+ 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;
+ },
+
+ sum: function(arr, attr, start) {
+ var sum = 0;
+
+ if(typeof start === 'number'){
+ sum += start;
+ }
+
+ if(attr) {
+ arr = lib.map(arr, function(v) {
+ return v[attr];
+ });
+ }
+
+ for(var i = 0; i < arr.length; i++) {
+ sum += arr[i];
+ }
+
+ return sum;
+ },
+
+ sort: r.makeMacro(['value', 'reverse', 'case_sensitive', 'attribute'], [], function(arr, reverse, caseSens, attr) {
+ // Copy it
+ 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);
+ },
+
+ striptags: function(input, preserve_linebreaks) {
+ input = normalize(input, '');
+ preserve_linebreaks = preserve_linebreaks || false;
+ var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>|<!--[\s\S]*?-->/gi;
+ var trimmedInput = filters.trim(input.replace(tags, ''));
+ var res = '';
+ if (preserve_linebreaks) {
+ res = trimmedInput
+ .replace(/^ +| +$/gm, '') // remove leading and trailing spaces
+ .replace(/ +/g, ' ') // squash adjacent spaces
+ .replace(/(\r\n)/g, '\n') // normalize linebreaks (CRLF -> LF)
+ .replace(/\n\n\n+/g, '\n\n'); // squash abnormal adjacent linebreaks
+ } else {
+ res = trimmedInput.replace(/\s+/gi, ' ');
+ }
+ return r.copySafeness(input, res);
+ },
+
+ title: function(str) {
+ str = normalize(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;
+ input = normalize(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) {
+ str = normalize(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"' : '');
+
+ // For the jinja regexp, see
+ // https://github.com/mitsuhiko/jinja2/blob/f15b814dcba6aa12bc74d1f7d0c881d55f7126be/jinja2/utils.py#L20-L23
+ var puncRE = /^(?:\(|<|&lt;)?(.*?)(?:\.|,|\)|\n|&gt;)?$/;
+ // from http://blog.gerv.net/2011/05/html5_email_address_regexp/
+ 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) {
+ // If the word has no length, bail. This can happen for str with
+ // trailing whitespace.
+ return word && word.length;
+ }).map(function(word) {
+ var matches = word.match(puncRE);
+ var possibleUrl = matches && matches[1] || word;
+
+ // url that starts with http or https
+ if (httpHttpsRE.test(possibleUrl))
+ return '<a href="' + possibleUrl + '"' + noFollowAttr + '>' + possibleUrl.substr(0, length) + '</a>';
+
+ // url that starts with www.
+ if (wwwRE.test(possibleUrl))
+ return '<a href="http://' + possibleUrl + '"' + noFollowAttr + '>' + possibleUrl.substr(0, length) + '</a>';
+
+ // an email address of the form username@domain.tld
+ if (emailRE.test(possibleUrl))
+ return '<a href="mailto:' + possibleUrl + '">' + possibleUrl + '</a>';
+
+ // url that ends in .com, .org or .net that is not an email address
+ if (tldRE.test(possibleUrl))
+ return '<a href="http://' + possibleUrl + '"' + noFollowAttr + '>' + possibleUrl.substr(0, length) + '</a>';
+
+ return word;
+
+ });
+
+ return words.join('');
+ },
+
+ wordcount: function(str) {
+ str = normalize(str, '');
+ var words = (str) ? str.match(/\w+/g) : null;
+ return (words) ? words.length : null;
+ },
+// CUSTOM FILTER
+ dateFormater:function(data){
+ return moment(data,"YYYY-mm-DD").format("mm-DD-YYYY");
+ },
+ dateFormatertextbox:function(data){
+ return moment(data,"DD/mm/YYYY").format("mm-DD-YYYY");
+ },
+
+ timestampConvert:function(datas){
+ // TIMESTAMP TO DATE
+ if(datas != undefined || datas!= null){
+ return moment.unix(datas/1000).format("MM-DD-YYYY");
+ }
+
+ },
+
+ timestampToTime:function(data){
+ // TIMESTAMP TO TIME CONVERTION
+ return moment.unix(data/1000).format("HH:mm");
+ },
+
+ '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;
+ }
+ };
+
+ // Aliases
+ filters.d = filters['default'];
+ filters.e = filters.escape;
+
+ module.exports = filters;
+
+
+/***/ },
+/* 14 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var Loader = __webpack_require__(15);
+ var PrecompiledLoader = __webpack_require__(16);
+
+ var WebLoader = Loader.extend({
+ init: function(baseURL, opts) {
+ this.baseURL = baseURL || '.';
+ opts = opts || {};
+
+ // 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;
+ },
+
+ 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) {
+ cb(err.content);
+ } else {
+ if (err.status === 404) {
+ result = null;
+ } else {
+ throw err.content;
+ }
+ }
+ }
+ else {
+ result = { src: src,
+ path: name,
+ noCache: !useCache };
+ if(cb) {
+ cb(null, result);
+ }
+ }
+ });
+
+ // 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, cb) {
+ // Only in the browser please
+ var ajax;
+ var loading = true;
+
+ if(window.XMLHttpRequest) { // Mozilla, Safari, ...
+ ajax = new XMLHttpRequest();
+ }
+ else if(window.ActiveXObject) { // IE 8 and older
+ /* global ActiveXObject */
+ ajax = new ActiveXObject('Microsoft.XMLHTTP');
+ }
+
+ ajax.onreadystatechange = function() {
+ if(ajax.readyState === 4 && loading) {
+ loading = false;
+ if(ajax.status === 0 || ajax.status === 200) {
+ cb(null, ajax.responseText);
+ }
+ else {
+ cb({ status: ajax.status, content: ajax.responseText });
+ }
+ }
+ };
+
+ url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' +
+ (new Date().getTime());
+
+ ajax.open('GET', url, this.async);
+ ajax.send();
+ }
+ });
+
+ module.exports = {
+ WebLoader: WebLoader,
+ PrecompiledLoader: PrecompiledLoader
+ };
+
+
+/***/ },
+/* 15 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var path = __webpack_require__(3);
+ var Obj = __webpack_require__(6);
+ var lib = __webpack_require__(1);
+
+ 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 /*, arg1, arg2, ...*/) {
+ 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);
+ }
+ });
+
+ module.exports = Loader;
+
+
+/***/ },
+/* 16 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var Loader = __webpack_require__(15);
+
+ var PrecompiledLoader = Loader.extend({
+ init: function(compiledTemplates) {
+ this.precompiled = compiledTemplates || {};
+ },
+
+ getSource: function(name) {
+ if (this.precompiled[name]) {
+ return {
+ src: { type: 'code',
+ obj: this.precompiled[name] },
+ path: name
+ };
+ }
+ return null;
+ }
+ });
+
+ module.exports = PrecompiledLoader;
+
+
+/***/ },
+/* 17 */
+/***/ function(module, exports) {
+
+ '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;
+ };
+ }
+
+ // Making this a function instead so it returns a new object
+ // each time it's called. That way, if something like an environment
+ // uses it, they will each have their own copy.
+ function globals() {
+ return {
+ range: function(start, stop, step) {
+ if(typeof stop === 'undefined') {
+ stop = start;
+ start = 0;
+ step = 1;
+ }
+ else if(!step) {
+ step = 1;
+ }
+
+ var arr = [];
+ var i;
+ if (step > 0) {
+ for (i=start; i<stop; i+=step) {
+ arr.push(i);
+ }
+ } else {
+ for (i=start; i>stop; i+=step) {
+ arr.push(i);
+ }
+ }
+ return arr;
+ },
+
+ // lipsum: function(n, html, min, max) {
+ // },
+
+ cycler: function() {
+ return cycler(Array.prototype.slice.call(arguments));
+ },
+
+ joiner: function(sep) {
+ return joiner(sep);
+ }
+ };
+ }
+
+ module.exports = globals;
+
+
+/***/ },
+/* 18 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(setImmediate, process) {// MIT license (by Elan Shanker).
+ (function(globals) {
+ 'use strict';
+
+ var executeSync = function(){
+ var args = Array.prototype.slice.call(arguments);
+ if (typeof args[0] === 'function'){
+ args[0].apply(null, args.splice(1));
+ }
+ };
+
+ var executeAsync = function(fn){
+ if (typeof setImmediate === 'function') {
+ setImmediate(fn);
+ } else if (typeof process !== 'undefined' && process.nextTick) {
+ process.nextTick(fn);
+ } else {
+ setTimeout(fn, 0);
+ }
+ };
+
+ var makeIterator = function (tasks) {
+ var makeCallback = function (index) {
+ var fn = function () {
+ if (tasks.length) {
+ tasks[index].apply(null, arguments);
+ }
+ return fn.next();
+ };
+ fn.next = function () {
+ return (index < tasks.length - 1) ? makeCallback(index + 1): null;
+ };
+ return fn;
+ };
+ return makeCallback(0);
+ };
+
+ var _isArray = Array.isArray || function(maybeArray){
+ return Object.prototype.toString.call(maybeArray) === '[object Array]';
+ };
+
+ var waterfall = function (tasks, callback, forceAsync) {
+ var nextTick = forceAsync ? executeAsync : executeSync;
+ callback = callback || function () {};
+ if (!_isArray(tasks)) {
+ var err = new Error('First argument to waterfall must be an array of functions');
+ return callback(err);
+ }
+ if (!tasks.length) {
+ return callback();
+ }
+ var wrapIterator = function (iterator) {
+ return function (err) {
+ if (err) {
+ callback.apply(null, arguments);
+ callback = function () {};
+ } else {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var next = iterator.next();
+ if (next) {
+ args.push(wrapIterator(next));
+ } else {
+ args.push(callback);
+ }
+ nextTick(function () {
+ iterator.apply(null, args);
+ });
+ }
+ };
+ };
+ wrapIterator(makeIterator(tasks))();
+ };
+
+ if (true) {
+ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
+ return waterfall;
+ }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); // RequireJS
+ } else if (typeof module !== 'undefined' && module.exports) {
+ module.exports = waterfall; // CommonJS
+ } else {
+ globals.waterfall = waterfall; // <script>
+ }
+ })(this);
+
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(19).setImmediate, __webpack_require__(3)))
+
+/***/ },
+/* 19 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(setImmediate, clearImmediate) {var nextTick = __webpack_require__(20).nextTick;
+ var apply = Function.prototype.apply;
+ var slice = Array.prototype.slice;
+ var immediateIds = {};
+ var nextImmediateId = 0;
+
+ // DOM APIs, for completeness
+
+ exports.setTimeout = function() {
+ return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout);
+ };
+ exports.setInterval = function() {
+ return new Timeout(apply.call(setInterval, window, arguments), clearInterval);
+ };
+ exports.clearTimeout =
+ exports.clearInterval = function(timeout) { timeout.close(); };
+
+ function Timeout(id, clearFn) {
+ this._id = id;
+ this._clearFn = clearFn;
+ }
+ Timeout.prototype.unref = Timeout.prototype.ref = function() {};
+ Timeout.prototype.close = function() {
+ this._clearFn.call(window, this._id);
+ };
+
+ // Does not start the time, just sets up the members needed.
+ exports.enroll = function(item, msecs) {
+ clearTimeout(item._idleTimeoutId);
+ item._idleTimeout = msecs;
+ };
+
+ exports.unenroll = function(item) {
+ clearTimeout(item._idleTimeoutId);
+ item._idleTimeout = -1;
+ };
+
+ exports._unrefActive = exports.active = function(item) {
+ clearTimeout(item._idleTimeoutId);
+
+ var msecs = item._idleTimeout;
+ if (msecs >= 0) {
+ item._idleTimeoutId = setTimeout(function onTimeout() {
+ if (item._onTimeout)
+ item._onTimeout();
+ }, msecs);
+ }
+ };
+
+ // That's not how node.js implements it but the exposed api is the same.
+ exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) {
+ var id = nextImmediateId++;
+ var args = arguments.length < 2 ? false : slice.call(arguments, 1);
+
+ immediateIds[id] = true;
+
+ nextTick(function onNextTick() {
+ if (immediateIds[id]) {
+ // fn.call() is faster so we optimize for the common use-case
+ // @see http://jsperf.com/call-apply-segu
+ if (args) {
+ fn.apply(null, args);
+ } else {
+ fn.call(null);
+ }
+ // Prevent ids from leaking
+ exports.clearImmediate(id);
+ }
+ });
+
+ return id;
+ };
+
+ exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) {
+ delete immediateIds[id];
+ };
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(19).setImmediate, __webpack_require__(19).clearImmediate))
+
+/***/ },
+/* 20 */
+/***/ function(module, exports) {
+
+ // shim for using process in browser
+
+ var process = module.exports = {};
+ var queue = [];
+ var draining = false;
+ var currentQueue;
+ var queueIndex = -1;
+
+ function cleanUpNextTick() {
+ draining = false;
+ if (currentQueue.length) {
+ queue = currentQueue.concat(queue);
+ } else {
+ queueIndex = -1;
+ }
+ if (queue.length) {
+ drainQueue();
+ }
+ }
+
+ function drainQueue() {
+ if (draining) {
+ return;
+ }
+ var timeout = setTimeout(cleanUpNextTick);
+ draining = true;
+
+ var len = queue.length;
+ while(len) {
+ currentQueue = queue;
+ queue = [];
+ while (++queueIndex < len) {
+ if (currentQueue) {
+ currentQueue[queueIndex].run();
+ }
+ }
+ queueIndex = -1;
+ len = queue.length;
+ }
+ currentQueue = null;
+ draining = false;
+ clearTimeout(timeout);
+ }
+
+ process.nextTick = function (fun) {
+ var args = new Array(arguments.length - 1);
+ if (arguments.length > 1) {
+ for (var i = 1; i < arguments.length; i++) {
+ args[i - 1] = arguments[i];
+ }
+ }
+ queue.push(new Item(fun, args));
+ if (queue.length === 1 && !draining) {
+ setTimeout(drainQueue, 0);
+ }
+ };
+
+ // v8 likes predictible objects
+ function Item(fun, array) {
+ this.fun = fun;
+ this.array = array;
+ }
+ Item.prototype.run = function () {
+ this.fun.apply(null, this.array);
+ };
+ process.title = 'browser';
+ process.browser = true;
+ process.env = {};
+ process.argv = [];
+ process.version = ''; // empty string to avoid regexp issues
+ process.versions = {};
+
+ function noop() {}
+
+ process.on = noop;
+ process.addListener = noop;
+ process.once = noop;
+ process.off = noop;
+ process.removeListener = noop;
+ process.removeAllListeners = noop;
+ process.emit = noop;
+
+ process.binding = function (name) {
+ throw new Error('process.binding is not supported');
+ };
+
+ process.cwd = function () { return '/' };
+ process.chdir = function (dir) {
+ throw new Error('process.chdir is not supported');
+ };
+ process.umask = function() { return 0; };
+
+
+/***/ },
+/* 21 */
+/***/ function(module, exports) {
+
+ function installCompat() {
+ 'use strict';
+
+ // This must be called like `nunjucks.installCompat` so that `this`
+ // references the nunjucks instance
+ var runtime = this.runtime; // jshint ignore:line
+ var lib = this.lib; // jshint ignore:line
+
+ var orig_contextOrFrameLookup = runtime.contextOrFrameLookup;
+ runtime.contextOrFrameLookup = function(context, frame, key) {
+ var val = orig_contextOrFrameLookup.apply(this, arguments);
+ if (val === undefined) {
+ switch (key) {
+ case 'True':
+ return true;
+ case 'False':
+ return false;
+ case 'None':
+ return null;
+ }
+ }
+
+ return val;
+ };
+
+ var orig_memberLookup = runtime.memberLookup;
+ var ARRAY_MEMBERS = {
+ pop: function(index) {
+ if (index === undefined) {
+ return this.pop();
+ }
+ if (index >= this.length || index < 0) {
+ throw new Error('KeyError');
+ }
+ return this.splice(index, 1);
+ },
+ append: function(element) {
+ return this.push(element);
+ },
+ remove: function(element) {
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] === element) {
+ return this.splice(i, 1);
+ }
+ }
+ throw new Error('ValueError');
+ },
+ count: function(element) {
+ var count = 0;
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] === element) {
+ count++;
+ }
+ }
+ return count;
+ },
+ index: function(element) {
+ var i;
+ if ((i = this.indexOf(element)) === -1) {
+ throw new Error('ValueError');
+ }
+ return i;
+ },
+ find: function(element) {
+ return this.indexOf(element);
+ },
+ insert: function(index, elem) {
+ return this.splice(index, 0, elem);
+ }
+ };
+ var OBJECT_MEMBERS = {
+ items: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push([k, this[k]]);
+ }
+ return ret;
+ },
+ values: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push(this[k]);
+ }
+ return ret;
+ },
+ keys: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push(k);
+ }
+ return ret;
+ },
+ get: function(key, def) {
+ var output = this[key];
+ if (output === undefined) {
+ output = def;
+ }
+ return output;
+ },
+ has_key: function(key) {
+ return this.hasOwnProperty(key);
+ },
+ pop: function(key, def) {
+ var output = this[key];
+ if (output === undefined && def !== undefined) {
+ output = def;
+ } else if (output === undefined) {
+ throw new Error('KeyError');
+ } else {
+ delete this[key];
+ }
+ return output;
+ },
+ popitem: function() {
+ for (var k in this) {
+ // Return the first object pair.
+ var val = this[k];
+ delete this[k];
+ return [k, val];
+ }
+ throw new Error('KeyError');
+ },
+ setdefault: function(key, def) {
+ if (key in this) {
+ return this[key];
+ }
+ if (def === undefined) {
+ def = null;
+ }
+ return this[key] = def;
+ },
+ update: function(kwargs) {
+ for (var k in kwargs) {
+ this[k] = kwargs[k];
+ }
+ return null; // Always returns None
+ }
+ };
+ OBJECT_MEMBERS.iteritems = OBJECT_MEMBERS.items;
+ OBJECT_MEMBERS.itervalues = OBJECT_MEMBERS.values;
+ OBJECT_MEMBERS.iterkeys = OBJECT_MEMBERS.keys;
+ runtime.memberLookup = function(obj, val, autoescape) { // jshint ignore:line
+ obj = obj || {};
+
+ // If the object is an object, return any of the methods that Python would
+ // otherwise provide.
+ if (lib.isArray(obj) && ARRAY_MEMBERS.hasOwnProperty(val)) {
+ return function() {return ARRAY_MEMBERS[val].apply(obj, arguments);};
+ }
+
+ if (lib.isObject(obj) && OBJECT_MEMBERS.hasOwnProperty(val)) {
+ return function() {return OBJECT_MEMBERS[val].apply(obj, arguments);};
+ }
+
+ return orig_memberLookup.apply(this, arguments);
+ };
+ }
+
+ module.exports = installCompat;
+
+
+/***/ }
+/******/ ])
+});
+; \ No newline at end of file