Passed
Pull Request — master (#69)
by Dave
02:19
created

convertFromArray()   B

Complexity

Conditions 6
Paths 14

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
nc 14
nop 2
dl 0
loc 35
rs 8.9777
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Static Analysis Results Baseliner (sarb).
5
 *
6
 * (c) Dave Liddament
7
 *
8
 * For the full copyright and licence information please view the LICENSE file distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace DaveLiddament\StaticAnalysisResultsBaseliner\Plugins\ResultsParsers\PhpCodeSnifferJsonResultsParser;
14
15
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\FileName;
16
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\InvalidPathException;
17
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\LineNumber;
18
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\Location;
19
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\ProjectRoot;
20
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\Type;
21
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\File\InvalidFileFormatException;
22
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\ResultsParser\AnalysisResult;
23
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\ResultsParser\AnalysisResults;
24
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\ResultsParser\AnalysisResultsBuilder;
25
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\ResultsParser\Identifier;
26
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\ResultsParser\ResultsParser;
27
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Utils\ArrayParseException;
28
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Utils\ArrayUtils;
29
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Utils\JsonParseException;
30
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Utils\JsonUtils;
31
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Utils\ParseAtLocationException;
32
33
/**
34
 * Handles PHP Code Sniffers's JSON output.
35
 */
36
class PhpCodeSnifferJsonResultsParser implements ResultsParser
37
{
38
    private const LINE = 'line';
39
    private const SOURCE = 'source';
40
    private const FILES = 'files';
41
    private const MESSAGES = 'messages';
42
    private const MESSAGE = 'message';
43
    private const ABSOLUTE_FILE_PATH = 'absoluteFilePath';
44
    private const ERRORS = 'errors';
45
    private const WARNINGS = 'warnings';
46
47
    /**
48
     * {@inheritdoc}
49
     */
50
    public function convertFromString(string $resultsAsString, ProjectRoot $projectRoot): AnalysisResults
51
    {
52
        try {
53
            $asArray = JsonUtils::toArray($resultsAsString);
54
        } catch (JsonParseException $e) {
55
            throw new InvalidFileFormatException('Not a valid JSON format');
56
        }
57
58
        return $this->convertFromArray($asArray, $projectRoot);
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function getIdentifier(): Identifier
65
    {
66
        return new PhpCodeSnifferJsonIdentifier();
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public function showTypeGuessingWarning(): bool
73
    {
74
        return false;
75
    }
76
77
    /**
78
     * Converts from an array.
79
     *
80
     * @phpstan-param array<mixed> $analysisResultsAsArray
81
     *
82
     * @throws ParseAtLocationException
83
     */
84
    private function convertFromArray(array $analysisResultsAsArray, ProjectRoot $projectRoot): AnalysisResults
85
    {
86
        $analysisResultsBuilder = new AnalysisResultsBuilder();
87
88
        try {
89
            $filesErrors = ArrayUtils::getArrayValue($analysisResultsAsArray, self::FILES);
90
        } catch (ArrayParseException $e) {
91
            throw ParseAtLocationException::issueParsing($e, 'Root node');
92
        }
93
94
        /** @psalm-suppress MixedAssignment */
95
        foreach ($filesErrors as $absoluteFilePath => $fileErrors) {
96
            try {
97
                if (!is_string($absoluteFilePath)) {
98
                    throw new ArrayParseException('Expected filename to be of type string');
99
                }
100
101
                ArrayUtils::assertArray($fileErrors);
102
103
                $fileNameAsString = $projectRoot->getPathRelativeToRootDirectory($absoluteFilePath);
104
                $fileName = new FileName($fileNameAsString);
105
106
                $messages = ArrayUtils::getArrayValue($fileErrors, self::MESSAGES);
107
108
                foreach ($messages as $message) {
109
                    ArrayUtils::assertArray($message);
110
                    $analysisResult = $this->convertAnalysisResultFromArray($message, $fileName, $absoluteFilePath);
111
                    $analysisResultsBuilder->addAnalysisResult($analysisResult);
112
                }
113
            } catch (ArrayParseException | JsonParseException | InvalidPathException $e) {
114
                throw ParseAtLocationException::issueParsing($e, "Result [$absoluteFilePath]");
115
            }
116
        }
117
118
        return $analysisResultsBuilder->build();
119
    }
120
121
    /**
122
     * @phpstan-param array<mixed> $analysisResultAsArray
123
     *
124
     * @throws ArrayParseException
125
     * @throws JsonParseException
126
     */
127
    private function convertAnalysisResultFromArray(
128
        array $analysisResultAsArray,
129
        FileName $fileName,
130
        string $absoluteFilePath
131
    ): AnalysisResult {
132
        $lineAsInt = ArrayUtils::getIntValue($analysisResultAsArray, self::LINE);
133
        $rawMessage = ArrayUtils::getStringValue($analysisResultAsArray, self::MESSAGE);
134
        $rawSource = ArrayUtils::getStringValue($analysisResultAsArray, self::SOURCE);
135
136
        $location = new Location(
137
            $fileName,
138
            new LineNumber($lineAsInt)
139
        );
140
141
        return new AnalysisResult(
142
            $location,
143
            new Type($rawSource),
144
            $rawMessage,
145
            JsonUtils::toString([
146
                self::ABSOLUTE_FILE_PATH => $absoluteFilePath,
147
                self::MESSAGE => $analysisResultAsArray,
148
            ])
149
        );
150
    }
151
}
152