diff --git a/README.md b/README.md
index 5e8ffc3..c5e349f 100644
--- a/README.md
+++ b/README.md
@@ -404,3 +404,94 @@ final class Alert
:+1:
+
+### PreMountMethodSignatureRule
+
+Enforces that methods with the `#[PreMount]` attribute have the correct signature: they must be public and have exactly one parameter of type `array`, with a return type of `array`.
+This ensures proper integration with the Symfony UX TwigComponent lifecycle hooks.
+
+```yaml
+rules:
+ - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PreMountMethodSignatureRule
+```
+
+```php
+// src/Twig/Components/Alert.php
+namespace App\Twig\Components;
+
+use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
+use Symfony\UX\TwigComponent\Attribute\PreMount;
+
+#[AsTwigComponent]
+final class Alert
+{
+ #[PreMount]
+ protected function preMount(array $data): array
+ {
+ return $data;
+ }
+}
+```
+
+```php
+// src/Twig/Components/Alert.php
+namespace App\Twig\Components;
+
+use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
+use Symfony\UX\TwigComponent\Attribute\PreMount;
+
+#[AsTwigComponent]
+final class Alert
+{
+ #[PreMount]
+ public function preMount(array $data): void
+ {
+ }
+}
+```
+
+```php
+// src/Twig/Components/Alert.php
+namespace App\Twig\Components;
+
+use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
+use Symfony\UX\TwigComponent\Attribute\PreMount;
+
+#[AsTwigComponent]
+final class Alert
+{
+ #[PreMount]
+ public function preMount(string $data): array
+ {
+ return [];
+ }
+}
+```
+
+:x:
+
+
+
+```php
+// src/Twig/Components/Alert.php
+namespace App\Twig\Components;
+
+use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
+use Symfony\UX\TwigComponent\Attribute\PreMount;
+
+#[AsTwigComponent]
+final class Alert
+{
+ #[PreMount]
+ public function preMount(array $data): array
+ {
+ $data['timestamp'] = time();
+
+ return $data;
+ }
+}
+```
+
+:+1:
+
+
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
deleted file mode 100644
index 42b264f..0000000
--- a/phpstan-baseline.neon
+++ /dev/null
@@ -1,25 +0,0 @@
-parameters:
- ignoreErrors:
- -
- message: '#^Property Kocal\\PHPStanSymfonyUX\\Tests\\Rules\\TwigComponent\\PublicPropertiesShouldBeCamelCaseRule\\Fixture\\ComponentWithPrivateNonCamelCaseProperties\:\:\$is_active is unused\.$#'
- identifier: property.unused
- count: 1
- path: tests/Rules/TwigComponent/PublicPropertiesShouldBeCamelCaseRule/Fixture/ComponentWithPrivateNonCamelCaseProperties.php
-
- -
- message: '#^Property Kocal\\PHPStanSymfonyUX\\Tests\\Rules\\TwigComponent\\PublicPropertiesShouldBeCamelCaseRule\\Fixture\\ComponentWithPrivateNonCamelCaseProperties\:\:\$user_name is unused\.$#'
- identifier: property.unused
- count: 1
- path: tests/Rules/TwigComponent/PublicPropertiesShouldBeCamelCaseRule/Fixture/ComponentWithPrivateNonCamelCaseProperties.php
-
- -
- message: '#^Method Kocal\\PHPStanSymfonyUX\\Tests\\Rules\\TwigComponent\\MethodsShouldBePublicOrPrivateRule\\Fixture\\ComponentWithPublicAndPrivateMethods\:\:privateMethod\(\) is unused\.$#'
- identifier: method.unused
- count: 1
- path: tests/Rules/TwigComponent/MethodsShouldBePublicOrPrivateRule/Fixture/ComponentWithPublicAndPrivateMethods.php
-
- -
- message: '#^Method Kocal\\PHPStanSymfonyUX\\Tests\\Rules\\TwigComponent\\MethodsShouldBePublicOrPrivateRule\\Fixture\\LiveComponentWithPublicAndPrivateMethods\:\:privateMethod\(\) is unused\.$#'
- identifier: method.unused
- count: 1
- path: tests/Rules/TwigComponent/MethodsShouldBePublicOrPrivateRule/Fixture/LiveComponentWithPublicAndPrivateMethods.php
diff --git a/phpstan.dist.neon b/phpstan.dist.neon
index ea25a23..e786f4c 100644
--- a/phpstan.dist.neon
+++ b/phpstan.dist.neon
@@ -1,9 +1,17 @@
-includes:
- - ./phpstan-baseline.neon
-
parameters:
level: max
paths:
- src
- tests
+
+ ignoreErrors:
+ -
+ paths:
+ - tests/**/Fixture/*
+ identifiers:
+ - method.unused
+ - missingType.iterableValue
+ - missingType.return
+ - property.unused
+ - return.unusedType
\ No newline at end of file
diff --git a/src/Rules/TwigComponent/PreMountMethodSignatureRule.php b/src/Rules/TwigComponent/PreMountMethodSignatureRule.php
new file mode 100644
index 0000000..4543c34
--- /dev/null
+++ b/src/Rules/TwigComponent/PreMountMethodSignatureRule.php
@@ -0,0 +1,115 @@
+
+ */
+final class PreMountMethodSignatureRule implements Rule
+{
+ public function getNodeType(): string
+ {
+ return Class_::class;
+ }
+
+ public function processNode(Node $node, Scope $scope): array
+ {
+ if (! AttributeFinder::findAnyAttribute($node, [AsTwigComponent::class, AsLiveComponent::class])) {
+ return [];
+ }
+
+ $errors = [];
+
+ foreach ($node->getMethods() as $method) {
+ // Check if the method has the PreMount attribute
+ if (! AttributeFinder::findAttribute($method, PreMount::class)) {
+ continue;
+ }
+
+ $errors = array_merge($errors, $this->validatePreMountMethod($method));
+ }
+
+ return $errors;
+ }
+
+ /**
+ * @return list<\PHPStan\Rules\IdentifierRuleError>
+ */
+ private function validatePreMountMethod(Node\Stmt\ClassMethod $node): array
+ {
+ $errors = [];
+
+ // Check if the method is public
+ if (! $node->isPublic()) {
+ $errors[] = RuleErrorBuilder::message(
+ sprintf('Method "%s" with #[PreMount] attribute must be public.', $node->name->toString())
+ )
+ ->identifier('symfonyUX.twigComponent.preMountMethodMustBePublic')
+ ->line($node->getLine())
+ ->tip('Change the method visibility to public.')
+ ->build();
+ }
+
+ // Check the return type
+ $returnType = $node->getReturnType();
+ if ($returnType === null) {
+ $errors[] = RuleErrorBuilder::message(
+ sprintf('Method "%s" with #[PreMount] attribute must have a return type of "array".', $node->name->toString())
+ )
+ ->identifier('symfonyUX.twigComponent.preMountMethodMissingReturnType')
+ ->line($node->getLine())
+ ->tip('Add ": array" return type to the method.')
+ ->build();
+ } else {
+ $isValidReturnType = $returnType instanceof Node\Identifier && $returnType->toString() === 'array';
+
+ if (! $isValidReturnType) {
+ $errors[] = RuleErrorBuilder::message(
+ sprintf('Method "%s" with #[PreMount] attribute must have a return type of "array".', $node->name->toString())
+ )
+ ->identifier('symfonyUX.twigComponent.preMountMethodInvalidReturnType')
+ ->line($returnType->getLine())
+ ->tip('Change the return type to ": array".')
+ ->build();
+ }
+ }
+
+ // Check that there is exactly one parameter of type array
+ if (count($node->params) !== 1) {
+ $errors[] = RuleErrorBuilder::message(
+ sprintf('Method "%s" with #[PreMount] attribute must have exactly one parameter of type "array".', $node->name->toString())
+ )
+ ->identifier('symfonyUX.twigComponent.preMountMethodInvalidParameterCount')
+ ->line($node->getLine())
+ ->tip('The method should have exactly one parameter: "array $data".')
+ ->build();
+ } else {
+ $param = $node->params[0];
+ $paramType = $param->type;
+
+ if (! $paramType instanceof Node\Identifier || $paramType->toString() !== 'array') {
+ $errors[] = RuleErrorBuilder::message(
+ sprintf('Method "%s" with #[PreMount] attribute must have a parameter of type "array".', $node->name->toString())
+ )
+ ->identifier('symfonyUX.twigComponent.preMountMethodInvalidParameterType')
+ ->line($param->getLine())
+ ->tip('Change the parameter type to "array".')
+ ->build();
+ }
+ }
+
+ return $errors;
+ }
+}
diff --git a/tests/Rules/TwigComponent/PreMountMethodSignatureRule/Fixture/InvalidNoParameter.php b/tests/Rules/TwigComponent/PreMountMethodSignatureRule/Fixture/InvalidNoParameter.php
new file mode 100644
index 0000000..301e101
--- /dev/null
+++ b/tests/Rules/TwigComponent/PreMountMethodSignatureRule/Fixture/InvalidNoParameter.php
@@ -0,0 +1,18 @@
+
+ */
+final class PreMountMethodSignatureRuleTest extends RuleTestCase
+{
+ public function testViolations(): void
+ {
+ $this->analyse(
+ [__DIR__ . '/Fixture/InvalidNotPublic.php'],
+ [
+ [
+ 'Method "preMount" with #[PreMount] attribute must be public.',
+ 13,
+ 'Change the method visibility to public.',
+ ],
+ ]
+ );
+
+ $this->analyse(
+ [__DIR__ . '/Fixture/InvalidNoReturnType.php'],
+ [
+ [
+ 'Method "preMount" with #[PreMount] attribute must have a return type of "array".',
+ 13,
+ 'Add ": array" return type to the method.',
+ ],
+ ]
+ );
+
+ $this->analyse(
+ [__DIR__ . '/Fixture/InvalidWrongReturnType.php'],
+ [
+ [
+ 'Method "preMount" with #[PreMount] attribute must have a return type of "array".',
+ 14,
+ 'Change the return type to ": array".',
+ ],
+ ]
+ );
+
+ $this->analyse(
+ [__DIR__ . '/Fixture/InvalidNoParameter.php'],
+ [
+ [
+ 'Method "preMount" with #[PreMount] attribute must have exactly one parameter of type "array".',
+ 13,
+ 'The method should have exactly one parameter: "array $data".',
+ ],
+ ]
+ );
+
+ $this->analyse(
+ [__DIR__ . '/Fixture/InvalidTooManyParameters.php'],
+ [
+ [
+ 'Method "preMount" with #[PreMount] attribute must have exactly one parameter of type "array".',
+ 13,
+ 'The method should have exactly one parameter: "array $data".',
+ ],
+ ]
+ );
+
+ $this->analyse(
+ [__DIR__ . '/Fixture/InvalidWithNullableReturnType.php'],
+ [
+ [
+ 'Method "preMount" with #[PreMount] attribute must have a return type of "array".',
+ 14,
+ 'Change the return type to ": array".',
+ ],
+ ]
+ );
+
+ $this->analyse(
+ [__DIR__ . '/Fixture/InvalidWrongParameterType.php'],
+ [
+ [
+ 'Method "preMount" with #[PreMount] attribute must have a parameter of type "array".',
+ 14,
+ 'Change the parameter type to "array".',
+ ],
+ ]
+ );
+ }
+
+ public function testNoViolations(): void
+ {
+ $this->analyse(
+ [__DIR__ . '/Fixture/NotAComponent.php'],
+ []
+ );
+
+ $this->analyse(
+ [__DIR__ . '/Fixture/ValidTwigComponent.php'],
+ []
+ );
+
+ $this->analyse(
+ [__DIR__ . '/Fixture/ValidLiveComponent.php'],
+ []
+ );
+ }
+
+ public static function getAdditionalConfigFiles(): array
+ {
+ return [__DIR__ . '/config/configured_rule.neon'];
+ }
+
+ protected function getRule(): Rule
+ {
+ return self::getContainer()->getByType(PreMountMethodSignatureRule::class);
+ }
+}
diff --git a/tests/Rules/TwigComponent/PreMountMethodSignatureRule/config/configured_rule.neon b/tests/Rules/TwigComponent/PreMountMethodSignatureRule/config/configured_rule.neon
new file mode 100644
index 0000000..defbfce
--- /dev/null
+++ b/tests/Rules/TwigComponent/PreMountMethodSignatureRule/config/configured_rule.neon
@@ -0,0 +1,2 @@
+rules:
+ - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PreMountMethodSignatureRule