Skip to content

Commit

Permalink
Merge pull request #31 from worksome/better_error_output
Browse files Browse the repository at this point in the history
feat(command): Improve error output in console command
  • Loading branch information
lukeraymonddowning authored Apr 11, 2023
2 parents ee75899 + f9d87d7 commit 8b5fc8f
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 14 deletions.
1 change: 1 addition & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@
'../src/Events',
'../src/Laravel',
'../src/InspectionDescription.php',
'../src/Utils/ProblemOutputGenerator.php',
]);
};
20 changes: 6 additions & 14 deletions src/Listeners/ConsolePrinterListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use Worksome\Graphlint\Events\AfterFixerEvent;
use Worksome\Graphlint\Events\BeforeAnalyseEvent;
use Worksome\Graphlint\ProblemDescriptor;
use Worksome\Graphlint\ShouldNotHappenException;
use Worksome\Graphlint\Utils\ProblemOutputGenerator;

class ConsolePrinterListener implements GraphlintListener
{
Expand Down Expand Up @@ -56,20 +56,12 @@ public function afterAnalyse(AfterAnalyseEvent $event): void
->count();
$this->style->warning("$unfixableErrors cannot be automatically fixed in $type schema");

$this->style->table(
[
'location',
'description',
],
$this->style->writeln(
Collection::make($problems)
->map(function (ProblemDescriptor $descriptor) {
$startToken = $descriptor->getNode()->loc?->startToken;
if ($startToken === null) {
throw new ShouldNotHappenException("No location on node.");
}

return ["$startToken->line:$startToken->column", $descriptor->getDescription()];
})->all()
->mapInto(ProblemOutputGenerator::class)
->map(fn (ProblemOutputGenerator $generator) => $generator->generate())
->flatten()
->all()
);
}
}
Expand Down
89 changes: 89 additions & 0 deletions src/Utils/ProblemOutputGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace Worksome\Graphlint\Utils;

use GraphQL\Language\Token;
use Worksome\Graphlint\ProblemDescriptor;
use Worksome\Graphlint\ShouldNotHappenException;

final readonly class ProblemOutputGenerator
{
public function __construct(
private ProblemDescriptor $descriptor,
private int $index,
private int $surroundingContextCharacters = 100,
) {
}

/**
* @return array<int, string>
*/
public function generate(): array
{
return [$this->title(), PHP_EOL, $this->schemaSnippet(), PHP_EOL];
}

private function title(): string
{
return sprintf(
"<bg=red;options=bold>%s %d: %s %s</>",
PHP_EOL . PHP_EOL,
$this->index + 1,
$this->descriptor->getDescription(),
PHP_EOL
);
}

private function schemaSnippet(): string
{
$bodyCharacters = mb_str_split($this->schemaBody());

$bodyCharacters[$this->startToken()->start] = sprintf(
'<fg=red>%s',
$bodyCharacters[$this->startToken()->start]
);
$bodyCharacters[$this->endToken()->end] = sprintf('%s</>', $bodyCharacters[$this->endToken()->end]);

$snippetStartIndex = max(0, $this->startToken()->start - $this->surroundingContextCharacters);
$snippetLength = $this->endToken()->end - $snippetStartIndex + $this->surroundingContextCharacters;

$snippetCharacters = array_splice($bodyCharacters, $snippetStartIndex, $snippetLength);

return sprintf('<fg=black>%s</>', implode('', $snippetCharacters));
}

private function startToken(): Token
{
$startToken = $this->descriptor->getNode()->loc?->startToken;

if ($startToken === null) {
throw new ShouldNotHappenException("No location on node.");
}

return $startToken;
}

private function endToken(): Token
{
$endToken = $this->descriptor->getNode()->loc?->endToken;

if ($endToken === null) {
throw new ShouldNotHappenException("No location on node.");
}

return $endToken;
}

private function schemaBody(): string
{
$body = $this->descriptor->getNode()->loc?->source?->body;

if ($body === null) {
throw new ShouldNotHappenException("No source on node.");
}

return $body;
}
}

0 comments on commit 8b5fc8f

Please sign in to comment.