Issues (2873)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

ui/js/handlebars.js (51 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
// lib/handlebars/base.js
2
var Handlebars = {};
3
4
Handlebars.VERSION = "1.0.beta.6";
5
6
Handlebars.helpers  = {};
7
Handlebars.partials = {};
8
9
Handlebars.registerHelper = function(name, fn, inverse) {
10
  if(inverse) { fn.not = inverse; }
11
  this.helpers[name] = fn;
12
};
13
14
Handlebars.registerPartial = function(name, str) {
15
  this.partials[name] = str;
16
};
17
18
Handlebars.registerHelper('helperMissing', function(arg) {
19
  if(arguments.length === 2) {
20
    return undefined;
21
  } else {
22
    throw new Error("Could not find property '" + arg + "'");
23
  }
24
});
25
26
var toString = Object.prototype.toString, functionType = "[object Function]";
27
28
Handlebars.registerHelper('blockHelperMissing', function(context, options) {
29
  var inverse = options.inverse || function() {}, fn = options.fn;
30
31
32
  var ret = "";
33
  var type = toString.call(context);
34
35
  if(type === functionType) { context = context.call(this); }
36
37
  if(context === true) {
38
    return fn(this);
39
  } else if(context === false || context == null) {
0 ignored issues
show
=== was expected, but instead == was given.
Loading history...
40
    return inverse(this);
41
  } else if(type === "[object Array]") {
42
    if(context.length > 0) {
43
      for(var i=0, j=context.length; i<j; i++) {
44
        ret = ret + fn(context[i]);
45
      }
46
    } else {
47
      ret = inverse(this);
48
    }
49
    return ret;
50
  } else {
51
    return fn(context);
52
  }
53
});
54
55
Handlebars.registerHelper('each', function(context, options) {
56
  var fn = options.fn, inverse = options.inverse;
57
  var ret = "";
58
59
  if(context && context.length > 0) {
60
    for(var i=0, j=context.length; i<j; i++) {
61
      ret = ret + fn(context[i]);
62
    }
63
  } else {
64
    ret = inverse(this);
65
  }
66
  return ret;
67
});
68
69
Handlebars.registerHelper('if', function(context, options) {
70
  var type = toString.call(context);
71
  if(type === functionType) { context = context.call(this); }
72
73
  if(!context || Handlebars.Utils.isEmpty(context)) {
74
    return options.inverse(this);
75
  } else {
76
    return options.fn(this);
77
  }
78
});
79
80
Handlebars.registerHelper('unless', function(context, options) {
81
  var fn = options.fn, inverse = options.inverse;
82
  options.fn = inverse;
83
  options.inverse = fn;
84
85
  return Handlebars.helpers['if'].call(this, context, options);
86
});
87
88
Handlebars.registerHelper('with', function(context, options) {
89
  return options.fn(context);
90
});
91
92
Handlebars.registerHelper('log', function(context) {
93
  Handlebars.log(context);
94
});
95
;
0 ignored issues
show
This semicolons seems to be unnecessary.
Loading history...
96
// lib/handlebars/compiler/parser.js
97
/* Jison generated parser */
98
var handlebars = (function(){
99
100
var parser = {trace: function trace() { },
101
yy: {},
102
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,"param":27,"STRING":28,"INTEGER":29,"BOOLEAN":30,"hashSegments":31,"hashSegment":32,"ID":33,"EQUALS":34,"pathSegments":35,"SEP":36,"$accept":0,"$end":1},
103
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",28:"STRING",29:"INTEGER",30:"BOOLEAN",33:"ID",34:"EQUALS",36:"SEP"},
104
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],[25,2],[25,1],[27,1],[27,1],[27,1],[27,1],[26,1],[31,2],[31,1],[32,3],[32,3],[32,3],[32,3],[21,1],[35,3],[35,1]],
105
performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
106
107
var $0 = $$.length - 1;
108
switch (yystate) {
109
case 1: return $$[$0-1];
110
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
111
case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]);
112
break;
113
case 3: this.$ = new yy.ProgramNode($$[$0]);
114
break;
115
case 4: this.$ = new yy.ProgramNode([]);
116
break;
117
case 5: this.$ = [$$[$0]];
118
break;
119
case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
120
break;
121
case 7: this.$ = new yy.InverseNode($$[$0-2], $$[$0-1], $$[$0]);
122
break;
123
case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0]);
124
break;
125
case 9: this.$ = $$[$0];
126
break;
127
case 10: this.$ = $$[$0];
128
break;
129
case 11: this.$ = new yy.ContentNode($$[$0]);
130
break;
131
case 12: this.$ = new yy.CommentNode($$[$0]);
132
break;
133
case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
134
break;
135
case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
136
break;
137
case 15: this.$ = $$[$0-1];
138
break;
139
case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
140
break;
141
case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true);
142
break;
143
case 18: this.$ = new yy.PartialNode($$[$0-1]);
144
break;
145
case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]);
146
break;
147
case 20:
148
break;
149
case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]];
150
break;
151
case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null];
152
break;
153
case 23: this.$ = [[$$[$0-1]], $$[$0]];
154
break;
155
case 24: this.$ = [[$$[$0]], null];
156
break;
157
case 25: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
158
break;
159
case 26: this.$ = [$$[$0]];
160
break;
161
case 27: this.$ = $$[$0];
162
break;
163
case 28: this.$ = new yy.StringNode($$[$0]);
164
break;
165
case 29: this.$ = new yy.IntegerNode($$[$0]);
166
break;
167
case 30: this.$ = new yy.BooleanNode($$[$0]);
168
break;
169
case 31: this.$ = new yy.HashNode($$[$0]);
170
break;
171
case 32: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
172
break;
173
case 33: this.$ = [$$[$0]];
174
break;
175
case 34: this.$ = [$$[$0-2], $$[$0]];
176
break;
177
case 35: this.$ = [$$[$0-2], new yy.StringNode($$[$0])];
178
break;
179
case 36: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])];
180
break;
181
case 37: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])];
182
break;
183
case 38: this.$ = new yy.IdNode($$[$0]);
184
break;
185
case 39: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
186
break;
187
case 40: this.$ = [$$[$0]];
188
break;
189
}
190
},
191
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,33:[1,25],35:24},{17:26,21:23,33:[1,25],35:24},{17:27,21:23,33:[1,25],35:24},{17:28,21:23,33:[1,25],35:24},{21:29,33:[1,25],35:24},{1:[2,1]},{6:30,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,31],21:23,33:[1,25],35:24},{10:32,20:[1,33]},{10:34,20:[1,33]},{18:[1,35]},{18:[2,24],21:40,25:36,26:37,27:38,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,38],28:[2,38],29:[2,38],30:[2,38],33:[2,38],36:[1,46]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],36:[2,40]},{18:[1,47]},{18:[1,48]},{18:[1,49]},{18:[1,50],21:51,33:[1,25],35:24},{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:52,33:[1,25],35:24},{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:40,26:53,27:54,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,23]},{18:[2,26],28:[2,26],29:[2,26],30:[2,26],33:[2,26]},{18:[2,31],32:55,33:[1,56]},{18:[2,27],28:[2,27],29:[2,27],30:[2,27],33:[2,27]},{18:[2,28],28:[2,28],29:[2,28],30:[2,28],33:[2,28]},{18:[2,29],28:[2,29],29:[2,29],30:[2,29],33:[2,29]},{18:[2,30],28:[2,30],29:[2,30],30:[2,30],33:[2,30]},{18:[2,33],33:[2,33]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],34:[1,57],36:[2,40]},{33:[1,58]},{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,59]},{18:[1,60]},{18:[2,21]},{18:[2,25],28:[2,25],29:[2,25],30:[2,25],33:[2,25]},{18:[2,32],33:[2,32]},{34:[1,57]},{21:61,28:[1,62],29:[1,63],30:[1,64],33:[1,25],35:24},{18:[2,39],28:[2,39],29:[2,39],30:[2,39],33:[2,39],36:[2,39]},{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,34],33:[2,34]},{18:[2,35],33:[2,35]},{18:[2,36],33:[2,36]},{18:[2,37],33:[2,37]}],
192
defaultActions: {16:[2,1],37:[2,23],53:[2,21]},
193
parseError: function parseError(str, hash) {
194
    throw new Error(str);
195
},
196
parse: function parse(input) {
197
    var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
198
    this.lexer.setInput(input);
199
    this.lexer.yy = this.yy;
200
    this.yy.lexer = this.lexer;
201
    if (typeof this.lexer.yylloc == "undefined")
0 ignored issues
show
=== was expected, but instead == was given.
Loading history...
202
        this.lexer.yylloc = {};
0 ignored issues
show
{ was expected, but instead this was given.
Loading history...
203
    var yyloc = this.lexer.yylloc;
204
    lstack.push(yyloc);
205
    if (typeof this.yy.parseError === "function")
206
        this.parseError = this.yy.parseError;
0 ignored issues
show
{ was expected, but instead this was given.
Loading history...
207
    function popStack(n) {
208
        stack.length = stack.length - 2 * n;
209
        vstack.length = vstack.length - n;
210
        lstack.length = lstack.length - n;
211
    }
212
    function lex() {
213
        var token;
214
        token = self.lexer.lex() || 1;
215
        if (typeof token !== "number") {
216
            token = self.symbols_[token] || token;
217
        }
218
        return token;
219
    }
220
    var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
221
    while (true) {
222
        state = stack[stack.length - 1];
223
        if (this.defaultActions[state]) {
224
            action = this.defaultActions[state];
225
        } else {
226
            if (symbol == null)
0 ignored issues
show
=== was expected, but instead == was given.
Loading history...
227
                symbol = lex();
0 ignored issues
show
{ was expected, but instead symbol was given.
Loading history...
228
            action = table[state] && table[state][symbol];
229
        }
230
        if (typeof action === "undefined" || !action.length || !action[0]) {
231
            if (!recovering) {
232
                expected = [];
233
                for (p in table[state])
234
                    if (this.terminals_[p] && p > 2) {
0 ignored issues
show
{ was expected, but instead if was given.
Loading history...
235
                        expected.push("'" + this.terminals_[p] + "'");
236
                    }
237
                var errStr = "";
238
                if (this.lexer.showPosition) {
239
                    errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + this.terminals_[symbol] + "'";
240
                } else {
241
                    errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'");
0 ignored issues
show
=== was expected, but instead == was given.
Loading history...
242
                }
243
                this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
244
            }
245
        }
246
        if (action[0] instanceof Array && action.length > 1) {
247
            throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
248
        }
249
        switch (action[0]) {
250
        case 1:
251
            stack.push(symbol);
252
            vstack.push(this.lexer.yytext);
253
            lstack.push(this.lexer.yylloc);
254
            stack.push(action[1]);
255
            symbol = null;
256
            if (!preErrorSymbol) {
257
                yyleng = this.lexer.yyleng;
258
                yytext = this.lexer.yytext;
259
                yylineno = this.lexer.yylineno;
260
                yyloc = this.lexer.yylloc;
261
                if (recovering > 0)
262
                    recovering--;
0 ignored issues
show
{ was expected, but instead recovering was given.
Loading history...
263
            } else {
264
                symbol = preErrorSymbol;
265
                preErrorSymbol = null;
266
            }
267
            break;
268
        case 2:
269
            len = this.productions_[action[1]][1];
270
            yyval.$ = vstack[vstack.length - len];
271
            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};
272
            r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
273
            if (typeof r !== "undefined") {
274
                return r;
275
            }
276
            if (len) {
277
                stack = stack.slice(0, -1 * len * 2);
278
                vstack = vstack.slice(0, -1 * len);
279
                lstack = lstack.slice(0, -1 * len);
280
            }
281
            stack.push(this.productions_[action[1]][0]);
282
            vstack.push(yyval.$);
283
            lstack.push(yyval._$);
284
            newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
285
            stack.push(newState);
286
            break;
287
        case 3:
288
            return true;
289
        }
290
    }
291
    return true;
292
}
293
};/* Jison generated lexer */
294
var lexer = (function(){
295
296
var lexer = ({EOF:1,
297
parseError:function parseError(str, hash) {
298
        if (this.yy.parseError) {
299
            this.yy.parseError(str, hash);
300
        } else {
301
            throw new Error(str);
302
        }
303
    },
304
setInput:function (input) {
305
        this._input = input;
306
        this._more = this._less = this.done = false;
307
        this.yylineno = this.yyleng = 0;
308
        this.yytext = this.matched = this.match = '';
309
        this.conditionStack = ['INITIAL'];
310
        this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
311
        return this;
312
    },
313
input:function () {
314
        var ch = this._input[0];
315
        this.yytext+=ch;
316
        this.yyleng++;
317
        this.match+=ch;
318
        this.matched+=ch;
319
        var lines = ch.match(/\n/);
320
        if (lines) this.yylineno++;
0 ignored issues
show
{ was expected, but instead this was given.
Loading history...
321
        this._input = this._input.slice(1);
322
        return ch;
323
    },
324
unput:function (ch) {
325
        this._input = ch + this._input;
326
        return this;
327
    },
328
more:function () {
329
        this._more = true;
330
        return this;
331
    },
332
pastInput:function () {
333
        var past = this.matched.substr(0, this.matched.length - this.match.length);
334
        return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
335
    },
336
upcomingInput:function () {
337
        var next = this.match;
338
        if (next.length < 20) {
339
            next += this._input.substr(0, 20-next.length);
340
        }
341
        return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
342
    },
343
showPosition:function () {
344
        var pre = this.pastInput();
345
        var c = new Array(pre.length + 1).join("-");
346
        return pre + this.upcomingInput() + "\n" + c+"^";
347
    },
348
next:function () {
349
        if (this.done) {
350
            return this.EOF;
351
        }
352
        if (!this._input) this.done = true;
0 ignored issues
show
{ was expected, but instead this was given.
Loading history...
353
354
        var token,
355
            match,
356
            col,
357
            lines;
358
        if (!this._more) {
359
            this.yytext = '';
360
            this.match = '';
361
        }
362
        var rules = this._currentRules();
363
        for (var i=0;i < rules.length; i++) {
364
            match = this._input.match(this.rules[rules[i]]);
365
            if (match) {
366
                lines = match[0].match(/\n.*/g);
367
                if (lines) this.yylineno += lines.length;
0 ignored issues
show
{ was expected, but instead this was given.
Loading history...
368
                this.yylloc = {first_line: this.yylloc.last_line,
369
                               last_line: this.yylineno+1,
370
                               first_column: this.yylloc.last_column,
371
                               last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length};
372
                this.yytext += match[0];
373
                this.match += match[0];
374
                this.matches = match;
375
                this.yyleng = this.yytext.length;
376
                this._more = false;
377
                this._input = this._input.slice(match[0].length);
378
                this.matched += match[0];
379
                token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);
380
                if (token) return token;
0 ignored issues
show
{ was expected, but instead return was given.
Loading history...
381
                else return;
0 ignored issues
show
{ was expected, but instead return was given.
Loading history...
382
            }
383
        }
384
        if (this._input === "") {
385
            return this.EOF;
386
        } else {
387
            this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
388
                    {text: "", token: null, line: this.yylineno});
389
        }
390
    },
391
lex:function lex() {
392
        var r = this.next();
393
        if (typeof r !== 'undefined') {
394
            return r;
395
        } else {
396
            return this.lex();
397
        }
398
    },
399
begin:function begin(condition) {
400
        this.conditionStack.push(condition);
401
    },
402
popState:function popState() {
403
        return this.conditionStack.pop();
404
    },
405
_currentRules:function _currentRules() {
406
        return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
407
    },
408
topState:function () {
409
        return this.conditionStack[this.conditionStack.length-2];
410
    },
411
pushState:function begin(condition) {
412
        this.begin(condition);
413
    }});
414
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
415
416
var YYSTATE=YY_START;
417
switch($avoiding_name_collisions) {
418
case 0:
419
                                   if(yy_.yytext.slice(-1) !== "\\") this.begin("mu");
0 ignored issues
show
{ was expected, but instead this was given.
Loading history...
420
                                   if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu");
0 ignored issues
show
{ was expected, but instead yy_ was given.
Loading history...
Unexpected use of a comma operator.
Loading history...
Did you forget to assign or call a function?

This error message can for example pop up if you forget to assign the result of a function call to a variable or pass it to another function:

function someFunction(x) {
    (x > 0) ? callFoo() : callBar();
}

// JSHint expects you to assign the result to a variable:
function someFunction(x) {
    var rs = (x > 0) ? callFoo() : callBar();
}

// If you do not use the result, you could also use if statements in the
// case above.
function someFunction(x) {
    if (x > 0) {
        callFoo();
    } else {
        callBar();
    }
}
Loading history...
421
                                   if(yy_.yytext) return 14;
0 ignored issues
show
{ was expected, but instead return was given.
Loading history...
422
423
break;
424
case 1: return 14;
425
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
426
case 2: this.popState(); return 14;
427
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
428
case 3: return 24;
429
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
430
case 4: return 16;
431
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
432
case 5: return 20;
433
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
434
case 6: return 19;
435
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
436
case 7: return 19;
437
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
438
case 8: return 23;
439
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
440
case 9: return 23;
441
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
442
case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
443
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
444
case 11: return 22;
445
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
446
case 12: return 34;
447
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
448
case 13: return 33;
449
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
450
case 14: return 33;
451
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
452
case 15: return 36;
453
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
454
case 16: /*ignore whitespace*/
455
break;
456
case 17: this.popState(); return 18;
457
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
458
case 18: this.popState(); return 18;
459
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
460
case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 28;
461
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
462
case 20: return 30;
463
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
464
case 21: return 30;
465
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
466
case 22: return 29;
467
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
468
case 23: return 33;
469
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
470
case 24: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 33;
471
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
472
case 25: return 'INVALID';
473
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
474
case 26: return 5;
475
break;
0 ignored issues
show
The code break after return is not reachable.
Loading history...
476
}
477
};
478
lexer.rules = [/^[^\x00]*?(?=(\{\{))/,/^[^\x00]+/,/^[^\x00]{2,}?(?=(\{\{))/,/^\{\{>/,/^\{\{#/,/^\{\{\//,/^\{\{\^/,/^\{\{\s*else\b/,/^\{\{\{/,/^\{\{&/,/^\{\{![\s\S]*?\}\}/,/^\{\{/,/^=/,/^\.(?=[} ])/,/^\.\./,/^[\/.]/,/^\s+/,/^\}\}\}/,/^\}\}/,/^"(\\["]|[^"])*"/,/^true(?=[}\s])/,/^false(?=[}\s])/,/^[0-9]+(?=[}\s])/,/^[a-zA-Z0-9_$-]+(?=[=}\s\/.])/,/^\[[^\]]*\]/,/^./,/^$/];
479
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],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,26],"inclusive":true}};return lexer;})();
480
parser.lexer = lexer;
481
return parser;
482
})();
483
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
484
exports.parser = handlebars;
485
exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); };
486
exports.main = function commonjsMain(args) {
487
    if (!args[1])
488
        throw new Error('Usage: '+args[0]+' FILE');
0 ignored issues
show
{ was expected, but instead throw was given.
Loading history...
489
    if (typeof process !== 'undefined') {
490
        var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8");
491
    } else {
492
        var cwd = require("file").path(require("file").cwd());
493
        var source = cwd.join(args[1]).read({charset: "utf-8"});
0 ignored issues
show
It seems like source was already defined.
Loading history...
494
    }
495
    return exports.parser.parse(source);
0 ignored issues
show
The variable source seems to be used out of scope.

This error can usually be fixed by declaring the variable in the scope where it is used:

function someFunction() {
    (function() {
        var i = 0;
    })();

    // i is not defined.
    alert(i);
}

// This can be fixed by moving the var statement to the outer scope.

function someFunction() {
    var i;
    (function() {
        i = 1;
    })();

    alert(i);
};
Loading history...
496
};
497
if (typeof module !== 'undefined' && require.main === module) {
498
  exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
499
}
500
};
0 ignored issues
show
This semicolons seems to be unnecessary.
Loading history...
There were too many errors found in this file; checking aborted after 32%.

If JSHint finds too many errors in a file, it aborts checking altogether because it suspects a configuration issue.

Further Reading:

Loading history...
501
;
502
// lib/handlebars/compiler/base.js
503
Handlebars.Parser = handlebars;
504
505
Handlebars.parse = function(string) {
506
  Handlebars.Parser.yy = Handlebars.AST;
507
  return Handlebars.Parser.parse(string);
508
};
509
510
Handlebars.print = function(ast) {
511
  return new Handlebars.PrintVisitor().accept(ast);
512
};
513
514
Handlebars.logger = {
515
  DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
516
517
  // override in the host environment
518
  log: function(level, str) {}
519
};
520
521
Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
522
;
523
// lib/handlebars/compiler/ast.js
524
(function() {
525
526
  Handlebars.AST = {};
527
528
  Handlebars.AST.ProgramNode = function(statements, inverse) {
529
    this.type = "program";
530
    this.statements = statements;
531
    if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
532
  };
533
534
  Handlebars.AST.MustacheNode = function(params, hash, unescaped) {
535
    this.type = "mustache";
536
    this.id = params[0];
537
    this.params = params.slice(1);
538
    this.hash = hash;
539
    this.escaped = !unescaped;
540
  };
541
542
  Handlebars.AST.PartialNode = function(id, context) {
543
    this.type    = "partial";
544
545
    // TODO: disallow complex IDs
546
547
    this.id      = id;
548
    this.context = context;
549
  };
550
551
  var verifyMatch = function(open, close) {
552
    if(open.original !== close.original) {
553
      throw new Handlebars.Exception(open.original + " doesn't match " + close.original);
554
    }
555
  };
556
557
  Handlebars.AST.BlockNode = function(mustache, program, close) {
558
    verifyMatch(mustache.id, close);
559
    this.type = "block";
560
    this.mustache = mustache;
561
    this.program  = program;
562
  };
563
564
  Handlebars.AST.InverseNode = function(mustache, program, close) {
565
    verifyMatch(mustache.id, close);
566
    this.type = "inverse";
567
    this.mustache = mustache;
568
    this.program  = program;
569
  };
570
571
  Handlebars.AST.ContentNode = function(string) {
572
    this.type = "content";
573
    this.string = string;
574
  };
575
576
  Handlebars.AST.HashNode = function(pairs) {
577
    this.type = "hash";
578
    this.pairs = pairs;
579
  };
580
581
  Handlebars.AST.IdNode = function(parts) {
582
    this.type = "ID";
583
    this.original = parts.join(".");
584
585
    var dig = [], depth = 0;
586
587
    for(var i=0,l=parts.length; i<l; i++) {
588
      var part = parts[i];
589
590
      if(part === "..") { depth++; }
591
      else if(part === "." || part === "this") { this.isScoped = true; }
592
      else { dig.push(part); }
593
    }
594
595
    this.parts    = dig;
596
    this.string   = dig.join('.');
597
    this.depth    = depth;
598
    this.isSimple = (dig.length === 1) && (depth === 0);
599
  };
600
601
  Handlebars.AST.StringNode = function(string) {
602
    this.type = "STRING";
603
    this.string = string;
604
  };
605
606
  Handlebars.AST.IntegerNode = function(integer) {
607
    this.type = "INTEGER";
608
    this.integer = integer;
609
  };
610
611
  Handlebars.AST.BooleanNode = function(bool) {
612
    this.type = "BOOLEAN";
613
    this.bool = bool;
614
  };
615
616
  Handlebars.AST.CommentNode = function(comment) {
617
    this.type = "comment";
618
    this.comment = comment;
619
  };
620
621
})();;
622
// lib/handlebars/utils.js
623
Handlebars.Exception = function(message) {
624
  var tmp = Error.prototype.constructor.apply(this, arguments);
625
626
  for (var p in tmp) {
627
    if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; }
628
  }
629
630
  this.message = tmp.message;
631
};
632
Handlebars.Exception.prototype = new Error;
633
634
// Build out our basic SafeString type
635
Handlebars.SafeString = function(string) {
636
  this.string = string;
637
};
638
Handlebars.SafeString.prototype.toString = function() {
639
  return this.string.toString();
640
};
641
642
(function() {
643
  var escape = {
644
    "<": "&lt;",
645
    ">": "&gt;",
646
    '"': "&quot;",
647
    "'": "&#x27;",
648
    "`": "&#x60;"
649
  };
650
651
  var badChars = /&(?!\w+;)|[<>"'`]/g;
652
  var possible = /[&<>"'`]/;
653
654
  var escapeChar = function(chr) {
655
    return escape[chr] || "&amp;";
656
  };
657
658
  Handlebars.Utils = {
659
    escapeExpression: function(string) {
660
      // don't escape SafeStrings, since they're already safe
661
      if (string instanceof Handlebars.SafeString) {
662
        return string.toString();
663
      } else if (string == null || string === false) {
664
        return "";
665
      }
666
667
      if(!possible.test(string)) { return string; }
668
      return string.replace(badChars, escapeChar);
669
    },
670
671
    isEmpty: function(value) {
672
      if (typeof value === "undefined") {
673
        return true;
674
      } else if (value === null) {
675
        return true;
676
      } else if (value === false) {
677
        return true;
678
      } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
679
        return true;
680
      } else {
681
        return false;
682
      }
683
    }
684
  };
685
})();;
686
// lib/handlebars/compiler/compiler.js
687
Handlebars.Compiler = function() {};
688
Handlebars.JavaScriptCompiler = function() {};
689
690
(function(Compiler, JavaScriptCompiler) {
691
  Compiler.OPCODE_MAP = {
692
    appendContent: 1,
693
    getContext: 2,
694
    lookupWithHelpers: 3,
695
    lookup: 4,
696
    append: 5,
697
    invokeMustache: 6,
698
    appendEscaped: 7,
699
    pushString: 8,
700
    truthyOrFallback: 9,
701
    functionOrFallback: 10,
702
    invokeProgram: 11,
703
    invokePartial: 12,
704
    push: 13,
705
    assignToHash: 15,
706
    pushStringParam: 16
707
  };
708
709
  Compiler.MULTI_PARAM_OPCODES = {
710
    appendContent: 1,
711
    getContext: 1,
712
    lookupWithHelpers: 2,
713
    lookup: 1,
714
    invokeMustache: 3,
715
    pushString: 1,
716
    truthyOrFallback: 1,
717
    functionOrFallback: 1,
718
    invokeProgram: 3,
719
    invokePartial: 1,
720
    push: 1,
721
    assignToHash: 1,
722
    pushStringParam: 1
723
  };
724
725
  Compiler.DISASSEMBLE_MAP = {};
726
727
  for(var prop in Compiler.OPCODE_MAP) {
728
    var value = Compiler.OPCODE_MAP[prop];
729
    Compiler.DISASSEMBLE_MAP[value] = prop;
730
  }
731
732
  Compiler.multiParamSize = function(code) {
733
    return Compiler.MULTI_PARAM_OPCODES[Compiler.DISASSEMBLE_MAP[code]];
734
  };
735
736
  Compiler.prototype = {
737
    compiler: Compiler,
738
739
    disassemble: function() {
740
      var opcodes = this.opcodes, opcode, nextCode;
741
      var out = [], str, name, value;
742
743
      for(var i=0, l=opcodes.length; i<l; i++) {
744
        opcode = opcodes[i];
745
746
        if(opcode === 'DECLARE') {
747
          name = opcodes[++i];
748
          value = opcodes[++i];
749
          out.push("DECLARE " + name + " = " + value);
750
        } else {
751
          str = Compiler.DISASSEMBLE_MAP[opcode];
752
753
          var extraParams = Compiler.multiParamSize(opcode);
754
          var codes = [];
755
756
          for(var j=0; j<extraParams; j++) {
757
            nextCode = opcodes[++i];
758
759
            if(typeof nextCode === "string") {
760
              nextCode = "\"" + nextCode.replace("\n", "\\n") + "\"";
761
            }
762
763
            codes.push(nextCode);
764
          }
765
766
          str = str + " " + codes.join(" ");
767
768
          out.push(str);
769
        }
770
      }
771
772
      return out.join("\n");
773
    },
774
775
    guid: 0,
776
777
    compile: function(program, options) {
778
      this.children = [];
779
      this.depths = {list: []};
780
      this.options = options;
781
782
      // These changes will propagate to the other compiler components
783
      var knownHelpers = this.options.knownHelpers;
784
      this.options.knownHelpers = {
785
        'helperMissing': true,
786
        'blockHelperMissing': true,
787
        'each': true,
788
        'if': true,
789
        'unless': true,
790
        'with': true,
791
        'log': true
792
      };
793
      if (knownHelpers) {
794
        for (var name in knownHelpers) {
795
          this.options.knownHelpers[name] = knownHelpers[name];
796
        }
797
      }
798
799
      return this.program(program);
800
    },
801
802
    accept: function(node) {
803
      return this[node.type](node);
804
    },
805
806
    program: function(program) {
807
      var statements = program.statements, statement;
808
      this.opcodes = [];
809
810
      for(var i=0, l=statements.length; i<l; i++) {
811
        statement = statements[i];
812
        this[statement.type](statement);
813
      }
814
      this.isSimple = l === 1;
815
816
      this.depths.list = this.depths.list.sort(function(a, b) {
817
        return a - b;
818
      });
819
820
      return this;
821
    },
822
823
    compileProgram: function(program) {
824
      var result = new this.compiler().compile(program, this.options);
825
      var guid = this.guid++;
826
827
      this.usePartial = this.usePartial || result.usePartial;
828
829
      this.children[guid] = result;
830
831
      for(var i=0, l=result.depths.list.length; i<l; i++) {
832
        depth = result.depths.list[i];
833
834
        if(depth < 2) { continue; }
835
        else { this.addDepth(depth - 1); }
836
      }
837
838
      return guid;
839
    },
840
841
    block: function(block) {
842
      var mustache = block.mustache;
843
      var depth, child, inverse, inverseGuid;
844
845
      var params = this.setupStackForMustache(mustache);
846
847
      var programGuid = this.compileProgram(block.program);
848
849
      if(block.program.inverse) {
850
        inverseGuid = this.compileProgram(block.program.inverse);
851
        this.declare('inverse', inverseGuid);
852
      }
853
854
      this.opcode('invokeProgram', programGuid, params.length, !!mustache.hash);
855
      this.declare('inverse', null);
856
      this.opcode('append');
857
    },
858
859
    inverse: function(block) {
860
      var params = this.setupStackForMustache(block.mustache);
861
862
      var programGuid = this.compileProgram(block.program);
863
864
      this.declare('inverse', programGuid);
865
866
      this.opcode('invokeProgram', null, params.length, !!block.mustache.hash);
867
      this.declare('inverse', null);
868
      this.opcode('append');
869
    },
870
871
    hash: function(hash) {
872
      var pairs = hash.pairs, pair, val;
873
874
      this.opcode('push', '{}');
875
876
      for(var i=0, l=pairs.length; i<l; i++) {
877
        pair = pairs[i];
878
        val  = pair[1];
879
880
        this.accept(val);
881
        this.opcode('assignToHash', pair[0]);
882
      }
883
    },
884
885
    partial: function(partial) {
886
      var id = partial.id;
887
      this.usePartial = true;
888
889
      if(partial.context) {
890
        this.ID(partial.context);
891
      } else {
892
        this.opcode('push', 'depth0');
893
      }
894
895
      this.opcode('invokePartial', id.original);
896
      this.opcode('append');
897
    },
898
899
    content: function(content) {
900
      this.opcode('appendContent', content.string);
901
    },
902
903
    mustache: function(mustache) {
904
      var params = this.setupStackForMustache(mustache);
905
906
      this.opcode('invokeMustache', params.length, mustache.id.original, !!mustache.hash);
907
908
      if(mustache.escaped && !this.options.noEscape) {
909
        this.opcode('appendEscaped');
910
      } else {
911
        this.opcode('append');
912
      }
913
    },
914
915
    ID: function(id) {
916
      this.addDepth(id.depth);
917
918
      this.opcode('getContext', id.depth);
919
920
      this.opcode('lookupWithHelpers', id.parts[0] || null, id.isScoped || false);
921
922
      for(var i=1, l=id.parts.length; i<l; i++) {
923
        this.opcode('lookup', id.parts[i]);
924
      }
925
    },
926
927
    STRING: function(string) {
928
      this.opcode('pushString', string.string);
929
    },
930
931
    INTEGER: function(integer) {
932
      this.opcode('push', integer.integer);
933
    },
934
935
    BOOLEAN: function(bool) {
936
      this.opcode('push', bool.bool);
937
    },
938
939
    comment: function() {},
940
941
    // HELPERS
942
    pushParams: function(params) {
943
      var i = params.length, param;
944
945
      while(i--) {
946
        param = params[i];
947
948
        if(this.options.stringParams) {
949
          if(param.depth) {
950
            this.addDepth(param.depth);
951
          }
952
953
          this.opcode('getContext', param.depth || 0);
954
          this.opcode('pushStringParam', param.string);
955
        } else {
956
          this[param.type](param);
957
        }
958
      }
959
    },
960
961
    opcode: function(name, val1, val2, val3) {
962
      this.opcodes.push(Compiler.OPCODE_MAP[name]);
963
      if(val1 !== undefined) { this.opcodes.push(val1); }
964
      if(val2 !== undefined) { this.opcodes.push(val2); }
965
      if(val3 !== undefined) { this.opcodes.push(val3); }
966
    },
967
968
    declare: function(name, value) {
969
      this.opcodes.push('DECLARE');
970
      this.opcodes.push(name);
971
      this.opcodes.push(value);
972
    },
973
974
    addDepth: function(depth) {
975
      if(depth === 0) { return; }
976
977
      if(!this.depths[depth]) {
978
        this.depths[depth] = true;
979
        this.depths.list.push(depth);
980
      }
981
    },
982
983
    setupStackForMustache: function(mustache) {
984
      var params = mustache.params;
985
986
      this.pushParams(params);
987
988
      if(mustache.hash) {
989
        this.hash(mustache.hash);
990
      }
991
992
      this.ID(mustache.id);
993
994
      return params;
995
    }
996
  };
997
998
  JavaScriptCompiler.prototype = {
999
    // PUBLIC API: You can override these methods in a subclass to provide
1000
    // alternative compiled forms for name lookup and buffering semantics
1001
    nameLookup: function(parent, name, type) {
1002
			if (/^[0-9]+$/.test(name)) {
1003
        return parent + "[" + name + "]";
1004
      } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1005
	    	return parent + "." + name;
1006
			}
1007
			else {
1008
				return parent + "['" + name + "']";
1009
      }
1010
    },
1011
1012
    appendToBuffer: function(string) {
1013
      if (this.environment.isSimple) {
1014
        return "return " + string + ";";
1015
      } else {
1016
        return "buffer += " + string + ";";
1017
      }
1018
    },
1019
1020
    initializeBuffer: function() {
1021
      return this.quotedString("");
1022
    },
1023
1024
    namespace: "Handlebars",
1025
    // END PUBLIC API
1026
1027
    compile: function(environment, options, context, asObject) {
1028
      this.environment = environment;
1029
      this.options = options || {};
1030
1031
      this.name = this.environment.name;
1032
      this.isChild = !!context;
1033
      this.context = context || {
1034
        programs: [],
1035
        aliases: { self: 'this' },
1036
        registers: {list: []}
1037
      };
1038
1039
      this.preamble();
1040
1041
      this.stackSlot = 0;
1042
      this.stackVars = [];
1043
1044
      this.compileChildren(environment, options);
1045
1046
      var opcodes = environment.opcodes, opcode;
1047
1048
      this.i = 0;
1049
1050
      for(l=opcodes.length; this.i<l; this.i++) {
1051
        opcode = this.nextOpcode(0);
1052
1053
        if(opcode[0] === 'DECLARE') {
1054
          this.i = this.i + 2;
1055
          this[opcode[1]] = opcode[2];
1056
        } else {
1057
          this.i = this.i + opcode[1].length;
1058
          this[opcode[0]].apply(this, opcode[1]);
1059
        }
1060
      }
1061
1062
      return this.createFunctionContext(asObject);
1063
    },
1064
1065
    nextOpcode: function(n) {
1066
      var opcodes = this.environment.opcodes, opcode = opcodes[this.i + n], name, val;
1067
      var extraParams, codes;
1068
1069
      if(opcode === 'DECLARE') {
1070
        name = opcodes[this.i + 1];
1071
        val  = opcodes[this.i + 2];
1072
        return ['DECLARE', name, val];
1073
      } else {
1074
        name = Compiler.DISASSEMBLE_MAP[opcode];
1075
1076
        extraParams = Compiler.multiParamSize(opcode);
1077
        codes = [];
1078
1079
        for(var j=0; j<extraParams; j++) {
1080
          codes.push(opcodes[this.i + j + 1 + n]);
1081
        }
1082
1083
        return [name, codes];
1084
      }
1085
    },
1086
1087
    eat: function(opcode) {
1088
      this.i = this.i + opcode.length;
1089
    },
1090
1091
    preamble: function() {
1092
      var out = [];
1093
1094
      // this register will disambiguate helper lookup from finding a function in
1095
      // a context. This is necessary for mustache compatibility, which requires
1096
      // that context functions in blocks are evaluated by blockHelperMissing, and
1097
      // then proceed as if the resulting value was provided to blockHelperMissing.
1098
      this.useRegister('foundHelper');
1099
1100
      if (!this.isChild) {
1101
        var namespace = this.namespace;
1102
        var copies = "helpers = helpers || " + namespace + ".helpers;";
1103
        if(this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
1104
        out.push(copies);
1105
      } else {
1106
        out.push('');
1107
      }
1108
1109
      if (!this.environment.isSimple) {
1110
        out.push(", buffer = " + this.initializeBuffer());
1111
      } else {
1112
        out.push("");
1113
      }
1114
1115
      // track the last context pushed into place to allow skipping the
1116
      // getContext opcode when it would be a noop
1117
      this.lastContext = 0;
1118
      this.source = out;
1119
    },
1120
1121
    createFunctionContext: function(asObject) {
1122
      var locals = this.stackVars;
1123
      if (!this.isChild) {
1124
        locals = locals.concat(this.context.registers.list);
1125
      }
1126
1127
      if(locals.length > 0) {
1128
        this.source[1] = this.source[1] + ", " + locals.join(", ");
1129
      }
1130
1131
      // Generate minimizer alias mappings
1132
      if (!this.isChild) {
1133
        var aliases = [];
1134
        for (var alias in this.context.aliases) {
1135
          this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1136
        }
1137
      }
1138
1139
      if (this.source[1]) {
1140
        this.source[1] = "var " + this.source[1].substring(2) + ";";
1141
      }
1142
1143
      // Merge children
1144
      if (!this.isChild) {
1145
        this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1146
      }
1147
1148
      if (!this.environment.isSimple) {
1149
        this.source.push("return buffer;");
1150
      }
1151
1152
      var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1153
1154
      for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1155
        params.push("depth" + this.environment.depths.list[i]);
1156
      }
1157
1158
      if (asObject) {
1159
        params.push(this.source.join("\n  "));
1160
1161
        return Function.apply(this, params);
1162
      } else {
1163
        var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n  ' + this.source.join("\n  ") + '}';
1164
        Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1165
        return functionSource;
1166
      }
1167
    },
1168
1169
    appendContent: function(content) {
1170
      this.source.push(this.appendToBuffer(this.quotedString(content)));
1171
    },
1172
1173
    append: function() {
1174
      var local = this.popStack();
1175
      this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1176
      if (this.environment.isSimple) {
1177
        this.source.push("else { " + this.appendToBuffer("''") + " }");
1178
      }
1179
    },
1180
1181
    appendEscaped: function() {
1182
      var opcode = this.nextOpcode(1), extra = "";
1183
      this.context.aliases.escapeExpression = 'this.escapeExpression';
1184
1185
      if(opcode[0] === 'appendContent') {
1186
        extra = " + " + this.quotedString(opcode[1][0]);
1187
        this.eat(opcode);
1188
      }
1189
1190
      this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra));
1191
    },
1192
1193
    getContext: function(depth) {
1194
      if(this.lastContext !== depth) {
1195
        this.lastContext = depth;
1196
      }
1197
    },
1198
1199
    lookupWithHelpers: function(name, isScoped) {
1200
      if(name) {
1201
        var topStack = this.nextStack();
1202
1203
        this.usingKnownHelper = false;
1204
1205
        var toPush;
1206
        if (!isScoped && this.options.knownHelpers[name]) {
1207
          toPush = topStack + " = " + this.nameLookup('helpers', name, 'helper');
1208
          this.usingKnownHelper = true;
1209
        } else if (isScoped || this.options.knownHelpersOnly) {
1210
          toPush = topStack + " = " + this.nameLookup('depth' + this.lastContext, name, 'context');
1211
        } else {
1212
          this.register('foundHelper', this.nameLookup('helpers', name, 'helper'));
1213
          toPush = topStack + " = foundHelper || " + this.nameLookup('depth' + this.lastContext, name, 'context');
1214
        }
1215
1216
        toPush += ';';
1217
        this.source.push(toPush);
1218
      } else {
1219
        this.pushStack('depth' + this.lastContext);
1220
      }
1221
    },
1222
1223
    lookup: function(name) {
1224
      var topStack = this.topStack();
1225
      this.source.push(topStack + " = (" + topStack + " === null || " + topStack + " === undefined || " + topStack + " === false ? " +
1226
 				topStack + " : " + this.nameLookup(topStack, name, 'context') + ");");
1227
    },
1228
1229
    pushStringParam: function(string) {
1230
      this.pushStack('depth' + this.lastContext);
1231
      this.pushString(string);
1232
    },
1233
1234
    pushString: function(string) {
1235
      this.pushStack(this.quotedString(string));
1236
    },
1237
1238
    push: function(name) {
1239
      this.pushStack(name);
1240
    },
1241
1242
    invokeMustache: function(paramSize, original, hasHash) {
1243
      this.populateParams(paramSize, this.quotedString(original), "{}", null, hasHash, function(nextStack, helperMissingString, id) {
1244
        if (!this.usingKnownHelper) {
1245
          this.context.aliases.helperMissing = 'helpers.helperMissing';
1246
          this.context.aliases.undef = 'void 0';
1247
          this.source.push("else if(" + id + "=== undef) { " + nextStack + " = helperMissing.call(" + helperMissingString + "); }");
1248
          if (nextStack !== id) {
1249
            this.source.push("else { " + nextStack + " = " + id + "; }");
1250
          }
1251
        }
1252
      });
1253
    },
1254
1255
    invokeProgram: function(guid, paramSize, hasHash) {
1256
      var inverse = this.programExpression(this.inverse);
1257
      var mainProgram = this.programExpression(guid);
1258
1259
      this.populateParams(paramSize, null, mainProgram, inverse, hasHash, function(nextStack, helperMissingString, id) {
1260
        if (!this.usingKnownHelper) {
1261
          this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1262
          this.source.push("else { " + nextStack + " = blockHelperMissing.call(" + helperMissingString + "); }");
1263
        }
1264
      });
1265
    },
1266
1267
    populateParams: function(paramSize, helperId, program, inverse, hasHash, fn) {
1268
      var needsRegister = hasHash || this.options.stringParams || inverse || this.options.data;
1269
      var id = this.popStack(), nextStack;
1270
      var params = [], param, stringParam, stringOptions;
1271
1272
      if (needsRegister) {
1273
        this.register('tmp1', program);
1274
        stringOptions = 'tmp1';
1275
      } else {
1276
        stringOptions = '{ hash: {} }';
1277
      }
1278
1279
      if (needsRegister) {
1280
        var hash = (hasHash ? this.popStack() : '{}');
1281
        this.source.push('tmp1.hash = ' + hash + ';');
1282
      }
1283
1284
      if(this.options.stringParams) {
1285
        this.source.push('tmp1.contexts = [];');
1286
      }
1287
1288
      for(var i=0; i<paramSize; i++) {
1289
        param = this.popStack();
1290
        params.push(param);
1291
1292
        if(this.options.stringParams) {
1293
          this.source.push('tmp1.contexts.push(' + this.popStack() + ');');
1294
        }
1295
      }
1296
1297
      if(inverse) {
1298
        this.source.push('tmp1.fn = tmp1;');
1299
        this.source.push('tmp1.inverse = ' + inverse + ';');
1300
      }
1301
1302
      if(this.options.data) {
1303
        this.source.push('tmp1.data = data;');
1304
      }
1305
1306
      params.push(stringOptions);
1307
1308
      this.populateCall(params, id, helperId || id, fn, program !== '{}');
1309
    },
1310
1311
    populateCall: function(params, id, helperId, fn, program) {
1312
      var paramString = ["depth0"].concat(params).join(", ");
1313
      var helperMissingString = ["depth0"].concat(helperId).concat(params).join(", ");
1314
1315
      var nextStack = this.nextStack();
1316
1317
      if (this.usingKnownHelper) {
1318
        this.source.push(nextStack + " = " + id + ".call(" + paramString + ");");
1319
      } else {
1320
        this.context.aliases.functionType = '"function"';
1321
        var condition = program ? "foundHelper && " : "";
1322
        this.source.push("if(" + condition + "typeof " + id + " === functionType) { " + nextStack + " = " + id + ".call(" + paramString + "); }");
1323
      }
1324
      fn.call(this, nextStack, helperMissingString, id);
1325
      this.usingKnownHelper = false;
1326
    },
1327
1328
    invokePartial: function(context) {
1329
      params = [this.nameLookup('partials', context, 'partial'), "'" + context + "'", this.popStack(), "helpers", "partials"];
1330
1331
      if (this.options.data) {
1332
        params.push("data");
1333
      }
1334
1335
      this.pushStack("self.invokePartial(" + params.join(", ") + ");");
1336
    },
1337
1338
    assignToHash: function(key) {
1339
      var value = this.popStack();
1340
      var hash = this.topStack();
1341
1342
      this.source.push(hash + "['" + key + "'] = " + value + ";");
1343
    },
1344
1345
    // HELPERS
1346
1347
    compiler: JavaScriptCompiler,
1348
1349
    compileChildren: function(environment, options) {
1350
      var children = environment.children, child, compiler;
1351
1352
      for(var i=0, l=children.length; i<l; i++) {
1353
        child = children[i];
1354
        compiler = new this.compiler();
1355
1356
        this.context.programs.push('');     // Placeholder to prevent name conflicts for nested children
1357
        var index = this.context.programs.length;
1358
        child.index = index;
1359
        child.name = 'program' + index;
1360
        this.context.programs[index] = compiler.compile(child, options, this.context);
1361
      }
1362
    },
1363
1364
    programExpression: function(guid) {
1365
      if(guid == null) { return "self.noop"; }
1366
1367
      var child = this.environment.children[guid],
1368
          depths = child.depths.list;
1369
      var programParams = [child.index, child.name, "data"];
1370
1371
      for(var i=0, l = depths.length; i<l; i++) {
1372
        depth = depths[i];
1373
1374
        if(depth === 1) { programParams.push("depth0"); }
1375
        else { programParams.push("depth" + (depth - 1)); }
1376
      }
1377
1378
      if(depths.length === 0) {
1379
        return "self.program(" + programParams.join(", ") + ")";
1380
      } else {
1381
        programParams.shift();
1382
        return "self.programWithDepth(" + programParams.join(", ") + ")";
1383
      }
1384
    },
1385
1386
    register: function(name, val) {
1387
      this.useRegister(name);
1388
      this.source.push(name + " = " + val + ";");
1389
    },
1390
1391
    useRegister: function(name) {
1392
      if(!this.context.registers[name]) {
1393
        this.context.registers[name] = true;
1394
        this.context.registers.list.push(name);
1395
      }
1396
    },
1397
1398
    pushStack: function(item) {
1399
      this.source.push(this.nextStack() + " = " + item + ";");
1400
      return "stack" + this.stackSlot;
1401
    },
1402
1403
    nextStack: function() {
1404
      this.stackSlot++;
1405
      if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1406
      return "stack" + this.stackSlot;
1407
    },
1408
1409
    popStack: function() {
1410
      return "stack" + this.stackSlot--;
1411
    },
1412
1413
    topStack: function() {
1414
      return "stack" + this.stackSlot;
1415
    },
1416
1417
    quotedString: function(str) {
1418
      return '"' + str
1419
        .replace(/\\/g, '\\\\')
1420
        .replace(/"/g, '\\"')
1421
        .replace(/\n/g, '\\n')
1422
        .replace(/\r/g, '\\r') + '"';
1423
    }
1424
  };
1425
1426
  var reservedWords = (
1427
    "break else new var" +
1428
    " case finally return void" +
1429
    " catch for switch while" +
1430
    " continue function this with" +
1431
    " default if throw" +
1432
    " delete in try" +
1433
    " do instanceof typeof" +
1434
    " abstract enum int short" +
1435
    " boolean export interface static" +
1436
    " byte extends long super" +
1437
    " char final native synchronized" +
1438
    " class float package throws" +
1439
    " const goto private transient" +
1440
    " debugger implements protected volatile" +
1441
    " double import public let yield"
1442
  ).split(" ");
1443
1444
  var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
1445
1446
  for(var i=0, l=reservedWords.length; i<l; i++) {
1447
    compilerWords[reservedWords[i]] = true;
1448
  }
1449
1450
	JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
1451
		if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
1452
			return true;
1453
		}
1454
		return false;
1455
	}
1456
1457
})(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
1458
1459
Handlebars.precompile = function(string, options) {
1460
  options = options || {};
1461
1462
  var ast = Handlebars.parse(string);
1463
  var environment = new Handlebars.Compiler().compile(ast, options);
1464
  return new Handlebars.JavaScriptCompiler().compile(environment, options);
1465
};
1466
1467
Handlebars.compile = function(string, options) {
1468
  options = options || {};
1469
1470
  var compiled;
1471
  function compile() {
1472
    var ast = Handlebars.parse(string);
1473
    var environment = new Handlebars.Compiler().compile(ast, options);
1474
    var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
1475
    return Handlebars.template(templateSpec);
1476
  }
1477
1478
  // Template is only compiled on first use and cached after that point.
1479
  return function(context, options) {
1480
    if (!compiled) {
1481
      compiled = compile();
1482
    }
1483
    return compiled.call(this, context, options);
1484
  };
1485
};
1486
;
1487
// lib/handlebars/runtime.js
1488
Handlebars.VM = {
1489
  template: function(templateSpec) {
1490
    // Just add water
1491
    var container = {
1492
      escapeExpression: Handlebars.Utils.escapeExpression,
1493
      invokePartial: Handlebars.VM.invokePartial,
1494
      programs: [],
1495
      program: function(i, fn, data) {
1496
        var programWrapper = this.programs[i];
1497
        if(data) {
1498
          return Handlebars.VM.program(fn, data);
1499
        } else if(programWrapper) {
1500
          return programWrapper;
1501
        } else {
1502
          programWrapper = this.programs[i] = Handlebars.VM.program(fn);
1503
          return programWrapper;
1504
        }
1505
      },
1506
      programWithDepth: Handlebars.VM.programWithDepth,
1507
      noop: Handlebars.VM.noop
1508
    };
1509
1510
    return function(context, options) {
1511
      options = options || {};
1512
      return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
1513
    };
1514
  },
1515
1516
  programWithDepth: function(fn, data, $depth) {
1517
    var args = Array.prototype.slice.call(arguments, 2);
1518
1519
    return function(context, options) {
1520
      options = options || {};
1521
1522
      return fn.apply(this, [context, options.data || data].concat(args));
1523
    };
1524
  },
1525
  program: function(fn, data) {
1526
    return function(context, options) {
1527
      options = options || {};
1528
1529
      return fn(context, options.data || data);
1530
    };
1531
  },
1532
  noop: function() { return ""; },
1533
  invokePartial: function(partial, name, context, helpers, partials, data) {
1534
    options = { helpers: helpers, partials: partials, data: data };
1535
1536
    if(partial === undefined) {
1537
      throw new Handlebars.Exception("The partial " + name + " could not be found");
1538
    } else if(partial instanceof Function) {
1539
      return partial(context, options);
1540
    } else if (!Handlebars.compile) {
1541
      throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
1542
    } else {
1543
      partials[name] = Handlebars.compile(partial);
1544
      return partials[name](context, options);
1545
    }
1546
  }
1547
};
1548
1549
Handlebars.template = Handlebars.VM.template;
1550
;
1551