diff options
Diffstat (limited to 'lib/handlebars/compiler/javascript-compiler.js')
-rw-r--r-- | lib/handlebars/compiler/javascript-compiler.js | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index b8fc976..ede0b5e 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -64,6 +64,7 @@ JavaScriptCompiler.prototype = { this.name = this.environment.name; this.isChild = !!context; this.context = context || { + decorators: [], programs: [], environments: [] }; @@ -81,7 +82,7 @@ JavaScriptCompiler.prototype = { this.compileChildren(environment, options); - this.useDepths = this.useDepths || environment.useDepths || this.options.compat; + this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat; this.useBlockParams = this.useBlockParams || environment.useBlockParams; let opcodes = environment.opcodes, @@ -107,16 +108,43 @@ JavaScriptCompiler.prototype = { throw new Exception('Compile completed with content left on stack'); } + if (!this.decorators.isEmpty()) { + this.useDecorators = true; + + this.decorators.prepend('var decorators = container.decorators;\n'); + this.decorators.push('return fn;'); + + if (asObject) { + this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]); + } else { + this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n'); + this.decorators.push('}\n'); + this.decorators = this.decorators.merge(); + } + } else { + this.decorators = undefined; + } + let fn = this.createFunctionContext(asObject); if (!this.isChild) { let ret = { compiler: this.compilerInfo(), main: fn }; - let programs = this.context.programs; + + if (this.decorators) { + ret.main_d = this.decorators; // eslint-disable-line camelcase + ret.useDecorators = true; + } + + let {programs, decorators} = this.context; for (i = 0, l = programs.length; i < l; i++) { if (programs[i]) { ret[i] = programs[i]; + if (decorators[i]) { + ret[i + '_d'] = decorators[i]; + ret.useDecorators = true; + } } } @@ -163,6 +191,7 @@ JavaScriptCompiler.prototype = { // getContext opcode when it would be a noop this.lastContext = 0; this.source = new CodeGen(this.options.srcName); + this.decorators = new CodeGen(this.options.srcName); }, createFunctionContext: function(asObject) { @@ -561,6 +590,24 @@ JavaScriptCompiler.prototype = { } }, + // [registerDecorator] + // + // On stack, before: hash, program, params..., ... + // On stack, after: ... + // + // Pops off the decorator's parameters, invokes the decorator, + // and inserts the decorator into the decorators list. + registerDecorator(paramSize, name) { + let foundDecorator = this.nameLookup('decorators', name, 'decorator'), + options = this.setupHelperArgs(name, paramSize); + + this.decorators.push([ + 'fn = ', + this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]), + ' || fn;' + ]); + }, + // [invokeHelper] // // On stack, before: hash, inverse, program, params..., ... @@ -738,6 +785,7 @@ JavaScriptCompiler.prototype = { child.index = index; child.name = 'program' + index; this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); + this.context.decorators[index] = compiler.decorators; this.context.environments[index] = child; this.useDepths = this.useDepths || compiler.useDepths; @@ -946,7 +994,16 @@ JavaScriptCompiler.prototype = { }, setupParams: function(helper, paramSize, params) { - let options = {}, contexts = [], types = [], ids = [], param; + let options = {}, + contexts = [], + types = [], + ids = [], + objectArgs = !params, + param; + + if (objectArgs) { + params = []; + } options.name = this.quotedString(helper); options.hash = this.popStack(); @@ -985,6 +1042,10 @@ JavaScriptCompiler.prototype = { } } + if (objectArgs) { + options.args = this.source.generateArray(params); + } + if (this.trackIds) { options.ids = this.source.generateArray(ids); } @@ -1009,9 +1070,11 @@ JavaScriptCompiler.prototype = { this.useRegister('options'); params.push('options'); return ['options=', options]; - } else { + } else if (params) { params.push(options); return ''; + } else { + return options; } } }; |