Passed
Push — main ( a82980...5a08b8 )
by mikhail
14:17
created

AnalyzeFileTask::isInWhitelist()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3.576

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
ccs 3
cts 5
cp 0.6
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3.576
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SavinMikhail\CommentsDensity\Analyzer;
6
7
use SavinMikhail\CommentsDensity\Cache\Cache;
0 ignored issues
show
Bug introduced by
The type SavinMikhail\CommentsDensity\Cache\Cache was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use SavinMikhail\CommentsDensity\Comments\CommentFactory;
0 ignored issues
show
Bug introduced by
The type SavinMikhail\CommentsDen...Comments\CommentFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use SavinMikhail\CommentsDensity\DTO\Input\ConfigDTO;
0 ignored issues
show
Bug introduced by
The type SavinMikhail\CommentsDensity\DTO\Input\ConfigDTO was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use SavinMikhail\CommentsDensity\DTO\Output\CommentDTO;
0 ignored issues
show
Bug introduced by
The type SavinMikhail\CommentsDensity\DTO\Output\CommentDTO was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use SavinMikhail\CommentsDensity\MissingDocblock\MissingDocBlockAnalyzer;
12
use SplFileInfo;
13
14
use Symfony\Component\Console\Output\OutputInterface;
15
use function array_merge;
16
use function file;
17
use function file_get_contents;
18
use function in_array;
19
use function is_array;
20
use function token_get_all;
21
22
use const T_COMMENT;
23
use const T_DOC_COMMENT;
24
25
readonly class AnalyzeFileTask
26
{
27 5
    public function __construct(
28
        private Cache                   $cache,
29
        private MissingDocBlockAnalyzer $docBlockAnalyzer,
30
        private MissingDocBlockAnalyzer $missingDocBlock,
31
        private CommentFactory          $commentFactory,
32
        private ConfigDTO               $configDTO,
33
        private OutputInterface         $output,
34
    ) {
35 5
    }
36
37
    /**
38
     * @param SplFileInfo $file
39
     * @return array{'lines': int, 'comments': array<array-key, array<string, int>>}
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{'lines': int, 'com...y, array<string, int>>} at position 10 could not be parsed: Unknown type name 'array-key' at position 10 in array{'lines': int, 'comments': array<array-key, array<string, int>>}.
Loading history...
40
     */
41 5
    public function run(SplFileInfo $file): array
42
    {
43 5
        if ($this->shouldSkipFile($file)) {
44
            return ['lines' => 0, 'comments' => []];
45
        }
46
47 5
        $fileComments = $this->cache->getCache($file->getRealPath());
48
49 5
        if (!$fileComments) {
50 5
            $fileComments = $this->analyzeFile($file->getRealPath());
51 5
            $this->cache->setCache($file->getRealPath(), $fileComments);
52
        }
53
54 5
        $totalLinesOfCode = $this->countTotalLines($file->getRealPath());
55
56 5
        return ['lines' => $totalLinesOfCode, 'comments' => $fileComments];
57
    }
58
59 5
    private function shouldSkipFile(SplFileInfo $file): bool
60
    {
61 5
        return
62 5
            $this->isInWhitelist($file->getRealPath()) ||
63 5
            $file->getSize() === 0 ||
64 5
            !$this->isPhpFile($file) ||
65 5
            !$file->isReadable();
66
    }
67
68
    /**
69
     * @param string $filename
70
     * @return CommentDTO[]
71
     */
72 5
    private function analyzeFile(string $filename): array
73
    {
74 5
        $this->output->writeln("<info>Analyzing $filename</info>");
75
76 5
        $code = file_get_contents($filename);
77 5
        $tokens = token_get_all($code);
78
79 5
        $comments = $this->getCommentsFromFile($tokens, $filename);
80 5
        if ($this->shouldAnalyzeMissingDocBlocks()) {
81 5
            $missingDocBlocks = $this->docBlockAnalyzer->getMissingDocblocks($code, $filename);
82 5
            $comments = array_merge($missingDocBlocks, $comments);
83
        }
84
85 5
        return $comments;
86
    }
87
88 5
    private function shouldAnalyzeMissingDocBlocks(): bool
89
    {
90 5
        return
91 5
            empty($this->configDTO->only)
92 5
            || in_array($this->missingDocBlock->getName(), $this->configDTO->only, true);
93
    }
94
95
    /**
96
     * @param array<mixed> $tokens
97
     * @return CommentDTO[]
98
     */
99 5
    private function getCommentsFromFile(array $tokens, string $filename): array
100
    {
101 5
        $comments = [];
102 5
        foreach ($tokens as $token) {
103 5
            if (!is_array($token) || !in_array($token[0], [T_COMMENT, T_DOC_COMMENT])) {
104 5
                continue;
105
            }
106 5
            $commentType = $this->commentFactory->classifyComment($token[1]);
107 5
            if ($commentType) {
108 5
                $comments[] =
109 5
                    new CommentDTO(
110 5
                        $commentType->getName(),
111 5
                        $commentType->getColor(),
112 5
                        $filename,
113 5
                        $token[2],
114 5
                        $token[1],
115 5
                    );
116
            }
117
        }
118 5
        return $comments;
119
    }
120
121 5
    private function countTotalLines(string $filename): int
122
    {
123 5
        $fileContent = file($filename);
124 5
        return count($fileContent);
125
    }
126
127 5
    private function isPhpFile(SplFileInfo $file): bool
128
    {
129 5
        return $file->isFile() && $file->getExtension() === 'php';
130
    }
131
132 5
    private function isInWhitelist(string $filePath): bool
133
    {
134 5
        foreach ($this->configDTO->exclude as $whitelistedDir) {
135
            if (str_contains($filePath, $whitelistedDir)) {
136
                return true;
137
            }
138
        }
139 5
        return false;
140
    }
141
}
142