diff options
Diffstat (limited to 'lib/handlebars/compiler/javascript-compiler.js')
-rw-r--r-- | lib/handlebars/compiler/javascript-compiler.js | 125 |
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; |