Add Twig 3 compatibility transformations for raw, divisibleby, and none

This commit is contained in:
Andy Miller
2025-11-18 17:46:20 +00:00
parent 5567a5a1cd
commit 7fd614f8b6
2 changed files with 104 additions and 2 deletions

View File

@@ -18,7 +18,10 @@ class Twig3CompatibilityTransformer
$code = $this->rewriteSpacelessBlocks($code);
$code = $this->rewriteFilterBlocks($code);
$code = $this->rewriteSameAsTests($code);
$code = $this->rewriteDivisibleByTests($code);
$code = $this->rewriteNoneTests($code);
$code = $this->rewriteReplaceFilterSignatures($code);
$code = $this->rewriteRawBlocks($code);
return $code;
}
@@ -135,12 +138,12 @@ class Twig3CompatibilityTransformer
private function rewriteSameAsTests(string $code): string
{
$pattern = '/([\'"])(?:\\\\.|(?!\\1).)*\\1|\\bis\\s+sameas\\b/is';
$pattern = '/([\'"])(?:\\\\.|(?!\\1).)*\\1|\\bis\\s+(?:not\\s+)?sameas\\b/is';
return (string) preg_replace_callback($pattern, static function ($matches) {
// If group 1 is not set, it means 'is sameas' was matched.
if (!isset($matches[1])) {
return str_ireplace('is sameas', 'is same as', $matches[0]);
return str_ireplace('sameas', 'same as', $matches[0]);
}
// Otherwise, it's a quoted string, so return it as is.
@@ -163,6 +166,56 @@ class Twig3CompatibilityTransformer
return $code;
}
private function rewriteRawBlocks(string $code): string
{
$openPattern = '/\{%(\-?)\s*raw\s*(\-?)%\}/i';
$code = (string) preg_replace_callback($openPattern, static function (array $matches): string {
$leading = $matches[1] === '-' ? '-' : '';
$trailing = $matches[2] === '-' ? '-' : '';
return '{%' . $leading . ' verbatim ' . $trailing . '%}';
}, $code);
$closePattern = '/\{%(\-?)\s*endraw\s*(\-?)%\}/i';
return (string) preg_replace_callback($closePattern, static function (array $matches): string {
$leading = $matches[1] === '-' ? '-' : '';
$trailing = $matches[2] === '-' ? '-' : '';
return '{%' . $leading . ' endverbatim ' . $trailing . '%}';
}, $code);
}
private function rewriteDivisibleByTests(string $code): string
{
$pattern = '/([\'"])(?:\\\\.|(?!\\1).)*\\1|\\bis\\s+(?:not\\s+)?divisibleby\\b/is';
return (string) preg_replace_callback($pattern, static function ($matches) {
// If group 1 is not set, it means 'is divisibleby' was matched.
if (!isset($matches[1])) {
return str_ireplace('divisibleby', 'divisible by', $matches[0]);
}
// Otherwise, it's a quoted string, so return it as is.
return $matches[0];
}, $code);
}
private function rewriteNoneTests(string $code): string
{
$pattern = '/([\'"])(?:\\\\.|(?!\\1).)*\\1|\\bis\\s+(?:not\\s+)?none\\b/is';
return (string) preg_replace_callback($pattern, static function ($matches) {
// If group 1 is not set, it means 'is none' was matched.
if (!isset($matches[1])) {
return str_ireplace('none', 'null', $matches[0]);
}
// Otherwise, it's a quoted string, so return it as is.
return $matches[0];
}, $code);
}
private function ensureWrapped(string $expression): string
{
$trimmed = trim($expression);

View File

@@ -30,6 +30,11 @@ class Twig3CompatibilityTransformerTest extends \PHPUnit\Framework\TestCase
$this->transformer->transform('{% if foo is sameas bar %}')
);
$this->assertSame(
'{% if foo is not same as bar %}',
$this->transformer->transform('{% if foo is not sameas bar %}')
);
$this->assertSame(
"'foo is sameas(bar)'",
$this->transformer->transform("'foo is sameas(bar)'")
@@ -102,4 +107,48 @@ class Twig3CompatibilityTransformerTest extends \PHPUnit\Framework\TestCase
$this->transformer->transform('{{ "hello world"|replace("hello", "goodbye") }}')
);
}
public function testRewriteRawBlocks(): void
{
$this->assertSame(
'{% verbatim %}foo{% endverbatim %}',
$this->transformer->transform('{% raw %}foo{% endraw %}')
);
$this->assertSame(
'{%- verbatim -%}foo{%- endverbatim -%}',
$this->transformer->transform('{%- raw -%}foo{%- endraw -%}')
);
}
public function testRewriteDivisibleBy(): void
{
$this->assertSame(
'{% if loop.index is divisible by(3) %}',
$this->transformer->transform('{% if loop.index is divisibleby(3) %}')
);
$this->assertSame(
'{% if loop.index is divisible by (3) %}',
$this->transformer->transform('{% if loop.index is divisibleby (3) %}')
);
$this->assertSame(
'{% if loop.index is not divisible by(3) %}',
$this->transformer->transform('{% if loop.index is not divisibleby(3) %}')
);
}
public function testRewriteNoneTest(): void
{
$this->assertSame(
'{% if var is null %}',
$this->transformer->transform('{% if var is none %}')
);
$this->assertSame(
'{% if var is not null %}',
$this->transformer->transform('{% if var is not none %}')
);
}
}