|
14 | 14 | namespace PhpCsFixerCustomFixers\Fixer; |
15 | 15 |
|
16 | 16 | use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface; |
17 | | -use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver; |
18 | | -use PhpCsFixer\FixerConfiguration\FixerOptionBuilder; |
19 | | -use PhpCsFixer\FixerDefinition\CodeSample; |
20 | | -use PhpCsFixer\FixerDefinition\FixerDefinition; |
| 17 | +use PhpCsFixer\Fixer\DeprecatedFixerInterface; |
| 18 | +use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; |
21 | 19 | use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; |
22 | | -use PhpCsFixer\Preg; |
23 | | -use PhpCsFixer\Tokenizer\Analyzer\Analysis\CaseAnalysis; |
24 | | -use PhpCsFixer\Tokenizer\Analyzer\ReferenceAnalyzer; |
25 | | -use PhpCsFixer\Tokenizer\Analyzer\SwitchAnalyzer; |
26 | | -use PhpCsFixer\Tokenizer\Token; |
27 | 20 | use PhpCsFixer\Tokenizer\Tokens; |
28 | 21 |
|
29 | | -final class OperatorLinebreakFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, DeprecatingFixerInterface |
| 22 | +/** |
| 23 | + * @deprecated |
| 24 | + */ |
| 25 | +final class OperatorLinebreakFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, DeprecatedFixerInterface |
30 | 26 | { |
31 | | - private const BOOLEAN_OPERATORS = [[T_BOOLEAN_AND], [T_BOOLEAN_OR], [T_LOGICAL_AND], [T_LOGICAL_OR], [T_LOGICAL_XOR]]; |
32 | | - private const NON_BOOLEAN_OPERATORS = ['%', '&', '*', '+', '-', '.', '/', ':', '<', '=', '>', '?', '^', '|', [T_AND_EQUAL], [T_COALESCE], [T_CONCAT_EQUAL], [T_DIV_EQUAL], [T_DOUBLE_ARROW], [T_IS_EQUAL], [T_IS_GREATER_OR_EQUAL], [T_IS_IDENTICAL], [T_IS_NOT_EQUAL], [T_IS_NOT_IDENTICAL], [T_IS_SMALLER_OR_EQUAL], [T_MINUS_EQUAL], [T_MOD_EQUAL], [T_MUL_EQUAL], [T_OBJECT_OPERATOR], [T_OR_EQUAL], [T_PAAMAYIM_NEKUDOTAYIM], [T_PLUS_EQUAL], [T_POW], [T_POW_EQUAL], [T_SL], [T_SL_EQUAL], [T_SPACESHIP], [T_SR], [T_SR_EQUAL], [T_XOR_EQUAL]]; |
33 | | - |
34 | | - /** @var string */ |
35 | | - private $position = 'beginning'; |
36 | | - |
37 | | - /** @var array<array<int|string>|string> */ |
38 | | - private $operators = []; |
| 27 | + /** @var \PhpCsFixer\Fixer\Operator\OperatorLinebreakFixer */ |
| 28 | + private $fixer; |
39 | 29 |
|
40 | 30 | public function __construct() |
41 | 31 | { |
42 | | - $this->operators = \array_merge(self::BOOLEAN_OPERATORS, self::NON_BOOLEAN_OPERATORS); |
| 32 | + $this->fixer = new \PhpCsFixer\Fixer\Operator\OperatorLinebreakFixer(); |
43 | 33 | } |
44 | 34 |
|
45 | 35 | public function getDefinition(): FixerDefinitionInterface |
46 | 36 | { |
47 | | - return new FixerDefinition( |
48 | | - 'Operators must always be at the beginning or at the end of the line.', |
49 | | - [new CodeSample('<?php |
50 | | -function foo() { |
51 | | - return $bar || |
52 | | - $baz; |
53 | | -} |
54 | | -')] |
55 | | - ); |
| 37 | + return $this->fixer->getDefinition(); |
56 | 38 | } |
57 | 39 |
|
58 | | - public function getConfigurationDefinition(): FixerConfigurationResolver |
| 40 | + public function getConfigurationDefinition(): FixerConfigurationResolverInterface |
59 | 41 | { |
60 | | - return new FixerConfigurationResolver([ |
61 | | - (new FixerOptionBuilder('only_booleans', 'whether to limit operators to only boolean ones')) |
62 | | - ->setAllowedTypes(['bool']) |
63 | | - ->setDefault(false) |
64 | | - ->getOption(), |
65 | | - (new FixerOptionBuilder('position', 'whether to place operators at the beginning or at the end of the line')) |
66 | | - ->setAllowedValues(['beginning', 'end']) |
67 | | - ->setDefault($this->position) |
68 | | - ->getOption(), |
69 | | - ]); |
| 42 | + return $this->fixer->getConfigurationDefinition(); |
70 | 43 | } |
71 | 44 |
|
72 | 45 | /** |
73 | 46 | * @param null|array<string, bool|string> $configuration |
74 | 47 | */ |
75 | 48 | public function configure(?array $configuration = null): void |
76 | 49 | { |
77 | | - if (isset($configuration['only_booleans']) && $configuration['only_booleans'] === true) { |
78 | | - $this->operators = self::BOOLEAN_OPERATORS; |
79 | | - } |
80 | | - |
81 | | - if (isset($configuration['position'])) { |
82 | | - /** @var string $position */ |
83 | | - $position = $configuration['position']; |
84 | | - $this->position = $position; |
85 | | - } |
| 50 | + $this->fixer->configure($configuration); |
86 | 51 | } |
87 | 52 |
|
88 | 53 | public function getPriority(): int |
89 | 54 | { |
90 | | - return 0; |
91 | | - } |
92 | | - |
93 | | - public function getPullRequestId(): int |
94 | | - { |
95 | | - return 4021; |
| 55 | + return $this->fixer->getPriority(); |
96 | 56 | } |
97 | 57 |
|
98 | 58 | public function isCandidate(Tokens $tokens): bool |
99 | 59 | { |
100 | | - return true; |
| 60 | + return $this->fixer->isCandidate($tokens); |
101 | 61 | } |
102 | 62 |
|
103 | 63 | public function isRisky(): bool |
104 | 64 | { |
105 | | - return false; |
| 65 | + return $this->fixer->isRisky(); |
106 | 66 | } |
107 | 67 |
|
108 | 68 | public function fix(\SplFileInfo $file, Tokens $tokens): void |
109 | 69 | { |
110 | | - $referenceAnalyzer = new ReferenceAnalyzer(); |
111 | | - |
112 | | - $excludedIndices = $this->getExcludedIndices($tokens); |
113 | | - |
114 | | - $index = $tokens->count(); |
115 | | - while ($index > 1) { |
116 | | - $index--; |
117 | | - |
118 | | - /** @var Token $token */ |
119 | | - $token = $tokens[$index]; |
120 | | - |
121 | | - if (!$token->equalsAny($this->operators, false)) { |
122 | | - continue; |
123 | | - } |
124 | | - |
125 | | - if ($referenceAnalyzer->isReference($tokens, $index)) { |
126 | | - continue; |
127 | | - } |
128 | | - |
129 | | - if (\in_array($index, $excludedIndices, true)) { |
130 | | - continue; |
131 | | - } |
132 | | - |
133 | | - $operatorIndices = [$index]; |
134 | | - if ($token->equals(':')) { |
135 | | - /** @var int $prevIndex */ |
136 | | - $prevIndex = $tokens->getPrevMeaningfulToken($index); |
137 | | - |
138 | | - /** @var Token $prevToken */ |
139 | | - $prevToken = $tokens[$prevIndex]; |
140 | | - |
141 | | - if ($prevToken->equals('?')) { |
142 | | - $operatorIndices = [$prevIndex, $index]; |
143 | | - $index = $prevIndex; |
144 | | - } |
145 | | - } |
146 | | - |
147 | | - $this->fixOperatorLinebreak($tokens, $operatorIndices); |
148 | | - } |
149 | | - } |
150 | | - |
151 | | - /** |
152 | | - * Currently only colons from "switch". |
153 | | - * |
154 | | - * @return int[] |
155 | | - */ |
156 | | - private function getExcludedIndices(Tokens $tokens): array |
157 | | - { |
158 | | - $indices = []; |
159 | | - for ($index = $tokens->count() - 1; $index > 0; $index--) { |
160 | | - /** @var Token $token */ |
161 | | - $token = $tokens[$index]; |
162 | | - |
163 | | - if ($token->isGivenKind(T_SWITCH)) { |
164 | | - $indices = \array_merge($indices, $this->getCasesColonsForSwitch($tokens, $index)); |
165 | | - } |
166 | | - } |
167 | | - |
168 | | - return $indices; |
169 | | - } |
170 | | - |
171 | | - /** |
172 | | - * @return int[] |
173 | | - */ |
174 | | - private function getCasesColonsForSwitch(Tokens $tokens, int $switchIndex): array |
175 | | - { |
176 | | - return \array_map( |
177 | | - static function (CaseAnalysis $caseAnalysis): int { |
178 | | - return $caseAnalysis->getColonIndex(); |
179 | | - }, |
180 | | - (new SwitchAnalyzer())->getSwitchAnalysis($tokens, $switchIndex)->getCases() |
181 | | - ); |
182 | | - } |
183 | | - |
184 | | - /** |
185 | | - * @param non-empty-array<int> $operatorIndices |
186 | | - */ |
187 | | - private function fixOperatorLinebreak(Tokens $tokens, array $operatorIndices): void |
188 | | - { |
189 | | - /** @var int $minOperatorIndices */ |
190 | | - $minOperatorIndices = \min($operatorIndices); |
191 | | - |
192 | | - /** @var int $maxOperatorIndices */ |
193 | | - $maxOperatorIndices = \max($operatorIndices); |
194 | | - |
195 | | - /** @var int $prevIndex */ |
196 | | - $prevIndex = $tokens->getPrevMeaningfulToken($minOperatorIndices); |
197 | | - $indexStart = $prevIndex + 1; |
198 | | - |
199 | | - /** @var int $nextIndex */ |
200 | | - $nextIndex = $tokens->getNextMeaningfulToken($maxOperatorIndices); |
201 | | - $indexEnd = $nextIndex - 1; |
202 | | - |
203 | | - if (!$this->isMultiline($tokens, $indexStart, $indexEnd)) { |
204 | | - return; // operator is not surrounded by multiline whitespaces, do not touch it |
205 | | - } |
206 | | - |
207 | | - if ($this->position === 'beginning') { |
208 | | - if (!$this->isMultiline($tokens, $maxOperatorIndices, $indexEnd)) { |
209 | | - return; // operator already is placed correctly |
210 | | - } |
211 | | - $this->fixMoveToTheBeginning($tokens, $operatorIndices); |
212 | | - |
213 | | - return; |
214 | | - } |
215 | | - |
216 | | - if (!$this->isMultiline($tokens, $indexStart, $minOperatorIndices)) { |
217 | | - return; // operator already is placed correctly |
218 | | - } |
219 | | - $this->fixMoveToTheEnd($tokens, $operatorIndices); |
220 | | - } |
221 | | - |
222 | | - /** |
223 | | - * @param non-empty-array<int> $operatorIndices |
224 | | - */ |
225 | | - private function fixMoveToTheBeginning(Tokens $tokens, array $operatorIndices): void |
226 | | - { |
227 | | - /** @var int $minOperatorIndices */ |
228 | | - $minOperatorIndices = \min($operatorIndices); |
229 | | - |
230 | | - /** @var int $maxOperatorIndices */ |
231 | | - $maxOperatorIndices = \max($operatorIndices); |
232 | | - |
233 | | - /** @var int $prevIndex */ |
234 | | - $prevIndex = $tokens->getNonEmptySibling($minOperatorIndices, -1); |
235 | | - |
236 | | - /** @var Token $prevToken */ |
237 | | - $prevToken = $tokens[$prevIndex]; |
238 | | - |
239 | | - /** @var int $nextIndex */ |
240 | | - $nextIndex = $tokens->getNextMeaningfulToken($maxOperatorIndices); |
241 | | - |
242 | | - for ($i = $nextIndex - 1; $i > $maxOperatorIndices; $i--) { |
243 | | - /** @var Token $token */ |
244 | | - $token = $tokens[$i]; |
245 | | - |
246 | | - if ($token->isWhitespace() && Preg::match('/\R/u', $token->getContent()) === 1) { |
247 | | - $isWhitespaceBefore = $prevToken->isWhitespace(); |
248 | | - $inserts = $this->getReplacementsAndClear($tokens, $operatorIndices, -1); |
249 | | - if ($isWhitespaceBefore) { |
250 | | - $inserts[] = new Token([T_WHITESPACE, ' ']); |
251 | | - } |
252 | | - $tokens->insertAt($nextIndex, $inserts); |
253 | | - |
254 | | - break; |
255 | | - } |
256 | | - } |
| 70 | + $this->fixer->fix($file, $tokens); |
257 | 71 | } |
258 | 72 |
|
259 | 73 | /** |
260 | | - * @param non-empty-array<int> $operatorIndices |
| 74 | + * @return string[] |
261 | 75 | */ |
262 | | - private function fixMoveToTheEnd(Tokens $tokens, array $operatorIndices): void |
| 76 | + public function getSuccessorsNames(): array |
263 | 77 | { |
264 | | - /** @var int $minOperatorIndices */ |
265 | | - $minOperatorIndices = \min($operatorIndices); |
266 | | - |
267 | | - /** @var int $maxOperatorIndices */ |
268 | | - $maxOperatorIndices = \max($operatorIndices); |
269 | | - |
270 | | - /** @var int $prevIndex */ |
271 | | - $prevIndex = $tokens->getPrevMeaningfulToken($minOperatorIndices); |
272 | | - |
273 | | - /** @var int $nextIndex */ |
274 | | - $nextIndex = $tokens->getNonEmptySibling($maxOperatorIndices, 1); |
275 | | - |
276 | | - /** @var Token $nextToken */ |
277 | | - $nextToken = $tokens[$nextIndex]; |
278 | | - |
279 | | - for ($i = $prevIndex + 1; $i < $maxOperatorIndices; $i++) { |
280 | | - /** @var Token $token */ |
281 | | - $token = $tokens[$i]; |
282 | | - |
283 | | - if ($token->isWhitespace() && Preg::match('/\R/u', $token->getContent()) === 1) { |
284 | | - $isWhitespaceAfter = $nextToken->isWhitespace(); |
285 | | - $inserts = $this->getReplacementsAndClear($tokens, $operatorIndices, 1); |
286 | | - if ($isWhitespaceAfter) { |
287 | | - \array_unshift($inserts, new Token([T_WHITESPACE, ' '])); |
288 | | - } |
289 | | - $tokens->insertAt($prevIndex + 1, $inserts); |
290 | | - |
291 | | - break; |
292 | | - } |
293 | | - } |
294 | | - } |
295 | | - |
296 | | - /** |
297 | | - * @param int[] $indices |
298 | | - * |
299 | | - * @return Token[] |
300 | | - */ |
301 | | - private function getReplacementsAndClear(Tokens $tokens, array $indices, int $direction): array |
302 | | - { |
303 | | - return \array_map( |
304 | | - static function (int $index) use ($tokens, $direction): Token { |
305 | | - /** @var Token $token */ |
306 | | - $token = $tokens[$index]; |
307 | | - |
308 | | - /** @var Token $siblingToken */ |
309 | | - $siblingToken = $tokens[$index + $direction]; |
310 | | - |
311 | | - if ($siblingToken->isWhitespace()) { |
312 | | - $tokens->clearAt($index + $direction); |
313 | | - } |
314 | | - $tokens->clearAt($index); |
315 | | - |
316 | | - return $token; |
317 | | - }, |
318 | | - $indices |
319 | | - ); |
320 | | - } |
321 | | - |
322 | | - private function isMultiline(Tokens $tokens, int $indexStart, int $indexEnd): bool |
323 | | - { |
324 | | - for ($index = $indexStart; $index <= $indexEnd; $index++) { |
325 | | - /** @var Token $token */ |
326 | | - $token = $tokens[$index]; |
327 | | - |
328 | | - if (\strpos($token->getContent(), "\n") !== false) { |
329 | | - return true; |
330 | | - } |
331 | | - } |
332 | | - |
333 | | - return false; |
| 78 | + return [$this->fixer->getName()]; |
334 | 79 | } |
335 | 80 | } |
0 commit comments