/etc/php/8.2/cli/conf.d/10-opcache.ini, /etc/php/8.2/cli/conf.d/10-pdo.ini, /etc/php/8.2/cli/conf.d/15-xml.ini, /etc/php/8.2/cli/conf.d/20-apcu.ini, /etc/php/8.2/cli/conf.d/20-calendar.ini, /etc/php/8.2/cli/conf.d/20-ctype.ini, /etc/php/8.2/cli/conf.d/20-curl.ini, /etc/php/8.2/cli/conf.d/20-dom.ini, /etc/php/8.2/cli/conf.d/20-ev.ini, /etc/php/8.2/cli/conf.d/20-exif.ini, /etc/php/8.2/cli/conf.d/20-ffi.ini, /etc/php/8.2/cli/conf.d/20-fileinfo.ini, /etc/php/8.2/cli/conf.d/20-ftp.ini, /etc/php/8.2/cli/conf.d/20-gd.ini, /etc/php/8.2/cli/conf.d/20-gettext.ini, /etc/php/8.2/cli/conf.d/20-gmp.ini, /etc/php/8.2/cli/conf.d/20-iconv.ini, /etc/php/8.2/cli/conf.d/20-igbinary.ini, /etc/php/8.2/cli/conf.d/20-imagick.ini, /etc/php/8.2/cli/conf.d/20-intl.ini, /etc/php/8.2/cli/conf.d/20-mbstring.ini, /etc/php/8.2/cli/conf.d/20-msgpack.ini, /etc/php/8.2/cli/conf.d/20-phar.ini, /etc/php/8.2/cli/conf.d/20-posix.ini, /etc/php/8.2/cli/conf.d/20-raphf.ini, /etc/php/8.2/cli/conf.d/20-readline.ini, /etc/php/8.2/cli/conf.d/20-redis.ini, /etc/php/8.2/cli/conf.d/20-shmop.ini, /etc/php/8.2/cli/conf.d/20-simplexml.ini, /etc/php/8.2/cli/conf.d/20-sockets.ini, /etc/php/8.2/cli/conf.d/20-ssh2.ini, /etc/php/8.2/cli/conf.d/20-sysvmsg.ini, /etc/php/8.2/cli/conf.d/20-sysvsem.ini, /etc/php/8.2/cli/conf.d/20-sysvshm.ini, /etc/php/8.2/cli/conf.d/20-tokenizer.ini, /etc/php/8.2/cli/conf.d/20-uuid.ini, /etc/php/8.2/cli/conf.d/20-xdebug.ini, /etc/php/8.2/cli/conf.d/20-xmlreader.ini, /etc/php/8.2/cli/conf.d/20-xmlwriter.ini, /etc/php/8.2/cli/conf.d/20-xsl.ini, /etc/php/8.2/cli/conf.d/20-yaml.ini, /etc/php/8.2/cli/conf.d/25-http.ini, /etc/php/8.2/cli/conf.d/25-memcached.ini, /etc/php/8.2/cli/conf.d/30-ds.ini
/etc/php/8.2/cli/php.ini
diff --git a/src/Template/Parser/StreamingCompiler.php b/src/Template/Parser/StreamingCompiler.php
index 00a4529..2e53a67 100644
--- a/src/Template/Parser/StreamingCompiler.php
+++ b/src/Template/Parser/StreamingCompiler.php
@@ -112,6 +112,9 @@ private function renderCharacterReference($document): Document
private function escapeData(int $selectionStart, Document $document): Closure
{
+ if($this->blockAttributes) {
+ return static fn(Closure $x) => $x($document);
+ }
$end = $document->mark() - 1;
$originalData = substr($document->code, $selectionStart, $end - $selectionStart);
$data = $this->blobber->replaceBlobs($originalData, $this->escaper->escapeHtml(...));
@@ -429,12 +432,18 @@ private function renderOpenTagName(Document $document): Document
case 'title':
case 'textarea':
$this->mustMatch = $tag;
+ if($this->blockAttributes) {
+ return $this->renderRCData($document);
+ }
$now = $document->mark();
return $this->renderRCData($document)
->snip($now, $this->lastTagCloseOpen, $output)
->insert($this->blobber->replaceBlobs($output, $this->escaper->escapeHtml(...)), $now);
case 'style':
$this->mustMatch = $tag;
+ if($this->blockAttributes) {
+ return $this->renderRawText($document);
+ }
$now = $document->mark();
return $this
->renderRawText($document)
@@ -447,12 +456,18 @@ private function renderOpenTagName(Document $document): Document
case 'plaintext':
case 'noframes':
$this->mustMatch = $tag;
+ if($this->blockAttributes) {
+ return $this->renderRawText($document);
+ }
$now = $document->mark();
return $this->renderRawText($document)
->snip($now, $this->lastTagCloseOpen, $output)
->insert($this->blobber->replaceBlobs($output, $this->escaper->escapeHtml(...)), $now);
case 'script':
$this->mustMatch = $tag;
+ if($this->blockAttributes) {
+ return $this->renderScriptData($document);
+ }
$now = $document->mark();
return $this
->renderScriptData($document)
@@ -1180,13 +1195,15 @@ private function renderAfterAttributeValueQuoted(Document $document): Document
private function processAttributes(Document $document): Document
{
- $value = $this->blobber->replaceBlobs(
- $this->attributeValue,
- $this->escaper->escapeHtmlAttr(...)
- );
+ if($this->blockAttributes) {
+ return $document;
+ }
+
+ $originalValue = $this->blobber->replaceBlobs($this->attributeValue, fn($_) => $_);
+ $value = $this->escaper->escapeHtmlAttr($originalValue);
// escaper doesn't escape single quotes, so we do that here.
$value = str_replace("'", ''', $value);
- $this->setAttribute($this->attributeName, $value);
+ $this->setAttribute($this->attributeName, $originalValue);
if ($value !== $this->attributeValue) {
// we need to update the rendered html too...
$here = $document->mark();
diff --git a/tests/StreamingTest.php b/tests/StreamingTest.php
index eb0e9f6..12481ae 100644
--- a/tests/StreamingTest.php
+++ b/tests/StreamingTest.php
@@ -213,3 +213,78 @@ public function render(): string
)->getHeader('Set-Cookie')[0]
)->toStartWith('csrf_token=');
});
+
+test('data providers do not escape their children', function () {
+ $container = containerWithComponents([
+ 'provider' => new class implements \Bottledcode\SwytchFramework\Template\Functional\DataProvider {
+
+ public function provideAttributes(): array
+ {
+ return ['test' => 'test'];
+ }
+
+ public function provideValues(string $value): mixed
+ {
+ return $value;
+ }
+
+ public function render(string $test = ''): string
+ {
+ if ($test) {
+ return 'oh no';
+ }
+ return '';
+ }
+ },
+ 'echo' => new class {
+ public function render(string $test = ''): string
+ {
+ return $test;
+ }
+ },
+ 'empty' => new class {
+ public function render()
+ {
+ return '';
+ }
+ }
+ ]);
+ $streamer = $container->get(StreamingCompiler::class);
+ $document = <<
+
+
+
+
+HTML;
+
+ $result = $streamer->compile($document);
+ expect($result)->toMatchHtmlSnapshot();
+});
+
+it('passes variables correctly', function () {
+ $container = containerWithComponents([
+ 'echo' => new class {
+ public function render(string $test = ''): string
+ {
+ return $test;
+ }
+ },
+ 'child' => new class {
+ public function render(string $test = ''): string
+ {
+ return "{{$test}}
";
+ }
+ }
+ ]);
+
+ $streamer = $container->get(StreamingCompiler::class);
+ $document = <<
+
+
+
+HTML;
+ $result = $streamer->compile($document);
+ expect($result)->toMatchHtmlSnapshot();
+});
diff --git a/tests/__snapshots__/StreamingTest__data_providers_do_not_escape_their_children__1.html b/tests/__snapshots__/StreamingTest__data_providers_do_not_escape_their_children__1.html
new file mode 100644
index 0000000..b8c597b
--- /dev/null
+++ b/tests/__snapshots__/StreamingTest__data_providers_do_not_escape_their_children__1.html
@@ -0,0 +1,5 @@
+test
+
+not overridden
+
+
diff --git a/tests/__snapshots__/StreamingTest__it_passes_variables_correctly__1.html b/tests/__snapshots__/StreamingTest__it_passes_variables_correctly__1.html
new file mode 100644
index 0000000..139edc9
--- /dev/null
+++ b/tests/__snapshots__/StreamingTest__it_passes_variables_correctly__1.html
@@ -0,0 +1,8 @@
+
+some text
+
+outer text
+inner text
+
+
+