summaryrefslogtreecommitdiffstats
path: root/lib/handlebars/compiler/javascript-compiler.js
diff options
context:
space:
mode:
authorkpdecker <kpdecker@gmail.com>2014-11-08 18:53:43 -0600
committerkpdecker <kpdecker@gmail.com>2014-11-08 18:53:43 -0600
commitac208b1bcd5f5661a4eabaeba1b6ef0c8767bad0 (patch)
tree9174a2e3a04484d119b18735fdfaf02b8ccf617e /lib/handlebars/compiler/javascript-compiler.js
parent8dfeabdd16ddbd940e17b053a5eddc36a7e26ee8 (diff)
downloadhandlebars.js-ac208b1bcd5f5661a4eabaeba1b6ef0c8767bad0.zip
handlebars.js-ac208b1bcd5f5661a4eabaeba1b6ef0c8767bad0.tar.gz
handlebars.js-ac208b1bcd5f5661a4eabaeba1b6ef0c8767bad0.tar.bz2
Only provide aliases for multiple use calls
Fixes #903
Diffstat (limited to 'lib/handlebars/compiler/javascript-compiler.js')
-rw-r--r--lib/handlebars/compiler/javascript-compiler.js65
1 files changed, 39 insertions, 26 deletions
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js
index 869a672..70af132 100644
--- a/lib/handlebars/compiler/javascript-compiler.js
+++ b/lib/handlebars/compiler/javascript-compiler.js
@@ -20,9 +20,7 @@ JavaScriptCompiler.prototype = {
}
},
depthedLookup: function(name) {
- this.aliases.lookup = 'this.lookup';
-
- return ['lookup(depths, "', name, '")'];
+ return [this.aliasable('this.lookup'), '(depths, "', name, '")'];
},
compilerInfo: function() {
@@ -171,9 +169,18 @@ JavaScriptCompiler.prototype = {
}
// Generate minimizer alias mappings
+ //
+ // When using true SourceNodes, this will update all references to the given alias
+ // as the source nodes are reused in situ. For the non-source node compilation mode,
+ // aliases will not be used, but this case is already being run on the client and
+ // we aren't concern about minimizing the template size.
+ var aliasCount = 0;
for (var alias in this.aliases) {
- if (this.aliases.hasOwnProperty(alias)) {
- varDeclarations += ', ' + alias + '=' + this.aliases[alias];
+ var node = this.aliases[alias];
+
+ if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {
+ varDeclarations += ', alias' + (++aliasCount) + '=' + alias;
+ node.children[0] = 'alias' + aliasCount;
}
}
@@ -264,15 +271,14 @@ JavaScriptCompiler.prototype = {
// replace it on the stack with the result of properly
// invoking blockHelperMissing.
blockValue: function(name) {
- this.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
-
- var params = [this.contextName(0)];
+ var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
+ params = [this.contextName(0)];
this.setupParams(name, 0, params);
var blockName = this.popStack();
params.splice(1, 0, blockName);
- this.push(this.source.functionCall('blockHelperMissing', 'call', params));
+ this.push(this.source.functionCall(blockHelperMissing, 'call', params));
},
// [ambiguousBlockValue]
@@ -282,10 +288,9 @@ JavaScriptCompiler.prototype = {
// On stack, after, if no lastHelper: same as [blockValue]
// On stack, after, if lastHelper: value
ambiguousBlockValue: function() {
- this.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
-
// We're being a bit cheeky and reusing the options value from the prior exec
- var params = [this.contextName(0)];
+ var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
+ params = [this.contextName(0)];
this.setupParams('', 0, params, true);
this.flushInline();
@@ -295,7 +300,7 @@ JavaScriptCompiler.prototype = {
this.pushSource([
'if (!', this.lastHelper, ') { ',
- current, ' = ', this.source.functionCall('blockHelperMissing', 'call', params),
+ current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params),
'}']);
},
@@ -347,9 +352,8 @@ JavaScriptCompiler.prototype = {
//
// Escape `value` and append it to the buffer
appendEscaped: function() {
- this.aliases.escapeExpression = 'this.escapeExpression';
-
- this.pushSource(this.appendToBuffer(['escapeExpression(', this.popStack(), ')']));
+ this.pushSource(this.appendToBuffer(
+ [this.aliasable('this.escapeExpression'), '(', this.popStack(), ')']));
},
// [getContext]
@@ -438,9 +442,7 @@ JavaScriptCompiler.prototype = {
// If the `value` is a lambda, replace it on the stack by
// the return value of the lambda
resolvePossibleLambda: function() {
- this.aliases.lambda = 'this.lambda';
-
- this.push(['lambda(', this.popStack(), ', ', this.contextName(0), ')']);
+ this.push([this.aliasable('this.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);
},
// [pushStringParam]
@@ -546,15 +548,13 @@ JavaScriptCompiler.prototype = {
//
// If the helper is not found, `helperMissing` is called.
invokeHelper: function(paramSize, name, isSimple) {
- this.aliases.helperMissing = 'helpers.helperMissing';
-
var nonHelper = this.popStack();
var helper = this.setupHelper(paramSize, name);
var simple = isSimple ? [helper.name, ' || '] : '';
this.push(
this.source.functionCall(
- ['('].concat(simple, nonHelper, ' || ', 'helperMissing)'),
+ ['('].concat(simple, nonHelper, ' || ', this.aliasable('helpers.helperMissing'), ')'),
'call',
helper.callParams));
},
@@ -584,8 +584,6 @@ JavaScriptCompiler.prototype = {
// and can be avoided by passing the `knownHelpers` and
// `knownHelpersOnly` flags at compile-time.
invokeAmbiguous: function(name, helperCall) {
- this.aliases.functionType = '"function"';
- this.aliases.helperMissing = 'helpers.helperMissing';
this.useRegister('helper');
var nonHelper = this.popStack();
@@ -596,9 +594,10 @@ JavaScriptCompiler.prototype = {
var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
this.push([
- '((helper = (helper = ', helperName, ' || ', nonHelper, ') != null ? helper : helperMissing',
+ '((helper = (helper = ', helperName, ' || ', nonHelper, ') != null ? helper : ',
+ this.aliasable('helpers.helperMissing'),
(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',
- '(typeof helper === functionType ? ',
+ '(typeof helper === ', this.aliasable('"function"'), ' ? ',
this.source.functionCall('helper','call', helper.callParams), ' : helper))'
]);
},
@@ -865,6 +864,20 @@ JavaScriptCompiler.prototype = {
return this.source.objectLiteral(obj);
},
+ aliasable: function(name) {
+ var ret = this.aliases[name];
+ if (ret) {
+ ret.referenceCount++;
+ return ret;
+ }
+
+ ret = this.aliases[name] = this.source.wrap(name);
+ ret.aliasable = true;
+ ret.referenceCount = 1;
+
+ return ret;
+ },
+
setupHelper: function(paramSize, name, blockHelper) {
var params = [],
paramsInit = this.setupParams(name, paramSize, params, blockHelper);