diff --git a/.github/workflows/composer-require-checker.yml b/.github/workflows/composer-require-checker.yml index 99dfb1c..df3e5d9 100644 --- a/.github/workflows/composer-require-checker.yml +++ b/.github/workflows/composer-require-checker.yml @@ -7,6 +7,7 @@ on: - 'tests/**' - 'composer.json' - '.github/workflows/composer-require-checker.yml' + - 'composer-require-checker.json' push: branches: ['master'] paths: *paths @@ -22,6 +23,7 @@ jobs: composer-require-checker: uses: yiisoft/actions/.github/workflows/composer-require-checker.yml@master with: + config: composer-require-checker.json os: >- ['ubuntu-latest'] php: >- diff --git a/CHANGELOG.md b/CHANGELOG.md index d7be0e5..e21c1a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ ## 1.0.1 under development -- Enh #4: Add the `no_empty_statement` rule to `@Yiisoft/Core` (@mspirkov) +- New #4: Add the `no_empty_statement` rule to `@Yiisoft/Core` (@mspirkov) +- New #11: Add `RemoveOverrideAttributeRector` Rector rule (@vjik) +- New #11: Add `SetList::YII_CORE` Rector set (@vjik) ## 1.0.0 January 23, 2026 diff --git a/README.md b/README.md index a954489..0c73609 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ [![type-coverage](https://shepherd.dev/github/yiisoft/code-style/coverage.svg)](https://shepherd.dev/github/yiisoft/code-style) [![psalm-level](https://shepherd.dev/github/yiisoft/code-style/level.svg)](https://shepherd.dev/github/yiisoft/code-style) -A package that provides [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) rule sets for enforcing code style -in Yii packages. +A package that provides [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) rule sets and +[Rector](https://github.com/rectorphp/rector) rules for enforcing code style in Yii packages. ## Requirements @@ -31,6 +31,8 @@ composer require --dev yiisoft/code-style ## General usage +### PHP CS Fixer + The package contains the following sets of rules: 1. `@Yiisoft/Core` @@ -61,6 +63,33 @@ return ConfigBuilder::build() ``` +### Rector + +The package provides [Rector](https://github.com/rectorphp/rector) rules: + +- `RemoveOverrideAttributeRector` — removes the `#[Override]` attribute from methods. Yii convention is not to use + this attribute. + +A ready-to-use `SetList::YII_CORE` set with rules recommended for Yii packages is also provided: + +```php +withPaths([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->withSets([ + SetList::YII_CORE, + ]); +``` + ## Documentation - [Internals](docs/internals.md) diff --git a/composer-require-checker.json b/composer-require-checker.json new file mode 100644 index 0000000..2b17420 --- /dev/null +++ b/composer-require-checker.json @@ -0,0 +1,29 @@ +{ + "symbol-whitelist": [ + "PhpParser\\Node", + "PhpParser\\Node\\Stmt\\ClassMethod", + "Rector\\CodeQuality\\Rector\\Class_\\InlineConstructorDefaultToPropertyRector", + "Rector\\Php74\\Rector\\Closure\\ClosureToArrowFunctionRector", + "Rector\\Php81\\Rector\\FuncCall\\NullToStrictStringFuncCallArgRector", + "Rector\\Php81\\Rector\\Property\\ReadOnlyPropertyRector", + "Rector\\Rector\\AbstractRector", + "Symplify\\RuleDocGenerator\\Contract\\DocumentedRuleInterface", + "Symplify\\RuleDocGenerator\\ValueObject\\CodeSample\\CodeSample", + "Symplify\\RuleDocGenerator\\ValueObject\\RuleDefinition", + "null", "true", "false", + "static", "self", "parent", + "array", "string", "int", "float", "bool", "iterable", "callable", "void", "object", "mixed", "never" + ], + "php-core-extensions": [ + "Core", + "date", + "json", + "hash", + "pcre", + "Phar", + "Reflection", + "SPL", + "standard" + ], + "scan-files": [] +} diff --git a/composer.json b/composer.json index eccb75b..f45066d 100644 --- a/composer.json +++ b/composer.json @@ -28,12 +28,12 @@ ], "require": { "php": "^7.4 || ^8.0", - "friendsofphp/php-cs-fixer": "^3.92.5" + "friendsofphp/php-cs-fixer": "^3.92.5", + "rector/rector": "^2.0" }, "require-dev": { "maglnet/composer-require-checker": "^3.8.0 || ^4.7.1", "phpunit/phpunit": "^9.6.31", - "rector/rector": "^2.3.4", "vimeo/psalm": "^5.26.1 || ^6.10.3" }, "autoload": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8f2359e..e2562c2 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,7 +4,7 @@ backupGlobals="false" colors="true" verbose="true" - bootstrap="vendor/autoload.php" + bootstrap="tests/bootstrap.php" failOnRisky="true" failOnWarning="true" convertErrorsToExceptions="true" diff --git a/rector.php b/rector.php index d545deb..3aa0ecd 100644 --- a/rector.php +++ b/rector.php @@ -2,9 +2,8 @@ declare(strict_types=1); -use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector; use Rector\Config\RectorConfig; -use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector; +use Yiisoft\CodeStyle\Rector\SetList; return RectorConfig::configure() ->withPaths([ @@ -12,9 +11,6 @@ __DIR__ . '/tests', ]) ->withPhp74Sets() - ->withRules([ - InlineConstructorDefaultToPropertyRector::class, - ]) - ->withSkip([ - ClosureToArrowFunctionRector::class, + ->withSets([ + SetList::YII_CORE, ]); diff --git a/src/Rector/Rules/RemoveOverrideAttributeRector.php b/src/Rector/Rules/RemoveOverrideAttributeRector.php new file mode 100644 index 0000000..63dbfab --- /dev/null +++ b/src/Rector/Rules/RemoveOverrideAttributeRector.php @@ -0,0 +1,74 @@ +attrGroups as $groupKey => $attrGroup) { + foreach ($attrGroup->attrs as $attrKey => $attr) { + if ($this->getName($attr->name) === 'Override') { + unset($attrGroup->attrs[$attrKey]); + $changed = true; + break; + } + } + + if ($attrGroup->attrs === []) { + unset($node->attrGroups[$groupKey]); + } + } + + if (!$changed) { + return null; + } + + $node->attrGroups = array_values($node->attrGroups); + + return $node; + } +} diff --git a/src/Rector/SetList.php b/src/Rector/SetList.php new file mode 100644 index 0000000..af70196 --- /dev/null +++ b/src/Rector/SetList.php @@ -0,0 +1,10 @@ +rules([ + InlineConstructorDefaultToPropertyRector::class, + RemoveOverrideAttributeRector::class, + ]); + + $rectorConfig->skip([ + ClosureToArrowFunctionRector::class, + ReadOnlyPropertyRector::class, + NullToStrictStringFuncCallArgRector::class, + ]); +}; diff --git a/tests/Rector/Rules/RemoveOverrideAttributeRector/Fixture/aliased_import.php.inc b/tests/Rector/Rules/RemoveOverrideAttributeRector/Fixture/aliased_import.php.inc new file mode 100644 index 0000000..7c4ea5a --- /dev/null +++ b/tests/Rector/Rules/RemoveOverrideAttributeRector/Fixture/aliased_import.php.inc @@ -0,0 +1,32 @@ += 8.3 + */ +final class RemoveOverrideAttributeRectorTest extends AbstractRectorTestCase +{ + /** + * @dataProvider provideData + */ + public function test(string $filePath): void + { + $this->doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/tests/Rector/Rules/RemoveOverrideAttributeRector/config/configured_rule.php b/tests/Rector/Rules/RemoveOverrideAttributeRector/config/configured_rule.php new file mode 100644 index 0000000..bd802af --- /dev/null +++ b/tests/Rector/Rules/RemoveOverrideAttributeRector/config/configured_rule.php @@ -0,0 +1,11 @@ +withRules([ + RemoveOverrideAttributeRector::class, + ]); diff --git a/tests/Rector/SetListTest.php b/tests/Rector/SetListTest.php new file mode 100644 index 0000000..cbcfe99 --- /dev/null +++ b/tests/Rector/SetListTest.php @@ -0,0 +1,25 @@ +assertFileExists(SetList::YII_CORE); + + $callable = require SetList::YII_CORE; + + $this->assertIsCallable($callable); + + $callable(new RectorConfig()); + + $this->addToAssertionCount(1); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..beb8ccd --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,17 @@ +