summaryrefslogtreecommitdiffstats
path: root/lib/handlebars/compiler/javascript-compiler.js
diff options
context:
space:
mode:
authorkpdecker <kpdecker@gmail.com>2014-01-19 17:32:25 -0600
committerkpdecker <kpdecker@gmail.com>2014-02-06 23:05:45 -0800
commit2812fe27758e38dbefad8b02c61ffb19aabf2410 (patch)
tree3d8acaf8d9cf3fdcf1e5f78b4e737bb5a19f0dd2 /lib/handlebars/compiler/javascript-compiler.js
parent8f07bbabeabaed5d8100261b952c9de07fad7a8c (diff)
downloadhandlebars.js-2812fe27758e38dbefad8b02c61ffb19aabf2410.zip
handlebars.js-2812fe27758e38dbefad8b02c61ffb19aabf2410.tar.gz
handlebars.js-2812fe27758e38dbefad8b02c61ffb19aabf2410.tar.bz2
Convert template spec to object literal
This allows for metadata to be associated with the template and a simplification of the template init logic.
Diffstat (limited to 'lib/handlebars/compiler/javascript-compiler.js')
-rw-r--r--lib/handlebars/compiler/javascript-compiler.js112
1 files changed, 55 insertions, 57 deletions
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js
index ff6bc47..f0ae5ac 100644
--- a/lib/handlebars/compiler/javascript-compiler.js
+++ b/lib/handlebars/compiler/javascript-compiler.js
@@ -35,7 +35,7 @@ JavaScriptCompiler.prototype = {
compilerInfo: function() {
var revision = COMPILER_REVISION,
versions = REVISION_CHANGES[revision];
- return "this.compilerInfo = ["+revision+",'"+versions+"'];\n";
+ return [revision, versions];
},
appendToBuffer: function(string) {
@@ -62,6 +62,7 @@ JavaScriptCompiler.prototype = {
this.options = options || {};
this.stringParams = this.options.stringParams;
this.trackIds = this.options.trackIds;
+ this.precompile = !asObject;
log('debug', this.environment.disassemble() + "\n\n");
@@ -69,14 +70,14 @@ JavaScriptCompiler.prototype = {
this.isChild = !!context;
this.context = context || {
programs: [],
- environments: [],
- aliases: { }
+ environments: []
};
this.preamble();
this.stackSlot = 0;
this.stackVars = [];
+ this.aliases = {};
this.registers = { list: [] };
this.hashes = [];
this.compileStack = [];
@@ -110,22 +111,38 @@ JavaScriptCompiler.prototype = {
throw new Exception('Compile completed with content left on stack');
}
- return this.createFunctionContext(asObject);
- },
+ var fn = this.createFunctionContext(asObject);
+ if (!this.isChild) {
+ var ret = {
+ compiler: this.compilerInfo(),
+ main: fn
+ };
+ this.context.programs.map(function(program, index) {
+ if (program) {
+ ret[index] = program;
+ }
+ });
- preamble: function() {
- var out = [];
+ if (this.environment.usePartial) {
+ ret.usePartial = true;
+ }
+ if (this.options.data) {
+ ret.useData = true;
+ }
- if (!this.isChild) {
- var namespace = this.namespace;
+ if (!asObject) {
+ ret.compiler = JSON.stringify(ret.compiler);
+ ret = this.objectLiteral(ret);
+ }
- var copies = "helpers = this.merge(helpers, " + namespace + ".helpers);";
- if (this.environment.usePartial) { copies = copies + " partials = this.merge(partials, " + namespace + ".partials);"; }
- if (this.options.data) { copies = copies + " data = this.initData(depth0, data);"; }
- out.push(copies);
+ return ret;
} else {
- out.push('');
+ return fn;
}
+ },
+
+ preamble: function() {
+ var out = [];
if (!this.environment.isSimple) {
out.push(", buffer = " + this.initializeBuffer());
@@ -143,32 +160,25 @@ JavaScriptCompiler.prototype = {
var locals = this.stackVars.concat(this.registers.list);
if(locals.length > 0) {
- this.source[1] = this.source[1] + ", " + locals.join(", ");
+ this.source[0] += ", " + locals.join(", ");
}
// Generate minimizer alias mappings
- if (!this.isChild) {
- for (var alias in this.context.aliases) {
- if (this.context.aliases.hasOwnProperty(alias)) {
- this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
- }
+ for (var alias in this.aliases) {
+ if (this.aliases.hasOwnProperty(alias)) {
+ this.source[0] += ', ' + alias + '=' + this.aliases[alias];
}
}
- if (this.source[1]) {
- this.source[1] = "var " + this.source[1].substring(2) + ";";
- }
-
- // Merge children
- if (!this.isChild) {
- this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
+ if (this.source[0]) {
+ this.source[0] = "var " + this.source[0].substring(2) + ";";
}
if (!this.environment.isSimple) {
this.pushSource("return buffer;");
}
- var params = this.isChild ? ["depth0", "data"] : [this.namespace, "depth0", "helpers", "partials", "data"];
+ var params = ["depth0", "helpers", "partials", "data"];
for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
params.push("depth" + this.environment.depths.list[i]);
@@ -177,18 +187,12 @@ JavaScriptCompiler.prototype = {
// Perform a second pass over the output to merge content when possible
var source = this.mergeSource();
- if (!this.isChild) {
- source = this.compilerInfo()+source;
- }
-
if (asObject) {
params.push(source);
return Function.apply(this, params);
} else {
- var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
- log('debug', functionSource + "\n\n");
- return functionSource;
+ return 'function(' + params.join(',') + ') {\n ' + source + '}';
}
},
mergeSource: function() {
@@ -225,7 +229,7 @@ JavaScriptCompiler.prototype = {
// replace it on the stack with the result of properly
// invoking blockHelperMissing.
blockValue: function(name) {
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
+ this.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
var params = ["depth0"];
this.setupParams(name, 0, params);
@@ -243,7 +247,7 @@ JavaScriptCompiler.prototype = {
// On stack, after, if no lastHelper: same as [blockValue]
// On stack, after, if lastHelper: value
ambiguousBlockValue: function() {
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
+ this.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
// We're being a bit cheeky and reusing the options value from the prior exec
var params = ["depth0"];
@@ -315,7 +319,7 @@ JavaScriptCompiler.prototype = {
//
// Escape `value` and append it to the buffer
appendEscaped: function() {
- this.context.aliases.escapeExpression = 'this.escapeExpression';
+ this.aliases.escapeExpression = 'this.escapeExpression';
this.pushSource(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
},
@@ -362,7 +366,7 @@ JavaScriptCompiler.prototype = {
// If the `value` is a lambda, replace it on the stack by
// the return value of the lambda
resolvePossibleLambda: function() {
- this.context.aliases.functionType = '"function"';
+ this.aliases.functionType = '"function"';
this.replaceStack(function(current) {
return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
@@ -507,7 +511,7 @@ JavaScriptCompiler.prototype = {
//
// If the helper is not found, `helperMissing` is called.
invokeHelper: function(paramSize, name, isRoot) {
- this.context.aliases.helperMissing = 'helpers.helperMissing';
+ this.aliases.helperMissing = 'helpers.helperMissing';
this.useRegister('helper');
var nonHelper = this.popStack();
@@ -553,7 +557,7 @@ JavaScriptCompiler.prototype = {
// and can be avoided by passing the `knownHelpers` and
// `knownHelpersOnly` flags at compile-time.
invokeAmbiguous: function(name, helperCall) {
- this.context.aliases.functionType = '"function"';
+ this.aliases.functionType = '"function"';
this.useRegister('helper');
this.emptyHash();
@@ -582,8 +586,7 @@ JavaScriptCompiler.prototype = {
params.push("data");
}
- this.context.aliases.self = "this";
- this.push("self.invokePartial(" + params.join(", ") + ")");
+ this.push("this.invokePartial(" + params.join(", ") + ")");
},
// [assignToHash]
@@ -648,7 +651,7 @@ JavaScriptCompiler.prototype = {
index = this.context.programs.length;
child.index = index;
child.name = 'program' + index;
- this.context.programs[index] = compiler.compile(child, options, this.context);
+ this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile);
this.context.environments[index] = child;
} else {
child.index = index;
@@ -666,25 +669,22 @@ JavaScriptCompiler.prototype = {
},
programExpression: function(guid) {
- this.context.aliases.self = "this";
-
if(guid == null) {
- return "self.noop";
+ return 'this.noop';
}
var child = this.environment.children[guid],
depths = child.depths.list, depth;
- var programParams = [child.index, child.name, "data"];
+ var programParams = [child.index, 'data'];
for(var i=0, l = depths.length; i<l; i++) {
depth = depths[i];
- if(depth === 1) { programParams.push("depth0"); }
- else { programParams.push("depth" + (depth - 1)); }
+ programParams.push('depth' + (depth - 1));
}
- return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")";
+ return (depths.length === 0 ? 'this.program(' : 'this.programWithDepth(') + programParams.join(', ') + ')';
},
register: function(name, val) {
@@ -842,7 +842,7 @@ JavaScriptCompiler.prototype = {
.replace(/\u2029/g, '\\u2029') + '"';
},
- setupHash: function(obj) {
+ objectLiteral: function(obj) {
var pairs = [];
for (var key in obj) {
@@ -888,13 +888,11 @@ JavaScriptCompiler.prototype = {
// helpers to do a check for `if (options.fn)`
if (program || inverse) {
if (!program) {
- this.context.aliases.self = "this";
- program = "self.noop";
+ program = 'this.noop';
}
if (!inverse) {
- this.context.aliases.self = "this";
- inverse = "self.noop";
+ inverse = 'this.noop';
}
options.fn = program;
@@ -932,7 +930,7 @@ JavaScriptCompiler.prototype = {
// the params and contexts arguments are passed in arrays
// to fill in
setupParams: function(helperName, paramSize, params, useRegister) {
- var options = this.setupHash(this.setupOptions(helperName, paramSize, params));
+ var options = this.objectLiteral(this.setupOptions(helperName, paramSize, params));
if (useRegister) {
this.useRegister('options');