barber 0.2.1 → 0.3.0
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.
- data/lib/barber/javascripts/ember-template-compiler.js +310 -95
- data/lib/barber/javascripts/handlebars.js +298 -89
- data/lib/barber/precompiler.rb +1 -1
- data/lib/barber/version.rb +1 -1
- metadata +4 -4
@@ -1,3 +1,27 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
Copyright (C) 2011 by Yehuda Katz
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
22
|
+
|
23
|
+
*/
|
24
|
+
|
1
25
|
// lib/handlebars/base.js
|
2
26
|
|
3
27
|
/*jshint eqnull:true*/
|
@@ -5,7 +29,13 @@ this.Handlebars = {};
|
|
5
29
|
|
6
30
|
(function(Handlebars) {
|
7
31
|
|
8
|
-
Handlebars.VERSION = "1.0.rc.
|
32
|
+
Handlebars.VERSION = "1.0.0-rc.3";
|
33
|
+
Handlebars.COMPILER_REVISION = 2;
|
34
|
+
|
35
|
+
Handlebars.REVISION_CHANGES = {
|
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'
|
38
|
+
};
|
9
39
|
|
10
40
|
Handlebars.helpers = {};
|
11
41
|
Handlebars.partials = {};
|
@@ -618,9 +648,13 @@ return new Parser;
|
|
618
648
|
// lib/handlebars/compiler/base.js
|
619
649
|
Handlebars.Parser = handlebars;
|
620
650
|
|
621
|
-
Handlebars.parse = function(
|
651
|
+
Handlebars.parse = function(input) {
|
652
|
+
|
653
|
+
// Just return if an already-compile AST was passed in.
|
654
|
+
if(input.constructor === Handlebars.AST.ProgramNode) { return input; }
|
655
|
+
|
622
656
|
Handlebars.Parser.yy = Handlebars.AST;
|
623
|
-
return Handlebars.Parser.parse(
|
657
|
+
return Handlebars.Parser.parse(input);
|
624
658
|
};
|
625
659
|
|
626
660
|
Handlebars.print = function(ast) {
|
@@ -702,8 +736,11 @@ Handlebars.print = function(ast) {
|
|
702
736
|
for(var i=0,l=parts.length; i<l; i++) {
|
703
737
|
var part = parts[i];
|
704
738
|
|
705
|
-
if(part === "..") {
|
706
|
-
|
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
|
+
}
|
707
744
|
else { dig.push(part); }
|
708
745
|
}
|
709
746
|
|
@@ -853,6 +890,26 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
853
890
|
|
854
891
|
return out.join("\n");
|
855
892
|
},
|
893
|
+
equals: function(other) {
|
894
|
+
var len = this.opcodes.length;
|
895
|
+
if (other.opcodes.length !== len) {
|
896
|
+
return false;
|
897
|
+
}
|
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) {
|
903
|
+
return false;
|
904
|
+
}
|
905
|
+
for (var j = 0; j < opcode.args.length; j++) {
|
906
|
+
if (opcode.args[j] !== otherOpcode.args[j]) {
|
907
|
+
return false;
|
908
|
+
}
|
909
|
+
}
|
910
|
+
}
|
911
|
+
return true;
|
912
|
+
},
|
856
913
|
|
857
914
|
guid: 0,
|
858
915
|
|
@@ -944,7 +1001,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
944
1001
|
// evaluate it by executing `blockHelperMissing`
|
945
1002
|
this.opcode('pushProgram', program);
|
946
1003
|
this.opcode('pushProgram', inverse);
|
947
|
-
this.opcode('
|
1004
|
+
this.opcode('emptyHash');
|
948
1005
|
this.opcode('blockValue');
|
949
1006
|
} else {
|
950
1007
|
this.ambiguousMustache(mustache, program, inverse);
|
@@ -953,7 +1010,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
953
1010
|
// evaluate it by executing `blockHelperMissing`
|
954
1011
|
this.opcode('pushProgram', program);
|
955
1012
|
this.opcode('pushProgram', inverse);
|
956
|
-
this.opcode('
|
1013
|
+
this.opcode('emptyHash');
|
957
1014
|
this.opcode('ambiguousBlockValue');
|
958
1015
|
}
|
959
1016
|
|
@@ -977,6 +1034,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
977
1034
|
|
978
1035
|
this.opcode('assignToHash', pair[0]);
|
979
1036
|
}
|
1037
|
+
this.opcode('popHash');
|
980
1038
|
},
|
981
1039
|
|
982
1040
|
partial: function(partial) {
|
@@ -1017,17 +1075,19 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1017
1075
|
},
|
1018
1076
|
|
1019
1077
|
ambiguousMustache: function(mustache, program, inverse) {
|
1020
|
-
var id = mustache.id,
|
1078
|
+
var id = mustache.id,
|
1079
|
+
name = id.parts[0],
|
1080
|
+
isBlock = program != null || inverse != null;
|
1021
1081
|
|
1022
1082
|
this.opcode('getContext', id.depth);
|
1023
1083
|
|
1024
1084
|
this.opcode('pushProgram', program);
|
1025
1085
|
this.opcode('pushProgram', inverse);
|
1026
1086
|
|
1027
|
-
this.opcode('invokeAmbiguous', name);
|
1087
|
+
this.opcode('invokeAmbiguous', name, isBlock);
|
1028
1088
|
},
|
1029
1089
|
|
1030
|
-
simpleMustache: function(mustache
|
1090
|
+
simpleMustache: function(mustache) {
|
1031
1091
|
var id = mustache.id;
|
1032
1092
|
|
1033
1093
|
if (id.type === 'DATA') {
|
@@ -1158,7 +1218,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1158
1218
|
if(mustache.hash) {
|
1159
1219
|
this.hash(mustache.hash);
|
1160
1220
|
} else {
|
1161
|
-
this.opcode('
|
1221
|
+
this.opcode('emptyHash');
|
1162
1222
|
}
|
1163
1223
|
|
1164
1224
|
return params;
|
@@ -1175,7 +1235,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1175
1235
|
if(mustache.hash) {
|
1176
1236
|
this.hash(mustache.hash);
|
1177
1237
|
} else {
|
1178
|
-
this.opcode('
|
1238
|
+
this.opcode('emptyHash');
|
1179
1239
|
}
|
1180
1240
|
|
1181
1241
|
return params;
|
@@ -1189,7 +1249,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1189
1249
|
JavaScriptCompiler.prototype = {
|
1190
1250
|
// PUBLIC API: You can override these methods in a subclass to provide
|
1191
1251
|
// alternative compiled forms for name lookup and buffering semantics
|
1192
|
-
nameLookup: function(parent, name, type) {
|
1252
|
+
nameLookup: function(parent, name /* , type*/) {
|
1193
1253
|
if (/^[0-9]+$/.test(name)) {
|
1194
1254
|
return parent + "[" + name + "]";
|
1195
1255
|
} else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
|
@@ -1204,7 +1264,11 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1204
1264
|
if (this.environment.isSimple) {
|
1205
1265
|
return "return " + string + ";";
|
1206
1266
|
} else {
|
1207
|
-
return
|
1267
|
+
return {
|
1268
|
+
appendToBuffer: true,
|
1269
|
+
content: string,
|
1270
|
+
toString: function() { return "buffer += " + string + ";"; }
|
1271
|
+
};
|
1208
1272
|
}
|
1209
1273
|
},
|
1210
1274
|
|
@@ -1225,6 +1289,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1225
1289
|
this.isChild = !!context;
|
1226
1290
|
this.context = context || {
|
1227
1291
|
programs: [],
|
1292
|
+
environments: [],
|
1228
1293
|
aliases: { }
|
1229
1294
|
};
|
1230
1295
|
|
@@ -1234,6 +1299,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1234
1299
|
this.stackVars = [];
|
1235
1300
|
this.registers = { list: [] };
|
1236
1301
|
this.compileStack = [];
|
1302
|
+
this.inlineStack = [];
|
1237
1303
|
|
1238
1304
|
this.compileChildren(environment, options);
|
1239
1305
|
|
@@ -1255,11 +1321,11 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1255
1321
|
},
|
1256
1322
|
|
1257
1323
|
nextOpcode: function() {
|
1258
|
-
var opcodes = this.environment.opcodes
|
1324
|
+
var opcodes = this.environment.opcodes;
|
1259
1325
|
return opcodes[this.i + 1];
|
1260
1326
|
},
|
1261
1327
|
|
1262
|
-
eat: function(
|
1328
|
+
eat: function() {
|
1263
1329
|
this.i = this.i + 1;
|
1264
1330
|
},
|
1265
1331
|
|
@@ -1297,7 +1363,6 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1297
1363
|
|
1298
1364
|
// Generate minimizer alias mappings
|
1299
1365
|
if (!this.isChild) {
|
1300
|
-
var aliases = [];
|
1301
1366
|
for (var alias in this.context.aliases) {
|
1302
1367
|
this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
|
1303
1368
|
}
|
@@ -1322,16 +1387,48 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1322
1387
|
params.push("depth" + this.environment.depths.list[i]);
|
1323
1388
|
}
|
1324
1389
|
|
1390
|
+
// Perform a second pass over the output to merge content when possible
|
1391
|
+
var source = this.mergeSource();
|
1392
|
+
|
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
|
+
}
|
1398
|
+
|
1325
1399
|
if (asObject) {
|
1326
|
-
params.push(
|
1400
|
+
params.push(source);
|
1327
1401
|
|
1328
1402
|
return Function.apply(this, params);
|
1329
1403
|
} else {
|
1330
|
-
var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' +
|
1404
|
+
var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
|
1331
1405
|
Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
|
1332
1406
|
return functionSource;
|
1333
1407
|
}
|
1334
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
|
+
}
|
1422
|
+
} else {
|
1423
|
+
if (buffer) {
|
1424
|
+
source += 'buffer += ' + buffer + ';\n ';
|
1425
|
+
buffer = undefined;
|
1426
|
+
}
|
1427
|
+
source += line + '\n ';
|
1428
|
+
}
|
1429
|
+
}
|
1430
|
+
return source;
|
1431
|
+
},
|
1335
1432
|
|
1336
1433
|
// [blockValue]
|
1337
1434
|
//
|
@@ -1369,6 +1466,9 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1369
1466
|
var current = this.topStack();
|
1370
1467
|
params.splice(1, 0, current);
|
1371
1468
|
|
1469
|
+
// Use the options value generated from the invocation
|
1470
|
+
params[params.length-1] = 'options';
|
1471
|
+
|
1372
1472
|
this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
|
1373
1473
|
},
|
1374
1474
|
|
@@ -1392,6 +1492,9 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1392
1492
|
// If `value` is truthy, or 0, it is coerced into a string and appended
|
1393
1493
|
// Otherwise, the empty string is appended
|
1394
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();
|
1395
1498
|
var local = this.popStack();
|
1396
1499
|
this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
|
1397
1500
|
if (this.environment.isSimple) {
|
@@ -1406,15 +1509,9 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1406
1509
|
//
|
1407
1510
|
// Escape `value` and append it to the buffer
|
1408
1511
|
appendEscaped: function() {
|
1409
|
-
var opcode = this.nextOpcode(), extra = "";
|
1410
1512
|
this.context.aliases.escapeExpression = 'this.escapeExpression';
|
1411
1513
|
|
1412
|
-
|
1413
|
-
extra = " + " + this.quotedString(opcode.args[0]);
|
1414
|
-
this.eat(opcode);
|
1415
|
-
}
|
1416
|
-
|
1417
|
-
this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra));
|
1514
|
+
this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
|
1418
1515
|
},
|
1419
1516
|
|
1420
1517
|
// [getContext]
|
@@ -1438,7 +1535,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1438
1535
|
// Looks up the value of `name` on the current context and pushes
|
1439
1536
|
// it onto the stack.
|
1440
1537
|
lookupOnContext: function(name) {
|
1441
|
-
this.
|
1538
|
+
this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
|
1442
1539
|
},
|
1443
1540
|
|
1444
1541
|
// [pushContext]
|
@@ -1486,7 +1583,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1486
1583
|
//
|
1487
1584
|
// Push the result of looking up `id` on the current data
|
1488
1585
|
lookupData: function(id) {
|
1489
|
-
this.
|
1586
|
+
this.push(this.nameLookup('data', id, 'data'));
|
1490
1587
|
},
|
1491
1588
|
|
1492
1589
|
// [pushStringParam]
|
@@ -1509,13 +1606,25 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1509
1606
|
}
|
1510
1607
|
},
|
1511
1608
|
|
1512
|
-
|
1513
|
-
this.
|
1609
|
+
emptyHash: function() {
|
1610
|
+
this.pushStackLiteral('{}');
|
1514
1611
|
|
1515
1612
|
if (this.options.stringParams) {
|
1516
1613
|
this.register('hashTypes', '{}');
|
1517
1614
|
}
|
1518
1615
|
},
|
1616
|
+
pushHash: function() {
|
1617
|
+
this.hash = {values: [], types: []};
|
1618
|
+
},
|
1619
|
+
popHash: function() {
|
1620
|
+
var hash = this.hash;
|
1621
|
+
this.hash = undefined;
|
1622
|
+
|
1623
|
+
if (this.options.stringParams) {
|
1624
|
+
this.register('hashTypes', '{' + hash.types.join(',') + '}');
|
1625
|
+
}
|
1626
|
+
this.push('{\n ' + hash.values.join(',\n ') + '\n }');
|
1627
|
+
},
|
1519
1628
|
|
1520
1629
|
// [pushString]
|
1521
1630
|
//
|
@@ -1534,7 +1643,8 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1534
1643
|
//
|
1535
1644
|
// Push an expression onto the stack
|
1536
1645
|
push: function(expr) {
|
1537
|
-
this.
|
1646
|
+
this.inlineStack.push(expr);
|
1647
|
+
return expr;
|
1538
1648
|
},
|
1539
1649
|
|
1540
1650
|
// [pushLiteral]
|
@@ -1577,12 +1687,14 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1577
1687
|
invokeHelper: function(paramSize, name) {
|
1578
1688
|
this.context.aliases.helperMissing = 'helpers.helperMissing';
|
1579
1689
|
|
1580
|
-
var helper = this.lastHelper = this.setupHelper(paramSize, name);
|
1581
|
-
this.register('foundHelper', helper.name);
|
1690
|
+
var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
|
1582
1691
|
|
1583
|
-
this.
|
1584
|
-
|
1585
|
-
|
1692
|
+
this.push(helper.name);
|
1693
|
+
this.replaceStack(function(name) {
|
1694
|
+
return name + ' ? ' + name + '.call(' +
|
1695
|
+
helper.callParams + ") " + ": helperMissing.call(" +
|
1696
|
+
helper.helperMissingParams + ")";
|
1697
|
+
});
|
1586
1698
|
},
|
1587
1699
|
|
1588
1700
|
// [invokeKnownHelper]
|
@@ -1594,7 +1706,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1594
1706
|
// so a `helperMissing` fallback is not required.
|
1595
1707
|
invokeKnownHelper: function(paramSize, name) {
|
1596
1708
|
var helper = this.setupHelper(paramSize, name);
|
1597
|
-
this.
|
1709
|
+
this.push(helper.name + ".call(" + helper.callParams + ")");
|
1598
1710
|
},
|
1599
1711
|
|
1600
1712
|
// [invokeAmbiguous]
|
@@ -1609,19 +1721,18 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1609
1721
|
// This operation emits more code than the other options,
|
1610
1722
|
// and can be avoided by passing the `knownHelpers` and
|
1611
1723
|
// `knownHelpersOnly` flags at compile-time.
|
1612
|
-
invokeAmbiguous: function(name) {
|
1724
|
+
invokeAmbiguous: function(name, helperCall) {
|
1613
1725
|
this.context.aliases.functionType = '"function"';
|
1614
1726
|
|
1615
|
-
this.pushStackLiteral('{}');
|
1616
|
-
var helper = this.setupHelper(0, name);
|
1727
|
+
this.pushStackLiteral('{}'); // Hash value
|
1728
|
+
var helper = this.setupHelper(0, name, helperCall);
|
1617
1729
|
|
1618
1730
|
var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
|
1619
|
-
this.register('foundHelper', helperName);
|
1620
1731
|
|
1621
1732
|
var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
|
1622
1733
|
var nextStack = this.nextStack();
|
1623
1734
|
|
1624
|
-
this.source.push('if (
|
1735
|
+
this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
|
1625
1736
|
this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }');
|
1626
1737
|
},
|
1627
1738
|
|
@@ -1640,7 +1751,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1640
1751
|
}
|
1641
1752
|
|
1642
1753
|
this.context.aliases.self = "this";
|
1643
|
-
this.
|
1754
|
+
this.push("self.invokePartial(" + params.join(", ") + ")");
|
1644
1755
|
},
|
1645
1756
|
|
1646
1757
|
// [assignToHash]
|
@@ -1651,17 +1762,19 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1651
1762
|
// Pops a value and hash off the stack, assigns `hash[key] = value`
|
1652
1763
|
// and pushes the hash back onto the stack.
|
1653
1764
|
assignToHash: function(key) {
|
1654
|
-
var value = this.popStack()
|
1765
|
+
var value = this.popStack(),
|
1766
|
+
type;
|
1655
1767
|
|
1656
1768
|
if (this.options.stringParams) {
|
1657
|
-
|
1769
|
+
type = this.popStack();
|
1658
1770
|
this.popStack();
|
1659
|
-
this.source.push("hashTypes['" + key + "'] = " + type + ";");
|
1660
1771
|
}
|
1661
1772
|
|
1662
|
-
var hash = this.
|
1663
|
-
|
1664
|
-
|
1773
|
+
var hash = this.hash;
|
1774
|
+
if (type) {
|
1775
|
+
hash.types.push("'" + key + "': " + type);
|
1776
|
+
}
|
1777
|
+
hash.values.push("'" + key + "': (" + value + ")");
|
1665
1778
|
},
|
1666
1779
|
|
1667
1780
|
// HELPERS
|
@@ -1675,11 +1788,27 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1675
1788
|
child = children[i];
|
1676
1789
|
compiler = new this.compiler();
|
1677
1790
|
|
1678
|
-
this.
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1791
|
+
var index = this.matchExistingProgram(child);
|
1792
|
+
|
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
|
+
}
|
1804
|
+
}
|
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
|
+
}
|
1683
1812
|
}
|
1684
1813
|
},
|
1685
1814
|
|
@@ -1723,57 +1852,111 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1723
1852
|
},
|
1724
1853
|
|
1725
1854
|
pushStackLiteral: function(item) {
|
1726
|
-
this.
|
1727
|
-
return item;
|
1855
|
+
return this.push(new Literal(item));
|
1728
1856
|
},
|
1729
1857
|
|
1730
1858
|
pushStack: function(item) {
|
1859
|
+
this.flushInline();
|
1860
|
+
|
1731
1861
|
var stack = this.incrStack();
|
1732
|
-
|
1862
|
+
if (item) {
|
1863
|
+
this.source.push(stack + " = " + item + ";");
|
1864
|
+
}
|
1733
1865
|
this.compileStack.push(stack);
|
1734
1866
|
return stack;
|
1735
1867
|
},
|
1736
1868
|
|
1737
1869
|
replaceStack: function(callback) {
|
1738
|
-
var
|
1739
|
-
|
1870
|
+
var prefix = '',
|
1871
|
+
inline = this.isInline(),
|
1872
|
+
stack;
|
1873
|
+
|
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);
|
1878
|
+
|
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();
|
1740
1885
|
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1886
|
+
prefix = '(' + this.push(name) + ' = ' + top + '),';
|
1887
|
+
stack = this.topStack();
|
1888
|
+
}
|
1889
|
+
} else {
|
1890
|
+
stack = this.topStack();
|
1744
1891
|
}
|
1745
1892
|
|
1746
|
-
|
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
|
+
}
|
1905
|
+
|
1906
|
+
this.source.push(stack + " = (" + prefix + item + ");");
|
1907
|
+
}
|
1747
1908
|
return stack;
|
1748
1909
|
},
|
1749
1910
|
|
1750
|
-
nextStack: function(
|
1751
|
-
|
1752
|
-
this.compileStack.push(name);
|
1753
|
-
return name;
|
1911
|
+
nextStack: function() {
|
1912
|
+
return this.pushStack();
|
1754
1913
|
},
|
1755
1914
|
|
1756
1915
|
incrStack: function() {
|
1757
1916
|
this.stackSlot++;
|
1758
1917
|
if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
|
1918
|
+
return this.topStackName();
|
1919
|
+
},
|
1920
|
+
topStackName: function() {
|
1759
1921
|
return "stack" + this.stackSlot;
|
1760
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
|
+
}
|
1935
|
+
}
|
1936
|
+
},
|
1937
|
+
isInline: function() {
|
1938
|
+
return this.inlineStack.length;
|
1939
|
+
},
|
1761
1940
|
|
1762
|
-
popStack: function() {
|
1763
|
-
var
|
1941
|
+
popStack: function(wrapped) {
|
1942
|
+
var inline = this.isInline(),
|
1943
|
+
item = (inline ? this.inlineStack : this.compileStack).pop();
|
1764
1944
|
|
1765
|
-
if (item instanceof Literal) {
|
1945
|
+
if (!wrapped && (item instanceof Literal)) {
|
1766
1946
|
return item.value;
|
1767
1947
|
} else {
|
1768
|
-
|
1948
|
+
if (!inline) {
|
1949
|
+
this.stackSlot--;
|
1950
|
+
}
|
1769
1951
|
return item;
|
1770
1952
|
}
|
1771
1953
|
},
|
1772
1954
|
|
1773
|
-
topStack: function() {
|
1774
|
-
var
|
1955
|
+
topStack: function(wrapped) {
|
1956
|
+
var stack = (this.isInline() ? this.inlineStack : this.compileStack),
|
1957
|
+
item = stack[stack.length - 1];
|
1775
1958
|
|
1776
|
-
if (item instanceof Literal) {
|
1959
|
+
if (!wrapped && (item instanceof Literal)) {
|
1777
1960
|
return item.value;
|
1778
1961
|
} else {
|
1779
1962
|
return item;
|
@@ -1788,22 +1971,22 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1788
1971
|
.replace(/\r/g, '\\r') + '"';
|
1789
1972
|
},
|
1790
1973
|
|
1791
|
-
setupHelper: function(paramSize, name) {
|
1974
|
+
setupHelper: function(paramSize, name, missingParams) {
|
1792
1975
|
var params = [];
|
1793
|
-
this.setupParams(paramSize, params);
|
1976
|
+
this.setupParams(paramSize, params, missingParams);
|
1794
1977
|
var foundHelper = this.nameLookup('helpers', name, 'helper');
|
1795
1978
|
|
1796
1979
|
return {
|
1797
1980
|
params: params,
|
1798
1981
|
name: foundHelper,
|
1799
1982
|
callParams: ["depth0"].concat(params).join(", "),
|
1800
|
-
helperMissingParams: ["depth0", this.quotedString(name)].concat(params).join(", ")
|
1983
|
+
helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
|
1801
1984
|
};
|
1802
1985
|
},
|
1803
1986
|
|
1804
1987
|
// the params and contexts arguments are passed in arrays
|
1805
1988
|
// to fill in
|
1806
|
-
setupParams: function(paramSize, params) {
|
1989
|
+
setupParams: function(paramSize, params, useRegister) {
|
1807
1990
|
var options = [], contexts = [], types = [], param, inverse, program;
|
1808
1991
|
|
1809
1992
|
options.push("hash:" + this.popStack());
|
@@ -1848,7 +2031,13 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1848
2031
|
options.push("data:data");
|
1849
2032
|
}
|
1850
2033
|
|
1851
|
-
|
2034
|
+
options = "{" + options.join(",") + "}";
|
2035
|
+
if (useRegister) {
|
2036
|
+
this.register('options', options);
|
2037
|
+
params.push('options');
|
2038
|
+
} else {
|
2039
|
+
params.push(options);
|
2040
|
+
}
|
1852
2041
|
return params.join(", ");
|
1853
2042
|
}
|
1854
2043
|
};
|
@@ -1886,23 +2075,23 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1886
2075
|
|
1887
2076
|
})(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
|
1888
2077
|
|
1889
|
-
Handlebars.precompile = function(
|
1890
|
-
if (typeof
|
1891
|
-
throw new Handlebars.Exception("You must pass a string to Handlebars.compile. You passed " +
|
2078
|
+
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);
|
1892
2081
|
}
|
1893
2082
|
|
1894
2083
|
options = options || {};
|
1895
2084
|
if (!('data' in options)) {
|
1896
2085
|
options.data = true;
|
1897
2086
|
}
|
1898
|
-
var ast = Handlebars.parse(
|
2087
|
+
var ast = Handlebars.parse(input);
|
1899
2088
|
var environment = new Handlebars.Compiler().compile(ast, options);
|
1900
2089
|
return new Handlebars.JavaScriptCompiler().compile(environment, options);
|
1901
2090
|
};
|
1902
2091
|
|
1903
|
-
Handlebars.compile = function(
|
1904
|
-
if (typeof
|
1905
|
-
throw new Handlebars.Exception("You must pass a string to Handlebars.compile. You passed " +
|
2092
|
+
Handlebars.compile = function(input, options) {
|
2093
|
+
if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
|
2094
|
+
throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
|
1906
2095
|
}
|
1907
2096
|
|
1908
2097
|
options = options || {};
|
@@ -1911,7 +2100,7 @@ Handlebars.compile = function(string, options) {
|
|
1911
2100
|
}
|
1912
2101
|
var compiled;
|
1913
2102
|
function compile() {
|
1914
|
-
var ast = Handlebars.parse(
|
2103
|
+
var ast = Handlebars.parse(input);
|
1915
2104
|
var environment = new Handlebars.Compiler().compile(ast, options);
|
1916
2105
|
var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
|
1917
2106
|
return Handlebars.template(templateSpec);
|
@@ -1946,12 +2135,32 @@ Handlebars.VM = {
|
|
1946
2135
|
}
|
1947
2136
|
},
|
1948
2137
|
programWithDepth: Handlebars.VM.programWithDepth,
|
1949
|
-
noop: Handlebars.VM.noop
|
2138
|
+
noop: Handlebars.VM.noop,
|
2139
|
+
compilerInfo: null
|
1950
2140
|
};
|
1951
2141
|
|
1952
2142
|
return function(context, options) {
|
1953
2143
|
options = options || {};
|
1954
|
-
|
2144
|
+
var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
|
2145
|
+
|
2146
|
+
var compilerInfo = container.compilerInfo || [],
|
2147
|
+
compilerRevision = compilerInfo[0] || 1,
|
2148
|
+
currentRevision = Handlebars.COMPILER_REVISION;
|
2149
|
+
|
2150
|
+
if (compilerRevision !== currentRevision) {
|
2151
|
+
if (compilerRevision < currentRevision) {
|
2152
|
+
var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision],
|
2153
|
+
compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision];
|
2154
|
+
throw "Template was precompiled with an older version of Handlebars than the current runtime. "+
|
2155
|
+
"Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").";
|
2156
|
+
} else {
|
2157
|
+
// Use the embedded version info since the runtime doesn't know about this revision yet
|
2158
|
+
throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+
|
2159
|
+
"Please update your runtime to a newer version ("+compilerInfo[1]+").";
|
2160
|
+
}
|
2161
|
+
}
|
2162
|
+
|
2163
|
+
return result;
|
1955
2164
|
};
|
1956
2165
|
},
|
1957
2166
|
|