1212 * with this source code in the file LICENSE.
1313 */
1414
15+ // PhpCsFixer\Fixer\Basic;
1516namespace NetteCodingStandard \Fixer \Basic ;
1617
1718use PhpCsFixer \AbstractFixer ;
1819use PhpCsFixer \Fixer \ConfigurableFixerInterface ;
20+ use PhpCsFixer \Fixer \ConfigurableFixerTrait ;
1921use PhpCsFixer \Fixer \Indentation ;
2022use PhpCsFixer \Fixer \WhitespacesAwareFixerInterface ;
2123use PhpCsFixer \FixerConfiguration \FixerConfigurationResolver ;
2426use PhpCsFixer \FixerDefinition \CodeSample ;
2527use PhpCsFixer \FixerDefinition \FixerDefinition ;
2628use PhpCsFixer \FixerDefinition \FixerDefinitionInterface ;
27- use PhpCsFixer \FixerDefinition \VersionSpecification ;
28- use PhpCsFixer \FixerDefinition \VersionSpecificCodeSample ;
2929use PhpCsFixer \Preg ;
3030use PhpCsFixer \Tokenizer \CT ;
3131use PhpCsFixer \Tokenizer \Token ;
3232use PhpCsFixer \Tokenizer \Tokens ;
3333use PhpCsFixer \Tokenizer \TokensAnalyzer ;
3434
35- final class CurlyBracesPositionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
35+ /**
36+ * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
37+ *
38+ * @phpstan-type _AutogeneratedInputConfiguration array{
39+ * allow_single_line_anonymous_functions?: bool,
40+ * allow_single_line_empty_anonymous_classes?: bool,
41+ * anonymous_classes_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
42+ * anonymous_functions_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
43+ * classes_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
44+ * control_structures_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
45+ * functions_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line'
46+ * }
47+ * @phpstan-type _AutogeneratedComputedConfiguration array{
48+ * allow_single_line_anonymous_functions: bool,
49+ * allow_single_line_empty_anonymous_classes: bool,
50+ * anonymous_classes_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
51+ * anonymous_functions_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
52+ * classes_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
53+ * control_structures_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
54+ * functions_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line'
55+ * }
56+ */
57+ final class BracesPositionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
3658{
59+ /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
60+ use ConfigurableFixerTrait;
61+
3762 use Indentation;
3863
3964 /**
@@ -46,13 +71,10 @@ final class CurlyBracesPositionFixer extends AbstractFixer implements Configurab
4671 */
4772 public const SAME_LINE = 'same_line ' ;
4873
49- /**
50- * {@inheritdoc}
51- */
5274 public function getDefinition (): FixerDefinitionInterface
5375 {
5476 return new FixerDefinition (
55- 'Curly braces must be placed as configured. ' ,
77+ 'Braces must be placed as configured. ' ,
5678 [
5779 new CodeSample (
5880 '<?php
@@ -70,15 +92,11 @@ function foo() {
7092{
7193 bar();
7294}
73- '
74- ),
75- new VersionSpecificCodeSample (
76- '<?php
95+
7796$foo = new class
7897{
7998};
80- ' ,
81- new VersionSpecification (70000 )
99+ '
82100 ),
83101 new CodeSample (
84102 '<?php
@@ -111,20 +129,18 @@ class Foo
111129 ' ,
112130 ['classes_opening_brace ' => self ::SAME_LINE ]
113131 ),
114- new VersionSpecificCodeSample (
132+ new CodeSample (
115133 '<?php
116134$foo = new class {
117135};
118136 ' ,
119- new VersionSpecification (70000 ),
120137 ['anonymous_classes_opening_brace ' => self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END ]
121138 ),
122- new VersionSpecificCodeSample (
139+ new CodeSample (
123140 '<?php
124141$foo = new class { };
125142$bar = new class { private $baz; };
126143 ' ,
127- new VersionSpecification (70000 ),
128144 ['allow_single_line_empty_anonymous_classes ' => true ]
129145 ),
130146 new CodeSample (
@@ -139,9 +155,6 @@ class Foo
139155 );
140156 }
141157
142- /**
143- * {@inheritdoc}
144- */
145158 public function isCandidate (Tokens $ tokens ): bool
146159 {
147160 return $ tokens ->isTokenKindFound ('{ ' );
@@ -150,16 +163,49 @@ public function isCandidate(Tokens $tokens): bool
150163 /**
151164 * {@inheritdoc}
152165 *
153- * Must run after ControlStructureBracesFixer.
166+ * Must run before SingleLineEmptyBodyFixer, StatementIndentationFixer.
167+ * Must run after ControlStructureBracesFixer, NoMultipleStatementsPerLineFixer.
154168 */
155169 public function getPriority (): int
156170 {
157- return parent ::getPriority ();
171+ return -2 ;
172+ }
173+
174+ /** @protected */
175+ public function createConfigurationDefinition (): FixerConfigurationResolverInterface
176+ {
177+ return new FixerConfigurationResolver ([
178+ (new FixerOptionBuilder ('control_structures_opening_brace ' , 'The position of the opening brace of control structures‘ body. ' ))
179+ ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
180+ ->setDefault (self ::SAME_LINE )
181+ ->getOption (),
182+ (new FixerOptionBuilder ('functions_opening_brace ' , 'The position of the opening brace of functions‘ body. ' ))
183+ ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
184+ ->setDefault (self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END )
185+ ->getOption (),
186+ (new FixerOptionBuilder ('anonymous_functions_opening_brace ' , 'The position of the opening brace of anonymous functions‘ body. ' ))
187+ ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
188+ ->setDefault (self ::SAME_LINE )
189+ ->getOption (),
190+ (new FixerOptionBuilder ('classes_opening_brace ' , 'The position of the opening brace of classes‘ body. ' ))
191+ ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
192+ ->setDefault (self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END )
193+ ->getOption (),
194+ (new FixerOptionBuilder ('anonymous_classes_opening_brace ' , 'The position of the opening brace of anonymous classes‘ body. ' ))
195+ ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
196+ ->setDefault (self ::SAME_LINE )
197+ ->getOption (),
198+ (new FixerOptionBuilder ('allow_single_line_empty_anonymous_classes ' , 'Allow anonymous classes to have opening and closing braces on the same line. ' ))
199+ ->setAllowedTypes (['bool ' ])
200+ ->setDefault (true )
201+ ->getOption (),
202+ (new FixerOptionBuilder ('allow_single_line_anonymous_functions ' , 'Allow anonymous functions to have opening and closing braces on the same line. ' ))
203+ ->setAllowedTypes (['bool ' ])
204+ ->setDefault (true )
205+ ->getOption (),
206+ ]);
158207 }
159208
160- /**
161- * {@inheritdoc}
162- */
163209 protected function applyFix (\SplFileInfo $ file , Tokens $ tokens ): void
164210 {
165211 $ classyTokens = Token::getClassyTokenKinds ();
@@ -181,7 +227,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
181227 $ openBraceIndex = $ tokens ->getNextTokenOfKind ($ index , ['{ ' ]);
182228
183229 if ($ tokensAnalyzer ->isAnonymousClass ($ index )) {
184- $ allowSingleLineIfEmpty = $ this ->configuration ['allow_single_line_empty_anonymous_classes ' ];
230+ $ allowSingleLineIfEmpty = true === $ this ->configuration ['allow_single_line_empty_anonymous_classes ' ];
185231 $ positionOption = 'anonymous_classes_opening_brace ' ;
186232 } else {
187233 $ positionOption = 'classes_opening_brace ' ;
@@ -194,7 +240,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
194240 }
195241
196242 if ($ tokensAnalyzer ->isLambda ($ index )) {
197- $ allowSingleLine = $ this ->configuration ['allow_single_line_anonymous_functions ' ];
243+ $ allowSingleLine = true === $ this ->configuration ['allow_single_line_anonymous_functions ' ];
198244 $ positionOption = 'anonymous_functions_opening_brace ' ;
199245 } else {
200246 $ positionOption = 'functions_opening_brace ' ;
@@ -223,7 +269,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
223269
224270 if (
225271 ($ allowSingleLineIfEmpty && !$ tokenInsideBraces ->isWhitespace () && !$ tokenInsideBraces ->isComment ())
226- || ($ tokenInsideBraces ->isWhitespace () && 1 === Preg::match ('/\R/ ' , $ tokenInsideBraces ->getContent ()))
272+ || ($ tokenInsideBraces ->isWhitespace () && Preg::match ('/\R/ ' , $ tokenInsideBraces ->getContent ()))
227273 ) {
228274 $ addNewlinesInsideBraces = true ;
229275
@@ -252,20 +298,18 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
252298 if (self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END === $ this ->configuration [$ positionOption ]) {
253299 $ whitespace = $ this ->whitespacesConfig ->getLineEnding ().$ this ->getLineIndentation ($ tokens , $ index );
254300
255- $ colon = false ;
256301 $ previousTokenIndex = $ openBraceIndex ;
257302 do {
258303 $ previousTokenIndex = $ tokens ->getPrevMeaningfulToken ($ previousTokenIndex );
259- $ colon = $ colon || $ tokens [$ previousTokenIndex ]->isGivenKind ([CT ::T_TYPE_COLON ]);
260- } while ($ tokens [$ previousTokenIndex ]->isGivenKind ([CT ::T_TYPE_COLON , CT ::T_NULLABLE_TYPE , T_STRING , T_NS_SEPARATOR , CT ::T_ARRAY_TYPEHINT , T_STATIC , CT ::T_TYPE_ALTERNATION , CT ::T_TYPE_INTERSECTION ]));
304+ } while ($ tokens [$ previousTokenIndex ]->isGivenKind ([CT ::T_TYPE_COLON , CT ::T_NULLABLE_TYPE , T_STRING , T_NS_SEPARATOR , CT ::T_ARRAY_TYPEHINT , T_STATIC , CT ::T_TYPE_ALTERNATION , CT ::T_TYPE_INTERSECTION , T_CALLABLE , CT ::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN , CT ::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE ]));
261305
262- if (! $ colon && $ tokens [$ previousTokenIndex ]->equals (') ' )) {
306+ if ($ tokens [$ previousTokenIndex ]->equals (') ' )) {
263307 if ($ tokens [--$ previousTokenIndex ]->isComment ()) {
264308 --$ previousTokenIndex ;
265309 }
266310 if (
267311 $ tokens [$ previousTokenIndex ]->isWhitespace ()
268- && 1 === Preg::match ('/\R/ ' , $ tokens [$ previousTokenIndex ]->getContent ())
312+ && Preg::match ('/\R/ ' , $ tokens [$ previousTokenIndex ]->getContent ())
269313 ) {
270314 $ whitespace = ' ' ;
271315 }
@@ -314,7 +358,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
314358 } else {
315359 $ tokens ->clearAt ($ openBraceIndex + 1 );
316360 }
317- } else {
361+ } elseif ( $ tokens [ $ openBraceIndex - 1 ]-> isWhitespace ()) {
318362 $ tokens ->clearAt ($ openBraceIndex - 1 );
319363 }
320364 }
@@ -344,10 +388,14 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
344388 continue ;
345389 }
346390
347- for ($ prevIndex = $ closeBraceIndex - 1 ; $ tokens ->isEmptyAt ($ prevIndex ); --$ prevIndex );
391+ $ prevIndex = $ closeBraceIndex - 1 ;
392+ while ($ tokens ->isEmptyAt ($ prevIndex )) {
393+ --$ prevIndex ;
394+ }
348395
349396 $ prevToken = $ tokens [$ prevIndex ];
350- if ($ prevToken ->isWhitespace () && 1 === Preg::match ('/\R/ ' , $ prevToken ->getContent ())) {
397+
398+ if ($ prevToken ->isWhitespace () && Preg::match ('/\R/ ' , $ prevToken ->getContent ())) {
351399 continue ;
352400 }
353401
@@ -356,43 +404,6 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
356404 }
357405 }
358406
359- /**
360- * {@inheritdoc}
361- */
362- protected function createConfigurationDefinition (): FixerConfigurationResolverInterface
363- {
364- return new FixerConfigurationResolver ([
365- (new FixerOptionBuilder ('control_structures_opening_brace ' , 'the position of the opening brace of control structures body. ' ))
366- ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
367- ->setDefault (self ::SAME_LINE )
368- ->getOption (),
369- (new FixerOptionBuilder ('functions_opening_brace ' , 'the position of the opening brace of functions body. ' ))
370- ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
371- ->setDefault (self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END )
372- ->getOption (),
373- (new FixerOptionBuilder ('anonymous_functions_opening_brace ' , 'the position of the opening brace of anonymous functions body. ' ))
374- ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
375- ->setDefault (self ::SAME_LINE )
376- ->getOption (),
377- (new FixerOptionBuilder ('classes_opening_brace ' , 'the position of the opening brace of classes body. ' ))
378- ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
379- ->setDefault (self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END )
380- ->getOption (),
381- (new FixerOptionBuilder ('anonymous_classes_opening_brace ' , 'the position of the opening brace of anonymous classes body. ' ))
382- ->setAllowedValues ([self ::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END , self ::SAME_LINE ])
383- ->setDefault (self ::SAME_LINE )
384- ->getOption (),
385- (new FixerOptionBuilder ('allow_single_line_empty_anonymous_classes ' , 'allow anonymous classes to have opening and closing braces on the same line. ' ))
386- ->setAllowedTypes (['bool ' ])
387- ->setDefault (true )
388- ->getOption (),
389- (new FixerOptionBuilder ('allow_single_line_anonymous_functions ' , 'allow anonymous functions to have opening and closing braces on the same line. ' ))
390- ->setAllowedTypes (['bool ' ])
391- ->setDefault (true )
392- ->getOption (),
393- ]);
394- }
395-
396407 private function findParenthesisEnd (Tokens $ tokens , int $ structureTokenIndex ): int
397408 {
398409 $ nextIndex = $ tokens ->getNextMeaningfulToken ($ structureTokenIndex );
@@ -411,7 +422,7 @@ private function isFollowedByNewLine(Tokens $tokens, int $index): bool
411422 for (++$ index , $ max = \count ($ tokens ) - 1 ; $ index < $ max ; ++$ index ) {
412423 $ token = $ tokens [$ index ];
413424 if (!$ token ->isComment ()) {
414- return $ token ->isWhitespace () && 1 === Preg::match ('/\R/ ' , $ token ->getContent ());
425+ return $ token ->isWhitespace () && Preg::match ('/\R/ ' , $ token ->getContent ());
415426 }
416427 }
417428
@@ -422,15 +433,10 @@ private function hasCommentOnSameLine(Tokens $tokens, int $index): bool
422433 {
423434 $ token = $ tokens [$ index + 1 ];
424435
425- if ($ token ->isWhitespace () && 1 !== Preg::match ('/\R/ ' , $ token ->getContent ())) {
436+ if ($ token ->isWhitespace () && ! Preg::match ('/\R/ ' , $ token ->getContent ())) {
426437 $ token = $ tokens [$ index + 2 ];
427438 }
428439
429440 return $ token ->isComment ();
430441 }
431-
432- public function getName (): string
433- {
434- return 'Nette/ ' . parent ::getName ();
435- }
436442}
0 commit comments