sht_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .rvmrc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ .DS_Store
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sht_rails.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Alexey
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,60 @@
1
+ # ShtRails
2
+
3
+ Shared handlebars templates for rails 3.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'sht_rails'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install sht_rails
18
+
19
+ ## Usage
20
+
21
+ $ rails g sht_rails:install
22
+
23
+ Generator add into "application.js" requirements for mustache and "templates" folder in "app". Next you can create handlebars templates in this folder or subfolders.
24
+
25
+ For example:
26
+
27
+ File: "app/templates/tests/_test.handlebars"
28
+
29
+ Hello {{msg}}!!!
30
+
31
+ In view you can render this template by this way:
32
+
33
+ <%= render "tests/test", :handlebars => {msg: "Test"} %>
34
+
35
+ The same template you can render in JavaScript:
36
+
37
+ var content = SHT['tests/test']({msg: "Test"});
38
+
39
+ ## Configuration
40
+
41
+ ShtRails.configure do |config|
42
+ config.template_extension = 'handlebars' # change extension of mustache templates
43
+ config.action_view_key = 'handlebars' # change name of key for rendering in ActionView mustache template
44
+ config.template_namespace = 'SHT' # change templates namespace in javascript
45
+ config.template_base_path = Rails.root.join("app", "templates") # templates dir
46
+ end
47
+
48
+ ## Demo
49
+
50
+ Site: [http://st-rails-example.herokuapp.com/sht](http://st-rails-example.herokuapp.com/sht)
51
+
52
+ Source code: [https://github.com/le0pard/st_rails_example](https://github.com/le0pard/st_rails_example)
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,19 @@
1
+ module ShtRails
2
+ module Generators
3
+ module Helpers
4
+
5
+ def asset_path
6
+ "app/assets"
7
+ end
8
+
9
+ def js_path
10
+ "#{asset_path}/javascripts"
11
+ end
12
+
13
+ def app_path
14
+ "app"
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,40 @@
1
+ require 'generators/sht_rails/helpers'
2
+ require 'rails'
3
+
4
+ module ShtRails
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include ShtRails::Generators::Helpers
8
+
9
+ desc "Install into rails"
10
+
11
+ class_option :manifest, :type => :string, :aliases => "-m", :default => 'application.js',
12
+ :desc => "Javascript manifest file to modify (or create)"
13
+
14
+ class_option :template_dir, :type => :string, :aliases => "-t", :default => 'templates',
15
+ :desc => "Template dir for mustache templates"
16
+
17
+ def inject_mustache
18
+ manifest = options[:manifest]
19
+ template_dir = options[:template_dir]
20
+
21
+ create_file("#{js_path}/#{manifest}") unless File.exists?("#{js_path}/#{manifest}")
22
+
23
+ append_to_file "#{js_path}/#{manifest}" do
24
+ out = ""
25
+ out << "//= require handlebars"
26
+ out << "\n"
27
+ out << "//= require_tree ../../#{template_dir}"
28
+ out << "\n"
29
+ out << "\n"
30
+ end
31
+ end
32
+
33
+ def create_dir
34
+ template_dir = options[:template_dir]
35
+ empty_directory "#{app_path}/#{template_dir}"
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,18 @@
1
+ require "sht_rails/version"
2
+ require "sht_rails/config"
3
+
4
+ module ShtRails
5
+ extend Config
6
+
7
+ autoload(:Tilt, 'sht_rails/tilt')
8
+
9
+ if defined?(Rails)
10
+ require 'sht_rails/engine'
11
+ else
12
+ require 'sprockets'
13
+ Sprockets.register_engine ".#{ShtRails.template_extension}", Tilt
14
+ end
15
+ end
16
+
17
+ # init action view handler
18
+ require "sht_rails/handlebars"
@@ -0,0 +1,35 @@
1
+ module ShtRails
2
+ # Change config options in an initializer:
3
+ #
4
+ # ShtRails.template_extension = 'handlebars'
5
+ #
6
+ # Or in a block:
7
+ #
8
+ # ShtRails.configure do |config|
9
+ # config.template_extension = 'handlebars'
10
+ # end
11
+
12
+ module Config
13
+ attr_accessor :template_base_path, :template_extension, :action_view_key, :template_namespace
14
+
15
+ def configure
16
+ yield self
17
+ end
18
+
19
+ def template_base_path
20
+ @template_base_path ||= Rails.root.join("app", "templates")
21
+ end
22
+
23
+ def template_extension
24
+ @template_extension ||= 'handlebars'
25
+ end
26
+
27
+ def action_view_key
28
+ @action_view_key ||= 'handlebars'
29
+ end
30
+
31
+ def template_namespace
32
+ @template_namespace ||= 'SHT'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ module ShtRails
2
+ class Engine < ::Rails::Engine
3
+ config.before_configuration do |app|
4
+ app.paths['app/views'] << ShtRails.template_base_path
5
+ end
6
+
7
+ initializer "sprockets.smt_rails", :after => "sprockets.environment", :group => :all do |app|
8
+ next unless app.assets
9
+ app.assets.register_engine(".#{ShtRails.template_extension}", Tilt)
10
+ app.config.assets.paths << ShtRails.template_base_path
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ require "handlebars"
2
+ require "active_support"
3
+
4
+ module ShtRails
5
+
6
+ module Handlebars
7
+ def self.call(template)
8
+ if template.locals.include?(ShtRails.action_view_key.to_s) || template.locals.include?(ShtRails.action_view_key.to_sym)
9
+ <<-SHT
10
+ hbs_context_for_sht = Handlebars::Context.new
11
+ partials.each do |key, value|
12
+ hbs_context_for_sht.register_partial(key, value)
13
+ end if defined?(partials) && partials.is_a?(Hash)
14
+ hbs_context_for_sht.compile(#{template.source.inspect}).call(#{ShtRails.action_view_key.to_s} || {}).html_safe
15
+ SHT
16
+ else
17
+ "#{template.source.inspect}.html_safe"
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ ActiveSupport.on_load(:action_view) do
24
+ ActionView::Template.register_template_handler(::ShtRails.template_extension.to_sym, ::ShtRails::Handlebars)
25
+ end
@@ -0,0 +1,39 @@
1
+ require 'tilt'
2
+
3
+ module ShtRails
4
+ class Tilt < Tilt::Template
5
+ def self.default_mime_type
6
+ 'application/javascript'
7
+ end
8
+
9
+ def prepare
10
+ @namespace = "this.#{ShtRails.template_namespace}"
11
+ end
12
+
13
+ attr_reader :namespace
14
+
15
+ def evaluate(scope, locals, &block)
16
+ template_key = path_to_key scope
17
+ <<-HandlebarsTemplate
18
+ (function() {
19
+ #{namespace} || (#{namespace} = {});
20
+ #{namespace}CachedShtTemplates || (#{namespace}CachedShtTemplates = {});
21
+ #{namespace}CachedShtTemplates[#{template_key.inspect}] = Handlebars.compile(#{data.inspect});
22
+ #{namespace}[#{template_key.inspect}] = function(object) {
23
+ if (object == null){
24
+ return #{ShtRails.template_namespace}CachedShtTemplates[#{template_key.inspect}];
25
+ } else {
26
+ return #{ShtRails.template_namespace}CachedShtTemplates[#{template_key.inspect}](object);
27
+ }
28
+ };
29
+ }).call(this);
30
+ HandlebarsTemplate
31
+ end
32
+
33
+ def path_to_key(scope)
34
+ path = scope.logical_path.to_s.split('/')
35
+ path.last.gsub!(/^_/, '')
36
+ path.join('/')
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module ShtRails
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/sht_rails/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Alexey Vasiliev"]
6
+ gem.email = ["leopard.not.a@gmail.com"]
7
+ gem.description = %q{Shared handlebars templates for rails 3}
8
+ gem.summary = %q{Shared handlebars templates for rails 3}
9
+ gem.homepage = "https://github.com/railsware/sht_rails"
10
+
11
+ gem.extra_rdoc_files = [ "LICENSE", "README.md" ]
12
+ gem.rdoc_options = ["--charset=UTF-8"]
13
+
14
+ gem.files = `git ls-files`.split($\)
15
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.name = "sht_rails"
18
+ gem.require_paths = ["lib"]
19
+ gem.version = ShtRails::VERSION
20
+
21
+ gem.add_runtime_dependency "rails", ">= 3.1.0"
22
+ gem.add_runtime_dependency "tilt", ">= 1.3.3"
23
+ gem.add_runtime_dependency "sprockets", ">= 2.0.3"
24
+ gem.add_runtime_dependency "handlebars", ">= 0.3.0"
25
+
26
+ gem.add_development_dependency "rake"
27
+ end
@@ -0,0 +1,1550 @@
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) {
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
+ ;
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;
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")
202
+ this.lexer.yylloc = {};
203
+ var yyloc = this.lexer.yylloc;
204
+ lstack.push(yyloc);
205
+ if (typeof this.yy.parseError === "function")
206
+ this.parseError = this.yy.parseError;
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)
227
+ symbol = lex();
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) {
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) + "'");
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--;
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++;
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;
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;
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;
381
+ else return;
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");
420
+ if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu");
421
+ if(yy_.yytext) return 14;
422
+
423
+ break;
424
+ case 1: return 14;
425
+ break;
426
+ case 2: this.popState(); return 14;
427
+ break;
428
+ case 3: return 24;
429
+ break;
430
+ case 4: return 16;
431
+ break;
432
+ case 5: return 20;
433
+ break;
434
+ case 6: return 19;
435
+ break;
436
+ case 7: return 19;
437
+ break;
438
+ case 8: return 23;
439
+ break;
440
+ case 9: return 23;
441
+ break;
442
+ case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
443
+ break;
444
+ case 11: return 22;
445
+ break;
446
+ case 12: return 34;
447
+ break;
448
+ case 13: return 33;
449
+ break;
450
+ case 14: return 33;
451
+ break;
452
+ case 15: return 36;
453
+ break;
454
+ case 16: /*ignore whitespace*/
455
+ break;
456
+ case 17: this.popState(); return 18;
457
+ break;
458
+ case 18: this.popState(); return 18;
459
+ break;
460
+ case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 28;
461
+ break;
462
+ case 20: return 30;
463
+ break;
464
+ case 21: return 30;
465
+ break;
466
+ case 22: return 29;
467
+ break;
468
+ case 23: return 33;
469
+ break;
470
+ case 24: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 33;
471
+ break;
472
+ case 25: return 'INVALID';
473
+ break;
474
+ case 26: return 5;
475
+ break;
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');
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"});
494
+ }
495
+ return exports.parser.parse(source);
496
+ }
497
+ if (typeof module !== 'undefined' && require.main === module) {
498
+ exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
499
+ }
500
+ };
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
+ ;