Skip to content

Commit 7398040

Browse files
authored
feat(view): parse RSS feeds with tempest/view (#1617)
1 parent bd1f916 commit 7398040

File tree

4 files changed

+75
-1
lines changed

4 files changed

+75
-1
lines changed

packages/view/src/Parser/TempestViewLexer.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public function lex(): TokenCollection
2929
$tokens[] = $this->lexComment();
3030
} elseif ($this->comesNext('<!doctype') || $this->comesNext('<!DOCTYPE')) {
3131
$tokens[] = $this->lexDocType();
32+
} elseif ($this->comesNext('<![CDATA')) {
33+
$tokens = [...$tokens, ...$this->lexCharacterData()];
3234
} elseif ($this->comesNext('<')) {
3335
$tokens = [...$tokens, ...$this->lexTag()];
3436
} else {
@@ -192,4 +194,22 @@ private function lexDoctype(): Token
192194

193195
return new Token($buffer, TokenType::DOCTYPE);
194196
}
197+
198+
private function lexCharacterData(): array
199+
{
200+
$tokens = [
201+
new Token($this->consumeIncluding('<![CDATA['), TokenType::CHARACTER_DATA_OPEN),
202+
];
203+
204+
$buffer = '';
205+
206+
while ($this->seek(3) !== ']]>' && $this->current !== null) {
207+
$buffer .= $this->consume();
208+
}
209+
210+
$tokens[] = new Token($buffer, TokenType::CONTENT);
211+
$tokens[] = new Token($this->consume(3), TokenType::CHARACTER_DATA_CLOSE);
212+
213+
return $tokens;
214+
}
195215
}

packages/view/src/Parser/TokenType.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ enum TokenType
1515
case PHP;
1616
case CONTENT;
1717
case DOCTYPE;
18+
case CHARACTER_DATA_OPEN;
19+
case CHARACTER_DATA_CLOSE;
1820
}

packages/view/tests/TempestViewLexerTest.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use PHPUnit\Framework\Attributes\TestWith;
66
use PHPUnit\Framework\TestCase;
77
use Tempest\View\Parser\TempestViewLexer;
8-
use Tempest\View\Parser\TempestViewParser;
98
use Tempest\View\Parser\Token;
109
use Tempest\View\Parser\TokenCollection;
1110
use Tempest\View\Parser\TokenType;
@@ -280,6 +279,25 @@ public function test_unclosed_comment_tag(): void
280279
);
281280
}
282281

282+
public function test_cdata(): void
283+
{
284+
$tokens = new TempestViewLexer(<<<'RSS'
285+
<title><![CDATA[ {{ $post['title'] }} ]]></title>
286+
RSS)->lex();
287+
288+
$this->assertTokens(
289+
expected: [
290+
new Token('<title', TokenType::OPEN_TAG_START),
291+
new Token('>', TokenType::OPEN_TAG_END),
292+
new Token('<![CDATA[', TokenType::CHARACTER_DATA_OPEN),
293+
new Token(' {{ $post[\'title\'] }} ', TokenType::CONTENT),
294+
new Token(']]>', TokenType::CHARACTER_DATA_CLOSE),
295+
new Token('</title>', TokenType::CLOSING_TAG),
296+
],
297+
actual: $tokens,
298+
);
299+
}
300+
283301
private function assertTokens(array $expected, TokenCollection $actual): void
284302
{
285303
$this->assertCount(count($expected), $actual);

tests/Integration/View/TempestViewRendererTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,4 +782,38 @@ class="block dark:bg-neutral-900 disabled:opacity-50 px-4 py-2.5 sm:py-3 border-
782782

783783
$this->assertSnippetsMatch('<p>This should be rendered</p>', $html);
784784
}
785+
786+
public function test_parse_rss_feed(): void
787+
{
788+
$rss = <<<'XML'
789+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
790+
<id>https://tempestphp.com/rss</id>
791+
<link rel="self" type="application/atom+xml" href="https://tempestphp.com/rss" />
792+
<title>Tempest</title>
793+
<entry :foreach="$posts as $post">
794+
<title><![CDATA[ {!! $post['title'] !!} ]]></title>
795+
<media:content :url="$post['url']" medium="image" />
796+
</entry>
797+
</feed>
798+
XML;
799+
800+
$parsed = $this->render($rss, posts: [
801+
['title' => '<h1>A</h1>', 'url' => 'https://tempestphp.com/a'],
802+
['title' => 'B', 'url' => 'https://tempestphp.com/b'],
803+
]);
804+
805+
$this->assertSnippetsMatch(<<<'RSS'
806+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
807+
<id>https://tempestphp.com/rss</id>
808+
<link rel="self" type="application/atom+xml" href="https://tempestphp.com/rss">
809+
<title>Tempest</title>
810+
<entry><title><![CDATA[ <h1>A</h1> ]]></title>
811+
<media:content medium="image" url="https://tempestphp.com/a"></media:content>
812+
</entry>
813+
<entry><title><![CDATA[ B ]]></title>
814+
<media:content medium="image" url="https://tempestphp.com/b"></media:content>
815+
</entry>
816+
</feed>
817+
RSS, $parsed);
818+
}
785819
}

0 commit comments

Comments
 (0)