IssueFactory   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 31
eloc 63
c 1
b 0
f 0
dl 0
loc 147
rs 9.92

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A buildNestingConsistencyIssue03() 0 12 4
A buildNestingConsistencyIssue0102() 0 17 5
C getIssue() 0 37 14
A buildIndentationIssue() 0 7 3
A buildEmptySectionIssue() 0 16 4
1
<?php
2
declare(strict_types=1);
3
4
namespace Pluswerk\TypoScriptAutoFixer\Adapter;
5
6
use Helmich\TypoScriptLint\Linter\Report\Issue;
7
use Helmich\TypoScriptParser\Tokenizer\LineGrouper;
8
use Helmich\TypoScriptParser\Tokenizer\TokenInterface;
9
use Pluswerk\TypoScriptAutoFixer\Issue\AbstractIssue;
10
use Pluswerk\TypoScriptAutoFixer\Issue\EmptySectionIssue;
11
use Pluswerk\TypoScriptAutoFixer\Issue\IndentationIssue;
12
use Pluswerk\TypoScriptAutoFixer\Issue\NestingConsistencyIssue;
13
use Pluswerk\TypoScriptAutoFixer\Issue\OperatorWhitespaceIssue;
14
15
final class IssueFactory
16
{
17
    private const INDENTATION_PATTERN = '/^Expected indent of (\d{1,2}) (spaces?|tabs?)\.$/';
18
    private const NESTED_CONSISTENCY_01 = '/^Common path prefix \".*\" with assignment to \".*\" in line (\d{1,})\. Consider merging them into a nested assignment.$/';
19
    private const NESTED_CONSISTENCY_02 = '/^Assignment to value \".*\", altough nested statement for path \".*\" exists at line (\d{1,})\.$/';
20
    private const NESTED_CONSISTENCY_03 = '/^Multiple nested statements for object path \"(.*)\"\. Consider merging them into one statement\.$/';
21
22
    /**
23
     * @var AdapterUtility
24
     */
25
    private $adapterUtility;
26
27
    public function __construct()
28
    {
29
        $this->adapterUtility = new AdapterUtility();
30
    }
31
32
    /**
33
     * @param Issue $issue
34
     * @param array $tokens
35
     *
36
     * @return AbstractIssue|null
37
     */
38
    public function getIssue(Issue $issue, array $tokens): ?AbstractIssue
39
    {
40
        $message = $issue->getMessage();
41
        $tokenLines = new LineGrouper($tokens);
0 ignored issues
show
Unused Code introduced by
The assignment to $tokenLines is dead and can be removed.
Loading history...
42
43
        switch ($message) {
44
            // OperatorWhitespaceIssue
45
            case 'Accessor should be followed by single space.':
46
            case 'No whitespace after object accessor.':
47
            case 'No whitespace after operator.':
48
            case 'Operator should be followed by single space.':
49
                return new OperatorWhitespaceIssue((int) $issue->getLine());
50
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
51
52
            // IndentationIssue
53
            case (preg_match(self::INDENTATION_PATTERN, $issue->getMessage(), $matches) ? $message : !$message):
54
                return $this->buildIndentationIssue($issue, $matches);
55
                break;
56
57
            // EmptySectionIssue
58
            case 'Empty assignment block':
59
                return $this->buildEmptySectionIssue($issue, $tokens);
60
                break;
61
62
            // NestingConsistencyIssue
63
            case (preg_match(self::NESTED_CONSISTENCY_01, $issue->getMessage(), $matches) ? $message : !$message):
64
            case (preg_match(self::NESTED_CONSISTENCY_02, $issue->getMessage(), $matches) ? $message : !$message):
65
                return $this->buildNestingConsistencyIssue0102($issue, $matches, $tokens);
66
                break;
67
            case (preg_match(self::NESTED_CONSISTENCY_03, $issue->getMessage(), $matches) ? $message : !$message):
68
                return $this->buildNestingConsistencyIssue03($issue, $matches, $tokens);
69
                break;
70
71
            // Default is null
72
            default:
73
                return null;
74
                break;
75
        }
76
    }
77
78
    /**
79
     * @param Issue $issue
80
     * @param array $tokens
81
     *
82
     * @return EmptySectionIssue|null
83
     */
84
    private function buildEmptySectionIssue(Issue $issue, array $tokens): ?EmptySectionIssue
85
    {
86
        $tokenLines = new LineGrouper($tokens);
87
        $startLine = (int) $issue->getLine();
88
        $lines = $tokenLines->getLines();
89
        $amountOfLines = count($lines);
90
        for ($i = $startLine; $i<=$amountOfLines; $i++) {
91
            foreach ($lines[$i] as $token) {
92
                if ($token->getType() === TokenInterface::TYPE_BRACE_CLOSE) {
93
                    $endLine = $i;
94
                    return new EmptySectionIssue($startLine, $endLine);
95
                    break 2;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
96
                }
97
            }
98
        }
99
        return null;
100
    }
101
102
    /**
103
     * @param Issue $issue
104
     * @param array $matches
105
     *
106
     * @return IndentationIssue
107
     */
108
    private function buildIndentationIssue(Issue $issue, array $matches): IndentationIssue
109
    {
110
        $char = ' ';
111
        if ($matches[2] === 'tab' || $matches[2] === 'tabs') {
112
            $char = "\t";
113
        }
114
        return new IndentationIssue((int) $issue->getLine(), (int)($matches[1] ?? 0), $char);
115
    }
116
117
    /**
118
     * @param Issue $issue
119
     * @param array $matches
120
     * @param array $tokens
121
     *
122
     * @return NestingConsistencyIssue
123
     */
124
    private function buildNestingConsistencyIssue0102(Issue $issue, array $matches, array $tokens): NestingConsistencyIssue
125
    {
126
        $secondLine = (int) $matches[1] ?? 0;
127
        $firstLine = (int) $issue->getLine();
128
129
        if ($secondLine < $firstLine) {
130
            [$secondLine, $firstLine] = [$firstLine, $secondLine];
131
        }
132
133
        $firstEndLine = $this->adapterUtility->findEndLineOfNestedStatement($firstLine, $tokens);
134
        $secondEndLine = $this->adapterUtility->findEndLineOfNestedStatement($secondLine, $tokens);
135
136
        if ($secondLine === 0 || $firstEndLine === 0 || $secondEndLine === 0) {
137
            return null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return null returns the type null which is incompatible with the type-hinted return Pluswerk\TypoScriptAutoF...NestingConsistencyIssue.
Loading history...
138
        }
139
140
        return new NestingConsistencyIssue($firstLine, $secondLine, $firstEndLine, $secondEndLine);
141
    }
142
143
    /**
144
     * @param Issue $issue
145
     * @param       $matches
146
     * @param array $tokens
147
     *
148
     * @return NestingConsistencyIssue|null
149
     */
150
    private function buildNestingConsistencyIssue03(Issue $issue, $matches, array $tokens): ?NestingConsistencyIssue
151
    {
152
        $secondLine = (int) $issue->getLine();
153
        $firstLine = $this->adapterUtility->findFirstNestedAppearanceOfObjectPath($secondLine, $matches[1], $tokens);
154
        $firstEndLine = $this->adapterUtility->findEndLineOfNestedStatement($firstLine, $tokens);
155
        $secondEndLine = $this->adapterUtility->findEndLineOfNestedStatement($secondLine, $tokens);
156
157
        if ($firstLine === 0 || $firstEndLine === 0 || $secondEndLine === 0) {
158
            return null;
159
        }
160
161
        return new NestingConsistencyIssue($firstLine, $secondLine, $firstEndLine, $secondEndLine);
162
    }
163
}
164