handlebars_assets 0.12.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NzMzMDYyMzljN2EyY2FjMGY2OWJmNDQ1MTQ1ZmIzNWU4NjA3MWJkMw==
5
+ data.tar.gz: !binary |-
6
+ YTZiMTM0YjMwZDUzZTU2NTI4ZmI1YWRkOGI4MzA0MDFhMzY0NTYwOQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ Yzc1YWZlYWYwZjhmMWIxOTFiMTFkM2M2ODFmMzlkMDM1MThjNDIzNmEwMDli
10
+ Zjc1YWMzMmFlZmE1NWRkZTQ4NjQ1ZGYyNjgxYTc5Mzk2OWMxMDRmYjQyZTVl
11
+ Y2QyNGQ3MmRiODQwYzE4ZmVlNTliYTY2ZDFjMGZkZTg4MzVlNmU=
12
+ data.tar.gz: !binary |-
13
+ ODlhZjY3ZDBmYzk2YzEyNmViODk4MDBiM2FiYTNlNDVkNmQxODA3OGU1YTkx
14
+ MDczYjVlNDcwMmRlODhmNzZlOGVjMmRkMTA2MzhiMzg3NTViNDA4MmI2ZmUy
15
+ ZDNlZjllODg2YWNmOWQ4ZDc3NTczZDEwMmJhNzExMTg3OTVhOTA=
@@ -1,5 +1,9 @@
1
1
  ## On master
2
2
 
3
+ ## 0.12.1 (2013-05-21)
4
+
5
+ * Update to handlebars 1.0.0-rc.4 - @turadg
6
+
3
7
  ## 0.12.0 (2013-02-17)
4
8
 
5
9
  * Support for patching `handlebars.js`
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- handlebars_assets (0.12.0)
4
+ handlebars_assets (0.12.1)
5
5
  execjs (>= 1.2.9)
6
6
  sprockets (>= 2.0.3)
7
7
  tilt
@@ -21,14 +21,14 @@ GEM
21
21
  multi_json (~> 1.0)
22
22
  haml (4.0.0)
23
23
  tilt
24
- hike (1.2.1)
25
- multi_json (1.4.0)
26
- rack (1.4.1)
24
+ hike (1.2.2)
25
+ multi_json (1.7.3)
26
+ rack (1.5.2)
27
27
  rake (10.0.3)
28
28
  slim (1.3.6)
29
29
  temple (~> 0.5.5)
30
30
  tilt (~> 1.3.3)
31
- sprockets (2.8.1)
31
+ sprockets (2.9.3)
32
32
  hike (~> 1.2)
33
33
  multi_json (~> 1.0)
34
34
  rack (~> 1.0)
data/README.md CHANGED
@@ -12,7 +12,7 @@ My pull request to allow `/` in partials was pulled into Handlebars. The hack th
12
12
 
13
13
  ## Version of handlebars.js
14
14
 
15
- `handlebars_assets` is packaged with an 1.0.0-rc3 of `handlebars.js`. See the section on using another version if that does not work for you.
15
+ `handlebars_assets` is packaged with an 1.0.0-rc4 of `handlebars.js`. See the section on using another version if that does not work for you.
16
16
 
17
17
  ## Installation with Rails 3.1+
18
18
 
@@ -221,6 +221,7 @@ Follow me on [Github](https://github.com/leshill) and [Twitter](https://twitter.
221
221
  * David Lee (@davidlee) : Slim support
222
222
  * Phil Cohen (@phlipper) : README cleanup
223
223
  * Akshay Rawat (@akshayrawat) : Update to handlebars.js 1.0.0-rc.3
224
+ * Turadg Aleahmad (@turadg) : Update to handlebars 1.0.0-rc.4
224
225
 
225
226
  # Contributing
226
227
 
@@ -70,6 +70,7 @@ module HandlebarsAssets
70
70
  def generate_known_helpers_hash
71
71
  known_helpers.inject({}) do |hash, helper|
72
72
  hash[helper] = true
73
+ hash
73
74
  end
74
75
  end
75
76
 
@@ -1,3 +1,3 @@
1
1
  module HandlebarsAssets
2
- VERSION = "0.12.0"
2
+ VERSION = "0.12.1"
3
3
  end
@@ -1,12 +1,10 @@
1
- (function(window) {
2
- var originalLookup = window.Handlebars.JavaScriptCompiler.prototype.nameLookup;
1
+ var originalLookup = Handlebars.JavaScriptCompiler.prototype.nameLookup;
3
2
 
4
- window.Handlebars.JavaScriptCompiler.prototype.nameLookup = function(parent, name, type) {
5
- if (type === 'context') {
6
- return '"CALLED PATCH"';
7
- }
8
- else {
9
- return originalLookup(parent, name, type);
10
- }
11
- };
12
- })(this);
3
+ Handlebars.JavaScriptCompiler.prototype.nameLookup = function(parent, name, type) {
4
+ if (type === 'context') {
5
+ return '"CALLED PATCH"';
6
+ }
7
+ else {
8
+ return originalLookup.call(this, parent, name, type);
9
+ }
10
+ };
@@ -22,31 +22,45 @@ THE SOFTWARE.
22
22
 
23
23
  */
24
24
 
25
- // lib/handlebars/base.js
26
-
27
- /*jshint eqnull:true*/
28
- this.Handlebars = {};
25
+ // lib/handlebars/browser-prefix.js
26
+ var Handlebars = {};
29
27
 
30
- (function(Handlebars) {
28
+ (function(Handlebars, undefined) {
29
+ ;
30
+ // lib/handlebars/base.js
31
31
 
32
- Handlebars.VERSION = "1.0.0-rc.3";
33
- Handlebars.COMPILER_REVISION = 2;
32
+ Handlebars.VERSION = "1.0.0-rc.4";
33
+ Handlebars.COMPILER_REVISION = 3;
34
34
 
35
35
  Handlebars.REVISION_CHANGES = {
36
36
  1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
37
- 2: '>= 1.0.0-rc.3'
37
+ 2: '== 1.0.0-rc.3',
38
+ 3: '>= 1.0.0-rc.4'
38
39
  };
39
40
 
40
41
  Handlebars.helpers = {};
41
42
  Handlebars.partials = {};
42
43
 
44
+ var toString = Object.prototype.toString,
45
+ functionType = '[object Function]',
46
+ objectType = '[object Object]';
47
+
43
48
  Handlebars.registerHelper = function(name, fn, inverse) {
44
- if(inverse) { fn.not = inverse; }
45
- this.helpers[name] = fn;
49
+ if (toString.call(name) === objectType) {
50
+ if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); }
51
+ Handlebars.Utils.extend(this.helpers, name);
52
+ } else {
53
+ if (inverse) { fn.not = inverse; }
54
+ this.helpers[name] = fn;
55
+ }
46
56
  };
47
57
 
48
58
  Handlebars.registerPartial = function(name, str) {
49
- this.partials[name] = str;
59
+ if (toString.call(name) === objectType) {
60
+ Handlebars.Utils.extend(this.partials, name);
61
+ } else {
62
+ this.partials[name] = str;
63
+ }
50
64
  };
51
65
 
52
66
  Handlebars.registerHelper('helperMissing', function(arg) {
@@ -57,13 +71,9 @@ Handlebars.registerHelper('helperMissing', function(arg) {
57
71
  }
58
72
  });
59
73
 
60
- var toString = Object.prototype.toString, functionType = "[object Function]";
61
-
62
74
  Handlebars.registerHelper('blockHelperMissing', function(context, options) {
63
75
  var inverse = options.inverse || function() {}, fn = options.fn;
64
76
 
65
-
66
- var ret = "";
67
77
  var type = toString.call(context);
68
78
 
69
79
  if(type === functionType) { context = context.call(this); }
@@ -154,23 +164,17 @@ Handlebars.registerHelper('if', function(context, options) {
154
164
  });
155
165
 
156
166
  Handlebars.registerHelper('unless', function(context, options) {
157
- var fn = options.fn, inverse = options.inverse;
158
- options.fn = inverse;
159
- options.inverse = fn;
160
-
161
- return Handlebars.helpers['if'].call(this, context, options);
167
+ return Handlebars.helpers['if'].call(this, context, {fn: options.inverse, inverse: options.fn});
162
168
  });
163
169
 
164
170
  Handlebars.registerHelper('with', function(context, options) {
165
- return options.fn(context);
171
+ if (!Handlebars.Utils.isEmpty(context)) return options.fn(context);
166
172
  });
167
173
 
168
174
  Handlebars.registerHelper('log', function(context, options) {
169
175
  var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
170
176
  Handlebars.log(level, context);
171
177
  });
172
-
173
- }(this.Handlebars));
174
178
  ;
175
179
  // lib/handlebars/compiler/parser.js
176
180
  /* Jison generated parser */
@@ -562,90 +566,93 @@ lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_STA
562
566
 
563
567
  var YYSTATE=YY_START
564
568
  switch($avoiding_name_collisions) {
565
- case 0:
569
+ case 0: yy_.yytext = "\\"; return 14;
570
+ break;
571
+ case 1:
566
572
  if(yy_.yytext.slice(-1) !== "\\") this.begin("mu");
567
573
  if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu");
568
574
  if(yy_.yytext) return 14;
569
575
 
570
576
  break;
571
- case 1: return 14;
577
+ case 2: return 14;
572
578
  break;
573
- case 2:
579
+ case 3:
574
580
  if(yy_.yytext.slice(-1) !== "\\") this.popState();
575
581
  if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1);
576
582
  return 14;
577
583
 
578
584
  break;
579
- case 3: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15;
585
+ case 4: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15;
580
586
  break;
581
- case 4: this.begin("par"); return 24;
587
+ case 5: this.begin("par"); return 24;
582
588
  break;
583
- case 5: return 16;
589
+ case 6: return 16;
584
590
  break;
585
- case 6: return 20;
586
- break;
587
- case 7: return 19;
591
+ case 7: return 20;
588
592
  break;
589
593
  case 8: return 19;
590
594
  break;
591
- case 9: return 23;
595
+ case 9: return 19;
592
596
  break;
593
597
  case 10: return 23;
594
598
  break;
595
- case 11: this.popState(); this.begin('com');
599
+ case 11: return 23;
596
600
  break;
597
- case 12: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
601
+ case 12: this.popState(); this.begin('com');
598
602
  break;
599
- case 13: return 22;
603
+ case 13: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
600
604
  break;
601
- case 14: return 36;
605
+ case 14: return 22;
602
606
  break;
603
- case 15: return 35;
607
+ case 15: return 36;
604
608
  break;
605
609
  case 16: return 35;
606
610
  break;
607
- case 17: return 39;
611
+ case 17: return 35;
608
612
  break;
609
- case 18: /*ignore whitespace*/
613
+ case 18: return 39;
610
614
  break;
611
- case 19: this.popState(); return 18;
615
+ case 19: /*ignore whitespace*/
612
616
  break;
613
617
  case 20: this.popState(); return 18;
614
618
  break;
615
- case 21: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30;
619
+ case 21: this.popState(); return 18;
616
620
  break;
617
- case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30;
621
+ case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30;
618
622
  break;
619
- case 23: yy_.yytext = yy_.yytext.substr(1); return 28;
623
+ case 23: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30;
620
624
  break;
621
- case 24: return 32;
625
+ case 24: yy_.yytext = yy_.yytext.substr(1); return 28;
622
626
  break;
623
627
  case 25: return 32;
624
628
  break;
625
- case 26: return 31;
629
+ case 26: return 32;
630
+ break;
631
+ case 27: return 31;
626
632
  break;
627
- case 27: return 35;
633
+ case 28: return 35;
628
634
  break;
629
- case 28: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35;
635
+ case 29: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35;
630
636
  break;
631
- case 29: return 'INVALID';
637
+ case 30: return 'INVALID';
632
638
  break;
633
- case 30: /*ignore whitespace*/
639
+ case 31: /*ignore whitespace*/
634
640
  break;
635
- case 31: this.popState(); return 37;
641
+ case 32: this.popState(); return 37;
636
642
  break;
637
- case 32: return 5;
643
+ case 33: return 5;
638
644
  break;
639
645
  }
640
646
  };
641
- lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/];
642
- lexer.conditions = {"mu":{"rules":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"par":{"rules":[30,31],"inclusive":false},"INITIAL":{"rules":[0,1,32],"inclusive":true}};
647
+ lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$:\-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$\-\/]+)/,/^(?:$)/];
648
+ lexer.conditions = {"mu":{"rules":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,33],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"par":{"rules":[31,32],"inclusive":false},"INITIAL":{"rules":[0,1,2,33],"inclusive":true}};
643
649
  return lexer;})()
644
650
  parser.lexer = lexer;
645
651
  function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;
646
652
  return new Parser;
647
653
  })();;
648
654
  // lib/handlebars/compiler/base.js
655
+
649
656
  Handlebars.Parser = handlebars;
650
657
 
651
658
  Handlebars.parse = function(input) {
@@ -656,139 +663,133 @@ Handlebars.parse = function(input) {
656
663
  Handlebars.Parser.yy = Handlebars.AST;
657
664
  return Handlebars.Parser.parse(input);
658
665
  };
659
-
660
- Handlebars.print = function(ast) {
661
- return new Handlebars.PrintVisitor().accept(ast);
662
- };;
666
+ ;
663
667
  // lib/handlebars/compiler/ast.js
664
- (function() {
665
-
666
- Handlebars.AST = {};
668
+ Handlebars.AST = {};
667
669
 
668
- Handlebars.AST.ProgramNode = function(statements, inverse) {
669
- this.type = "program";
670
- this.statements = statements;
671
- if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
672
- };
670
+ Handlebars.AST.ProgramNode = function(statements, inverse) {
671
+ this.type = "program";
672
+ this.statements = statements;
673
+ if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
674
+ };
673
675
 
674
- Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
675
- this.type = "mustache";
676
- this.escaped = !unescaped;
677
- this.hash = hash;
676
+ Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
677
+ this.type = "mustache";
678
+ this.escaped = !unescaped;
679
+ this.hash = hash;
678
680
 
679
- var id = this.id = rawParams[0];
680
- var params = this.params = rawParams.slice(1);
681
+ var id = this.id = rawParams[0];
682
+ var params = this.params = rawParams.slice(1);
681
683
 
682
- // a mustache is an eligible helper if:
683
- // * its id is simple (a single part, not `this` or `..`)
684
- var eligibleHelper = this.eligibleHelper = id.isSimple;
684
+ // a mustache is an eligible helper if:
685
+ // * its id is simple (a single part, not `this` or `..`)
686
+ var eligibleHelper = this.eligibleHelper = id.isSimple;
685
687
 
686
- // a mustache is definitely a helper if:
687
- // * it is an eligible helper, and
688
- // * it has at least one parameter or hash segment
689
- this.isHelper = eligibleHelper && (params.length || hash);
688
+ // a mustache is definitely a helper if:
689
+ // * it is an eligible helper, and
690
+ // * it has at least one parameter or hash segment
691
+ this.isHelper = eligibleHelper && (params.length || hash);
690
692
 
691
- // if a mustache is an eligible helper but not a definite
692
- // helper, it is ambiguous, and will be resolved in a later
693
- // pass or at runtime.
694
- };
693
+ // if a mustache is an eligible helper but not a definite
694
+ // helper, it is ambiguous, and will be resolved in a later
695
+ // pass or at runtime.
696
+ };
695
697
 
696
- Handlebars.AST.PartialNode = function(partialName, context) {
697
- this.type = "partial";
698
- this.partialName = partialName;
699
- this.context = context;
700
- };
698
+ Handlebars.AST.PartialNode = function(partialName, context) {
699
+ this.type = "partial";
700
+ this.partialName = partialName;
701
+ this.context = context;
702
+ };
701
703
 
704
+ Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
702
705
  var verifyMatch = function(open, close) {
703
706
  if(open.original !== close.original) {
704
707
  throw new Handlebars.Exception(open.original + " doesn't match " + close.original);
705
708
  }
706
709
  };
707
710
 
708
- Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
709
- verifyMatch(mustache.id, close);
710
- this.type = "block";
711
- this.mustache = mustache;
712
- this.program = program;
713
- this.inverse = inverse;
711
+ verifyMatch(mustache.id, close);
712
+ this.type = "block";
713
+ this.mustache = mustache;
714
+ this.program = program;
715
+ this.inverse = inverse;
714
716
 
715
- if (this.inverse && !this.program) {
716
- this.isInverse = true;
717
- }
718
- };
717
+ if (this.inverse && !this.program) {
718
+ this.isInverse = true;
719
+ }
720
+ };
719
721
 
720
- Handlebars.AST.ContentNode = function(string) {
721
- this.type = "content";
722
- this.string = string;
723
- };
722
+ Handlebars.AST.ContentNode = function(string) {
723
+ this.type = "content";
724
+ this.string = string;
725
+ };
724
726
 
725
- Handlebars.AST.HashNode = function(pairs) {
726
- this.type = "hash";
727
- this.pairs = pairs;
728
- };
727
+ Handlebars.AST.HashNode = function(pairs) {
728
+ this.type = "hash";
729
+ this.pairs = pairs;
730
+ };
729
731
 
730
- Handlebars.AST.IdNode = function(parts) {
731
- this.type = "ID";
732
- this.original = parts.join(".");
732
+ Handlebars.AST.IdNode = function(parts) {
733
+ this.type = "ID";
734
+ this.original = parts.join(".");
733
735
 
734
- var dig = [], depth = 0;
736
+ var dig = [], depth = 0;
735
737
 
736
- for(var i=0,l=parts.length; i<l; i++) {
737
- var part = parts[i];
738
+ for(var i=0,l=parts.length; i<l; i++) {
739
+ var part = parts[i];
738
740
 
739
- if (part === ".." || part === "." || part === "this") {
740
- if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + this.original); }
741
- else if (part === "..") { depth++; }
742
- else { this.isScoped = true; }
743
- }
744
- else { dig.push(part); }
741
+ if (part === ".." || part === "." || part === "this") {
742
+ if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + this.original); }
743
+ else if (part === "..") { depth++; }
744
+ else { this.isScoped = true; }
745
745
  }
746
+ else { dig.push(part); }
747
+ }
746
748
 
747
- this.parts = dig;
748
- this.string = dig.join('.');
749
- this.depth = depth;
750
-
751
- // an ID is simple if it only has one part, and that part is not
752
- // `..` or `this`.
753
- this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
749
+ this.parts = dig;
750
+ this.string = dig.join('.');
751
+ this.depth = depth;
754
752
 
755
- this.stringModeValue = this.string;
756
- };
753
+ // an ID is simple if it only has one part, and that part is not
754
+ // `..` or `this`.
755
+ this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
757
756
 
758
- Handlebars.AST.PartialNameNode = function(name) {
759
- this.type = "PARTIAL_NAME";
760
- this.name = name;
761
- };
757
+ this.stringModeValue = this.string;
758
+ };
762
759
 
763
- Handlebars.AST.DataNode = function(id) {
764
- this.type = "DATA";
765
- this.id = id;
766
- };
760
+ Handlebars.AST.PartialNameNode = function(name) {
761
+ this.type = "PARTIAL_NAME";
762
+ this.name = name;
763
+ };
767
764
 
768
- Handlebars.AST.StringNode = function(string) {
769
- this.type = "STRING";
770
- this.string = string;
771
- this.stringModeValue = string;
772
- };
765
+ Handlebars.AST.DataNode = function(id) {
766
+ this.type = "DATA";
767
+ this.id = id;
768
+ };
773
769
 
774
- Handlebars.AST.IntegerNode = function(integer) {
775
- this.type = "INTEGER";
776
- this.integer = integer;
777
- this.stringModeValue = Number(integer);
778
- };
770
+ Handlebars.AST.StringNode = function(string) {
771
+ this.type = "STRING";
772
+ this.string = string;
773
+ this.stringModeValue = string;
774
+ };
779
775
 
780
- Handlebars.AST.BooleanNode = function(bool) {
781
- this.type = "BOOLEAN";
782
- this.bool = bool;
783
- this.stringModeValue = bool === "true";
784
- };
776
+ Handlebars.AST.IntegerNode = function(integer) {
777
+ this.type = "INTEGER";
778
+ this.integer = integer;
779
+ this.stringModeValue = Number(integer);
780
+ };
785
781
 
786
- Handlebars.AST.CommentNode = function(comment) {
787
- this.type = "comment";
788
- this.comment = comment;
789
- };
782
+ Handlebars.AST.BooleanNode = function(bool) {
783
+ this.type = "BOOLEAN";
784
+ this.bool = bool;
785
+ this.stringModeValue = bool === "true";
786
+ };
790
787
 
791
- })();;
788
+ Handlebars.AST.CommentNode = function(comment) {
789
+ this.type = "comment";
790
+ this.comment = comment;
791
+ };
792
+ ;
792
793
  // lib/handlebars/utils.js
793
794
 
794
795
  var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
@@ -811,1273 +812,1301 @@ Handlebars.SafeString.prototype.toString = function() {
811
812
  return this.string.toString();
812
813
  };
813
814
 
814
- (function() {
815
- var escape = {
816
- "&": "&amp;",
817
- "<": "&lt;",
818
- ">": "&gt;",
819
- '"': "&quot;",
820
- "'": "&#x27;",
821
- "`": "&#x60;"
822
- };
815
+ var escape = {
816
+ "&": "&amp;",
817
+ "<": "&lt;",
818
+ ">": "&gt;",
819
+ '"': "&quot;",
820
+ "'": "&#x27;",
821
+ "`": "&#x60;"
822
+ };
823
823
 
824
- var badChars = /[&<>"'`]/g;
825
- var possible = /[&<>"'`]/;
824
+ var badChars = /[&<>"'`]/g;
825
+ var possible = /[&<>"'`]/;
826
826
 
827
- var escapeChar = function(chr) {
828
- return escape[chr] || "&amp;";
829
- };
827
+ var escapeChar = function(chr) {
828
+ return escape[chr] || "&amp;";
829
+ };
830
830
 
831
- Handlebars.Utils = {
832
- escapeExpression: function(string) {
833
- // don't escape SafeStrings, since they're already safe
834
- if (string instanceof Handlebars.SafeString) {
835
- return string.toString();
836
- } else if (string == null || string === false) {
837
- return "";
831
+ Handlebars.Utils = {
832
+ extend: function(obj, value) {
833
+ for(var key in value) {
834
+ if(value.hasOwnProperty(key)) {
835
+ obj[key] = value[key];
838
836
  }
837
+ }
838
+ },
839
839
 
840
- if(!possible.test(string)) { return string; }
841
- return string.replace(badChars, escapeChar);
842
- },
840
+ escapeExpression: function(string) {
841
+ // don't escape SafeStrings, since they're already safe
842
+ if (string instanceof Handlebars.SafeString) {
843
+ return string.toString();
844
+ } else if (string == null || string === false) {
845
+ return "";
846
+ }
843
847
 
844
- isEmpty: function(value) {
845
- if (!value && value !== 0) {
846
- return true;
847
- } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
848
- return true;
849
- } else {
850
- return false;
851
- }
848
+ // Force a string conversion as this will be done by the append regardless and
849
+ // the regex test will do this transparently behind the scenes, causing issues if
850
+ // an object's to string has escaped characters in it.
851
+ string = string.toString();
852
+
853
+ if(!possible.test(string)) { return string; }
854
+ return string.replace(badChars, escapeChar);
855
+ },
856
+
857
+ isEmpty: function(value) {
858
+ if (!value && value !== 0) {
859
+ return true;
860
+ } else if(toString.call(value) === "[object Array]" && value.length === 0) {
861
+ return true;
862
+ } else {
863
+ return false;
852
864
  }
853
- };
854
- })();;
865
+ }
866
+ };
867
+ ;
855
868
  // lib/handlebars/compiler/compiler.js
856
869
 
857
870
  /*jshint eqnull:true*/
858
- Handlebars.Compiler = function() {};
859
- Handlebars.JavaScriptCompiler = function() {};
871
+ var Compiler = Handlebars.Compiler = function() {};
872
+ var JavaScriptCompiler = Handlebars.JavaScriptCompiler = function() {};
860
873
 
861
- (function(Compiler, JavaScriptCompiler) {
862
- // the foundHelper register will disambiguate helper lookup from finding a
863
- // function in a context. This is necessary for mustache compatibility, which
864
- // requires that context functions in blocks are evaluated by blockHelperMissing,
865
- // and then proceed as if the resulting value was provided to blockHelperMissing.
874
+ // the foundHelper register will disambiguate helper lookup from finding a
875
+ // function in a context. This is necessary for mustache compatibility, which
876
+ // requires that context functions in blocks are evaluated by blockHelperMissing,
877
+ // and then proceed as if the resulting value was provided to blockHelperMissing.
866
878
 
867
- Compiler.prototype = {
868
- compiler: Compiler,
879
+ Compiler.prototype = {
880
+ compiler: Compiler,
869
881
 
870
- disassemble: function() {
871
- var opcodes = this.opcodes, opcode, out = [], params, param;
882
+ disassemble: function() {
883
+ var opcodes = this.opcodes, opcode, out = [], params, param;
872
884
 
873
- for (var i=0, l=opcodes.length; i<l; i++) {
874
- opcode = opcodes[i];
885
+ for (var i=0, l=opcodes.length; i<l; i++) {
886
+ opcode = opcodes[i];
875
887
 
876
- if (opcode.opcode === 'DECLARE') {
877
- out.push("DECLARE " + opcode.name + "=" + opcode.value);
878
- } else {
879
- params = [];
880
- for (var j=0; j<opcode.args.length; j++) {
881
- param = opcode.args[j];
882
- if (typeof param === "string") {
883
- param = "\"" + param.replace("\n", "\\n") + "\"";
884
- }
885
- params.push(param);
888
+ if (opcode.opcode === 'DECLARE') {
889
+ out.push("DECLARE " + opcode.name + "=" + opcode.value);
890
+ } else {
891
+ params = [];
892
+ for (var j=0; j<opcode.args.length; j++) {
893
+ param = opcode.args[j];
894
+ if (typeof param === "string") {
895
+ param = "\"" + param.replace("\n", "\\n") + "\"";
886
896
  }
887
- out.push(opcode.opcode + " " + params.join(" "));
897
+ params.push(param);
888
898
  }
899
+ out.push(opcode.opcode + " " + params.join(" "));
889
900
  }
901
+ }
890
902
 
891
- return out.join("\n");
892
- },
893
- equals: function(other) {
894
- var len = this.opcodes.length;
895
- if (other.opcodes.length !== len) {
903
+ return out.join("\n");
904
+ },
905
+ equals: function(other) {
906
+ var len = this.opcodes.length;
907
+ if (other.opcodes.length !== len) {
908
+ return false;
909
+ }
910
+
911
+ for (var i = 0; i < len; i++) {
912
+ var opcode = this.opcodes[i],
913
+ otherOpcode = other.opcodes[i];
914
+ if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
896
915
  return false;
897
916
  }
898
-
899
- for (var i = 0; i < len; i++) {
900
- var opcode = this.opcodes[i],
901
- otherOpcode = other.opcodes[i];
902
- if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
917
+ for (var j = 0; j < opcode.args.length; j++) {
918
+ if (opcode.args[j] !== otherOpcode.args[j]) {
903
919
  return false;
904
920
  }
905
- for (var j = 0; j < opcode.args.length; j++) {
906
- if (opcode.args[j] !== otherOpcode.args[j]) {
907
- return false;
908
- }
909
- }
910
921
  }
911
- return true;
912
- },
922
+ }
913
923
 
914
- guid: 0,
915
-
916
- compile: function(program, options) {
917
- this.children = [];
918
- this.depths = {list: []};
919
- this.options = options;
920
-
921
- // These changes will propagate to the other compiler components
922
- var knownHelpers = this.options.knownHelpers;
923
- this.options.knownHelpers = {
924
- 'helperMissing': true,
925
- 'blockHelperMissing': true,
926
- 'each': true,
927
- 'if': true,
928
- 'unless': true,
929
- 'with': true,
930
- 'log': true
931
- };
932
- if (knownHelpers) {
933
- for (var name in knownHelpers) {
934
- this.options.knownHelpers[name] = knownHelpers[name];
935
- }
924
+ len = this.children.length;
925
+ if (other.children.length !== len) {
926
+ return false;
927
+ }
928
+ for (i = 0; i < len; i++) {
929
+ if (!this.children[i].equals(other.children[i])) {
930
+ return false;
936
931
  }
932
+ }
937
933
 
938
- return this.program(program);
939
- },
934
+ return true;
935
+ },
940
936
 
941
- accept: function(node) {
942
- return this[node.type](node);
943
- },
937
+ guid: 0,
938
+
939
+ compile: function(program, options) {
940
+ this.children = [];
941
+ this.depths = {list: []};
942
+ this.options = options;
943
+
944
+ // These changes will propagate to the other compiler components
945
+ var knownHelpers = this.options.knownHelpers;
946
+ this.options.knownHelpers = {
947
+ 'helperMissing': true,
948
+ 'blockHelperMissing': true,
949
+ 'each': true,
950
+ 'if': true,
951
+ 'unless': true,
952
+ 'with': true,
953
+ 'log': true
954
+ };
955
+ if (knownHelpers) {
956
+ for (var name in knownHelpers) {
957
+ this.options.knownHelpers[name] = knownHelpers[name];
958
+ }
959
+ }
944
960
 
945
- program: function(program) {
946
- var statements = program.statements, statement;
947
- this.opcodes = [];
961
+ return this.program(program);
962
+ },
948
963
 
949
- for(var i=0, l=statements.length; i<l; i++) {
950
- statement = statements[i];
951
- this[statement.type](statement);
952
- }
953
- this.isSimple = l === 1;
964
+ accept: function(node) {
965
+ return this[node.type](node);
966
+ },
954
967
 
955
- this.depths.list = this.depths.list.sort(function(a, b) {
956
- return a - b;
957
- });
968
+ program: function(program) {
969
+ var statements = program.statements, statement;
970
+ this.opcodes = [];
958
971
 
959
- return this;
960
- },
972
+ for(var i=0, l=statements.length; i<l; i++) {
973
+ statement = statements[i];
974
+ this[statement.type](statement);
975
+ }
976
+ this.isSimple = l === 1;
961
977
 
962
- compileProgram: function(program) {
963
- var result = new this.compiler().compile(program, this.options);
964
- var guid = this.guid++, depth;
978
+ this.depths.list = this.depths.list.sort(function(a, b) {
979
+ return a - b;
980
+ });
965
981
 
966
- this.usePartial = this.usePartial || result.usePartial;
982
+ return this;
983
+ },
967
984
 
968
- this.children[guid] = result;
985
+ compileProgram: function(program) {
986
+ var result = new this.compiler().compile(program, this.options);
987
+ var guid = this.guid++, depth;
969
988
 
970
- for(var i=0, l=result.depths.list.length; i<l; i++) {
971
- depth = result.depths.list[i];
989
+ this.usePartial = this.usePartial || result.usePartial;
972
990
 
973
- if(depth < 2) { continue; }
974
- else { this.addDepth(depth - 1); }
975
- }
991
+ this.children[guid] = result;
976
992
 
977
- return guid;
978
- },
993
+ for(var i=0, l=result.depths.list.length; i<l; i++) {
994
+ depth = result.depths.list[i];
979
995
 
980
- block: function(block) {
981
- var mustache = block.mustache,
982
- program = block.program,
983
- inverse = block.inverse;
996
+ if(depth < 2) { continue; }
997
+ else { this.addDepth(depth - 1); }
998
+ }
984
999
 
985
- if (program) {
986
- program = this.compileProgram(program);
987
- }
1000
+ return guid;
1001
+ },
988
1002
 
989
- if (inverse) {
990
- inverse = this.compileProgram(inverse);
991
- }
1003
+ block: function(block) {
1004
+ var mustache = block.mustache,
1005
+ program = block.program,
1006
+ inverse = block.inverse;
992
1007
 
993
- var type = this.classifyMustache(mustache);
1008
+ if (program) {
1009
+ program = this.compileProgram(program);
1010
+ }
994
1011
 
995
- if (type === "helper") {
996
- this.helperMustache(mustache, program, inverse);
997
- } else if (type === "simple") {
998
- this.simpleMustache(mustache);
1012
+ if (inverse) {
1013
+ inverse = this.compileProgram(inverse);
1014
+ }
999
1015
 
1000
- // now that the simple mustache is resolved, we need to
1001
- // evaluate it by executing `blockHelperMissing`
1002
- this.opcode('pushProgram', program);
1003
- this.opcode('pushProgram', inverse);
1004
- this.opcode('emptyHash');
1005
- this.opcode('blockValue');
1006
- } else {
1007
- this.ambiguousMustache(mustache, program, inverse);
1008
-
1009
- // now that the simple mustache is resolved, we need to
1010
- // evaluate it by executing `blockHelperMissing`
1011
- this.opcode('pushProgram', program);
1012
- this.opcode('pushProgram', inverse);
1013
- this.opcode('emptyHash');
1014
- this.opcode('ambiguousBlockValue');
1015
- }
1016
+ var type = this.classifyMustache(mustache);
1016
1017
 
1017
- this.opcode('append');
1018
- },
1018
+ if (type === "helper") {
1019
+ this.helperMustache(mustache, program, inverse);
1020
+ } else if (type === "simple") {
1021
+ this.simpleMustache(mustache);
1019
1022
 
1020
- hash: function(hash) {
1021
- var pairs = hash.pairs, pair, val;
1023
+ // now that the simple mustache is resolved, we need to
1024
+ // evaluate it by executing `blockHelperMissing`
1025
+ this.opcode('pushProgram', program);
1026
+ this.opcode('pushProgram', inverse);
1027
+ this.opcode('emptyHash');
1028
+ this.opcode('blockValue');
1029
+ } else {
1030
+ this.ambiguousMustache(mustache, program, inverse);
1022
1031
 
1023
- this.opcode('pushHash');
1032
+ // now that the simple mustache is resolved, we need to
1033
+ // evaluate it by executing `blockHelperMissing`
1034
+ this.opcode('pushProgram', program);
1035
+ this.opcode('pushProgram', inverse);
1036
+ this.opcode('emptyHash');
1037
+ this.opcode('ambiguousBlockValue');
1038
+ }
1024
1039
 
1025
- for(var i=0, l=pairs.length; i<l; i++) {
1026
- pair = pairs[i];
1027
- val = pair[1];
1040
+ this.opcode('append');
1041
+ },
1028
1042
 
1029
- if (this.options.stringParams) {
1030
- this.opcode('pushStringParam', val.stringModeValue, val.type);
1031
- } else {
1032
- this.accept(val);
1033
- }
1043
+ hash: function(hash) {
1044
+ var pairs = hash.pairs, pair, val;
1034
1045
 
1035
- this.opcode('assignToHash', pair[0]);
1036
- }
1037
- this.opcode('popHash');
1038
- },
1046
+ this.opcode('pushHash');
1039
1047
 
1040
- partial: function(partial) {
1041
- var partialName = partial.partialName;
1042
- this.usePartial = true;
1048
+ for(var i=0, l=pairs.length; i<l; i++) {
1049
+ pair = pairs[i];
1050
+ val = pair[1];
1043
1051
 
1044
- if(partial.context) {
1045
- this.ID(partial.context);
1052
+ if (this.options.stringParams) {
1053
+ if(val.depth) {
1054
+ this.addDepth(val.depth);
1055
+ }
1056
+ this.opcode('getContext', val.depth || 0);
1057
+ this.opcode('pushStringParam', val.stringModeValue, val.type);
1046
1058
  } else {
1047
- this.opcode('push', 'depth0');
1059
+ this.accept(val);
1048
1060
  }
1049
1061
 
1050
- this.opcode('invokePartial', partialName.name);
1051
- this.opcode('append');
1052
- },
1053
-
1054
- content: function(content) {
1055
- this.opcode('appendContent', content.string);
1056
- },
1062
+ this.opcode('assignToHash', pair[0]);
1063
+ }
1064
+ this.opcode('popHash');
1065
+ },
1057
1066
 
1058
- mustache: function(mustache) {
1059
- var options = this.options;
1060
- var type = this.classifyMustache(mustache);
1067
+ partial: function(partial) {
1068
+ var partialName = partial.partialName;
1069
+ this.usePartial = true;
1061
1070
 
1062
- if (type === "simple") {
1063
- this.simpleMustache(mustache);
1064
- } else if (type === "helper") {
1065
- this.helperMustache(mustache);
1066
- } else {
1067
- this.ambiguousMustache(mustache);
1068
- }
1071
+ if(partial.context) {
1072
+ this.ID(partial.context);
1073
+ } else {
1074
+ this.opcode('push', 'depth0');
1075
+ }
1069
1076
 
1070
- if(mustache.escaped && !options.noEscape) {
1071
- this.opcode('appendEscaped');
1072
- } else {
1073
- this.opcode('append');
1074
- }
1075
- },
1077
+ this.opcode('invokePartial', partialName.name);
1078
+ this.opcode('append');
1079
+ },
1076
1080
 
1077
- ambiguousMustache: function(mustache, program, inverse) {
1078
- var id = mustache.id,
1079
- name = id.parts[0],
1080
- isBlock = program != null || inverse != null;
1081
+ content: function(content) {
1082
+ this.opcode('appendContent', content.string);
1083
+ },
1081
1084
 
1082
- this.opcode('getContext', id.depth);
1085
+ mustache: function(mustache) {
1086
+ var options = this.options;
1087
+ var type = this.classifyMustache(mustache);
1083
1088
 
1084
- this.opcode('pushProgram', program);
1085
- this.opcode('pushProgram', inverse);
1089
+ if (type === "simple") {
1090
+ this.simpleMustache(mustache);
1091
+ } else if (type === "helper") {
1092
+ this.helperMustache(mustache);
1093
+ } else {
1094
+ this.ambiguousMustache(mustache);
1095
+ }
1086
1096
 
1087
- this.opcode('invokeAmbiguous', name, isBlock);
1088
- },
1097
+ if(mustache.escaped && !options.noEscape) {
1098
+ this.opcode('appendEscaped');
1099
+ } else {
1100
+ this.opcode('append');
1101
+ }
1102
+ },
1089
1103
 
1090
- simpleMustache: function(mustache) {
1091
- var id = mustache.id;
1104
+ ambiguousMustache: function(mustache, program, inverse) {
1105
+ var id = mustache.id,
1106
+ name = id.parts[0],
1107
+ isBlock = program != null || inverse != null;
1092
1108
 
1093
- if (id.type === 'DATA') {
1094
- this.DATA(id);
1095
- } else if (id.parts.length) {
1096
- this.ID(id);
1097
- } else {
1098
- // Simplified ID for `this`
1099
- this.addDepth(id.depth);
1100
- this.opcode('getContext', id.depth);
1101
- this.opcode('pushContext');
1102
- }
1109
+ this.opcode('getContext', id.depth);
1103
1110
 
1104
- this.opcode('resolvePossibleLambda');
1105
- },
1111
+ this.opcode('pushProgram', program);
1112
+ this.opcode('pushProgram', inverse);
1106
1113
 
1107
- helperMustache: function(mustache, program, inverse) {
1108
- var params = this.setupFullMustacheParams(mustache, program, inverse),
1109
- name = mustache.id.parts[0];
1114
+ this.opcode('invokeAmbiguous', name, isBlock);
1115
+ },
1110
1116
 
1111
- if (this.options.knownHelpers[name]) {
1112
- this.opcode('invokeKnownHelper', params.length, name);
1113
- } else if (this.knownHelpersOnly) {
1114
- throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
1115
- } else {
1116
- this.opcode('invokeHelper', params.length, name);
1117
- }
1118
- },
1117
+ simpleMustache: function(mustache) {
1118
+ var id = mustache.id;
1119
1119
 
1120
- ID: function(id) {
1120
+ if (id.type === 'DATA') {
1121
+ this.DATA(id);
1122
+ } else if (id.parts.length) {
1123
+ this.ID(id);
1124
+ } else {
1125
+ // Simplified ID for `this`
1121
1126
  this.addDepth(id.depth);
1122
1127
  this.opcode('getContext', id.depth);
1128
+ this.opcode('pushContext');
1129
+ }
1123
1130
 
1124
- var name = id.parts[0];
1125
- if (!name) {
1126
- this.opcode('pushContext');
1127
- } else {
1128
- this.opcode('lookupOnContext', id.parts[0]);
1129
- }
1130
-
1131
- for(var i=1, l=id.parts.length; i<l; i++) {
1132
- this.opcode('lookup', id.parts[i]);
1133
- }
1134
- },
1131
+ this.opcode('resolvePossibleLambda');
1132
+ },
1135
1133
 
1136
- DATA: function(data) {
1137
- this.options.data = true;
1138
- this.opcode('lookupData', data.id);
1139
- },
1134
+ helperMustache: function(mustache, program, inverse) {
1135
+ var params = this.setupFullMustacheParams(mustache, program, inverse),
1136
+ name = mustache.id.parts[0];
1140
1137
 
1141
- STRING: function(string) {
1142
- this.opcode('pushString', string.string);
1143
- },
1138
+ if (this.options.knownHelpers[name]) {
1139
+ this.opcode('invokeKnownHelper', params.length, name);
1140
+ } else if (this.options.knownHelpersOnly) {
1141
+ throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
1142
+ } else {
1143
+ this.opcode('invokeHelper', params.length, name);
1144
+ }
1145
+ },
1144
1146
 
1145
- INTEGER: function(integer) {
1146
- this.opcode('pushLiteral', integer.integer);
1147
- },
1147
+ ID: function(id) {
1148
+ this.addDepth(id.depth);
1149
+ this.opcode('getContext', id.depth);
1148
1150
 
1149
- BOOLEAN: function(bool) {
1150
- this.opcode('pushLiteral', bool.bool);
1151
- },
1151
+ var name = id.parts[0];
1152
+ if (!name) {
1153
+ this.opcode('pushContext');
1154
+ } else {
1155
+ this.opcode('lookupOnContext', id.parts[0]);
1156
+ }
1152
1157
 
1153
- comment: function() {},
1158
+ for(var i=1, l=id.parts.length; i<l; i++) {
1159
+ this.opcode('lookup', id.parts[i]);
1160
+ }
1161
+ },
1154
1162
 
1155
- // HELPERS
1156
- opcode: function(name) {
1157
- this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
1158
- },
1163
+ DATA: function(data) {
1164
+ this.options.data = true;
1165
+ this.opcode('lookupData', data.id);
1166
+ },
1159
1167
 
1160
- declare: function(name, value) {
1161
- this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
1162
- },
1168
+ STRING: function(string) {
1169
+ this.opcode('pushString', string.string);
1170
+ },
1163
1171
 
1164
- addDepth: function(depth) {
1165
- if(isNaN(depth)) { throw new Error("EWOT"); }
1166
- if(depth === 0) { return; }
1172
+ INTEGER: function(integer) {
1173
+ this.opcode('pushLiteral', integer.integer);
1174
+ },
1167
1175
 
1168
- if(!this.depths[depth]) {
1169
- this.depths[depth] = true;
1170
- this.depths.list.push(depth);
1171
- }
1172
- },
1176
+ BOOLEAN: function(bool) {
1177
+ this.opcode('pushLiteral', bool.bool);
1178
+ },
1173
1179
 
1174
- classifyMustache: function(mustache) {
1175
- var isHelper = mustache.isHelper;
1176
- var isEligible = mustache.eligibleHelper;
1177
- var options = this.options;
1180
+ comment: function() {},
1178
1181
 
1179
- // if ambiguous, we can possibly resolve the ambiguity now
1180
- if (isEligible && !isHelper) {
1181
- var name = mustache.id.parts[0];
1182
+ // HELPERS
1183
+ opcode: function(name) {
1184
+ this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
1185
+ },
1182
1186
 
1183
- if (options.knownHelpers[name]) {
1184
- isHelper = true;
1185
- } else if (options.knownHelpersOnly) {
1186
- isEligible = false;
1187
- }
1188
- }
1187
+ declare: function(name, value) {
1188
+ this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
1189
+ },
1189
1190
 
1190
- if (isHelper) { return "helper"; }
1191
- else if (isEligible) { return "ambiguous"; }
1192
- else { return "simple"; }
1193
- },
1191
+ addDepth: function(depth) {
1192
+ if(isNaN(depth)) { throw new Error("EWOT"); }
1193
+ if(depth === 0) { return; }
1194
1194
 
1195
- pushParams: function(params) {
1196
- var i = params.length, param;
1195
+ if(!this.depths[depth]) {
1196
+ this.depths[depth] = true;
1197
+ this.depths.list.push(depth);
1198
+ }
1199
+ },
1197
1200
 
1198
- while(i--) {
1199
- param = params[i];
1201
+ classifyMustache: function(mustache) {
1202
+ var isHelper = mustache.isHelper;
1203
+ var isEligible = mustache.eligibleHelper;
1204
+ var options = this.options;
1200
1205
 
1201
- if(this.options.stringParams) {
1202
- if(param.depth) {
1203
- this.addDepth(param.depth);
1204
- }
1206
+ // if ambiguous, we can possibly resolve the ambiguity now
1207
+ if (isEligible && !isHelper) {
1208
+ var name = mustache.id.parts[0];
1205
1209
 
1206
- this.opcode('getContext', param.depth || 0);
1207
- this.opcode('pushStringParam', param.stringModeValue, param.type);
1208
- } else {
1209
- this[param.type](param);
1210
- }
1210
+ if (options.knownHelpers[name]) {
1211
+ isHelper = true;
1212
+ } else if (options.knownHelpersOnly) {
1213
+ isEligible = false;
1211
1214
  }
1212
- },
1213
-
1214
- setupMustacheParams: function(mustache) {
1215
- var params = mustache.params;
1216
- this.pushParams(params);
1215
+ }
1217
1216
 
1218
- if(mustache.hash) {
1219
- this.hash(mustache.hash);
1220
- } else {
1221
- this.opcode('emptyHash');
1222
- }
1217
+ if (isHelper) { return "helper"; }
1218
+ else if (isEligible) { return "ambiguous"; }
1219
+ else { return "simple"; }
1220
+ },
1223
1221
 
1224
- return params;
1225
- },
1222
+ pushParams: function(params) {
1223
+ var i = params.length, param;
1226
1224
 
1227
- // this will replace setupMustacheParams when we're done
1228
- setupFullMustacheParams: function(mustache, program, inverse) {
1229
- var params = mustache.params;
1230
- this.pushParams(params);
1225
+ while(i--) {
1226
+ param = params[i];
1231
1227
 
1232
- this.opcode('pushProgram', program);
1233
- this.opcode('pushProgram', inverse);
1228
+ if(this.options.stringParams) {
1229
+ if(param.depth) {
1230
+ this.addDepth(param.depth);
1231
+ }
1234
1232
 
1235
- if(mustache.hash) {
1236
- this.hash(mustache.hash);
1233
+ this.opcode('getContext', param.depth || 0);
1234
+ this.opcode('pushStringParam', param.stringModeValue, param.type);
1237
1235
  } else {
1238
- this.opcode('emptyHash');
1236
+ this[param.type](param);
1239
1237
  }
1238
+ }
1239
+ },
1240
+
1241
+ setupMustacheParams: function(mustache) {
1242
+ var params = mustache.params;
1243
+ this.pushParams(params);
1240
1244
 
1241
- return params;
1245
+ if(mustache.hash) {
1246
+ this.hash(mustache.hash);
1247
+ } else {
1248
+ this.opcode('emptyHash');
1242
1249
  }
1243
- };
1244
1250
 
1245
- var Literal = function(value) {
1246
- this.value = value;
1247
- };
1251
+ return params;
1252
+ },
1248
1253
 
1249
- JavaScriptCompiler.prototype = {
1250
- // PUBLIC API: You can override these methods in a subclass to provide
1251
- // alternative compiled forms for name lookup and buffering semantics
1252
- nameLookup: function(parent, name /* , type*/) {
1253
- if (/^[0-9]+$/.test(name)) {
1254
- return parent + "[" + name + "]";
1255
- } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1256
- return parent + "." + name;
1257
- }
1258
- else {
1259
- return parent + "['" + name + "']";
1260
- }
1261
- },
1254
+ // this will replace setupMustacheParams when we're done
1255
+ setupFullMustacheParams: function(mustache, program, inverse) {
1256
+ var params = mustache.params;
1257
+ this.pushParams(params);
1262
1258
 
1263
- appendToBuffer: function(string) {
1264
- if (this.environment.isSimple) {
1265
- return "return " + string + ";";
1266
- } else {
1267
- return {
1268
- appendToBuffer: true,
1269
- content: string,
1270
- toString: function() { return "buffer += " + string + ";"; }
1271
- };
1272
- }
1273
- },
1259
+ this.opcode('pushProgram', program);
1260
+ this.opcode('pushProgram', inverse);
1274
1261
 
1275
- initializeBuffer: function() {
1276
- return this.quotedString("");
1277
- },
1262
+ if(mustache.hash) {
1263
+ this.hash(mustache.hash);
1264
+ } else {
1265
+ this.opcode('emptyHash');
1266
+ }
1278
1267
 
1279
- namespace: "Handlebars",
1280
- // END PUBLIC API
1268
+ return params;
1269
+ }
1270
+ };
1281
1271
 
1282
- compile: function(environment, options, context, asObject) {
1283
- this.environment = environment;
1284
- this.options = options || {};
1272
+ var Literal = function(value) {
1273
+ this.value = value;
1274
+ };
1285
1275
 
1286
- Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
1276
+ JavaScriptCompiler.prototype = {
1277
+ // PUBLIC API: You can override these methods in a subclass to provide
1278
+ // alternative compiled forms for name lookup and buffering semantics
1279
+ nameLookup: function(parent, name /* , type*/) {
1280
+ if (/^[0-9]+$/.test(name)) {
1281
+ return parent + "[" + name + "]";
1282
+ } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1283
+ return parent + "." + name;
1284
+ }
1285
+ else {
1286
+ return parent + "['" + name + "']";
1287
+ }
1288
+ },
1287
1289
 
1288
- this.name = this.environment.name;
1289
- this.isChild = !!context;
1290
- this.context = context || {
1291
- programs: [],
1292
- environments: [],
1293
- aliases: { }
1290
+ appendToBuffer: function(string) {
1291
+ if (this.environment.isSimple) {
1292
+ return "return " + string + ";";
1293
+ } else {
1294
+ return {
1295
+ appendToBuffer: true,
1296
+ content: string,
1297
+ toString: function() { return "buffer += " + string + ";"; }
1294
1298
  };
1299
+ }
1300
+ },
1295
1301
 
1296
- this.preamble();
1302
+ initializeBuffer: function() {
1303
+ return this.quotedString("");
1304
+ },
1297
1305
 
1298
- this.stackSlot = 0;
1299
- this.stackVars = [];
1300
- this.registers = { list: [] };
1301
- this.compileStack = [];
1302
- this.inlineStack = [];
1306
+ namespace: "Handlebars",
1307
+ // END PUBLIC API
1303
1308
 
1304
- this.compileChildren(environment, options);
1309
+ compile: function(environment, options, context, asObject) {
1310
+ this.environment = environment;
1311
+ this.options = options || {};
1305
1312
 
1306
- var opcodes = environment.opcodes, opcode;
1313
+ Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
1307
1314
 
1308
- this.i = 0;
1315
+ this.name = this.environment.name;
1316
+ this.isChild = !!context;
1317
+ this.context = context || {
1318
+ programs: [],
1319
+ environments: [],
1320
+ aliases: { }
1321
+ };
1309
1322
 
1310
- for(l=opcodes.length; this.i<l; this.i++) {
1311
- opcode = opcodes[this.i];
1323
+ this.preamble();
1312
1324
 
1313
- if(opcode.opcode === 'DECLARE') {
1314
- this[opcode.name] = opcode.value;
1315
- } else {
1316
- this[opcode.opcode].apply(this, opcode.args);
1317
- }
1318
- }
1325
+ this.stackSlot = 0;
1326
+ this.stackVars = [];
1327
+ this.registers = { list: [] };
1328
+ this.compileStack = [];
1329
+ this.inlineStack = [];
1319
1330
 
1320
- return this.createFunctionContext(asObject);
1321
- },
1331
+ this.compileChildren(environment, options);
1322
1332
 
1323
- nextOpcode: function() {
1324
- var opcodes = this.environment.opcodes;
1325
- return opcodes[this.i + 1];
1326
- },
1333
+ var opcodes = environment.opcodes, opcode;
1327
1334
 
1328
- eat: function() {
1329
- this.i = this.i + 1;
1330
- },
1335
+ this.i = 0;
1331
1336
 
1332
- preamble: function() {
1333
- var out = [];
1337
+ for(l=opcodes.length; this.i<l; this.i++) {
1338
+ opcode = opcodes[this.i];
1334
1339
 
1335
- if (!this.isChild) {
1336
- var namespace = this.namespace;
1337
- var copies = "helpers = helpers || " + namespace + ".helpers;";
1338
- if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
1339
- if (this.options.data) { copies = copies + " data = data || {};"; }
1340
- out.push(copies);
1340
+ if(opcode.opcode === 'DECLARE') {
1341
+ this[opcode.name] = opcode.value;
1341
1342
  } else {
1342
- out.push('');
1343
+ this[opcode.opcode].apply(this, opcode.args);
1343
1344
  }
1345
+ }
1344
1346
 
1345
- if (!this.environment.isSimple) {
1346
- out.push(", buffer = " + this.initializeBuffer());
1347
- } else {
1348
- out.push("");
1349
- }
1347
+ return this.createFunctionContext(asObject);
1348
+ },
1350
1349
 
1351
- // track the last context pushed into place to allow skipping the
1352
- // getContext opcode when it would be a noop
1353
- this.lastContext = 0;
1354
- this.source = out;
1355
- },
1350
+ nextOpcode: function() {
1351
+ var opcodes = this.environment.opcodes;
1352
+ return opcodes[this.i + 1];
1353
+ },
1356
1354
 
1357
- createFunctionContext: function(asObject) {
1358
- var locals = this.stackVars.concat(this.registers.list);
1355
+ eat: function() {
1356
+ this.i = this.i + 1;
1357
+ },
1359
1358
 
1360
- if(locals.length > 0) {
1361
- this.source[1] = this.source[1] + ", " + locals.join(", ");
1362
- }
1359
+ preamble: function() {
1360
+ var out = [];
1363
1361
 
1364
- // Generate minimizer alias mappings
1365
- if (!this.isChild) {
1366
- for (var alias in this.context.aliases) {
1367
- this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1368
- }
1369
- }
1362
+ if (!this.isChild) {
1363
+ var namespace = this.namespace;
1364
+ var copies = "helpers = helpers || " + namespace + ".helpers;";
1365
+ if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
1366
+ if (this.options.data) { copies = copies + " data = data || {};"; }
1367
+ out.push(copies);
1368
+ } else {
1369
+ out.push('');
1370
+ }
1370
1371
 
1371
- if (this.source[1]) {
1372
- this.source[1] = "var " + this.source[1].substring(2) + ";";
1373
- }
1372
+ if (!this.environment.isSimple) {
1373
+ out.push(", buffer = " + this.initializeBuffer());
1374
+ } else {
1375
+ out.push("");
1376
+ }
1374
1377
 
1375
- // Merge children
1376
- if (!this.isChild) {
1377
- this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1378
- }
1378
+ // track the last context pushed into place to allow skipping the
1379
+ // getContext opcode when it would be a noop
1380
+ this.lastContext = 0;
1381
+ this.source = out;
1382
+ },
1379
1383
 
1380
- if (!this.environment.isSimple) {
1381
- this.source.push("return buffer;");
1382
- }
1384
+ createFunctionContext: function(asObject) {
1385
+ var locals = this.stackVars.concat(this.registers.list);
1383
1386
 
1384
- var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1387
+ if(locals.length > 0) {
1388
+ this.source[1] = this.source[1] + ", " + locals.join(", ");
1389
+ }
1385
1390
 
1386
- for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1387
- params.push("depth" + this.environment.depths.list[i]);
1391
+ // Generate minimizer alias mappings
1392
+ if (!this.isChild) {
1393
+ for (var alias in this.context.aliases) {
1394
+ this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1388
1395
  }
1396
+ }
1389
1397
 
1390
- // Perform a second pass over the output to merge content when possible
1391
- var source = this.mergeSource();
1398
+ if (this.source[1]) {
1399
+ this.source[1] = "var " + this.source[1].substring(2) + ";";
1400
+ }
1392
1401
 
1393
- if (!this.isChild) {
1394
- var revision = Handlebars.COMPILER_REVISION,
1395
- versions = Handlebars.REVISION_CHANGES[revision];
1396
- source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
1397
- }
1402
+ // Merge children
1403
+ if (!this.isChild) {
1404
+ this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1405
+ }
1398
1406
 
1399
- if (asObject) {
1400
- params.push(source);
1407
+ if (!this.environment.isSimple) {
1408
+ this.source.push("return buffer;");
1409
+ }
1401
1410
 
1402
- return Function.apply(this, params);
1403
- } else {
1404
- var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
1405
- Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1406
- return functionSource;
1407
- }
1408
- },
1409
- mergeSource: function() {
1410
- // WARN: We are not handling the case where buffer is still populated as the source should
1411
- // not have buffer append operations as their final action.
1412
- var source = '',
1413
- buffer;
1414
- for (var i = 0, len = this.source.length; i < len; i++) {
1415
- var line = this.source[i];
1416
- if (line.appendToBuffer) {
1417
- if (buffer) {
1418
- buffer = buffer + '\n + ' + line.content;
1419
- } else {
1420
- buffer = line.content;
1421
- }
1411
+ var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1412
+
1413
+ for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1414
+ params.push("depth" + this.environment.depths.list[i]);
1415
+ }
1416
+
1417
+ // Perform a second pass over the output to merge content when possible
1418
+ var source = this.mergeSource();
1419
+
1420
+ if (!this.isChild) {
1421
+ var revision = Handlebars.COMPILER_REVISION,
1422
+ versions = Handlebars.REVISION_CHANGES[revision];
1423
+ source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
1424
+ }
1425
+
1426
+ if (asObject) {
1427
+ params.push(source);
1428
+
1429
+ return Function.apply(this, params);
1430
+ } else {
1431
+ var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
1432
+ Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1433
+ return functionSource;
1434
+ }
1435
+ },
1436
+ mergeSource: function() {
1437
+ // WARN: We are not handling the case where buffer is still populated as the source should
1438
+ // not have buffer append operations as their final action.
1439
+ var source = '',
1440
+ buffer;
1441
+ for (var i = 0, len = this.source.length; i < len; i++) {
1442
+ var line = this.source[i];
1443
+ if (line.appendToBuffer) {
1444
+ if (buffer) {
1445
+ buffer = buffer + '\n + ' + line.content;
1422
1446
  } else {
1423
- if (buffer) {
1424
- source += 'buffer += ' + buffer + ';\n ';
1425
- buffer = undefined;
1426
- }
1427
- source += line + '\n ';
1447
+ buffer = line.content;
1448
+ }
1449
+ } else {
1450
+ if (buffer) {
1451
+ source += 'buffer += ' + buffer + ';\n ';
1452
+ buffer = undefined;
1428
1453
  }
1454
+ source += line + '\n ';
1429
1455
  }
1430
- return source;
1431
- },
1432
-
1433
- // [blockValue]
1434
- //
1435
- // On stack, before: hash, inverse, program, value
1436
- // On stack, after: return value of blockHelperMissing
1437
- //
1438
- // The purpose of this opcode is to take a block of the form
1439
- // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
1440
- // replace it on the stack with the result of properly
1441
- // invoking blockHelperMissing.
1442
- blockValue: function() {
1443
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1444
-
1445
- var params = ["depth0"];
1446
- this.setupParams(0, params);
1447
-
1448
- this.replaceStack(function(current) {
1449
- params.splice(1, 0, current);
1450
- return "blockHelperMissing.call(" + params.join(", ") + ")";
1451
- });
1452
- },
1456
+ }
1457
+ return source;
1458
+ },
1453
1459
 
1454
- // [ambiguousBlockValue]
1455
- //
1456
- // On stack, before: hash, inverse, program, value
1457
- // Compiler value, before: lastHelper=value of last found helper, if any
1458
- // On stack, after, if no lastHelper: same as [blockValue]
1459
- // On stack, after, if lastHelper: value
1460
- ambiguousBlockValue: function() {
1461
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1460
+ // [blockValue]
1461
+ //
1462
+ // On stack, before: hash, inverse, program, value
1463
+ // On stack, after: return value of blockHelperMissing
1464
+ //
1465
+ // The purpose of this opcode is to take a block of the form
1466
+ // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
1467
+ // replace it on the stack with the result of properly
1468
+ // invoking blockHelperMissing.
1469
+ blockValue: function() {
1470
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1471
+
1472
+ var params = ["depth0"];
1473
+ this.setupParams(0, params);
1474
+
1475
+ this.replaceStack(function(current) {
1476
+ params.splice(1, 0, current);
1477
+ return "blockHelperMissing.call(" + params.join(", ") + ")";
1478
+ });
1479
+ },
1462
1480
 
1463
- var params = ["depth0"];
1464
- this.setupParams(0, params);
1481
+ // [ambiguousBlockValue]
1482
+ //
1483
+ // On stack, before: hash, inverse, program, value
1484
+ // Compiler value, before: lastHelper=value of last found helper, if any
1485
+ // On stack, after, if no lastHelper: same as [blockValue]
1486
+ // On stack, after, if lastHelper: value
1487
+ ambiguousBlockValue: function() {
1488
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1465
1489
 
1466
- var current = this.topStack();
1467
- params.splice(1, 0, current);
1490
+ var params = ["depth0"];
1491
+ this.setupParams(0, params);
1468
1492
 
1469
- // Use the options value generated from the invocation
1470
- params[params.length-1] = 'options';
1493
+ var current = this.topStack();
1494
+ params.splice(1, 0, current);
1471
1495
 
1472
- this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
1473
- },
1496
+ // Use the options value generated from the invocation
1497
+ params[params.length-1] = 'options';
1474
1498
 
1475
- // [appendContent]
1476
- //
1477
- // On stack, before: ...
1478
- // On stack, after: ...
1479
- //
1480
- // Appends the string value of `content` to the current buffer
1481
- appendContent: function(content) {
1482
- this.source.push(this.appendToBuffer(this.quotedString(content)));
1483
- },
1499
+ this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
1500
+ },
1484
1501
 
1485
- // [append]
1486
- //
1487
- // On stack, before: value, ...
1488
- // On stack, after: ...
1489
- //
1490
- // Coerces `value` to a String and appends it to the current buffer.
1491
- //
1492
- // If `value` is truthy, or 0, it is coerced into a string and appended
1493
- // Otherwise, the empty string is appended
1494
- append: function() {
1495
- // Force anything that is inlined onto the stack so we don't have duplication
1496
- // when we examine local
1497
- this.flushInline();
1498
- var local = this.popStack();
1499
- this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1500
- if (this.environment.isSimple) {
1501
- this.source.push("else { " + this.appendToBuffer("''") + " }");
1502
- }
1503
- },
1502
+ // [appendContent]
1503
+ //
1504
+ // On stack, before: ...
1505
+ // On stack, after: ...
1506
+ //
1507
+ // Appends the string value of `content` to the current buffer
1508
+ appendContent: function(content) {
1509
+ this.source.push(this.appendToBuffer(this.quotedString(content)));
1510
+ },
1504
1511
 
1505
- // [appendEscaped]
1506
- //
1507
- // On stack, before: value, ...
1508
- // On stack, after: ...
1509
- //
1510
- // Escape `value` and append it to the buffer
1511
- appendEscaped: function() {
1512
- this.context.aliases.escapeExpression = 'this.escapeExpression';
1512
+ // [append]
1513
+ //
1514
+ // On stack, before: value, ...
1515
+ // On stack, after: ...
1516
+ //
1517
+ // Coerces `value` to a String and appends it to the current buffer.
1518
+ //
1519
+ // If `value` is truthy, or 0, it is coerced into a string and appended
1520
+ // Otherwise, the empty string is appended
1521
+ append: function() {
1522
+ // Force anything that is inlined onto the stack so we don't have duplication
1523
+ // when we examine local
1524
+ this.flushInline();
1525
+ var local = this.popStack();
1526
+ this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1527
+ if (this.environment.isSimple) {
1528
+ this.source.push("else { " + this.appendToBuffer("''") + " }");
1529
+ }
1530
+ },
1513
1531
 
1514
- this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
1515
- },
1532
+ // [appendEscaped]
1533
+ //
1534
+ // On stack, before: value, ...
1535
+ // On stack, after: ...
1536
+ //
1537
+ // Escape `value` and append it to the buffer
1538
+ appendEscaped: function() {
1539
+ this.context.aliases.escapeExpression = 'this.escapeExpression';
1516
1540
 
1517
- // [getContext]
1518
- //
1519
- // On stack, before: ...
1520
- // On stack, after: ...
1521
- // Compiler value, after: lastContext=depth
1522
- //
1523
- // Set the value of the `lastContext` compiler value to the depth
1524
- getContext: function(depth) {
1525
- if(this.lastContext !== depth) {
1526
- this.lastContext = depth;
1527
- }
1528
- },
1541
+ this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
1542
+ },
1529
1543
 
1530
- // [lookupOnContext]
1531
- //
1532
- // On stack, before: ...
1533
- // On stack, after: currentContext[name], ...
1534
- //
1535
- // Looks up the value of `name` on the current context and pushes
1536
- // it onto the stack.
1537
- lookupOnContext: function(name) {
1538
- this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
1539
- },
1544
+ // [getContext]
1545
+ //
1546
+ // On stack, before: ...
1547
+ // On stack, after: ...
1548
+ // Compiler value, after: lastContext=depth
1549
+ //
1550
+ // Set the value of the `lastContext` compiler value to the depth
1551
+ getContext: function(depth) {
1552
+ if(this.lastContext !== depth) {
1553
+ this.lastContext = depth;
1554
+ }
1555
+ },
1540
1556
 
1541
- // [pushContext]
1542
- //
1543
- // On stack, before: ...
1544
- // On stack, after: currentContext, ...
1545
- //
1546
- // Pushes the value of the current context onto the stack.
1547
- pushContext: function() {
1548
- this.pushStackLiteral('depth' + this.lastContext);
1549
- },
1557
+ // [lookupOnContext]
1558
+ //
1559
+ // On stack, before: ...
1560
+ // On stack, after: currentContext[name], ...
1561
+ //
1562
+ // Looks up the value of `name` on the current context and pushes
1563
+ // it onto the stack.
1564
+ lookupOnContext: function(name) {
1565
+ this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
1566
+ },
1550
1567
 
1551
- // [resolvePossibleLambda]
1552
- //
1553
- // On stack, before: value, ...
1554
- // On stack, after: resolved value, ...
1555
- //
1556
- // If the `value` is a lambda, replace it on the stack by
1557
- // the return value of the lambda
1558
- resolvePossibleLambda: function() {
1559
- this.context.aliases.functionType = '"function"';
1560
-
1561
- this.replaceStack(function(current) {
1562
- return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
1563
- });
1564
- },
1568
+ // [pushContext]
1569
+ //
1570
+ // On stack, before: ...
1571
+ // On stack, after: currentContext, ...
1572
+ //
1573
+ // Pushes the value of the current context onto the stack.
1574
+ pushContext: function() {
1575
+ this.pushStackLiteral('depth' + this.lastContext);
1576
+ },
1565
1577
 
1566
- // [lookup]
1567
- //
1568
- // On stack, before: value, ...
1569
- // On stack, after: value[name], ...
1570
- //
1571
- // Replace the value on the stack with the result of looking
1572
- // up `name` on `value`
1573
- lookup: function(name) {
1574
- this.replaceStack(function(current) {
1575
- return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
1576
- });
1577
- },
1578
+ // [resolvePossibleLambda]
1579
+ //
1580
+ // On stack, before: value, ...
1581
+ // On stack, after: resolved value, ...
1582
+ //
1583
+ // If the `value` is a lambda, replace it on the stack by
1584
+ // the return value of the lambda
1585
+ resolvePossibleLambda: function() {
1586
+ this.context.aliases.functionType = '"function"';
1587
+
1588
+ this.replaceStack(function(current) {
1589
+ return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
1590
+ });
1591
+ },
1578
1592
 
1579
- // [lookupData]
1580
- //
1581
- // On stack, before: ...
1582
- // On stack, after: data[id], ...
1583
- //
1584
- // Push the result of looking up `id` on the current data
1585
- lookupData: function(id) {
1586
- this.push(this.nameLookup('data', id, 'data'));
1587
- },
1593
+ // [lookup]
1594
+ //
1595
+ // On stack, before: value, ...
1596
+ // On stack, after: value[name], ...
1597
+ //
1598
+ // Replace the value on the stack with the result of looking
1599
+ // up `name` on `value`
1600
+ lookup: function(name) {
1601
+ this.replaceStack(function(current) {
1602
+ return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
1603
+ });
1604
+ },
1588
1605
 
1589
- // [pushStringParam]
1590
- //
1591
- // On stack, before: ...
1592
- // On stack, after: string, currentContext, ...
1593
- //
1594
- // This opcode is designed for use in string mode, which
1595
- // provides the string value of a parameter along with its
1596
- // depth rather than resolving it immediately.
1597
- pushStringParam: function(string, type) {
1598
- this.pushStackLiteral('depth' + this.lastContext);
1599
-
1600
- this.pushString(type);
1601
-
1602
- if (typeof string === 'string') {
1603
- this.pushString(string);
1604
- } else {
1605
- this.pushStackLiteral(string);
1606
- }
1607
- },
1606
+ // [lookupData]
1607
+ //
1608
+ // On stack, before: ...
1609
+ // On stack, after: data[id], ...
1610
+ //
1611
+ // Push the result of looking up `id` on the current data
1612
+ lookupData: function(id) {
1613
+ this.push(this.nameLookup('data', id, 'data'));
1614
+ },
1608
1615
 
1609
- emptyHash: function() {
1610
- this.pushStackLiteral('{}');
1616
+ // [pushStringParam]
1617
+ //
1618
+ // On stack, before: ...
1619
+ // On stack, after: string, currentContext, ...
1620
+ //
1621
+ // This opcode is designed for use in string mode, which
1622
+ // provides the string value of a parameter along with its
1623
+ // depth rather than resolving it immediately.
1624
+ pushStringParam: function(string, type) {
1625
+ this.pushStackLiteral('depth' + this.lastContext);
1626
+
1627
+ this.pushString(type);
1628
+
1629
+ if (typeof string === 'string') {
1630
+ this.pushString(string);
1631
+ } else {
1632
+ this.pushStackLiteral(string);
1633
+ }
1634
+ },
1611
1635
 
1612
- if (this.options.stringParams) {
1613
- this.register('hashTypes', '{}');
1614
- }
1615
- },
1616
- pushHash: function() {
1617
- this.hash = {values: [], types: []};
1618
- },
1619
- popHash: function() {
1620
- var hash = this.hash;
1621
- this.hash = undefined;
1636
+ emptyHash: function() {
1637
+ this.pushStackLiteral('{}');
1622
1638
 
1623
- if (this.options.stringParams) {
1624
- this.register('hashTypes', '{' + hash.types.join(',') + '}');
1625
- }
1626
- this.push('{\n ' + hash.values.join(',\n ') + '\n }');
1627
- },
1639
+ if (this.options.stringParams) {
1640
+ this.register('hashTypes', '{}');
1641
+ this.register('hashContexts', '{}');
1642
+ }
1643
+ },
1644
+ pushHash: function() {
1645
+ this.hash = {values: [], types: [], contexts: []};
1646
+ },
1647
+ popHash: function() {
1648
+ var hash = this.hash;
1649
+ this.hash = undefined;
1628
1650
 
1629
- // [pushString]
1630
- //
1631
- // On stack, before: ...
1632
- // On stack, after: quotedString(string), ...
1633
- //
1634
- // Push a quoted version of `string` onto the stack
1635
- pushString: function(string) {
1636
- this.pushStackLiteral(this.quotedString(string));
1637
- },
1651
+ if (this.options.stringParams) {
1652
+ this.register('hashContexts', '{' + hash.contexts.join(',') + '}');
1653
+ this.register('hashTypes', '{' + hash.types.join(',') + '}');
1654
+ }
1655
+ this.push('{\n ' + hash.values.join(',\n ') + '\n }');
1656
+ },
1638
1657
 
1639
- // [push]
1640
- //
1641
- // On stack, before: ...
1642
- // On stack, after: expr, ...
1643
- //
1644
- // Push an expression onto the stack
1645
- push: function(expr) {
1646
- this.inlineStack.push(expr);
1647
- return expr;
1648
- },
1658
+ // [pushString]
1659
+ //
1660
+ // On stack, before: ...
1661
+ // On stack, after: quotedString(string), ...
1662
+ //
1663
+ // Push a quoted version of `string` onto the stack
1664
+ pushString: function(string) {
1665
+ this.pushStackLiteral(this.quotedString(string));
1666
+ },
1649
1667
 
1650
- // [pushLiteral]
1651
- //
1652
- // On stack, before: ...
1653
- // On stack, after: value, ...
1654
- //
1655
- // Pushes a value onto the stack. This operation prevents
1656
- // the compiler from creating a temporary variable to hold
1657
- // it.
1658
- pushLiteral: function(value) {
1659
- this.pushStackLiteral(value);
1660
- },
1668
+ // [push]
1669
+ //
1670
+ // On stack, before: ...
1671
+ // On stack, after: expr, ...
1672
+ //
1673
+ // Push an expression onto the stack
1674
+ push: function(expr) {
1675
+ this.inlineStack.push(expr);
1676
+ return expr;
1677
+ },
1661
1678
 
1662
- // [pushProgram]
1663
- //
1664
- // On stack, before: ...
1665
- // On stack, after: program(guid), ...
1666
- //
1667
- // Push a program expression onto the stack. This takes
1668
- // a compile-time guid and converts it into a runtime-accessible
1669
- // expression.
1670
- pushProgram: function(guid) {
1671
- if (guid != null) {
1672
- this.pushStackLiteral(this.programExpression(guid));
1673
- } else {
1674
- this.pushStackLiteral(null);
1675
- }
1676
- },
1679
+ // [pushLiteral]
1680
+ //
1681
+ // On stack, before: ...
1682
+ // On stack, after: value, ...
1683
+ //
1684
+ // Pushes a value onto the stack. This operation prevents
1685
+ // the compiler from creating a temporary variable to hold
1686
+ // it.
1687
+ pushLiteral: function(value) {
1688
+ this.pushStackLiteral(value);
1689
+ },
1677
1690
 
1678
- // [invokeHelper]
1679
- //
1680
- // On stack, before: hash, inverse, program, params..., ...
1681
- // On stack, after: result of helper invocation
1682
- //
1683
- // Pops off the helper's parameters, invokes the helper,
1684
- // and pushes the helper's return value onto the stack.
1685
- //
1686
- // If the helper is not found, `helperMissing` is called.
1687
- invokeHelper: function(paramSize, name) {
1688
- this.context.aliases.helperMissing = 'helpers.helperMissing';
1689
-
1690
- var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
1691
-
1692
- this.push(helper.name);
1693
- this.replaceStack(function(name) {
1694
- return name + ' ? ' + name + '.call(' +
1695
- helper.callParams + ") " + ": helperMissing.call(" +
1696
- helper.helperMissingParams + ")";
1697
- });
1698
- },
1691
+ // [pushProgram]
1692
+ //
1693
+ // On stack, before: ...
1694
+ // On stack, after: program(guid), ...
1695
+ //
1696
+ // Push a program expression onto the stack. This takes
1697
+ // a compile-time guid and converts it into a runtime-accessible
1698
+ // expression.
1699
+ pushProgram: function(guid) {
1700
+ if (guid != null) {
1701
+ this.pushStackLiteral(this.programExpression(guid));
1702
+ } else {
1703
+ this.pushStackLiteral(null);
1704
+ }
1705
+ },
1699
1706
 
1700
- // [invokeKnownHelper]
1701
- //
1702
- // On stack, before: hash, inverse, program, params..., ...
1703
- // On stack, after: result of helper invocation
1704
- //
1705
- // This operation is used when the helper is known to exist,
1706
- // so a `helperMissing` fallback is not required.
1707
- invokeKnownHelper: function(paramSize, name) {
1708
- var helper = this.setupHelper(paramSize, name);
1709
- this.push(helper.name + ".call(" + helper.callParams + ")");
1710
- },
1707
+ // [invokeHelper]
1708
+ //
1709
+ // On stack, before: hash, inverse, program, params..., ...
1710
+ // On stack, after: result of helper invocation
1711
+ //
1712
+ // Pops off the helper's parameters, invokes the helper,
1713
+ // and pushes the helper's return value onto the stack.
1714
+ //
1715
+ // If the helper is not found, `helperMissing` is called.
1716
+ invokeHelper: function(paramSize, name) {
1717
+ this.context.aliases.helperMissing = 'helpers.helperMissing';
1718
+
1719
+ var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
1720
+
1721
+ this.push(helper.name);
1722
+ this.replaceStack(function(name) {
1723
+ return name + ' ? ' + name + '.call(' +
1724
+ helper.callParams + ") " + ": helperMissing.call(" +
1725
+ helper.helperMissingParams + ")";
1726
+ });
1727
+ },
1711
1728
 
1712
- // [invokeAmbiguous]
1713
- //
1714
- // On stack, before: hash, inverse, program, params..., ...
1715
- // On stack, after: result of disambiguation
1716
- //
1717
- // This operation is used when an expression like `{{foo}}`
1718
- // is provided, but we don't know at compile-time whether it
1719
- // is a helper or a path.
1720
- //
1721
- // This operation emits more code than the other options,
1722
- // and can be avoided by passing the `knownHelpers` and
1723
- // `knownHelpersOnly` flags at compile-time.
1724
- invokeAmbiguous: function(name, helperCall) {
1725
- this.context.aliases.functionType = '"function"';
1726
-
1727
- this.pushStackLiteral('{}'); // Hash value
1728
- var helper = this.setupHelper(0, name, helperCall);
1729
-
1730
- var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
1731
-
1732
- var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1733
- var nextStack = this.nextStack();
1734
-
1735
- this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
1736
- this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }');
1737
- },
1729
+ // [invokeKnownHelper]
1730
+ //
1731
+ // On stack, before: hash, inverse, program, params..., ...
1732
+ // On stack, after: result of helper invocation
1733
+ //
1734
+ // This operation is used when the helper is known to exist,
1735
+ // so a `helperMissing` fallback is not required.
1736
+ invokeKnownHelper: function(paramSize, name) {
1737
+ var helper = this.setupHelper(paramSize, name);
1738
+ this.push(helper.name + ".call(" + helper.callParams + ")");
1739
+ },
1738
1740
 
1739
- // [invokePartial]
1740
- //
1741
- // On stack, before: context, ...
1742
- // On stack after: result of partial invocation
1743
- //
1744
- // This operation pops off a context, invokes a partial with that context,
1745
- // and pushes the result of the invocation back.
1746
- invokePartial: function(name) {
1747
- var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
1748
-
1749
- if (this.options.data) {
1750
- params.push("data");
1751
- }
1741
+ // [invokeAmbiguous]
1742
+ //
1743
+ // On stack, before: hash, inverse, program, params..., ...
1744
+ // On stack, after: result of disambiguation
1745
+ //
1746
+ // This operation is used when an expression like `{{foo}}`
1747
+ // is provided, but we don't know at compile-time whether it
1748
+ // is a helper or a path.
1749
+ //
1750
+ // This operation emits more code than the other options,
1751
+ // and can be avoided by passing the `knownHelpers` and
1752
+ // `knownHelpersOnly` flags at compile-time.
1753
+ invokeAmbiguous: function(name, helperCall) {
1754
+ this.context.aliases.functionType = '"function"';
1755
+
1756
+ this.pushStackLiteral('{}'); // Hash value
1757
+ var helper = this.setupHelper(0, name, helperCall);
1758
+
1759
+ var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
1760
+
1761
+ var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1762
+ var nextStack = this.nextStack();
1763
+
1764
+ this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
1765
+ this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }');
1766
+ },
1752
1767
 
1753
- this.context.aliases.self = "this";
1754
- this.push("self.invokePartial(" + params.join(", ") + ")");
1755
- },
1768
+ // [invokePartial]
1769
+ //
1770
+ // On stack, before: context, ...
1771
+ // On stack after: result of partial invocation
1772
+ //
1773
+ // This operation pops off a context, invokes a partial with that context,
1774
+ // and pushes the result of the invocation back.
1775
+ invokePartial: function(name) {
1776
+ var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
1777
+
1778
+ if (this.options.data) {
1779
+ params.push("data");
1780
+ }
1756
1781
 
1757
- // [assignToHash]
1758
- //
1759
- // On stack, before: value, hash, ...
1760
- // On stack, after: hash, ...
1761
- //
1762
- // Pops a value and hash off the stack, assigns `hash[key] = value`
1763
- // and pushes the hash back onto the stack.
1764
- assignToHash: function(key) {
1765
- var value = this.popStack(),
1766
- type;
1782
+ this.context.aliases.self = "this";
1783
+ this.push("self.invokePartial(" + params.join(", ") + ")");
1784
+ },
1767
1785
 
1768
- if (this.options.stringParams) {
1769
- type = this.popStack();
1770
- this.popStack();
1771
- }
1786
+ // [assignToHash]
1787
+ //
1788
+ // On stack, before: value, hash, ...
1789
+ // On stack, after: hash, ...
1790
+ //
1791
+ // Pops a value and hash off the stack, assigns `hash[key] = value`
1792
+ // and pushes the hash back onto the stack.
1793
+ assignToHash: function(key) {
1794
+ var value = this.popStack(),
1795
+ context,
1796
+ type;
1797
+
1798
+ if (this.options.stringParams) {
1799
+ type = this.popStack();
1800
+ context = this.popStack();
1801
+ }
1772
1802
 
1773
- var hash = this.hash;
1774
- if (type) {
1775
- hash.types.push("'" + key + "': " + type);
1776
- }
1777
- hash.values.push("'" + key + "': (" + value + ")");
1778
- },
1803
+ var hash = this.hash;
1804
+ if (context) {
1805
+ hash.contexts.push("'" + key + "': " + context);
1806
+ }
1807
+ if (type) {
1808
+ hash.types.push("'" + key + "': " + type);
1809
+ }
1810
+ hash.values.push("'" + key + "': (" + value + ")");
1811
+ },
1779
1812
 
1780
- // HELPERS
1813
+ // HELPERS
1781
1814
 
1782
- compiler: JavaScriptCompiler,
1815
+ compiler: JavaScriptCompiler,
1783
1816
 
1784
- compileChildren: function(environment, options) {
1785
- var children = environment.children, child, compiler;
1817
+ compileChildren: function(environment, options) {
1818
+ var children = environment.children, child, compiler;
1786
1819
 
1787
- for(var i=0, l=children.length; i<l; i++) {
1788
- child = children[i];
1789
- compiler = new this.compiler();
1820
+ for(var i=0, l=children.length; i<l; i++) {
1821
+ child = children[i];
1822
+ compiler = new this.compiler();
1790
1823
 
1791
- var index = this.matchExistingProgram(child);
1824
+ var index = this.matchExistingProgram(child);
1792
1825
 
1793
- if (index == null) {
1794
- this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
1795
- index = this.context.programs.length;
1796
- child.index = index;
1797
- child.name = 'program' + index;
1798
- this.context.programs[index] = compiler.compile(child, options, this.context);
1799
- this.context.environments[index] = child;
1800
- } else {
1801
- child.index = index;
1802
- child.name = 'program' + index;
1803
- }
1826
+ if (index == null) {
1827
+ this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
1828
+ index = this.context.programs.length;
1829
+ child.index = index;
1830
+ child.name = 'program' + index;
1831
+ this.context.programs[index] = compiler.compile(child, options, this.context);
1832
+ this.context.environments[index] = child;
1833
+ } else {
1834
+ child.index = index;
1835
+ child.name = 'program' + index;
1804
1836
  }
1805
- },
1806
- matchExistingProgram: function(child) {
1807
- for (var i = 0, len = this.context.environments.length; i < len; i++) {
1808
- var environment = this.context.environments[i];
1809
- if (environment && environment.equals(child)) {
1810
- return i;
1811
- }
1837
+ }
1838
+ },
1839
+ matchExistingProgram: function(child) {
1840
+ for (var i = 0, len = this.context.environments.length; i < len; i++) {
1841
+ var environment = this.context.environments[i];
1842
+ if (environment && environment.equals(child)) {
1843
+ return i;
1812
1844
  }
1813
- },
1814
-
1815
- programExpression: function(guid) {
1816
- this.context.aliases.self = "this";
1845
+ }
1846
+ },
1817
1847
 
1818
- if(guid == null) {
1819
- return "self.noop";
1820
- }
1848
+ programExpression: function(guid) {
1849
+ this.context.aliases.self = "this";
1821
1850
 
1822
- var child = this.environment.children[guid],
1823
- depths = child.depths.list, depth;
1851
+ if(guid == null) {
1852
+ return "self.noop";
1853
+ }
1824
1854
 
1825
- var programParams = [child.index, child.name, "data"];
1855
+ var child = this.environment.children[guid],
1856
+ depths = child.depths.list, depth;
1826
1857
 
1827
- for(var i=0, l = depths.length; i<l; i++) {
1828
- depth = depths[i];
1858
+ var programParams = [child.index, child.name, "data"];
1829
1859
 
1830
- if(depth === 1) { programParams.push("depth0"); }
1831
- else { programParams.push("depth" + (depth - 1)); }
1832
- }
1860
+ for(var i=0, l = depths.length; i<l; i++) {
1861
+ depth = depths[i];
1833
1862
 
1834
- if(depths.length === 0) {
1835
- return "self.program(" + programParams.join(", ") + ")";
1836
- } else {
1837
- programParams.shift();
1838
- return "self.programWithDepth(" + programParams.join(", ") + ")";
1839
- }
1840
- },
1863
+ if(depth === 1) { programParams.push("depth0"); }
1864
+ else { programParams.push("depth" + (depth - 1)); }
1865
+ }
1841
1866
 
1842
- register: function(name, val) {
1843
- this.useRegister(name);
1844
- this.source.push(name + " = " + val + ";");
1845
- },
1867
+ return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")";
1868
+ },
1846
1869
 
1847
- useRegister: function(name) {
1848
- if(!this.registers[name]) {
1849
- this.registers[name] = true;
1850
- this.registers.list.push(name);
1851
- }
1852
- },
1870
+ register: function(name, val) {
1871
+ this.useRegister(name);
1872
+ this.source.push(name + " = " + val + ";");
1873
+ },
1853
1874
 
1854
- pushStackLiteral: function(item) {
1855
- return this.push(new Literal(item));
1856
- },
1875
+ useRegister: function(name) {
1876
+ if(!this.registers[name]) {
1877
+ this.registers[name] = true;
1878
+ this.registers.list.push(name);
1879
+ }
1880
+ },
1857
1881
 
1858
- pushStack: function(item) {
1859
- this.flushInline();
1882
+ pushStackLiteral: function(item) {
1883
+ return this.push(new Literal(item));
1884
+ },
1860
1885
 
1861
- var stack = this.incrStack();
1862
- if (item) {
1863
- this.source.push(stack + " = " + item + ";");
1864
- }
1865
- this.compileStack.push(stack);
1866
- return stack;
1867
- },
1886
+ pushStack: function(item) {
1887
+ this.flushInline();
1868
1888
 
1869
- replaceStack: function(callback) {
1870
- var prefix = '',
1871
- inline = this.isInline(),
1872
- stack;
1889
+ var stack = this.incrStack();
1890
+ if (item) {
1891
+ this.source.push(stack + " = " + item + ";");
1892
+ }
1893
+ this.compileStack.push(stack);
1894
+ return stack;
1895
+ },
1873
1896
 
1874
- // If we are currently inline then we want to merge the inline statement into the
1875
- // replacement statement via ','
1876
- if (inline) {
1877
- var top = this.popStack(true);
1897
+ replaceStack: function(callback) {
1898
+ var prefix = '',
1899
+ inline = this.isInline(),
1900
+ stack;
1878
1901
 
1879
- if (top instanceof Literal) {
1880
- // Literals do not need to be inlined
1881
- stack = top.value;
1882
- } else {
1883
- // Get or create the current stack name for use by the inline
1884
- var name = this.stackSlot ? this.topStackName() : this.incrStack();
1902
+ // If we are currently inline then we want to merge the inline statement into the
1903
+ // replacement statement via ','
1904
+ if (inline) {
1905
+ var top = this.popStack(true);
1885
1906
 
1886
- prefix = '(' + this.push(name) + ' = ' + top + '),';
1887
- stack = this.topStack();
1888
- }
1907
+ if (top instanceof Literal) {
1908
+ // Literals do not need to be inlined
1909
+ stack = top.value;
1889
1910
  } else {
1911
+ // Get or create the current stack name for use by the inline
1912
+ var name = this.stackSlot ? this.topStackName() : this.incrStack();
1913
+
1914
+ prefix = '(' + this.push(name) + ' = ' + top + '),';
1890
1915
  stack = this.topStack();
1891
1916
  }
1917
+ } else {
1918
+ stack = this.topStack();
1919
+ }
1892
1920
 
1893
- var item = callback.call(this, stack);
1894
-
1895
- if (inline) {
1896
- if (this.inlineStack.length || this.compileStack.length) {
1897
- this.popStack();
1898
- }
1899
- this.push('(' + prefix + item + ')');
1900
- } else {
1901
- // Prevent modification of the context depth variable. Through replaceStack
1902
- if (!/^stack/.test(stack)) {
1903
- stack = this.nextStack();
1904
- }
1921
+ var item = callback.call(this, stack);
1905
1922
 
1906
- this.source.push(stack + " = (" + prefix + item + ");");
1923
+ if (inline) {
1924
+ if (this.inlineStack.length || this.compileStack.length) {
1925
+ this.popStack();
1907
1926
  }
1908
- return stack;
1909
- },
1910
-
1911
- nextStack: function() {
1912
- return this.pushStack();
1913
- },
1914
-
1915
- incrStack: function() {
1916
- this.stackSlot++;
1917
- if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1918
- return this.topStackName();
1919
- },
1920
- topStackName: function() {
1921
- return "stack" + this.stackSlot;
1922
- },
1923
- flushInline: function() {
1924
- var inlineStack = this.inlineStack;
1925
- if (inlineStack.length) {
1926
- this.inlineStack = [];
1927
- for (var i = 0, len = inlineStack.length; i < len; i++) {
1928
- var entry = inlineStack[i];
1929
- if (entry instanceof Literal) {
1930
- this.compileStack.push(entry);
1931
- } else {
1932
- this.pushStack(entry);
1933
- }
1934
- }
1927
+ this.push('(' + prefix + item + ')');
1928
+ } else {
1929
+ // Prevent modification of the context depth variable. Through replaceStack
1930
+ if (!/^stack/.test(stack)) {
1931
+ stack = this.nextStack();
1935
1932
  }
1936
- },
1937
- isInline: function() {
1938
- return this.inlineStack.length;
1939
- },
1940
1933
 
1941
- popStack: function(wrapped) {
1942
- var inline = this.isInline(),
1943
- item = (inline ? this.inlineStack : this.compileStack).pop();
1934
+ this.source.push(stack + " = (" + prefix + item + ");");
1935
+ }
1936
+ return stack;
1937
+ },
1944
1938
 
1945
- if (!wrapped && (item instanceof Literal)) {
1946
- return item.value;
1947
- } else {
1948
- if (!inline) {
1949
- this.stackSlot--;
1939
+ nextStack: function() {
1940
+ return this.pushStack();
1941
+ },
1942
+
1943
+ incrStack: function() {
1944
+ this.stackSlot++;
1945
+ if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1946
+ return this.topStackName();
1947
+ },
1948
+ topStackName: function() {
1949
+ return "stack" + this.stackSlot;
1950
+ },
1951
+ flushInline: function() {
1952
+ var inlineStack = this.inlineStack;
1953
+ if (inlineStack.length) {
1954
+ this.inlineStack = [];
1955
+ for (var i = 0, len = inlineStack.length; i < len; i++) {
1956
+ var entry = inlineStack[i];
1957
+ if (entry instanceof Literal) {
1958
+ this.compileStack.push(entry);
1959
+ } else {
1960
+ this.pushStack(entry);
1950
1961
  }
1951
- return item;
1952
1962
  }
1953
- },
1963
+ }
1964
+ },
1965
+ isInline: function() {
1966
+ return this.inlineStack.length;
1967
+ },
1954
1968
 
1955
- topStack: function(wrapped) {
1956
- var stack = (this.isInline() ? this.inlineStack : this.compileStack),
1957
- item = stack[stack.length - 1];
1969
+ popStack: function(wrapped) {
1970
+ var inline = this.isInline(),
1971
+ item = (inline ? this.inlineStack : this.compileStack).pop();
1958
1972
 
1959
- if (!wrapped && (item instanceof Literal)) {
1960
- return item.value;
1961
- } else {
1962
- return item;
1973
+ if (!wrapped && (item instanceof Literal)) {
1974
+ return item.value;
1975
+ } else {
1976
+ if (!inline) {
1977
+ this.stackSlot--;
1963
1978
  }
1964
- },
1979
+ return item;
1980
+ }
1981
+ },
1965
1982
 
1966
- quotedString: function(str) {
1967
- return '"' + str
1968
- .replace(/\\/g, '\\\\')
1969
- .replace(/"/g, '\\"')
1970
- .replace(/\n/g, '\\n')
1971
- .replace(/\r/g, '\\r') + '"';
1972
- },
1983
+ topStack: function(wrapped) {
1984
+ var stack = (this.isInline() ? this.inlineStack : this.compileStack),
1985
+ item = stack[stack.length - 1];
1973
1986
 
1974
- setupHelper: function(paramSize, name, missingParams) {
1975
- var params = [];
1976
- this.setupParams(paramSize, params, missingParams);
1977
- var foundHelper = this.nameLookup('helpers', name, 'helper');
1987
+ if (!wrapped && (item instanceof Literal)) {
1988
+ return item.value;
1989
+ } else {
1990
+ return item;
1991
+ }
1992
+ },
1978
1993
 
1979
- return {
1980
- params: params,
1981
- name: foundHelper,
1982
- callParams: ["depth0"].concat(params).join(", "),
1983
- helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
1984
- };
1985
- },
1994
+ quotedString: function(str) {
1995
+ return '"' + str
1996
+ .replace(/\\/g, '\\\\')
1997
+ .replace(/"/g, '\\"')
1998
+ .replace(/\n/g, '\\n')
1999
+ .replace(/\r/g, '\\r')
2000
+ .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
2001
+ .replace(/\u2029/g, '\\u2029') + '"';
2002
+ },
1986
2003
 
1987
- // the params and contexts arguments are passed in arrays
1988
- // to fill in
1989
- setupParams: function(paramSize, params, useRegister) {
1990
- var options = [], contexts = [], types = [], param, inverse, program;
2004
+ setupHelper: function(paramSize, name, missingParams) {
2005
+ var params = [];
2006
+ this.setupParams(paramSize, params, missingParams);
2007
+ var foundHelper = this.nameLookup('helpers', name, 'helper');
1991
2008
 
1992
- options.push("hash:" + this.popStack());
2009
+ return {
2010
+ params: params,
2011
+ name: foundHelper,
2012
+ callParams: ["depth0"].concat(params).join(", "),
2013
+ helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
2014
+ };
2015
+ },
1993
2016
 
1994
- inverse = this.popStack();
1995
- program = this.popStack();
2017
+ // the params and contexts arguments are passed in arrays
2018
+ // to fill in
2019
+ setupParams: function(paramSize, params, useRegister) {
2020
+ var options = [], contexts = [], types = [], param, inverse, program;
1996
2021
 
1997
- // Avoid setting fn and inverse if neither are set. This allows
1998
- // helpers to do a check for `if (options.fn)`
1999
- if (program || inverse) {
2000
- if (!program) {
2001
- this.context.aliases.self = "this";
2002
- program = "self.noop";
2003
- }
2022
+ options.push("hash:" + this.popStack());
2004
2023
 
2005
- if (!inverse) {
2006
- this.context.aliases.self = "this";
2007
- inverse = "self.noop";
2008
- }
2024
+ inverse = this.popStack();
2025
+ program = this.popStack();
2009
2026
 
2010
- options.push("inverse:" + inverse);
2011
- options.push("fn:" + program);
2027
+ // Avoid setting fn and inverse if neither are set. This allows
2028
+ // helpers to do a check for `if (options.fn)`
2029
+ if (program || inverse) {
2030
+ if (!program) {
2031
+ this.context.aliases.self = "this";
2032
+ program = "self.noop";
2012
2033
  }
2013
2034
 
2014
- for(var i=0; i<paramSize; i++) {
2015
- param = this.popStack();
2016
- params.push(param);
2017
-
2018
- if(this.options.stringParams) {
2019
- types.push(this.popStack());
2020
- contexts.push(this.popStack());
2021
- }
2035
+ if (!inverse) {
2036
+ this.context.aliases.self = "this";
2037
+ inverse = "self.noop";
2022
2038
  }
2023
2039
 
2024
- if (this.options.stringParams) {
2025
- options.push("contexts:[" + contexts.join(",") + "]");
2026
- options.push("types:[" + types.join(",") + "]");
2027
- options.push("hashTypes:hashTypes");
2028
- }
2040
+ options.push("inverse:" + inverse);
2041
+ options.push("fn:" + program);
2042
+ }
2029
2043
 
2030
- if(this.options.data) {
2031
- options.push("data:data");
2032
- }
2044
+ for(var i=0; i<paramSize; i++) {
2045
+ param = this.popStack();
2046
+ params.push(param);
2033
2047
 
2034
- options = "{" + options.join(",") + "}";
2035
- if (useRegister) {
2036
- this.register('options', options);
2037
- params.push('options');
2038
- } else {
2039
- params.push(options);
2048
+ if(this.options.stringParams) {
2049
+ types.push(this.popStack());
2050
+ contexts.push(this.popStack());
2040
2051
  }
2041
- return params.join(", ");
2042
2052
  }
2043
- };
2044
2053
 
2045
- var reservedWords = (
2046
- "break else new var" +
2047
- " case finally return void" +
2048
- " catch for switch while" +
2049
- " continue function this with" +
2050
- " default if throw" +
2051
- " delete in try" +
2052
- " do instanceof typeof" +
2053
- " abstract enum int short" +
2054
- " boolean export interface static" +
2055
- " byte extends long super" +
2056
- " char final native synchronized" +
2057
- " class float package throws" +
2058
- " const goto private transient" +
2059
- " debugger implements protected volatile" +
2060
- " double import public let yield"
2061
- ).split(" ");
2062
-
2063
- var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
2064
-
2065
- for(var i=0, l=reservedWords.length; i<l; i++) {
2066
- compilerWords[reservedWords[i]] = true;
2067
- }
2054
+ if (this.options.stringParams) {
2055
+ options.push("contexts:[" + contexts.join(",") + "]");
2056
+ options.push("types:[" + types.join(",") + "]");
2057
+ options.push("hashContexts:hashContexts");
2058
+ options.push("hashTypes:hashTypes");
2059
+ }
2068
2060
 
2069
- JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
2070
- if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
2071
- return true;
2061
+ if(this.options.data) {
2062
+ options.push("data:data");
2072
2063
  }
2073
- return false;
2074
- };
2075
2064
 
2076
- })(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
2065
+ options = "{" + options.join(",") + "}";
2066
+ if (useRegister) {
2067
+ this.register('options', options);
2068
+ params.push('options');
2069
+ } else {
2070
+ params.push(options);
2071
+ }
2072
+ return params.join(", ");
2073
+ }
2074
+ };
2075
+
2076
+ var reservedWords = (
2077
+ "break else new var" +
2078
+ " case finally return void" +
2079
+ " catch for switch while" +
2080
+ " continue function this with" +
2081
+ " default if throw" +
2082
+ " delete in try" +
2083
+ " do instanceof typeof" +
2084
+ " abstract enum int short" +
2085
+ " boolean export interface static" +
2086
+ " byte extends long super" +
2087
+ " char final native synchronized" +
2088
+ " class float package throws" +
2089
+ " const goto private transient" +
2090
+ " debugger implements protected volatile" +
2091
+ " double import public let yield"
2092
+ ).split(" ");
2093
+
2094
+ var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
2095
+
2096
+ for(var i=0, l=reservedWords.length; i<l; i++) {
2097
+ compilerWords[reservedWords[i]] = true;
2098
+ }
2099
+
2100
+ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
2101
+ if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
2102
+ return true;
2103
+ }
2104
+ return false;
2105
+ };
2077
2106
 
2078
2107
  Handlebars.precompile = function(input, options) {
2079
- if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2080
- throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
2108
+ if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2109
+ throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
2081
2110
  }
2082
2111
 
2083
2112
  options = options || {};
@@ -2085,12 +2114,12 @@ Handlebars.precompile = function(input, options) {
2085
2114
  options.data = true;
2086
2115
  }
2087
2116
  var ast = Handlebars.parse(input);
2088
- var environment = new Handlebars.Compiler().compile(ast, options);
2089
- return new Handlebars.JavaScriptCompiler().compile(environment, options);
2117
+ var environment = new Compiler().compile(ast, options);
2118
+ return new JavaScriptCompiler().compile(environment, options);
2090
2119
  };
2091
2120
 
2092
2121
  Handlebars.compile = function(input, options) {
2093
- if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2122
+ if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2094
2123
  throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
2095
2124
  }
2096
2125
 
@@ -2101,8 +2130,8 @@ Handlebars.compile = function(input, options) {
2101
2130
  var compiled;
2102
2131
  function compile() {
2103
2132
  var ast = Handlebars.parse(input);
2104
- var environment = new Handlebars.Compiler().compile(ast, options);
2105
- var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
2133
+ var environment = new Compiler().compile(ast, options);
2134
+ var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true);
2106
2135
  return Handlebars.template(templateSpec);
2107
2136
  }
2108
2137
 
@@ -2114,8 +2143,10 @@ Handlebars.compile = function(input, options) {
2114
2143
  return compiled.call(this, context, options);
2115
2144
  };
2116
2145
  };
2146
+
2117
2147
  ;
2118
2148
  // lib/handlebars/runtime.js
2149
+
2119
2150
  Handlebars.VM = {
2120
2151
  template: function(templateSpec) {
2121
2152
  // Just add water
@@ -2126,13 +2157,11 @@ Handlebars.VM = {
2126
2157
  program: function(i, fn, data) {
2127
2158
  var programWrapper = this.programs[i];
2128
2159
  if(data) {
2129
- return Handlebars.VM.program(fn, data);
2130
- } else if(programWrapper) {
2131
- return programWrapper;
2132
- } else {
2133
- programWrapper = this.programs[i] = Handlebars.VM.program(fn);
2134
- return programWrapper;
2160
+ programWrapper = Handlebars.VM.program(i, fn, data);
2161
+ } else if (!programWrapper) {
2162
+ programWrapper = this.programs[i] = Handlebars.VM.program(i, fn);
2135
2163
  }
2164
+ return programWrapper;
2136
2165
  },
2137
2166
  programWithDepth: Handlebars.VM.programWithDepth,
2138
2167
  noop: Handlebars.VM.noop,
@@ -2164,21 +2193,27 @@ Handlebars.VM = {
2164
2193
  };
2165
2194
  },
2166
2195
 
2167
- programWithDepth: function(fn, data, $depth) {
2168
- var args = Array.prototype.slice.call(arguments, 2);
2196
+ programWithDepth: function(i, fn, data /*, $depth */) {
2197
+ var args = Array.prototype.slice.call(arguments, 3);
2169
2198
 
2170
- return function(context, options) {
2199
+ var program = function(context, options) {
2171
2200
  options = options || {};
2172
2201
 
2173
2202
  return fn.apply(this, [context, options.data || data].concat(args));
2174
2203
  };
2204
+ program.program = i;
2205
+ program.depth = args.length;
2206
+ return program;
2175
2207
  },
2176
- program: function(fn, data) {
2177
- return function(context, options) {
2208
+ program: function(i, fn, data) {
2209
+ var program = function(context, options) {
2178
2210
  options = options || {};
2179
2211
 
2180
2212
  return fn(context, options.data || data);
2181
2213
  };
2214
+ program.program = i;
2215
+ program.depth = 0;
2216
+ return program;
2182
2217
  },
2183
2218
  noop: function() { return ""; },
2184
2219
  invokePartial: function(partial, name, context, helpers, partials, data) {
@@ -2199,3 +2234,6 @@ Handlebars.VM = {
2199
2234
 
2200
2235
  Handlebars.template = Handlebars.VM.template;
2201
2236
  ;
2237
+ // lib/handlebars/browser-suffix.js
2238
+ })(Handlebars);
2239
+ ;