diff options
author | Indrajith K L | 2017-01-17 15:37:25 +0530 |
---|---|---|
committer | Indrajith K L | 2017-01-17 15:37:25 +0530 |
commit | 550e2f03ad0b60b3c9db3d68dbf014dcb740a2ff (patch) | |
tree | faf6bff0bdde8f01514a3f59ecca943569647c40 /src/libs/nunjucks.js | |
download | JSTemplate-550e2f03ad0b60b3c9db3d68dbf014dcb740a2ff.tar.gz JSTemplate-550e2f03ad0b60b3c9db3d68dbf014dcb740a2ff.tar.bz2 JSTemplate-550e2f03ad0b60b3c9db3d68dbf014dcb740a2ff.zip |
Initial Commit
Diffstat (limited to 'src/libs/nunjucks.js')
-rw-r--r-- | src/libs/nunjucks.js | 6692 |
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 = { + '&': '&', + '"': '"', + '\'': ''', + '<': '<', + '>': '>' + }; + + 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 = /^(?:\(|<|<)?(.*?)(?:\.|,|\)|\n|>)?$/; + // 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 |