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.
- checksums.yaml +15 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +5 -5
- data/README.md +2 -1
- data/lib/handlebars_assets/config.rb +1 -0
- data/lib/handlebars_assets/version.rb +1 -1
- data/test/patch/patch.js +9 -11
- data/vendor/assets/javascripts/handlebars.js +1246 -1208
- data/vendor/assets/javascripts/handlebars.runtime.js +96 -72
- metadata +26 -41
checksums.yaml
ADDED
@@ -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=
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
handlebars_assets (0.12.
|
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.
|
25
|
-
multi_json (1.
|
26
|
-
rack (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.
|
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-
|
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
|
|
data/test/patch/patch.js
CHANGED
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
|
-
var originalLookup = window.Handlebars.JavaScriptCompiler.prototype.nameLookup;
|
1
|
+
var originalLookup = Handlebars.JavaScriptCompiler.prototype.nameLookup;
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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/
|
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.
|
33
|
-
Handlebars.COMPILER_REVISION =
|
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: '
|
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(
|
45
|
-
|
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
|
-
|
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
|
-
|
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
|
577
|
+
case 2: return 14;
|
572
578
|
break;
|
573
|
-
case
|
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
|
585
|
+
case 4: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15;
|
580
586
|
break;
|
581
|
-
case
|
587
|
+
case 5: this.begin("par"); return 24;
|
582
588
|
break;
|
583
|
-
case
|
589
|
+
case 6: return 16;
|
584
590
|
break;
|
585
|
-
case
|
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
|
595
|
+
case 9: return 19;
|
592
596
|
break;
|
593
597
|
case 10: return 23;
|
594
598
|
break;
|
595
|
-
case 11:
|
599
|
+
case 11: return 23;
|
596
600
|
break;
|
597
|
-
case 12:
|
601
|
+
case 12: this.popState(); this.begin('com');
|
598
602
|
break;
|
599
|
-
case 13: return
|
603
|
+
case 13: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
|
600
604
|
break;
|
601
|
-
case 14: return
|
605
|
+
case 14: return 22;
|
602
606
|
break;
|
603
|
-
case 15: return
|
607
|
+
case 15: return 36;
|
604
608
|
break;
|
605
609
|
case 16: return 35;
|
606
610
|
break;
|
607
|
-
case 17: return
|
611
|
+
case 17: return 35;
|
608
612
|
break;
|
609
|
-
case 18:
|
613
|
+
case 18: return 39;
|
610
614
|
break;
|
611
|
-
case 19:
|
615
|
+
case 19: /*ignore whitespace*/
|
612
616
|
break;
|
613
617
|
case 20: this.popState(); return 18;
|
614
618
|
break;
|
615
|
-
case 21:
|
619
|
+
case 21: this.popState(); return 18;
|
616
620
|
break;
|
617
|
-
case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\
|
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
|
623
|
+
case 23: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30;
|
620
624
|
break;
|
621
|
-
case 24: return
|
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
|
629
|
+
case 26: return 32;
|
630
|
+
break;
|
631
|
+
case 27: return 31;
|
626
632
|
break;
|
627
|
-
case
|
633
|
+
case 28: return 35;
|
628
634
|
break;
|
629
|
-
case
|
635
|
+
case 29: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35;
|
630
636
|
break;
|
631
|
-
case
|
637
|
+
case 30: return 'INVALID';
|
632
638
|
break;
|
633
|
-
case
|
639
|
+
case 31: /*ignore whitespace*/
|
634
640
|
break;
|
635
|
-
case
|
641
|
+
case 32: this.popState(); return 37;
|
636
642
|
break;
|
637
|
-
case
|
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]))/,/^(
|
642
|
-
lexer.conditions = {"mu":{"rules":[
|
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
|
-
|
665
|
-
|
666
|
-
Handlebars.AST = {};
|
668
|
+
Handlebars.AST = {};
|
667
669
|
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
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
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
676
|
+
Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
|
677
|
+
this.type = "mustache";
|
678
|
+
this.escaped = !unescaped;
|
679
|
+
this.hash = hash;
|
678
680
|
|
679
|
-
|
680
|
-
|
681
|
+
var id = this.id = rawParams[0];
|
682
|
+
var params = this.params = rawParams.slice(1);
|
681
683
|
|
682
|
-
|
683
|
-
|
684
|
-
|
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
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
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
|
-
|
692
|
-
|
693
|
-
|
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
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
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
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
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
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
717
|
+
if (this.inverse && !this.program) {
|
718
|
+
this.isInverse = true;
|
719
|
+
}
|
720
|
+
};
|
719
721
|
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
722
|
+
Handlebars.AST.ContentNode = function(string) {
|
723
|
+
this.type = "content";
|
724
|
+
this.string = string;
|
725
|
+
};
|
724
726
|
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
727
|
+
Handlebars.AST.HashNode = function(pairs) {
|
728
|
+
this.type = "hash";
|
729
|
+
this.pairs = pairs;
|
730
|
+
};
|
729
731
|
|
730
|
-
|
731
|
-
|
732
|
-
|
732
|
+
Handlebars.AST.IdNode = function(parts) {
|
733
|
+
this.type = "ID";
|
734
|
+
this.original = parts.join(".");
|
733
735
|
|
734
|
-
|
736
|
+
var dig = [], depth = 0;
|
735
737
|
|
736
|
-
|
737
|
-
|
738
|
+
for(var i=0,l=parts.length; i<l; i++) {
|
739
|
+
var part = parts[i];
|
738
740
|
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
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
|
-
|
748
|
-
|
749
|
-
|
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
|
-
|
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
|
-
|
759
|
-
|
760
|
-
this.name = name;
|
761
|
-
};
|
757
|
+
this.stringModeValue = this.string;
|
758
|
+
};
|
762
759
|
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
760
|
+
Handlebars.AST.PartialNameNode = function(name) {
|
761
|
+
this.type = "PARTIAL_NAME";
|
762
|
+
this.name = name;
|
763
|
+
};
|
767
764
|
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
};
|
765
|
+
Handlebars.AST.DataNode = function(id) {
|
766
|
+
this.type = "DATA";
|
767
|
+
this.id = id;
|
768
|
+
};
|
773
769
|
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
770
|
+
Handlebars.AST.StringNode = function(string) {
|
771
|
+
this.type = "STRING";
|
772
|
+
this.string = string;
|
773
|
+
this.stringModeValue = string;
|
774
|
+
};
|
779
775
|
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
776
|
+
Handlebars.AST.IntegerNode = function(integer) {
|
777
|
+
this.type = "INTEGER";
|
778
|
+
this.integer = integer;
|
779
|
+
this.stringModeValue = Number(integer);
|
780
|
+
};
|
785
781
|
|
786
|
-
|
787
|
-
|
788
|
-
|
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
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
};
|
815
|
+
var escape = {
|
816
|
+
"&": "&",
|
817
|
+
"<": "<",
|
818
|
+
">": ">",
|
819
|
+
'"': """,
|
820
|
+
"'": "'",
|
821
|
+
"`": "`"
|
822
|
+
};
|
823
823
|
|
824
|
-
|
825
|
-
|
824
|
+
var badChars = /[&<>"'`]/g;
|
825
|
+
var possible = /[&<>"'`]/;
|
826
826
|
|
827
|
-
|
828
|
-
|
829
|
-
|
827
|
+
var escapeChar = function(chr) {
|
828
|
+
return escape[chr] || "&";
|
829
|
+
};
|
830
830
|
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
if
|
835
|
-
|
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
|
-
|
841
|
-
|
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
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
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
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
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
|
-
|
868
|
-
|
879
|
+
Compiler.prototype = {
|
880
|
+
compiler: Compiler,
|
869
881
|
|
870
|
-
|
871
|
-
|
882
|
+
disassemble: function() {
|
883
|
+
var opcodes = this.opcodes, opcode, out = [], params, param;
|
872
884
|
|
873
|
-
|
874
|
-
|
885
|
+
for (var i=0, l=opcodes.length; i<l; i++) {
|
886
|
+
opcode = opcodes[i];
|
875
887
|
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
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
|
-
|
897
|
+
params.push(param);
|
888
898
|
}
|
899
|
+
out.push(opcode.opcode + " " + params.join(" "));
|
889
900
|
}
|
901
|
+
}
|
890
902
|
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
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
|
-
|
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
|
-
|
912
|
-
},
|
922
|
+
}
|
913
923
|
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
this.
|
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
|
-
|
939
|
-
|
934
|
+
return true;
|
935
|
+
},
|
940
936
|
|
941
|
-
|
942
|
-
|
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
|
946
|
-
|
947
|
-
this.opcodes = [];
|
961
|
+
return this.program(program);
|
962
|
+
},
|
948
963
|
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
}
|
953
|
-
this.isSimple = l === 1;
|
964
|
+
accept: function(node) {
|
965
|
+
return this[node.type](node);
|
966
|
+
},
|
954
967
|
|
955
|
-
|
956
|
-
|
957
|
-
|
968
|
+
program: function(program) {
|
969
|
+
var statements = program.statements, statement;
|
970
|
+
this.opcodes = [];
|
958
971
|
|
959
|
-
|
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
|
-
|
963
|
-
|
964
|
-
|
978
|
+
this.depths.list = this.depths.list.sort(function(a, b) {
|
979
|
+
return a - b;
|
980
|
+
});
|
965
981
|
|
966
|
-
|
982
|
+
return this;
|
983
|
+
},
|
967
984
|
|
968
|
-
|
985
|
+
compileProgram: function(program) {
|
986
|
+
var result = new this.compiler().compile(program, this.options);
|
987
|
+
var guid = this.guid++, depth;
|
969
988
|
|
970
|
-
|
971
|
-
depth = result.depths.list[i];
|
989
|
+
this.usePartial = this.usePartial || result.usePartial;
|
972
990
|
|
973
|
-
|
974
|
-
else { this.addDepth(depth - 1); }
|
975
|
-
}
|
991
|
+
this.children[guid] = result;
|
976
992
|
|
977
|
-
|
978
|
-
|
993
|
+
for(var i=0, l=result.depths.list.length; i<l; i++) {
|
994
|
+
depth = result.depths.list[i];
|
979
995
|
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
inverse = block.inverse;
|
996
|
+
if(depth < 2) { continue; }
|
997
|
+
else { this.addDepth(depth - 1); }
|
998
|
+
}
|
984
999
|
|
985
|
-
|
986
|
-
|
987
|
-
}
|
1000
|
+
return guid;
|
1001
|
+
},
|
988
1002
|
|
989
|
-
|
990
|
-
|
991
|
-
|
1003
|
+
block: function(block) {
|
1004
|
+
var mustache = block.mustache,
|
1005
|
+
program = block.program,
|
1006
|
+
inverse = block.inverse;
|
992
1007
|
|
993
|
-
|
1008
|
+
if (program) {
|
1009
|
+
program = this.compileProgram(program);
|
1010
|
+
}
|
994
1011
|
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
this.simpleMustache(mustache);
|
1012
|
+
if (inverse) {
|
1013
|
+
inverse = this.compileProgram(inverse);
|
1014
|
+
}
|
999
1015
|
|
1000
|
-
|
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
|
-
|
1018
|
-
|
1018
|
+
if (type === "helper") {
|
1019
|
+
this.helperMustache(mustache, program, inverse);
|
1020
|
+
} else if (type === "simple") {
|
1021
|
+
this.simpleMustache(mustache);
|
1019
1022
|
|
1020
|
-
|
1021
|
-
|
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
|
-
|
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
|
-
|
1026
|
-
|
1027
|
-
val = pair[1];
|
1040
|
+
this.opcode('append');
|
1041
|
+
},
|
1028
1042
|
|
1029
|
-
|
1030
|
-
|
1031
|
-
} else {
|
1032
|
-
this.accept(val);
|
1033
|
-
}
|
1043
|
+
hash: function(hash) {
|
1044
|
+
var pairs = hash.pairs, pair, val;
|
1034
1045
|
|
1035
|
-
|
1036
|
-
}
|
1037
|
-
this.opcode('popHash');
|
1038
|
-
},
|
1046
|
+
this.opcode('pushHash');
|
1039
1047
|
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1048
|
+
for(var i=0, l=pairs.length; i<l; i++) {
|
1049
|
+
pair = pairs[i];
|
1050
|
+
val = pair[1];
|
1043
1051
|
|
1044
|
-
if(
|
1045
|
-
|
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.
|
1059
|
+
this.accept(val);
|
1048
1060
|
}
|
1049
1061
|
|
1050
|
-
this.opcode('
|
1051
|
-
|
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
|
-
|
1059
|
-
|
1060
|
-
|
1067
|
+
partial: function(partial) {
|
1068
|
+
var partialName = partial.partialName;
|
1069
|
+
this.usePartial = true;
|
1061
1070
|
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
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
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
this.opcode('append');
|
1074
|
-
}
|
1075
|
-
},
|
1077
|
+
this.opcode('invokePartial', partialName.name);
|
1078
|
+
this.opcode('append');
|
1079
|
+
},
|
1076
1080
|
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
isBlock = program != null || inverse != null;
|
1081
|
+
content: function(content) {
|
1082
|
+
this.opcode('appendContent', content.string);
|
1083
|
+
},
|
1081
1084
|
|
1082
|
-
|
1085
|
+
mustache: function(mustache) {
|
1086
|
+
var options = this.options;
|
1087
|
+
var type = this.classifyMustache(mustache);
|
1083
1088
|
|
1084
|
-
|
1085
|
-
this.
|
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
|
-
|
1088
|
-
|
1097
|
+
if(mustache.escaped && !options.noEscape) {
|
1098
|
+
this.opcode('appendEscaped');
|
1099
|
+
} else {
|
1100
|
+
this.opcode('append');
|
1101
|
+
}
|
1102
|
+
},
|
1089
1103
|
|
1090
|
-
|
1091
|
-
|
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
|
-
|
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
|
-
|
1105
|
-
|
1111
|
+
this.opcode('pushProgram', program);
|
1112
|
+
this.opcode('pushProgram', inverse);
|
1106
1113
|
|
1107
|
-
|
1108
|
-
|
1109
|
-
name = mustache.id.parts[0];
|
1114
|
+
this.opcode('invokeAmbiguous', name, isBlock);
|
1115
|
+
},
|
1110
1116
|
|
1111
|
-
|
1112
|
-
|
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
|
-
|
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
|
-
|
1125
|
-
|
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
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
},
|
1134
|
+
helperMustache: function(mustache, program, inverse) {
|
1135
|
+
var params = this.setupFullMustacheParams(mustache, program, inverse),
|
1136
|
+
name = mustache.id.parts[0];
|
1140
1137
|
|
1141
|
-
|
1142
|
-
this.opcode('
|
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
|
-
|
1146
|
-
|
1147
|
-
|
1147
|
+
ID: function(id) {
|
1148
|
+
this.addDepth(id.depth);
|
1149
|
+
this.opcode('getContext', id.depth);
|
1148
1150
|
|
1149
|
-
|
1150
|
-
|
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
|
-
|
1158
|
+
for(var i=1, l=id.parts.length; i<l; i++) {
|
1159
|
+
this.opcode('lookup', id.parts[i]);
|
1160
|
+
}
|
1161
|
+
},
|
1154
1162
|
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1163
|
+
DATA: function(data) {
|
1164
|
+
this.options.data = true;
|
1165
|
+
this.opcode('lookupData', data.id);
|
1166
|
+
},
|
1159
1167
|
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1168
|
+
STRING: function(string) {
|
1169
|
+
this.opcode('pushString', string.string);
|
1170
|
+
},
|
1163
1171
|
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1172
|
+
INTEGER: function(integer) {
|
1173
|
+
this.opcode('pushLiteral', integer.integer);
|
1174
|
+
},
|
1167
1175
|
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
}
|
1172
|
-
},
|
1176
|
+
BOOLEAN: function(bool) {
|
1177
|
+
this.opcode('pushLiteral', bool.bool);
|
1178
|
+
},
|
1173
1179
|
|
1174
|
-
|
1175
|
-
var isHelper = mustache.isHelper;
|
1176
|
-
var isEligible = mustache.eligibleHelper;
|
1177
|
-
var options = this.options;
|
1180
|
+
comment: function() {},
|
1178
1181
|
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
+
// HELPERS
|
1183
|
+
opcode: function(name) {
|
1184
|
+
this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
|
1185
|
+
},
|
1182
1186
|
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
isEligible = false;
|
1187
|
-
}
|
1188
|
-
}
|
1187
|
+
declare: function(name, value) {
|
1188
|
+
this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
|
1189
|
+
},
|
1189
1190
|
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
},
|
1191
|
+
addDepth: function(depth) {
|
1192
|
+
if(isNaN(depth)) { throw new Error("EWOT"); }
|
1193
|
+
if(depth === 0) { return; }
|
1194
1194
|
|
1195
|
-
|
1196
|
-
|
1195
|
+
if(!this.depths[depth]) {
|
1196
|
+
this.depths[depth] = true;
|
1197
|
+
this.depths.list.push(depth);
|
1198
|
+
}
|
1199
|
+
},
|
1197
1200
|
|
1198
|
-
|
1199
|
-
|
1201
|
+
classifyMustache: function(mustache) {
|
1202
|
+
var isHelper = mustache.isHelper;
|
1203
|
+
var isEligible = mustache.eligibleHelper;
|
1204
|
+
var options = this.options;
|
1200
1205
|
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
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
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
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
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
}
|
1217
|
+
if (isHelper) { return "helper"; }
|
1218
|
+
else if (isEligible) { return "ambiguous"; }
|
1219
|
+
else { return "simple"; }
|
1220
|
+
},
|
1223
1221
|
|
1224
|
-
|
1225
|
-
|
1222
|
+
pushParams: function(params) {
|
1223
|
+
var i = params.length, param;
|
1226
1224
|
|
1227
|
-
|
1228
|
-
|
1229
|
-
var params = mustache.params;
|
1230
|
-
this.pushParams(params);
|
1225
|
+
while(i--) {
|
1226
|
+
param = params[i];
|
1231
1227
|
|
1232
|
-
this.
|
1233
|
-
|
1228
|
+
if(this.options.stringParams) {
|
1229
|
+
if(param.depth) {
|
1230
|
+
this.addDepth(param.depth);
|
1231
|
+
}
|
1234
1232
|
|
1235
|
-
|
1236
|
-
this.
|
1233
|
+
this.opcode('getContext', param.depth || 0);
|
1234
|
+
this.opcode('pushStringParam', param.stringModeValue, param.type);
|
1237
1235
|
} else {
|
1238
|
-
this.
|
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
|
-
|
1245
|
+
if(mustache.hash) {
|
1246
|
+
this.hash(mustache.hash);
|
1247
|
+
} else {
|
1248
|
+
this.opcode('emptyHash');
|
1242
1249
|
}
|
1243
|
-
};
|
1244
1250
|
|
1245
|
-
|
1246
|
-
|
1247
|
-
};
|
1251
|
+
return params;
|
1252
|
+
},
|
1248
1253
|
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
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
|
-
|
1264
|
-
|
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
|
-
|
1276
|
-
|
1277
|
-
}
|
1262
|
+
if(mustache.hash) {
|
1263
|
+
this.hash(mustache.hash);
|
1264
|
+
} else {
|
1265
|
+
this.opcode('emptyHash');
|
1266
|
+
}
|
1278
1267
|
|
1279
|
-
|
1280
|
-
|
1268
|
+
return params;
|
1269
|
+
}
|
1270
|
+
};
|
1281
1271
|
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1272
|
+
var Literal = function(value) {
|
1273
|
+
this.value = value;
|
1274
|
+
};
|
1285
1275
|
|
1286
|
-
|
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
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
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
|
-
|
1302
|
+
initializeBuffer: function() {
|
1303
|
+
return this.quotedString("");
|
1304
|
+
},
|
1297
1305
|
|
1298
|
-
|
1299
|
-
|
1300
|
-
this.registers = { list: [] };
|
1301
|
-
this.compileStack = [];
|
1302
|
-
this.inlineStack = [];
|
1306
|
+
namespace: "Handlebars",
|
1307
|
+
// END PUBLIC API
|
1303
1308
|
|
1304
|
-
|
1309
|
+
compile: function(environment, options, context, asObject) {
|
1310
|
+
this.environment = environment;
|
1311
|
+
this.options = options || {};
|
1305
1312
|
|
1306
|
-
|
1313
|
+
Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
|
1307
1314
|
|
1308
|
-
|
1315
|
+
this.name = this.environment.name;
|
1316
|
+
this.isChild = !!context;
|
1317
|
+
this.context = context || {
|
1318
|
+
programs: [],
|
1319
|
+
environments: [],
|
1320
|
+
aliases: { }
|
1321
|
+
};
|
1309
1322
|
|
1310
|
-
|
1311
|
-
opcode = opcodes[this.i];
|
1323
|
+
this.preamble();
|
1312
1324
|
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
}
|
1325
|
+
this.stackSlot = 0;
|
1326
|
+
this.stackVars = [];
|
1327
|
+
this.registers = { list: [] };
|
1328
|
+
this.compileStack = [];
|
1329
|
+
this.inlineStack = [];
|
1319
1330
|
|
1320
|
-
|
1321
|
-
},
|
1331
|
+
this.compileChildren(environment, options);
|
1322
1332
|
|
1323
|
-
|
1324
|
-
var opcodes = this.environment.opcodes;
|
1325
|
-
return opcodes[this.i + 1];
|
1326
|
-
},
|
1333
|
+
var opcodes = environment.opcodes, opcode;
|
1327
1334
|
|
1328
|
-
|
1329
|
-
this.i = this.i + 1;
|
1330
|
-
},
|
1335
|
+
this.i = 0;
|
1331
1336
|
|
1332
|
-
|
1333
|
-
|
1337
|
+
for(l=opcodes.length; this.i<l; this.i++) {
|
1338
|
+
opcode = opcodes[this.i];
|
1334
1339
|
|
1335
|
-
if
|
1336
|
-
|
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
|
-
|
1343
|
+
this[opcode.opcode].apply(this, opcode.args);
|
1343
1344
|
}
|
1345
|
+
}
|
1344
1346
|
|
1345
|
-
|
1346
|
-
|
1347
|
-
} else {
|
1348
|
-
out.push("");
|
1349
|
-
}
|
1347
|
+
return this.createFunctionContext(asObject);
|
1348
|
+
},
|
1350
1349
|
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
},
|
1350
|
+
nextOpcode: function() {
|
1351
|
+
var opcodes = this.environment.opcodes;
|
1352
|
+
return opcodes[this.i + 1];
|
1353
|
+
},
|
1356
1354
|
|
1357
|
-
|
1358
|
-
|
1355
|
+
eat: function() {
|
1356
|
+
this.i = this.i + 1;
|
1357
|
+
},
|
1359
1358
|
|
1360
|
-
|
1361
|
-
|
1362
|
-
}
|
1359
|
+
preamble: function() {
|
1360
|
+
var out = [];
|
1363
1361
|
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
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
|
-
|
1372
|
-
|
1373
|
-
|
1372
|
+
if (!this.environment.isSimple) {
|
1373
|
+
out.push(", buffer = " + this.initializeBuffer());
|
1374
|
+
} else {
|
1375
|
+
out.push("");
|
1376
|
+
}
|
1374
1377
|
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
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
|
-
|
1381
|
-
|
1382
|
-
}
|
1384
|
+
createFunctionContext: function(asObject) {
|
1385
|
+
var locals = this.stackVars.concat(this.registers.list);
|
1383
1386
|
|
1384
|
-
|
1387
|
+
if(locals.length > 0) {
|
1388
|
+
this.source[1] = this.source[1] + ", " + locals.join(", ");
|
1389
|
+
}
|
1385
1390
|
|
1386
|
-
|
1387
|
-
|
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
|
-
|
1391
|
-
|
1398
|
+
if (this.source[1]) {
|
1399
|
+
this.source[1] = "var " + this.source[1].substring(2) + ";";
|
1400
|
+
}
|
1392
1401
|
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
}
|
1402
|
+
// Merge children
|
1403
|
+
if (!this.isChild) {
|
1404
|
+
this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
|
1405
|
+
}
|
1398
1406
|
|
1399
|
-
|
1400
|
-
|
1407
|
+
if (!this.environment.isSimple) {
|
1408
|
+
this.source.push("return buffer;");
|
1409
|
+
}
|
1401
1410
|
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
mergeSource
|
1410
|
-
|
1411
|
-
|
1412
|
-
var
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
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
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
source +=
|
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
|
-
|
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
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
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
|
-
|
1464
|
-
|
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
|
-
|
1467
|
-
|
1490
|
+
var params = ["depth0"];
|
1491
|
+
this.setupParams(0, params);
|
1468
1492
|
|
1469
|
-
|
1470
|
-
|
1493
|
+
var current = this.topStack();
|
1494
|
+
params.splice(1, 0, current);
|
1471
1495
|
|
1472
|
-
|
1473
|
-
|
1496
|
+
// Use the options value generated from the invocation
|
1497
|
+
params[params.length-1] = 'options';
|
1474
1498
|
|
1475
|
-
|
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
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
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
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
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
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
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
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
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
|
-
|
1567
|
-
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
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
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
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
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
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
|
-
|
1610
|
-
|
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
|
-
|
1613
|
-
|
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
|
-
|
1624
|
-
|
1625
|
-
}
|
1626
|
-
|
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
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
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
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
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
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
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
|
-
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
|
1670
|
-
|
1671
|
-
|
1672
|
-
|
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
|
-
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
this.
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
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
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
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
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
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
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
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
|
-
|
1754
|
-
|
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
|
-
|
1758
|
-
|
1759
|
-
|
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
|
-
|
1769
|
-
|
1770
|
-
|
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
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
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
|
-
|
1813
|
+
// HELPERS
|
1781
1814
|
|
1782
|
-
|
1815
|
+
compiler: JavaScriptCompiler,
|
1783
1816
|
|
1784
|
-
|
1785
|
-
|
1817
|
+
compileChildren: function(environment, options) {
|
1818
|
+
var children = environment.children, child, compiler;
|
1786
1819
|
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1820
|
+
for(var i=0, l=children.length; i<l; i++) {
|
1821
|
+
child = children[i];
|
1822
|
+
compiler = new this.compiler();
|
1790
1823
|
|
1791
|
-
|
1824
|
+
var index = this.matchExistingProgram(child);
|
1792
1825
|
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
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
|
-
|
1807
|
-
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
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
|
-
|
1819
|
-
|
1820
|
-
}
|
1848
|
+
programExpression: function(guid) {
|
1849
|
+
this.context.aliases.self = "this";
|
1821
1850
|
|
1822
|
-
|
1823
|
-
|
1851
|
+
if(guid == null) {
|
1852
|
+
return "self.noop";
|
1853
|
+
}
|
1824
1854
|
|
1825
|
-
|
1855
|
+
var child = this.environment.children[guid],
|
1856
|
+
depths = child.depths.list, depth;
|
1826
1857
|
|
1827
|
-
|
1828
|
-
depth = depths[i];
|
1858
|
+
var programParams = [child.index, child.name, "data"];
|
1829
1859
|
|
1830
|
-
|
1831
|
-
|
1832
|
-
}
|
1860
|
+
for(var i=0, l = depths.length; i<l; i++) {
|
1861
|
+
depth = depths[i];
|
1833
1862
|
|
1834
|
-
if(
|
1835
|
-
|
1836
|
-
|
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
|
-
|
1843
|
-
|
1844
|
-
this.source.push(name + " = " + val + ";");
|
1845
|
-
},
|
1867
|
+
return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")";
|
1868
|
+
},
|
1846
1869
|
|
1847
|
-
|
1848
|
-
|
1849
|
-
|
1850
|
-
|
1851
|
-
}
|
1852
|
-
},
|
1870
|
+
register: function(name, val) {
|
1871
|
+
this.useRegister(name);
|
1872
|
+
this.source.push(name + " = " + val + ";");
|
1873
|
+
},
|
1853
1874
|
|
1854
|
-
|
1855
|
-
|
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
|
-
|
1859
|
-
|
1882
|
+
pushStackLiteral: function(item) {
|
1883
|
+
return this.push(new Literal(item));
|
1884
|
+
},
|
1860
1885
|
|
1861
|
-
|
1862
|
-
|
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
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
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
|
-
|
1875
|
-
|
1876
|
-
|
1877
|
-
|
1897
|
+
replaceStack: function(callback) {
|
1898
|
+
var prefix = '',
|
1899
|
+
inline = this.isInline(),
|
1900
|
+
stack;
|
1878
1901
|
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
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
|
-
|
1887
|
-
|
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
|
-
|
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
|
-
|
1923
|
+
if (inline) {
|
1924
|
+
if (this.inlineStack.length || this.compileStack.length) {
|
1925
|
+
this.popStack();
|
1907
1926
|
}
|
1908
|
-
|
1909
|
-
}
|
1910
|
-
|
1911
|
-
|
1912
|
-
|
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
|
-
|
1942
|
-
|
1943
|
-
|
1934
|
+
this.source.push(stack + " = (" + prefix + item + ");");
|
1935
|
+
}
|
1936
|
+
return stack;
|
1937
|
+
},
|
1944
1938
|
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
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
|
-
|
1956
|
-
|
1957
|
-
|
1969
|
+
popStack: function(wrapped) {
|
1970
|
+
var inline = this.isInline(),
|
1971
|
+
item = (inline ? this.inlineStack : this.compileStack).pop();
|
1958
1972
|
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
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
|
-
|
1967
|
-
|
1968
|
-
.
|
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
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1987
|
+
if (!wrapped && (item instanceof Literal)) {
|
1988
|
+
return item.value;
|
1989
|
+
} else {
|
1990
|
+
return item;
|
1991
|
+
}
|
1992
|
+
},
|
1978
1993
|
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
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
|
-
|
1988
|
-
|
1989
|
-
setupParams
|
1990
|
-
|
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
|
-
|
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
|
-
|
1995
|
-
|
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
|
-
|
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
|
-
|
2006
|
-
|
2007
|
-
inverse = "self.noop";
|
2008
|
-
}
|
2024
|
+
inverse = this.popStack();
|
2025
|
+
program = this.popStack();
|
2009
2026
|
|
2010
|
-
|
2011
|
-
|
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
|
-
|
2015
|
-
|
2016
|
-
|
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
|
-
|
2025
|
-
|
2026
|
-
|
2027
|
-
options.push("hashTypes:hashTypes");
|
2028
|
-
}
|
2040
|
+
options.push("inverse:" + inverse);
|
2041
|
+
options.push("fn:" + program);
|
2042
|
+
}
|
2029
2043
|
|
2030
|
-
|
2031
|
-
|
2032
|
-
|
2044
|
+
for(var i=0; i<paramSize; i++) {
|
2045
|
+
param = this.popStack();
|
2046
|
+
params.push(param);
|
2033
2047
|
|
2034
|
-
options
|
2035
|
-
|
2036
|
-
this.
|
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
|
-
|
2046
|
-
|
2047
|
-
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
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
|
-
|
2070
|
-
|
2071
|
-
return true;
|
2061
|
+
if(this.options.data) {
|
2062
|
+
options.push("data:data");
|
2072
2063
|
}
|
2073
|
-
return false;
|
2074
|
-
};
|
2075
2064
|
|
2076
|
-
|
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 (
|
2080
|
-
throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.
|
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
|
2089
|
-
return new
|
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 (
|
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
|
2105
|
-
var templateSpec = new
|
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
|
-
|
2130
|
-
} else if(programWrapper) {
|
2131
|
-
|
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
|
2168
|
-
var args = Array.prototype.slice.call(arguments,
|
2196
|
+
programWithDepth: function(i, fn, data /*, $depth */) {
|
2197
|
+
var args = Array.prototype.slice.call(arguments, 3);
|
2169
2198
|
|
2170
|
-
|
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
|
-
|
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
|
+
;
|