Issues (167)

src/Error/helpers.php (2 issues)

Labels
Severity
1
<?php
2
3
namespace Digia\GraphQL\Error;
4
5
use Digia\GraphQL\Language\Source;
6
use Digia\GraphQL\Language\SourceLocation;
7
8
// Format error
9
10
/**
11
 * @param GraphQLException|null $error
12
 * @return array
13
 * @throws InvariantException
14
 */
15
function formatError(?GraphQLException $error): array
16
{
17
    if (null === $error) {
18
        throw new InvariantException('Received null error.');
19
    }
20
21
    return [
22
        'message'   => $error->getMessage(),
23
        'locations' => $error->getLocationsAsArray(),
24
        'path'      => $error->getPath(),
25
    ];
26
}
27
28
// Print error
29
30
/**
31
 * @param GraphQLException $error
32
 * @return string
33
 */
34
function printError(GraphQLException $error): string
35
{
36
    $printedLocations = [];
37
    $nodes            = $error->getNodes();
38
39
    if (!empty($nodes)) {
40
        foreach ($nodes as $node) {
41
            $location = $node->getLocation();
42
            if (null !== $location) {
43
                $printedLocations[] = highlightSourceAtLocation(
44
                    $location->getSource(),
0 ignored issues
show
It seems like $location->getSource() can also be of type null; however, parameter $source of Digia\GraphQL\Error\highlightSourceAtLocation() does only seem to accept Digia\GraphQL\Language\Source, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

44
                    /** @scrutinizer ignore-type */ $location->getSource(),
Loading history...
45
                    SourceLocation::fromSource($location->getSource(), $location->getStart())
0 ignored issues
show
It seems like $location->getSource() can also be of type null; however, parameter $source of Digia\GraphQL\Language\S...eLocation::fromSource() does only seem to accept Digia\GraphQL\Language\Source, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

45
                    SourceLocation::fromSource(/** @scrutinizer ignore-type */ $location->getSource(), $location->getStart())
Loading history...
46
                );
47
            }
48
        }
49
    } elseif ($error->hasSource() && $error->hasLocations()) {
50
        foreach ($error->getLocations() as $location) {
51
            $printedLocations[] = highlightSourceAtLocation($error->getSource(), $location);
52
        }
53
    }
54
55
    return empty($printedLocations)
56
        ? $error->getMessage()
57
        : \implode("\n\n", \array_merge([$error->getMessage()], $printedLocations)) . "\n";
58
}
59
60
/**
61
 * @param Source         $source
62
 * @param SourceLocation $location
63
 * @return string
64
 */
65
function highlightSourceAtLocation(Source $source, SourceLocation $location): string
66
{
67
    $line           = $location->getLine();
68
    $locationOffset = $source->getLocationOffset();
69
    $lineOffset     = $locationOffset->getLine() - 1;
70
    $columnOffset   = getColumnOffset($source, $location);
71
    $contextLine    = $line + $lineOffset;
72
    $contextColumn  = $location->getColumn() + $columnOffset;
73
    $prevLineNum    = (string)($contextLine - 1);
74
    $lineNum        = (string)$contextLine;
75
    $nextLineNum    = (string)($contextLine + 1);
76
    $padLen         = \mb_strlen($nextLineNum);
77
    $lines          = \preg_split("/\r\n|[\n\r]/", $source->getBody());
78
    $lines          = false === $lines ? [] : $lines;
79
    $lines[0]       = whitespace($locationOffset->getColumn() - 1) . $lines[0];
80
    $outputLines    = [
81
        \sprintf('%s (%s:%s)', $source->getName(), $contextLine, $contextColumn),
82
        $line >= 2 ? leftPad($padLen, $prevLineNum) . ': ' . $lines[$line - 2] : null,
83
        leftPad($padLen, $lineNum) . ': ' . $lines[$line - 1],
84
        whitespace(2 + $padLen + $contextColumn - 1) . '^',
85
        $line < \count($lines) ? leftPad($padLen, $nextLineNum) . ': ' . $lines[$line] : null,
86
    ];
87
88
    return \implode("\n", \array_filter($outputLines, function ($line) {
89
        return null !== $line;
90
    }));
91
}
92
93
/**
94
 * @param Source         $source
95
 * @param SourceLocation $location
96
 * @return int
97
 */
98
function getColumnOffset(Source $source, SourceLocation $location): int
99
{
100
    return $location->getLine() === 1 ? $source->getLocationOffset()->getColumn() - 1 : 0;
101
}
102
103
/**
104
 * @param int $length
105
 * @return string
106
 */
107
function whitespace(int $length): string
108
{
109
    return \str_repeat(' ', $length);
110
}
111
112
/**
113
 * @param int    $length
114
 * @param string $str
115
 * @return string
116
 */
117
function leftPad(int $length, string $str): string
118
{
119
    return whitespace($length - \mb_strlen($str)) . $str;
120
}
121