diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js index e3eb7864a..1c8ab0d3b 100644 --- a/lib/handlebars/compiler/helpers.js +++ b/lib/handlebars/compiler/helpers.js @@ -70,7 +70,7 @@ export function prepareMustache(path, params, hash, open, strip, locInfo) { return new this.MustacheStatement(path, params, hash, escaped, strip, this.locInfo(locInfo)); } -export function prepareRawBlock(openRawBlock, content, close, locInfo) { +export function prepareRawBlock(openRawBlock, contents, close, locInfo) { if (openRawBlock.path.original !== close) { let errorNode = {loc: openRawBlock.path.loc}; @@ -78,7 +78,7 @@ export function prepareRawBlock(openRawBlock, content, close, locInfo) { } locInfo = this.locInfo(locInfo); - let program = new this.Program([content], null, {}, locInfo); + let program = new this.Program(contents, null, {}, locInfo); return new this.BlockStatement( openRawBlock.path, openRawBlock.params, openRawBlock.hash, diff --git a/spec/helpers.js b/spec/helpers.js index 54ef0f288..00bcb79cb 100644 --- a/spec/helpers.js +++ b/spec/helpers.js @@ -28,6 +28,16 @@ describe('helpers', function() { 'raw block helper gets raw content'); }); + it('helper for nested raw block gets raw content', function() { + var string = '{{{{a}}}} {{{{b}}}} {{{{/b}}}} {{{{/a}}}}'; + var helpers = { + a: function(options) { + return options.fn(); + } + }; + shouldCompileTo(string, [{}, helpers], ' {{{{b}}}} {{{{/b}}}} ', 'raw block helper should get nested raw block as raw content'); + }); + it('helper block with complex lookup expression', function() { var string = '{{#goodbyes}}{{../name}}{{/goodbyes}}'; var hash = {name: 'Alan'}; diff --git a/src/handlebars.l b/src/handlebars.l index ff2128355..f7df8f55c 100644 --- a/src/handlebars.l +++ b/src/handlebars.l @@ -49,12 +49,21 @@ ID [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD} return 'CONTENT'; } +// nested raw block will create stacked 'raw' condition +"{{{{"/[^/] this.begin('raw'); return 'CONTENT'; "{{{{/"[^\s!"#%-,\.\/;->@\[-\^`\{-~]+/[=}\s\/.]"}}}}" { - yytext = yytext.substr(5, yyleng-9); this.popState(); - return 'END_RAW_BLOCK'; + // Should be using `this.topState()` below, but it currently + // returns the second top instead of the first top. Opened an + // issue about it at https://github.com/zaach/jison/issues/291 + if (this.conditionStack[this.conditionStack.length-1] === 'raw') { + return 'CONTENT'; + } else { + yytext = yytext.substr(5, yyleng-9); + return 'END_RAW_BLOCK'; + } } -[^\x00]*?/("{{{{/") { return 'CONTENT'; } +[^\x00]*?/("{{{{") { return 'CONTENT'; } [\s\S]*?"--"{RIGHT_STRIP}?"}}" { this.popState(); diff --git a/src/handlebars.yy b/src/handlebars.yy index 2424e27fd..ecc79afc6 100644 --- a/src/handlebars.yy +++ b/src/handlebars.yy @@ -26,7 +26,7 @@ content ; rawBlock - : openRawBlock content END_RAW_BLOCK -> yy.prepareRawBlock($1, $2, $3, @$) + : openRawBlock content+ END_RAW_BLOCK -> yy.prepareRawBlock($1, $2, $3, @$) ; openRawBlock