Skip to content

Commit

Permalink
refact(core): Refactor FriendlyErrorFormatter for improved structure …
Browse files Browse the repository at this point in the history
…and separation of concerns
  • Loading branch information
yamadashy committed Sep 23, 2024
1 parent ab5c0ed commit 933ef9d
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 130 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ jobs:
- name: Run static analysis
run: composer run analyze

typos:
name: "Check for typos"
runs-on: "ubuntu-latest"

steps:
- name: "Checkout"
uses: actions/checkout@v4

- name: "Check for typos"
uses: "crate-ci/typos@v1.24.5"

unit_tests:
name: 'Unit Test ${{ matrix.php-version }}, ${{ matrix.dependency-version }}'
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/.idea/
/.vscode/
composer.lock
.phpunit.cache
.phpunit.result.cache
.php-cs-fixer.cache
repopack-output.xml
Expand Down
5 changes: 5 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[files]
extend-exclude = [
".git/",
]
ignore-hidden = false
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
<?php declare(strict_types=1);

namespace Yamadashy\PhpStanFriendlyFormatter;
namespace Yamadashy\PhpStanFriendlyFormatter\CodeHighlight;

use JakubOnderka\PhpConsoleColor\ConsoleColor as OldConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter as OldHighlighter;
use JakubOnderka\PhpConsoleColor\ConsoleColor as LegacyConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter as LegacyHighlighter;
use PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor;
use PHP_Parallel_Lint\PhpConsoleHighlighter\Highlighter;

class CodeHighlighter
{
/** @var FallbackHighlighter|Highlighter|OldHighlighter */
/**
* @var FallbackHighlighter|Highlighter|LegacyHighlighter
*
* @phpstan-ignore class.notFound
*/
private $highlighter;

public function __construct()
Expand All @@ -26,8 +30,8 @@ class_exists('\JakubOnderka\PhpConsoleHighlighter\Highlighter')
&& class_exists('\JakubOnderka\PhpConsoleColor\ConsoleColor')
) {
// Support Highlighter and ConsoleColor < 1.0.
$colors = new OldConsoleColor();
$this->highlighter = new OldHighlighter($colors);
$colors = new LegacyConsoleColor();
$this->highlighter = new LegacyHighlighter($colors);
} else {
// Fallback to non-highlighted output
$this->highlighter = new FallbackHighlighter();
Expand All @@ -36,6 +40,7 @@ class_exists('\JakubOnderka\PhpConsoleHighlighter\Highlighter')

public function highlight(string $fileContent, int $lineNumber, int $lineBefore, int $lineAfter): string
{
/** @phpstan-ignore class.notFound */
$content = $this->highlighter->getCodeSnippet(
$fileContent,
$lineNumber,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php declare(strict_types=1);

namespace Yamadashy\PhpStanFriendlyFormatter;

use PHP_Parallel_Lint\PhpConsoleHighlighter\Highlighter;
namespace Yamadashy\PhpStanFriendlyFormatter\CodeHighlight;

/**
* @see Highlighter
Expand Down
25 changes: 25 additions & 0 deletions src/Config/FriendlyFormatterConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types=1);

namespace Yamadashy\PhpStanFriendlyFormatter\Config;

class FriendlyFormatterConfig
{
/** @var int */
public $lineBefore;

/** @var int */
public $lineAfter;

/** @var null|string */
public $editorUrl;

public function __construct(
int $lineBefore,
int $lineAfter,
?string $editorUrl
) {
$this->lineBefore = $lineBefore;
$this->lineAfter = $lineAfter;
$this->editorUrl = $editorUrl;
}
}
110 changes: 110 additions & 0 deletions src/ErrorFormat/ErrorWriter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php declare(strict_types=1);

namespace Yamadashy\PhpStanFriendlyFormatter\ErrorFormat;

use PHPStan\Analyser\Error;
use PHPStan\Command\AnalysisResult;
use PHPStan\Command\Output;
use PHPStan\File\RelativePathHelper;
use Yamadashy\PhpStanFriendlyFormatter\CodeHighlight\CodeHighlighter;
use Yamadashy\PhpStanFriendlyFormatter\Config\FriendlyFormatterConfig;

class ErrorWriter
{
/** @var RelativePathHelper */
private $relativePathHelper;

/** @var FriendlyFormatterConfig */
private $config;

public function __construct(
RelativePathHelper $relativePathHelper,
FriendlyFormatterConfig $config
) {
$this->relativePathHelper = $relativePathHelper;
$this->config = $config;
}

public function writeFileSpecificErrors(AnalysisResult $analysisResult, Output $output): void
{
$codeHighlighter = new CodeHighlighter();
$errorsByFile = [];

foreach ($analysisResult->getFileSpecificErrors() as $error) {
$filePath = $error->getTraitFilePath() ?? $error->getFilePath();
$relativeFilePath = $this->relativePathHelper->getRelativePath($filePath);
$errorsByFile[$relativeFilePath][] = $error;
}

foreach ($errorsByFile as $relativeFilePath => $errors) {
$output->writeLineFormatted("❯ {$relativeFilePath}");
$output->writeLineFormatted('--'.str_repeat('-', mb_strlen($relativeFilePath)));
$output->writeLineFormatted('');

foreach ($errors as $error) {
$message = $error->getMessage();
$tip = $this->getFormattedTip($error);
$errorIdentifier = $error->getIdentifier();
$filePath = $error->getTraitFilePath() ?? $error->getFilePath();
$line = $error->getLine();
$fileContent = null;

if (file_exists($filePath)) {
$fileContent = (string) file_get_contents($filePath);
}

if (null === $fileContent) {
$codeSnippet = ' <fg=#888><no such file></>';
} elseif (null === $line) {
$codeSnippet = ' <fg=#888><unknown file line></>';
} else {
$codeSnippet = $codeHighlighter->highlight($fileContent, $line, $this->config->lineBefore, $this->config->lineAfter);
}

$output->writeLineFormatted(" <fg=red;options=bold>✘</> <fg=default;options=bold>{$message}</>");

if (null !== $tip) {
$output->writeLineFormatted(" <fg=default>πŸ’‘ {$tip}</>");
}

if (null !== $errorIdentifier) {
$output->writeLineFormatted(" <fg=default>πŸͺͺ {$errorIdentifier}</>");
}

if (\is_string($this->config->editorUrl)) {
$output->writeLineFormatted(' ✏️ '.str_replace(['%file%', '%line%'], [$error->getTraitFilePath() ?? $error->getFilePath(), (string) $error->getLine()], $this->config->editorUrl));
}

$output->writeLineFormatted($codeSnippet);
$output->writeLineFormatted('');
}
}
}

public function writeNotFileSpecificErrors(AnalysisResult $analysisResult, Output $output): void
{
foreach ($analysisResult->getNotFileSpecificErrors() as $notFileSpecificError) {
$output->writeLineFormatted(" <fg=red;options=bold>✘</> <fg=default;options=bold>{$notFileSpecificError}</>");
$output->writeLineFormatted('');
}
}

public function writeWarnings(AnalysisResult $analysisResult, Output $output): void
{
foreach ($analysisResult->getWarnings() as $warning) {
$output->writeLineFormatted(" <fg=yellow;options=bold>⚠</> <fg=default;options=bold>{$warning}</>");
$output->writeLineFormatted('');
}
}

private function getFormattedTip(Error $error): ?string
{
$tip = $error->getTip();

if (null === $tip) {
return null;
}

return implode("\n ", explode("\n", $tip));
}
}
32 changes: 32 additions & 0 deletions src/ErrorFormat/SummaryWriter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);

namespace Yamadashy\PhpStanFriendlyFormatter\ErrorFormat;

use PHPStan\Command\AnalysisResult;
use PHPStan\Command\Output;

class SummaryWriter
{
public function writeGroupedErrorsSummary(AnalysisResult $analysisResult, Output $output): void
{
/** @var array<string, int> $errorCounter */
$errorCounter = [];

foreach ($analysisResult->getFileSpecificErrors() as $error) {
$identifier = $error->getIdentifier() ?? '<no-identifier>';
if (!\array_key_exists($identifier, $errorCounter)) {
$errorCounter[$identifier] = 0;
}
++$errorCounter[$identifier];
}

arsort($errorCounter);

$output->writeLineFormatted('πŸ“Š Error Identifier Summary:');
$output->writeLineFormatted('────────────────────────────');

foreach ($errorCounter as $identifier => $count) {
$output->writeLineFormatted(\sprintf(' %d %s', $count, $identifier));
}
}
}
Loading

0 comments on commit 933ef9d

Please sign in to comment.