vendor/assets/javascripts/handlebars.js in handlebars_assets-0.18 vs vendor/assets/javascripts/handlebars.js in handlebars_assets-0.19

- old
+ new

@@ -1,8 +1,8 @@ /*! - handlebars v2.0.0 + handlebars v3.0.0 Copyright (C) 2011-2014 by Yehuda Katz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -23,43 +23,28 @@ THE SOFTWARE. @license */ /* exported Handlebars */ +if (!window) { + var window = {}; +} + (function (root, factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { module.exports = factory(); } else { - root.Handlebars = root.Handlebars || factory(); + root.Handlebars = factory(); } }(this, function () { -// handlebars/safe-string.js -var __module4__ = (function() { - "use strict"; - var __exports__; - // Build out our basic SafeString type - function SafeString(string) { - this.string = string; - } - - SafeString.prototype.toString = function() { - return "" + this.string; - }; - - __exports__ = SafeString; - return __exports__; -})(); - // handlebars/utils.js -var __module3__ = (function(__dependency1__) { +var __module3__ = (function() { "use strict"; var __exports__ = {}; /*jshint -W004 */ - var SafeString = __dependency1__; - var escape = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", @@ -105,15 +90,25 @@ /* istanbul ignore next */ var isArray = Array.isArray || function(value) { return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; }; __exports__.isArray = isArray; + // Older IE versions do not directly support indexOf so we must implement our own, sadly. + function indexOf(array, value) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + return -1; + } + __exports__.indexOf = indexOf; function escapeExpression(string) { // don't escape SafeStrings, since they're already safe - if (string instanceof SafeString) { - return string.toString(); + if (string && string.toHTML) { + return string.toHTML(); } else if (string == null) { return ""; } else if (!string) { return string + ''; } @@ -135,43 +130,51 @@ } else { return false; } } - __exports__.isEmpty = isEmpty;function appendContextPath(contextPath, id) { + __exports__.isEmpty = isEmpty;function blockParams(params, ids) { + params.path = ids; + return params; + } + + __exports__.blockParams = blockParams;function appendContextPath(contextPath, id) { return (contextPath ? contextPath + '.' : '') + id; } __exports__.appendContextPath = appendContextPath; return __exports__; -})(__module4__); +})(); // handlebars/exception.js -var __module5__ = (function() { +var __module4__ = (function() { "use strict"; var __exports__; var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; function Exception(message, node) { - var line; - if (node && node.firstLine) { - line = node.firstLine; + var loc = node && node.loc, + line, + column; + if (loc) { + line = loc.start.line; + column = loc.start.column; - message += ' - ' + line + ':' + node.firstColumn; + message += ' - ' + line + ':' + column; } var tmp = Error.prototype.constructor.call(this, message); // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. for (var idx = 0; idx < errorProps.length; idx++) { this[errorProps[idx]] = tmp[errorProps[idx]]; } - if (line) { + if (loc) { this.lineNumber = line; - this.column = node.firstColumn; + this.column = column; } } Exception.prototype = new Error(); @@ -184,11 +187,11 @@ "use strict"; var __exports__ = {}; var Utils = __dependency1__; var Exception = __dependency2__; - var VERSION = "2.0.0"; + var VERSION = "3.0.0"; __exports__.VERSION = VERSION;var COMPILER_REVISION = 6; __exports__.COMPILER_REVISION = COMPILER_REVISION; var REVISION_CHANGES = { 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 2: '== 1.0.0-rc.3', @@ -230,10 +233,13 @@ registerPartial: function(name, partial) { if (toString.call(name) === objectType) { Utils.extend(this.partials, name); } else { + if (typeof partial === 'undefined') { + throw new Exception('Attempting to register a partial as undefined'); + } this.partials[name] = partial; } }, unregisterPartial: function(name) { delete this.partials[name]; @@ -297,40 +303,51 @@ if (options.data) { data = createFrame(options.data); } + function execIteration(key, i, last) { + if (data) { + data.key = key; + data.index = i; + data.first = i === 0; + data.last = !!last; + + if (contextPath) { + data.contextPath = contextPath + key; + } + } + + ret = ret + fn(context[key], { + data: data, + blockParams: Utils.blockParams([context[key], key], [contextPath + key, null]) + }); + } + if(context && typeof context === 'object') { if (isArray(context)) { for(var j = context.length; i<j; i++) { - if (data) { - data.index = i; - data.first = (i === 0); - data.last = (i === (context.length-1)); - - if (contextPath) { - data.contextPath = contextPath + i; - } - } - ret = ret + fn(context[i], { data: data }); + execIteration(i, i, i === context.length-1); } } else { + var priorKey; + for(var key in context) { if(context.hasOwnProperty(key)) { - if(data) { - data.key = key; - data.index = i; - data.first = (i === 0); - - if (contextPath) { - data.contextPath = contextPath + key; - } + // We're running the iterations one step out of sync so we can detect + // the last iteration without have to scan the object twice and create + // an itermediate keys array. + if (priorKey) { + execIteration(priorKey, i-1); } - ret = ret + fn(context[key], {data: data}); + priorKey = key; i++; } } + if (priorKey) { + execIteration(priorKey, i-1, true); + } } } if(i === 0){ ret = inverse(this); @@ -390,19 +407,17 @@ // State enum DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, - level: 3, + level: 1, - // can be overridden in the host environment + // Can be overridden in the host environment log: function(level, message) { - if (logger.level <= level) { + if (typeof console !== 'undefined' && logger.level <= level) { var method = logger.methodMap[level]; - if (typeof console !== 'undefined' && console[method]) { - console[method].call(console, message); - } + (console[method] || console.log).call(console, message); } } }; __exports__.logger = logger; var log = logger.log; @@ -412,12 +427,29 @@ frame._parent = object; return frame; }; __exports__.createFrame = createFrame; return __exports__; -})(__module3__, __module5__); +})(__module3__, __module4__); +// handlebars/safe-string.js +var __module5__ = (function() { + "use strict"; + var __exports__; + // Build out our basic SafeString type + function SafeString(string) { + this.string = string; + } + + SafeString.prototype.toString = SafeString.prototype.toHTML = function() { + return "" + this.string; + }; + + __exports__ = SafeString; + return __exports__; +})(); + // handlebars/runtime.js var __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) { "use strict"; var __exports__ = {}; var Utils = __dependency1__; @@ -457,42 +489,48 @@ // Note: Using env.VM references rather than local var references throughout this section to allow // for external users to override these as psuedo-supported APIs. env.VM.checkRevision(templateSpec.compiler); - var invokePartialWrapper = function(partial, indent, name, context, hash, helpers, partials, data, depths) { - if (hash) { - context = Utils.extend({}, context, hash); + var invokePartialWrapper = function(partial, context, options) { + if (options.hash) { + context = Utils.extend({}, context, options.hash); } - var result = env.VM.invokePartial.call(this, partial, name, context, helpers, partials, data, depths); + partial = env.VM.resolvePartial.call(this, partial, context, options); + var result = env.VM.invokePartial.call(this, partial, context, options); if (result == null && env.compile) { - var options = { helpers: helpers, partials: partials, data: data, depths: depths }; - partials[name] = env.compile(partial, { data: data !== undefined, compat: templateSpec.compat }, env); - result = partials[name](context, options); + options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env); + result = options.partials[options.name](context, options); } if (result != null) { - if (indent) { + if (options.indent) { var lines = result.split('\n'); for (var i = 0, l = lines.length; i < l; i++) { if (!lines[i] && i + 1 === l) { break; } - lines[i] = indent + lines[i]; + lines[i] = options.indent + lines[i]; } result = lines.join('\n'); } return result; } else { - throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); + throw new Exception("The partial " + options.name + " could not be compiled when running in runtime-only mode"); } }; // Just add water var container = { + strict: function(obj, name) { + if (!(name in obj)) { + throw new Exception('"' + name + '" not defined in ' + obj); + } + return obj[name]; + }, lookup: function(depths, name) { var len = depths.length; for (var i = 0; i < len; i++) { if (depths[i] && depths[i][name] != null) { return depths[i][name]; @@ -509,15 +547,15 @@ fn: function(i) { return templateSpec[i]; }, programs: [], - program: function(i, data, depths) { + program: function(i, data, declaredBlockParams, blockParams, depths) { var programWrapper = this.programs[i], fn = this.fn(i); - if (data || depths) { - programWrapper = program(this, i, fn, data, depths); + if (data || depths || blockParams || declaredBlockParams) { + programWrapper = program(this, i, fn, data, declaredBlockParams, blockParams, depths); } else if (!programWrapper) { programWrapper = this.programs[i] = program(this, i, fn); } return programWrapper; }, @@ -548,16 +586,17 @@ ret._setup(options); if (!options.partial && templateSpec.useData) { data = initData(context, data); } - var depths; + var depths, + blockParams = templateSpec.useBlockParams ? [] : undefined; if (templateSpec.useDepths) { depths = options.depths ? [context].concat(options.depths) : [context]; } - return templateSpec.main.call(container, context, container.helpers, container.partials, data, depths); + return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths); }; ret.isTop = true; ret._setup = function(options) { if (!options.partial) { @@ -570,36 +609,56 @@ container.helpers = options.helpers; container.partials = options.partials; } }; - ret._child = function(i, data, depths) { + ret._child = function(i, data, blockParams, depths) { + if (templateSpec.useBlockParams && !blockParams) { + throw new Exception('must pass block params'); + } if (templateSpec.useDepths && !depths) { throw new Exception('must pass parent depths'); } - return program(container, i, templateSpec[i], data, depths); + return program(container, i, templateSpec[i], data, 0, blockParams, depths); }; return ret; } - __exports__.template = template;function program(container, i, fn, data, depths) { + __exports__.template = template;function program(container, i, fn, data, declaredBlockParams, blockParams, depths) { var prog = function(context, options) { options = options || {}; - return fn.call(container, context, container.helpers, container.partials, options.data || data, depths && [context].concat(depths)); + return fn.call(container, + context, + container.helpers, container.partials, + options.data || data, + blockParams && [options.blockParams].concat(blockParams), + depths && [context].concat(depths)); }; prog.program = i; prog.depth = depths ? depths.length : 0; + prog.blockParams = declaredBlockParams || 0; return prog; } - __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data, depths) { - var options = { partial: true, helpers: helpers, partials: partials, data: data, depths: depths }; + __exports__.program = program;function resolvePartial(partial, context, options) { + if (!partial) { + partial = options.partials[options.name]; + } else if (!partial.call && !options.name) { + // This is a dynamic partial that returned a string + options.name = partial; + partial = options.partials[partial]; + } + return partial; + } + __exports__.resolvePartial = resolvePartial;function invokePartial(partial, context, options) { + options.partial = true; + if(partial === undefined) { - throw new Exception("The partial " + name + " could not be found"); + throw new Exception("The partial " + options.name + " could not be found"); } else if(partial instanceof Function) { return partial(context, options); } } @@ -611,11 +670,11 @@ data.root = context; } return data; } return __exports__; -})(__module3__, __module5__, __module2__); +})(__module3__, __module4__, __module2__); // handlebars.runtime.js var __module1__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { "use strict"; var __exports__; @@ -648,235 +707,174 @@ }; var Handlebars = create(); Handlebars.create = create; + /*jshint -W040 */ + /* istanbul ignore next */ + var root = typeof global !== 'undefined' ? global : window, + $Handlebars = root.Handlebars; + /* istanbul ignore next */ + Handlebars.noConflict = function() { + if (root.Handlebars === Handlebars) { + root.Handlebars = $Handlebars; + } + }; + Handlebars['default'] = Handlebars; __exports__ = Handlebars; return __exports__; -})(__module2__, __module4__, __module5__, __module3__, __module6__); +})(__module2__, __module5__, __module4__, __module3__, __module6__); // handlebars/compiler/ast.js -var __module7__ = (function(__dependency1__) { +var __module7__ = (function() { "use strict"; var __exports__; - var Exception = __dependency1__; - - function LocationInfo(locInfo) { - locInfo = locInfo || {}; - this.firstLine = locInfo.first_line; - this.firstColumn = locInfo.first_column; - this.lastColumn = locInfo.last_column; - this.lastLine = locInfo.last_line; - } - var AST = { - ProgramNode: function(statements, strip, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "program"; - this.statements = statements; - this.strip = strip; - }, + Program: function(statements, blockParams, strip, locInfo) { + this.loc = locInfo; + this.type = 'Program'; + this.body = statements; - MustacheNode: function(rawParams, hash, open, strip, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "mustache"; + this.blockParams = blockParams; this.strip = strip; - - // Open may be a string parsed from the parser or a passed boolean flag - if (open != null && open.charAt) { - // Must use charAt to support IE pre-10 - var escapeFlag = open.charAt(3) || open.charAt(2); - this.escaped = escapeFlag !== '{' && escapeFlag !== '&'; - } else { - this.escaped = !!open; - } - - if (rawParams instanceof AST.SexprNode) { - this.sexpr = rawParams; - } else { - // Support old AST API - this.sexpr = new AST.SexprNode(rawParams, hash); - } - - // Support old AST API that stored this info in MustacheNode - this.id = this.sexpr.id; - this.params = this.sexpr.params; - this.hash = this.sexpr.hash; - this.eligibleHelper = this.sexpr.eligibleHelper; - this.isHelper = this.sexpr.isHelper; }, - SexprNode: function(rawParams, hash, locInfo) { - LocationInfo.call(this, locInfo); + MustacheStatement: function(path, params, hash, escaped, strip, locInfo) { + this.loc = locInfo; + this.type = 'MustacheStatement'; - this.type = "sexpr"; + this.path = path; + this.params = params || []; this.hash = hash; + this.escaped = escaped; - var id = this.id = rawParams[0]; - var params = this.params = rawParams.slice(1); - - // a mustache is definitely a helper if: - // * it is an eligible helper, and - // * it has at least one parameter or hash segment - this.isHelper = !!(params.length || hash); - - // a mustache is an eligible helper if: - // * its id is simple (a single part, not `this` or `..`) - this.eligibleHelper = this.isHelper || id.isSimple; - - // if a mustache is an eligible helper but not a definite - // helper, it is ambiguous, and will be resolved in a later - // pass or at runtime. - }, - - PartialNode: function(partialName, context, hash, strip, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "partial"; - this.partialName = partialName; - this.context = context; - this.hash = hash; this.strip = strip; - - this.strip.inlineStandalone = true; }, - BlockNode: function(mustache, program, inverse, strip, locInfo) { - LocationInfo.call(this, locInfo); + BlockStatement: function(path, params, hash, program, inverse, openStrip, inverseStrip, closeStrip, locInfo) { + this.loc = locInfo; + this.type = 'BlockStatement'; - this.type = 'block'; - this.mustache = mustache; + this.path = path; + this.params = params || []; + this.hash = hash; this.program = program; this.inverse = inverse; - this.strip = strip; - if (inverse && !program) { - this.isInverse = true; - } + this.openStrip = openStrip; + this.inverseStrip = inverseStrip; + this.closeStrip = closeStrip; }, - RawBlockNode: function(mustache, content, close, locInfo) { - LocationInfo.call(this, locInfo); + PartialStatement: function(name, params, hash, strip, locInfo) { + this.loc = locInfo; + this.type = 'PartialStatement'; - if (mustache.sexpr.id.original !== close) { - throw new Exception(mustache.sexpr.id.original + " doesn't match " + close, this); - } + this.name = name; + this.params = params || []; + this.hash = hash; - content = new AST.ContentNode(content, locInfo); - - this.type = 'block'; - this.mustache = mustache; - this.program = new AST.ProgramNode([content], {}, locInfo); + this.indent = ''; + this.strip = strip; }, - ContentNode: function(string, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "content"; - this.original = this.string = string; + ContentStatement: function(string, locInfo) { + this.loc = locInfo; + this.type = 'ContentStatement'; + this.original = this.value = string; }, - HashNode: function(pairs, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "hash"; - this.pairs = pairs; + CommentStatement: function(comment, strip, locInfo) { + this.loc = locInfo; + this.type = 'CommentStatement'; + this.value = comment; + + this.strip = strip; }, - IdNode: function(parts, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "ID"; + SubExpression: function(path, params, hash, locInfo) { + this.loc = locInfo; - var original = "", - dig = [], - depth = 0, - depthString = ''; + this.type = 'SubExpression'; + this.path = path; + this.params = params || []; + this.hash = hash; + }, - for(var i=0,l=parts.length; i<l; i++) { - var part = parts[i].part; - original += (parts[i].separator || '') + part; + PathExpression: function(data, depth, parts, original, locInfo) { + this.loc = locInfo; + this.type = 'PathExpression'; - if (part === ".." || part === "." || part === "this") { - if (dig.length > 0) { - throw new Exception("Invalid path: " + original, this); - } else if (part === "..") { - depth++; - depthString += '../'; - } else { - this.isScoped = true; - } - } else { - dig.push(part); - } - } - + this.data = data; this.original = original; - this.parts = dig; - this.string = dig.join('.'); + this.parts = parts; this.depth = depth; - this.idName = depthString + this.string; - - // an ID is simple if it only has one part, and that part is not - // `..` or `this`. - this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; - - this.stringModeValue = this.string; }, - PartialNameNode: function(name, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "PARTIAL_NAME"; - this.name = name.original; + StringLiteral: function(string, locInfo) { + this.loc = locInfo; + this.type = 'StringLiteral'; + this.original = + this.value = string; }, - DataNode: function(id, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "DATA"; - this.id = id; - this.stringModeValue = id.stringModeValue; - this.idName = '@' + id.stringModeValue; - }, - - StringNode: function(string, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "STRING"; + NumberLiteral: function(number, locInfo) { + this.loc = locInfo; + this.type = 'NumberLiteral'; this.original = - this.string = - this.stringModeValue = string; + this.value = Number(number); }, - NumberNode: function(number, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "NUMBER"; + BooleanLiteral: function(bool, locInfo) { + this.loc = locInfo; + this.type = 'BooleanLiteral'; this.original = - this.number = number; - this.stringModeValue = Number(number); + this.value = bool === 'true'; }, - BooleanNode: function(bool, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "BOOLEAN"; - this.bool = bool; - this.stringModeValue = bool === "true"; + Hash: function(pairs, locInfo) { + this.loc = locInfo; + this.type = 'Hash'; + this.pairs = pairs; }, + HashPair: function(key, value, locInfo) { + this.loc = locInfo; + this.type = 'HashPair'; + this.key = key; + this.value = value; + }, - CommentNode: function(comment, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "comment"; - this.comment = comment; + // Public API used to evaluate derived attributes regarding AST nodes + helpers: { + // a mustache is definitely a helper if: + // * it is an eligible helper, and + // * it has at least one parameter or hash segment + // TODO: Make these public utility methods + helperExpression: function(node) { + return !!(node.type === 'SubExpression' || node.params.length || node.hash); + }, - this.strip = { - inlineStandalone: true - }; + scopedId: function(path) { + return (/^\.|this\b/).test(path.original); + }, + + // an ID is simple if it only has one part, and that part is not + // `..` or `this`. + simpleId: function(path) { + return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth; + } } }; // Must be exported as an object rather than the root of the module as the jison lexer - // most modify the object to operate properly. + // must modify the object to operate properly. __exports__ = AST; return __exports__; -})(__module5__); +})(); // handlebars/compiler/parser.js var __module9__ = (function() { "use strict"; var __exports__; @@ -884,107 +882,151 @@ /* istanbul ignore next */ /* Jison generated parser */ var handlebars = (function(){ var parser = {trace: function trace() { }, yy: {}, - symbols_: {"error":2,"root":3,"program":4,"EOF":5,"program_repetition0":6,"statement":7,"mustache":8,"block":9,"rawBlock":10,"partial":11,"CONTENT":12,"COMMENT":13,"openRawBlock":14,"END_RAW_BLOCK":15,"OPEN_RAW_BLOCK":16,"sexpr":17,"CLOSE_RAW_BLOCK":18,"openBlock":19,"block_option0":20,"closeBlock":21,"openInverse":22,"block_option1":23,"OPEN_BLOCK":24,"CLOSE":25,"OPEN_INVERSE":26,"inverseAndProgram":27,"INVERSE":28,"OPEN_ENDBLOCK":29,"path":30,"OPEN":31,"OPEN_UNESCAPED":32,"CLOSE_UNESCAPED":33,"OPEN_PARTIAL":34,"partialName":35,"param":36,"partial_option0":37,"partial_option1":38,"sexpr_repetition0":39,"sexpr_option0":40,"dataName":41,"STRING":42,"NUMBER":43,"BOOLEAN":44,"OPEN_SEXPR":45,"CLOSE_SEXPR":46,"hash":47,"hash_repetition_plus0":48,"hashSegment":49,"ID":50,"EQUALS":51,"DATA":52,"pathSegments":53,"SEP":54,"$accept":0,"$end":1}, - terminals_: {2:"error",5:"EOF",12:"CONTENT",13:"COMMENT",15:"END_RAW_BLOCK",16:"OPEN_RAW_BLOCK",18:"CLOSE_RAW_BLOCK",24:"OPEN_BLOCK",25:"CLOSE",26:"OPEN_INVERSE",28:"INVERSE",29:"OPEN_ENDBLOCK",31:"OPEN",32:"OPEN_UNESCAPED",33:"CLOSE_UNESCAPED",34:"OPEN_PARTIAL",42:"STRING",43:"NUMBER",44:"BOOLEAN",45:"OPEN_SEXPR",46:"CLOSE_SEXPR",50:"ID",51:"EQUALS",52:"DATA",54:"SEP"}, - productions_: [0,[3,2],[4,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[10,3],[14,3],[9,4],[9,4],[19,3],[22,3],[27,2],[21,3],[8,3],[8,3],[11,5],[11,4],[17,3],[17,1],[36,1],[36,1],[36,1],[36,1],[36,1],[36,3],[47,1],[49,3],[35,1],[35,1],[35,1],[41,2],[30,1],[53,3],[53,1],[6,0],[6,2],[20,0],[20,1],[23,0],[23,1],[37,0],[37,1],[38,0],[38,1],[39,0],[39,2],[40,0],[40,1],[48,1],[48,2]], + symbols_: {"error":2,"root":3,"program":4,"EOF":5,"program_repetition0":6,"statement":7,"mustache":8,"block":9,"rawBlock":10,"partial":11,"content":12,"COMMENT":13,"CONTENT":14,"openRawBlock":15,"END_RAW_BLOCK":16,"OPEN_RAW_BLOCK":17,"helperName":18,"openRawBlock_repetition0":19,"openRawBlock_option0":20,"CLOSE_RAW_BLOCK":21,"openBlock":22,"block_option0":23,"closeBlock":24,"openInverse":25,"block_option1":26,"OPEN_BLOCK":27,"openBlock_repetition0":28,"openBlock_option0":29,"openBlock_option1":30,"CLOSE":31,"OPEN_INVERSE":32,"openInverse_repetition0":33,"openInverse_option0":34,"openInverse_option1":35,"openInverseChain":36,"OPEN_INVERSE_CHAIN":37,"openInverseChain_repetition0":38,"openInverseChain_option0":39,"openInverseChain_option1":40,"inverseAndProgram":41,"INVERSE":42,"inverseChain":43,"inverseChain_option0":44,"OPEN_ENDBLOCK":45,"OPEN":46,"mustache_repetition0":47,"mustache_option0":48,"OPEN_UNESCAPED":49,"mustache_repetition1":50,"mustache_option1":51,"CLOSE_UNESCAPED":52,"OPEN_PARTIAL":53,"partialName":54,"partial_repetition0":55,"partial_option0":56,"param":57,"sexpr":58,"OPEN_SEXPR":59,"sexpr_repetition0":60,"sexpr_option0":61,"CLOSE_SEXPR":62,"hash":63,"hash_repetition_plus0":64,"hashSegment":65,"ID":66,"EQUALS":67,"blockParams":68,"OPEN_BLOCK_PARAMS":69,"blockParams_repetition_plus0":70,"CLOSE_BLOCK_PARAMS":71,"path":72,"dataName":73,"STRING":74,"NUMBER":75,"BOOLEAN":76,"DATA":77,"pathSegments":78,"SEP":79,"$accept":0,"$end":1}, + terminals_: {2:"error",5:"EOF",13:"COMMENT",14:"CONTENT",16:"END_RAW_BLOCK",17:"OPEN_RAW_BLOCK",21:"CLOSE_RAW_BLOCK",27:"OPEN_BLOCK",31:"CLOSE",32:"OPEN_INVERSE",37:"OPEN_INVERSE_CHAIN",42:"INVERSE",45:"OPEN_ENDBLOCK",46:"OPEN",49:"OPEN_UNESCAPED",52:"CLOSE_UNESCAPED",53:"OPEN_PARTIAL",59:"OPEN_SEXPR",62:"CLOSE_SEXPR",66:"ID",67:"EQUALS",69:"OPEN_BLOCK_PARAMS",71:"CLOSE_BLOCK_PARAMS",74:"STRING",75:"NUMBER",76:"BOOLEAN",77:"DATA",79:"SEP"}, + productions_: [0,[3,2],[4,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[12,1],[10,3],[15,5],[9,4],[9,4],[22,6],[25,6],[36,6],[41,2],[43,3],[43,1],[24,3],[8,5],[8,5],[11,5],[57,1],[57,1],[58,5],[63,1],[65,3],[68,3],[18,1],[18,1],[18,1],[18,1],[18,1],[54,1],[54,1],[73,2],[72,1],[78,3],[78,1],[6,0],[6,2],[19,0],[19,2],[20,0],[20,1],[23,0],[23,1],[26,0],[26,1],[28,0],[28,2],[29,0],[29,1],[30,0],[30,1],[33,0],[33,2],[34,0],[34,1],[35,0],[35,1],[38,0],[38,2],[39,0],[39,1],[40,0],[40,1],[44,0],[44,1],[47,0],[47,2],[48,0],[48,1],[50,0],[50,2],[51,0],[51,1],[55,0],[55,2],[56,0],[56,1],[60,0],[60,2],[61,0],[61,1],[64,1],[64,2],[70,1],[70,2]], performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { var $0 = $$.length - 1; switch (yystate) { - case 1: yy.prepareProgram($$[$0-1].statements, true); return $$[$0-1]; + case 1: return $$[$0-1]; break; - case 2:this.$ = new yy.ProgramNode(yy.prepareProgram($$[$0]), {}, this._$); + case 2:this.$ = new yy.Program($$[$0], null, {}, yy.locInfo(this._$)); break; case 3:this.$ = $$[$0]; break; case 4:this.$ = $$[$0]; break; case 5:this.$ = $$[$0]; break; case 6:this.$ = $$[$0]; break; - case 7:this.$ = new yy.ContentNode($$[$0], this._$); + case 7:this.$ = $$[$0]; break; - case 8:this.$ = new yy.CommentNode($$[$0], this._$); + case 8:this.$ = new yy.CommentStatement(yy.stripComment($$[$0]), yy.stripFlags($$[$0], $$[$0]), yy.locInfo(this._$)); break; - case 9:this.$ = new yy.RawBlockNode($$[$0-2], $$[$0-1], $$[$0], this._$); + case 9:this.$ = new yy.ContentStatement($$[$0], yy.locInfo(this._$)); break; - case 10:this.$ = new yy.MustacheNode($$[$0-1], null, '', '', this._$); + case 10:this.$ = yy.prepareRawBlock($$[$0-2], $$[$0-1], $$[$0], this._$); break; - case 11:this.$ = yy.prepareBlock($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], false, this._$); + case 11:this.$ = { path: $$[$0-3], params: $$[$0-2], hash: $$[$0-1] }; break; - case 12:this.$ = yy.prepareBlock($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], true, this._$); + case 12:this.$ = yy.prepareBlock($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], false, this._$); break; - case 13:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$); + case 13:this.$ = yy.prepareBlock($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], true, this._$); break; - case 14:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$); + case 14:this.$ = { path: $$[$0-4], params: $$[$0-3], hash: $$[$0-2], blockParams: $$[$0-1], strip: yy.stripFlags($$[$0-5], $$[$0]) }; break; - case 15:this.$ = { strip: yy.stripFlags($$[$0-1], $$[$0-1]), program: $$[$0] }; + case 15:this.$ = { path: $$[$0-4], params: $$[$0-3], hash: $$[$0-2], blockParams: $$[$0-1], strip: yy.stripFlags($$[$0-5], $$[$0]) }; break; - case 16:this.$ = {path: $$[$0-1], strip: yy.stripFlags($$[$0-2], $$[$0])}; + case 16:this.$ = { path: $$[$0-4], params: $$[$0-3], hash: $$[$0-2], blockParams: $$[$0-1], strip: yy.stripFlags($$[$0-5], $$[$0]) }; break; - case 17:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$); + case 17:this.$ = { strip: yy.stripFlags($$[$0-1], $$[$0-1]), program: $$[$0] }; break; - case 18:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$); + case 18: + var inverse = yy.prepareBlock($$[$0-2], $$[$0-1], $$[$0], $$[$0], false, this._$), + program = new yy.Program([inverse], null, {}, yy.locInfo(this._$)); + program.chained = true; + + this.$ = { strip: $$[$0-2].strip, program: program, chain: true }; + break; - case 19:this.$ = new yy.PartialNode($$[$0-3], $$[$0-2], $$[$0-1], yy.stripFlags($$[$0-4], $$[$0]), this._$); + case 19:this.$ = $$[$0]; break; - case 20:this.$ = new yy.PartialNode($$[$0-2], undefined, $$[$0-1], yy.stripFlags($$[$0-3], $$[$0]), this._$); + case 20:this.$ = {path: $$[$0-1], strip: yy.stripFlags($$[$0-2], $$[$0])}; break; - case 21:this.$ = new yy.SexprNode([$$[$0-2]].concat($$[$0-1]), $$[$0], this._$); + case 21:this.$ = yy.prepareMustache($$[$0-3], $$[$0-2], $$[$0-1], $$[$0-4], yy.stripFlags($$[$0-4], $$[$0]), this._$); break; - case 22:this.$ = new yy.SexprNode([$$[$0]], null, this._$); + case 22:this.$ = yy.prepareMustache($$[$0-3], $$[$0-2], $$[$0-1], $$[$0-4], yy.stripFlags($$[$0-4], $$[$0]), this._$); break; - case 23:this.$ = $$[$0]; + case 23:this.$ = new yy.PartialStatement($$[$0-3], $$[$0-2], $$[$0-1], yy.stripFlags($$[$0-4], $$[$0]), yy.locInfo(this._$)); break; - case 24:this.$ = new yy.StringNode($$[$0], this._$); + case 24:this.$ = $$[$0]; break; - case 25:this.$ = new yy.NumberNode($$[$0], this._$); + case 25:this.$ = $$[$0]; break; - case 26:this.$ = new yy.BooleanNode($$[$0], this._$); + case 26:this.$ = new yy.SubExpression($$[$0-3], $$[$0-2], $$[$0-1], yy.locInfo(this._$)); break; - case 27:this.$ = $$[$0]; + case 27:this.$ = new yy.Hash($$[$0], yy.locInfo(this._$)); break; - case 28:$$[$0-1].isHelper = true; this.$ = $$[$0-1]; + case 28:this.$ = new yy.HashPair($$[$0-2], $$[$0], yy.locInfo(this._$)); break; - case 29:this.$ = new yy.HashNode($$[$0], this._$); + case 29:this.$ = $$[$0-1]; break; - case 30:this.$ = [$$[$0-2], $$[$0]]; + case 30:this.$ = $$[$0]; break; - case 31:this.$ = new yy.PartialNameNode($$[$0], this._$); + case 31:this.$ = $$[$0]; break; - case 32:this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0], this._$), this._$); + case 32:this.$ = new yy.StringLiteral($$[$0], yy.locInfo(this._$)); break; - case 33:this.$ = new yy.PartialNameNode(new yy.NumberNode($$[$0], this._$)); + case 33:this.$ = new yy.NumberLiteral($$[$0], yy.locInfo(this._$)); break; - case 34:this.$ = new yy.DataNode($$[$0], this._$); + case 34:this.$ = new yy.BooleanLiteral($$[$0], yy.locInfo(this._$)); break; - case 35:this.$ = new yy.IdNode($$[$0], this._$); + case 35:this.$ = $$[$0]; break; - case 36: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2]; + case 36:this.$ = $$[$0]; break; - case 37:this.$ = [{part: $$[$0]}]; + case 37:this.$ = yy.preparePath(true, $$[$0], this._$); break; - case 38:this.$ = []; + case 38:this.$ = yy.preparePath(false, $$[$0], this._$); break; - case 39:$$[$0-1].push($$[$0]); + case 39: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2]; break; - case 48:this.$ = []; + case 40:this.$ = [{part: $$[$0]}]; break; - case 49:$$[$0-1].push($$[$0]); + case 41:this.$ = []; break; - case 52:this.$ = [$$[$0]]; + case 42:$$[$0-1].push($$[$0]); break; - case 53:$$[$0-1].push($$[$0]); + case 43:this.$ = []; break; + case 44:$$[$0-1].push($$[$0]); + break; + case 51:this.$ = []; + break; + case 52:$$[$0-1].push($$[$0]); + break; + case 57:this.$ = []; + break; + case 58:$$[$0-1].push($$[$0]); + break; + case 63:this.$ = []; + break; + case 64:$$[$0-1].push($$[$0]); + break; + case 71:this.$ = []; + break; + case 72:$$[$0-1].push($$[$0]); + break; + case 75:this.$ = []; + break; + case 76:$$[$0-1].push($$[$0]); + break; + case 79:this.$ = []; + break; + case 80:$$[$0-1].push($$[$0]); + break; + case 83:this.$ = []; + break; + case 84:$$[$0-1].push($$[$0]); + break; + case 87:this.$ = [$$[$0]]; + break; + case 88:$$[$0-1].push($$[$0]); + break; + case 89:this.$ = [$$[$0]]; + break; + case 90:$$[$0-1].push($$[$0]); + break; } }, - table: [{3:1,4:2,5:[2,38],6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],31:[2,38],32:[2,38],34:[2,38]},{1:[3]},{5:[1,4]},{5:[2,2],7:5,8:6,9:7,10:8,11:9,12:[1,10],13:[1,11],14:16,16:[1,20],19:14,22:15,24:[1,18],26:[1,19],28:[2,2],29:[2,2],31:[1,12],32:[1,13],34:[1,17]},{1:[2,1]},{5:[2,39],12:[2,39],13:[2,39],16:[2,39],24:[2,39],26:[2,39],28:[2,39],29:[2,39],31:[2,39],32:[2,39],34:[2,39]},{5:[2,3],12:[2,3],13:[2,3],16:[2,3],24:[2,3],26:[2,3],28:[2,3],29:[2,3],31:[2,3],32:[2,3],34:[2,3]},{5:[2,4],12:[2,4],13:[2,4],16:[2,4],24:[2,4],26:[2,4],28:[2,4],29:[2,4],31:[2,4],32:[2,4],34:[2,4]},{5:[2,5],12:[2,5],13:[2,5],16:[2,5],24:[2,5],26:[2,5],28:[2,5],29:[2,5],31:[2,5],32:[2,5],34:[2,5]},{5:[2,6],12:[2,6],13:[2,6],16:[2,6],24:[2,6],26:[2,6],28:[2,6],29:[2,6],31:[2,6],32:[2,6],34:[2,6]},{5:[2,7],12:[2,7],13:[2,7],16:[2,7],24:[2,7],26:[2,7],28:[2,7],29:[2,7],31:[2,7],32:[2,7],34:[2,7]},{5:[2,8],12:[2,8],13:[2,8],16:[2,8],24:[2,8],26:[2,8],28:[2,8],29:[2,8],31:[2,8],32:[2,8],34:[2,8]},{17:21,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:27,30:22,41:23,50:[1,26],52:[1,25],53:24},{4:28,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],28:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{4:29,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],28:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{12:[1,30]},{30:32,35:31,42:[1,33],43:[1,34],50:[1,26],53:24},{17:35,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:36,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:37,30:22,41:23,50:[1,26],52:[1,25],53:24},{25:[1,38]},{18:[2,48],25:[2,48],33:[2,48],39:39,42:[2,48],43:[2,48],44:[2,48],45:[2,48],46:[2,48],50:[2,48],52:[2,48]},{18:[2,22],25:[2,22],33:[2,22],46:[2,22]},{18:[2,35],25:[2,35],33:[2,35],42:[2,35],43:[2,35],44:[2,35],45:[2,35],46:[2,35],50:[2,35],52:[2,35],54:[1,40]},{30:41,50:[1,26],53:24},{18:[2,37],25:[2,37],33:[2,37],42:[2,37],43:[2,37],44:[2,37],45:[2,37],46:[2,37],50:[2,37],52:[2,37],54:[2,37]},{33:[1,42]},{20:43,27:44,28:[1,45],29:[2,40]},{23:46,27:47,28:[1,45],29:[2,42]},{15:[1,48]},{25:[2,46],30:51,36:49,38:50,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],47:57,48:58,49:60,50:[1,59],52:[1,25],53:24},{25:[2,31],42:[2,31],43:[2,31],44:[2,31],45:[2,31],50:[2,31],52:[2,31]},{25:[2,32],42:[2,32],43:[2,32],44:[2,32],45:[2,32],50:[2,32],52:[2,32]},{25:[2,33],42:[2,33],43:[2,33],44:[2,33],45:[2,33],50:[2,33],52:[2,33]},{25:[1,61]},{25:[1,62]},{18:[1,63]},{5:[2,17],12:[2,17],13:[2,17],16:[2,17],24:[2,17],26:[2,17],28:[2,17],29:[2,17],31:[2,17],32:[2,17],34:[2,17]},{18:[2,50],25:[2,50],30:51,33:[2,50],36:65,40:64,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],46:[2,50],47:66,48:58,49:60,50:[1,59],52:[1,25],53:24},{50:[1,67]},{18:[2,34],25:[2,34],33:[2,34],42:[2,34],43:[2,34],44:[2,34],45:[2,34],46:[2,34],50:[2,34],52:[2,34]},{5:[2,18],12:[2,18],13:[2,18],16:[2,18],24:[2,18],26:[2,18],28:[2,18],29:[2,18],31:[2,18],32:[2,18],34:[2,18]},{21:68,29:[1,69]},{29:[2,41]},{4:70,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{21:71,29:[1,69]},{29:[2,43]},{5:[2,9],12:[2,9],13:[2,9],16:[2,9],24:[2,9],26:[2,9],28:[2,9],29:[2,9],31:[2,9],32:[2,9],34:[2,9]},{25:[2,44],37:72,47:73,48:58,49:60,50:[1,74]},{25:[1,75]},{18:[2,23],25:[2,23],33:[2,23],42:[2,23],43:[2,23],44:[2,23],45:[2,23],46:[2,23],50:[2,23],52:[2,23]},{18:[2,24],25:[2,24],33:[2,24],42:[2,24],43:[2,24],44:[2,24],45:[2,24],46:[2,24],50:[2,24],52:[2,24]},{18:[2,25],25:[2,25],33:[2,25],42:[2,25],43:[2,25],44:[2,25],45:[2,25],46:[2,25],50:[2,25],52:[2,25]},{18:[2,26],25:[2,26],33:[2,26],42:[2,26],43:[2,26],44:[2,26],45:[2,26],46:[2,26],50:[2,26],52:[2,26]},{18:[2,27],25:[2,27],33:[2,27],42:[2,27],43:[2,27],44:[2,27],45:[2,27],46:[2,27],50:[2,27],52:[2,27]},{17:76,30:22,41:23,50:[1,26],52:[1,25],53:24},{25:[2,47]},{18:[2,29],25:[2,29],33:[2,29],46:[2,29],49:77,50:[1,74]},{18:[2,37],25:[2,37],33:[2,37],42:[2,37],43:[2,37],44:[2,37],45:[2,37],46:[2,37],50:[2,37],51:[1,78],52:[2,37],54:[2,37]},{18:[2,52],25:[2,52],33:[2,52],46:[2,52],50:[2,52]},{12:[2,13],13:[2,13],16:[2,13],24:[2,13],26:[2,13],28:[2,13],29:[2,13],31:[2,13],32:[2,13],34:[2,13]},{12:[2,14],13:[2,14],16:[2,14],24:[2,14],26:[2,14],28:[2,14],29:[2,14],31:[2,14],32:[2,14],34:[2,14]},{12:[2,10]},{18:[2,21],25:[2,21],33:[2,21],46:[2,21]},{18:[2,49],25:[2,49],33:[2,49],42:[2,49],43:[2,49],44:[2,49],45:[2,49],46:[2,49],50:[2,49],52:[2,49]},{18:[2,51],25:[2,51],33:[2,51],46:[2,51]},{18:[2,36],25:[2,36],33:[2,36],42:[2,36],43:[2,36],44:[2,36],45:[2,36],46:[2,36],50:[2,36],52:[2,36],54:[2,36]},{5:[2,11],12:[2,11],13:[2,11],16:[2,11],24:[2,11],26:[2,11],28:[2,11],29:[2,11],31:[2,11],32:[2,11],34:[2,11]},{30:79,50:[1,26],53:24},{29:[2,15]},{5:[2,12],12:[2,12],13:[2,12],16:[2,12],24:[2,12],26:[2,12],28:[2,12],29:[2,12],31:[2,12],32:[2,12],34:[2,12]},{25:[1,80]},{25:[2,45]},{51:[1,78]},{5:[2,20],12:[2,20],13:[2,20],16:[2,20],24:[2,20],26:[2,20],28:[2,20],29:[2,20],31:[2,20],32:[2,20],34:[2,20]},{46:[1,81]},{18:[2,53],25:[2,53],33:[2,53],46:[2,53],50:[2,53]},{30:51,36:82,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],50:[1,26],52:[1,25],53:24},{25:[1,83]},{5:[2,19],12:[2,19],13:[2,19],16:[2,19],24:[2,19],26:[2,19],28:[2,19],29:[2,19],31:[2,19],32:[2,19],34:[2,19]},{18:[2,28],25:[2,28],33:[2,28],42:[2,28],43:[2,28],44:[2,28],45:[2,28],46:[2,28],50:[2,28],52:[2,28]},{18:[2,30],25:[2,30],33:[2,30],46:[2,30],50:[2,30]},{5:[2,16],12:[2,16],13:[2,16],16:[2,16],24:[2,16],26:[2,16],28:[2,16],29:[2,16],31:[2,16],32:[2,16],34:[2,16]}], - defaultActions: {4:[2,1],44:[2,41],47:[2,43],57:[2,47],63:[2,10],70:[2,15],73:[2,45]}, + table: [{3:1,4:2,5:[2,41],6:3,13:[2,41],14:[2,41],17:[2,41],27:[2,41],32:[2,41],46:[2,41],49:[2,41],53:[2,41]},{1:[3]},{5:[1,4]},{5:[2,2],7:5,8:6,9:7,10:8,11:9,12:10,13:[1,11],14:[1,18],15:16,17:[1,21],22:14,25:15,27:[1,19],32:[1,20],37:[2,2],42:[2,2],45:[2,2],46:[1,12],49:[1,13],53:[1,17]},{1:[2,1]},{5:[2,42],13:[2,42],14:[2,42],17:[2,42],27:[2,42],32:[2,42],37:[2,42],42:[2,42],45:[2,42],46:[2,42],49:[2,42],53:[2,42]},{5:[2,3],13:[2,3],14:[2,3],17:[2,3],27:[2,3],32:[2,3],37:[2,3],42:[2,3],45:[2,3],46:[2,3],49:[2,3],53:[2,3]},{5:[2,4],13:[2,4],14:[2,4],17:[2,4],27:[2,4],32:[2,4],37:[2,4],42:[2,4],45:[2,4],46:[2,4],49:[2,4],53:[2,4]},{5:[2,5],13:[2,5],14:[2,5],17:[2,5],27:[2,5],32:[2,5],37:[2,5],42:[2,5],45:[2,5],46:[2,5],49:[2,5],53:[2,5]},{5:[2,6],13:[2,6],14:[2,6],17:[2,6],27:[2,6],32:[2,6],37:[2,6],42:[2,6],45:[2,6],46:[2,6],49:[2,6],53:[2,6]},{5:[2,7],13:[2,7],14:[2,7],17:[2,7],27:[2,7],32:[2,7],37:[2,7],42:[2,7],45:[2,7],46:[2,7],49:[2,7],53:[2,7]},{5:[2,8],13:[2,8],14:[2,8],17:[2,8],27:[2,8],32:[2,8],37:[2,8],42:[2,8],45:[2,8],46:[2,8],49:[2,8],53:[2,8]},{18:22,66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{18:31,66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{4:32,6:3,13:[2,41],14:[2,41],17:[2,41],27:[2,41],32:[2,41],37:[2,41],42:[2,41],45:[2,41],46:[2,41],49:[2,41],53:[2,41]},{4:33,6:3,13:[2,41],14:[2,41],17:[2,41],27:[2,41],32:[2,41],42:[2,41],45:[2,41],46:[2,41],49:[2,41],53:[2,41]},{12:34,14:[1,18]},{18:36,54:35,58:37,59:[1,38],66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{5:[2,9],13:[2,9],14:[2,9],16:[2,9],17:[2,9],27:[2,9],32:[2,9],37:[2,9],42:[2,9],45:[2,9],46:[2,9],49:[2,9],53:[2,9]},{18:39,66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{18:40,66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{18:41,66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{31:[2,71],47:42,59:[2,71],66:[2,71],74:[2,71],75:[2,71],76:[2,71],77:[2,71]},{21:[2,30],31:[2,30],52:[2,30],59:[2,30],62:[2,30],66:[2,30],69:[2,30],74:[2,30],75:[2,30],76:[2,30],77:[2,30]},{21:[2,31],31:[2,31],52:[2,31],59:[2,31],62:[2,31],66:[2,31],69:[2,31],74:[2,31],75:[2,31],76:[2,31],77:[2,31]},{21:[2,32],31:[2,32],52:[2,32],59:[2,32],62:[2,32],66:[2,32],69:[2,32],74:[2,32],75:[2,32],76:[2,32],77:[2,32]},{21:[2,33],31:[2,33],52:[2,33],59:[2,33],62:[2,33],66:[2,33],69:[2,33],74:[2,33],75:[2,33],76:[2,33],77:[2,33]},{21:[2,34],31:[2,34],52:[2,34],59:[2,34],62:[2,34],66:[2,34],69:[2,34],74:[2,34],75:[2,34],76:[2,34],77:[2,34]},{21:[2,38],31:[2,38],52:[2,38],59:[2,38],62:[2,38],66:[2,38],69:[2,38],74:[2,38],75:[2,38],76:[2,38],77:[2,38],79:[1,43]},{66:[1,30],78:44},{21:[2,40],31:[2,40],52:[2,40],59:[2,40],62:[2,40],66:[2,40],69:[2,40],74:[2,40],75:[2,40],76:[2,40],77:[2,40],79:[2,40]},{50:45,52:[2,75],59:[2,75],66:[2,75],74:[2,75],75:[2,75],76:[2,75],77:[2,75]},{23:46,36:48,37:[1,50],41:49,42:[1,51],43:47,45:[2,47]},{26:52,41:53,42:[1,51],45:[2,49]},{16:[1,54]},{31:[2,79],55:55,59:[2,79],66:[2,79],74:[2,79],75:[2,79],76:[2,79],77:[2,79]},{31:[2,35],59:[2,35],66:[2,35],74:[2,35],75:[2,35],76:[2,35],77:[2,35]},{31:[2,36],59:[2,36],66:[2,36],74:[2,36],75:[2,36],76:[2,36],77:[2,36]},{18:56,66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{28:57,31:[2,51],59:[2,51],66:[2,51],69:[2,51],74:[2,51],75:[2,51],76:[2,51],77:[2,51]},{31:[2,57],33:58,59:[2,57],66:[2,57],69:[2,57],74:[2,57],75:[2,57],76:[2,57],77:[2,57]},{19:59,21:[2,43],59:[2,43],66:[2,43],74:[2,43],75:[2,43],76:[2,43],77:[2,43]},{18:63,31:[2,73],48:60,57:61,58:64,59:[1,38],63:62,64:65,65:66,66:[1,67],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{66:[1,68]},{21:[2,37],31:[2,37],52:[2,37],59:[2,37],62:[2,37],66:[2,37],69:[2,37],74:[2,37],75:[2,37],76:[2,37],77:[2,37],79:[1,43]},{18:63,51:69,52:[2,77],57:70,58:64,59:[1,38],63:71,64:65,65:66,66:[1,67],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{24:72,45:[1,73]},{45:[2,48]},{4:74,6:3,13:[2,41],14:[2,41],17:[2,41],27:[2,41],32:[2,41],37:[2,41],42:[2,41],45:[2,41],46:[2,41],49:[2,41],53:[2,41]},{45:[2,19]},{18:75,66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{4:76,6:3,13:[2,41],14:[2,41],17:[2,41],27:[2,41],32:[2,41],45:[2,41],46:[2,41],49:[2,41],53:[2,41]},{24:77,45:[1,73]},{45:[2,50]},{5:[2,10],13:[2,10],14:[2,10],17:[2,10],27:[2,10],32:[2,10],37:[2,10],42:[2,10],45:[2,10],46:[2,10],49:[2,10],53:[2,10]},{18:63,31:[2,81],56:78,57:79,58:64,59:[1,38],63:80,64:65,65:66,66:[1,67],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{59:[2,83],60:81,62:[2,83],66:[2,83],74:[2,83],75:[2,83],76:[2,83],77:[2,83]},{18:63,29:82,31:[2,53],57:83,58:64,59:[1,38],63:84,64:65,65:66,66:[1,67],69:[2,53],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{18:63,31:[2,59],34:85,57:86,58:64,59:[1,38],63:87,64:65,65:66,66:[1,67],69:[2,59],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{18:63,20:88,21:[2,45],57:89,58:64,59:[1,38],63:90,64:65,65:66,66:[1,67],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{31:[1,91]},{31:[2,72],59:[2,72],66:[2,72],74:[2,72],75:[2,72],76:[2,72],77:[2,72]},{31:[2,74]},{21:[2,24],31:[2,24],52:[2,24],59:[2,24],62:[2,24],66:[2,24],69:[2,24],74:[2,24],75:[2,24],76:[2,24],77:[2,24]},{21:[2,25],31:[2,25],52:[2,25],59:[2,25],62:[2,25],66:[2,25],69:[2,25],74:[2,25],75:[2,25],76:[2,25],77:[2,25]},{21:[2,27],31:[2,27],52:[2,27],62:[2,27],65:92,66:[1,93],69:[2,27]},{21:[2,87],31:[2,87],52:[2,87],62:[2,87],66:[2,87],69:[2,87]},{21:[2,40],31:[2,40],52:[2,40],59:[2,40],62:[2,40],66:[2,40],67:[1,94],69:[2,40],74:[2,40],75:[2,40],76:[2,40],77:[2,40],79:[2,40]},{21:[2,39],31:[2,39],52:[2,39],59:[2,39],62:[2,39],66:[2,39],69:[2,39],74:[2,39],75:[2,39],76:[2,39],77:[2,39],79:[2,39]},{52:[1,95]},{52:[2,76],59:[2,76],66:[2,76],74:[2,76],75:[2,76],76:[2,76],77:[2,76]},{52:[2,78]},{5:[2,12],13:[2,12],14:[2,12],17:[2,12],27:[2,12],32:[2,12],37:[2,12],42:[2,12],45:[2,12],46:[2,12],49:[2,12],53:[2,12]},{18:96,66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{36:48,37:[1,50],41:49,42:[1,51],43:98,44:97,45:[2,69]},{31:[2,63],38:99,59:[2,63],66:[2,63],69:[2,63],74:[2,63],75:[2,63],76:[2,63],77:[2,63]},{45:[2,17]},{5:[2,13],13:[2,13],14:[2,13],17:[2,13],27:[2,13],32:[2,13],37:[2,13],42:[2,13],45:[2,13],46:[2,13],49:[2,13],53:[2,13]},{31:[1,100]},{31:[2,80],59:[2,80],66:[2,80],74:[2,80],75:[2,80],76:[2,80],77:[2,80]},{31:[2,82]},{18:63,57:102,58:64,59:[1,38],61:101,62:[2,85],63:103,64:65,65:66,66:[1,67],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{30:104,31:[2,55],68:105,69:[1,106]},{31:[2,52],59:[2,52],66:[2,52],69:[2,52],74:[2,52],75:[2,52],76:[2,52],77:[2,52]},{31:[2,54],69:[2,54]},{31:[2,61],35:107,68:108,69:[1,106]},{31:[2,58],59:[2,58],66:[2,58],69:[2,58],74:[2,58],75:[2,58],76:[2,58],77:[2,58]},{31:[2,60],69:[2,60]},{21:[1,109]},{21:[2,44],59:[2,44],66:[2,44],74:[2,44],75:[2,44],76:[2,44],77:[2,44]},{21:[2,46]},{5:[2,21],13:[2,21],14:[2,21],17:[2,21],27:[2,21],32:[2,21],37:[2,21],42:[2,21],45:[2,21],46:[2,21],49:[2,21],53:[2,21]},{21:[2,88],31:[2,88],52:[2,88],62:[2,88],66:[2,88],69:[2,88]},{67:[1,94]},{18:63,57:110,58:64,59:[1,38],66:[1,30],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{5:[2,22],13:[2,22],14:[2,22],17:[2,22],27:[2,22],32:[2,22],37:[2,22],42:[2,22],45:[2,22],46:[2,22],49:[2,22],53:[2,22]},{31:[1,111]},{45:[2,18]},{45:[2,70]},{18:63,31:[2,65],39:112,57:113,58:64,59:[1,38],63:114,64:65,65:66,66:[1,67],69:[2,65],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,29],78:28},{5:[2,23],13:[2,23],14:[2,23],17:[2,23],27:[2,23],32:[2,23],37:[2,23],42:[2,23],45:[2,23],46:[2,23],49:[2,23],53:[2,23]},{62:[1,115]},{59:[2,84],62:[2,84],66:[2,84],74:[2,84],75:[2,84],76:[2,84],77:[2,84]},{62:[2,86]},{31:[1,116]},{31:[2,56]},{66:[1,118],70:117},{31:[1,119]},{31:[2,62]},{14:[2,11]},{21:[2,28],31:[2,28],52:[2,28],62:[2,28],66:[2,28],69:[2,28]},{5:[2,20],13:[2,20],14:[2,20],17:[2,20],27:[2,20],32:[2,20],37:[2,20],42:[2,20],45:[2,20],46:[2,20],49:[2,20],53:[2,20]},{31:[2,67],40:120,68:121,69:[1,106]},{31:[2,64],59:[2,64],66:[2,64],69:[2,64],74:[2,64],75:[2,64],76:[2,64],77:[2,64]},{31:[2,66],69:[2,66]},{21:[2,26],31:[2,26],52:[2,26],59:[2,26],62:[2,26],66:[2,26],69:[2,26],74:[2,26],75:[2,26],76:[2,26],77:[2,26]},{13:[2,14],14:[2,14],17:[2,14],27:[2,14],32:[2,14],37:[2,14],42:[2,14],45:[2,14],46:[2,14],49:[2,14],53:[2,14]},{66:[1,123],71:[1,122]},{66:[2,89],71:[2,89]},{13:[2,15],14:[2,15],17:[2,15],27:[2,15],32:[2,15],42:[2,15],45:[2,15],46:[2,15],49:[2,15],53:[2,15]},{31:[1,124]},{31:[2,68]},{31:[2,29]},{66:[2,90],71:[2,90]},{13:[2,16],14:[2,16],17:[2,16],27:[2,16],32:[2,16],37:[2,16],42:[2,16],45:[2,16],46:[2,16],49:[2,16],53:[2,16]}], + defaultActions: {4:[2,1],47:[2,48],49:[2,19],53:[2,50],62:[2,74],71:[2,78],76:[2,17],80:[2,82],90:[2,46],97:[2,18],98:[2,70],103:[2,86],105:[2,56],108:[2,62],109:[2,11],121:[2,68],122:[2,29]}, parseError: function parseError(str, hash) { throw new Error(str); }, parse: function parse(input) { var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; @@ -1277,262 +1319,428 @@ strip(0,1); this.begin("emu"); } else { this.begin("mu"); } - if(yy_.yytext) return 12; - + if(yy_.yytext) return 14; + break; - case 1:return 12; + case 1:return 14; break; case 2: this.popState(); - return 12; - + return 14; + break; case 3: yy_.yytext = yy_.yytext.substr(5, yy_.yyleng-9); this.popState(); - return 15; - + return 16; + break; - case 4: return 12; + case 4: return 14; break; - case 5:strip(0,4); this.popState(); return 13; + case 5: + this.popState(); + return 13; + break; - case 6:return 45; + case 6:return 59; break; - case 7:return 46; + case 7:return 62; break; - case 8: return 16; + case 8: return 17; break; case 9: this.popState(); this.begin('raw'); - return 18; - + return 21; + break; - case 10:return 34; + case 10:return 53; break; - case 11:return 24; + case 11:return 27; break; - case 12:return 29; + case 12:return 45; break; - case 13:this.popState(); return 28; + case 13:this.popState(); return 42; break; - case 14:this.popState(); return 28; + case 14:this.popState(); return 42; break; - case 15:return 26; + case 15:return 32; break; - case 16:return 26; + case 16:return 37; break; - case 17:return 32; + case 17:return 49; break; - case 18:return 31; + case 18:return 46; break; - case 19:this.popState(); this.begin('com'); + case 19: + this.unput(yy_.yytext); + this.popState(); + this.begin('com'); + break; - case 20:strip(3,5); this.popState(); return 13; + case 20: + this.popState(); + return 13; + break; - case 21:return 31; + case 21:return 46; break; - case 22:return 51; + case 22:return 67; break; - case 23:return 50; + case 23:return 66; break; - case 24:return 50; + case 24:return 66; break; - case 25:return 54; + case 25:return 79; break; case 26:// ignore whitespace break; - case 27:this.popState(); return 33; + case 27:this.popState(); return 52; break; - case 28:this.popState(); return 25; + case 28:this.popState(); return 31; break; - case 29:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 42; + case 29:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 74; break; - case 30:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 42; + case 30:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 74; break; - case 31:return 52; + case 31:return 77; break; - case 32:return 44; + case 32:return 76; break; - case 33:return 44; + case 33:return 76; break; - case 34:return 43; + case 34:return 75; break; - case 35:return 50; + case 35:return 69; break; - case 36:yy_.yytext = strip(1,2); return 50; + case 36:return 71; break; - case 37:return 'INVALID'; + case 37:return 66; break; - case 38:return 5; + case 38:yy_.yytext = strip(1,2); return 66; break; + case 39:return 'INVALID'; + break; + case 40:return 5; + break; } }; - lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{\/)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; - lexer.conditions = {"mu":{"rules":[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[5],"inclusive":false},"raw":{"rules":[3,4],"inclusive":false},"INITIAL":{"rules":[0,1,38],"inclusive":true}}; + lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{\/)))/,/^(?:[\s\S]*?--(~)?\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{(~)?!--)/,/^(?:\{\{(~)?![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)|])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:as\s+\|)/,/^(?:\|)/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; + lexer.conditions = {"mu":{"rules":[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[5],"inclusive":false},"raw":{"rules":[3,4],"inclusive":false},"INITIAL":{"rules":[0,1,40],"inclusive":true}}; return lexer;})() parser.lexer = lexer; function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; return new Parser; })();__exports__ = handlebars; /* jshint ignore:end */ return __exports__; })(); -// handlebars/compiler/helpers.js -var __module10__ = (function(__dependency1__) { +// handlebars/compiler/visitor.js +var __module11__ = (function(__dependency1__, __dependency2__) { "use strict"; - var __exports__ = {}; + var __exports__; var Exception = __dependency1__; + var AST = __dependency2__; - function stripFlags(open, close) { - return { - left: open.charAt(2) === '~', - right: close.charAt(close.length-3) === '~' - }; + function Visitor() { + this.parents = []; } - __exports__.stripFlags = stripFlags; - function prepareBlock(mustache, program, inverseAndProgram, close, inverted, locInfo) { - /*jshint -W040 */ - if (mustache.sexpr.id.original !== close.path.original) { - throw new Exception(mustache.sexpr.id.original + ' doesn\'t match ' + close.path.original, mustache); - } + Visitor.prototype = { + constructor: Visitor, + mutating: false, - var inverse = inverseAndProgram && inverseAndProgram.program; + // Visits a given value. If mutating, will replace the value if necessary. + acceptKey: function(node, name) { + var value = this.accept(node[name]); + if (this.mutating) { + // Hacky sanity check: + if (value && (!value.type || !AST[value.type])) { + throw new Exception('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type); + } + node[name] = value; + } + }, - var strip = { - left: mustache.strip.left, - right: close.strip.right, + // Performs an accept operation with added sanity check to ensure + // required keys are not removed. + acceptRequired: function(node, name) { + this.acceptKey(node, name); - // Determine the standalone candiacy. Basically flag our content as being possibly standalone - // so our parent can determine if we actually are standalone - openStandalone: isNextWhitespace(program.statements), - closeStandalone: isPrevWhitespace((inverse || program).statements) - }; + if (!node[name]) { + throw new Exception(node.type + ' requires ' + name); + } + }, - if (mustache.strip.right) { - omitRight(program.statements, null, true); - } + // Traverses a given array. If mutating, empty respnses will be removed + // for child elements. + acceptArray: function(array) { + for (var i = 0, l = array.length; i < l; i++) { + this.acceptKey(array, i); - if (inverse) { - var inverseStrip = inverseAndProgram.strip; + if (!array[i]) { + array.splice(i, 1); + i--; + l--; + } + } + }, - if (inverseStrip.left) { - omitLeft(program.statements, null, true); + accept: function(object) { + if (!object) { + return; } - if (inverseStrip.right) { - omitRight(inverse.statements, null, true); + + if (this.current) { + this.parents.unshift(this.current); } - if (close.strip.left) { - omitLeft(inverse.statements, null, true); - } + this.current = object; - // Find standalone else statments - if (isPrevWhitespace(program.statements) - && isNextWhitespace(inverse.statements)) { + var ret = this[object.type](object); - omitLeft(program.statements); - omitRight(inverse.statements); + this.current = this.parents.shift(); + + if (!this.mutating || ret) { + return ret; + } else if (ret !== false) { + return object; } - } else { - if (close.strip.left) { - omitLeft(program.statements, null, true); - } - } + }, - if (inverted) { - return new this.BlockNode(mustache, inverse, program, strip, locInfo); - } else { - return new this.BlockNode(mustache, program, inverse, strip, locInfo); + Program: function(program) { + this.acceptArray(program.body); + }, + + MustacheStatement: function(mustache) { + this.acceptRequired(mustache, 'path'); + this.acceptArray(mustache.params); + this.acceptKey(mustache, 'hash'); + }, + + BlockStatement: function(block) { + this.acceptRequired(block, 'path'); + this.acceptArray(block.params); + this.acceptKey(block, 'hash'); + + this.acceptKey(block, 'program'); + this.acceptKey(block, 'inverse'); + }, + + PartialStatement: function(partial) { + this.acceptRequired(partial, 'name'); + this.acceptArray(partial.params); + this.acceptKey(partial, 'hash'); + }, + + ContentStatement: function(/* content */) {}, + CommentStatement: function(/* comment */) {}, + + SubExpression: function(sexpr) { + this.acceptRequired(sexpr, 'path'); + this.acceptArray(sexpr.params); + this.acceptKey(sexpr, 'hash'); + }, + PartialExpression: function(partial) { + this.acceptRequired(partial, 'name'); + this.acceptArray(partial.params); + this.acceptKey(partial, 'hash'); + }, + + PathExpression: function(/* path */) {}, + + StringLiteral: function(/* string */) {}, + NumberLiteral: function(/* number */) {}, + BooleanLiteral: function(/* bool */) {}, + + Hash: function(hash) { + this.acceptArray(hash.pairs); + }, + HashPair: function(pair) { + this.acceptRequired(pair, 'value'); } + }; + + __exports__ = Visitor; + return __exports__; +})(__module4__, __module7__); + +// handlebars/compiler/whitespace-control.js +var __module10__ = (function(__dependency1__) { + "use strict"; + var __exports__; + var Visitor = __dependency1__; + + function WhitespaceControl() { } + WhitespaceControl.prototype = new Visitor(); - __exports__.prepareBlock = prepareBlock; - function prepareProgram(statements, isRoot) { - for (var i = 0, l = statements.length; i < l; i++) { - var current = statements[i], - strip = current.strip; + WhitespaceControl.prototype.Program = function(program) { + var isRoot = !this.isRootSeen; + this.isRootSeen = true; + var body = program.body; + for (var i = 0, l = body.length; i < l; i++) { + var current = body[i], + strip = this.accept(current); + if (!strip) { continue; } - var _isPrevWhitespace = isPrevWhitespace(statements, i, isRoot, current.type === 'partial'), - _isNextWhitespace = isNextWhitespace(statements, i, isRoot), + var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot), + _isNextWhitespace = isNextWhitespace(body, i, isRoot), openStandalone = strip.openStandalone && _isPrevWhitespace, closeStandalone = strip.closeStandalone && _isNextWhitespace, inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace; - if (strip.right) { - omitRight(statements, i, true); + if (strip.close) { + omitRight(body, i, true); } - if (strip.left) { - omitLeft(statements, i, true); + if (strip.open) { + omitLeft(body, i, true); } if (inlineStandalone) { - omitRight(statements, i); + omitRight(body, i); - if (omitLeft(statements, i)) { + if (omitLeft(body, i)) { // If we are on a standalone node, save the indent info for partials - if (current.type === 'partial') { - current.indent = (/([ \t]+$)/).exec(statements[i-1].original) ? RegExp.$1 : ''; + if (current.type === 'PartialStatement') { + // Pull out the whitespace from the final line + current.indent = (/([ \t]+$)/).exec(body[i-1].original)[1]; } } } if (openStandalone) { - omitRight((current.program || current.inverse).statements); + omitRight((current.program || current.inverse).body); // Strip out the previous content node if it's whitespace only - omitLeft(statements, i); + omitLeft(body, i); } if (closeStandalone) { // Always strip the next node - omitRight(statements, i); + omitRight(body, i); - omitLeft((current.inverse || current.program).statements); + omitLeft((current.inverse || current.program).body); } } - return statements; - } + return program; + }; + WhitespaceControl.prototype.BlockStatement = function(block) { + this.accept(block.program); + this.accept(block.inverse); - __exports__.prepareProgram = prepareProgram;function isPrevWhitespace(statements, i, isRoot) { + // Find the inverse program that is involed with whitespace stripping. + var program = block.program || block.inverse, + inverse = block.program && block.inverse, + firstInverse = inverse, + lastInverse = inverse; + + if (inverse && inverse.chained) { + firstInverse = inverse.body[0].program; + + // Walk the inverse chain to find the last inverse that is actually in the chain. + while (lastInverse.chained) { + lastInverse = lastInverse.body[lastInverse.body.length-1].program; + } + } + + var strip = { + open: block.openStrip.open, + close: block.closeStrip.close, + + // Determine the standalone candiacy. Basically flag our content as being possibly standalone + // so our parent can determine if we actually are standalone + openStandalone: isNextWhitespace(program.body), + closeStandalone: isPrevWhitespace((firstInverse || program).body) + }; + + if (block.openStrip.close) { + omitRight(program.body, null, true); + } + + if (inverse) { + var inverseStrip = block.inverseStrip; + + if (inverseStrip.open) { + omitLeft(program.body, null, true); + } + + if (inverseStrip.close) { + omitRight(firstInverse.body, null, true); + } + if (block.closeStrip.open) { + omitLeft(lastInverse.body, null, true); + } + + // Find standalone else statments + if (isPrevWhitespace(program.body) + && isNextWhitespace(firstInverse.body)) { + + omitLeft(program.body); + omitRight(firstInverse.body); + } + } else { + if (block.closeStrip.open) { + omitLeft(program.body, null, true); + } + } + + return strip; + }; + + WhitespaceControl.prototype.MustacheStatement = function(mustache) { + return mustache.strip; + }; + + WhitespaceControl.prototype.PartialStatement = + WhitespaceControl.prototype.CommentStatement = function(node) { + /* istanbul ignore next */ + var strip = node.strip || {}; + return { + inlineStandalone: true, + open: strip.open, + close: strip.close + }; + }; + + + function isPrevWhitespace(body, i, isRoot) { if (i === undefined) { - i = statements.length; + i = body.length; } // Nodes that end with newlines are considered whitespace (but are special // cased for strip operations) - var prev = statements[i-1], - sibling = statements[i-2]; + var prev = body[i-1], + sibling = body[i-2]; if (!prev) { return isRoot; } - if (prev.type === 'content') { + if (prev.type === 'ContentStatement') { return (sibling || !isRoot ? (/\r?\n\s*?$/) : (/(^|\r?\n)\s*?$/)).test(prev.original); } } - function isNextWhitespace(statements, i, isRoot) { + function isNextWhitespace(body, i, isRoot) { if (i === undefined) { i = -1; } - var next = statements[i+1], - sibling = statements[i+2]; + var next = body[i+1], + sibling = body[i+2]; if (!next) { return isRoot; } - if (next.type === 'content') { + if (next.type === 'ContentStatement') { return (sibling || !isRoot ? (/^\s*?\r?\n/) : (/^\s*?(\r?\n|$)/)).test(next.original); } } // Marks the node to the right of the position as omitted. @@ -1540,79 +1748,216 @@ // // If i is undefined, then the first child will be marked as such. // // If mulitple is truthy then all whitespace will be stripped out until non-whitespace // content is met. - function omitRight(statements, i, multiple) { - var current = statements[i == null ? 0 : i + 1]; - if (!current || current.type !== 'content' || (!multiple && current.rightStripped)) { + function omitRight(body, i, multiple) { + var current = body[i == null ? 0 : i + 1]; + if (!current || current.type !== 'ContentStatement' || (!multiple && current.rightStripped)) { return; } - var original = current.string; - current.string = current.string.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), ''); - current.rightStripped = current.string !== original; + var original = current.value; + current.value = current.value.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), ''); + current.rightStripped = current.value !== original; } // Marks the node to the left of the position as omitted. // I.e. ' '{{foo}} will mark the ' ' node as omitted. // // If i is undefined then the last child will be marked as such. // // If mulitple is truthy then all whitespace will be stripped out until non-whitespace // content is met. - function omitLeft(statements, i, multiple) { - var current = statements[i == null ? statements.length - 1 : i - 1]; - if (!current || current.type !== 'content' || (!multiple && current.leftStripped)) { + function omitLeft(body, i, multiple) { + var current = body[i == null ? body.length - 1 : i - 1]; + if (!current || current.type !== 'ContentStatement' || (!multiple && current.leftStripped)) { return; } // We omit the last node if it's whitespace only and not preceeded by a non-content node. - var original = current.string; - current.string = current.string.replace(multiple ? (/\s+$/) : (/[ \t]+$/), ''); - current.leftStripped = current.string !== original; + var original = current.value; + current.value = current.value.replace(multiple ? (/\s+$/) : (/[ \t]+$/), ''); + current.leftStripped = current.value !== original; return current.leftStripped; } + + __exports__ = WhitespaceControl; return __exports__; -})(__module5__); +})(__module11__); +// handlebars/compiler/helpers.js +var __module12__ = (function(__dependency1__) { + "use strict"; + var __exports__ = {}; + var Exception = __dependency1__; + + function SourceLocation(source, locInfo) { + this.source = source; + this.start = { + line: locInfo.first_line, + column: locInfo.first_column + }; + this.end = { + line: locInfo.last_line, + column: locInfo.last_column + }; + } + + __exports__.SourceLocation = SourceLocation;function stripFlags(open, close) { + return { + open: open.charAt(2) === '~', + close: close.charAt(close.length-3) === '~' + }; + } + + __exports__.stripFlags = stripFlags;function stripComment(comment) { + return comment.replace(/^\{\{~?\!-?-?/, '') + .replace(/-?-?~?\}\}$/, ''); + } + + __exports__.stripComment = stripComment;function preparePath(data, parts, locInfo) { + /*jshint -W040 */ + locInfo = this.locInfo(locInfo); + + var original = data ? '@' : '', + dig = [], + depth = 0, + depthString = ''; + + for(var i=0,l=parts.length; i<l; i++) { + var part = parts[i].part; + original += (parts[i].separator || '') + part; + + if (part === '..' || part === '.' || part === 'this') { + if (dig.length > 0) { + throw new Exception('Invalid path: ' + original, {loc: locInfo}); + } else if (part === '..') { + depth++; + depthString += '../'; + } + } else { + dig.push(part); + } + } + + return new this.PathExpression(data, depth, dig, original, locInfo); + } + + __exports__.preparePath = preparePath;function prepareMustache(path, params, hash, open, strip, locInfo) { + /*jshint -W040 */ + // Must use charAt to support IE pre-10 + var escapeFlag = open.charAt(3) || open.charAt(2), + escaped = escapeFlag !== '{' && escapeFlag !== '&'; + + return new this.MustacheStatement(path, params, hash, escaped, strip, this.locInfo(locInfo)); + } + + __exports__.prepareMustache = prepareMustache;function prepareRawBlock(openRawBlock, content, close, locInfo) { + /*jshint -W040 */ + if (openRawBlock.path.original !== close) { + var errorNode = {loc: openRawBlock.path.loc}; + + throw new Exception(openRawBlock.path.original + " doesn't match " + close, errorNode); + } + + locInfo = this.locInfo(locInfo); + var program = new this.Program([content], null, {}, locInfo); + + return new this.BlockStatement( + openRawBlock.path, openRawBlock.params, openRawBlock.hash, + program, undefined, + {}, {}, {}, + locInfo); + } + + __exports__.prepareRawBlock = prepareRawBlock;function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) { + /*jshint -W040 */ + // When we are chaining inverse calls, we will not have a close path + if (close && close.path && openBlock.path.original !== close.path.original) { + var errorNode = {loc: openBlock.path.loc}; + + throw new Exception(openBlock.path.original + ' doesn\'t match ' + close.path.original, errorNode); + } + + program.blockParams = openBlock.blockParams; + + var inverse, + inverseStrip; + + if (inverseAndProgram) { + if (inverseAndProgram.chain) { + inverseAndProgram.program.body[0].closeStrip = close.strip; + } + + inverseStrip = inverseAndProgram.strip; + inverse = inverseAndProgram.program; + } + + if (inverted) { + inverted = inverse; + inverse = program; + program = inverted; + } + + return new this.BlockStatement( + openBlock.path, openBlock.params, openBlock.hash, + program, inverse, + openBlock.strip, inverseStrip, close && close.strip, + this.locInfo(locInfo)); + } + + __exports__.prepareBlock = prepareBlock; + return __exports__; +})(__module4__); + // handlebars/compiler/base.js -var __module8__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { +var __module8__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { "use strict"; var __exports__ = {}; var parser = __dependency1__; var AST = __dependency2__; - var Helpers = __dependency3__; - var extend = __dependency4__.extend; + var WhitespaceControl = __dependency3__; + var Helpers = __dependency4__; + var extend = __dependency5__.extend; __exports__.parser = parser; var yy = {}; extend(yy, Helpers, AST); - function parse(input) { - // Just return if an already-compile AST was passed in. - if (input.constructor === AST.ProgramNode) { return input; } + function parse(input, options) { + // Just return if an already-compiled AST was passed in. + if (input.type === 'Program') { return input; } parser.yy = yy; - return parser.parse(input); + // Altering the shared object here, but this is ok as parser is a sync operation + yy.locInfo = function(locInfo) { + return new yy.SourceLocation(options && options.srcName, locInfo); + }; + + var strip = new WhitespaceControl(); + return strip.accept(parser.parse(input)); } __exports__.parse = parse; return __exports__; -})(__module9__, __module7__, __module10__, __module3__); +})(__module9__, __module7__, __module10__, __module12__, __module3__); // handlebars/compiler/compiler.js -var __module11__ = (function(__dependency1__, __dependency2__) { +var __module13__ = (function(__dependency1__, __dependency2__, __dependency3__) { "use strict"; var __exports__ = {}; var Exception = __dependency1__; var isArray = __dependency2__.isArray; + var indexOf = __dependency2__.indexOf; + var AST = __dependency3__; var slice = [].slice; + function Compiler() {} __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a // function in a context. This is necessary for mustache compatibility, which // requires that context functions in blocks are evaluated by blockHelperMissing, @@ -1648,20 +1993,22 @@ }, guid: 0, compile: function(program, options) { + this.sourceNode = []; this.opcodes = []; this.children = []; - this.depths = {list: []}; this.options = options; this.stringParams = options.stringParams; this.trackIds = options.trackIds; + options.blockParams = options.blockParams || []; + // These changes will propagate to the other compiler components - var knownHelpers = this.options.knownHelpers; - this.options.knownHelpers = { + var knownHelpers = options.knownHelpers; + options.knownHelpers = { 'helperMissing': true, 'blockHelperMissing': true, 'each': true, 'if': true, 'unless': true, @@ -1669,83 +2016,76 @@ 'log': true, 'lookup': true }; if (knownHelpers) { for (var name in knownHelpers) { - this.options.knownHelpers[name] = knownHelpers[name]; + options.knownHelpers[name] = knownHelpers[name]; } } return this.accept(program); }, - accept: function(node) { - return this[node.type](node); - }, - - program: function(program) { - var statements = program.statements; - - for(var i=0, l=statements.length; i<l; i++) { - this.accept(statements[i]); - } - this.isSimple = l === 1; - - this.depths.list = this.depths.list.sort(function(a, b) { - return a - b; - }); - - return this; - }, - compileProgram: function(program) { var result = new this.compiler().compile(program, this.options); - var guid = this.guid++, depth; + var guid = this.guid++; this.usePartial = this.usePartial || result.usePartial; this.children[guid] = result; + this.useDepths = this.useDepths || result.useDepths; - for(var i=0, l=result.depths.list.length; i<l; i++) { - depth = result.depths.list[i]; + return guid; + }, - if(depth < 2) { continue; } - else { this.addDepth(depth - 1); } + accept: function(node) { + this.sourceNode.unshift(node); + var ret = this[node.type](node); + this.sourceNode.shift(); + return ret; + }, + + Program: function(program) { + this.options.blockParams.unshift(program.blockParams); + + var body = program.body; + for(var i=0, l=body.length; i<l; i++) { + this.accept(body[i]); } - return guid; + this.options.blockParams.shift(); + + this.isSimple = l === 1; + this.blockParams = program.blockParams ? program.blockParams.length : 0; + + return this; }, - block: function(block) { - var mustache = block.mustache, - program = block.program, + BlockStatement: function(block) { + transformLiteralToPath(block); + + var program = block.program, inverse = block.inverse; - if (program) { - program = this.compileProgram(program); - } + program = program && this.compileProgram(program); + inverse = inverse && this.compileProgram(inverse); - if (inverse) { - inverse = this.compileProgram(inverse); - } + var type = this.classifySexpr(block); - var sexpr = mustache.sexpr; - var type = this.classifySexpr(sexpr); + if (type === 'helper') { + this.helperSexpr(block, program, inverse); + } else if (type === 'simple') { + this.simpleSexpr(block); - if (type === "helper") { - this.helperSexpr(sexpr, program, inverse); - } else if (type === "simple") { - this.simpleSexpr(sexpr); - // now that the simple mustache is resolved, we need to // evaluate it by executing `blockHelperMissing` this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); this.opcode('emptyHash'); - this.opcode('blockValue', sexpr.id.original); + this.opcode('blockValue', block.path.original); } else { - this.ambiguousSexpr(sexpr, program, inverse); + this.ambiguousSexpr(block, program, inverse); // now that the simple mustache is resolved, we need to // evaluate it by executing `blockHelperMissing` this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); @@ -1754,236 +2094,278 @@ } this.opcode('append'); }, - hash: function(hash) { - var pairs = hash.pairs, i, l; + PartialStatement: function(partial) { + this.usePartial = true; - this.opcode('pushHash'); + var params = partial.params; + if (params.length > 1) { + throw new Exception('Unsupported number of partial arguments: ' + params.length, partial); + } else if (!params.length) { + params.push({type: 'PathExpression', parts: [], depth: 0}); + } - for(i=0, l=pairs.length; i<l; i++) { - this.pushParam(pairs[i][1]); + var partialName = partial.name.original, + isDynamic = partial.name.type === 'SubExpression'; + if (isDynamic) { + this.accept(partial.name); } - while(i--) { - this.opcode('assignToHash', pairs[i][0]); - } - this.opcode('popHash'); - }, - partial: function(partial) { - var partialName = partial.partialName; - this.usePartial = true; + this.setupFullMustacheParams(partial, undefined, undefined, true); - if (partial.hash) { - this.accept(partial.hash); - } else { - this.opcode('push', 'undefined'); + var indent = partial.indent || ''; + if (this.options.preventIndent && indent) { + this.opcode('appendContent', indent); + indent = ''; } - if (partial.context) { - this.accept(partial.context); - } else { - this.opcode('getContext', 0); - this.opcode('pushContext'); - } - - this.opcode('invokePartial', partialName.name, partial.indent || ''); + this.opcode('invokePartial', isDynamic, partialName, indent); this.opcode('append'); }, - content: function(content) { - if (content.string) { - this.opcode('appendContent', content.string); - } - }, + MustacheStatement: function(mustache) { + this.SubExpression(mustache); - mustache: function(mustache) { - this.sexpr(mustache.sexpr); - if(mustache.escaped && !this.options.noEscape) { this.opcode('appendEscaped'); } else { this.opcode('append'); } }, + ContentStatement: function(content) { + if (content.value) { + this.opcode('appendContent', content.value); + } + }, + + CommentStatement: function() {}, + + SubExpression: function(sexpr) { + transformLiteralToPath(sexpr); + var type = this.classifySexpr(sexpr); + + if (type === 'simple') { + this.simpleSexpr(sexpr); + } else if (type === 'helper') { + this.helperSexpr(sexpr); + } else { + this.ambiguousSexpr(sexpr); + } + }, ambiguousSexpr: function(sexpr, program, inverse) { - var id = sexpr.id, - name = id.parts[0], + var path = sexpr.path, + name = path.parts[0], isBlock = program != null || inverse != null; - this.opcode('getContext', id.depth); + this.opcode('getContext', path.depth); this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); - this.ID(id); + this.accept(path); this.opcode('invokeAmbiguous', name, isBlock); }, simpleSexpr: function(sexpr) { - var id = sexpr.id; - - if (id.type === 'DATA') { - this.DATA(id); - } else if (id.parts.length) { - this.ID(id); - } else { - // Simplified ID for `this` - this.addDepth(id.depth); - this.opcode('getContext', id.depth); - this.opcode('pushContext'); - } - + this.accept(sexpr.path); this.opcode('resolvePossibleLambda'); }, helperSexpr: function(sexpr, program, inverse) { var params = this.setupFullMustacheParams(sexpr, program, inverse), - id = sexpr.id, - name = id.parts[0]; + path = sexpr.path, + name = path.parts[0]; if (this.options.knownHelpers[name]) { this.opcode('invokeKnownHelper', params.length, name); } else if (this.options.knownHelpersOnly) { throw new Exception("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr); } else { - id.falsy = true; + path.falsy = true; - this.ID(id); - this.opcode('invokeHelper', params.length, id.original, id.isSimple); + this.accept(path); + this.opcode('invokeHelper', params.length, path.original, AST.helpers.simpleId(path)); } }, - sexpr: function(sexpr) { - var type = this.classifySexpr(sexpr); + PathExpression: function(path) { + this.addDepth(path.depth); + this.opcode('getContext', path.depth); - if (type === "simple") { - this.simpleSexpr(sexpr); - } else if (type === "helper") { - this.helperSexpr(sexpr); - } else { - this.ambiguousSexpr(sexpr); - } - }, + var name = path.parts[0], + scoped = AST.helpers.scopedId(path), + blockParamId = !path.depth && !scoped && this.blockParamIndex(name); - ID: function(id) { - this.addDepth(id.depth); - this.opcode('getContext', id.depth); - - var name = id.parts[0]; - if (!name) { + if (blockParamId) { + this.opcode('lookupBlockParam', blockParamId, path.parts); + } else if (!name) { // Context reference, i.e. `{{foo .}}` or `{{foo ..}}` this.opcode('pushContext'); + } else if (path.data) { + this.options.data = true; + this.opcode('lookupData', path.depth, path.parts); } else { - this.opcode('lookupOnContext', id.parts, id.falsy, id.isScoped); + this.opcode('lookupOnContext', path.parts, path.falsy, scoped); } }, - DATA: function(data) { - this.options.data = true; - this.opcode('lookupData', data.id.depth, data.id.parts); + StringLiteral: function(string) { + this.opcode('pushString', string.value); }, - STRING: function(string) { - this.opcode('pushString', string.string); + NumberLiteral: function(number) { + this.opcode('pushLiteral', number.value); }, - NUMBER: function(number) { - this.opcode('pushLiteral', number.number); + BooleanLiteral: function(bool) { + this.opcode('pushLiteral', bool.value); }, - BOOLEAN: function(bool) { - this.opcode('pushLiteral', bool.bool); - }, + Hash: function(hash) { + var pairs = hash.pairs, i, l; - comment: function() {}, + this.opcode('pushHash'); + for (i=0, l=pairs.length; i<l; i++) { + this.pushParam(pairs[i].value); + } + while (i--) { + this.opcode('assignToHash', pairs[i].key); + } + this.opcode('popHash'); + }, + // HELPERS opcode: function(name) { - this.opcodes.push({ opcode: name, args: slice.call(arguments, 1) }); + this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), loc: this.sourceNode[0].loc }); }, addDepth: function(depth) { - if(depth === 0) { return; } - - if(!this.depths[depth]) { - this.depths[depth] = true; - this.depths.list.push(depth); + if (!depth) { + return; } + + this.useDepths = true; }, classifySexpr: function(sexpr) { - var isHelper = sexpr.isHelper; - var isEligible = sexpr.eligibleHelper; - var options = this.options; + var isSimple = AST.helpers.simpleId(sexpr.path); + var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]); + + // a mustache is an eligible helper if: + // * its id is simple (a single part, not `this` or `..`) + var isHelper = !isBlockParam && AST.helpers.helperExpression(sexpr); + + // if a mustache is an eligible helper but not a definite + // helper, it is ambiguous, and will be resolved in a later + // pass or at runtime. + var isEligible = !isBlockParam && (isHelper || isSimple); + + var options = this.options; + // if ambiguous, we can possibly resolve the ambiguity now // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc. if (isEligible && !isHelper) { - var name = sexpr.id.parts[0]; + var name = sexpr.path.parts[0]; if (options.knownHelpers[name]) { isHelper = true; } else if (options.knownHelpersOnly) { isEligible = false; } } - if (isHelper) { return "helper"; } - else if (isEligible) { return "ambiguous"; } - else { return "simple"; } + if (isHelper) { return 'helper'; } + else if (isEligible) { return 'ambiguous'; } + else { return 'simple'; } }, pushParams: function(params) { for(var i=0, l=params.length; i<l; i++) { this.pushParam(params[i]); } }, pushParam: function(val) { + var value = val.value != null ? val.value : val.original || ''; + if (this.stringParams) { + if (value.replace) { + value = value + .replace(/^(\.?\.\/)*/g, '') + .replace(/\//g, '.'); + } + if(val.depth) { this.addDepth(val.depth); } this.opcode('getContext', val.depth || 0); - this.opcode('pushStringParam', val.stringModeValue, val.type); + this.opcode('pushStringParam', value, val.type); - if (val.type === 'sexpr') { - // Subexpressions get evaluated and passed in + if (val.type === 'SubExpression') { + // SubExpressions get evaluated and passed in // in string params mode. - this.sexpr(val); + this.accept(val); } } else { if (this.trackIds) { - this.opcode('pushId', val.type, val.idName || val.stringModeValue); + var blockParamIndex; + if (val.parts && !AST.helpers.scopedId(val) && !val.depth) { + blockParamIndex = this.blockParamIndex(val.parts[0]); + } + if (blockParamIndex) { + var blockParamChild = val.parts.slice(1).join('.'); + this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild); + } else { + value = val.original || value; + if (value.replace) { + value = value + .replace(/^\.\//g, '') + .replace(/^\.$/g, ''); + } + + this.opcode('pushId', val.type, value); + } } this.accept(val); } }, - setupFullMustacheParams: function(sexpr, program, inverse) { + setupFullMustacheParams: function(sexpr, program, inverse, omitEmpty) { var params = sexpr.params; this.pushParams(params); this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); if (sexpr.hash) { - this.hash(sexpr.hash); + this.accept(sexpr.hash); } else { - this.opcode('emptyHash'); + this.opcode('emptyHash', omitEmpty); } return params; + }, + + blockParamIndex: function(name) { + for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) { + var blockParams = this.options.blockParams[depth], + param = blockParams && indexOf(blockParams, name); + if (blockParams && param >= 0) { + return [depth, param]; + } + } } }; function precompile(input, options, env) { - if (input == null || (typeof input !== 'string' && input.constructor !== env.AST.ProgramNode)) { + if (input == null || (typeof input !== 'string' && input.type !== 'Program')) { throw new Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input); } options = options || {}; if (!('data' in options)) { @@ -1991,17 +2373,17 @@ } if (options.compat) { options.useDepths = true; } - var ast = env.parse(input); + var ast = env.parse(input, options); var environment = new env.Compiler().compile(ast, options); return new env.JavaScriptCompiler().compile(environment, options); } __exports__.precompile = precompile;function compile(input, options, env) { - if (input == null || (typeof input !== 'string' && input.constructor !== env.AST.ProgramNode)) { + if (input == null || (typeof input !== 'string' && input.type !== 'Program')) { throw new Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); } options = options || {}; @@ -2013,11 +2395,11 @@ } var compiled; function compileInput() { - var ast = env.parse(input); + var ast = env.parse(input, options); var environment = new env.Compiler().compile(ast, options); var templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); return env.template(templateSpec); } @@ -2032,15 +2414,15 @@ if (!compiled) { compiled = compileInput(); } return compiled._setup(options); }; - ret._child = function(i, data, depths) { + ret._child = function(i, data, blockParams, depths) { if (!compiled) { compiled = compileInput(); } - return compiled._child(i, data, depths); + return compiled._child(i, data, blockParams, depths); }; return ret; } __exports__.compile = compile;function argEquals(a, b) { @@ -2055,20 +2437,191 @@ } } return true; } } + + function transformLiteralToPath(sexpr) { + if (!sexpr.path.parts) { + var literal = sexpr.path; + // Casting to string here to make false and 0 literal values play nicely with the rest + // of the system. + sexpr.path = new AST.PathExpression(false, 0, [literal.original+''], literal.original+'', literal.log); + } + } return __exports__; -})(__module5__, __module3__); +})(__module4__, __module3__, __module7__); +// handlebars/compiler/code-gen.js +var __module15__ = (function(__dependency1__) { + "use strict"; + var __exports__; + var isArray = __dependency1__.isArray; + + try { + var SourceMap = require('source-map'), + SourceNode = SourceMap.SourceNode; + } catch (err) { + /* istanbul ignore next: tested but not covered in istanbul due to dist build */ + SourceNode = function(line, column, srcFile, chunks) { + this.src = ''; + if (chunks) { + this.add(chunks); + } + }; + /* istanbul ignore next */ + SourceNode.prototype = { + add: function(chunks) { + if (isArray(chunks)) { + chunks = chunks.join(''); + } + this.src += chunks; + }, + prepend: function(chunks) { + if (isArray(chunks)) { + chunks = chunks.join(''); + } + this.src = chunks + this.src; + }, + toStringWithSourceMap: function() { + return {code: this.toString()}; + }, + toString: function() { + return this.src; + } + }; + } + + + function castChunk(chunk, codeGen, loc) { + if (isArray(chunk)) { + var ret = []; + + for (var i = 0, len = chunk.length; i < len; i++) { + ret.push(codeGen.wrap(chunk[i], loc)); + } + return ret; + } else if (typeof chunk === 'boolean' || typeof chunk === 'number') { + // Handle primitives that the SourceNode will throw up on + return chunk+''; + } + return chunk; + } + + + function CodeGen(srcFile) { + this.srcFile = srcFile; + this.source = []; + } + + CodeGen.prototype = { + prepend: function(source, loc) { + this.source.unshift(this.wrap(source, loc)); + }, + push: function(source, loc) { + this.source.push(this.wrap(source, loc)); + }, + + merge: function() { + var source = this.empty(); + this.each(function(line) { + source.add([' ', line, '\n']); + }); + return source; + }, + + each: function(iter) { + for (var i = 0, len = this.source.length; i < len; i++) { + iter(this.source[i]); + } + }, + + empty: function(loc) { + loc = loc || this.currentLocation || {start:{}}; + return new SourceNode(loc.start.line, loc.start.column, this.srcFile); + }, + wrap: function(chunk, loc) { + if (chunk instanceof SourceNode) { + return chunk; + } + + loc = loc || this.currentLocation || {start:{}}; + chunk = castChunk(chunk, this, loc); + + return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk); + }, + + functionCall: function(fn, type, params) { + params = this.generateList(params); + return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']); + }, + + quotedString: function(str) { + return '"' + (str + '') + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; + }, + + objectLiteral: function(obj) { + var pairs = []; + + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + var value = castChunk(obj[key], this); + if (value !== 'undefined') { + pairs.push([this.quotedString(key), ':', value]); + } + } + } + + var ret = this.generateList(pairs); + ret.prepend('{'); + ret.add('}'); + return ret; + }, + + + generateList: function(entries, loc) { + var ret = this.empty(loc); + + for (var i = 0, len = entries.length; i < len; i++) { + if (i) { + ret.add(','); + } + + ret.add(castChunk(entries[i], this, loc)); + } + + return ret; + }, + + generateArray: function(entries, loc) { + var ret = this.generateList(entries, loc); + ret.prepend('['); + ret.add(']'); + + return ret; + } + }; + + __exports__ = CodeGen; + return __exports__; +})(__module3__); + // handlebars/compiler/javascript-compiler.js -var __module12__ = (function(__dependency1__, __dependency2__) { +var __module14__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { "use strict"; var __exports__; var COMPILER_REVISION = __dependency1__.COMPILER_REVISION; var REVISION_CHANGES = __dependency1__.REVISION_CHANGES; var Exception = __dependency2__; + var isArray = __dependency3__.isArray; + var CodeGen = __dependency4__; function Literal(value) { this.value = value; } @@ -2077,44 +2630,48 @@ JavaScriptCompiler.prototype = { // PUBLIC API: You can override these methods in a subclass to provide // alternative compiled forms for name lookup and buffering semantics nameLookup: function(parent, name /* , type*/) { if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { - return parent + "." + name; + return [parent, ".", name]; } else { - return parent + "['" + name + "']"; + return [parent, "['", name, "']"]; } }, depthedLookup: function(name) { - this.aliases.lookup = 'this.lookup'; - - return 'lookup(depths, "' + name + '")'; + return [this.aliasable('this.lookup'), '(depths, "', name, '")']; }, compilerInfo: function() { var revision = COMPILER_REVISION, versions = REVISION_CHANGES[revision]; return [revision, versions]; }, - appendToBuffer: function(string) { + appendToBuffer: function(source, location, explicit) { + // Force a source as this simplifies the merge logic. + if (!isArray(source)) { + source = [source]; + } + source = this.source.wrap(source, location); + if (this.environment.isSimple) { - return "return " + string + ";"; + return ['return ', source, ';']; + } else if (explicit) { + // This is a case where the buffer operation occurs as a child of another + // construct, generally braces. We have to explicitly output these buffer + // operations to ensure that the emitted code goes in the correct location. + return ['buffer += ', source, ';']; } else { - return { - appendToBuffer: true, - content: string, - toString: function() { return "buffer += " + string + ";"; } - }; + source.appendToBuffer = true; + return source; } }, initializeBuffer: function() { return this.quotedString(""); }, - - namespace: "Handlebars", // END PUBLIC API compile: function(environment, options, context, asObject) { this.environment = environment; this.options = options; @@ -2136,27 +2693,33 @@ this.aliases = {}; this.registers = { list: [] }; this.hashes = []; this.compileStack = []; this.inlineStack = []; + this.blockParams = []; this.compileChildren(environment, options); - this.useDepths = this.useDepths || environment.depths.list.length || this.options.compat; + this.useDepths = this.useDepths || environment.useDepths || this.options.compat; + this.useBlockParams = this.useBlockParams || environment.useBlockParams; var opcodes = environment.opcodes, opcode, + firstLoc, i, l; for (i = 0, l = opcodes.length; i < l; i++) { opcode = opcodes[i]; + this.source.currentLocation = opcode.loc; + firstLoc = firstLoc || opcode.loc; this[opcode.opcode].apply(this, opcode.args); } // Flush any trailing content that might be pending. + this.source.currentLocation = firstLoc; this.pushSource(''); /* istanbul ignore next */ if (this.stackSlot || this.inlineStack.length || this.compileStack.length) { throw new Exception('Compile completed with content left on stack'); @@ -2182,17 +2745,31 @@ ret.useData = true; } if (this.useDepths) { ret.useDepths = true; } + if (this.useBlockParams) { + ret.useBlockParams = true; + } if (this.options.compat) { ret.compat = true; } if (!asObject) { ret.compiler = JSON.stringify(ret.compiler); + + this.source.currentLocation = {start: {line: 1, column: 0}}; ret = this.objectLiteral(ret); + + if (options.srcName) { + ret = ret.toStringWithSourceMap({file: options.destName}); + ret.map = ret.map && ret.map.toString(); + } else { + ret = ret.toString(); + } + } else { + ret.compilerOptions = this.options; } return ret; } else { return fn; @@ -2201,11 +2778,11 @@ preamble: function() { // track the last context pushed into place to allow skipping the // getContext opcode when it would be a noop this.lastContext = 0; - this.source = []; + this.source = new CodeGen(this.options.srcName); }, createFunctionContext: function(asObject) { var varDeclarations = ''; @@ -2213,18 +2790,30 @@ if(locals.length > 0) { varDeclarations += ", " + locals.join(", "); } // Generate minimizer alias mappings + // + // When using true SourceNodes, this will update all references to the given alias + // as the source nodes are reused in situ. For the non-source node compilation mode, + // aliases will not be used, but this case is already being run on the client and + // we aren't concern about minimizing the template size. + var aliasCount = 0; for (var alias in this.aliases) { - if (this.aliases.hasOwnProperty(alias)) { - varDeclarations += ', ' + alias + '=' + this.aliases[alias]; + var node = this.aliases[alias]; + + if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) { + varDeclarations += ', alias' + (++aliasCount) + '=' + alias; + node.children[0] = 'alias' + aliasCount; } } var params = ["depth0", "helpers", "partials", "data"]; + if (this.useBlockParams || this.useDepths) { + params.push('blockParams'); + } if (this.useDepths) { params.push('depths'); } // Perform a second pass over the output to merge content when possible @@ -2233,63 +2822,71 @@ if (asObject) { params.push(source); return Function.apply(this, params); } else { - return 'function(' + params.join(',') + ') {\n ' + source + '}'; + return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']); } }, mergeSource: function(varDeclarations) { - var source = '', - buffer, + var isSimple = this.environment.isSimple, appendOnly = !this.forceBuffer, - appendFirst; + appendFirst, - for (var i = 0, len = this.source.length; i < len; i++) { - var line = this.source[i]; + sourceSeen, + bufferStart, + bufferEnd; + this.source.each(function(line) { if (line.appendToBuffer) { - if (buffer) { - buffer = buffer + '\n + ' + line.content; + if (bufferStart) { + line.prepend(' + '); } else { - buffer = line.content; + bufferStart = line; } + bufferEnd = line; } else { - if (buffer) { - if (!source) { + if (bufferStart) { + if (!sourceSeen) { appendFirst = true; - source = buffer + ';\n '; } else { - source += 'buffer += ' + buffer + ';\n '; + bufferStart.prepend('buffer += '); } - buffer = undefined; + bufferEnd.add(';'); + bufferStart = bufferEnd = undefined; } - source += line + '\n '; - if (!this.environment.isSimple) { + sourceSeen = true; + if (!isSimple) { appendOnly = false; } } - } + }); + if (appendOnly) { - if (buffer || !source) { - source += 'return ' + (buffer || '""') + ';\n'; + if (bufferStart) { + bufferStart.prepend('return '); + bufferEnd.add(';'); + } else if (!sourceSeen) { + this.source.push('return "";'); } } else { varDeclarations += ", buffer = " + (appendFirst ? '' : this.initializeBuffer()); - if (buffer) { - source += 'return buffer + ' + buffer + ';\n'; + + if (bufferStart) { + bufferStart.prepend('return buffer + '); + bufferEnd.add(';'); } else { - source += 'return buffer;\n'; + this.source.push('return buffer;'); } } if (varDeclarations) { - source = 'var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n ') + source; + this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')); } - return source; + return this.source.merge(); }, // [blockValue] // // On stack, before: hash, inverse, program, value @@ -2298,40 +2895,41 @@ // The purpose of this opcode is to take a block of the form // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and // replace it on the stack with the result of properly // invoking blockHelperMissing. blockValue: function(name) { - this.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; + var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), + params = [this.contextName(0)]; + this.setupHelperArgs(name, 0, params); - var params = [this.contextName(0)]; - this.setupParams(name, 0, params); - var blockName = this.popStack(); params.splice(1, 0, blockName); - this.push('blockHelperMissing.call(' + params.join(', ') + ')'); + this.push(this.source.functionCall(blockHelperMissing, 'call', params)); }, // [ambiguousBlockValue] // // On stack, before: hash, inverse, program, value // Compiler value, before: lastHelper=value of last found helper, if any // On stack, after, if no lastHelper: same as [blockValue] // On stack, after, if lastHelper: value ambiguousBlockValue: function() { - this.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; - // We're being a bit cheeky and reusing the options value from the prior exec - var params = [this.contextName(0)]; - this.setupParams('', 0, params, true); + var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), + params = [this.contextName(0)]; + this.setupHelperArgs('', 0, params, true); this.flushInline(); var current = this.topStack(); params.splice(1, 0, current); - this.pushSource("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }"); + this.pushSource([ + 'if (!', this.lastHelper, ') { ', + current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), + '}']); }, // [appendContent] // // On stack, before: ... @@ -2339,10 +2937,12 @@ // // Appends the string value of `content` to the current buffer appendContent: function(content) { if (this.pendingContent) { content = this.pendingContent + content; + } else { + this.pendingLocation = this.source.currentLocation; } this.pendingContent = content; }, @@ -2354,30 +2954,34 @@ // Coerces `value` to a String and appends it to the current buffer. // // If `value` is truthy, or 0, it is coerced into a string and appended // Otherwise, the empty string is appended append: function() { - // Force anything that is inlined onto the stack so we don't have duplication - // when we examine local - this.flushInline(); - var local = this.popStack(); - this.pushSource('if (' + local + ' != null) { ' + this.appendToBuffer(local) + ' }'); - if (this.environment.isSimple) { - this.pushSource("else { " + this.appendToBuffer("''") + " }"); + if (this.isInline()) { + this.replaceStack(function(current) { + return [' != null ? ', current, ' : ""']; + }); + + this.pushSource(this.appendToBuffer(this.popStack())); + } else { + var local = this.popStack(); + this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']); + if (this.environment.isSimple) { + this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']); + } } }, // [appendEscaped] // // On stack, before: value, ... // On stack, after: ... // // Escape `value` and append it to the buffer appendEscaped: function() { - this.aliases.escapeExpression = 'this.escapeExpression'; - - this.pushSource(this.appendToBuffer("escapeExpression(" + this.popStack() + ")")); + this.pushSource(this.appendToBuffer( + [this.aliasable('this.escapeExpression'), '(', this.popStack(), ')'])); }, // [getContext] // // On stack, before: ... @@ -2405,37 +3009,37 @@ // On stack, after: currentContext[name], ... // // Looks up the value of `name` on the current context and pushes // it onto the stack. lookupOnContext: function(parts, falsy, scoped) { - /*jshint -W083 */ - var i = 0, - len = parts.length; + var i = 0; if (!scoped && this.options.compat && !this.lastContext) { // The depthed query is expected to handle the undefined logic for the root level that // is implemented below, so we evaluate that directly in compat mode this.push(this.depthedLookup(parts[i++])); } else { this.pushContext(); } - for (; i < len; i++) { - this.replaceStack(function(current) { - var lookup = this.nameLookup(current, parts[i], 'context'); - // We want to ensure that zero and false are handled properly if the context (falsy flag) - // needs to have the special handling for these values. - if (!falsy) { - return ' != null ? ' + lookup + ' : ' + current; - } else { - // Otherwise we can use generic falsy handling - return ' && ' + lookup; - } - }); - } + this.resolvePath('context', parts, i, falsy); }, + // [lookupBlockParam] + // + // On stack, before: ... + // On stack, after: blockParam[name], ... + // + // Looks up the value of `parts` on the given block param and pushes + // it onto the stack. + lookupBlockParam: function(blockParamId, parts) { + this.useBlockParams = true; + + this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); + this.resolvePath('context', parts, 1); + }, + // [lookupData] // // On stack, before: ... // On stack, after: data, ... // @@ -2446,14 +3050,32 @@ this.pushStackLiteral('data'); } else { this.pushStackLiteral('this.data(data, ' + depth + ')'); } + this.resolvePath('data', parts, 0, true); + }, + + resolvePath: function(type, parts, i, falsy) { + /*jshint -W083 */ + if (this.options.strict || this.options.assumeObjects) { + this.push(strictLookup(this.options.strict, this, parts, type)); + return; + } + var len = parts.length; - for (var i = 0; i < len; i++) { + for (; i < len; i++) { this.replaceStack(function(current) { - return ' && ' + this.nameLookup(current, parts[i], 'data'); + var lookup = this.nameLookup(current, parts[i], type); + // We want to ensure that zero and false are handled properly if the context (falsy flag) + // needs to have the special handling for these values. + if (!falsy) { + return [' != null ? ', lookup, ' : ', current]; + } else { + // Otherwise we can use generic falsy handling + return [' && ', lookup]; + } }); } }, // [resolvePossibleLambda] @@ -2462,13 +3084,11 @@ // On stack, after: resolved value, ... // // If the `value` is a lambda, replace it on the stack by // the return value of the lambda resolvePossibleLambda: function() { - this.aliases.lambda = 'this.lambda'; - - this.push('lambda(' + this.popStack() + ', ' + this.contextName(0) + ')'); + this.push([this.aliasable('this.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']); }, // [pushStringParam] // // On stack, before: ... @@ -2481,29 +3101,28 @@ this.pushContext(); this.pushString(type); // If it's a subexpression, the string result // will be pushed after this opcode. - if (type !== 'sexpr') { + if (type !== 'SubExpression') { if (typeof string === 'string') { this.pushString(string); } else { this.pushStackLiteral(string); } } }, - emptyHash: function() { - this.pushStackLiteral('{}'); - + emptyHash: function(omitEmpty) { if (this.trackIds) { this.push('{}'); // hashIds } if (this.stringParams) { this.push('{}'); // hashContexts this.push('{}'); // hashTypes } + this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); }, pushHash: function() { if (this.hash) { this.hashes.push(this.hash); } @@ -2512,18 +3131,18 @@ popHash: function() { var hash = this.hash; this.hash = this.hashes.pop(); if (this.trackIds) { - this.push('{' + hash.ids.join(',') + '}'); + this.push(this.objectLiteral(hash.ids)); } if (this.stringParams) { - this.push('{' + hash.contexts.join(',') + '}'); - this.push('{' + hash.types.join(',') + '}'); + this.push(this.objectLiteral(hash.contexts)); + this.push(this.objectLiteral(hash.types)); } - this.push('{\n ' + hash.values.join(',\n ') + '\n }'); + this.push(this.objectLiteral(hash.values)); }, // [pushString] // // On stack, before: ... @@ -2532,21 +3151,10 @@ // Push a quoted version of `string` onto the stack pushString: function(string) { this.pushStackLiteral(this.quotedString(string)); }, - // [push] - // - // On stack, before: ... - // On stack, after: expr, ... - // - // Push an expression onto the stack - push: function(expr) { - this.inlineStack.push(expr); - return expr; - }, - // [pushLiteral] // // On stack, before: ... // On stack, after: value, ... // @@ -2581,17 +3189,21 @@ // Pops off the helper's parameters, invokes the helper, // and pushes the helper's return value onto the stack. // // If the helper is not found, `helperMissing` is called. invokeHelper: function(paramSize, name, isSimple) { - this.aliases.helperMissing = 'helpers.helperMissing'; - var nonHelper = this.popStack(); var helper = this.setupHelper(paramSize, name); + var simple = isSimple ? [helper.name, ' || '] : ''; - var lookup = (isSimple ? helper.name + ' || ' : '') + nonHelper + ' || helperMissing'; - this.push('((' + lookup + ').call(' + helper.callParams + '))'); + var lookup = ['('].concat(simple, nonHelper); + if (!this.options.strict) { + lookup.push(' || ', this.aliasable('helpers.helperMissing')); + } + lookup.push(')'); + + this.push(this.source.functionCall(lookup, 'call', helper.callParams)); }, // [invokeKnownHelper] // // On stack, before: hash, inverse, program, params..., ... @@ -2599,11 +3211,11 @@ // // This operation is used when the helper is known to exist, // so a `helperMissing` fallback is not required. invokeKnownHelper: function(paramSize, name) { var helper = this.setupHelper(paramSize, name); - this.push(helper.name + ".call(" + helper.callParams + ")"); + this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); }, // [invokeAmbiguous] // // On stack, before: hash, inverse, program, params..., ... @@ -2615,47 +3227,71 @@ // // This operation emits more code than the other options, // and can be avoided by passing the `knownHelpers` and // `knownHelpersOnly` flags at compile-time. invokeAmbiguous: function(name, helperCall) { - this.aliases.functionType = '"function"'; - this.aliases.helperMissing = 'helpers.helperMissing'; this.useRegister('helper'); var nonHelper = this.popStack(); this.emptyHash(); var helper = this.setupHelper(0, name, helperCall); var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); - this.push( - '((helper = (helper = ' + helperName + ' || ' + nonHelper + ') != null ? helper : helperMissing' - + (helper.paramsInit ? '),(' + helper.paramsInit : '') + '),' - + '(typeof helper === functionType ? helper.call(' + helper.callParams + ') : helper))'); + var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')']; + if (!this.options.strict) { + lookup[0] = '(helper = '; + lookup.push( + ' != null ? helper : ', + this.aliasable('helpers.helperMissing') + ); + } + + this.push([ + '(', lookup, + (helper.paramsInit ? ['),(', helper.paramsInit] : []), '),', + '(typeof helper === ', this.aliasable('"function"'), ' ? ', + this.source.functionCall('helper','call', helper.callParams), ' : helper))' + ]); }, // [invokePartial] // // On stack, before: context, ... // On stack after: result of partial invocation // // This operation pops off a context, invokes a partial with that context, // and pushes the result of the invocation back. - invokePartial: function(name, indent) { - var params = [this.nameLookup('partials', name, 'partial'), "'" + indent + "'", "'" + name + "'", this.popStack(), this.popStack(), "helpers", "partials"]; + invokePartial: function(isDynamic, name, indent) { + var params = [], + options = this.setupParams(name, 1, params, false); - if (this.options.data) { - params.push("data"); - } else if (this.options.compat) { - params.push('undefined'); + if (isDynamic) { + name = this.popStack(); + delete options.name; } + + if (indent) { + options.indent = JSON.stringify(indent); + } + options.helpers = 'helpers'; + options.partials = 'partials'; + + if (!isDynamic) { + params.unshift(this.nameLookup('partials', name, 'partial')); + } else { + params.unshift(name); + } + if (this.options.compat) { - params.push('depths'); + options.depths = 'depths'; } + options = this.objectLiteral(options); + params.push(options); - this.push("this.invokePartial(" + params.join(", ") + ")"); + this.push(this.source.functionCall('this.invokePartial', '', params)); }, // [assignToHash] // // On stack, before: value, ..., hash, ... @@ -2676,25 +3312,29 @@ context = this.popStack(); } var hash = this.hash; if (context) { - hash.contexts.push("'" + key + "': " + context); + hash.contexts[key] = context; } if (type) { - hash.types.push("'" + key + "': " + type); + hash.types[key] = type; } if (id) { - hash.ids.push("'" + key + "': " + id); + hash.ids[key] = id; } - hash.values.push("'" + key + "': (" + value + ")"); + hash.values[key] = value; }, - pushId: function(type, name) { - if (type === 'ID' || type === 'DATA') { + pushId: function(type, name, child) { + if (type === 'BlockParam') { + this.pushStackLiteral( + 'blockParams[' + name[0] + '].path[' + name[1] + ']' + + (child ? ' + ' + JSON.stringify('.' + child) : '')); + } else if (type === 'PathExpression') { this.pushString(name); - } else if (type === 'sexpr') { + } else if (type === 'SubExpression') { this.pushStackLiteral('true'); } else { this.pushStackLiteral('null'); } }, @@ -2719,13 +3359,17 @@ child.name = 'program' + index; this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); this.context.environments[index] = child; this.useDepths = this.useDepths || compiler.useDepths; + this.useBlockParams = this.useBlockParams || compiler.useBlockParams; } else { child.index = index; child.name = 'program' + index; + + this.useDepths = this.useDepths || child.useDepths; + this.useBlockParams = this.useBlockParams || child.useBlockParams; } } }, matchExistingProgram: function(child) { for (var i = 0, len = this.context.environments.length; i < len; i++) { @@ -2736,17 +3380,16 @@ } }, programExpression: function(guid) { var child = this.environment.children[guid], - depths = child.depths.list, - useDepths = this.useDepths, - depth; + programParams = [child.index, 'data', child.blockParams]; - var programParams = [child.index, 'data']; - - if (useDepths) { + if (this.useBlockParams || this.useDepths) { + programParams.push('blockParams'); + } + if (this.useDepths) { programParams.push('depths'); } return 'this.program(' + programParams.join(', ') + ')'; }, @@ -2756,37 +3399,37 @@ this.registers[name] = true; this.registers.list.push(name); } }, + push: function(expr) { + if (!(expr instanceof Literal)) { + expr = this.source.wrap(expr); + } + + this.inlineStack.push(expr); + return expr; + }, + pushStackLiteral: function(item) { - return this.push(new Literal(item)); + this.push(new Literal(item)); }, pushSource: function(source) { if (this.pendingContent) { - this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent))); + this.source.push( + this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation)); this.pendingContent = undefined; } if (source) { this.source.push(source); } }, - pushStack: function(item) { - this.flushInline(); - - var stack = this.incrStack(); - this.pushSource(stack + " = " + item + ";"); - this.compileStack.push(stack); - return stack; - }, - replaceStack: function(callback) { - var prefix = '', - inline = this.isInline(), + var prefix = ['('], stack, createdStack, usedLiteral; /* istanbul ignore next */ @@ -2797,18 +3440,19 @@ // We want to merge the inline statement into the replacement statement via ',' var top = this.popStack(true); if (top instanceof Literal) { // Literals do not need to be inlined - prefix = stack = top.value; + stack = [top.value]; + prefix = ['(', stack]; usedLiteral = true; } else { // Get or create the current stack name for use by the inline - createdStack = !this.stackSlot; - var name = !createdStack ? this.topStackName() : this.incrStack(); + createdStack = true; + var name = this.incrStack(); - prefix = '(' + this.push(name) + ' = ' + top + ')'; + prefix = ['((', this.push(name), ' = ', top, ')']; stack = this.topStack(); } var item = callback.call(this, stack); @@ -2816,11 +3460,11 @@ this.popStack(); } if (createdStack) { this.stackSlot--; } - this.push('(' + prefix + item + ')'); + this.push(prefix.concat(item, ')')); }, incrStack: function() { this.stackSlot++; if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } @@ -2829,19 +3473,20 @@ topStackName: function() { return "stack" + this.stackSlot; }, flushInline: function() { var inlineStack = this.inlineStack; - if (inlineStack.length) { - this.inlineStack = []; - for (var i = 0, len = inlineStack.length; i < len; i++) { - var entry = inlineStack[i]; - if (entry instanceof Literal) { - this.compileStack.push(entry); - } else { - this.pushStack(entry); - } + this.inlineStack = []; + for (var i = 0, len = inlineStack.length; i < len; i++) { + var entry = inlineStack[i]; + /* istanbul ignore if */ + if (entry instanceof Literal) { + this.compileStack.push(entry); + } else { + var stack = this.incrStack(); + this.pushSource([stack, ' = ', entry, ';']); + this.compileStack.push(stack); } } }, isInline: function() { return this.inlineStack.length; @@ -2867,10 +3512,11 @@ topStack: function() { var stack = (this.isInline() ? this.inlineStack : this.compileStack), item = stack[stack.length - 1]; + /* istanbul ignore if */ if (item instanceof Literal) { return item.value; } else { return item; } @@ -2883,46 +3529,46 @@ return 'depth' + context; } }, quotedString: function(str) { - return '"' + str - .replace(/\\/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 - .replace(/\u2029/g, '\\u2029') + '"'; + return this.source.quotedString(str); }, objectLiteral: function(obj) { - var pairs = []; + return this.source.objectLiteral(obj); + }, - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - pairs.push(this.quotedString(key) + ':' + obj[key]); - } + aliasable: function(name) { + var ret = this.aliases[name]; + if (ret) { + ret.referenceCount++; + return ret; } - return '{' + pairs.join(',') + '}'; + ret = this.aliases[name] = this.source.wrap(name); + ret.aliasable = true; + ret.referenceCount = 1; + + return ret; }, setupHelper: function(paramSize, name, blockHelper) { var params = [], - paramsInit = this.setupParams(name, paramSize, params, blockHelper); + paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); var foundHelper = this.nameLookup('helpers', name, 'helper'); return { params: params, paramsInit: paramsInit, name: foundHelper, - callParams: [this.contextName(0)].concat(params).join(", ") + callParams: [this.contextName(0)].concat(params) }; }, - setupOptions: function(helper, paramSize, params) { - var options = {}, contexts = [], types = [], ids = [], param, inverse, program; + setupParams: function(helper, paramSize, params) { + var options = {}, contexts = [], types = [], ids = [], param; options.name = this.quotedString(helper); options.hash = this.popStack(); if (this.trackIds) { @@ -2931,26 +3577,18 @@ if (this.stringParams) { options.hashTypes = this.popStack(); options.hashContexts = this.popStack(); } - inverse = this.popStack(); - program = this.popStack(); + var inverse = this.popStack(), + program = this.popStack(); // Avoid setting fn and inverse if neither are set. This allows // helpers to do a check for `if (options.fn)` if (program || inverse) { - if (!program) { - program = 'this.noop'; - } - - if (!inverse) { - inverse = 'this.noop'; - } - - options.fn = program; - options.inverse = inverse; + options.fn = program || 'this.noop'; + options.inverse = inverse || 'this.noop'; } // The parameters go on to the stack in order (making sure that they are evaluated in order) // so we need to pop them off the stack in reverse order var i = paramSize; @@ -2966,40 +3604,41 @@ contexts[i] = this.popStack(); } } if (this.trackIds) { - options.ids = "[" + ids.join(",") + "]"; + options.ids = this.source.generateArray(ids); } if (this.stringParams) { - options.types = "[" + types.join(",") + "]"; - options.contexts = "[" + contexts.join(",") + "]"; + options.types = this.source.generateArray(types); + options.contexts = this.source.generateArray(contexts); } if (this.options.data) { - options.data = "data"; + options.data = 'data'; } - + if (this.useBlockParams) { + options.blockParams = 'blockParams'; + } return options; }, - // the params and contexts arguments are passed in arrays - // to fill in - setupParams: function(helperName, paramSize, params, useRegister) { - var options = this.objectLiteral(this.setupOptions(helperName, paramSize, params)); - + setupHelperArgs: function(helper, paramSize, params, useRegister) { + var options = this.setupParams(helper, paramSize, params, true); + options = this.objectLiteral(options); if (useRegister) { this.useRegister('options'); params.push('options'); - return 'options=' + options; + return ['options=', options]; } else { params.push(options); return ''; } } }; + var reservedWords = ( "break else new var" + " case finally return void" + " catch for switch while" + " continue function this with" + @@ -3011,11 +3650,12 @@ " byte extends long super" + " char final native synchronized" + " class float package throws" + " const goto private transient" + " debugger implements protected volatile" + - " double import public let yield" + " double import public let yield await" + + " null true false" ).split(" "); var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; for(var i=0, l=reservedWords.length; i<l; i++) { @@ -3024,13 +3664,33 @@ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name); }; + function strictLookup(requireTerminal, compiler, parts, type) { + var stack = compiler.popStack(); + + var i = 0, + len = parts.length; + if (requireTerminal) { + len--; + } + + for (; i < len; i++) { + stack = compiler.nameLookup(stack, parts[i], type); + } + + if (requireTerminal) { + return [compiler.aliasable('this.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')']; + } else { + return stack; + } + } + __exports__ = JavaScriptCompiler; return __exports__; -})(__module2__, __module5__); +})(__module2__, __module4__, __module3__, __module15__); // handlebars.js var __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { "use strict"; var __exports__; @@ -3067,13 +3727,24 @@ }; Handlebars = create(); Handlebars.create = create; + /*jshint -W040 */ + /* istanbul ignore next */ + var root = typeof global !== 'undefined' ? global : window, + $Handlebars = root.Handlebars; + /* istanbul ignore next */ + Handlebars.noConflict = function() { + if (root.Handlebars === Handlebars) { + root.Handlebars = $Handlebars; + } + }; + Handlebars['default'] = Handlebars; __exports__ = Handlebars; return __exports__; -})(__module1__, __module7__, __module8__, __module11__, __module12__); +})(__module1__, __module7__, __module8__, __module13__, __module14__); return __module0__; }));