From 19cdb95157b6f4627731a67d374f2f5a146418f9 Mon Sep 17 00:00:00 2001 From: Carlos Granados Date: Wed, 28 Feb 2024 19:13:46 +0100 Subject: [PATCH] Add Immutable attribute and the possibility to exclude some annotations --- README.md | 18 ++++++ composer.json | 2 +- ...tic-analysis-annotations-to-attributes.php | 3 + src/AnnotationsToAttributesRector.php | 16 ++++-- tests/ExcludeAnnotationsTest.php | 29 ++++++++++ tests/Fixture/ImmutableAttributeTest.php.inc | 55 +++++++++++++++++++ .../ExcludeAnnotationsTest.php.inc | 51 +++++++++++++++++ ...nfigured-rule-with-exclude-annotations.php | 19 +++++++ 8 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 tests/ExcludeAnnotationsTest.php create mode 100644 tests/Fixture/ImmutableAttributeTest.php.inc create mode 100644 tests/SpecialFixture/ExcludeAnnotationsTest.php.inc create mode 100644 tests/config/configured-rule-with-exclude-annotations.php diff --git a/README.md b/README.md index 0be59cc..ece16b4 100644 --- a/README.md +++ b/README.md @@ -108,11 +108,29 @@ return RectorConfig::configure() ); ``` +If you want to replace most annotations but exclude a few, you can use the `excludeAnnotations` config parameter like this: + +```php +use Rector\Config\RectorConfig; +use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector; + +return RectorConfig::configure() + ->withConfiguredRule( + AnnotationsToAttributesRector::class, + [ + 'excludeAnnotations' => ['throws', 'deprecated'], + ] + ); +``` + +That would convert all annotations except `@throws` and `@deprecated` + These are the available attributes and their corresponding PHPDoc annotations: | Attribute | PHPDoc Annotations | |-------------------------------------------------------------------------------------------------------------------|--------------------| | [Deprecated](https://github.com/php-static-analysis/attributes/blob/main/doc/Deprecated.md) | `@deprecated` | +| [Immmutable](https://github.com/php-static-analysis/attributes/blob/main/doc/Immmutable.md) | `@immmutable` | | [Impure](https://github.com/php-static-analysis/attributes/blob/main/doc/Impure.md) | `@impure` | | [Internal](https://github.com/php-static-analysis/attributes/blob/main/doc/Internal.md) | `@internal` | | [IsReadOnly](https://github.com/php-static-analysis/attributes/blob/main/doc/IsReadOnly.md) | `@readonly` | diff --git a/composer.json b/composer.json index 664d3fc..77e1290 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "require": { "php": ">=8.0", "cweagans/composer-patches": "^1.7", - "php-static-analysis/attributes": "^0.1.16 || dev-main", + "php-static-analysis/attributes": "^0.1.17 || dev-main", "rector/rector": "^0.19 || ^1.0" }, "require-dev": { diff --git a/config/sets/php-static-analysis-annotations-to-attributes.php b/config/sets/php-static-analysis-annotations-to-attributes.php index c62d480..7620b94 100644 --- a/config/sets/php-static-analysis-annotations-to-attributes.php +++ b/config/sets/php-static-analysis-annotations-to-attributes.php @@ -3,6 +3,7 @@ declare(strict_types=1); use PhpStaticAnalysis\Attributes\Deprecated; +use PhpStaticAnalysis\Attributes\Immutable; use PhpStaticAnalysis\Attributes\Impure; use PhpStaticAnalysis\Attributes\Internal; use PhpStaticAnalysis\Attributes\Method; @@ -36,6 +37,7 @@ [ new AnnotationToAttribute('deprecated', Deprecated::class), new AnnotationToAttribute('extends', TemplateExtends::class), + new AnnotationToAttribute('immutable', Immutable::class), new AnnotationToAttribute('impure', Impure::class), new AnnotationToAttribute('implements', TemplateImplements::class), new AnnotationToAttribute('internal', Internal::class), @@ -65,6 +67,7 @@ 'addParamAttributeOnParameters' => false, 'useTypeAttributeForReturnAnnotation' => false, 'usePropertyAttributeForVarAnnotation' => false, + 'excludeAnnotations' => [], ] ); }; diff --git a/src/AnnotationsToAttributesRector.php b/src/AnnotationsToAttributesRector.php index 1ff9604..58f506b 100644 --- a/src/AnnotationsToAttributesRector.php +++ b/src/AnnotationsToAttributesRector.php @@ -124,19 +124,22 @@ public function addArrays(array $array1, array $array2): array /** * @psalm-suppress MoreSpecificImplementedParamType */ - #[Param(configuration: '(AnnotationToAttribute|bool)[]')] + #[Param(configuration: '(AnnotationToAttribute|bool|string[])[]')] public function configure(array $configuration): void { + $excludedAnnotations = []; foreach ($configuration as $key => $value) { if ($value instanceof AnnotationToAttribute) { $tag = str_replace('_', '-', $value->getTag()); $this->annotationsToAttributes[$tag] = $value; - } elseif ($key == 'addParamAttributeOnParameters') { + } elseif (is_bool($value) && $key == 'addParamAttributeOnParameters') { $this->addParamAttributeOnParameters = $value; - } elseif ($key == 'useTypeAttributeForReturnAnnotation') { + } elseif (is_bool($value) && $key == 'useTypeAttributeForReturnAnnotation') { $this->useTypeAttributeForReturnAnnotation = $value; - } elseif ($key == 'usePropertyAttributeForVarAnnotation') { + } elseif (is_bool($value) && $key == 'usePropertyAttributeForVarAnnotation') { $this->usePropertyAttributeForVarAnnotation = $value; + } elseif (is_array($value) && $key == 'excludeAnnotations') { + $excludedAnnotations = $value; } } if ($this->useTypeAttributeForReturnAnnotation) { @@ -151,6 +154,11 @@ public function configure(array $configuration): void new AnnotationToAttribute('var', Property::class); } } + foreach ($excludedAnnotations as $excludedAnnotation) { + if (isset($this->annotationsToAttributes[$excludedAnnotation])) { + unset($this->annotationsToAttributes[$excludedAnnotation]); + } + } } #[Returns('array>')] diff --git a/tests/ExcludeAnnotationsTest.php b/tests/ExcludeAnnotationsTest.php new file mode 100644 index 0000000..d74e37f --- /dev/null +++ b/tests/ExcludeAnnotationsTest.php @@ -0,0 +1,29 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + yield [__DIR__ . '/SpecialFixture/ExcludeAnnotationsTest.php.inc']; + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured-rule-with-exclude-annotations.php'; + } +} diff --git a/tests/Fixture/ImmutableAttributeTest.php.inc b/tests/Fixture/ImmutableAttributeTest.php.inc new file mode 100644 index 0000000..386a707 --- /dev/null +++ b/tests/Fixture/ImmutableAttributeTest.php.inc @@ -0,0 +1,55 @@ + +----- + diff --git a/tests/SpecialFixture/ExcludeAnnotationsTest.php.inc b/tests/SpecialFixture/ExcludeAnnotationsTest.php.inc new file mode 100644 index 0000000..078f357 --- /dev/null +++ b/tests/SpecialFixture/ExcludeAnnotationsTest.php.inc @@ -0,0 +1,51 @@ + +----- + diff --git a/tests/config/configured-rule-with-exclude-annotations.php b/tests/config/configured-rule-with-exclude-annotations.php new file mode 100644 index 0000000..bfb5ef5 --- /dev/null +++ b/tests/config/configured-rule-with-exclude-annotations.php @@ -0,0 +1,19 @@ +sets([ + PhpStaticAnalysisSetList::ANNOTATIONS_TO_ATTRIBUTES + ]); + $rectorConfig->ruleWithConfiguration( + AnnotationsToAttributesRector::class, + [ + 'excludeAnnotations' => ['throws', 'deprecated'], + ] + ); +};