Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refact(core): Refactor FriendlyErrorFormatter for improved structure … #11

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
yamadashy marked this conversation as resolved.
Show resolved Hide resolved

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
3 changes: 2 additions & 1 deletion .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
])
->in(__DIR__);

$config = new PhpCsFixer\Config();
$config = (new PhpCsFixer\Config())
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect());

return $config
->setRiskyAllowed(true)
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
17 changes: 11 additions & 6 deletions src/CodeHighlighter.php → src/CodeHighlight/CodeHighlighter.php
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;
yamadashy marked this conversation as resolved.
Show resolved Hide resolved

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
*/
yamadashy marked this conversation as resolved.
Show resolved Hide resolved
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 */
yamadashy marked this conversation as resolved.
Show resolved Hide resolved
$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;
yamadashy marked this conversation as resolved.
Show resolved Hide resolved

/**
* @see Highlighter
Expand Down
33 changes: 33 additions & 0 deletions src/Config/FriendlyFormatterConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?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
) {
if ($lineBefore < 0) {
throw new \InvalidArgumentException('lineBefore must be a non-negative integer.');
}

if ($lineAfter < 0) {
throw new \InvalidArgumentException('lineAfter must be a non-negative integer.');
}

$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;
yamadashy marked this conversation as resolved.
Show resolved Hide resolved

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));
}
}
34 changes: 34 additions & 0 deletions src/ErrorFormat/SummaryWriter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types=1);

namespace Yamadashy\PhpStanFriendlyFormatter\ErrorFormat;

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

class SummaryWriter
{
private const IDENTIFIER_NO_IDENTIFIER = '<no-identifier>';

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

foreach ($analysisResult->getFileSpecificErrors() as $error) {
$identifier = $error->getIdentifier() ?? self::IDENTIFIER_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