TypoScriptLinter   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Test Coverage

Coverage 90.91%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 11
eloc 43
c 1
b 0
f 0
dl 0
loc 138
ccs 40
cts 44
cp 0.9091
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A lintSyntaxTree() 0 16 2
A lintTokenStream() 0 16 2
A isInstalled() 0 3 1
A lint() 0 23 4
A initializeConfiguration() 0 7 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Pluswerk\TypoScriptLinter;
5
6
use GrumPHP\Collection\LintErrorsCollection;
7
use GrumPHP\Linter\LinterInterface;
8
use Helmich\TypoScriptLint\Linter\LinterConfiguration;
9
use Helmich\TypoScriptLint\Linter\Report\File;
10
use Helmich\TypoScriptLint\Linter\Report\Issue;
11
use Helmich\TypoScriptLint\Linter\Report\Report;
12
use Helmich\TypoScriptLint\Linter\Sniff\SniffLocator;
13
use Helmich\TypoScriptLint\Logging\LinterLoggerInterface;
14
use Helmich\TypoScriptParser\Parser\AST\Statement;
15
use Helmich\TypoScriptParser\Parser\ParseError;
16
use Helmich\TypoScriptParser\Parser\Parser;
17
use Helmich\TypoScriptParser\Tokenizer\Tokenizer;
18
use Helmich\TypoScriptParser\Tokenizer\TokenizerException;
19
use SplFileInfo;
20
use Symfony\Component\Config\Definition\Processor;
21
22
final class TypoScriptLinter implements LinterInterface
23
{
24
    /**
25
     * @var Tokenizer
26
     */
27
    private $tokenizer;
28
29
    /**
30
     * @var Parser
31
     */
32
    private $parser;
33
34
    /**
35
     * @var SniffLocator
36
     */
37
    private $sniffLocator;
38
39
    /**
40
     * @var LinterConfiguration
41
     */
42
    private $configuration;
43
44
    /**
45
     * @var Processor
46
     */
47
    private $processor;
48
49 10
    public function __construct()
50
    {
51 10
        $this->tokenizer = new Tokenizer();
52 10
        $this->parser = new Parser($this->tokenizer);
53 10
        $this->sniffLocator = new SniffLocator();
54 10
        $this->configuration = new LinterConfiguration();
55 10
        $this->processor = new Processor();
56 10
    }
57
58
    /**
59
     * @param array $configArray
60
     */
61 10
    public function initializeConfiguration(array $configArray): void
62
    {
63 10
        $preProcessedConfig = $configArray;
64
        // Remove grumphp configuration, which is not allowed in TypoScript linter.
65 10
        unset($preProcessedConfig['ignore_patterns'], $preProcessedConfig['triggered_by']);
66 10
        $processedConfiguration = $this->processor->processConfiguration($this->configuration, [$preProcessedConfig]);
67 10
        $this->configuration->setConfiguration($processedConfiguration);
68 10
    }
69
70
    /**
71
     * @param \Symfony\Component\Finder\SplFileInfo $file
72
     *
73
     * @return LintErrorsCollection
74
     * @throws \Exception
75
     */
76 9
    public function lint(SplFileInfo $file): LintErrorsCollection
77
    {
78 9
        $filename = $file->getPathname();
79 9
        $file = new File($filename);
80 9
        $lintErrors = new LintErrorsCollection();
81
82
        try {
83 9
            $tokens     = $this->tokenizer->tokenizeStream($filename);
84 9
            $statements = $this->parser->parseTokens($tokens);
85
86 9
            $file = $this->lintTokenStream($tokens, $file, $this->configuration);
87 9
            $file = $this->lintSyntaxTree($statements, $file, $this->configuration);
88
        } catch (TokenizerException $tokenizerException) {
89
            $file->addIssue(Issue::createFromTokenizerError($tokenizerException));
90
        } catch (ParseError $parseError) {
91
            $file->addIssue(Issue::createFromParseError($parseError));
92
        }
93
94 9
        foreach ($file->getIssues() as $issue) {
95 8
            $lintErrors->add(TypoScriptLintError::fromIssue($issue, $filename));
96
        }
97
98 9
        return $lintErrors;
99
    }
100
101
    /**
102
     * @param array               $tokens
103
     * @param File                $file
104
     * @param LinterConfiguration $configuration
105
     *
106
     * @return File
107
     * @throws \Exception
108
     */
109 9
    private function lintTokenStream(
110
        array $tokens,
111
        File $file,
112
        LinterConfiguration $configuration
113
    ): File {
114 9
        $sniffs = $this->sniffLocator->getTokenStreamSniffs($configuration);
115
116 9
        foreach ($sniffs as $sniff) {
117 9
            $sniffReport = $file->cloneEmpty();
118
119 9
            $sniff->sniff($tokens, $sniffReport, $configuration);
120
121 9
            $file = $file->merge($sniffReport);
122
        }
123
124 9
        return $file;
125
    }
126
127
    /**
128
     * @param Statement[]           $statements
129
     * @param File                  $file
130
     * @param LinterConfiguration   $configuration
131
     * @param LinterLoggerInterface $logger
132
     * @return File
133
     */
134 9
    private function lintSyntaxTree(
135
        array $statements,
136
        File $file,
137
        LinterConfiguration $configuration
138
    ): File {
139 9
        $sniffs = $this->sniffLocator->getSyntaxTreeSniffs($configuration);
140
141 9
        foreach ($sniffs as $sniff) {
142 9
            $sniffReport = $file->cloneEmpty();
143
144 9
            $sniff->sniff($statements, $sniffReport, $configuration);
145
146 9
            $file = $file->merge($sniffReport);
147
        }
148
149 9
        return $file;
150
    }
151
152
    /**
153
     * @return bool
154
     *
155
     * @todo Check if we have to check for something is installed?
156
     */
157 9
    public function isInstalled(): bool
158
    {
159 9
        return true;
160
    }
161
}
162