diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
index 6528b58..79502d9 100644
--- a/.github/workflows/run-tests.yml
+++ b/.github/workflows/run-tests.yml
@@ -9,7 +9,7 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest]
- php: [8.0, 8.1, 8.2]
+ php: [8.2, 8.3, 8.4]
dependency-version: [prefer-lowest, prefer-stable]
name: P${{ matrix.php }} - ${{ matrix.dependency-version }} - ${{ matrix.os }}
diff --git a/.gitignore b/.gitignore
index f12bc46..c1b5059 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.idea
+cache/*
.php_cs
.php_cs.cache
.phpunit.result.cache
diff --git a/composer.json b/composer.json
index b5b30e0..40f77e5 100644
--- a/composer.json
+++ b/composer.json
@@ -16,15 +16,14 @@
}
],
"require": {
- "php": "^7.4|^8.0",
- "twig/twig": "^3.0"
+ "php": "^8.2",
+ "twig/twig": "^3.21"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.0",
- "pestphp/pest": "^1.0",
- "phpunit/phpunit": "^9.3",
- "symfony/var-dumper": "^5.2",
- "vimeo/psalm": "^3.11"
+ "friendsofphp/php-cs-fixer": "^3.75",
+ "pestphp/pest": "^3.8",
+ "symfony/var-dumper": "^7.2",
+ "vimeo/psalm": "^6.10"
},
"autoload": {
"psr-4": {
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 1d5bedd..914d54e 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,31 +1,20 @@
-
-
+
tests
-
+
- ./src
+ src
-
-
-
-
-
-
-
-
-
+
+ vendor
+
+
diff --git a/src/Configuration.php b/src/Configuration.php
index 4077aa5..de709c9 100644
--- a/src/Configuration.php
+++ b/src/Configuration.php
@@ -157,8 +157,8 @@ public function setup()
$this->twig->setLexer(new ComponentLexer($this->twig));
}
- /** @var \Twig\Extension\EscaperExtension */
- $escaper = $this->twig->getExtension(\Twig\Extension\EscaperExtension::class);
+ /** @var \Twig\Runtime\EscaperRuntime */
+ $escaper = $this->twig->getRuntime(\Twig\Runtime\EscaperRuntime::class);
$escaper->addSafeClass(ComponentAttributeBag::class, ['all']);
$escaper->addSafeClass(ComponentSlot::class, ['all']);
}
diff --git a/src/Node/ComponentNode.php b/src/Node/ComponentNode.php
index 77e0f95..456b891 100644
--- a/src/Node/ComponentNode.php
+++ b/src/Node/ComponentNode.php
@@ -61,15 +61,12 @@ protected function addGetTemplate(Compiler $compiler)
$repr = $this->isDynamicComponent() ? 'raw' : 'repr';
$compiler
- ->raw('$this->loadTemplate(' . PHP_EOL)
+ ->raw('$this->load(' . PHP_EOL)
->indent(1)
->write('')
->$repr($this->getTemplateName())
->raw(', ' . PHP_EOL)
->write('')
- ->$repr($this->getTemplateName())
- ->raw(', ' . PHP_EOL)
- ->write('')
->repr($this->getTemplateLine())
->indent(-1)
->raw(PHP_EOL . ');' . PHP_EOL . PHP_EOL);
@@ -97,17 +94,19 @@ public function getDynamicComponent()
if ($value->hasAttribute('value')) {
// Returns the component string value
$component = '\'' . $value->getAttribute('value') . '\'';
+
break;
}
if ($value->hasAttribute('name')) {
// Uses the context to get the component value
$component = '($context[\'' . $value->getAttribute('name') . '\'] ?? null)';
+
break;
}
}
- if (!$component) {
+ if (! $component) {
throw new Exception('Dynamic component must have a component attribute');
}
@@ -130,6 +129,7 @@ public static function parseDynamicComponent($path, $component)
// Strip anything from the path before the dynamic component name, so it begins with the namespace
$dynamicComponentEndPosition = strpos($path, self::DYNAMIC_COMPONENT_NAME) + strlen(self::DYNAMIC_COMPONENT_NAME);
$pathEnd = substr($path, $dynamicComponentEndPosition);
+
return $component . $pathEnd;
}
@@ -185,7 +185,7 @@ protected function addTemplateArguments(Compiler $compiler)
public function filterVariables()
{
- if (!$this->isDynamicComponent()) {
+ if (! $this->isDynamicComponent()) {
return;
}
diff --git a/src/Node/SlotNode.php b/src/Node/SlotNode.php
index e90b903..79c5455 100644
--- a/src/Node/SlotNode.php
+++ b/src/Node/SlotNode.php
@@ -13,7 +13,7 @@ final class SlotNode extends Node implements NodeOutputInterface
{
public function __construct($name, $body, ?AbstractExpression $variables, int $lineno = 0)
{
- parent::__construct(['body' => $body], ['name' => $name], $lineno, null);
+ parent::__construct(['body' => $body], ['name' => $name], $lineno);
if ($variables) {
$this->setNode('variables', $variables);
diff --git a/src/TokenParser/ComponentTokenParser.php b/src/TokenParser/ComponentTokenParser.php
index 5485e5c..bfcef98 100644
--- a/src/TokenParser/ComponentTokenParser.php
+++ b/src/TokenParser/ComponentTokenParser.php
@@ -66,7 +66,7 @@ protected function parseArguments()
}
if ($stream->nextIf(/* Token::NAME_TYPE */5, 'with')) {
- $variables = $this->parser->getExpressionParser()->parseExpression();
+ $variables = $this->parser->parseExpression();
}
$stream->expect(/* Token::BLOCK_END_TYPE */3);
@@ -80,9 +80,9 @@ public function parseComponentName(): string
$path = [];
- if ($this->parser->getCurrentToken()->getType() != /** Token::NAME_TYPE */ 5) {
- throw new Exception('First token must be a name type');
- }
+ // if ($this->parser->getCurrentToken()->getType() !== Token::NAME_TYPE) {
+ // throw new Exception('First token must be a name type');
+ // }
$name = $this->getNameSection();
@@ -93,7 +93,7 @@ public function parseComponentName(): string
$path[] = $name;
- while ($stream->nextIf(9 /** Token::PUNCTUATION_TYPE */, '.')) {
+ while ($stream->nextIf(8 /** Token::PUNCTUATION_TYPE */, '.')) {
$path[] = $this->getNameSection();
}
diff --git a/src/TokenParser/SlotTokenParser.php b/src/TokenParser/SlotTokenParser.php
index 22b6789..f1e5a49 100644
--- a/src/TokenParser/SlotTokenParser.php
+++ b/src/TokenParser/SlotTokenParser.php
@@ -33,7 +33,7 @@ protected function parseArguments(): array
}
if ($stream->nextIf(/* Token::NAME_TYPE */5, 'with')) {
- $variables = $this->parser->getExpressionParser()->parseExpression();
+ $variables = $this->parser->parseExpression();
}
$stream->expect(/* Token::BLOCK_END_TYPE */3);
@@ -45,9 +45,10 @@ public function parseSlotName(): string
{
$stream = $this->parser->getStream();
- if ($this->parser->getCurrentToken()->getType() != /** Token::NAME_TYPE */ 5) {
- throw new Exception('First token must be a name type');
- }
+ //$stream->expect(5);
+ // if ($this->parser->getCurrentToken()->getType() != /** Token::NAME_TYPE */ 5) {
+ // throw new Exception('First token must be a name type');
+ // }
return $stream->next()->getValue();
}
diff --git a/tests/ComponentTokenParserTest.php b/tests/ComponentTokenParserTest.php
index 0fad788..26a6f9b 100644
--- a/tests/ComponentTokenParserTest.php
+++ b/tests/ComponentTokenParserTest.php
@@ -4,10 +4,12 @@
use Performing\TwigComponents\Configuration;
use Performing\TwigComponents\TokenParser\ComponentTokenParser;
+use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
class ComponentTokenParserTest extends TestCase
{
+ #[Test]
public function testGetComponentPathWithHintPath()
{
$loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/templates');
@@ -27,6 +29,7 @@ public function testGetComponentPathWithHintPath()
$this->assertEquals('mynamespace.myplugin::components.test.component', $componentPath);
}
+ #[Test]
public function testGetComponentPathWithoutHintPath()
{
$loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/templates');
diff --git a/tests/ComponentsTestTrait.php b/tests/ComponentsTestTrait.php
index 549bfd5..0efcc15 100644
--- a/tests/ComponentsTestTrait.php
+++ b/tests/ComponentsTestTrait.php
@@ -2,9 +2,11 @@
namespace Performing\TwigComponents\Tests;
+use PHPUnit\Framework\Attributes\Test;
+
trait ComponentsTestTrait
{
- /** @test */
+ #[Test]
public function render_simple_component()
{
$html = $this->twig->render('test_simple_component.twig');
@@ -14,7 +16,7 @@ public function render_simple_component()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_simple_component_with_dash()
{
$html = $this->twig->render('test_simple_component_with_dash.twig');
@@ -24,7 +26,7 @@ public function render_simple_component_with_dash()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_simple_component_in_folder()
{
$html = $this->twig->render('test_simple_component_in_folder.twig');
@@ -34,7 +36,7 @@ public function render_simple_component_in_folder()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_component_with_slots()
{
$html = $this->twig->render('test_with_slots.twig');
@@ -44,7 +46,7 @@ public function render_component_with_slots()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_xtags_with_slots()
{
$html = $this->twig->render('test_xtags_with_slots.twig');
@@ -54,7 +56,7 @@ public function render_xtags_with_slots()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_nested_xtags_with_slots()
{
$html = $this->twig->render('test_nested_xtags_with_slots.twig');
@@ -64,7 +66,7 @@ public function render_nested_xtags_with_slots()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_deeply_nested_xtags_with_slots()
{
$html = $this->twig->render('test_deeply_nested_xtags_with_slots.twig');
@@ -75,7 +77,7 @@ public function render_deeply_nested_xtags_with_slots()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_component_with_xtags()
{
$html = $this->twig->render('test_xtags_component.twig');
@@ -87,7 +89,7 @@ public function render_component_with_xtags()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_component_with_attributes()
{
$html = $this->twig->render('test_with_attributes.twig');
@@ -101,7 +103,7 @@ public function render_component_with_attributes()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_namespaced_component()
{
$html = $this->twig->render('test_namespaced_component.twig');
@@ -111,7 +113,7 @@ public function render_namespaced_component()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_namespaced_xtags_component()
{
$html = $this->twig->render('test_namespaced_xtags_component.twig');
@@ -123,7 +125,7 @@ public function render_namespaced_xtags_component()
HTML, $html);
}
- /** @test */
+ #[Test]
public function test_class_merge_works_with_components_in_components()
{
$template = $this->twig->createTemplate(<<assertEquals('', $html);
}
- /** @test */
+ #[Test]
public function test_attributes_dont_conflict_with_components_in_components()
{
$template = $this->twig->createTemplate(<<assertEquals('
', $html);
}
- /** @test */
+ #[Test]
public function render_simple_dynamic_component()
{
$html = $this->twig->render('test_simple_dynamic_component.twig');
@@ -156,7 +158,7 @@ public function render_simple_dynamic_component()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_dynamic_component_with_xtags()
{
$html = $this->twig->render('test_xtags_dynamic_component.twig');
@@ -168,7 +170,7 @@ public function render_dynamic_component_with_xtags()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_namespaced_dynamic_component()
{
$html = $this->twig->render('test_namespaced_dynamic_component.twig');
@@ -178,7 +180,7 @@ public function render_namespaced_dynamic_component()
HTML, $html);
}
- /** @test */
+ #[Test]
public function render_namespaced_xtags_dynamic_component()
{
$html = $this->twig->render('test_namespaced_xtags_dynamic_component.twig');
diff --git a/tests/GlobalContextTest.php b/tests/GlobalContextTest.php
index a113d50..75ee7f9 100644
--- a/tests/GlobalContextTest.php
+++ b/tests/GlobalContextTest.php
@@ -3,6 +3,7 @@
namespace Performing\TwigComponents\Tests;
use Performing\TwigComponents\Configuration;
+use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
class GlobalContextTest extends TestCase
@@ -36,7 +37,7 @@ public function setUp(): void
$this->twig = $this->setupTwig();
}
- /** @test */
+ #[Test]
public function share_global_context_inside_components()
{
$template = $this->twig->createTemplate(<<