Skip to content

Commit

Permalink
TemplateParserHtml: HTML attribute name can be PrintNode or string (B…
Browse files Browse the repository at this point in the history
…C break)
  • Loading branch information
dg committed Aug 12, 2023
1 parent bf3a5d9 commit cb8c748
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 44 deletions.
30 changes: 6 additions & 24 deletions src/Latte/Compiler/TemplateParserHtml.php
Original file line number Diff line number Diff line change
Expand Up @@ -259,19 +259,13 @@ private function parseAttributeWhitespace(): Node
private function parseAttribute(): ?Node
{
$stream = $this->parser->getStream();
$followsLatte = $stream->is(Token::Latte_TagOpen);
$save = $stream->getIndex();
try {
$name = $this->parseAttributeName();
if (!$name) {
return null;
}
} catch (CompileException $e) {
if ($followsLatte && $stream->peek()) { // it is not lexer exception
$stream->seek($save);
return $this->parser->parseLatteStatement(); // attribute name with the value like '<span {if true}attr1=val{/if}>'
if ($stream->is(Token::Latte_TagOpen)) {
$name = $this->parser->parseLatteStatement();
if (!$name instanceof Latte\Essential\Nodes\PrintNode) {
return $name; // value like '<span {if true}attr1=val{/if}>'
}
throw $e;
} else {
$name = $this->parser->parseText();
}

[$value, $quote] = $this->parseAttributeValue();
Expand All @@ -284,18 +278,6 @@ private function parseAttribute(): ?Node
}


private function parseAttributeName(): ?AreaNode
{
$stream = $this->parser->getStream();
return $this->parser->parseFragment(fn() => match ($stream->peek()->type) {
Token::Html_Name => $this->parser->parseText(),
Token::Latte_TagOpen => $this->parser->parseLatteStatement(),
Token::Latte_CommentOpen => $this->parser->parseLatteComment(),
default => null,
})->simplify();
}


private function parseAttributeValue(): ?array
{
$stream = $this->parser->getStream();
Expand Down
12 changes: 12 additions & 0 deletions tests/common/Compiler.errors.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ Assert::exception(
'Unexpected \'"a"{/if\', expecting {/if} (on line 1 at column 22)',
);

Assert::exception(
fn() => $latte->compile('<span {if true}title{/if}=a></span>'),
Latte\CompileException::class,
"Unexpected '=a></span', expecting end of HTML tag (on line 1 at column 26)",
);

Assert::exception(
fn() => $latte->compile('<span title{if true}{/if}=a></span>'),
Latte\CompileException::class,
"Unexpected '=a></span', expecting end of HTML tag (on line 1 at column 26)",
);

Assert::exception(
fn() => $latte->compile('<a n:href n:href>'),
Latte\CompileException::class,
Expand Down
33 changes: 13 additions & 20 deletions tests/common/TemplateParser.nodes.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -198,40 +198,33 @@ Assert::match(<<<'XX'
| | | | | | content: ' '
| | | | | | position: 1:27 (offset 26)
| | | | | 3 => Latte\Compiler\Nodes\Html\AttributeNode
| | | | | | name: FooNode
| | | | | | name: Latte\Compiler\Nodes\TextNode
| | | | | | | content: 'attr5'
| | | | | | | position: 1:28 (offset 27)
| | | | | | value: FooNode
| | | | | | | position: 1:45 (offset 44)
| | | | | | | position: 1:34 (offset 33)
| | | | | | quote: null
| | | | | | position: 1:28 (offset 27)
| | | | | 4 => Latte\Compiler\Nodes\TextNode
| | | | | | content: ' '
| | | | | | position: 1:57 (offset 56)
| | | | | | position: 1:46 (offset 45)
| | | | | 5 => Latte\Compiler\Nodes\Html\AttributeNode
| | | | | | name: Latte\Compiler\Nodes\FragmentNode
| | | | | | | children: array (3)
| | | | | | | | 0 => Latte\Compiler\Nodes\TextNode
| | | | | | | | | content: 'attr6'
| | | | | | | | | position: 1:58 (offset 57)
| | | | | | | | 1 => FooNode
| | | | | | | | | position: 1:63 (offset 62)
| | | | | | | | 2 => Latte\Compiler\Nodes\TextNode
| | | | | | | | | content: 'b'
| | | | | | | | | position: 1:69 (offset 68)
| | | | | | | position: 1:58 (offset 57)
| | | | | | name: Latte\Compiler\Nodes\TextNode
| | | | | | | content: 'attr6'
| | | | | | | position: 1:47 (offset 46)
| | | | | | value: Latte\Compiler\Nodes\FragmentNode
| | | | | | | children: array (3)
| | | | | | | | 0 => Latte\Compiler\Nodes\TextNode
| | | | | | | | | content: 'c'
| | | | | | | | | position: 1:71 (offset 70)
| | | | | | | | | position: 1:53 (offset 52)
| | | | | | | | 1 => FooNode
| | | | | | | | | position: 1:72 (offset 71)
| | | | | | | | | position: 1:54 (offset 53)
| | | | | | | | 2 => Latte\Compiler\Nodes\TextNode
| | | | | | | | | content: 'd'
| | | | | | | | | position: 1:78 (offset 77)
| | | | | | | position: 1:71 (offset 70)
| | | | | | | | | position: 1:60 (offset 59)
| | | | | | | position: 1:53 (offset 52)
| | | | | | quote: null
| | | | | | position: 1:58 (offset 57)
| | | | | | position: 1:47 (offset 46)
| | | | position: 1:4 (offset 3)
| | | selfClosing: false
| | | content: null
Expand All @@ -249,7 +242,7 @@ Assert::match(<<<'XX'
| position: 1:1 (offset 0)
contentType: 'html'
position: null
XX, parse("<br {foo}attr4='val'{/foo} {foo}attr5{/foo}={foo}b{/foo} attr6{foo/}b=c{foo/}d>"));
XX, parse("<br {foo}attr4='val'{/foo} attr5={foo}b{/foo} attr6=c{foo/}d>"));


Assert::match(<<<'XX'
Expand Down

0 comments on commit cb8c748

Please sign in to comment.