github.com/enmand/kubernetes@v1.2.0-alpha.0/third_party/swagger-ui/lib/handlebars-1.0.0.js (about) 1 /* 2 3 Copyright (C) 2011 by Yehuda Katz 4 5 Permission is hereby granted, free of charge, to any person obtaining a copy 6 of this software and associated documentation files (the "Software"), to deal 7 in the Software without restriction, including without limitation the rights 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 copies of the Software, and to permit persons to whom the Software is 10 furnished to do so, subject to the following conditions: 11 12 The above copyright notice and this permission notice shall be included in 13 all copies or substantial portions of the Software. 14 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 THE SOFTWARE. 22 23 */ 24 25 // lib/handlebars/browser-prefix.js 26 var Handlebars = {}; 27 28 (function(Handlebars, undefined) { 29 ; 30 // lib/handlebars/base.js 31 32 Handlebars.VERSION = "1.0.0"; 33 Handlebars.COMPILER_REVISION = 4; 34 35 Handlebars.REVISION_CHANGES = { 36 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 37 2: '== 1.0.0-rc.3', 38 3: '== 1.0.0-rc.4', 39 4: '>= 1.0.0' 40 }; 41 42 Handlebars.helpers = {}; 43 Handlebars.partials = {}; 44 45 var toString = Object.prototype.toString, 46 functionType = '[object Function]', 47 objectType = '[object Object]'; 48 49 Handlebars.registerHelper = function(name, fn, inverse) { 50 if (toString.call(name) === objectType) { 51 if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } 52 Handlebars.Utils.extend(this.helpers, name); 53 } else { 54 if (inverse) { fn.not = inverse; } 55 this.helpers[name] = fn; 56 } 57 }; 58 59 Handlebars.registerPartial = function(name, str) { 60 if (toString.call(name) === objectType) { 61 Handlebars.Utils.extend(this.partials, name); 62 } else { 63 this.partials[name] = str; 64 } 65 }; 66 67 Handlebars.registerHelper('helperMissing', function(arg) { 68 if(arguments.length === 2) { 69 return undefined; 70 } else { 71 throw new Error("Missing helper: '" + arg + "'"); 72 } 73 }); 74 75 Handlebars.registerHelper('blockHelperMissing', function(context, options) { 76 var inverse = options.inverse || function() {}, fn = options.fn; 77 78 var type = toString.call(context); 79 80 if(type === functionType) { context = context.call(this); } 81 82 if(context === true) { 83 return fn(this); 84 } else if(context === false || context == null) { 85 return inverse(this); 86 } else if(type === "[object Array]") { 87 if(context.length > 0) { 88 return Handlebars.helpers.each(context, options); 89 } else { 90 return inverse(this); 91 } 92 } else { 93 return fn(context); 94 } 95 }); 96 97 Handlebars.K = function() {}; 98 99 Handlebars.createFrame = Object.create || function(object) { 100 Handlebars.K.prototype = object; 101 var obj = new Handlebars.K(); 102 Handlebars.K.prototype = null; 103 return obj; 104 }; 105 106 Handlebars.logger = { 107 DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, 108 109 methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'}, 110 111 // can be overridden in the host environment 112 log: function(level, obj) { 113 if (Handlebars.logger.level <= level) { 114 var method = Handlebars.logger.methodMap[level]; 115 if (typeof console !== 'undefined' && console[method]) { 116 console[method].call(console, obj); 117 } 118 } 119 } 120 }; 121 122 Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); }; 123 124 Handlebars.registerHelper('each', function(context, options) { 125 var fn = options.fn, inverse = options.inverse; 126 var i = 0, ret = "", data; 127 128 var type = toString.call(context); 129 if(type === functionType) { context = context.call(this); } 130 131 if (options.data) { 132 data = Handlebars.createFrame(options.data); 133 } 134 135 if(context && typeof context === 'object') { 136 if(context instanceof Array){ 137 for(var j = context.length; i<j; i++) { 138 if (data) { data.index = i; } 139 ret = ret + fn(context[i], { data: data }); 140 } 141 } else { 142 for(var key in context) { 143 if(context.hasOwnProperty(key)) { 144 if(data) { data.key = key; } 145 ret = ret + fn(context[key], {data: data}); 146 i++; 147 } 148 } 149 } 150 } 151 152 if(i === 0){ 153 ret = inverse(this); 154 } 155 156 return ret; 157 }); 158 159 Handlebars.registerHelper('if', function(conditional, options) { 160 var type = toString.call(conditional); 161 if(type === functionType) { conditional = conditional.call(this); } 162 163 if(!conditional || Handlebars.Utils.isEmpty(conditional)) { 164 return options.inverse(this); 165 } else { 166 return options.fn(this); 167 } 168 }); 169 170 Handlebars.registerHelper('unless', function(conditional, options) { 171 return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn}); 172 }); 173 174 Handlebars.registerHelper('with', function(context, options) { 175 var type = toString.call(context); 176 if(type === functionType) { context = context.call(this); } 177 178 if (!Handlebars.Utils.isEmpty(context)) return options.fn(context); 179 }); 180 181 Handlebars.registerHelper('log', function(context, options) { 182 var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; 183 Handlebars.log(level, context); 184 }); 185 ; 186 // lib/handlebars/compiler/parser.js 187 /* Jison generated parser */ 188 var handlebars = (function(){ 189 var parser = {trace: function trace() { }, 190 yy: {}, 191 symbols_: {"error":2,"root":3,"program":4,"EOF":5,"simpleInverse":6,"statements":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"CLOSE_UNESCAPED":24,"OPEN_PARTIAL":25,"partialName":26,"params":27,"hash":28,"dataName":29,"param":30,"STRING":31,"INTEGER":32,"BOOLEAN":33,"hashSegments":34,"hashSegment":35,"ID":36,"EQUALS":37,"DATA":38,"pathSegments":39,"SEP":40,"$accept":0,"$end":1}, 192 terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"CLOSE_UNESCAPED",25:"OPEN_PARTIAL",31:"STRING",32:"INTEGER",33:"BOOLEAN",36:"ID",37:"EQUALS",38:"DATA",40:"SEP"}, 193 productions_: [0,[3,2],[4,2],[4,3],[4,2],[4,1],[4,1],[4,0],[7,1],[7,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[6,2],[17,3],[17,2],[17,2],[17,1],[17,1],[27,2],[27,1],[30,1],[30,1],[30,1],[30,1],[30,1],[28,1],[34,2],[34,1],[35,3],[35,3],[35,3],[35,3],[35,3],[26,1],[26,1],[26,1],[29,2],[21,1],[39,3],[39,1]], 194 performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { 195 196 var $0 = $$.length - 1; 197 switch (yystate) { 198 case 1: return $$[$0-1]; 199 break; 200 case 2: this.$ = new yy.ProgramNode([], $$[$0]); 201 break; 202 case 3: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]); 203 break; 204 case 4: this.$ = new yy.ProgramNode($$[$0-1], []); 205 break; 206 case 5: this.$ = new yy.ProgramNode($$[$0]); 207 break; 208 case 6: this.$ = new yy.ProgramNode([], []); 209 break; 210 case 7: this.$ = new yy.ProgramNode([]); 211 break; 212 case 8: this.$ = [$$[$0]]; 213 break; 214 case 9: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; 215 break; 216 case 10: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]); 217 break; 218 case 11: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]); 219 break; 220 case 12: this.$ = $$[$0]; 221 break; 222 case 13: this.$ = $$[$0]; 223 break; 224 case 14: this.$ = new yy.ContentNode($$[$0]); 225 break; 226 case 15: this.$ = new yy.CommentNode($$[$0]); 227 break; 228 case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); 229 break; 230 case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); 231 break; 232 case 18: this.$ = $$[$0-1]; 233 break; 234 case 19: 235 // Parsing out the '&' escape token at this level saves ~500 bytes after min due to the removal of one parser node. 236 this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2][2] === '&'); 237 238 break; 239 case 20: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true); 240 break; 241 case 21: this.$ = new yy.PartialNode($$[$0-1]); 242 break; 243 case 22: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]); 244 break; 245 case 23: 246 break; 247 case 24: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]]; 248 break; 249 case 25: this.$ = [[$$[$0-1]].concat($$[$0]), null]; 250 break; 251 case 26: this.$ = [[$$[$0-1]], $$[$0]]; 252 break; 253 case 27: this.$ = [[$$[$0]], null]; 254 break; 255 case 28: this.$ = [[$$[$0]], null]; 256 break; 257 case 29: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; 258 break; 259 case 30: this.$ = [$$[$0]]; 260 break; 261 case 31: this.$ = $$[$0]; 262 break; 263 case 32: this.$ = new yy.StringNode($$[$0]); 264 break; 265 case 33: this.$ = new yy.IntegerNode($$[$0]); 266 break; 267 case 34: this.$ = new yy.BooleanNode($$[$0]); 268 break; 269 case 35: this.$ = $$[$0]; 270 break; 271 case 36: this.$ = new yy.HashNode($$[$0]); 272 break; 273 case 37: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; 274 break; 275 case 38: this.$ = [$$[$0]]; 276 break; 277 case 39: this.$ = [$$[$0-2], $$[$0]]; 278 break; 279 case 40: this.$ = [$$[$0-2], new yy.StringNode($$[$0])]; 280 break; 281 case 41: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])]; 282 break; 283 case 42: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])]; 284 break; 285 case 43: this.$ = [$$[$0-2], $$[$0]]; 286 break; 287 case 44: this.$ = new yy.PartialNameNode($$[$0]); 288 break; 289 case 45: this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0])); 290 break; 291 case 46: this.$ = new yy.PartialNameNode(new yy.IntegerNode($$[$0])); 292 break; 293 case 47: this.$ = new yy.DataNode($$[$0]); 294 break; 295 case 48: this.$ = new yy.IdNode($$[$0]); 296 break; 297 case 49: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2]; 298 break; 299 case 50: this.$ = [{part: $$[$0]}]; 300 break; 301 } 302 }, 303 table: [{3:1,4:2,5:[2,7],6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],22:[1,14],23:[1,15],25:[1,16]},{1:[3]},{5:[1,17]},{5:[2,6],7:18,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,6],22:[1,14],23:[1,15],25:[1,16]},{5:[2,5],6:20,8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,5],22:[1,14],23:[1,15],25:[1,16]},{17:23,18:[1,22],21:24,29:25,36:[1,28],38:[1,27],39:26},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],25:[2,8]},{4:29,6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,7],22:[1,14],23:[1,15],25:[1,16]},{4:30,6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,7],22:[1,14],23:[1,15],25:[1,16]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],25:[2,12]},{5:[2,13],14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],25:[2,13]},{5:[2,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],25:[2,14]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],25:[2,15]},{17:31,21:24,29:25,36:[1,28],38:[1,27],39:26},{17:32,21:24,29:25,36:[1,28],38:[1,27],39:26},{17:33,21:24,29:25,36:[1,28],38:[1,27],39:26},{21:35,26:34,31:[1,36],32:[1,37],36:[1,28],39:26},{1:[2,1]},{5:[2,2],8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,2],22:[1,14],23:[1,15],25:[1,16]},{17:23,21:24,29:25,36:[1,28],38:[1,27],39:26},{5:[2,4],7:38,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,4],22:[1,14],23:[1,15],25:[1,16]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],25:[2,9]},{5:[2,23],14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],25:[2,23]},{18:[1,39]},{18:[2,27],21:44,24:[2,27],27:40,28:41,29:48,30:42,31:[1,45],32:[1,46],33:[1,47],34:43,35:49,36:[1,50],38:[1,27],39:26},{18:[2,28],24:[2,28]},{18:[2,48],24:[2,48],31:[2,48],32:[2,48],33:[2,48],36:[2,48],38:[2,48],40:[1,51]},{21:52,36:[1,28],39:26},{18:[2,50],24:[2,50],31:[2,50],32:[2,50],33:[2,50],36:[2,50],38:[2,50],40:[2,50]},{10:53,20:[1,54]},{10:55,20:[1,54]},{18:[1,56]},{18:[1,57]},{24:[1,58]},{18:[1,59],21:60,36:[1,28],39:26},{18:[2,44],36:[2,44]},{18:[2,45],36:[2,45]},{18:[2,46],36:[2,46]},{5:[2,3],8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,3],22:[1,14],23:[1,15],25:[1,16]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],25:[2,17]},{18:[2,25],21:44,24:[2,25],28:61,29:48,30:62,31:[1,45],32:[1,46],33:[1,47],34:43,35:49,36:[1,50],38:[1,27],39:26},{18:[2,26],24:[2,26]},{18:[2,30],24:[2,30],31:[2,30],32:[2,30],33:[2,30],36:[2,30],38:[2,30]},{18:[2,36],24:[2,36],35:63,36:[1,64]},{18:[2,31],24:[2,31],31:[2,31],32:[2,31],33:[2,31],36:[2,31],38:[2,31]},{18:[2,32],24:[2,32],31:[2,32],32:[2,32],33:[2,32],36:[2,32],38:[2,32]},{18:[2,33],24:[2,33],31:[2,33],32:[2,33],33:[2,33],36:[2,33],38:[2,33]},{18:[2,34],24:[2,34],31:[2,34],32:[2,34],33:[2,34],36:[2,34],38:[2,34]},{18:[2,35],24:[2,35],31:[2,35],32:[2,35],33:[2,35],36:[2,35],38:[2,35]},{18:[2,38],24:[2,38],36:[2,38]},{18:[2,50],24:[2,50],31:[2,50],32:[2,50],33:[2,50],36:[2,50],37:[1,65],38:[2,50],40:[2,50]},{36:[1,66]},{18:[2,47],24:[2,47],31:[2,47],32:[2,47],33:[2,47],36:[2,47],38:[2,47]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],25:[2,10]},{21:67,36:[1,28],39:26},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],25:[2,11]},{14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],25:[2,16]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],25:[2,19]},{5:[2,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],25:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],25:[2,21]},{18:[1,68]},{18:[2,24],24:[2,24]},{18:[2,29],24:[2,29],31:[2,29],32:[2,29],33:[2,29],36:[2,29],38:[2,29]},{18:[2,37],24:[2,37],36:[2,37]},{37:[1,65]},{21:69,29:73,31:[1,70],32:[1,71],33:[1,72],36:[1,28],38:[1,27],39:26},{18:[2,49],24:[2,49],31:[2,49],32:[2,49],33:[2,49],36:[2,49],38:[2,49],40:[2,49]},{18:[1,74]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],25:[2,22]},{18:[2,39],24:[2,39],36:[2,39]},{18:[2,40],24:[2,40],36:[2,40]},{18:[2,41],24:[2,41],36:[2,41]},{18:[2,42],24:[2,42],36:[2,42]},{18:[2,43],24:[2,43],36:[2,43]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],25:[2,18]}], 304 defaultActions: {17:[2,1]}, 305 parseError: function parseError(str, hash) { 306 throw new Error(str); 307 }, 308 parse: function parse(input) { 309 var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; 310 this.lexer.setInput(input); 311 this.lexer.yy = this.yy; 312 this.yy.lexer = this.lexer; 313 this.yy.parser = this; 314 if (typeof this.lexer.yylloc == "undefined") 315 this.lexer.yylloc = {}; 316 var yyloc = this.lexer.yylloc; 317 lstack.push(yyloc); 318 var ranges = this.lexer.options && this.lexer.options.ranges; 319 if (typeof this.yy.parseError === "function") 320 this.parseError = this.yy.parseError; 321 function popStack(n) { 322 stack.length = stack.length - 2 * n; 323 vstack.length = vstack.length - n; 324 lstack.length = lstack.length - n; 325 } 326 function lex() { 327 var token; 328 token = self.lexer.lex() || 1; 329 if (typeof token !== "number") { 330 token = self.symbols_[token] || token; 331 } 332 return token; 333 } 334 var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; 335 while (true) { 336 state = stack[stack.length - 1]; 337 if (this.defaultActions[state]) { 338 action = this.defaultActions[state]; 339 } else { 340 if (symbol === null || typeof symbol == "undefined") { 341 symbol = lex(); 342 } 343 action = table[state] && table[state][symbol]; 344 } 345 if (typeof action === "undefined" || !action.length || !action[0]) { 346 var errStr = ""; 347 if (!recovering) { 348 expected = []; 349 for (p in table[state]) 350 if (this.terminals_[p] && p > 2) { 351 expected.push("'" + this.terminals_[p] + "'"); 352 } 353 if (this.lexer.showPosition) { 354 errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; 355 } else { 356 errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); 357 } 358 this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); 359 } 360 } 361 if (action[0] instanceof Array && action.length > 1) { 362 throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); 363 } 364 switch (action[0]) { 365 case 1: 366 stack.push(symbol); 367 vstack.push(this.lexer.yytext); 368 lstack.push(this.lexer.yylloc); 369 stack.push(action[1]); 370 symbol = null; 371 if (!preErrorSymbol) { 372 yyleng = this.lexer.yyleng; 373 yytext = this.lexer.yytext; 374 yylineno = this.lexer.yylineno; 375 yyloc = this.lexer.yylloc; 376 if (recovering > 0) 377 recovering--; 378 } else { 379 symbol = preErrorSymbol; 380 preErrorSymbol = null; 381 } 382 break; 383 case 2: 384 len = this.productions_[action[1]][1]; 385 yyval.$ = vstack[vstack.length - len]; 386 yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; 387 if (ranges) { 388 yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; 389 } 390 r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); 391 if (typeof r !== "undefined") { 392 return r; 393 } 394 if (len) { 395 stack = stack.slice(0, -1 * len * 2); 396 vstack = vstack.slice(0, -1 * len); 397 lstack = lstack.slice(0, -1 * len); 398 } 399 stack.push(this.productions_[action[1]][0]); 400 vstack.push(yyval.$); 401 lstack.push(yyval._$); 402 newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; 403 stack.push(newState); 404 break; 405 case 3: 406 return true; 407 } 408 } 409 return true; 410 } 411 }; 412 /* Jison generated lexer */ 413 var lexer = (function(){ 414 var lexer = ({EOF:1, 415 parseError:function parseError(str, hash) { 416 if (this.yy.parser) { 417 this.yy.parser.parseError(str, hash); 418 } else { 419 throw new Error(str); 420 } 421 }, 422 setInput:function (input) { 423 this._input = input; 424 this._more = this._less = this.done = false; 425 this.yylineno = this.yyleng = 0; 426 this.yytext = this.matched = this.match = ''; 427 this.conditionStack = ['INITIAL']; 428 this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; 429 if (this.options.ranges) this.yylloc.range = [0,0]; 430 this.offset = 0; 431 return this; 432 }, 433 input:function () { 434 var ch = this._input[0]; 435 this.yytext += ch; 436 this.yyleng++; 437 this.offset++; 438 this.match += ch; 439 this.matched += ch; 440 var lines = ch.match(/(?:\r\n?|\n).*/g); 441 if (lines) { 442 this.yylineno++; 443 this.yylloc.last_line++; 444 } else { 445 this.yylloc.last_column++; 446 } 447 if (this.options.ranges) this.yylloc.range[1]++; 448 449 this._input = this._input.slice(1); 450 return ch; 451 }, 452 unput:function (ch) { 453 var len = ch.length; 454 var lines = ch.split(/(?:\r\n?|\n)/g); 455 456 this._input = ch + this._input; 457 this.yytext = this.yytext.substr(0, this.yytext.length-len-1); 458 //this.yyleng -= len; 459 this.offset -= len; 460 var oldLines = this.match.split(/(?:\r\n?|\n)/g); 461 this.match = this.match.substr(0, this.match.length-1); 462 this.matched = this.matched.substr(0, this.matched.length-1); 463 464 if (lines.length-1) this.yylineno -= lines.length-1; 465 var r = this.yylloc.range; 466 467 this.yylloc = {first_line: this.yylloc.first_line, 468 last_line: this.yylineno+1, 469 first_column: this.yylloc.first_column, 470 last_column: lines ? 471 (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length: 472 this.yylloc.first_column - len 473 }; 474 475 if (this.options.ranges) { 476 this.yylloc.range = [r[0], r[0] + this.yyleng - len]; 477 } 478 return this; 479 }, 480 more:function () { 481 this._more = true; 482 return this; 483 }, 484 less:function (n) { 485 this.unput(this.match.slice(n)); 486 }, 487 pastInput:function () { 488 var past = this.matched.substr(0, this.matched.length - this.match.length); 489 return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); 490 }, 491 upcomingInput:function () { 492 var next = this.match; 493 if (next.length < 20) { 494 next += this._input.substr(0, 20-next.length); 495 } 496 return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); 497 }, 498 showPosition:function () { 499 var pre = this.pastInput(); 500 var c = new Array(pre.length + 1).join("-"); 501 return pre + this.upcomingInput() + "\n" + c+"^"; 502 }, 503 next:function () { 504 if (this.done) { 505 return this.EOF; 506 } 507 if (!this._input) this.done = true; 508 509 var token, 510 match, 511 tempMatch, 512 index, 513 col, 514 lines; 515 if (!this._more) { 516 this.yytext = ''; 517 this.match = ''; 518 } 519 var rules = this._currentRules(); 520 for (var i=0;i < rules.length; i++) { 521 tempMatch = this._input.match(this.rules[rules[i]]); 522 if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { 523 match = tempMatch; 524 index = i; 525 if (!this.options.flex) break; 526 } 527 } 528 if (match) { 529 lines = match[0].match(/(?:\r\n?|\n).*/g); 530 if (lines) this.yylineno += lines.length; 531 this.yylloc = {first_line: this.yylloc.last_line, 532 last_line: this.yylineno+1, 533 first_column: this.yylloc.last_column, 534 last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length}; 535 this.yytext += match[0]; 536 this.match += match[0]; 537 this.matches = match; 538 this.yyleng = this.yytext.length; 539 if (this.options.ranges) { 540 this.yylloc.range = [this.offset, this.offset += this.yyleng]; 541 } 542 this._more = false; 543 this._input = this._input.slice(match[0].length); 544 this.matched += match[0]; 545 token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); 546 if (this.done && this._input) this.done = false; 547 if (token) return token; 548 else return; 549 } 550 if (this._input === "") { 551 return this.EOF; 552 } else { 553 return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), 554 {text: "", token: null, line: this.yylineno}); 555 } 556 }, 557 lex:function lex() { 558 var r = this.next(); 559 if (typeof r !== 'undefined') { 560 return r; 561 } else { 562 return this.lex(); 563 } 564 }, 565 begin:function begin(condition) { 566 this.conditionStack.push(condition); 567 }, 568 popState:function popState() { 569 return this.conditionStack.pop(); 570 }, 571 _currentRules:function _currentRules() { 572 return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; 573 }, 574 topState:function () { 575 return this.conditionStack[this.conditionStack.length-2]; 576 }, 577 pushState:function begin(condition) { 578 this.begin(condition); 579 }}); 580 lexer.options = {}; 581 lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { 582 583 var YYSTATE=YY_START 584 switch($avoiding_name_collisions) { 585 case 0: yy_.yytext = "\\"; return 14; 586 break; 587 case 1: 588 if(yy_.yytext.slice(-1) !== "\\") this.begin("mu"); 589 if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu"); 590 if(yy_.yytext) return 14; 591 592 break; 593 case 2: return 14; 594 break; 595 case 3: 596 if(yy_.yytext.slice(-1) !== "\\") this.popState(); 597 if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1); 598 return 14; 599 600 break; 601 case 4: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15; 602 break; 603 case 5: return 25; 604 break; 605 case 6: return 16; 606 break; 607 case 7: return 20; 608 break; 609 case 8: return 19; 610 break; 611 case 9: return 19; 612 break; 613 case 10: return 23; 614 break; 615 case 11: return 22; 616 break; 617 case 12: this.popState(); this.begin('com'); 618 break; 619 case 13: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; 620 break; 621 case 14: return 22; 622 break; 623 case 15: return 37; 624 break; 625 case 16: return 36; 626 break; 627 case 17: return 36; 628 break; 629 case 18: return 40; 630 break; 631 case 19: /*ignore whitespace*/ 632 break; 633 case 20: this.popState(); return 24; 634 break; 635 case 21: this.popState(); return 18; 636 break; 637 case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 31; 638 break; 639 case 23: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 31; 640 break; 641 case 24: return 38; 642 break; 643 case 25: return 33; 644 break; 645 case 26: return 33; 646 break; 647 case 27: return 32; 648 break; 649 case 28: return 36; 650 break; 651 case 29: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 36; 652 break; 653 case 30: return 'INVALID'; 654 break; 655 case 31: return 5; 656 break; 657 } 658 }; 659 lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}\/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; 660 lexer.conditions = {"mu":{"rules":[5,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],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"INITIAL":{"rules":[0,1,2,31],"inclusive":true}}; 661 return lexer;})() 662 parser.lexer = lexer; 663 function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; 664 return new Parser; 665 })();; 666 // lib/handlebars/compiler/base.js 667 668 Handlebars.Parser = handlebars; 669 670 Handlebars.parse = function(input) { 671 672 // Just return if an already-compile AST was passed in. 673 if(input.constructor === Handlebars.AST.ProgramNode) { return input; } 674 675 Handlebars.Parser.yy = Handlebars.AST; 676 return Handlebars.Parser.parse(input); 677 }; 678 ; 679 // lib/handlebars/compiler/ast.js 680 Handlebars.AST = {}; 681 682 Handlebars.AST.ProgramNode = function(statements, inverse) { 683 this.type = "program"; 684 this.statements = statements; 685 if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); } 686 }; 687 688 Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) { 689 this.type = "mustache"; 690 this.escaped = !unescaped; 691 this.hash = hash; 692 693 var id = this.id = rawParams[0]; 694 var params = this.params = rawParams.slice(1); 695 696 // a mustache is an eligible helper if: 697 // * its id is simple (a single part, not `this` or `..`) 698 var eligibleHelper = this.eligibleHelper = id.isSimple; 699 700 // a mustache is definitely a helper if: 701 // * it is an eligible helper, and 702 // * it has at least one parameter or hash segment 703 this.isHelper = eligibleHelper && (params.length || hash); 704 705 // if a mustache is an eligible helper but not a definite 706 // helper, it is ambiguous, and will be resolved in a later 707 // pass or at runtime. 708 }; 709 710 Handlebars.AST.PartialNode = function(partialName, context) { 711 this.type = "partial"; 712 this.partialName = partialName; 713 this.context = context; 714 }; 715 716 Handlebars.AST.BlockNode = function(mustache, program, inverse, close) { 717 var verifyMatch = function(open, close) { 718 if(open.original !== close.original) { 719 throw new Handlebars.Exception(open.original + " doesn't match " + close.original); 720 } 721 }; 722 723 verifyMatch(mustache.id, close); 724 this.type = "block"; 725 this.mustache = mustache; 726 this.program = program; 727 this.inverse = inverse; 728 729 if (this.inverse && !this.program) { 730 this.isInverse = true; 731 } 732 }; 733 734 Handlebars.AST.ContentNode = function(string) { 735 this.type = "content"; 736 this.string = string; 737 }; 738 739 Handlebars.AST.HashNode = function(pairs) { 740 this.type = "hash"; 741 this.pairs = pairs; 742 }; 743 744 Handlebars.AST.IdNode = function(parts) { 745 this.type = "ID"; 746 747 var original = "", 748 dig = [], 749 depth = 0; 750 751 for(var i=0,l=parts.length; i<l; i++) { 752 var part = parts[i].part; 753 original += (parts[i].separator || '') + part; 754 755 if (part === ".." || part === "." || part === "this") { 756 if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + original); } 757 else if (part === "..") { depth++; } 758 else { this.isScoped = true; } 759 } 760 else { dig.push(part); } 761 } 762 763 this.original = original; 764 this.parts = dig; 765 this.string = dig.join('.'); 766 this.depth = depth; 767 768 // an ID is simple if it only has one part, and that part is not 769 // `..` or `this`. 770 this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; 771 772 this.stringModeValue = this.string; 773 }; 774 775 Handlebars.AST.PartialNameNode = function(name) { 776 this.type = "PARTIAL_NAME"; 777 this.name = name.original; 778 }; 779 780 Handlebars.AST.DataNode = function(id) { 781 this.type = "DATA"; 782 this.id = id; 783 }; 784 785 Handlebars.AST.StringNode = function(string) { 786 this.type = "STRING"; 787 this.original = 788 this.string = 789 this.stringModeValue = string; 790 }; 791 792 Handlebars.AST.IntegerNode = function(integer) { 793 this.type = "INTEGER"; 794 this.original = 795 this.integer = integer; 796 this.stringModeValue = Number(integer); 797 }; 798 799 Handlebars.AST.BooleanNode = function(bool) { 800 this.type = "BOOLEAN"; 801 this.bool = bool; 802 this.stringModeValue = bool === "true"; 803 }; 804 805 Handlebars.AST.CommentNode = function(comment) { 806 this.type = "comment"; 807 this.comment = comment; 808 }; 809 ; 810 // lib/handlebars/utils.js 811 812 var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; 813 814 Handlebars.Exception = function(message) { 815 var tmp = Error.prototype.constructor.apply(this, arguments); 816 817 // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. 818 for (var idx = 0; idx < errorProps.length; idx++) { 819 this[errorProps[idx]] = tmp[errorProps[idx]]; 820 } 821 }; 822 Handlebars.Exception.prototype = new Error(); 823 824 // Build out our basic SafeString type 825 Handlebars.SafeString = function(string) { 826 this.string = string; 827 }; 828 Handlebars.SafeString.prototype.toString = function() { 829 return this.string.toString(); 830 }; 831 832 var escape = { 833 "&": "&", 834 "<": "<", 835 ">": ">", 836 '"': """, 837 "'": "'", 838 "`": "`" 839 }; 840 841 var badChars = /[&<>"'`]/g; 842 var possible = /[&<>"'`]/; 843 844 var escapeChar = function(chr) { 845 return escape[chr] || "&"; 846 }; 847 848 Handlebars.Utils = { 849 extend: function(obj, value) { 850 for(var key in value) { 851 if(value.hasOwnProperty(key)) { 852 obj[key] = value[key]; 853 } 854 } 855 }, 856 857 escapeExpression: function(string) { 858 // don't escape SafeStrings, since they're already safe 859 if (string instanceof Handlebars.SafeString) { 860 return string.toString(); 861 } else if (string == null || string === false) { 862 return ""; 863 } 864 865 // Force a string conversion as this will be done by the append regardless and 866 // the regex test will do this transparently behind the scenes, causing issues if 867 // an object's to string has escaped characters in it. 868 string = string.toString(); 869 870 if(!possible.test(string)) { return string; } 871 return string.replace(badChars, escapeChar); 872 }, 873 874 isEmpty: function(value) { 875 if (!value && value !== 0) { 876 return true; 877 } else if(toString.call(value) === "[object Array]" && value.length === 0) { 878 return true; 879 } else { 880 return false; 881 } 882 } 883 }; 884 ; 885 // lib/handlebars/compiler/compiler.js 886 887 /*jshint eqnull:true*/ 888 var Compiler = Handlebars.Compiler = function() {}; 889 var JavaScriptCompiler = Handlebars.JavaScriptCompiler = function() {}; 890 891 // the foundHelper register will disambiguate helper lookup from finding a 892 // function in a context. This is necessary for mustache compatibility, which 893 // requires that context functions in blocks are evaluated by blockHelperMissing, 894 // and then proceed as if the resulting value was provided to blockHelperMissing. 895 896 Compiler.prototype = { 897 compiler: Compiler, 898 899 disassemble: function() { 900 var opcodes = this.opcodes, opcode, out = [], params, param; 901 902 for (var i=0, l=opcodes.length; i<l; i++) { 903 opcode = opcodes[i]; 904 905 if (opcode.opcode === 'DECLARE') { 906 out.push("DECLARE " + opcode.name + "=" + opcode.value); 907 } else { 908 params = []; 909 for (var j=0; j<opcode.args.length; j++) { 910 param = opcode.args[j]; 911 if (typeof param === "string") { 912 param = "\"" + param.replace("\n", "\\n") + "\""; 913 } 914 params.push(param); 915 } 916 out.push(opcode.opcode + " " + params.join(" ")); 917 } 918 } 919 920 return out.join("\n"); 921 }, 922 equals: function(other) { 923 var len = this.opcodes.length; 924 if (other.opcodes.length !== len) { 925 return false; 926 } 927 928 for (var i = 0; i < len; i++) { 929 var opcode = this.opcodes[i], 930 otherOpcode = other.opcodes[i]; 931 if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) { 932 return false; 933 } 934 for (var j = 0; j < opcode.args.length; j++) { 935 if (opcode.args[j] !== otherOpcode.args[j]) { 936 return false; 937 } 938 } 939 } 940 941 len = this.children.length; 942 if (other.children.length !== len) { 943 return false; 944 } 945 for (i = 0; i < len; i++) { 946 if (!this.children[i].equals(other.children[i])) { 947 return false; 948 } 949 } 950 951 return true; 952 }, 953 954 guid: 0, 955 956 compile: function(program, options) { 957 this.children = []; 958 this.depths = {list: []}; 959 this.options = options; 960 961 // These changes will propagate to the other compiler components 962 var knownHelpers = this.options.knownHelpers; 963 this.options.knownHelpers = { 964 'helperMissing': true, 965 'blockHelperMissing': true, 966 'each': true, 967 'if': true, 968 'unless': true, 969 'with': true, 970 'log': true 971 }; 972 if (knownHelpers) { 973 for (var name in knownHelpers) { 974 this.options.knownHelpers[name] = knownHelpers[name]; 975 } 976 } 977 978 return this.program(program); 979 }, 980 981 accept: function(node) { 982 return this[node.type](node); 983 }, 984 985 program: function(program) { 986 var statements = program.statements, statement; 987 this.opcodes = []; 988 989 for(var i=0, l=statements.length; i<l; i++) { 990 statement = statements[i]; 991 this[statement.type](statement); 992 } 993 this.isSimple = l === 1; 994 995 this.depths.list = this.depths.list.sort(function(a, b) { 996 return a - b; 997 }); 998 999 return this; 1000 }, 1001 1002 compileProgram: function(program) { 1003 var result = new this.compiler().compile(program, this.options); 1004 var guid = this.guid++, depth; 1005 1006 this.usePartial = this.usePartial || result.usePartial; 1007 1008 this.children[guid] = result; 1009 1010 for(var i=0, l=result.depths.list.length; i<l; i++) { 1011 depth = result.depths.list[i]; 1012 1013 if(depth < 2) { continue; } 1014 else { this.addDepth(depth - 1); } 1015 } 1016 1017 return guid; 1018 }, 1019 1020 block: function(block) { 1021 var mustache = block.mustache, 1022 program = block.program, 1023 inverse = block.inverse; 1024 1025 if (program) { 1026 program = this.compileProgram(program); 1027 } 1028 1029 if (inverse) { 1030 inverse = this.compileProgram(inverse); 1031 } 1032 1033 var type = this.classifyMustache(mustache); 1034 1035 if (type === "helper") { 1036 this.helperMustache(mustache, program, inverse); 1037 } else if (type === "simple") { 1038 this.simpleMustache(mustache); 1039 1040 // now that the simple mustache is resolved, we need to 1041 // evaluate it by executing `blockHelperMissing` 1042 this.opcode('pushProgram', program); 1043 this.opcode('pushProgram', inverse); 1044 this.opcode('emptyHash'); 1045 this.opcode('blockValue'); 1046 } else { 1047 this.ambiguousMustache(mustache, program, inverse); 1048 1049 // now that the simple mustache is resolved, we need to 1050 // evaluate it by executing `blockHelperMissing` 1051 this.opcode('pushProgram', program); 1052 this.opcode('pushProgram', inverse); 1053 this.opcode('emptyHash'); 1054 this.opcode('ambiguousBlockValue'); 1055 } 1056 1057 this.opcode('append'); 1058 }, 1059 1060 hash: function(hash) { 1061 var pairs = hash.pairs, pair, val; 1062 1063 this.opcode('pushHash'); 1064 1065 for(var i=0, l=pairs.length; i<l; i++) { 1066 pair = pairs[i]; 1067 val = pair[1]; 1068 1069 if (this.options.stringParams) { 1070 if(val.depth) { 1071 this.addDepth(val.depth); 1072 } 1073 this.opcode('getContext', val.depth || 0); 1074 this.opcode('pushStringParam', val.stringModeValue, val.type); 1075 } else { 1076 this.accept(val); 1077 } 1078 1079 this.opcode('assignToHash', pair[0]); 1080 } 1081 this.opcode('popHash'); 1082 }, 1083 1084 partial: function(partial) { 1085 var partialName = partial.partialName; 1086 this.usePartial = true; 1087 1088 if(partial.context) { 1089 this.ID(partial.context); 1090 } else { 1091 this.opcode('push', 'depth0'); 1092 } 1093 1094 this.opcode('invokePartial', partialName.name); 1095 this.opcode('append'); 1096 }, 1097 1098 content: function(content) { 1099 this.opcode('appendContent', content.string); 1100 }, 1101 1102 mustache: function(mustache) { 1103 var options = this.options; 1104 var type = this.classifyMustache(mustache); 1105 1106 if (type === "simple") { 1107 this.simpleMustache(mustache); 1108 } else if (type === "helper") { 1109 this.helperMustache(mustache); 1110 } else { 1111 this.ambiguousMustache(mustache); 1112 } 1113 1114 if(mustache.escaped && !options.noEscape) { 1115 this.opcode('appendEscaped'); 1116 } else { 1117 this.opcode('append'); 1118 } 1119 }, 1120 1121 ambiguousMustache: function(mustache, program, inverse) { 1122 var id = mustache.id, 1123 name = id.parts[0], 1124 isBlock = program != null || inverse != null; 1125 1126 this.opcode('getContext', id.depth); 1127 1128 this.opcode('pushProgram', program); 1129 this.opcode('pushProgram', inverse); 1130 1131 this.opcode('invokeAmbiguous', name, isBlock); 1132 }, 1133 1134 simpleMustache: function(mustache) { 1135 var id = mustache.id; 1136 1137 if (id.type === 'DATA') { 1138 this.DATA(id); 1139 } else if (id.parts.length) { 1140 this.ID(id); 1141 } else { 1142 // Simplified ID for `this` 1143 this.addDepth(id.depth); 1144 this.opcode('getContext', id.depth); 1145 this.opcode('pushContext'); 1146 } 1147 1148 this.opcode('resolvePossibleLambda'); 1149 }, 1150 1151 helperMustache: function(mustache, program, inverse) { 1152 var params = this.setupFullMustacheParams(mustache, program, inverse), 1153 name = mustache.id.parts[0]; 1154 1155 if (this.options.knownHelpers[name]) { 1156 this.opcode('invokeKnownHelper', params.length, name); 1157 } else if (this.options.knownHelpersOnly) { 1158 throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name); 1159 } else { 1160 this.opcode('invokeHelper', params.length, name); 1161 } 1162 }, 1163 1164 ID: function(id) { 1165 this.addDepth(id.depth); 1166 this.opcode('getContext', id.depth); 1167 1168 var name = id.parts[0]; 1169 if (!name) { 1170 this.opcode('pushContext'); 1171 } else { 1172 this.opcode('lookupOnContext', id.parts[0]); 1173 } 1174 1175 for(var i=1, l=id.parts.length; i<l; i++) { 1176 this.opcode('lookup', id.parts[i]); 1177 } 1178 }, 1179 1180 DATA: function(data) { 1181 this.options.data = true; 1182 if (data.id.isScoped || data.id.depth) { 1183 throw new Handlebars.Exception('Scoped data references are not supported: ' + data.original); 1184 } 1185 1186 this.opcode('lookupData'); 1187 var parts = data.id.parts; 1188 for(var i=0, l=parts.length; i<l; i++) { 1189 this.opcode('lookup', parts[i]); 1190 } 1191 }, 1192 1193 STRING: function(string) { 1194 this.opcode('pushString', string.string); 1195 }, 1196 1197 INTEGER: function(integer) { 1198 this.opcode('pushLiteral', integer.integer); 1199 }, 1200 1201 BOOLEAN: function(bool) { 1202 this.opcode('pushLiteral', bool.bool); 1203 }, 1204 1205 comment: function() {}, 1206 1207 // HELPERS 1208 opcode: function(name) { 1209 this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) }); 1210 }, 1211 1212 declare: function(name, value) { 1213 this.opcodes.push({ opcode: 'DECLARE', name: name, value: value }); 1214 }, 1215 1216 addDepth: function(depth) { 1217 if(isNaN(depth)) { throw new Error("EWOT"); } 1218 if(depth === 0) { return; } 1219 1220 if(!this.depths[depth]) { 1221 this.depths[depth] = true; 1222 this.depths.list.push(depth); 1223 } 1224 }, 1225 1226 classifyMustache: function(mustache) { 1227 var isHelper = mustache.isHelper; 1228 var isEligible = mustache.eligibleHelper; 1229 var options = this.options; 1230 1231 // if ambiguous, we can possibly resolve the ambiguity now 1232 if (isEligible && !isHelper) { 1233 var name = mustache.id.parts[0]; 1234 1235 if (options.knownHelpers[name]) { 1236 isHelper = true; 1237 } else if (options.knownHelpersOnly) { 1238 isEligible = false; 1239 } 1240 } 1241 1242 if (isHelper) { return "helper"; } 1243 else if (isEligible) { return "ambiguous"; } 1244 else { return "simple"; } 1245 }, 1246 1247 pushParams: function(params) { 1248 var i = params.length, param; 1249 1250 while(i--) { 1251 param = params[i]; 1252 1253 if(this.options.stringParams) { 1254 if(param.depth) { 1255 this.addDepth(param.depth); 1256 } 1257 1258 this.opcode('getContext', param.depth || 0); 1259 this.opcode('pushStringParam', param.stringModeValue, param.type); 1260 } else { 1261 this[param.type](param); 1262 } 1263 } 1264 }, 1265 1266 setupMustacheParams: function(mustache) { 1267 var params = mustache.params; 1268 this.pushParams(params); 1269 1270 if(mustache.hash) { 1271 this.hash(mustache.hash); 1272 } else { 1273 this.opcode('emptyHash'); 1274 } 1275 1276 return params; 1277 }, 1278 1279 // this will replace setupMustacheParams when we're done 1280 setupFullMustacheParams: function(mustache, program, inverse) { 1281 var params = mustache.params; 1282 this.pushParams(params); 1283 1284 this.opcode('pushProgram', program); 1285 this.opcode('pushProgram', inverse); 1286 1287 if(mustache.hash) { 1288 this.hash(mustache.hash); 1289 } else { 1290 this.opcode('emptyHash'); 1291 } 1292 1293 return params; 1294 } 1295 }; 1296 1297 var Literal = function(value) { 1298 this.value = value; 1299 }; 1300 1301 JavaScriptCompiler.prototype = { 1302 // PUBLIC API: You can override these methods in a subclass to provide 1303 // alternative compiled forms for name lookup and buffering semantics 1304 nameLookup: function(parent, name /* , type*/) { 1305 if (/^[0-9]+$/.test(name)) { 1306 return parent + "[" + name + "]"; 1307 } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { 1308 return parent + "." + name; 1309 } 1310 else { 1311 return parent + "['" + name + "']"; 1312 } 1313 }, 1314 1315 appendToBuffer: function(string) { 1316 if (this.environment.isSimple) { 1317 return "return " + string + ";"; 1318 } else { 1319 return { 1320 appendToBuffer: true, 1321 content: string, 1322 toString: function() { return "buffer += " + string + ";"; } 1323 }; 1324 } 1325 }, 1326 1327 initializeBuffer: function() { 1328 return this.quotedString(""); 1329 }, 1330 1331 namespace: "Handlebars", 1332 // END PUBLIC API 1333 1334 compile: function(environment, options, context, asObject) { 1335 this.environment = environment; 1336 this.options = options || {}; 1337 1338 Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n"); 1339 1340 this.name = this.environment.name; 1341 this.isChild = !!context; 1342 this.context = context || { 1343 programs: [], 1344 environments: [], 1345 aliases: { } 1346 }; 1347 1348 this.preamble(); 1349 1350 this.stackSlot = 0; 1351 this.stackVars = []; 1352 this.registers = { list: [] }; 1353 this.compileStack = []; 1354 this.inlineStack = []; 1355 1356 this.compileChildren(environment, options); 1357 1358 var opcodes = environment.opcodes, opcode; 1359 1360 this.i = 0; 1361 1362 for(l=opcodes.length; this.i<l; this.i++) { 1363 opcode = opcodes[this.i]; 1364 1365 if(opcode.opcode === 'DECLARE') { 1366 this[opcode.name] = opcode.value; 1367 } else { 1368 this[opcode.opcode].apply(this, opcode.args); 1369 } 1370 } 1371 1372 return this.createFunctionContext(asObject); 1373 }, 1374 1375 nextOpcode: function() { 1376 var opcodes = this.environment.opcodes; 1377 return opcodes[this.i + 1]; 1378 }, 1379 1380 eat: function() { 1381 this.i = this.i + 1; 1382 }, 1383 1384 preamble: function() { 1385 var out = []; 1386 1387 if (!this.isChild) { 1388 var namespace = this.namespace; 1389 1390 var copies = "helpers = this.merge(helpers, " + namespace + ".helpers);"; 1391 if (this.environment.usePartial) { copies = copies + " partials = this.merge(partials, " + namespace + ".partials);"; } 1392 if (this.options.data) { copies = copies + " data = data || {};"; } 1393 out.push(copies); 1394 } else { 1395 out.push(''); 1396 } 1397 1398 if (!this.environment.isSimple) { 1399 out.push(", buffer = " + this.initializeBuffer()); 1400 } else { 1401 out.push(""); 1402 } 1403 1404 // track the last context pushed into place to allow skipping the 1405 // getContext opcode when it would be a noop 1406 this.lastContext = 0; 1407 this.source = out; 1408 }, 1409 1410 createFunctionContext: function(asObject) { 1411 var locals = this.stackVars.concat(this.registers.list); 1412 1413 if(locals.length > 0) { 1414 this.source[1] = this.source[1] + ", " + locals.join(", "); 1415 } 1416 1417 // Generate minimizer alias mappings 1418 if (!this.isChild) { 1419 for (var alias in this.context.aliases) { 1420 if (this.context.aliases.hasOwnProperty(alias)) { 1421 this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; 1422 } 1423 } 1424 } 1425 1426 if (this.source[1]) { 1427 this.source[1] = "var " + this.source[1].substring(2) + ";"; 1428 } 1429 1430 // Merge children 1431 if (!this.isChild) { 1432 this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; 1433 } 1434 1435 if (!this.environment.isSimple) { 1436 this.source.push("return buffer;"); 1437 } 1438 1439 var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; 1440 1441 for(var i=0, l=this.environment.depths.list.length; i<l; i++) { 1442 params.push("depth" + this.environment.depths.list[i]); 1443 } 1444 1445 // Perform a second pass over the output to merge content when possible 1446 var source = this.mergeSource(); 1447 1448 if (!this.isChild) { 1449 var revision = Handlebars.COMPILER_REVISION, 1450 versions = Handlebars.REVISION_CHANGES[revision]; 1451 source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source; 1452 } 1453 1454 if (asObject) { 1455 params.push(source); 1456 1457 return Function.apply(this, params); 1458 } else { 1459 var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}'; 1460 Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n"); 1461 return functionSource; 1462 } 1463 }, 1464 mergeSource: function() { 1465 // WARN: We are not handling the case where buffer is still populated as the source should 1466 // not have buffer append operations as their final action. 1467 var source = '', 1468 buffer; 1469 for (var i = 0, len = this.source.length; i < len; i++) { 1470 var line = this.source[i]; 1471 if (line.appendToBuffer) { 1472 if (buffer) { 1473 buffer = buffer + '\n + ' + line.content; 1474 } else { 1475 buffer = line.content; 1476 } 1477 } else { 1478 if (buffer) { 1479 source += 'buffer += ' + buffer + ';\n '; 1480 buffer = undefined; 1481 } 1482 source += line + '\n '; 1483 } 1484 } 1485 return source; 1486 }, 1487 1488 // [blockValue] 1489 // 1490 // On stack, before: hash, inverse, program, value 1491 // On stack, after: return value of blockHelperMissing 1492 // 1493 // The purpose of this opcode is to take a block of the form 1494 // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and 1495 // replace it on the stack with the result of properly 1496 // invoking blockHelperMissing. 1497 blockValue: function() { 1498 this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; 1499 1500 var params = ["depth0"]; 1501 this.setupParams(0, params); 1502 1503 this.replaceStack(function(current) { 1504 params.splice(1, 0, current); 1505 return "blockHelperMissing.call(" + params.join(", ") + ")"; 1506 }); 1507 }, 1508 1509 // [ambiguousBlockValue] 1510 // 1511 // On stack, before: hash, inverse, program, value 1512 // Compiler value, before: lastHelper=value of last found helper, if any 1513 // On stack, after, if no lastHelper: same as [blockValue] 1514 // On stack, after, if lastHelper: value 1515 ambiguousBlockValue: function() { 1516 this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; 1517 1518 var params = ["depth0"]; 1519 this.setupParams(0, params); 1520 1521 var current = this.topStack(); 1522 params.splice(1, 0, current); 1523 1524 // Use the options value generated from the invocation 1525 params[params.length-1] = 'options'; 1526 1527 this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }"); 1528 }, 1529 1530 // [appendContent] 1531 // 1532 // On stack, before: ... 1533 // On stack, after: ... 1534 // 1535 // Appends the string value of `content` to the current buffer 1536 appendContent: function(content) { 1537 this.source.push(this.appendToBuffer(this.quotedString(content))); 1538 }, 1539 1540 // [append] 1541 // 1542 // On stack, before: value, ... 1543 // On stack, after: ... 1544 // 1545 // Coerces `value` to a String and appends it to the current buffer. 1546 // 1547 // If `value` is truthy, or 0, it is coerced into a string and appended 1548 // Otherwise, the empty string is appended 1549 append: function() { 1550 // Force anything that is inlined onto the stack so we don't have duplication 1551 // when we examine local 1552 this.flushInline(); 1553 var local = this.popStack(); 1554 this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }"); 1555 if (this.environment.isSimple) { 1556 this.source.push("else { " + this.appendToBuffer("''") + " }"); 1557 } 1558 }, 1559 1560 // [appendEscaped] 1561 // 1562 // On stack, before: value, ... 1563 // On stack, after: ... 1564 // 1565 // Escape `value` and append it to the buffer 1566 appendEscaped: function() { 1567 this.context.aliases.escapeExpression = 'this.escapeExpression'; 1568 1569 this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")")); 1570 }, 1571 1572 // [getContext] 1573 // 1574 // On stack, before: ... 1575 // On stack, after: ... 1576 // Compiler value, after: lastContext=depth 1577 // 1578 // Set the value of the `lastContext` compiler value to the depth 1579 getContext: function(depth) { 1580 if(this.lastContext !== depth) { 1581 this.lastContext = depth; 1582 } 1583 }, 1584 1585 // [lookupOnContext] 1586 // 1587 // On stack, before: ... 1588 // On stack, after: currentContext[name], ... 1589 // 1590 // Looks up the value of `name` on the current context and pushes 1591 // it onto the stack. 1592 lookupOnContext: function(name) { 1593 this.push(this.nameLookup('depth' + this.lastContext, name, 'context')); 1594 }, 1595 1596 // [pushContext] 1597 // 1598 // On stack, before: ... 1599 // On stack, after: currentContext, ... 1600 // 1601 // Pushes the value of the current context onto the stack. 1602 pushContext: function() { 1603 this.pushStackLiteral('depth' + this.lastContext); 1604 }, 1605 1606 // [resolvePossibleLambda] 1607 // 1608 // On stack, before: value, ... 1609 // On stack, after: resolved value, ... 1610 // 1611 // If the `value` is a lambda, replace it on the stack by 1612 // the return value of the lambda 1613 resolvePossibleLambda: function() { 1614 this.context.aliases.functionType = '"function"'; 1615 1616 this.replaceStack(function(current) { 1617 return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current; 1618 }); 1619 }, 1620 1621 // [lookup] 1622 // 1623 // On stack, before: value, ... 1624 // On stack, after: value[name], ... 1625 // 1626 // Replace the value on the stack with the result of looking 1627 // up `name` on `value` 1628 lookup: function(name) { 1629 this.replaceStack(function(current) { 1630 return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context'); 1631 }); 1632 }, 1633 1634 // [lookupData] 1635 // 1636 // On stack, before: ... 1637 // On stack, after: data[id], ... 1638 // 1639 // Push the result of looking up `id` on the current data 1640 lookupData: function(id) { 1641 this.push('data'); 1642 }, 1643 1644 // [pushStringParam] 1645 // 1646 // On stack, before: ... 1647 // On stack, after: string, currentContext, ... 1648 // 1649 // This opcode is designed for use in string mode, which 1650 // provides the string value of a parameter along with its 1651 // depth rather than resolving it immediately. 1652 pushStringParam: function(string, type) { 1653 this.pushStackLiteral('depth' + this.lastContext); 1654 1655 this.pushString(type); 1656 1657 if (typeof string === 'string') { 1658 this.pushString(string); 1659 } else { 1660 this.pushStackLiteral(string); 1661 } 1662 }, 1663 1664 emptyHash: function() { 1665 this.pushStackLiteral('{}'); 1666 1667 if (this.options.stringParams) { 1668 this.register('hashTypes', '{}'); 1669 this.register('hashContexts', '{}'); 1670 } 1671 }, 1672 pushHash: function() { 1673 this.hash = {values: [], types: [], contexts: []}; 1674 }, 1675 popHash: function() { 1676 var hash = this.hash; 1677 this.hash = undefined; 1678 1679 if (this.options.stringParams) { 1680 this.register('hashContexts', '{' + hash.contexts.join(',') + '}'); 1681 this.register('hashTypes', '{' + hash.types.join(',') + '}'); 1682 } 1683 this.push('{\n ' + hash.values.join(',\n ') + '\n }'); 1684 }, 1685 1686 // [pushString] 1687 // 1688 // On stack, before: ... 1689 // On stack, after: quotedString(string), ... 1690 // 1691 // Push a quoted version of `string` onto the stack 1692 pushString: function(string) { 1693 this.pushStackLiteral(this.quotedString(string)); 1694 }, 1695 1696 // [push] 1697 // 1698 // On stack, before: ... 1699 // On stack, after: expr, ... 1700 // 1701 // Push an expression onto the stack 1702 push: function(expr) { 1703 this.inlineStack.push(expr); 1704 return expr; 1705 }, 1706 1707 // [pushLiteral] 1708 // 1709 // On stack, before: ... 1710 // On stack, after: value, ... 1711 // 1712 // Pushes a value onto the stack. This operation prevents 1713 // the compiler from creating a temporary variable to hold 1714 // it. 1715 pushLiteral: function(value) { 1716 this.pushStackLiteral(value); 1717 }, 1718 1719 // [pushProgram] 1720 // 1721 // On stack, before: ... 1722 // On stack, after: program(guid), ... 1723 // 1724 // Push a program expression onto the stack. This takes 1725 // a compile-time guid and converts it into a runtime-accessible 1726 // expression. 1727 pushProgram: function(guid) { 1728 if (guid != null) { 1729 this.pushStackLiteral(this.programExpression(guid)); 1730 } else { 1731 this.pushStackLiteral(null); 1732 } 1733 }, 1734 1735 // [invokeHelper] 1736 // 1737 // On stack, before: hash, inverse, program, params..., ... 1738 // On stack, after: result of helper invocation 1739 // 1740 // Pops off the helper's parameters, invokes the helper, 1741 // and pushes the helper's return value onto the stack. 1742 // 1743 // If the helper is not found, `helperMissing` is called. 1744 invokeHelper: function(paramSize, name) { 1745 this.context.aliases.helperMissing = 'helpers.helperMissing'; 1746 1747 var helper = this.lastHelper = this.setupHelper(paramSize, name, true); 1748 var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context'); 1749 1750 this.push(helper.name + ' || ' + nonHelper); 1751 this.replaceStack(function(name) { 1752 return name + ' ? ' + name + '.call(' + 1753 helper.callParams + ") " + ": helperMissing.call(" + 1754 helper.helperMissingParams + ")"; 1755 }); 1756 }, 1757 1758 // [invokeKnownHelper] 1759 // 1760 // On stack, before: hash, inverse, program, params..., ... 1761 // On stack, after: result of helper invocation 1762 // 1763 // This operation is used when the helper is known to exist, 1764 // so a `helperMissing` fallback is not required. 1765 invokeKnownHelper: function(paramSize, name) { 1766 var helper = this.setupHelper(paramSize, name); 1767 this.push(helper.name + ".call(" + helper.callParams + ")"); 1768 }, 1769 1770 // [invokeAmbiguous] 1771 // 1772 // On stack, before: hash, inverse, program, params..., ... 1773 // On stack, after: result of disambiguation 1774 // 1775 // This operation is used when an expression like `{{foo}}` 1776 // is provided, but we don't know at compile-time whether it 1777 // is a helper or a path. 1778 // 1779 // This operation emits more code than the other options, 1780 // and can be avoided by passing the `knownHelpers` and 1781 // `knownHelpersOnly` flags at compile-time. 1782 invokeAmbiguous: function(name, helperCall) { 1783 this.context.aliases.functionType = '"function"'; 1784 1785 this.pushStackLiteral('{}'); // Hash value 1786 var helper = this.setupHelper(0, name, helperCall); 1787 1788 var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); 1789 1790 var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context'); 1791 var nextStack = this.nextStack(); 1792 1793 this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }'); 1794 this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }'); 1795 }, 1796 1797 // [invokePartial] 1798 // 1799 // On stack, before: context, ... 1800 // On stack after: result of partial invocation 1801 // 1802 // This operation pops off a context, invokes a partial with that context, 1803 // and pushes the result of the invocation back. 1804 invokePartial: function(name) { 1805 var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"]; 1806 1807 if (this.options.data) { 1808 params.push("data"); 1809 } 1810 1811 this.context.aliases.self = "this"; 1812 this.push("self.invokePartial(" + params.join(", ") + ")"); 1813 }, 1814 1815 // [assignToHash] 1816 // 1817 // On stack, before: value, hash, ... 1818 // On stack, after: hash, ... 1819 // 1820 // Pops a value and hash off the stack, assigns `hash[key] = value` 1821 // and pushes the hash back onto the stack. 1822 assignToHash: function(key) { 1823 var value = this.popStack(), 1824 context, 1825 type; 1826 1827 if (this.options.stringParams) { 1828 type = this.popStack(); 1829 context = this.popStack(); 1830 } 1831 1832 var hash = this.hash; 1833 if (context) { 1834 hash.contexts.push("'" + key + "': " + context); 1835 } 1836 if (type) { 1837 hash.types.push("'" + key + "': " + type); 1838 } 1839 hash.values.push("'" + key + "': (" + value + ")"); 1840 }, 1841 1842 // HELPERS 1843 1844 compiler: JavaScriptCompiler, 1845 1846 compileChildren: function(environment, options) { 1847 var children = environment.children, child, compiler; 1848 1849 for(var i=0, l=children.length; i<l; i++) { 1850 child = children[i]; 1851 compiler = new this.compiler(); 1852 1853 var index = this.matchExistingProgram(child); 1854 1855 if (index == null) { 1856 this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children 1857 index = this.context.programs.length; 1858 child.index = index; 1859 child.name = 'program' + index; 1860 this.context.programs[index] = compiler.compile(child, options, this.context); 1861 this.context.environments[index] = child; 1862 } else { 1863 child.index = index; 1864 child.name = 'program' + index; 1865 } 1866 } 1867 }, 1868 matchExistingProgram: function(child) { 1869 for (var i = 0, len = this.context.environments.length; i < len; i++) { 1870 var environment = this.context.environments[i]; 1871 if (environment && environment.equals(child)) { 1872 return i; 1873 } 1874 } 1875 }, 1876 1877 programExpression: function(guid) { 1878 this.context.aliases.self = "this"; 1879 1880 if(guid == null) { 1881 return "self.noop"; 1882 } 1883 1884 var child = this.environment.children[guid], 1885 depths = child.depths.list, depth; 1886 1887 var programParams = [child.index, child.name, "data"]; 1888 1889 for(var i=0, l = depths.length; i<l; i++) { 1890 depth = depths[i]; 1891 1892 if(depth === 1) { programParams.push("depth0"); } 1893 else { programParams.push("depth" + (depth - 1)); } 1894 } 1895 1896 return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")"; 1897 }, 1898 1899 register: function(name, val) { 1900 this.useRegister(name); 1901 this.source.push(name + " = " + val + ";"); 1902 }, 1903 1904 useRegister: function(name) { 1905 if(!this.registers[name]) { 1906 this.registers[name] = true; 1907 this.registers.list.push(name); 1908 } 1909 }, 1910 1911 pushStackLiteral: function(item) { 1912 return this.push(new Literal(item)); 1913 }, 1914 1915 pushStack: function(item) { 1916 this.flushInline(); 1917 1918 var stack = this.incrStack(); 1919 if (item) { 1920 this.source.push(stack + " = " + item + ";"); 1921 } 1922 this.compileStack.push(stack); 1923 return stack; 1924 }, 1925 1926 replaceStack: function(callback) { 1927 var prefix = '', 1928 inline = this.isInline(), 1929 stack; 1930 1931 // If we are currently inline then we want to merge the inline statement into the 1932 // replacement statement via ',' 1933 if (inline) { 1934 var top = this.popStack(true); 1935 1936 if (top instanceof Literal) { 1937 // Literals do not need to be inlined 1938 stack = top.value; 1939 } else { 1940 // Get or create the current stack name for use by the inline 1941 var name = this.stackSlot ? this.topStackName() : this.incrStack(); 1942 1943 prefix = '(' + this.push(name) + ' = ' + top + '),'; 1944 stack = this.topStack(); 1945 } 1946 } else { 1947 stack = this.topStack(); 1948 } 1949 1950 var item = callback.call(this, stack); 1951 1952 if (inline) { 1953 if (this.inlineStack.length || this.compileStack.length) { 1954 this.popStack(); 1955 } 1956 this.push('(' + prefix + item + ')'); 1957 } else { 1958 // Prevent modification of the context depth variable. Through replaceStack 1959 if (!/^stack/.test(stack)) { 1960 stack = this.nextStack(); 1961 } 1962 1963 this.source.push(stack + " = (" + prefix + item + ");"); 1964 } 1965 return stack; 1966 }, 1967 1968 nextStack: function() { 1969 return this.pushStack(); 1970 }, 1971 1972 incrStack: function() { 1973 this.stackSlot++; 1974 if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } 1975 return this.topStackName(); 1976 }, 1977 topStackName: function() { 1978 return "stack" + this.stackSlot; 1979 }, 1980 flushInline: function() { 1981 var inlineStack = this.inlineStack; 1982 if (inlineStack.length) { 1983 this.inlineStack = []; 1984 for (var i = 0, len = inlineStack.length; i < len; i++) { 1985 var entry = inlineStack[i]; 1986 if (entry instanceof Literal) { 1987 this.compileStack.push(entry); 1988 } else { 1989 this.pushStack(entry); 1990 } 1991 } 1992 } 1993 }, 1994 isInline: function() { 1995 return this.inlineStack.length; 1996 }, 1997 1998 popStack: function(wrapped) { 1999 var inline = this.isInline(), 2000 item = (inline ? this.inlineStack : this.compileStack).pop(); 2001 2002 if (!wrapped && (item instanceof Literal)) { 2003 return item.value; 2004 } else { 2005 if (!inline) { 2006 this.stackSlot--; 2007 } 2008 return item; 2009 } 2010 }, 2011 2012 topStack: function(wrapped) { 2013 var stack = (this.isInline() ? this.inlineStack : this.compileStack), 2014 item = stack[stack.length - 1]; 2015 2016 if (!wrapped && (item instanceof Literal)) { 2017 return item.value; 2018 } else { 2019 return item; 2020 } 2021 }, 2022 2023 quotedString: function(str) { 2024 return '"' + str 2025 .replace(/\\/g, '\\\\') 2026 .replace(/"/g, '\\"') 2027 .replace(/\n/g, '\\n') 2028 .replace(/\r/g, '\\r') 2029 .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 2030 .replace(/\u2029/g, '\\u2029') + '"'; 2031 }, 2032 2033 setupHelper: function(paramSize, name, missingParams) { 2034 var params = []; 2035 this.setupParams(paramSize, params, missingParams); 2036 var foundHelper = this.nameLookup('helpers', name, 'helper'); 2037 2038 return { 2039 params: params, 2040 name: foundHelper, 2041 callParams: ["depth0"].concat(params).join(", "), 2042 helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") 2043 }; 2044 }, 2045 2046 // the params and contexts arguments are passed in arrays 2047 // to fill in 2048 setupParams: function(paramSize, params, useRegister) { 2049 var options = [], contexts = [], types = [], param, inverse, program; 2050 2051 options.push("hash:" + this.popStack()); 2052 2053 inverse = this.popStack(); 2054 program = this.popStack(); 2055 2056 // Avoid setting fn and inverse if neither are set. This allows 2057 // helpers to do a check for `if (options.fn)` 2058 if (program || inverse) { 2059 if (!program) { 2060 this.context.aliases.self = "this"; 2061 program = "self.noop"; 2062 } 2063 2064 if (!inverse) { 2065 this.context.aliases.self = "this"; 2066 inverse = "self.noop"; 2067 } 2068 2069 options.push("inverse:" + inverse); 2070 options.push("fn:" + program); 2071 } 2072 2073 for(var i=0; i<paramSize; i++) { 2074 param = this.popStack(); 2075 params.push(param); 2076 2077 if(this.options.stringParams) { 2078 types.push(this.popStack()); 2079 contexts.push(this.popStack()); 2080 } 2081 } 2082 2083 if (this.options.stringParams) { 2084 options.push("contexts:[" + contexts.join(",") + "]"); 2085 options.push("types:[" + types.join(",") + "]"); 2086 options.push("hashContexts:hashContexts"); 2087 options.push("hashTypes:hashTypes"); 2088 } 2089 2090 if(this.options.data) { 2091 options.push("data:data"); 2092 } 2093 2094 options = "{" + options.join(",") + "}"; 2095 if (useRegister) { 2096 this.register('options', options); 2097 params.push('options'); 2098 } else { 2099 params.push(options); 2100 } 2101 return params.join(", "); 2102 } 2103 }; 2104 2105 var reservedWords = ( 2106 "break else new var" + 2107 " case finally return void" + 2108 " catch for switch while" + 2109 " continue function this with" + 2110 " default if throw" + 2111 " delete in try" + 2112 " do instanceof typeof" + 2113 " abstract enum int short" + 2114 " boolean export interface static" + 2115 " byte extends long super" + 2116 " char final native synchronized" + 2117 " class float package throws" + 2118 " const goto private transient" + 2119 " debugger implements protected volatile" + 2120 " double import public let yield" 2121 ).split(" "); 2122 2123 var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; 2124 2125 for(var i=0, l=reservedWords.length; i<l; i++) { 2126 compilerWords[reservedWords[i]] = true; 2127 } 2128 2129 JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { 2130 if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) { 2131 return true; 2132 } 2133 return false; 2134 }; 2135 2136 Handlebars.precompile = function(input, options) { 2137 if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { 2138 throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input); 2139 } 2140 2141 options = options || {}; 2142 if (!('data' in options)) { 2143 options.data = true; 2144 } 2145 var ast = Handlebars.parse(input); 2146 var environment = new Compiler().compile(ast, options); 2147 return new JavaScriptCompiler().compile(environment, options); 2148 }; 2149 2150 Handlebars.compile = function(input, options) { 2151 if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { 2152 throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); 2153 } 2154 2155 options = options || {}; 2156 if (!('data' in options)) { 2157 options.data = true; 2158 } 2159 var compiled; 2160 function compile() { 2161 var ast = Handlebars.parse(input); 2162 var environment = new Compiler().compile(ast, options); 2163 var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true); 2164 return Handlebars.template(templateSpec); 2165 } 2166 2167 // Template is only compiled on first use and cached after that point. 2168 return function(context, options) { 2169 if (!compiled) { 2170 compiled = compile(); 2171 } 2172 return compiled.call(this, context, options); 2173 }; 2174 }; 2175 2176 ; 2177 // lib/handlebars/runtime.js 2178 2179 Handlebars.VM = { 2180 template: function(templateSpec) { 2181 // Just add water 2182 var container = { 2183 escapeExpression: Handlebars.Utils.escapeExpression, 2184 invokePartial: Handlebars.VM.invokePartial, 2185 programs: [], 2186 program: function(i, fn, data) { 2187 var programWrapper = this.programs[i]; 2188 if(data) { 2189 programWrapper = Handlebars.VM.program(i, fn, data); 2190 } else if (!programWrapper) { 2191 programWrapper = this.programs[i] = Handlebars.VM.program(i, fn); 2192 } 2193 return programWrapper; 2194 }, 2195 merge: function(param, common) { 2196 var ret = param || common; 2197 2198 if (param && common) { 2199 ret = {}; 2200 Handlebars.Utils.extend(ret, common); 2201 Handlebars.Utils.extend(ret, param); 2202 } 2203 return ret; 2204 }, 2205 programWithDepth: Handlebars.VM.programWithDepth, 2206 noop: Handlebars.VM.noop, 2207 compilerInfo: null 2208 }; 2209 2210 return function(context, options) { 2211 options = options || {}; 2212 var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data); 2213 2214 var compilerInfo = container.compilerInfo || [], 2215 compilerRevision = compilerInfo[0] || 1, 2216 currentRevision = Handlebars.COMPILER_REVISION; 2217 2218 if (compilerRevision !== currentRevision) { 2219 if (compilerRevision < currentRevision) { 2220 var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision], 2221 compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision]; 2222 throw "Template was precompiled with an older version of Handlebars than the current runtime. "+ 2223 "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."; 2224 } else { 2225 // Use the embedded version info since the runtime doesn't know about this revision yet 2226 throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+ 2227 "Please update your runtime to a newer version ("+compilerInfo[1]+")."; 2228 } 2229 } 2230 2231 return result; 2232 }; 2233 }, 2234 2235 programWithDepth: function(i, fn, data /*, $depth */) { 2236 var args = Array.prototype.slice.call(arguments, 3); 2237 2238 var program = function(context, options) { 2239 options = options || {}; 2240 2241 return fn.apply(this, [context, options.data || data].concat(args)); 2242 }; 2243 program.program = i; 2244 program.depth = args.length; 2245 return program; 2246 }, 2247 program: function(i, fn, data) { 2248 var program = function(context, options) { 2249 options = options || {}; 2250 2251 return fn(context, options.data || data); 2252 }; 2253 program.program = i; 2254 program.depth = 0; 2255 return program; 2256 }, 2257 noop: function() { return ""; }, 2258 invokePartial: function(partial, name, context, helpers, partials, data) { 2259 var options = { helpers: helpers, partials: partials, data: data }; 2260 2261 if(partial === undefined) { 2262 throw new Handlebars.Exception("The partial " + name + " could not be found"); 2263 } else if(partial instanceof Function) { 2264 return partial(context, options); 2265 } else if (!Handlebars.compile) { 2266 throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); 2267 } else { 2268 partials[name] = Handlebars.compile(partial, {data: data !== undefined}); 2269 return partials[name](context, options); 2270 } 2271 } 2272 }; 2273 2274 Handlebars.template = Handlebars.VM.template; 2275 ; 2276 // lib/handlebars/browser-suffix.js 2277 })(Handlebars); 2278 ;