summaryrefslogtreecommitdiffstats
path: root/lib/handlebars/compiler/javascript-compiler.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/handlebars/compiler/javascript-compiler.js')
-rw-r--r--lib/handlebars/compiler/javascript-compiler.js125
1 files changed, 80 insertions, 45 deletions
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js
index b7318bc..159a38b 100644
--- a/lib/handlebars/compiler/javascript-compiler.js
+++ b/lib/handlebars/compiler/javascript-compiler.js
@@ -1,31 +1,41 @@
-var compilerbase = require("./base");
+import { COMPILER_REVISION, REVISION_CHANGES, log } from "../base";
-exports.attach = function(Handlebars) {
-
-compilerbase.attach(Handlebars);
-
-// BEGIN(BROWSER)
-/*jshint eqnull:true*/
-
-var Literal = function(value) {
+function Literal(value) {
this.value = value;
-};
-
+}
-var JavaScriptCompiler = Handlebars.JavaScriptCompiler = function() {};
+function JavaScriptCompiler() {}
JavaScriptCompiler.prototype = {
// PUBLIC API: You can override these methods in a subclass to provide
// alternative compiled forms for name lookup and buffering semantics
nameLookup: function(parent, name /* , type*/) {
+ var wrap,
+ ret;
+ if (parent.indexOf('depth') === 0) {
+ wrap = true;
+ }
+
if (/^[0-9]+$/.test(name)) {
- return parent + "[" + name + "]";
+ ret = parent + "[" + name + "]";
} else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
- return parent + "." + name;
+ ret = parent + "." + name;
}
else {
- return parent + "['" + name + "']";
+ ret = parent + "['" + name + "']";
}
+
+ if (wrap) {
+ return '(' + parent + ' && ' + ret + ')';
+ } else {
+ return ret;
+ }
+ },
+
+ compilerInfo: function() {
+ var revision = COMPILER_REVISION,
+ versions = REVISION_CHANGES[revision];
+ return "this.compilerInfo = ["+revision+",'"+versions+"'];\n";
},
appendToBuffer: function(string) {
@@ -51,7 +61,7 @@ JavaScriptCompiler.prototype = {
this.environment = environment;
this.options = options || {};
- Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
+ log('debug', this.environment.disassemble() + "\n\n");
this.name = this.environment.name;
this.isChild = !!context;
@@ -83,18 +93,17 @@ JavaScriptCompiler.prototype = {
} else {
this[opcode.opcode].apply(this, opcode.args);
}
- }
- return this.createFunctionContext(asObject);
- },
+ // Reset the stripNext flag if it was not set by this operation.
+ if (opcode.opcode !== this.stripNext) {
+ this.stripNext = false;
+ }
+ }
- nextOpcode: function() {
- var opcodes = this.environment.opcodes;
- return opcodes[this.i + 1];
- },
+ // Flush any trailing content that might be pending.
+ this.pushSource('');
- eat: function() {
- this.i = this.i + 1;
+ return this.createFunctionContext(asObject);
},
preamble: function() {
@@ -149,7 +158,7 @@ JavaScriptCompiler.prototype = {
}
if (!this.environment.isSimple) {
- this.source.push("return buffer;");
+ this.pushSource("return buffer;");
}
var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
@@ -162,9 +171,7 @@ JavaScriptCompiler.prototype = {
var source = this.mergeSource();
if (!this.isChild) {
- var revision = Handlebars.COMPILER_REVISION,
- versions = Handlebars.REVISION_CHANGES[revision];
- source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
+ source = this.compilerInfo()+source;
}
if (asObject) {
@@ -173,7 +180,7 @@ JavaScriptCompiler.prototype = {
return Function.apply(this, params);
} else {
var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
- Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
+ log('debug', functionSource + "\n\n");
return functionSource;
}
},
@@ -240,7 +247,7 @@ JavaScriptCompiler.prototype = {
// Use the options value generated from the invocation
params[params.length-1] = 'options';
- this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
+ this.pushSource("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
},
// [appendContent]
@@ -250,7 +257,28 @@ JavaScriptCompiler.prototype = {
//
// Appends the string value of `content` to the current buffer
appendContent: function(content) {
- this.source.push(this.appendToBuffer(this.quotedString(content)));
+ if (this.pendingContent) {
+ content = this.pendingContent + content;
+ }
+ if (this.stripNext) {
+ content = content.replace(/^\s+/, '');
+ }
+
+ this.pendingContent = content;
+ },
+
+ // [strip]
+ //
+ // On stack, before: ...
+ // On stack, after: ...
+ //
+ // Removes any trailing whitespace from the prior content node and flags
+ // the next operation for stripping if it is a content node.
+ strip: function() {
+ if (this.pendingContent) {
+ this.pendingContent = this.pendingContent.replace(/\s+$/, '');
+ }
+ this.stripNext = 'strip';
},
// [append]
@@ -267,9 +295,9 @@ JavaScriptCompiler.prototype = {
// when we examine local
this.flushInline();
var local = this.popStack();
- this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
+ this.pushSource("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
if (this.environment.isSimple) {
- this.source.push("else { " + this.appendToBuffer("''") + " }");
+ this.pushSource("else { " + this.appendToBuffer("''") + " }");
}
},
@@ -282,7 +310,7 @@ JavaScriptCompiler.prototype = {
appendEscaped: function() {
this.context.aliases.escapeExpression = 'this.escapeExpression';
- this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
+ this.pushSource(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
},
// [getContext]
@@ -506,8 +534,8 @@ JavaScriptCompiler.prototype = {
var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
var nextStack = this.nextStack();
- this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
- this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }');
+ this.pushSource('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
+ this.pushSource('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.call(' + helper.callParams + ') : ' + nextStack + '; }');
},
// [invokePartial]
@@ -614,7 +642,7 @@ JavaScriptCompiler.prototype = {
register: function(name, val) {
this.useRegister(name);
- this.source.push(name + " = " + val + ";");
+ this.pushSource(name + " = " + val + ";");
},
useRegister: function(name) {
@@ -628,12 +656,23 @@ JavaScriptCompiler.prototype = {
return this.push(new Literal(item));
},
+ pushSource: function(source) {
+ if (this.pendingContent) {
+ this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent)));
+ this.pendingContent = undefined;
+ }
+
+ if (source) {
+ this.source.push(source);
+ }
+ },
+
pushStack: function(item) {
this.flushInline();
var stack = this.incrStack();
if (item) {
- this.source.push(stack + " = " + item + ";");
+ this.pushSource(stack + " = " + item + ";");
}
this.compileStack.push(stack);
return stack;
@@ -676,7 +715,7 @@ JavaScriptCompiler.prototype = {
stack = this.nextStack();
}
- this.source.push(stack + " = (" + prefix + item + ");");
+ this.pushSource(stack + " = (" + prefix + item + ");");
}
return stack;
},
@@ -849,8 +888,4 @@ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
return false;
};
-// END(BROWSER)
-
-return Handlebars;
-
-};
+export default JavaScriptCompiler;