2019-10-13 05:59:52 +00:00
< ? php
2021-05-09 20:15:43 +00:00
declare ( strict_types = 1 );
2022-06-06 17:12:56 +00:00
namespace Rector\ChangesReporting\Output ;
2017-10-22 14:31:29 +00:00
2023-02-02 09:24:12 +00:00
use RectorPrefix202302\Nette\Utils\Strings ;
2022-06-06 17:12:56 +00:00
use Rector\ChangesReporting\Annotation\RectorsChangelogResolver ;
use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface ;
use Rector\Core\Contract\Console\OutputStyleInterface ;
use Rector\Core\ValueObject\Configuration ;
use Rector\Core\ValueObject\Error\SystemError ;
use Rector\Core\ValueObject\ProcessResult ;
use Rector\Core\ValueObject\Reporting\FileDiff ;
2022-06-07 08:22:29 +00:00
final class ConsoleOutputFormatter implements OutputFormatterInterface
2017-10-22 14:31:29 +00:00
{
2019-05-25 16:36:53 +00:00
/**
* @ var string
*/
public const NAME = 'console' ;
2020-09-23 09:16:40 +00:00
/**
* @ var string
2020-10-29 18:04:33 +00:00
* @ see https :// regex101 . com / r / q8I66g / 1
2020-09-23 09:16:40 +00:00
*/
private const ON_LINE_REGEX = '# on line #' ;
2019-08-10 07:28:27 +00:00
/**
2021-12-04 12:47:17 +00:00
* @ readonly
2021-05-10 23:39:21 +00:00
* @ var \Rector\Core\Contract\Console\OutputStyleInterface
2019-08-10 07:28:27 +00:00
*/
2022-02-11 12:13:24 +00:00
private $rectorOutputStyle ;
2021-04-10 14:54:24 +00:00
/**
2021-12-04 12:47:17 +00:00
* @ readonly
2021-05-10 23:39:21 +00:00
* @ var \Rector\ChangesReporting\Annotation\RectorsChangelogResolver
2021-04-10 14:54:24 +00:00
*/
2021-04-10 16:22:25 +00:00
private $rectorsChangelogResolver ;
2022-06-07 08:22:29 +00:00
public function __construct ( OutputStyleInterface $rectorOutputStyle , RectorsChangelogResolver $rectorsChangelogResolver )
2021-05-09 20:15:43 +00:00
{
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle = $rectorOutputStyle ;
2021-04-10 16:22:25 +00:00
$this -> rectorsChangelogResolver = $rectorsChangelogResolver ;
2017-10-22 14:31:29 +00:00
}
2022-06-07 08:22:29 +00:00
public function report ( ProcessResult $processResult , Configuration $configuration ) : void
2019-05-28 14:28:46 +00:00
{
2021-06-22 19:34:44 +00:00
if ( $configuration -> shouldShowDiffs ()) {
2021-04-12 10:34:04 +00:00
$this -> reportFileDiffs ( $processResult -> getFileDiffs ());
2021-01-29 20:12:09 +00:00
}
2021-04-12 10:34:04 +00:00
$this -> reportErrors ( $processResult -> getErrors ());
$this -> reportRemovedFilesAndNodes ( $processResult );
if ( $processResult -> getErrors () !== []) {
2019-05-28 14:47:55 +00:00
return ;
}
2021-12-28 12:08:43 +00:00
// to keep space between progress bar and success message
if ( $configuration -> shouldShowProgressBar () && $processResult -> getFileDiffs () === []) {
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> newLine ();
2021-12-28 12:08:43 +00:00
}
2021-06-22 19:34:44 +00:00
$message = $this -> createSuccessMessage ( $processResult , $configuration );
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> success ( $message );
2019-05-28 14:28:46 +00:00
}
2021-05-09 20:15:43 +00:00
public function getName () : string
2019-05-25 16:36:53 +00:00
{
return self :: NAME ;
}
2018-01-02 06:03:11 +00:00
/**
2018-02-08 15:51:16 +00:00
* @ param FileDiff [] $fileDiffs
2018-01-02 06:03:11 +00:00
*/
2021-07-05 23:06:30 +00:00
private function reportFileDiffs ( array $fileDiffs ) : void
2018-01-02 06:03:11 +00:00
{
2021-05-09 20:15:43 +00:00
if ( \count ( $fileDiffs ) <= 0 ) {
2018-01-06 23:09:22 +00:00
return ;
}
2018-12-07 17:54:24 +00:00
// normalize
2021-05-09 20:15:43 +00:00
\ksort ( $fileDiffs );
$message = \sprintf ( '%d file%s with changes' , \count ( $fileDiffs ), \count ( $fileDiffs ) === 1 ? '' : 's' );
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> title ( $message );
2018-01-06 20:10:35 +00:00
$i = 0 ;
2018-02-08 15:51:16 +00:00
foreach ( $fileDiffs as $fileDiff ) {
2019-05-28 20:38:21 +00:00
$relativeFilePath = $fileDiff -> getRelativeFilePath ();
2021-08-26 12:11:00 +00:00
// append line number for faster file jump in diff
$firstLineNumber = $fileDiff -> getFirstLineNumber ();
if ( $firstLineNumber !== null ) {
$relativeFilePath .= ':' . $firstLineNumber ;
}
2021-05-09 20:15:43 +00:00
$message = \sprintf ( '<options=bold>%d) %s</>' , ++ $i , $relativeFilePath );
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> writeln ( $message );
$this -> rectorOutputStyle -> newLine ();
$this -> rectorOutputStyle -> writeln ( $fileDiff -> getDiffConsoleFormatted ());
2021-04-10 16:22:25 +00:00
$rectorsChangelogsLines = $this -> createRectorChangelogLines ( $fileDiff );
2020-03-19 00:07:07 +00:00
if ( $fileDiff -> getRectorChanges () !== []) {
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> writeln ( '<options=underscore>Applied rules:</>' );
$this -> rectorOutputStyle -> listing ( $rectorsChangelogsLines );
$this -> rectorOutputStyle -> newLine ();
2018-11-05 01:27:48 +00:00
}
2018-01-02 06:03:11 +00:00
}
}
2018-09-17 10:38:11 +00:00
/**
2021-12-04 19:10:58 +00:00
* @ param SystemError [] $errors
2018-09-17 10:38:11 +00:00
*/
2021-07-05 23:06:30 +00:00
private function reportErrors ( array $errors ) : void
2018-09-17 10:38:11 +00:00
{
foreach ( $errors as $error ) {
2020-08-11 10:59:04 +00:00
$errorMessage = $error -> getMessage ();
$errorMessage = $this -> normalizePathsToRelativeWithLine ( $errorMessage );
2022-01-04 14:11:25 +00:00
$message = \sprintf ( 'Could not process %s%s, due to: %s"%s".' , $error -> getFile () !== null ? '"' . $error -> getFile () . '" file' : 'some files' , $error -> getRectorClass () !== null ? ' by "' . $error -> getRectorClass () . '"' : '' , \PHP_EOL , $errorMessage );
2021-11-28 19:07:44 +00:00
if ( $error -> getLine () !== null ) {
2018-09-17 10:38:11 +00:00
$message .= ' On line: ' . $error -> getLine ();
}
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> error ( $message );
2018-09-17 10:38:11 +00:00
}
}
2022-06-07 08:22:29 +00:00
private function reportRemovedFilesAndNodes ( ProcessResult $processResult ) : void
2019-08-06 07:37:31 +00:00
{
2021-04-12 10:34:04 +00:00
if ( $processResult -> getAddedFilesCount () !== 0 ) {
2021-05-09 20:15:43 +00:00
$message = \sprintf ( '%d files were added' , $processResult -> getAddedFilesCount ());
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> note ( $message );
2020-10-31 12:59:40 +00:00
}
2021-04-12 10:34:04 +00:00
if ( $processResult -> getRemovedFilesCount () !== 0 ) {
2021-05-09 20:15:43 +00:00
$message = \sprintf ( '%d files were removed' , $processResult -> getRemovedFilesCount ());
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> note ( $message );
2019-08-06 07:37:31 +00:00
}
2021-04-12 10:34:04 +00:00
$this -> reportRemovedNodes ( $processResult );
2019-08-10 07:28:27 +00:00
}
2021-07-05 23:06:30 +00:00
private function normalizePathsToRelativeWithLine ( string $errorMessage ) : string
2020-08-11 10:59:04 +00:00
{
2021-05-09 20:15:43 +00:00
$regex = '#' . \preg_quote ( \getcwd (), '#' ) . '/#' ;
2023-01-10 11:07:38 +00:00
$errorMessage = Strings :: replace ( $errorMessage , $regex );
return Strings :: replace ( $errorMessage , self :: ON_LINE_REGEX );
2020-08-11 10:59:04 +00:00
}
2022-06-07 08:22:29 +00:00
private function reportRemovedNodes ( ProcessResult $processResult ) : void
2019-08-10 07:28:27 +00:00
{
2021-04-12 10:34:04 +00:00
if ( $processResult -> getRemovedNodeCount () === 0 ) {
2019-08-10 07:28:27 +00:00
return ;
}
2021-05-09 20:15:43 +00:00
$message = \sprintf ( '%d nodes were removed' , $processResult -> getRemovedNodeCount ());
2022-02-11 12:13:24 +00:00
$this -> rectorOutputStyle -> warning ( $message );
2019-08-10 07:28:27 +00:00
}
2022-06-07 08:22:29 +00:00
private function createSuccessMessage ( ProcessResult $processResult , Configuration $configuration ) : string
2021-01-29 20:12:09 +00:00
{
2021-05-09 20:15:43 +00:00
$changeCount = \count ( $processResult -> getFileDiffs ()) + $processResult -> getRemovedAndAddedFilesCount ();
2021-01-29 20:12:09 +00:00
if ( $changeCount === 0 ) {
return 'Rector is done!' ;
}
2021-06-22 19:34:44 +00:00
return \sprintf ( '%d file%s %s by Rector' , $changeCount , $changeCount > 1 ? 's' : '' , $configuration -> isDryRun () ? 'would have changed (dry-run)' : ( $changeCount === 1 ? 'has' : 'have' ) . ' been changed' );
2021-01-29 20:12:09 +00:00
}
2021-04-10 16:22:25 +00:00
/**
* @ return string []
*/
2022-06-07 08:22:29 +00:00
private function createRectorChangelogLines ( FileDiff $fileDiff ) : array
2021-04-10 16:22:25 +00:00
{
$rectorsChangelogs = $this -> rectorsChangelogResolver -> resolveIncludingMissing ( $fileDiff -> getRectorClasses ());
$rectorsChangelogsLines = [];
foreach ( $rectorsChangelogs as $rectorClass => $changelog ) {
2022-06-07 08:22:29 +00:00
$rectorShortClass = ( string ) Strings :: after ( $rectorClass , '\\' , - 1 );
2021-04-12 19:16:36 +00:00
$rectorsChangelogsLines [] = $changelog === null ? $rectorShortClass : $rectorShortClass . ' (' . $changelog . ')' ;
2021-04-10 16:22:25 +00:00
}
return $rectorsChangelogsLines ;
}
2017-10-22 14:31:29 +00:00
}