Skip to content

Commit

Permalink
JumpNode: correctly closes all HTML elements [Closes #340]
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Nov 9, 2023
1 parent 30f172b commit b7a4e6e
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 73 deletions.
7 changes: 5 additions & 2 deletions src/Latte/Compiler/Nodes/Html/ElementNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class ElementNode extends AreaNode
/** n:tag & n:tag- support */
public AreaNode $tagNode;
public bool $captureTagName = false;
public bool $breakable = false;
private ?string $endTagVar;


Expand Down Expand Up @@ -96,9 +97,11 @@ public function print(PrintContext $context): string

if ($this->content) {
$context->beginEscape()->enterHtmlText($this);
$res .= $this->content->print($context);
$content = $this->content->print($context);
$context->restoreEscape();
$res .= 'echo ' . $endTag . ';';
$res .= $this->breakable
? 'try { ' . $content . ' } finally { echo ' . $endTag . '; } '
: $content . 'echo ' . $endTag . ';';
}

return $res;
Expand Down
31 changes: 15 additions & 16 deletions src/Latte/Essential/Nodes/JumpNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class JumpNode extends StatementNode
{
public string $type;
public ExpressionNode $condition;
public ?string $endTag = null;


public static function create(Tag $tag): static
Expand All @@ -46,34 +45,34 @@ public static function create(Tag $tag): static
throw new CompileException("Tag {{$tag->name}} is unexpected here.", $tag->position);
}

$last = $parent?->prefix === Tag::PrefixNone
? $parent->htmlElement->parent
: $parent?->htmlElement;
$el = $tag->htmlElement;
while ($el && $el !== $last) {
$el->breakable = true;
$el = $el->parent;
}

$node = new static;
$node->type = $tag->name;
$node->condition = $tag->parser->parseExpression();
if (isset($tag->htmlElement->nAttributes['foreach'])) {
$node->endTag = $tag->htmlElement->name;
}
return $node;
}


public function print(PrintContext $context): string
{
$cmd = match ($this->type) {
'breakIf' => 'break;',
'continueIf' => 'continue;',
'skipIf' => '{ $iterator->skipRound(); continue; }',
'exitIf' => 'return;',
};

if ($this->endTag) {
$cmd = "{ echo \"</$this->endTag>\\n\"; $cmd; } ";
}

return $context->format(
"if (%node) %line %raw\n",
$this->condition,
$this->position,
$cmd,
match ($this->type) {
'breakIf' => 'break;',
'continueIf' => 'continue;',
'skipIf' => '{ $iterator->skipRound(); continue; }',
'exitIf' => 'return;',
},
);
}

Expand Down
4 changes: 4 additions & 0 deletions tests/common/TemplateParser.nodes.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ Assert::match(<<<'XX'
| | | | print: Closure($context)
| | | | position: null
| | | captureTagName: false
| | | breakable: false
| | | endTagVar: unset
| | | name: 'br'
| | | position: 1:1 (offset 0)
Expand Down Expand Up @@ -237,6 +238,7 @@ Assert::match(<<<'XX'
| | | | print: Closure($context)
| | | | position: null
| | | captureTagName: false
| | | breakable: false
| | | endTagVar: unset
| | | name: 'br'
| | | position: 1:1 (offset 0)
Expand Down Expand Up @@ -295,6 +297,7 @@ Assert::match(<<<'XX'
| | | | print: Closure($context)
| | | | position: null
| | | captureTagName: false
| | | breakable: false
| | | endTagVar: unset
| | | name: 'p'
| | | position: 1:1 (offset 0)
Expand All @@ -306,4 +309,5 @@ Assert::match(<<<'XX'
| position: 1:1 (offset 0)
contentType: 'html'
position: null

XX, parse("<p>\n...\n</p>"));
19 changes: 19 additions & 0 deletions tests/tags/exitIf.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,22 @@ Assert::match(
XX,
$latte->compile($template),
);


$template = <<<'XX'
<div>{exitIf true}</div>
XX;

Assert::match(
<<<'XX'
%A%
echo '<div>';
try {
if (true) /* line 1 */ return;
} finally {
echo '</div>';
}
%A%
XX,
$latte->compile($template),
);
40 changes: 19 additions & 21 deletions tests/tags/expected/foreach.breaking.attr.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
';
foreach ([0, 1, 2, 3] as $i) /* line 3 */ {
echo ' <li>';
echo LR\Filters::escapeHtmlText($i) /* line 3 */;
if (true) /* line 3 */ {
echo "</li>\n";
break;
;
try {
echo LR\Filters::escapeHtmlText($i) /* line 3 */;
if (true) /* line 3 */ break;
} finally {
echo '</li>';
}
echo '</li>
';
echo "\n";

}

Expand All @@ -22,14 +21,13 @@
';
foreach ([0, 1, 2, 3] as $i) /* line 7 */ {
echo ' <li>';
echo LR\Filters::escapeHtmlText($i) /* line 7 */;
if (true) /* line 7 */ {
echo "</li>\n";
continue;
;
try {
echo LR\Filters::escapeHtmlText($i) /* line 7 */;
if (true) /* line 7 */ continue;
} finally {
echo '</li>';
}
echo '</li>
';
echo "\n";

}

Expand All @@ -39,16 +37,16 @@
';
foreach ($iterator = $ʟ_it = new Latte\Essential\CachingIterator([0, 1, 2, 3], $ʟ_it ?? null) as $i) /* line 11 */ {
echo ' <li>';
echo LR\Filters::escapeHtmlText($i) /* line 11 */;
if (true) /* line 11 */ {
echo "</li>\n";
{
try {
echo LR\Filters::escapeHtmlText($i) /* line 11 */;
if (true) /* line 11 */ {
$iterator->skipRound();
continue;
};
}
} finally {
echo '</li>';
}
echo '</li>
';
echo "\n";

}
$iterator = $ʟ_it = $ʟ_it->getParent();
Expand Down
37 changes: 37 additions & 0 deletions tests/tags/expected/foreach.breaking.tags.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
%A%
foreach ([0, 1] as $i) /* line %d% */ {
echo '<div>';
try {
echo '
<span>';
try {
if (true) /* line %d% */ break;
} finally {
echo '</span>';
}
echo "\n";
} finally {
echo '</div>';
}
echo "\n";

}

echo '
<div>
';
foreach ([0, 1] as $i) /* line %d% */ {
echo ' <span>';
try {
if (true) /* line %d% */ break;
} finally {
echo '</span>';
}
echo "\n";

}

echo '</div>
';
%A%
8 changes: 2 additions & 6 deletions tests/tags/expected/general.n-attributes.html
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,10 @@


<ul title="foreach break">
<li>John</li>
</ul>
<li>John</li></ul>

<ul title="foreach continue">
<li>John</li>
<li>Mary</li>
<li>Paul</li>
</ul>
<li>John</li> <li>Mary</li> <li>Paul</li></ul>


<ul title="inner foreach break">
Expand Down
26 changes: 12 additions & 14 deletions tests/tags/expected/general.n-attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -339,14 +339,13 @@ public function main(array $ʟ_args): void
';
foreach ($people as $person) /* line %d% */ {
echo ' <li>';
echo LR\Filters::escapeHtmlText($person) /* line %d% */;
if (true) /* line %d% */ {
echo "</li>\n";
break;
;
try {
echo LR\Filters::escapeHtmlText($person) /* line 107 */;
if (true) /* line 107 */ break;
} finally {
echo '</li>';
}
echo '</li>
';
echo "\n";

}

Expand All @@ -356,14 +355,13 @@ public function main(array $ʟ_args): void
';
foreach ($people as $person) /* line %d% */ {
echo ' <li>';
echo LR\Filters::escapeHtmlText($person) /* line %d% */;
if (true) /* line %d% */ {
echo "</li>\n";
continue;
;
try {
echo LR\Filters::escapeHtmlText($person) /* line 111 */;
if (true) /* line 111 */ continue;
} finally {
echo '</li>';
}
echo '</li>
';
echo "\n";

}

Expand Down
47 changes: 35 additions & 12 deletions tests/tags/foreach.breaking.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -125,22 +125,13 @@ Assert::match(
<<<'XX'
<ul title="foreach break">
<li>0</li>
</ul>
<li>0</li></ul>
<ul title="foreach continue">
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<li>0</li> <li>1</li> <li>2</li> <li>3</li></ul>
<ul title="foreach skip">
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<li>0</li> <li>1</li> <li>2</li> <li>3</li></ul>
<ul title="inner foreach break">
Expand All @@ -158,3 +149,35 @@ Assert::match(
XX,
$latte->renderToString($template),
);


$template = <<<'EOD'
{foreach [0, 1] as $i}
<div>
<span>{breakIf true}</span>
</div>
{/foreach}
<div>
{foreach [0, 1] as $i}
<span>{breakIf true}</span>
{/foreach}
</div>

EOD;

Assert::matchFile(
__DIR__ . '/expected/foreach.breaking.tags.php',
$latte->compile($template),
);

Assert::match(
<<<'XX'
<div>
<span></span></div>
<div>
<span></span></div>

XX,
$latte->renderToString($template),
);
3 changes: 1 addition & 2 deletions tests/tags/n-ifcontent.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ Assert::match(


Assert::match(
'<div>1</div>
<div>2</div>',
'<div>1</div><div>2</div>',
$latte->renderToString('<div n:foreach="[1,2] as $n" n:ifcontent>{$n}{continueIf true}</div>'),
);

Expand Down

0 comments on commit b7a4e6e

Please sign in to comment.