diff --git a/composer.json b/composer.json index d6cf06595..c44a0020d 100644 --- a/composer.json +++ b/composer.json @@ -7,11 +7,10 @@ ], "require": { "php": ">=8.3", - "entropy/entropy": "^0.2.2", + "entropy/entropy": "^0.4", "nette/robot-loader": "^4.1", "nette/utils": "^4.1", "nikic/php-parser": "^5.7", - "symfony/console": "^6.4.24", "symfony/finder": "^7.4|^8.0", "symfony/yaml": "^7.4|^8.0", "webmozart/assert": "^2.4" @@ -25,9 +24,9 @@ "shipmonk/composer-dependency-analyser": "^1.8", "symfony/config": "^6.4", "symfony/dependency-injection": "^6.4", - "symplify/easy-coding-standard": "^13.1", - "symplify/phpstan-extensions": "^12.0", - "tomasvotruba/class-leak": "^2.1|^3.0", + "symplify/easy-coding-standard": "^13.2", + "symplify/phpstan-rules": "^14.11", + "tomasvotruba/class-leak": "^2.1", "tomasvotruba/unused-public": "^2.2", "tracy/tracy": "^2.12" }, diff --git a/phpstan.neon b/phpstan.neon index 15e9303ad..eba17be71 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,6 +8,11 @@ parameters: treatPhpDocTypesAsCertain: false errorFormat: symplify + # see https://github.com/symplify/phpstan-rules#usage + symfonyReturnType: true + laravelReturnType: true + pathStrings: true + excludePaths: - */Fixture/* - */Source/* diff --git a/src/Command/AliceYamlFixturesToPhpCommand.php b/src/Command/AliceYamlFixturesToPhpCommand.php index 5197d042a..4310b3d09 100644 --- a/src/Command/AliceYamlFixturesToPhpCommand.php +++ b/src/Command/AliceYamlFixturesToPhpCommand.php @@ -6,12 +6,12 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Nette\Utils\FileSystem; use PhpParser\BuilderHelpers; use PhpParser\Node\Stmt\Return_; use PhpParser\PrettyPrinter\Standard; use Rector\SwissKnife\Finder\FilesFinder; -use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Yaml\Yaml; /** @@ -20,7 +20,7 @@ final readonly class AliceYamlFixturesToPhpCommand implements CommandInterface { public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -53,12 +53,12 @@ public function run(array $sources): int // remove YAML file unlink($yamlFileInfo->getRealPath()); - $this->symfonyStyle->writeln('[DELETED] ' . $yamlFileInfo->getRelativePathname()); - $this->symfonyStyle->writeln('[ADDED] ' . $phpFilePath); - $this->symfonyStyle->newLine(); + $this->outputPrinter->writeln('[DELETED] ' . $yamlFileInfo->getRelativePathname()); + $this->outputPrinter->writeln('[ADDED] ' . $phpFilePath); + $this->outputPrinter->newline(); } - $this->symfonyStyle->success( + $this->outputPrinter->success( sprintf('Successfully converted %d Alice YAML fixtures to PHP', count($yamlFileInfos)) ); diff --git a/src/Command/CheckCommentedCodeCommand.php b/src/Command/CheckCommentedCodeCommand.php index 166951fa6..e4ce1200f 100644 --- a/src/Command/CheckCommentedCodeCommand.php +++ b/src/Command/CheckCommentedCodeCommand.php @@ -6,9 +6,9 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Rector\SwissKnife\Comments\CommentedCodeAnalyzer; use Rector\SwissKnife\Finder\PhpFilesFinder; -use Symfony\Component\Console\Style\SymfonyStyle; final readonly class CheckCommentedCodeCommand implements CommandInterface { @@ -16,7 +16,7 @@ public function __construct( private CommentedCodeAnalyzer $commentedCodeAnalyzer, - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -32,7 +32,7 @@ public function run(array $sources, array $skipFiles = [], int $lineLimit = self $phpFileInfos = PhpFilesFinder::find($sources, $skipFiles); $message = sprintf('Analysing %d *.php files', count($phpFileInfos)); - $this->symfonyStyle->note($message); + $this->outputPrinter->writeln($message); $commentedLinesByFilePaths = []; foreach ($phpFileInfos as $phpFileInfo) { @@ -46,18 +46,18 @@ public function run(array $sources, array $skipFiles = [], int $lineLimit = self } if ($commentedLinesByFilePaths === []) { - $this->symfonyStyle->success('No commented code found'); + $this->outputPrinter->success('No commented code found'); return ExitCode::SUCCESS; } foreach ($commentedLinesByFilePaths as $filePath => $commentedLines) { foreach ($commentedLines as $commentedLine) { $messageLine = ' * ' . $filePath . ':' . $commentedLine; - $this->symfonyStyle->writeln($messageLine); + $this->outputPrinter->writeln($messageLine); } } - $this->symfonyStyle->error('Errors found'); + $this->outputPrinter->error('Errors found'); return ExitCode::ERROR; } diff --git a/src/Command/CheckConflictsCommand.php b/src/Command/CheckConflictsCommand.php index a7c0a25bb..0b5995c08 100644 --- a/src/Command/CheckConflictsCommand.php +++ b/src/Command/CheckConflictsCommand.php @@ -6,15 +6,15 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Rector\SwissKnife\Finder\FilesFinder; use Rector\SwissKnife\Git\ConflictResolver; -use Symfony\Component\Console\Style\SymfonyStyle; final readonly class CheckConflictsCommand implements CommandInterface { public function __construct( private ConflictResolver $conflictResolver, - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -35,14 +35,14 @@ public function run(array $sources, array $exclude = []): int $conflictsCountByFilePath = $this->conflictResolver->extractFromFileInfos($filePaths); if ($conflictsCountByFilePath === []) { $message = sprintf('No conflicts found in %d files', count($fileInfos)); - $this->symfonyStyle->success($message); + $this->outputPrinter->success($message); return ExitCode::SUCCESS; } foreach ($conflictsCountByFilePath as $file => $conflictCount) { $message = sprintf('File "%s" contains %d unresolved conflicts', $file, $conflictCount); - $this->symfonyStyle->error($message); + $this->outputPrinter->error($message); } return ExitCode::ERROR; diff --git a/src/Command/DumpEditorconfigCommand.php b/src/Command/DumpEditorconfigCommand.php index 3919429ec..929ad7e72 100644 --- a/src/Command/DumpEditorconfigCommand.php +++ b/src/Command/DumpEditorconfigCommand.php @@ -6,13 +6,13 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Nette\Utils\FileSystem; -use Symfony\Component\Console\Style\SymfonyStyle; final readonly class DumpEditorconfigCommand implements CommandInterface { public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -30,14 +30,14 @@ public function run(): int { $projectEditorconfigFilePath = getcwd() . '/.editorconfig'; if (file_exists($projectEditorconfigFilePath)) { - $this->symfonyStyle->error('.editorconfig file already exists'); + $this->outputPrinter->error('.editorconfig file already exists'); return ExitCode::ERROR; } FileSystem::copy(__DIR__ . '/../../templates/.editorconfig', $projectEditorconfigFilePath); - $this->symfonyStyle->success('.editorconfig file was created'); + $this->outputPrinter->success('.editorconfig file was created'); return ExitCode::SUCCESS; } diff --git a/src/Command/FinalizeClassesCommand.php b/src/Command/FinalizeClassesCommand.php index 207872273..c19b923c5 100644 --- a/src/Command/FinalizeClassesCommand.php +++ b/src/Command/FinalizeClassesCommand.php @@ -6,6 +6,8 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; +use Entropy\Console\Output\ProgressBar; use Nette\Utils\FileSystem; use Nette\Utils\Strings; use Rector\SwissKnife\Analyzer\NeedsFinalizeAnalyzer; @@ -15,7 +17,6 @@ use Rector\SwissKnife\MockedClassResolver; use Rector\SwissKnife\ParentClassResolver; use Rector\SwissKnife\PhpParser\CachedPhpParser; -use Symfony\Component\Console\Style\SymfonyStyle; final readonly class FinalizeClassesCommand implements CommandInterface { @@ -25,7 +26,8 @@ private const string NEWLINE_CLASS_START_REGEX = '#^(readonly )?class\s#m'; public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, + private ProgressBar $progressBar, private ParentClassResolver $parentClassResolver, private EntityClassResolver $entityClassResolver, private CachedPhpParser $cachedPhpParser, @@ -47,7 +49,7 @@ public function run( array $skipFiles = [], bool $noProgress = false ): int { - $this->symfonyStyle->title('1. Detecting parent and entity classes'); + $this->outputPrinter->title('1. Detecting parent and entity classes'); $phpFileInfos = PhpFilesFinder::find($paths, $skipFiles); @@ -55,7 +57,7 @@ public function run( // double to count for both parent and entity resolver $stepRatio = $skipMocked ? 3 : 2; - $this->symfonyStyle->progressStart($stepRatio * count($phpFileInfos)); + $this->progressBar->start($stepRatio * count($phpFileInfos)); } $progressClosure = function () use ($noProgress): void { @@ -63,7 +65,7 @@ public function run( return; } - $this->symfonyStyle->progressAdvance(); + $this->progressBar->advance(); }; $parentClassNames = $this->parentClassResolver->resolve($phpFileInfos, $progressClosure); @@ -72,22 +74,22 @@ public function run( $mockedClassNames = $skipMocked ? $this->mockedClassResolver->resolve($paths, $progressClosure) : []; if (! $noProgress) { - $this->symfonyStyle->progressFinish(); + $this->progressBar->finish(); } - $this->symfonyStyle->writeln(sprintf( + $this->outputPrinter->writeln(sprintf( 'Found %d parent and %d entity classes', count($parentClassNames), count($entityClassNames) )); if ($skipMocked) { - $this->symfonyStyle->writeln(sprintf('Also %d mocked classes', count($mockedClassNames))); + $this->outputPrinter->writeln(sprintf('Also %d mocked classes', count($mockedClassNames))); } - $this->symfonyStyle->newLine(1); + $this->outputPrinter->newline(1); - $this->symfonyStyle->title('2. Finalizing safe classes'); + $this->outputPrinter->title('2. Finalizing safe classes'); $excludedClasses = array_merge($parentClassNames, $entityClassNames, $mockedClassNames); $needsFinalizeAnalyzer = new NeedsFinalizeAnalyzer($excludedClasses, $this->cachedPhpParser); @@ -114,18 +116,18 @@ public function run( } if ($finalizedFilePaths === []) { - $this->symfonyStyle->success('Nothing to finalize'); + $this->outputPrinter->success('Nothing to finalize'); return ExitCode::SUCCESS; } - $this->symfonyStyle->listing($finalizedFilePaths); + $this->outputPrinter->listing($finalizedFilePaths); $countFinalizedClasses = count($finalizedFilePaths); $pluralClassText = $countFinalizedClasses === 1 ? 'class' : 'classes'; // to make it fail in CI if ($dryRun) { - $this->symfonyStyle->error(sprintf( + $this->outputPrinter->error(sprintf( '%d %s can be finalized', $countFinalizedClasses, $pluralClassText, @@ -134,7 +136,7 @@ public function run( return ExitCode::ERROR; } - $this->symfonyStyle->success(sprintf('%d %s finalized', $countFinalizedClasses, $pluralClassText)); + $this->outputPrinter->success(sprintf('%d %s finalized', $countFinalizedClasses, $pluralClassText)); return ExitCode::SUCCESS; } diff --git a/src/Command/FindMultiClassesCommand.php b/src/Command/FindMultiClassesCommand.php index 3a607b65a..92f71f847 100644 --- a/src/Command/FindMultiClassesCommand.php +++ b/src/Command/FindMultiClassesCommand.php @@ -6,16 +6,16 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Rector\SwissKnife\FileSystem\PathHelper; use Rector\SwissKnife\Finder\MultipleClassInOneFileFinder; use Rector\SwissKnife\Finder\PhpFilesFinder; -use Symfony\Component\Console\Style\SymfonyStyle; final readonly class FindMultiClassesCommand implements CommandInterface { public function __construct( private MultipleClassInOneFileFinder $multipleClassInOneFileFinder, - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -31,7 +31,7 @@ public function run(array $sources, array $excludePaths): int $multipleClassesByFile = $this->multipleClassInOneFileFinder->findInDirectories($sources, $excludePaths); if ($multipleClassesByFile === []) { - $this->symfonyStyle->success(sprintf('No file with 2+ classes found in %d files', count($phpFileInfos))); + $this->outputPrinter->success(sprintf('No file with 2+ classes found in %d files', count($phpFileInfos))); return ExitCode::SUCCESS; } @@ -41,8 +41,8 @@ public function run(array $sources, array $excludePaths): int $relativeFilePath = PathHelper::relativeToCwd($filePath); $message = sprintf('File "%s" contains %d classes', $relativeFilePath, count($classes)); - $this->symfonyStyle->section($message); - $this->symfonyStyle->listing($classes); + $this->outputPrinter->section($message); + $this->outputPrinter->listing($classes); } return ExitCode::ERROR; diff --git a/src/Command/GenerateSymfonyConfigBuildersCommand.php b/src/Command/GenerateSymfonyConfigBuildersCommand.php index 798f6725e..c3eaba102 100644 --- a/src/Command/GenerateSymfonyConfigBuildersCommand.php +++ b/src/Command/GenerateSymfonyConfigBuildersCommand.php @@ -6,12 +6,12 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; -use Symfony\Component\Console\Style\SymfonyStyle; +use Entropy\Console\Output\OutputPrinter; final readonly class GenerateSymfonyConfigBuildersCommand implements CommandInterface { public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -30,7 +30,7 @@ public function getDescription(): string */ public function run(): int { - $this->symfonyStyle->error( + $this->outputPrinter->error( 'This command is deprecated. Symfony 5.3 config builders were deprecated in Symfony 7.4 in favor of the new PHP configuration API. See https://symfony.com/blog/new-in-symfony-7-4-better-php-configuration' ); diff --git a/src/Command/GenerateSymfonySmokeTestsCommand.php b/src/Command/GenerateSymfonySmokeTestsCommand.php index a7c0c85c5..277a245c3 100644 --- a/src/Command/GenerateSymfonySmokeTestsCommand.php +++ b/src/Command/GenerateSymfonySmokeTestsCommand.php @@ -6,13 +6,13 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Nette\Utils\FileSystem; use Nette\Utils\Json; use Rector\SwissKnife\SmokeTestgen\FileSystem\TestsDirectoryResolver; use Rector\SwissKnife\SmokeTestgen\Templating\TemplateDecorator; use Rector\SwissKnife\SmokeTestgen\TestTemplateResolver; use Rector\SwissKnife\SmokeTestgen\Utils\TestPathResolver; -use Symfony\Component\Console\Style\SymfonyStyle; use Webmozart\Assert\Assert; final readonly class GenerateSymfonySmokeTestsCommand implements CommandInterface @@ -21,7 +21,7 @@ public function __construct( private TestsDirectoryResolver $testsDirectoryResolver, private TestTemplateResolver $testTemplateResolver, private TemplateDecorator $templateDecorator, - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -40,24 +40,24 @@ public function getDescription(): string */ public function run(): int { - $this->symfonyStyle->writeln('Resolving directory for smoke tests'); + $this->outputPrinter->writeln('Resolving directory for smoke tests'); $smokeTestsDirectory = $this->testsDirectoryResolver->resolveSmokeUnitTestDirectory(getcwd()); - $this->symfonyStyle->writeln(' * ' . $smokeTestsDirectory); + $this->outputPrinter->writeln(' * ' . $smokeTestsDirectory); $requirePackages = $this->resolveProjectRequiredPackageNames(getcwd()); $testByPackageSubscribers = $this->testTemplateResolver->matchProjectPackages($requirePackages); if ($testByPackageSubscribers === []) { - $this->symfonyStyle->warning( + $this->outputPrinter->warning( 'No test templates found for the required packages. Make sure you project uses Composer to manage version and has Symfony/Doctrine packages listed in "require" section' ); return ExitCode::ERROR; } - $this->symfonyStyle->newLine(); - $this->symfonyStyle->writeln(sprintf( + $this->outputPrinter->newline(); + $this->outputPrinter->writeln(sprintf( 'Found %d smoke test%s that might come handy', count($testByPackageSubscribers), count($testByPackageSubscribers) > 1 ? 's' : '' @@ -69,7 +69,7 @@ public function run(): int $projectTestFilePath = TestPathResolver::resolve($test, $smokeTestsDirectory); if (file_exists($projectTestFilePath)) { - $this->symfonyStyle->writeln( + $this->outputPrinter->writeln( sprintf('File %s already exists, skipping', $projectTestFilePath) ); continue; @@ -80,13 +80,13 @@ public function run(): int FileSystem::write($projectTestFilePath, $templateContents); - $this->symfonyStyle->writeln(sprintf('Generated new test file %s', $projectTestFilePath)); + $this->outputPrinter->writeln(sprintf('Generated new test file %s', $projectTestFilePath)); ++$generatedTestCount; } if ($generatedTestCount === 0) { - $this->symfonyStyle->success('No new test files were generated. All required tests already exist.'); + $this->outputPrinter->success('No new test files were generated. All required tests already exist.'); return ExitCode::SUCCESS; } @@ -101,14 +101,14 @@ public function run(): int FileSystem::write($projectTestCaseFilePath, $templateContents); } - $this->symfonyStyle->success(sprintf( + $this->outputPrinter->success(sprintf( 'Generated %d new test file%s in "%s"', $generatedTestCount, $generatedTestCount > 1 ? 's' : '', $smokeTestsDirectory )); - $this->symfonyStyle->newLine(); + $this->outputPrinter->newline(); return ExitCode::SUCCESS; } diff --git a/src/Command/NamespaceToPSR4Command.php b/src/Command/NamespaceToPSR4Command.php index b36ed03cd..2bf7b5054 100644 --- a/src/Command/NamespaceToPSR4Command.php +++ b/src/Command/NamespaceToPSR4Command.php @@ -6,16 +6,16 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Nette\Utils\FileSystem; use Nette\Utils\Strings; -use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; final readonly class NamespaceToPSR4Command implements CommandInterface { public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -45,7 +45,7 @@ public function run(string $path, string $namespaceRoot): int } // 2. incorrect namespace found - $this->symfonyStyle->note(sprintf( + $this->outputPrinter->writeln(sprintf( 'File "%s"%s fixed to expected namespace "%s"', $fileInfo->getRelativePathname(), PHP_EOL, @@ -66,9 +66,9 @@ public function run(string $path, string $namespaceRoot): int } if ($changedFilesCount === 0) { - $this->symfonyStyle->success(sprintf('All %d files have correct namespace', count($fileInfos))); + $this->outputPrinter->success(sprintf('All %d files have correct namespace', count($fileInfos))); } else { - $this->symfonyStyle->success(sprintf('Fixed %d files', $changedFilesCount)); + $this->outputPrinter->success(sprintf('Fixed %d files', $changedFilesCount)); } return ExitCode::SUCCESS; diff --git a/src/Command/PrettyJsonCommand.php b/src/Command/PrettyJsonCommand.php index 9273af135..1c7a164d7 100644 --- a/src/Command/PrettyJsonCommand.php +++ b/src/Command/PrettyJsonCommand.php @@ -6,16 +6,16 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Nette\Utils\FileSystem; use Nette\Utils\Json; use Rector\SwissKnife\FileSystem\JsonAnalyzer; use Rector\SwissKnife\Finder\FilesFinder; -use Symfony\Component\Console\Style\SymfonyStyle; final readonly class PrettyJsonCommand implements CommandInterface { public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, private JsonAnalyzer $jsonAnalyzer, ) { } @@ -31,12 +31,12 @@ public function run(array $sources, bool $dryRun = false): int $jsonFileInfos = FilesFinder::findJsonFiles($sources); if ($jsonFileInfos === []) { - $this->symfonyStyle->error('No *.json files found'); + $this->outputPrinter->error('No *.json files found'); return ExitCode::ERROR; } $message = sprintf('Analysing %d *.json files', count($jsonFileInfos)); - $this->symfonyStyle->note($message); + $this->outputPrinter->writeln($message); $printedFilePaths = []; @@ -44,7 +44,7 @@ public function run(array $sources, bool $dryRun = false): int foreach ($jsonFileInfos as $jsonFileInfo) { $jsonContent = FileSystem::read($jsonFileInfo->getRealPath()); if ($this->jsonAnalyzer->isPrettyPrinted($jsonContent)) { - $this->symfonyStyle->writeln( + $this->outputPrinter->writeln( sprintf('File "%s" is already pretty', $jsonFileInfo->getRelativePathname()) ); continue; @@ -69,8 +69,8 @@ public function run(array $sources, bool $dryRun = false): int $dryRun ? 'would be changed' : 'changed' ); - $this->symfonyStyle->success($successMessage); - $this->symfonyStyle->listing($printedFilePaths); + $this->outputPrinter->success($successMessage); + $this->outputPrinter->listing($printedFilePaths); return ExitCode::SUCCESS; } diff --git a/src/Command/PrivatizeConstantsCommand.php b/src/Command/PrivatizeConstantsCommand.php index 2aed1bd73..60c41f8e6 100644 --- a/src/Command/PrivatizeConstantsCommand.php +++ b/src/Command/PrivatizeConstantsCommand.php @@ -6,6 +6,8 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; +use Entropy\Console\Output\ProgressBar; use Nette\Utils\FileSystem; use Nette\Utils\Strings; use Rector\SwissKnife\Contract\ClassConstantFetchInterface; @@ -17,13 +19,13 @@ use Rector\SwissKnife\ValueObject\ClassConstantFetch\CurrentClassConstantFetch; use Rector\SwissKnife\ValueObject\VisibilityChangeStats; use Rector\SwissKnife\YAML\YamlConfigConstantExtractor; -use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Finder\SplFileInfo; final readonly class PrivatizeConstantsCommand implements CommandInterface { public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, + private ProgressBar $progressBar, private ClassConstantFetchFinder $classConstantFetchFinder, private ClassConstFinder $classConstFinder, private TwigTemplateConstantExtractor $twigTemplateConstantExtractor, @@ -56,15 +58,15 @@ public function run( ): int { $phpFileInfos = PhpFilesFinder::find($sources, $excludedPaths); if ($phpFileInfos === []) { - $this->symfonyStyle->warning('No PHP files found in provided paths'); + $this->outputPrinter->warning('No PHP files found in provided paths'); return ExitCode::SUCCESS; } - $this->symfonyStyle->title('Finding class const fetches...'); + $this->outputPrinter->title('Finding class const fetches...'); - $progressBar = $this->symfonyStyle->createProgressBar(count($phpFileInfos)); - $phpClassConstantFetches = $this->classConstantFetchFinder->find($phpFileInfos, $progressBar, $isDebug); + $this->progressBar->start(count($phpFileInfos)); + $phpClassConstantFetches = $this->classConstantFetchFinder->find($phpFileInfos, $this->progressBar, $isDebug); // find usage in twig files $twigClassConstantFetches = $this->twigTemplateConstantExtractor->extractFromDirs($sources); @@ -76,14 +78,16 @@ public function run( $yamlClassConstantFetches ); - $this->symfonyStyle->newLine(2); - $this->symfonyStyle->success(sprintf('Found %d class constant fetches', count($classConstantFetches))); - $this->symfonyStyle->success(sprintf('Found %d constants in Twig templates', count($twigClassConstantFetches))); - $this->symfonyStyle->success(sprintf('Found %d constants in YAML configs', count($yamlClassConstantFetches))); + $this->outputPrinter->newline(2); + $this->outputPrinter->success(sprintf('Found %d class constant fetches', count($classConstantFetches))); + $this->outputPrinter->success( + sprintf('Found %d constants in Twig templates', count($twigClassConstantFetches)) + ); + $this->outputPrinter->success(sprintf('Found %d constants in YAML configs', count($yamlClassConstantFetches))); - $this->symfonyStyle->newLine(2); + $this->outputPrinter->newline(2); - $this->symfonyStyle->title('Changing class constant visibility based on use...'); + $this->outputPrinter->title('Changing class constant visibility based on use...'); $visibilityChangeStats = new VisibilityChangeStats(); @@ -94,23 +98,23 @@ public function run( } if (! $visibilityChangeStats->hasAnyChange()) { - $this->symfonyStyle->warning('No constants were privatized'); + $this->outputPrinter->warning('No constants were privatized'); return ExitCode::SUCCESS; } - $this->symfonyStyle->newLine(2); + $this->outputPrinter->newline(2); // to make it fail in CI if ($dryRun) { - $this->symfonyStyle->error( + $this->outputPrinter->error( sprintf('%d constants can be privatized', $visibilityChangeStats->getPrivateCount()) ); return ExitCode::ERROR; } - $this->symfonyStyle->success( + $this->outputPrinter->success( sprintf('Totally %d constants were made private', $visibilityChangeStats->getPrivateCount()) ); @@ -141,7 +145,7 @@ private function processFileInfo( $visibilityChangeStats->countPrivate(); if ($dryRun) { - $this->symfonyStyle->writeln( + $this->outputPrinter->writeln( sprintf('Constant "%s" could be changed to private', $classConstant->getConstantName()) ); continue; @@ -155,7 +159,7 @@ private function processFileInfo( ); FileSystem::write($phpFileInfo->getRealPath(), $changedFileContents, null); - $this->symfonyStyle->writeln( + $this->outputPrinter->writeln( sprintf('Constant "%s" changed to private', $classConstant->getConstantName()) ); } diff --git a/src/Command/SearchRegexCommand.php b/src/Command/SearchRegexCommand.php index f31017867..d3ccd6c23 100644 --- a/src/Command/SearchRegexCommand.php +++ b/src/Command/SearchRegexCommand.php @@ -6,15 +6,17 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; +use Entropy\Console\Output\ProgressBar; use Nette\Utils\Strings; use Rector\SwissKnife\Finder\PhpFilesFinder; -use Symfony\Component\Console\Style\SymfonyStyle; use Webmozart\Assert\Assert; final readonly class SearchRegexCommand implements CommandInterface { public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, + private ProgressBar $progressBar, ) { } @@ -35,15 +37,15 @@ public function run(string $regex, ?string $projectDirectory = null): int $phpFileInfos = PhpFilesFinder::find([$projectDirectory]); $message = sprintf('Going through %d *.php files', count($phpFileInfos)); - $this->symfonyStyle->writeln($message); + $this->outputPrinter->writeln($message); - $this->symfonyStyle->writeln('Searching for regex: ' . $regex); - $this->symfonyStyle->newLine(); + $this->outputPrinter->writeln('Searching for regex: ' . $regex); + $this->outputPrinter->newline(); $foundCasesCount = 0; $markedFiles = []; - $progressBar = $this->symfonyStyle->createProgressBar(count($phpFileInfos)); + $this->progressBar->start(count($phpFileInfos)); foreach ($phpFileInfos as $phpFileInfo) { $matches = Strings::matchAll($phpFileInfo->getContents(), $regex); @@ -55,19 +57,19 @@ public function run(string $regex, ?string $projectDirectory = null): int $foundCasesCount += $currentMatchesCount; $markedFiles[$phpFileInfo->getRelativePathname()] = $currentMatchesCount; - $progressBar->advance(); + $this->progressBar->advance(); } - $progressBar->finish(); - $this->symfonyStyle->newLine(2); + $this->progressBar->finish(); + $this->outputPrinter->newline(2); ksort($markedFiles); foreach ($markedFiles as $filePath => $count) { - $this->symfonyStyle->writeln(sprintf(' * %s: %d', $filePath, $count)); + $this->outputPrinter->writeln(sprintf(' * %s: %d', $filePath, $count)); } - $this->symfonyStyle->newLine(2); - $this->symfonyStyle->success(sprintf('Found %d cases in %d files', $foundCasesCount, count($markedFiles))); + $this->outputPrinter->newline(2); + $this->outputPrinter->success(sprintf('Found %d cases in %d files', $foundCasesCount, count($markedFiles))); return ExitCode::SUCCESS; } diff --git a/src/Command/SplitSymfonyConfigToPerPackageCommand.php b/src/Command/SplitSymfonyConfigToPerPackageCommand.php index ac8da390d..46266036f 100644 --- a/src/Command/SplitSymfonyConfigToPerPackageCommand.php +++ b/src/Command/SplitSymfonyConfigToPerPackageCommand.php @@ -6,6 +6,7 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Nette\Utils\FileSystem; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Scalar\String_; @@ -18,7 +19,6 @@ use Rector\SwissKnife\PhpParser\NodeFactory\SplitConfigClosureFactory; use Rector\SwissKnife\PhpParser\NodeVisitor\AddImportConfigMethodCallNodeVisitor; use Rector\SwissKnife\PhpParser\NodeVisitor\ExtractSymfonyExtensionCallNodeVisitor; -use Symfony\Component\Console\Style\SymfonyStyle; use Webmozart\Assert\Assert; final readonly class SplitSymfonyConfigToPerPackageCommand implements CommandInterface @@ -26,7 +26,7 @@ private Standard $printerStandard; public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, private SplitConfigClosureFactory $splitConfigClosureFactory, ) { $this->printerStandard = new Standard(); @@ -48,7 +48,7 @@ public function run(string $configPath, string $outputDir): int $symfonyExtensionMethodCalls = $this->extractSymfonyExtensionMethodCalls($stmts); if ($symfonyExtensionMethodCalls === []) { - $this->symfonyStyle->warning('No extension() method calls found'); + $this->outputPrinter->warning('No extension() method calls found'); return ExitCode::SUCCESS; } diff --git a/src/Command/SpotLazyTraitsCommand.php b/src/Command/SpotLazyTraitsCommand.php index b404fccbe..de8c229a6 100644 --- a/src/Command/SpotLazyTraitsCommand.php +++ b/src/Command/SpotLazyTraitsCommand.php @@ -6,13 +6,13 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Rector\SwissKnife\Traits\TraitSpotter; -use Symfony\Component\Console\Style\SymfonyStyle; final readonly class SpotLazyTraitsCommand implements CommandInterface { public function __construct( - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, private TraitSpotter $traitSpotter, ) { } @@ -24,32 +24,32 @@ public function __construct( */ public function run(array $sources, int $maxUsed = 2): int { - $this->symfonyStyle->title('Looking for trait definitions'); + $this->outputPrinter->title('Looking for trait definitions'); $traitSpottingResult = $this->traitSpotter->analyse($sources); if ($traitSpottingResult->getTraitCount() === 0) { - $this->symfonyStyle->success('No traits were found in your project, nothing to worry about'); + $this->outputPrinter->success('No traits were found in your project, nothing to worry about'); return ExitCode::SUCCESS; } - $this->symfonyStyle->writeln( + $this->outputPrinter->writeln( sprintf( 'Found %d trait%s in the whole project', $traitSpottingResult->getTraitCount(), $traitSpottingResult->getTraitCount() === 1 ? '' : 's' ) ); - $this->symfonyStyle->listing($traitSpottingResult->getTraitFilePaths()); + $this->outputPrinter->listing($traitSpottingResult->getTraitFilePaths()); - $this->symfonyStyle->newLine(); + $this->outputPrinter->newline(); - $this->symfonyStyle->title(sprintf('Looking for traits used less than %d-times', $maxUsed)); + $this->outputPrinter->title(sprintf('Looking for traits used less than %d-times', $maxUsed)); $leastUsedTraitsMetadatas = $traitSpottingResult->getTraitMaximumUsedTimes($maxUsed); foreach ($leastUsedTraitsMetadatas as $leastUsedTraitMetadata) { - $this->symfonyStyle->writeln(sprintf( + $this->outputPrinter->writeln(sprintf( 'Trait "%s" (%d lines) is used only in %d file%s', $leastUsedTraitMetadata->getShortTraitName(), $leastUsedTraitMetadata->getLineCount(), @@ -57,11 +57,11 @@ public function run(array $sources, int $maxUsed = 2): int $leastUsedTraitMetadata->getUsedInCount() === 1 ? '' : 's' )); - $this->symfonyStyle->listing($leastUsedTraitMetadata->getUsedIn()); - $this->symfonyStyle->newLine(); + $this->outputPrinter->listing($leastUsedTraitMetadata->getUsedIn()); + $this->outputPrinter->newline(); } - $this->symfonyStyle->warning(sprintf( + $this->outputPrinter->warning(sprintf( 'Inline these traits or refactor them to a service if meaningful.%sChange "--max-used" to different number to get more result', PHP_EOL )); diff --git a/src/DependencyInjection/ContainerFactory.php b/src/DependencyInjection/ContainerFactory.php index b7088c67b..af962ab76 100644 --- a/src/DependencyInjection/ContainerFactory.php +++ b/src/DependencyInjection/ContainerFactory.php @@ -7,9 +7,6 @@ use Entropy\Container\Container; use PhpParser\Parser; use PhpParser\ParserFactory; -use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Output\ConsoleOutput; -use Symfony\Component\Console\Style\SymfonyStyle; /** * @api used in tests @@ -27,11 +24,6 @@ public function create(): Container return $phpParserFactory->createForNewestSupportedVersion(); }); - $container->service( - SymfonyStyle::class, - static fn (): SymfonyStyle => new SymfonyStyle(new ArrayInput([]), new ConsoleOutput()) - ); - return $container; } } diff --git a/src/PhpParser/Finder/ClassConstantFetchFinder.php b/src/PhpParser/Finder/ClassConstantFetchFinder.php index d7213f91b..f19d5d78a 100644 --- a/src/PhpParser/Finder/ClassConstantFetchFinder.php +++ b/src/PhpParser/Finder/ClassConstantFetchFinder.php @@ -4,14 +4,14 @@ namespace Rector\SwissKnife\PhpParser\Finder; +use Entropy\Console\Output\OutputPrinter; +use Entropy\Console\Output\ProgressBar; use Rector\SwissKnife\Contract\ClassConstantFetchInterface; use Rector\SwissKnife\Exception\NotImplementedYetException; use Rector\SwissKnife\Exception\ShouldNotHappenException; use Rector\SwissKnife\PhpParser\CachedPhpParser; use Rector\SwissKnife\PhpParser\NodeTraverserFactory; use Rector\SwissKnife\PhpParser\NodeVisitor\FindClassConstFetchNodeVisitor; -use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Finder\SplFileInfo; /** @@ -21,7 +21,7 @@ { public function __construct( private CachedPhpParser $cachedPhpParser, - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, ) { } @@ -36,7 +36,7 @@ public function find(array $phpFileInfos, ProgressBar $progressBar, bool $isDebu foreach ($phpFileInfos as $phpFileInfo) { if ($isDebug) { - $this->symfonyStyle->writeln('Processing ' . $phpFileInfo->getRealPath()); + $this->outputPrinter->writeln('Processing ' . $phpFileInfo->getRealPath()); } $fileStmts = $this->cachedPhpParser->parseFile($phpFileInfo->getRealPath()); @@ -46,7 +46,7 @@ public function find(array $phpFileInfos, ProgressBar $progressBar, bool $isDebu } catch (ShouldNotHappenException|NotImplementedYetException $exception) { // render debug contents if verbose if ($isDebug) { - $this->symfonyStyle->error($exception->getMessage()); + $this->outputPrinter->error($exception->getMessage()); } } diff --git a/src/Testing/Command/DetectUnitTestsCommand.php b/src/Testing/Command/DetectUnitTestsCommand.php index 7868f6c31..835b702a8 100644 --- a/src/Testing/Command/DetectUnitTestsCommand.php +++ b/src/Testing/Command/DetectUnitTestsCommand.php @@ -6,10 +6,10 @@ use Entropy\Console\Contract\CommandInterface; use Entropy\Console\Enum\ExitCode; +use Entropy\Console\Output\OutputPrinter; use Nette\Utils\FileSystem; use Rector\SwissKnife\Testing\Printer\PHPUnitXmlPrinter; use Rector\SwissKnife\Testing\UnitTestFilePathsFinder; -use Symfony\Component\Console\Style\SymfonyStyle; use Webmozart\Assert\Assert; final readonly class DetectUnitTestsCommand implements CommandInterface @@ -18,7 +18,7 @@ public function __construct( private PHPUnitXmlPrinter $phpunitXmlPrinter, - private SymfonyStyle $symfonyStyle, + private OutputPrinter $outputPrinter, private UnitTestFilePathsFinder $unitTestFilePathsFinder, ) { } @@ -33,7 +33,7 @@ public function run(array $sources): int $unitTestCasesClassesToFilePaths = $this->unitTestFilePathsFinder->findInDirectories($sources); if ($unitTestCasesClassesToFilePaths === []) { - $this->symfonyStyle->note('No unit tests found in provided paths'); + $this->outputPrinter->writeln('No unit tests found in provided paths'); return ExitCode::SUCCESS; } @@ -48,7 +48,7 @@ public function run(array $sources): int self::OUTPUT_FILENAME, ); - $this->symfonyStyle->success($successMessage); + $this->outputPrinter->success($successMessage); return ExitCode::SUCCESS; } diff --git a/tests/PhpParser/Finder/ClassConstantFetchFinder/ClassConstantFetchFinderTest.php b/tests/PhpParser/Finder/ClassConstantFetchFinder/ClassConstantFetchFinderTest.php index c4ad59e63..f2e8a2de7 100644 --- a/tests/PhpParser/Finder/ClassConstantFetchFinder/ClassConstantFetchFinderTest.php +++ b/tests/PhpParser/Finder/ClassConstantFetchFinder/ClassConstantFetchFinderTest.php @@ -4,6 +4,8 @@ namespace Rector\SwissKnife\Tests\PhpParser\Finder\ClassConstantFetchFinder; +use Entropy\Console\Output\OutputColorizer; +use Entropy\Console\Output\ProgressBar; use Override; use Rector\SwissKnife\Contract\ClassConstantFetchInterface; use Rector\SwissKnife\Finder\PhpFilesFinder; @@ -12,8 +14,6 @@ use Rector\SwissKnife\ValueObject\ClassConstantFetch\CurrentClassConstantFetch; use Rector\SwissKnife\ValueObject\ClassConstantFetch\ExternalClassAccessConstantFetch; use RuntimeException; -use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Output\NullOutput; final class ClassConstantFetchFinderTest extends AbstractTestCase { @@ -53,7 +53,7 @@ public function testParseError(): void ); $directory = __DIR__ . '/Fixture/Error'; - $progressBar = new ProgressBar(new NullOutput()); + $progressBar = new ProgressBar(new OutputColorizer()); $fileInfos = PhpFilesFinder::find([$directory]); $this->classConstantFetchFinder->find($fileInfos, $progressBar, false); } @@ -63,7 +63,7 @@ public function testParseError(): void */ private function findInDirectory(string $directory): array { - $progressBar = new ProgressBar(new NullOutput()); + $progressBar = new ProgressBar(new OutputColorizer()); $fileInfos = PhpFilesFinder::find([$directory]); return $this->classConstantFetchFinder->find($fileInfos, $progressBar, false);