Test Failed
Push — main ( 5a08b8...db15c0 )
by mikhail
03:27
created

AnalyzeFileTask::run()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.0123

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 16
ccs 8
cts 9
cp 0.8889
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3.0123
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SavinMikhail\CommentsDensity\Analyzer;
6
7
use SavinMikhail\CommentsDensity\Cache\Cache;
8
use SavinMikhail\CommentsDensity\Comments\CommentFactory;
9
use SavinMikhail\CommentsDensity\DTO\Input\ConfigDTO;
10
use SavinMikhail\CommentsDensity\DTO\Output\CommentDTO;
11
use SavinMikhail\CommentsDensity\MissingDocblock\MissingDocBlockAnalyzer;
12
use SplFileInfo;
13
use Symfony\Component\Console\Output\OutputInterface;
14
15
use function array_merge;
16
use function count;
17
use function file;
18
use function file_get_contents;
19
use function in_array;
20
use function is_array;
21
use function token_get_all;
22
23
use const T_COMMENT;
24
use const T_DOC_COMMENT;
25
26
final readonly class AnalyzeFileTask
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_READONLY, expecting T_CLASS on line 26 at column 6
Loading history...
27 5
{
28
    public function __construct(
29
        private Cache $cache,
30
        private MissingDocBlockAnalyzer $docBlockAnalyzer,
31
        private MissingDocBlockAnalyzer $missingDocBlock,
32
        private CommentFactory $commentFactory,
33
        private ConfigDTO $configDTO,
34
        private OutputInterface $output,
35 5
    ) {}
36
37
    /**
38
     * @return array{'lines': int, 'comments': array<array-key, array<string, int>>}
39
     */
40
    public function run(SplFileInfo $file): array
41 5
    {
42
        if ($this->shouldSkipFile($file)) {
43 5
            return ['lines' => 0, 'comments' => []];
44
        }
45
46
        $fileComments = $this->cache->getCache($file->getRealPath());
47 5
48
        if (!$fileComments) {
49 5
            $fileComments = $this->analyzeFile($file->getRealPath());
50 5
            $this->cache->setCache($file->getRealPath(), $fileComments);
51 5
        }
52
53
        $totalLinesOfCode = $this->countTotalLines($file->getRealPath());
54 5
55
        return ['lines' => $totalLinesOfCode, 'comments' => $fileComments];
56 5
    }
57
58
    private function shouldSkipFile(SplFileInfo $file): bool
59 5
    {
60
        return
61 5
            $this->isInWhitelist($file->getRealPath())
62 5
            || $file->getSize() === 0
63 5
            || !$this->isPhpFile($file)
64 5
            || !$file->isReadable();
65 5
    }
66
67
    /**
68
     * @return CommentDTO[]
69
     */
70
    private function analyzeFile(string $filename): array
71
    {
72 5
        $this->output->writeln("<info>Analyzing {$filename}</info>");
73
74 5
        $code = file_get_contents($filename);
75
        $tokens = token_get_all($code);
76 5
77 5
        $comments = $this->getCommentsFromFile($tokens, $filename);
78
        if ($this->shouldAnalyzeMissingDocBlocks()) {
79 5
            $missingDocBlocks = $this->docBlockAnalyzer->getMissingDocblocks($code, $filename);
80 5
            $comments = array_merge($missingDocBlocks, $comments);
81 5
        }
82 5
83
        return $comments;
84
    }
85 5
86
    private function shouldAnalyzeMissingDocBlocks(): bool
87
    {
88 5
        return
89
            empty($this->configDTO->only)
90 5
            || in_array($this->missingDocBlock->getName(), $this->configDTO->only, true);
91 5
    }
92 5
93
    /**
94
     * @param array<mixed> $tokens
95
     * @return CommentDTO[]
96
     */
97
    private function getCommentsFromFile(array $tokens, string $filename): array
98
    {
99 5
        $comments = [];
100
        foreach ($tokens as $token) {
101 5
            if (!is_array($token) || !in_array($token[0], [T_COMMENT, T_DOC_COMMENT], true)) {
102 5
                continue;
103 5
            }
104 5
            $commentType = $this->commentFactory->classifyComment($token[1]);
105
            if ($commentType) {
106 5
                $comments[] =
107 5
                    new CommentDTO(
108 5
                        $commentType->getName(),
109 5
                        $commentType->getColor(),
110 5
                        $filename,
111 5
                        $token[2],
112 5
                        $token[1],
113 5
                    );
114 5
            }
115 5
        }
116
117
        return $comments;
118 5
    }
119
120
    private function countTotalLines(string $filename): int
121 5
    {
122
        $fileContent = file($filename);
123 5
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
140
        return false;
141
    }
142
}
143