sinatra-handlebars 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ .*.swp
@@ -0,0 +1,45 @@
1
+ # Sinatra Handlebars
2
+
3
+ Helpers for serving Handlebars.js templates in [Sinatra][sinatra].
4
+
5
+ - Pre-compile handlebars templates from separate view files rather than littering them throughout your html.
6
+
7
+
8
+ ## Installation
9
+ ### Bundler users
10
+
11
+ If you use Bundler, add it to your *Gemfile.*
12
+
13
+ ``` ruby
14
+ gem 'sinatra-handlebars', git: 'http://github.com/benkitzelman/sinatra-handlebars'
15
+ ```
16
+
17
+
18
+ ## Setup
19
+
20
+ Install the plugin and add some options.
21
+
22
+ ``` ruby
23
+ require 'sinatra/handlebars'
24
+
25
+ class App < Sinatra::Base
26
+ register Sinatra::Handlebars
27
+ handlebars {
28
+ templates '/js/templates.js', ['app/templates/*']
29
+ }
30
+ end
31
+ ```
32
+
33
+
34
+ ## Partials
35
+ Partial template filenames must be prefixed with an '_', and are referenced without the prefix.
36
+ For example, for the partial template file '_MyPartial.hbs', to render in a parent template it would be referenced as {{> MyPartial}}
37
+
38
+
39
+ ## Sinatra AssetPack
40
+ If you're using the [sinatra-assetpack][assetpack] gem, add your served templates to a package.
41
+
42
+
43
+ [assetpack]: https://github.com/rstacruz/sinatra-assetpack
44
+ [ember]: http://emberjs.com
45
+ [sinatra]: http://sinatrarb.com
@@ -0,0 +1,91 @@
1
+ require File.join(File.dirname(__FILE__), 'options')
2
+
3
+ module Sinatra
4
+ module Handlebars
5
+ def self.version
6
+ "0.0.4"
7
+ end
8
+
9
+ def self.registered(app)
10
+ app.extend ClassMethods
11
+ end
12
+
13
+ module ClassMethods
14
+
15
+ # set handlebars options
16
+ def handlebars(&block)
17
+ @handlebars_options ||= Options.new(self, &block)
18
+ handlebars_init! if block_given?
19
+ @handlebars_options
20
+ end
21
+
22
+ def handlebars_init!
23
+ handlebars.template_packages.each do |route, globs|
24
+ get route do
25
+ mtime, output = @template_cache.fetch(route) do
26
+
27
+ paths = globs.map do |glob|
28
+ glob = File.expand_path(glob)
29
+ Dir[glob].map { |x| x.squeeze('/') }
30
+ end.flatten.uniq
31
+
32
+ # compute the maximum mtime for all paths
33
+ mtime = paths.map do |path|
34
+ if File.file?(path)
35
+ File.mtime(path).to_i
36
+ end
37
+ end.compact.max
38
+
39
+ [mtime, self.class.js_content(paths)]
40
+ end
41
+
42
+ content_type :js
43
+ last_modified mtime
44
+ output
45
+ end
46
+ end
47
+ end
48
+
49
+ def vendor_js
50
+ vendor_js_files.inject('') {|memo, path| memo + File.read(path) }
51
+ end
52
+
53
+ def vendor_js_files
54
+ Dir[File.join(File.dirname(__FILE__), '../../', 'vendor', '/*.js')]
55
+ end
56
+
57
+ def js_content(paths)
58
+ @js_content ||= %{
59
+ // Vendor Content
60
+ #{vendor_js}
61
+
62
+ //Templates
63
+ (function() {
64
+ window.HandlebarsTemplates = {};
65
+ #{templates_as_javascript(paths).join("\n")}
66
+ })();
67
+ }.strip.gsub(/^ {16}/, '')
68
+ end
69
+
70
+ def templates_as_javascript(paths)
71
+ template_paths(paths).map do |(name, path)|
72
+ content = File.read(path)
73
+ if name =~ /^_/
74
+ "Handlebars.registerPartial(#{name.sub(/^_/, '').inspect}, #{content.inspect});"
75
+ else
76
+ "window.HandlebarsTemplates[#{name.inspect}] = Handlebars.compile(#{content.inspect});"
77
+ end
78
+ end
79
+ end
80
+
81
+ def template_paths(paths)
82
+ template_paths = {}
83
+ paths.each do |path|
84
+ template_paths[File.basename(path, '.hbs')] = path
85
+ end
86
+ template_paths
87
+ end
88
+
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,18 @@
1
+ module Sinatra
2
+ module Handlebars
3
+ class Options
4
+ attr_reader :template_packages
5
+
6
+ def initialize(app, &block)
7
+ @app = app
8
+ @template_packages = {}
9
+
10
+ instance_eval(&block)
11
+ end
12
+
13
+ def templates(route, files=[])
14
+ @template_packages[route] = files
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require './lib/sinatra/handlebars'
2
+ Gem::Specification.new do |s|
3
+ s.name = 'sinatra-handlebars'
4
+ s.version = Sinatra::Handlebars.version
5
+ s.summary = 'Compile Handlebars templates as Javascript and serve in a Sinatra app'
6
+ s.description = 'Compiles and serves Handlebars template files (.hbs) as javascript from the configured Sinatra route, so they can be included as script from a given web page'
7
+ s.authors = ['Ben Kitzelman']
8
+ s.email = ['benkitzelman@hotmail.com']
9
+ s.homepage = 'http://github.com/benkitzelman/sinatra-handlebars'
10
+ s.files = `git ls-files`.strip.split("\n")
11
+ s.executables = Dir['bin/*'].map { |f| File.basename(f) }
12
+
13
+ s.add_dependency 'sinatra'
14
+ end
@@ -0,0 +1,1549 @@
1
+ var Handlebars = {};
2
+
3
+ Handlebars.VERSION = "1.0.beta.6";
4
+
5
+ Handlebars.helpers = {};
6
+ Handlebars.partials = {};
7
+
8
+ Handlebars.registerHelper = function(name, fn, inverse) {
9
+ if(inverse) { fn.not = inverse; }
10
+ this.helpers[name] = fn;
11
+ };
12
+
13
+ Handlebars.registerPartial = function(name, str) {
14
+ this.partials[name] = str;
15
+ };
16
+
17
+ Handlebars.registerHelper('helperMissing', function(arg) {
18
+ if(arguments.length === 2) {
19
+ return undefined;
20
+ } else {
21
+ throw new Error("Could not find property '" + arg + "'");
22
+ }
23
+ });
24
+
25
+ var toString = Object.prototype.toString, functionType = "[object Function]";
26
+
27
+ Handlebars.registerHelper('blockHelperMissing', function(context, options) {
28
+ var inverse = options.inverse || function() {}, fn = options.fn;
29
+
30
+
31
+ var ret = "";
32
+ var type = toString.call(context);
33
+
34
+ if(type === functionType) { context = context.call(this); }
35
+
36
+ if(context === true) {
37
+ return fn(this);
38
+ } else if(context === false || context == null) {
39
+ return inverse(this);
40
+ } else if(type === "[object Array]") {
41
+ if(context.length > 0) {
42
+ for(var i=0, j=context.length; i<j; i++) {
43
+ ret = ret + fn(context[i]);
44
+ }
45
+ } else {
46
+ ret = inverse(this);
47
+ }
48
+ return ret;
49
+ } else {
50
+ return fn(context);
51
+ }
52
+ });
53
+
54
+ Handlebars.registerHelper('each', function(context, options) {
55
+ var fn = options.fn, inverse = options.inverse;
56
+ var ret = "";
57
+
58
+ if(context && context.length > 0) {
59
+ for(var i=0, j=context.length; i<j; i++) {
60
+ ret = ret + fn(context[i]);
61
+ }
62
+ } else {
63
+ ret = inverse(this);
64
+ }
65
+ return ret;
66
+ });
67
+
68
+ Handlebars.registerHelper('if', function(context, options) {
69
+ var type = toString.call(context);
70
+ if(type === functionType) { context = context.call(this); }
71
+
72
+ if(!context || Handlebars.Utils.isEmpty(context)) {
73
+ return options.inverse(this);
74
+ } else {
75
+ return options.fn(this);
76
+ }
77
+ });
78
+
79
+ Handlebars.registerHelper('unless', function(context, options) {
80
+ var fn = options.fn, inverse = options.inverse;
81
+ options.fn = inverse;
82
+ options.inverse = fn;
83
+
84
+ return Handlebars.helpers['if'].call(this, context, options);
85
+ });
86
+
87
+ Handlebars.registerHelper('with', function(context, options) {
88
+ return options.fn(context);
89
+ });
90
+
91
+ Handlebars.registerHelper('log', function(context) {
92
+ Handlebars.log(context);
93
+ });
94
+ ;
95
+ // lib/handlebars/compiler/parser.js
96
+ /* Jison generated parser */
97
+ var handlebars = (function(){
98
+
99
+ var parser = {trace: function trace() { },
100
+ yy: {},
101
+ 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},
102
+ 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"},
103
+ 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]],
104
+ performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
105
+
106
+ var $0 = $$.length - 1;
107
+ switch (yystate) {
108
+ case 1: return $$[$0-1]
109
+ break;
110
+ case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0])
111
+ break;
112
+ case 3: this.$ = new yy.ProgramNode($$[$0])
113
+ break;
114
+ case 4: this.$ = new yy.ProgramNode([])
115
+ break;
116
+ case 5: this.$ = [$$[$0]]
117
+ break;
118
+ case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]
119
+ break;
120
+ case 7: this.$ = new yy.InverseNode($$[$0-2], $$[$0-1], $$[$0])
121
+ break;
122
+ case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0])
123
+ break;
124
+ case 9: this.$ = $$[$0]
125
+ break;
126
+ case 10: this.$ = $$[$0]
127
+ break;
128
+ case 11: this.$ = new yy.ContentNode($$[$0])
129
+ break;
130
+ case 12: this.$ = new yy.CommentNode($$[$0])
131
+ break;
132
+ case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
133
+ break;
134
+ case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
135
+ break;
136
+ case 15: this.$ = $$[$0-1]
137
+ break;
138
+ case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
139
+ break;
140
+ case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true)
141
+ break;
142
+ case 18: this.$ = new yy.PartialNode($$[$0-1])
143
+ break;
144
+ case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1])
145
+ break;
146
+ case 20:
147
+ break;
148
+ case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]]
149
+ break;
150
+ case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null]
151
+ break;
152
+ case 23: this.$ = [[$$[$0-1]], $$[$0]]
153
+ break;
154
+ case 24: this.$ = [[$$[$0]], null]
155
+ break;
156
+ case 25: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
157
+ break;
158
+ case 26: this.$ = [$$[$0]]
159
+ break;
160
+ case 27: this.$ = $$[$0]
161
+ break;
162
+ case 28: this.$ = new yy.StringNode($$[$0])
163
+ break;
164
+ case 29: this.$ = new yy.IntegerNode($$[$0])
165
+ break;
166
+ case 30: this.$ = new yy.BooleanNode($$[$0])
167
+ break;
168
+ case 31: this.$ = new yy.HashNode($$[$0])
169
+ break;
170
+ case 32: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]
171
+ break;
172
+ case 33: this.$ = [$$[$0]]
173
+ break;
174
+ case 34: this.$ = [$$[$0-2], $$[$0]]
175
+ break;
176
+ case 35: this.$ = [$$[$0-2], new yy.StringNode($$[$0])]
177
+ break;
178
+ case 36: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])]
179
+ break;
180
+ case 37: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])]
181
+ break;
182
+ case 38: this.$ = new yy.IdNode($$[$0])
183
+ break;
184
+ case 39: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
185
+ break;
186
+ case 40: this.$ = [$$[$0]]
187
+ break;
188
+ }
189
+ },
190
+ 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]}],
191
+ defaultActions: {16:[2,1],37:[2,23],53:[2,21]},
192
+ parseError: function parseError(str, hash) {
193
+ throw new Error(str);
194
+ },
195
+ parse: function parse(input) {
196
+ var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
197
+ this.lexer.setInput(input);
198
+ this.lexer.yy = this.yy;
199
+ this.yy.lexer = this.lexer;
200
+ if (typeof this.lexer.yylloc == "undefined")
201
+ this.lexer.yylloc = {};
202
+ var yyloc = this.lexer.yylloc;
203
+ lstack.push(yyloc);
204
+ if (typeof this.yy.parseError === "function")
205
+ this.parseError = this.yy.parseError;
206
+ function popStack(n) {
207
+ stack.length = stack.length - 2 * n;
208
+ vstack.length = vstack.length - n;
209
+ lstack.length = lstack.length - n;
210
+ }
211
+ function lex() {
212
+ var token;
213
+ token = self.lexer.lex() || 1;
214
+ if (typeof token !== "number") {
215
+ token = self.symbols_[token] || token;
216
+ }
217
+ return token;
218
+ }
219
+ var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
220
+ while (true) {
221
+ state = stack[stack.length - 1];
222
+ if (this.defaultActions[state]) {
223
+ action = this.defaultActions[state];
224
+ } else {
225
+ if (symbol == null)
226
+ symbol = lex();
227
+ action = table[state] && table[state][symbol];
228
+ }
229
+ if (typeof action === "undefined" || !action.length || !action[0]) {
230
+ if (!recovering) {
231
+ expected = [];
232
+ for (p in table[state])
233
+ if (this.terminals_[p] && p > 2) {
234
+ expected.push("'" + this.terminals_[p] + "'");
235
+ }
236
+ var errStr = "";
237
+ if (this.lexer.showPosition) {
238
+ errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + this.terminals_[symbol] + "'";
239
+ } else {
240
+ errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'");
241
+ }
242
+ this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
243
+ }
244
+ }
245
+ if (action[0] instanceof Array && action.length > 1) {
246
+ throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
247
+ }
248
+ switch (action[0]) {
249
+ case 1:
250
+ stack.push(symbol);
251
+ vstack.push(this.lexer.yytext);
252
+ lstack.push(this.lexer.yylloc);
253
+ stack.push(action[1]);
254
+ symbol = null;
255
+ if (!preErrorSymbol) {
256
+ yyleng = this.lexer.yyleng;
257
+ yytext = this.lexer.yytext;
258
+ yylineno = this.lexer.yylineno;
259
+ yyloc = this.lexer.yylloc;
260
+ if (recovering > 0)
261
+ recovering--;
262
+ } else {
263
+ symbol = preErrorSymbol;
264
+ preErrorSymbol = null;
265
+ }
266
+ break;
267
+ case 2:
268
+ len = this.productions_[action[1]][1];
269
+ yyval.$ = vstack[vstack.length - len];
270
+ 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};
271
+ r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
272
+ if (typeof r !== "undefined") {
273
+ return r;
274
+ }
275
+ if (len) {
276
+ stack = stack.slice(0, -1 * len * 2);
277
+ vstack = vstack.slice(0, -1 * len);
278
+ lstack = lstack.slice(0, -1 * len);
279
+ }
280
+ stack.push(this.productions_[action[1]][0]);
281
+ vstack.push(yyval.$);
282
+ lstack.push(yyval._$);
283
+ newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
284
+ stack.push(newState);
285
+ break;
286
+ case 3:
287
+ return true;
288
+ }
289
+ }
290
+ return true;
291
+ }
292
+ };/* Jison generated lexer */
293
+ var lexer = (function(){
294
+
295
+ var lexer = ({EOF:1,
296
+ parseError:function parseError(str, hash) {
297
+ if (this.yy.parseError) {
298
+ this.yy.parseError(str, hash);
299
+ } else {
300
+ throw new Error(str);
301
+ }
302
+ },
303
+ setInput:function (input) {
304
+ this._input = input;
305
+ this._more = this._less = this.done = false;
306
+ this.yylineno = this.yyleng = 0;
307
+ this.yytext = this.matched = this.match = '';
308
+ this.conditionStack = ['INITIAL'];
309
+ this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
310
+ return this;
311
+ },
312
+ input:function () {
313
+ var ch = this._input[0];
314
+ this.yytext+=ch;
315
+ this.yyleng++;
316
+ this.match+=ch;
317
+ this.matched+=ch;
318
+ var lines = ch.match(/\n/);
319
+ if (lines) this.yylineno++;
320
+ this._input = this._input.slice(1);
321
+ return ch;
322
+ },
323
+ unput:function (ch) {
324
+ this._input = ch + this._input;
325
+ return this;
326
+ },
327
+ more:function () {
328
+ this._more = true;
329
+ return this;
330
+ },
331
+ pastInput:function () {
332
+ var past = this.matched.substr(0, this.matched.length - this.match.length);
333
+ return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
334
+ },
335
+ upcomingInput:function () {
336
+ var next = this.match;
337
+ if (next.length < 20) {
338
+ next += this._input.substr(0, 20-next.length);
339
+ }
340
+ return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
341
+ },
342
+ showPosition:function () {
343
+ var pre = this.pastInput();
344
+ var c = new Array(pre.length + 1).join("-");
345
+ return pre + this.upcomingInput() + "\n" + c+"^";
346
+ },
347
+ next:function () {
348
+ if (this.done) {
349
+ return this.EOF;
350
+ }
351
+ if (!this._input) this.done = true;
352
+
353
+ var token,
354
+ match,
355
+ col,
356
+ lines;
357
+ if (!this._more) {
358
+ this.yytext = '';
359
+ this.match = '';
360
+ }
361
+ var rules = this._currentRules();
362
+ for (var i=0;i < rules.length; i++) {
363
+ match = this._input.match(this.rules[rules[i]]);
364
+ if (match) {
365
+ lines = match[0].match(/\n.*/g);
366
+ if (lines) this.yylineno += lines.length;
367
+ this.yylloc = {first_line: this.yylloc.last_line,
368
+ last_line: this.yylineno+1,
369
+ first_column: this.yylloc.last_column,
370
+ last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
371
+ this.yytext += match[0];
372
+ this.match += match[0];
373
+ this.matches = match;
374
+ this.yyleng = this.yytext.length;
375
+ this._more = false;
376
+ this._input = this._input.slice(match[0].length);
377
+ this.matched += match[0];
378
+ token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);
379
+ if (token) return token;
380
+ else return;
381
+ }
382
+ }
383
+ if (this._input === "") {
384
+ return this.EOF;
385
+ } else {
386
+ this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
387
+ {text: "", token: null, line: this.yylineno});
388
+ }
389
+ },
390
+ lex:function lex() {
391
+ var r = this.next();
392
+ if (typeof r !== 'undefined') {
393
+ return r;
394
+ } else {
395
+ return this.lex();
396
+ }
397
+ },
398
+ begin:function begin(condition) {
399
+ this.conditionStack.push(condition);
400
+ },
401
+ popState:function popState() {
402
+ return this.conditionStack.pop();
403
+ },
404
+ _currentRules:function _currentRules() {
405
+ return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
406
+ },
407
+ topState:function () {
408
+ return this.conditionStack[this.conditionStack.length-2];
409
+ },
410
+ pushState:function begin(condition) {
411
+ this.begin(condition);
412
+ }});
413
+ lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
414
+
415
+ var YYSTATE=YY_START
416
+ switch($avoiding_name_collisions) {
417
+ case 0:
418
+ if(yy_.yytext.slice(-1) !== "\\") this.begin("mu");
419
+ if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu");
420
+ if(yy_.yytext) return 14;
421
+
422
+ break;
423
+ case 1: return 14;
424
+ break;
425
+ case 2: this.popState(); return 14;
426
+ break;
427
+ case 3: return 24;
428
+ break;
429
+ case 4: return 16;
430
+ break;
431
+ case 5: return 20;
432
+ break;
433
+ case 6: return 19;
434
+ break;
435
+ case 7: return 19;
436
+ break;
437
+ case 8: return 23;
438
+ break;
439
+ case 9: return 23;
440
+ break;
441
+ case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
442
+ break;
443
+ case 11: return 22;
444
+ break;
445
+ case 12: return 34;
446
+ break;
447
+ case 13: return 33;
448
+ break;
449
+ case 14: return 33;
450
+ break;
451
+ case 15: return 36;
452
+ break;
453
+ case 16: /*ignore whitespace*/
454
+ break;
455
+ case 17: this.popState(); return 18;
456
+ break;
457
+ case 18: this.popState(); return 18;
458
+ break;
459
+ case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 28;
460
+ break;
461
+ case 20: return 30;
462
+ break;
463
+ case 21: return 30;
464
+ break;
465
+ case 22: return 29;
466
+ break;
467
+ case 23: return 33;
468
+ break;
469
+ case 24: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 33;
470
+ break;
471
+ case 25: return 'INVALID';
472
+ break;
473
+ case 26: return 5;
474
+ break;
475
+ }
476
+ };
477
+ lexer.rules = [/^[^\x00]*?(?=(\{\{))/,/^[^\x00]+/,/^[^\x00]{2,}?(?=(\{\{))/,/^\{\{>/,/^\{\{#/,/^\{\{\//,/^\{\{\^/,/^\{\{\s*else\b/,/^\{\{\{/,/^\{\{&/,/^\{\{![\s\S]*?\}\}/,/^\{\{/,/^=/,/^\.(?=[} ])/,/^\.\./,/^[\/.]/,/^\s+/,/^\}\}\}/,/^\}\}/,/^"(\\["]|[^"])*"/,/^true(?=[}\s])/,/^false(?=[}\s])/,/^[0-9]+(?=[}\s])/,/^[a-zA-Z0-9_$-]+(?=[=}\s\/.])/,/^\[[^\]]*\]/,/^./,/^$/];
478
+ 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;})()
479
+ parser.lexer = lexer;
480
+ return parser;
481
+ })();
482
+ if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
483
+ exports.parser = handlebars;
484
+ exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); }
485
+ exports.main = function commonjsMain(args) {
486
+ if (!args[1])
487
+ throw new Error('Usage: '+args[0]+' FILE');
488
+ if (typeof process !== 'undefined') {
489
+ var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8");
490
+ } else {
491
+ var cwd = require("file").path(require("file").cwd());
492
+ var source = cwd.join(args[1]).read({charset: "utf-8"});
493
+ }
494
+ return exports.parser.parse(source);
495
+ }
496
+ if (typeof module !== 'undefined' && require.main === module) {
497
+ exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
498
+ }
499
+ };
500
+ ;
501
+ // lib/handlebars/compiler/base.js
502
+ Handlebars.Parser = handlebars;
503
+
504
+ Handlebars.parse = function(string) {
505
+ Handlebars.Parser.yy = Handlebars.AST;
506
+ return Handlebars.Parser.parse(string);
507
+ };
508
+
509
+ Handlebars.print = function(ast) {
510
+ return new Handlebars.PrintVisitor().accept(ast);
511
+ };
512
+
513
+ Handlebars.logger = {
514
+ DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
515
+
516
+ // override in the host environment
517
+ log: function(level, str) {}
518
+ };
519
+
520
+ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
521
+ ;
522
+ // lib/handlebars/compiler/ast.js
523
+ (function() {
524
+
525
+ Handlebars.AST = {};
526
+
527
+ Handlebars.AST.ProgramNode = function(statements, inverse) {
528
+ this.type = "program";
529
+ this.statements = statements;
530
+ if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
531
+ };
532
+
533
+ Handlebars.AST.MustacheNode = function(params, hash, unescaped) {
534
+ this.type = "mustache";
535
+ this.id = params[0];
536
+ this.params = params.slice(1);
537
+ this.hash = hash;
538
+ this.escaped = !unescaped;
539
+ };
540
+
541
+ Handlebars.AST.PartialNode = function(id, context) {
542
+ this.type = "partial";
543
+
544
+ // TODO: disallow complex IDs
545
+
546
+ this.id = id;
547
+ this.context = context;
548
+ };
549
+
550
+ var verifyMatch = function(open, close) {
551
+ if(open.original !== close.original) {
552
+ throw new Handlebars.Exception(open.original + " doesn't match " + close.original);
553
+ }
554
+ };
555
+
556
+ Handlebars.AST.BlockNode = function(mustache, program, close) {
557
+ verifyMatch(mustache.id, close);
558
+ this.type = "block";
559
+ this.mustache = mustache;
560
+ this.program = program;
561
+ };
562
+
563
+ Handlebars.AST.InverseNode = function(mustache, program, close) {
564
+ verifyMatch(mustache.id, close);
565
+ this.type = "inverse";
566
+ this.mustache = mustache;
567
+ this.program = program;
568
+ };
569
+
570
+ Handlebars.AST.ContentNode = function(string) {
571
+ this.type = "content";
572
+ this.string = string;
573
+ };
574
+
575
+ Handlebars.AST.HashNode = function(pairs) {
576
+ this.type = "hash";
577
+ this.pairs = pairs;
578
+ };
579
+
580
+ Handlebars.AST.IdNode = function(parts) {
581
+ this.type = "ID";
582
+ this.original = parts.join(".");
583
+
584
+ var dig = [], depth = 0;
585
+
586
+ for(var i=0,l=parts.length; i<l; i++) {
587
+ var part = parts[i];
588
+
589
+ if(part === "..") { depth++; }
590
+ else if(part === "." || part === "this") { this.isScoped = true; }
591
+ else { dig.push(part); }
592
+ }
593
+
594
+ this.parts = dig;
595
+ this.string = dig.join('.');
596
+ this.depth = depth;
597
+ this.isSimple = (dig.length === 1) && (depth === 0);
598
+ };
599
+
600
+ Handlebars.AST.StringNode = function(string) {
601
+ this.type = "STRING";
602
+ this.string = string;
603
+ };
604
+
605
+ Handlebars.AST.IntegerNode = function(integer) {
606
+ this.type = "INTEGER";
607
+ this.integer = integer;
608
+ };
609
+
610
+ Handlebars.AST.BooleanNode = function(bool) {
611
+ this.type = "BOOLEAN";
612
+ this.bool = bool;
613
+ };
614
+
615
+ Handlebars.AST.CommentNode = function(comment) {
616
+ this.type = "comment";
617
+ this.comment = comment;
618
+ };
619
+
620
+ })();;
621
+ // lib/handlebars/utils.js
622
+ Handlebars.Exception = function(message) {
623
+ var tmp = Error.prototype.constructor.apply(this, arguments);
624
+
625
+ for (var p in tmp) {
626
+ if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; }
627
+ }
628
+
629
+ this.message = tmp.message;
630
+ };
631
+ Handlebars.Exception.prototype = new Error;
632
+
633
+ // Build out our basic SafeString type
634
+ Handlebars.SafeString = function(string) {
635
+ this.string = string;
636
+ };
637
+ Handlebars.SafeString.prototype.toString = function() {
638
+ return this.string.toString();
639
+ };
640
+
641
+ (function() {
642
+ var escape = {
643
+ "<": "&lt;",
644
+ ">": "&gt;",
645
+ '"': "&quot;",
646
+ "'": "&#x27;",
647
+ "`": "&#x60;"
648
+ };
649
+
650
+ var badChars = /&(?!\w+;)|[<>"'`]/g;
651
+ var possible = /[&<>"'`]/;
652
+
653
+ var escapeChar = function(chr) {
654
+ return escape[chr] || "&amp;";
655
+ };
656
+
657
+ Handlebars.Utils = {
658
+ escapeExpression: function(string) {
659
+ // don't escape SafeStrings, since they're already safe
660
+ if (string instanceof Handlebars.SafeString) {
661
+ return string.toString();
662
+ } else if (string == null || string === false) {
663
+ return "";
664
+ }
665
+
666
+ if(!possible.test(string)) { return string; }
667
+ return string.replace(badChars, escapeChar);
668
+ },
669
+
670
+ isEmpty: function(value) {
671
+ if (typeof value === "undefined") {
672
+ return true;
673
+ } else if (value === null) {
674
+ return true;
675
+ } else if (value === false) {
676
+ return true;
677
+ } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
678
+ return true;
679
+ } else {
680
+ return false;
681
+ }
682
+ }
683
+ };
684
+ })();;
685
+ // lib/handlebars/compiler/compiler.js
686
+ Handlebars.Compiler = function() {};
687
+ Handlebars.JavaScriptCompiler = function() {};
688
+
689
+ (function(Compiler, JavaScriptCompiler) {
690
+ Compiler.OPCODE_MAP = {
691
+ appendContent: 1,
692
+ getContext: 2,
693
+ lookupWithHelpers: 3,
694
+ lookup: 4,
695
+ append: 5,
696
+ invokeMustache: 6,
697
+ appendEscaped: 7,
698
+ pushString: 8,
699
+ truthyOrFallback: 9,
700
+ functionOrFallback: 10,
701
+ invokeProgram: 11,
702
+ invokePartial: 12,
703
+ push: 13,
704
+ assignToHash: 15,
705
+ pushStringParam: 16
706
+ };
707
+
708
+ Compiler.MULTI_PARAM_OPCODES = {
709
+ appendContent: 1,
710
+ getContext: 1,
711
+ lookupWithHelpers: 2,
712
+ lookup: 1,
713
+ invokeMustache: 3,
714
+ pushString: 1,
715
+ truthyOrFallback: 1,
716
+ functionOrFallback: 1,
717
+ invokeProgram: 3,
718
+ invokePartial: 1,
719
+ push: 1,
720
+ assignToHash: 1,
721
+ pushStringParam: 1
722
+ };
723
+
724
+ Compiler.DISASSEMBLE_MAP = {};
725
+
726
+ for(var prop in Compiler.OPCODE_MAP) {
727
+ var value = Compiler.OPCODE_MAP[prop];
728
+ Compiler.DISASSEMBLE_MAP[value] = prop;
729
+ }
730
+
731
+ Compiler.multiParamSize = function(code) {
732
+ return Compiler.MULTI_PARAM_OPCODES[Compiler.DISASSEMBLE_MAP[code]];
733
+ };
734
+
735
+ Compiler.prototype = {
736
+ compiler: Compiler,
737
+
738
+ disassemble: function() {
739
+ var opcodes = this.opcodes, opcode, nextCode;
740
+ var out = [], str, name, value;
741
+
742
+ for(var i=0, l=opcodes.length; i<l; i++) {
743
+ opcode = opcodes[i];
744
+
745
+ if(opcode === 'DECLARE') {
746
+ name = opcodes[++i];
747
+ value = opcodes[++i];
748
+ out.push("DECLARE " + name + " = " + value);
749
+ } else {
750
+ str = Compiler.DISASSEMBLE_MAP[opcode];
751
+
752
+ var extraParams = Compiler.multiParamSize(opcode);
753
+ var codes = [];
754
+
755
+ for(var j=0; j<extraParams; j++) {
756
+ nextCode = opcodes[++i];
757
+
758
+ if(typeof nextCode === "string") {
759
+ nextCode = "\"" + nextCode.replace("\n", "\\n") + "\"";
760
+ }
761
+
762
+ codes.push(nextCode);
763
+ }
764
+
765
+ str = str + " " + codes.join(" ");
766
+
767
+ out.push(str);
768
+ }
769
+ }
770
+
771
+ return out.join("\n");
772
+ },
773
+
774
+ guid: 0,
775
+
776
+ compile: function(program, options) {
777
+ this.children = [];
778
+ this.depths = {list: []};
779
+ this.options = options;
780
+
781
+ // These changes will propagate to the other compiler components
782
+ var knownHelpers = this.options.knownHelpers;
783
+ this.options.knownHelpers = {
784
+ 'helperMissing': true,
785
+ 'blockHelperMissing': true,
786
+ 'each': true,
787
+ 'if': true,
788
+ 'unless': true,
789
+ 'with': true,
790
+ 'log': true
791
+ };
792
+ if (knownHelpers) {
793
+ for (var name in knownHelpers) {
794
+ this.options.knownHelpers[name] = knownHelpers[name];
795
+ }
796
+ }
797
+
798
+ return this.program(program);
799
+ },
800
+
801
+ accept: function(node) {
802
+ return this[node.type](node);
803
+ },
804
+
805
+ program: function(program) {
806
+ var statements = program.statements, statement;
807
+ this.opcodes = [];
808
+
809
+ for(var i=0, l=statements.length; i<l; i++) {
810
+ statement = statements[i];
811
+ this[statement.type](statement);
812
+ }
813
+ this.isSimple = l === 1;
814
+
815
+ this.depths.list = this.depths.list.sort(function(a, b) {
816
+ return a - b;
817
+ });
818
+
819
+ return this;
820
+ },
821
+
822
+ compileProgram: function(program) {
823
+ var result = new this.compiler().compile(program, this.options);
824
+ var guid = this.guid++;
825
+
826
+ this.usePartial = this.usePartial || result.usePartial;
827
+
828
+ this.children[guid] = result;
829
+
830
+ for(var i=0, l=result.depths.list.length; i<l; i++) {
831
+ depth = result.depths.list[i];
832
+
833
+ if(depth < 2) { continue; }
834
+ else { this.addDepth(depth - 1); }
835
+ }
836
+
837
+ return guid;
838
+ },
839
+
840
+ block: function(block) {
841
+ var mustache = block.mustache;
842
+ var depth, child, inverse, inverseGuid;
843
+
844
+ var params = this.setupStackForMustache(mustache);
845
+
846
+ var programGuid = this.compileProgram(block.program);
847
+
848
+ if(block.program.inverse) {
849
+ inverseGuid = this.compileProgram(block.program.inverse);
850
+ this.declare('inverse', inverseGuid);
851
+ }
852
+
853
+ this.opcode('invokeProgram', programGuid, params.length, !!mustache.hash);
854
+ this.declare('inverse', null);
855
+ this.opcode('append');
856
+ },
857
+
858
+ inverse: function(block) {
859
+ var params = this.setupStackForMustache(block.mustache);
860
+
861
+ var programGuid = this.compileProgram(block.program);
862
+
863
+ this.declare('inverse', programGuid);
864
+
865
+ this.opcode('invokeProgram', null, params.length, !!block.mustache.hash);
866
+ this.declare('inverse', null);
867
+ this.opcode('append');
868
+ },
869
+
870
+ hash: function(hash) {
871
+ var pairs = hash.pairs, pair, val;
872
+
873
+ this.opcode('push', '{}');
874
+
875
+ for(var i=0, l=pairs.length; i<l; i++) {
876
+ pair = pairs[i];
877
+ val = pair[1];
878
+
879
+ this.accept(val);
880
+ this.opcode('assignToHash', pair[0]);
881
+ }
882
+ },
883
+
884
+ partial: function(partial) {
885
+ var id = partial.id;
886
+ this.usePartial = true;
887
+
888
+ if(partial.context) {
889
+ this.ID(partial.context);
890
+ } else {
891
+ this.opcode('push', 'depth0');
892
+ }
893
+
894
+ this.opcode('invokePartial', id.original);
895
+ this.opcode('append');
896
+ },
897
+
898
+ content: function(content) {
899
+ this.opcode('appendContent', content.string);
900
+ },
901
+
902
+ mustache: function(mustache) {
903
+ var params = this.setupStackForMustache(mustache);
904
+
905
+ this.opcode('invokeMustache', params.length, mustache.id.original, !!mustache.hash);
906
+
907
+ if(mustache.escaped && !this.options.noEscape) {
908
+ this.opcode('appendEscaped');
909
+ } else {
910
+ this.opcode('append');
911
+ }
912
+ },
913
+
914
+ ID: function(id) {
915
+ this.addDepth(id.depth);
916
+
917
+ this.opcode('getContext', id.depth);
918
+
919
+ this.opcode('lookupWithHelpers', id.parts[0] || null, id.isScoped || false);
920
+
921
+ for(var i=1, l=id.parts.length; i<l; i++) {
922
+ this.opcode('lookup', id.parts[i]);
923
+ }
924
+ },
925
+
926
+ STRING: function(string) {
927
+ this.opcode('pushString', string.string);
928
+ },
929
+
930
+ INTEGER: function(integer) {
931
+ this.opcode('push', integer.integer);
932
+ },
933
+
934
+ BOOLEAN: function(bool) {
935
+ this.opcode('push', bool.bool);
936
+ },
937
+
938
+ comment: function() {},
939
+
940
+ // HELPERS
941
+ pushParams: function(params) {
942
+ var i = params.length, param;
943
+
944
+ while(i--) {
945
+ param = params[i];
946
+
947
+ if(this.options.stringParams) {
948
+ if(param.depth) {
949
+ this.addDepth(param.depth);
950
+ }
951
+
952
+ this.opcode('getContext', param.depth || 0);
953
+ this.opcode('pushStringParam', param.string);
954
+ } else {
955
+ this[param.type](param);
956
+ }
957
+ }
958
+ },
959
+
960
+ opcode: function(name, val1, val2, val3) {
961
+ this.opcodes.push(Compiler.OPCODE_MAP[name]);
962
+ if(val1 !== undefined) { this.opcodes.push(val1); }
963
+ if(val2 !== undefined) { this.opcodes.push(val2); }
964
+ if(val3 !== undefined) { this.opcodes.push(val3); }
965
+ },
966
+
967
+ declare: function(name, value) {
968
+ this.opcodes.push('DECLARE');
969
+ this.opcodes.push(name);
970
+ this.opcodes.push(value);
971
+ },
972
+
973
+ addDepth: function(depth) {
974
+ if(depth === 0) { return; }
975
+
976
+ if(!this.depths[depth]) {
977
+ this.depths[depth] = true;
978
+ this.depths.list.push(depth);
979
+ }
980
+ },
981
+
982
+ setupStackForMustache: function(mustache) {
983
+ var params = mustache.params;
984
+
985
+ this.pushParams(params);
986
+
987
+ if(mustache.hash) {
988
+ this.hash(mustache.hash);
989
+ }
990
+
991
+ this.ID(mustache.id);
992
+
993
+ return params;
994
+ }
995
+ };
996
+
997
+ JavaScriptCompiler.prototype = {
998
+ // PUBLIC API: You can override these methods in a subclass to provide
999
+ // alternative compiled forms for name lookup and buffering semantics
1000
+ nameLookup: function(parent, name, type) {
1001
+ if (/^[0-9]+$/.test(name)) {
1002
+ return parent + "[" + name + "]";
1003
+ } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1004
+ return parent + "." + name;
1005
+ }
1006
+ else {
1007
+ return parent + "['" + name + "']";
1008
+ }
1009
+ },
1010
+
1011
+ appendToBuffer: function(string) {
1012
+ if (this.environment.isSimple) {
1013
+ return "return " + string + ";";
1014
+ } else {
1015
+ return "buffer += " + string + ";";
1016
+ }
1017
+ },
1018
+
1019
+ initializeBuffer: function() {
1020
+ return this.quotedString("");
1021
+ },
1022
+
1023
+ namespace: "Handlebars",
1024
+ // END PUBLIC API
1025
+
1026
+ compile: function(environment, options, context, asObject) {
1027
+ this.environment = environment;
1028
+ this.options = options || {};
1029
+
1030
+ this.name = this.environment.name;
1031
+ this.isChild = !!context;
1032
+ this.context = context || {
1033
+ programs: [],
1034
+ aliases: { self: 'this' },
1035
+ registers: {list: []}
1036
+ };
1037
+
1038
+ this.preamble();
1039
+
1040
+ this.stackSlot = 0;
1041
+ this.stackVars = [];
1042
+
1043
+ this.compileChildren(environment, options);
1044
+
1045
+ var opcodes = environment.opcodes, opcode;
1046
+
1047
+ this.i = 0;
1048
+
1049
+ for(l=opcodes.length; this.i<l; this.i++) {
1050
+ opcode = this.nextOpcode(0);
1051
+
1052
+ if(opcode[0] === 'DECLARE') {
1053
+ this.i = this.i + 2;
1054
+ this[opcode[1]] = opcode[2];
1055
+ } else {
1056
+ this.i = this.i + opcode[1].length;
1057
+ this[opcode[0]].apply(this, opcode[1]);
1058
+ }
1059
+ }
1060
+
1061
+ return this.createFunctionContext(asObject);
1062
+ },
1063
+
1064
+ nextOpcode: function(n) {
1065
+ var opcodes = this.environment.opcodes, opcode = opcodes[this.i + n], name, val;
1066
+ var extraParams, codes;
1067
+
1068
+ if(opcode === 'DECLARE') {
1069
+ name = opcodes[this.i + 1];
1070
+ val = opcodes[this.i + 2];
1071
+ return ['DECLARE', name, val];
1072
+ } else {
1073
+ name = Compiler.DISASSEMBLE_MAP[opcode];
1074
+
1075
+ extraParams = Compiler.multiParamSize(opcode);
1076
+ codes = [];
1077
+
1078
+ for(var j=0; j<extraParams; j++) {
1079
+ codes.push(opcodes[this.i + j + 1 + n]);
1080
+ }
1081
+
1082
+ return [name, codes];
1083
+ }
1084
+ },
1085
+
1086
+ eat: function(opcode) {
1087
+ this.i = this.i + opcode.length;
1088
+ },
1089
+
1090
+ preamble: function() {
1091
+ var out = [];
1092
+
1093
+ // this register will disambiguate helper lookup from finding a function in
1094
+ // a context. This is necessary for mustache compatibility, which requires
1095
+ // that context functions in blocks are evaluated by blockHelperMissing, and
1096
+ // then proceed as if the resulting value was provided to blockHelperMissing.
1097
+ this.useRegister('foundHelper');
1098
+
1099
+ if (!this.isChild) {
1100
+ var namespace = this.namespace;
1101
+ var copies = "helpers = helpers || " + namespace + ".helpers;";
1102
+ if(this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
1103
+ out.push(copies);
1104
+ } else {
1105
+ out.push('');
1106
+ }
1107
+
1108
+ if (!this.environment.isSimple) {
1109
+ out.push(", buffer = " + this.initializeBuffer());
1110
+ } else {
1111
+ out.push("");
1112
+ }
1113
+
1114
+ // track the last context pushed into place to allow skipping the
1115
+ // getContext opcode when it would be a noop
1116
+ this.lastContext = 0;
1117
+ this.source = out;
1118
+ },
1119
+
1120
+ createFunctionContext: function(asObject) {
1121
+ var locals = this.stackVars;
1122
+ if (!this.isChild) {
1123
+ locals = locals.concat(this.context.registers.list);
1124
+ }
1125
+
1126
+ if(locals.length > 0) {
1127
+ this.source[1] = this.source[1] + ", " + locals.join(", ");
1128
+ }
1129
+
1130
+ // Generate minimizer alias mappings
1131
+ if (!this.isChild) {
1132
+ var aliases = []
1133
+ for (var alias in this.context.aliases) {
1134
+ this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1135
+ }
1136
+ }
1137
+
1138
+ if (this.source[1]) {
1139
+ this.source[1] = "var " + this.source[1].substring(2) + ";";
1140
+ }
1141
+
1142
+ // Merge children
1143
+ if (!this.isChild) {
1144
+ this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1145
+ }
1146
+
1147
+ if (!this.environment.isSimple) {
1148
+ this.source.push("return buffer;");
1149
+ }
1150
+
1151
+ var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1152
+
1153
+ for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1154
+ params.push("depth" + this.environment.depths.list[i]);
1155
+ }
1156
+
1157
+ if (asObject) {
1158
+ params.push(this.source.join("\n "));
1159
+
1160
+ return Function.apply(this, params);
1161
+ } else {
1162
+ var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + this.source.join("\n ") + '}';
1163
+ Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1164
+ return functionSource;
1165
+ }
1166
+ },
1167
+
1168
+ appendContent: function(content) {
1169
+ this.source.push(this.appendToBuffer(this.quotedString(content)));
1170
+ },
1171
+
1172
+ append: function() {
1173
+ var local = this.popStack();
1174
+ this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1175
+ if (this.environment.isSimple) {
1176
+ this.source.push("else { " + this.appendToBuffer("''") + " }");
1177
+ }
1178
+ },
1179
+
1180
+ appendEscaped: function() {
1181
+ var opcode = this.nextOpcode(1), extra = "";
1182
+ this.context.aliases.escapeExpression = 'this.escapeExpression';
1183
+
1184
+ if(opcode[0] === 'appendContent') {
1185
+ extra = " + " + this.quotedString(opcode[1][0]);
1186
+ this.eat(opcode);
1187
+ }
1188
+
1189
+ this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra));
1190
+ },
1191
+
1192
+ getContext: function(depth) {
1193
+ if(this.lastContext !== depth) {
1194
+ this.lastContext = depth;
1195
+ }
1196
+ },
1197
+
1198
+ lookupWithHelpers: function(name, isScoped) {
1199
+ if(name) {
1200
+ var topStack = this.nextStack();
1201
+
1202
+ this.usingKnownHelper = false;
1203
+
1204
+ var toPush;
1205
+ if (!isScoped && this.options.knownHelpers[name]) {
1206
+ toPush = topStack + " = " + this.nameLookup('helpers', name, 'helper');
1207
+ this.usingKnownHelper = true;
1208
+ } else if (isScoped || this.options.knownHelpersOnly) {
1209
+ toPush = topStack + " = " + this.nameLookup('depth' + this.lastContext, name, 'context');
1210
+ } else {
1211
+ this.register('foundHelper', this.nameLookup('helpers', name, 'helper'));
1212
+ toPush = topStack + " = foundHelper || " + this.nameLookup('depth' + this.lastContext, name, 'context');
1213
+ }
1214
+
1215
+ toPush += ';';
1216
+ this.source.push(toPush);
1217
+ } else {
1218
+ this.pushStack('depth' + this.lastContext);
1219
+ }
1220
+ },
1221
+
1222
+ lookup: function(name) {
1223
+ var topStack = this.topStack();
1224
+ this.source.push(topStack + " = (" + topStack + " === null || " + topStack + " === undefined || " + topStack + " === false ? " +
1225
+ topStack + " : " + this.nameLookup(topStack, name, 'context') + ");");
1226
+ },
1227
+
1228
+ pushStringParam: function(string) {
1229
+ this.pushStack('depth' + this.lastContext);
1230
+ this.pushString(string);
1231
+ },
1232
+
1233
+ pushString: function(string) {
1234
+ this.pushStack(this.quotedString(string));
1235
+ },
1236
+
1237
+ push: function(name) {
1238
+ this.pushStack(name);
1239
+ },
1240
+
1241
+ invokeMustache: function(paramSize, original, hasHash) {
1242
+ this.populateParams(paramSize, this.quotedString(original), "{}", null, hasHash, function(nextStack, helperMissingString, id) {
1243
+ if (!this.usingKnownHelper) {
1244
+ this.context.aliases.helperMissing = 'helpers.helperMissing';
1245
+ this.context.aliases.undef = 'void 0';
1246
+ this.source.push("else if(" + id + "=== undef) { " + nextStack + " = helperMissing.call(" + helperMissingString + "); }");
1247
+ if (nextStack !== id) {
1248
+ this.source.push("else { " + nextStack + " = " + id + "; }");
1249
+ }
1250
+ }
1251
+ });
1252
+ },
1253
+
1254
+ invokeProgram: function(guid, paramSize, hasHash) {
1255
+ var inverse = this.programExpression(this.inverse);
1256
+ var mainProgram = this.programExpression(guid);
1257
+
1258
+ this.populateParams(paramSize, null, mainProgram, inverse, hasHash, function(nextStack, helperMissingString, id) {
1259
+ if (!this.usingKnownHelper) {
1260
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1261
+ this.source.push("else { " + nextStack + " = blockHelperMissing.call(" + helperMissingString + "); }");
1262
+ }
1263
+ });
1264
+ },
1265
+
1266
+ populateParams: function(paramSize, helperId, program, inverse, hasHash, fn) {
1267
+ var needsRegister = hasHash || this.options.stringParams || inverse || this.options.data;
1268
+ var id = this.popStack(), nextStack;
1269
+ var params = [], param, stringParam, stringOptions;
1270
+
1271
+ if (needsRegister) {
1272
+ this.register('tmp1', program);
1273
+ stringOptions = 'tmp1';
1274
+ } else {
1275
+ stringOptions = '{ hash: {} }';
1276
+ }
1277
+
1278
+ if (needsRegister) {
1279
+ var hash = (hasHash ? this.popStack() : '{}');
1280
+ this.source.push('tmp1.hash = ' + hash + ';');
1281
+ }
1282
+
1283
+ if(this.options.stringParams) {
1284
+ this.source.push('tmp1.contexts = [];');
1285
+ }
1286
+
1287
+ for(var i=0; i<paramSize; i++) {
1288
+ param = this.popStack();
1289
+ params.push(param);
1290
+
1291
+ if(this.options.stringParams) {
1292
+ this.source.push('tmp1.contexts.push(' + this.popStack() + ');');
1293
+ }
1294
+ }
1295
+
1296
+ if(inverse) {
1297
+ this.source.push('tmp1.fn = tmp1;');
1298
+ this.source.push('tmp1.inverse = ' + inverse + ';');
1299
+ }
1300
+
1301
+ if(this.options.data) {
1302
+ this.source.push('tmp1.data = data;');
1303
+ }
1304
+
1305
+ params.push(stringOptions);
1306
+
1307
+ this.populateCall(params, id, helperId || id, fn, program !== '{}');
1308
+ },
1309
+
1310
+ populateCall: function(params, id, helperId, fn, program) {
1311
+ var paramString = ["depth0"].concat(params).join(", ");
1312
+ var helperMissingString = ["depth0"].concat(helperId).concat(params).join(", ");
1313
+
1314
+ var nextStack = this.nextStack();
1315
+
1316
+ if (this.usingKnownHelper) {
1317
+ this.source.push(nextStack + " = " + id + ".call(" + paramString + ");");
1318
+ } else {
1319
+ this.context.aliases.functionType = '"function"';
1320
+ var condition = program ? "foundHelper && " : ""
1321
+ this.source.push("if(" + condition + "typeof " + id + " === functionType) { " + nextStack + " = " + id + ".call(" + paramString + "); }");
1322
+ }
1323
+ fn.call(this, nextStack, helperMissingString, id);
1324
+ this.usingKnownHelper = false;
1325
+ },
1326
+
1327
+ invokePartial: function(context) {
1328
+ params = [this.nameLookup('partials', context, 'partial'), "'" + context + "'", this.popStack(), "helpers", "partials"];
1329
+
1330
+ if (this.options.data) {
1331
+ params.push("data");
1332
+ }
1333
+
1334
+ this.pushStack("self.invokePartial(" + params.join(", ") + ");");
1335
+ },
1336
+
1337
+ assignToHash: function(key) {
1338
+ var value = this.popStack();
1339
+ var hash = this.topStack();
1340
+
1341
+ this.source.push(hash + "['" + key + "'] = " + value + ";");
1342
+ },
1343
+
1344
+ // HELPERS
1345
+
1346
+ compiler: JavaScriptCompiler,
1347
+
1348
+ compileChildren: function(environment, options) {
1349
+ var children = environment.children, child, compiler;
1350
+
1351
+ for(var i=0, l=children.length; i<l; i++) {
1352
+ child = children[i];
1353
+ compiler = new this.compiler();
1354
+
1355
+ this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
1356
+ var index = this.context.programs.length;
1357
+ child.index = index;
1358
+ child.name = 'program' + index;
1359
+ this.context.programs[index] = compiler.compile(child, options, this.context);
1360
+ }
1361
+ },
1362
+
1363
+ programExpression: function(guid) {
1364
+ if(guid == null) { return "self.noop"; }
1365
+
1366
+ var child = this.environment.children[guid],
1367
+ depths = child.depths.list;
1368
+ var programParams = [child.index, child.name, "data"];
1369
+
1370
+ for(var i=0, l = depths.length; i<l; i++) {
1371
+ depth = depths[i];
1372
+
1373
+ if(depth === 1) { programParams.push("depth0"); }
1374
+ else { programParams.push("depth" + (depth - 1)); }
1375
+ }
1376
+
1377
+ if(depths.length === 0) {
1378
+ return "self.program(" + programParams.join(", ") + ")";
1379
+ } else {
1380
+ programParams.shift();
1381
+ return "self.programWithDepth(" + programParams.join(", ") + ")";
1382
+ }
1383
+ },
1384
+
1385
+ register: function(name, val) {
1386
+ this.useRegister(name);
1387
+ this.source.push(name + " = " + val + ";");
1388
+ },
1389
+
1390
+ useRegister: function(name) {
1391
+ if(!this.context.registers[name]) {
1392
+ this.context.registers[name] = true;
1393
+ this.context.registers.list.push(name);
1394
+ }
1395
+ },
1396
+
1397
+ pushStack: function(item) {
1398
+ this.source.push(this.nextStack() + " = " + item + ";");
1399
+ return "stack" + this.stackSlot;
1400
+ },
1401
+
1402
+ nextStack: function() {
1403
+ this.stackSlot++;
1404
+ if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1405
+ return "stack" + this.stackSlot;
1406
+ },
1407
+
1408
+ popStack: function() {
1409
+ return "stack" + this.stackSlot--;
1410
+ },
1411
+
1412
+ topStack: function() {
1413
+ return "stack" + this.stackSlot;
1414
+ },
1415
+
1416
+ quotedString: function(str) {
1417
+ return '"' + str
1418
+ .replace(/\\/g, '\\\\')
1419
+ .replace(/"/g, '\\"')
1420
+ .replace(/\n/g, '\\n')
1421
+ .replace(/\r/g, '\\r') + '"';
1422
+ }
1423
+ };
1424
+
1425
+ var reservedWords = (
1426
+ "break else new var" +
1427
+ " case finally return void" +
1428
+ " catch for switch while" +
1429
+ " continue function this with" +
1430
+ " default if throw" +
1431
+ " delete in try" +
1432
+ " do instanceof typeof" +
1433
+ " abstract enum int short" +
1434
+ " boolean export interface static" +
1435
+ " byte extends long super" +
1436
+ " char final native synchronized" +
1437
+ " class float package throws" +
1438
+ " const goto private transient" +
1439
+ " debugger implements protected volatile" +
1440
+ " double import public let yield"
1441
+ ).split(" ");
1442
+
1443
+ var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
1444
+
1445
+ for(var i=0, l=reservedWords.length; i<l; i++) {
1446
+ compilerWords[reservedWords[i]] = true;
1447
+ }
1448
+
1449
+ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
1450
+ if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
1451
+ return true;
1452
+ }
1453
+ return false;
1454
+ }
1455
+
1456
+ })(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
1457
+
1458
+ Handlebars.precompile = function(string, options) {
1459
+ options = options || {};
1460
+
1461
+ var ast = Handlebars.parse(string);
1462
+ var environment = new Handlebars.Compiler().compile(ast, options);
1463
+ return new Handlebars.JavaScriptCompiler().compile(environment, options);
1464
+ };
1465
+
1466
+ Handlebars.compile = function(string, options) {
1467
+ options = options || {};
1468
+
1469
+ var compiled;
1470
+ function compile() {
1471
+ var ast = Handlebars.parse(string);
1472
+ var environment = new Handlebars.Compiler().compile(ast, options);
1473
+ var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
1474
+ return Handlebars.template(templateSpec);
1475
+ }
1476
+
1477
+ // Template is only compiled on first use and cached after that point.
1478
+ return function(context, options) {
1479
+ if (!compiled) {
1480
+ compiled = compile();
1481
+ }
1482
+ return compiled.call(this, context, options);
1483
+ };
1484
+ };
1485
+ ;
1486
+ // lib/handlebars/runtime.js
1487
+ Handlebars.VM = {
1488
+ template: function(templateSpec) {
1489
+ // Just add water
1490
+ var container = {
1491
+ escapeExpression: Handlebars.Utils.escapeExpression,
1492
+ invokePartial: Handlebars.VM.invokePartial,
1493
+ programs: [],
1494
+ program: function(i, fn, data) {
1495
+ var programWrapper = this.programs[i];
1496
+ if(data) {
1497
+ return Handlebars.VM.program(fn, data);
1498
+ } else if(programWrapper) {
1499
+ return programWrapper;
1500
+ } else {
1501
+ programWrapper = this.programs[i] = Handlebars.VM.program(fn);
1502
+ return programWrapper;
1503
+ }
1504
+ },
1505
+ programWithDepth: Handlebars.VM.programWithDepth,
1506
+ noop: Handlebars.VM.noop
1507
+ };
1508
+
1509
+ return function(context, options) {
1510
+ options = options || {};
1511
+ return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
1512
+ };
1513
+ },
1514
+
1515
+ programWithDepth: function(fn, data, $depth) {
1516
+ var args = Array.prototype.slice.call(arguments, 2);
1517
+
1518
+ return function(context, options) {
1519
+ options = options || {};
1520
+
1521
+ return fn.apply(this, [context, options.data || data].concat(args));
1522
+ };
1523
+ },
1524
+ program: function(fn, data) {
1525
+ return function(context, options) {
1526
+ options = options || {};
1527
+
1528
+ return fn(context, options.data || data);
1529
+ };
1530
+ },
1531
+ noop: function() { return ""; },
1532
+ invokePartial: function(partial, name, context, helpers, partials, data) {
1533
+ options = { helpers: helpers, partials: partials, data: data };
1534
+
1535
+ if(partial === undefined) {
1536
+ throw new Handlebars.Exception("The partial " + name + " could not be found");
1537
+ } else if(partial instanceof Function) {
1538
+ return partial(context, options);
1539
+ } else if (!Handlebars.compile) {
1540
+ throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
1541
+ } else {
1542
+ partials[name] = Handlebars.compile(partial);
1543
+ return partials[name](context, options);
1544
+ }
1545
+ }
1546
+ };
1547
+
1548
+ Handlebars.template = Handlebars.VM.template;
1549
+ ;