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