From c11fcc162eb16d5c7608af1d020b177104474ac0 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sun, 2 May 2021 14:51:24 +0200 Subject: [PATCH] Add support for `else if` See handlebars-lang/handlebars.js#892 --- .../php/com/handlebarsjs/BlockNode.class.php | 7 ++++--- .../handlebarsjs/HandlebarsParser.class.php | 18 ++++++++++++++++-- .../com/handlebarsjs/IfBlockHelper.class.php | 3 +-- .../unittest/IfHelperTest.class.php | 7 +++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/main/php/com/handlebarsjs/BlockNode.class.php b/src/main/php/com/handlebarsjs/BlockNode.class.php index 4222533..2f3d782 100755 --- a/src/main/php/com/handlebarsjs/BlockNode.class.php +++ b/src/main/php/com/handlebarsjs/BlockNode.class.php @@ -1,6 +1,7 @@ name, ($this->options ? ' '.implode(' ', $this->options) : ''), - \xp::stringOf($this->fn, ' '), - \xp::stringOf($this->inverse, ' ') + Objects::stringOf($this->fn, ' '), + Objects::stringOf($this->inverse, ' ') ); } @@ -133,7 +134,7 @@ public function equals($cmp) { $this->name === $cmp->name && $this->start === $cmp->start && $this->end === $cmp->end && - \util\Objects::equal($this->options, $cmp->options) && + Objects::equal($this->options, $cmp->options) && $this->fn->equals($cmp->fn) && $this->inverse->equals($cmp->inverse) ); diff --git a/src/main/php/com/handlebarsjs/HandlebarsParser.class.php b/src/main/php/com/handlebarsjs/HandlebarsParser.class.php index 97da34c..7a690ce 100755 --- a/src/main/php/com/handlebarsjs/HandlebarsParser.class.php +++ b/src/main/php/com/handlebarsjs/HandlebarsParser.class.php @@ -208,9 +208,23 @@ protected function initialize() { $state->target->add(new IteratorNode(true)); return; } else if ('else' === $parsed[0] && $state->parents) { - $context= $state->parents[sizeof($state->parents) - 1]; + $context= &$state->parents[sizeof($state->parents) - 1]; if ($context instanceof BlockNode) { - $state->target= $context->inverse(); + + // `else if` vs. `else` + if (isset($parsed[1]) && 'if' === (string)$parsed[1]) { + $context= $context->inverse()->add(new IfBlockHelper( + array_slice($parsed, 2), + null, + null, + $state->start, + $state->end + )); + $state->target= $context->fn(); + } else { + $state->target= $context->inverse(); + } + return; } // Fall through, "else" has no special meaning here. diff --git a/src/main/php/com/handlebarsjs/IfBlockHelper.class.php b/src/main/php/com/handlebarsjs/IfBlockHelper.class.php index 3b28b6e..7340177 100755 --- a/src/main/php/com/handlebarsjs/IfBlockHelper.class.php +++ b/src/main/php/com/handlebarsjs/IfBlockHelper.class.php @@ -27,8 +27,7 @@ public function __construct($options= [], NodeList $fn= null, NodeList $inverse= * @param io.streams.OutputStream $out */ public function write($context, $out) { - $f= $this->options[0]; - $target= $f($this, $context, []); + $target= $this->options[0]($this, $context, []); if ($target instanceof \Generator ? $target->valid() : $context->isTruthy($target)) { $this->fn->write($context, $out); diff --git a/src/test/php/com/handlebarsjs/unittest/IfHelperTest.class.php b/src/test/php/com/handlebarsjs/unittest/IfHelperTest.class.php index 7f01c64..82da9d1 100755 --- a/src/test/php/com/handlebarsjs/unittest/IfHelperTest.class.php +++ b/src/test/php/com/handlebarsjs/unittest/IfHelperTest.class.php @@ -25,6 +25,13 @@ public function shows_for_non_empty_array() { ])); } + #[Test, Values(map: ['one' => '1', 'two' => '2', 'three' => '3', 'other' => '3'])] + public function chained_elses($key, $expected) { + Assert::equals($expected, $this->evaluate('{{#if one}}1{{else if two}}2{{else}}3{{/if}}', [ + $key => true + ])); + } + #[Test, Values(['else', '^'])] public function else_invoked_for_non_truthy($else) { Assert::equals('Default', $this->evaluate('{{#if var}}-{{var}}-{{'.$else.'}}Default{{/if}}', [