Completed
Pull Request — master (#139)
by Christoffer
02:23
created

locatedError()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.2
c 0
b 0
f 0
cc 4
eloc 7
nc 1
nop 3
1
<?php
2
3
namespace Digia\GraphQL\Error;
4
5
use Digia\GraphQL\Language\Source;
6
use Digia\GraphQL\Language\SourceLocation;
7
use function Digia\GraphQL\Util\invariant;
8
9
// Format error
10
11
/**
12
 * @param GraphQLException|null $error
13
 * @return array
14
 * @throws InvariantException
15
 */
16
function formatError(?GraphQLException $error): array
17
{
18
    invariant(null !== $error, 'Received null error.');
19
20
    return [
21
        'message'   => $error->getMessage(),
0 ignored issues
show
Bug introduced by
The method getMessage() does not exist on null. ( Ignorable by Annotation )

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

21
        'message'   => $error->/** @scrutinizer ignore-call */ getMessage(),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
22
        'locations' => $error->getLocationsAsArray(),
23
        'path'      => $error->getPath(),
24
    ];
25
}
26
27
// Located error
28
29
/**
30
 * @param \Exception   $originalException
31
 * @param array        $nodes
32
 * @param string|array $path
33
 * @return GraphQLException
34
 */
35
function locatedError(\Exception $originalException, array $nodes, $path): ExecutionException
36
{
37
    return new ExecutionException(
38
        $originalException->getMessage(),
39
        $originalException instanceof GraphQLException ? $originalException->getNodes() : $nodes,
40
        $originalException instanceof GraphQLException ? $originalException->getSource() : null,
41
        $originalException instanceof GraphQLException ? $originalException->getPositions() : null,
42
        $path,
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type string; however, parameter $path of Digia\GraphQL\Error\Exec...xception::__construct() does only seem to accept null|array, 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

42
        /** @scrutinizer ignore-type */ $path,
Loading history...
43
        $originalException
44
    );
45
}
46
47
48
// Print error
49
50
/**
51
 * @param GraphQLException $error
52
 * @return string
53
 */
54
function printError(GraphQLException $error): string
55
{
56
    $printedLocations = [];
57
    $nodes            = $error->getNodes();
58
59
    if (!empty($nodes)) {
60
        foreach ($nodes as $node) {
61
            $location = $node->getLocation();
62
            if (null !== $location) {
63
                $printedLocations[] = highlightSourceAtLocation(
64
                    $location->getSource(),
65
                    SourceLocation::fromSource($location->getSource(), $location->getStart())
66
                );
67
            }
68
        }
69
    } elseif ($error->hasSource() && $error->hasLocations()) {
70
        foreach ($error->getLocations() as $location) {
71
            $printedLocations[] = highlightSourceAtLocation($error->getSource(), $location);
72
        }
73
    }
74
75
    return empty($printedLocations)
76
        ? $error->getMessage()
77
        : \implode("\n\n", \array_merge([$error->getMessage()], $printedLocations)) . "\n";
78
}
79
80
/**
81
 * @param Source         $source
82
 * @param SourceLocation $location
83
 * @return string
84
 */
85
function highlightSourceAtLocation(Source $source, SourceLocation $location): string
86
{
87
    $line           = $location->getLine();
88
    $locationOffset = $source->getLocationOffset();
89
    $lineOffset     = $locationOffset->getLine() - 1;
90
    $columnOffset   = getColumnOffset($source, $location);
91
    $contextLine    = $line + $lineOffset;
92
    $contextColumn  = $location->getColumn() + $columnOffset;
93
    $prevLineNum    = (string)($contextLine - 1);
94
    $lineNum        = (string)$contextLine;
95
    $nextLineNum    = (string)($contextLine + 1);
96
    $padLen         = \mb_strlen($nextLineNum);
97
    $lines          = \preg_split("/\r\n|[\n\r]/", $source->getBody());
98
    $lines[0]       = whitespace($locationOffset->getColumn() - 1) . $lines[0];
99
    $outputLines = [
100
        \sprintf('%s (%s:%s)', $source->getName(), $contextLine, $contextColumn),
101
        $line >= 2 ? leftPad($padLen, $prevLineNum) . ': ' . $lines[$line - 2] : null,
102
        leftPad($padLen, $lineNum) . ': ' . $lines[$line - 1],
103
        whitespace(2 + $padLen + $contextColumn - 1) . '^',
104
        $line < \count($lines) ? leftPad($padLen, $nextLineNum) . ': ' . $lines[$line] : null,
0 ignored issues
show
Bug introduced by
It seems like $lines can also be of type false; however, parameter $var of count() does only seem to accept Countable|array, 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

104
        $line < \count(/** @scrutinizer ignore-type */ $lines) ? leftPad($padLen, $nextLineNum) . ': ' . $lines[$line] : null,
Loading history...
105
    ];
106
107
    return \implode("\n", \array_filter($outputLines, function ($line) {
108
        return null !== $line;
109
    }));
110
}
111
112
/**
113
 * @param Source         $source
114
 * @param SourceLocation $location
115
 * @return int
116
 */
117
function getColumnOffset(Source $source, SourceLocation $location): int
118
{
119
    return $location->getLine() === 1 ? $source->getLocationOffset()->getColumn() - 1 : 0;
120
}
121
122
/**
123
 * @param int $length
124
 * @return string
125
 */
126
function whitespace(int $length): string
127
{
128
    return \str_repeat(' ', $length);
129
}
130
131
/**
132
 * @param int    $length
133
 * @param string $str
134
 * @return string
135
 */
136
function leftPad(int $length, string $str): string
137
{
138
    return whitespace($length - \mb_strlen($str)) . $str;
139
}
140