From 5105e765527c20992b39dc4a308e2b44526eb606 Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Mon, 17 Nov 2025 19:40:29 +0300 Subject: [PATCH] Added Rector --- README.md | 39 +++++++++++++++++- bin/codestyle | 2 + composer.json | 6 ++- presets/rector/default.php | 44 ++++++++++++++++++++ presets/rector/laravel.php | 77 +++++++++++++++++++++++++++++++++++ rector.php | 15 +++++++ src/Console/RectorCommand.php | 64 +++++++++++++++++++++++++++++ 7 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 presets/rector/default.php create mode 100644 presets/rector/laravel.php create mode 100644 rector.php create mode 100644 src/Console/RectorCommand.php diff --git a/README.md b/README.md index ca0a931..ed61242 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ You can install the package using [Composer](https://getcomposer.org): ```bash composer require dragon-code/codestyler --dev -composer config scripts.style "vendor/bin/pint --parallel" +composer config scripts.style "vendor/bin/rector && vendor/bin/pint --parallel" ``` It is also possible to establish dependence in the global area of visibility: @@ -44,6 +44,7 @@ and `biome.json` file for [Biome Linter](https://biomejs.dev): "scripts": { "post-update-cmd": [ "vendor/bin/codestyle pint 8.4", + "vendor/bin/codestyle rector laravel", "vendor/bin/codestyle editorconfig", "vendor/bin/codestyle npm", "composer normalize" @@ -59,6 +60,7 @@ When using a globally established dependence, the call must be replaced with the "scripts": { "post-update-cmd": [ "codestyle pint 8.4", + "codestyle rector laravel", "codestyle editorconfig", "codestyle npm", "composer normalize" @@ -100,6 +102,35 @@ The linter is invoked by a console command: composer style ``` +### Rector + +[`Rector`](https://getrector.com) is uses as the code rector for PHP. + +The Rector is invoked by a console command: + +```bash +composer style +``` + +To do this, make sure the file is in the root of the project. +You can also automate this process by adding a call to the file copy function in the `scripts.post-update-cmd` +section of the `composer.json` file. + +```JSON +{ + "scripts": { + "post-update-cmd": [ + "vendor/bin/codestyle rector laravel" + ] + } +} +``` + +Available presets: + +- `laravel` +- `default` + ### Node Linter [Biome](https://biomejs.dev) is used as the linter for JS, CSS and JSON. @@ -183,11 +214,15 @@ After completing all the steps, the `composer.json` file will have the following "scripts": { "post-update-cmd": [ "vendor/bin/codestyle pint 8.4", + "vendor/bin/codestyle rector laravel", "vendor/bin/codestyle editorconfig", "vendor/bin/codestyle npm", "composer normalize" ], - "style": "vendor/bin/pint --parallel" + "style": [ + "vendor/bin/pint --parallel", + "vendor/bin/rector" + ] } } ``` diff --git a/bin/codestyle b/bin/codestyle index 20c1d92..c043f04 100644 --- a/bin/codestyle +++ b/bin/codestyle @@ -6,6 +6,7 @@ declare(strict_types=1); use DragonCode\Codestyler\Console\EditorConfigCommand; use DragonCode\Codestyler\Console\NpmCommand; use DragonCode\Codestyler\Console\PintCommand; +use DragonCode\Codestyler\Console\RectorCommand; use Symfony\Component\Console\Application; if (PHP_SAPI !== 'cli' || (PHP_MAJOR_VERSION < 8 && PHP_MINOR_VERSION < 2)) { @@ -44,6 +45,7 @@ $application = new Application('The Dragon Code: Styler', '6.x'); $application->add(new EditorConfigCommand); $application->add(new PintCommand); +$application->add(new RectorCommand); $application->add(new NpmCommand); $application->run(); diff --git a/composer.json b/composer.json index a250d1a..d02def9 100644 --- a/composer.json +++ b/composer.json @@ -43,6 +43,7 @@ "require": { "php": "^8.2", "ext-json": "*", + "driftingly/rector-laravel": "^2.1", "ergebnis/composer-normalize": "^2.48", "laravel/pint": "^1.24", "symfony/console": "^7.3" @@ -74,6 +75,9 @@ "php bin/codestyle pint 8.2", "composer normalize" ], - "style": "vendor/bin/pint ./bin/codestyle ./src/ ./tests" + "style": [ + "vendor/bin/rector", + "vendor/bin/pint ./bin/codestyle ./src/ ./tests" + ] } } diff --git a/presets/rector/default.php b/presets/rector/default.php new file mode 100644 index 0000000..3a5af63 --- /dev/null +++ b/presets/rector/default.php @@ -0,0 +1,44 @@ + array_filter($paths, fn (string $path): bool => realpath($path) !== false); + +return RectorConfig::configure() + ->withPaths( + $paths([ + 'app', + 'config', + 'database', + 'public/index.php', + 'resources', + 'src', + 'tests', + ]) + ) + ->withFileExtensions(['php']) + ->withParallel() + ->withPreparedSets( + deadCode : true, + typeDeclarations: true, + ) + ->withPhpSets() + ->withImportNames( + removeUnusedImports: true, + ) + ->withComposerBased( + phpunit: true + ) + ->withAttributesSets( + phpunit: true, + ) + ->withConfiguredRule(RemoveDumpDataDeadCodeRector::class, [ + 'dd', + 'dump', + 'var_dump', + 'print_r', + 'echo', + ]); diff --git a/presets/rector/laravel.php b/presets/rector/laravel.php new file mode 100644 index 0000000..8b1c3ed --- /dev/null +++ b/presets/rector/laravel.php @@ -0,0 +1,77 @@ + array_filter($paths, fn (string $path): bool => realpath($path) !== false); + +return RectorConfig::configure() + ->withPaths( + $paths([ + 'app', + 'bin', + 'bootstrap', + 'config', + 'database', + 'lang', + 'operations', + 'public/index.php', + 'resources', + 'routes', + 'src', + 'tests', + ]) + ) + ->withSkip( + $paths(['bootstrap/cache']) + ) + ->withFileExtensions(['php']) + ->withParallel() + ->withPreparedSets( + deadCode : true, + typeDeclarations: true, + ) + ->withPhpSets() + ->withSetProviders(LaravelSetProvider::class) + ->withImportNames( + removeUnusedImports: true, + ) + ->withComposerBased( + phpunit: true, + laravel: true + ) + ->withAttributesSets( + phpunit: true, + ) + ->withSets([ + LaravelSetList::LARAVEL_COLLECTION, + LaravelSetList::LARAVEL_FACADE_ALIASES_TO_FULL_NAMES, + LaravelSetList::LARAVEL_TESTING, + ]) + ->withConfiguredRule(RemoveDumpDataDeadCodeRector::class, [ + 'dd', + 'dump', + 'var_dump', + 'print_r', + 'echo', + ]) + ->withConfiguredRule(WhereToWhereLikeRector::class, [ + WhereToWhereLikeRector::USING_POSTGRES_DRIVER => true, + ]) + ->withRules([ + RemoveModelPropertyFromFactoriesRector::class, + UseComponentPropertyWithinCommandsRector::class, + TypeHintTappableCallRector::class, + EloquentWhereRelationTypeHintingParameterRector::class, + EloquentWhereTypeHintClosureParameterRector::class, + ]); diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..b29b004 --- /dev/null +++ b/rector.php @@ -0,0 +1,15 @@ +withPaths([ + 'bin', + 'presets', + 'src', + 'rector.php', +]); diff --git a/src/Console/RectorCommand.php b/src/Console/RectorCommand.php new file mode 100644 index 0000000..4db79ea --- /dev/null +++ b/src/Console/RectorCommand.php @@ -0,0 +1,64 @@ +setName('rector') + ->setDescription('Publishes presets for the Rector') + ->addArgument('preset', InputArgument::REQUIRED, 'The name of the preset') + ->addOption('path', 'p', InputOption::VALUE_OPTIONAL, 'Path to publish files', realpath('.')); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $version = $input->getArgument('preset'); + $path = $input->getOption('path'); + + if (! $this->validateVersion($version)) { + $output->writeln("Preset \"$version\" not found for Rector."); + + return static::FAILURE; + } + + if (! $this->validateDirectory($path)) { + $output->writeln("Directory \"$path\" not found."); + + return static::FAILURE; + } + + copy($this->presetPath($version), $path . '/rector.php'); + + $output->writeln("Preset \"$version\" published successfully."); + + return static::SUCCESS; + } + + protected function validateVersion(string $version): bool + { + return file_exists( + $this->presetPath($version) + ); + } + + protected function validateDirectory(string $path): bool + { + return file_exists($path) && is_dir($path); + } + + protected function presetPath(string $version): string + { + return __DIR__ . "/../../presets/rector/$version.php"; + } +}