diff --git a/lib/helpers.js b/lib/helpers.js index ef567e2..10b7367 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -164,8 +164,18 @@ export function prepareBlock( ); } - if (inverseAndProgram.chain) { - inverseAndProgram.program.body[0].closeStrip = close.strip; + // Only at the outermost block (where close is the real closing tag, not another + // chain link) propagate its strip flags through all chained else-if blocks. + if (inverseAndProgram.chain && !close.chain) { + const closeStrip = close.strip; + let innerBlock = inverseAndProgram.program.body[0]; + // Walk the full chain so every block gets the real closing tag's strip flags. + while (innerBlock) { + innerBlock.closeStrip = closeStrip; + innerBlock = (innerBlock.inverse && innerBlock.inverse.chained) + ? innerBlock.inverse.body[0] + : null; + } } inverseStrip = inverseAndProgram.strip; diff --git a/lib/whitespace-control.js b/lib/whitespace-control.js index 8d98c14..9c4b6f2 100644 --- a/lib/whitespace-control.js +++ b/lib/whitespace-control.js @@ -55,7 +55,21 @@ WhitespaceControl.prototype.Program = function (program) { // Always strip the next node omitRight(body, i); - omitLeft((current.inverse || current.program).body); + // For chained else-if blocks, walk the chain and strip trailing indent + // from every terminal body so all execution paths lose the close-tag indent. + let chainNode = current.inverse; + if (chainNode && chainNode.chained) { + while (chainNode && chainNode.chained) { + let lastBlock = chainNode.body[chainNode.body.length - 1]; + omitLeft(lastBlock.program.body); + chainNode = lastBlock.inverse; + } + if (chainNode) { + omitLeft(chainNode.body); + } + } else { + omitLeft((current.inverse || current.program).body); + } } } diff --git a/spec/ast.js b/spec/ast.js index 31c4c44..7265efa 100644 --- a/spec/ast.js +++ b/spec/ast.js @@ -17,6 +17,17 @@ describe('ast', function () { equals(ast.body[0].value, ''); equals(ast.body[1].program.body[0].value, 'foo'); }); + + it('tilde on one else-if does not strip trailing whitespace in later branches', function () { + let ast = parse('{{#if a}}A{{else if b}}B {{~else if c}}C {{/if}}'), + block = ast.body[0], + bBlock = block.inverse.body[0], + cBlock = bBlock.inverse.body[0]; + + equals(block.program.body[0].value, 'A'); + equals(bBlock.program.body[0].value, 'B'); // tilde strips trailing space from b + equals(cBlock.program.body[0].value, 'C '); // no tilde on {{/if}}, space preserved + }); }); describe('parseWithoutProcessing', function () { @@ -236,6 +247,20 @@ describe('ast', function () { equals(ast.body[2].value, ''); }); + + it('strips close-tag indent from all chained else-if branches', function () { + let ast = parse( + ' {{#if a}}\n foo\n {{else if b}}\n bar\n {{else if c}}\n baz\n {{/if}}' + ), + block = ast.body[1], + bBlock = block.inverse.body[0], + cBlock = bBlock.inverse.body[0]; + + equals(ast.body[0].value, ''); + equals(block.program.body[0].value, ' foo\n'); + equals(bBlock.program.body[0].value, ' bar\n'); + equals(cBlock.program.body[0].value, ' baz\n'); // indent before {{/if}} stripped + }); }); describe('partials - parseWithoutProcessing', function () { it('simple partial', function () {