Skip to content

Commit 414b4c0

Browse files
committed
Add AttributesNewLineFixer
1 parent 0d5954b commit 414b4c0

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Ticketswap\PhpCsFixerConfig\Fixer;
6+
7+
use Override;
8+
use PhpCsFixer\AbstractFixer;
9+
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
10+
use PhpCsFixer\FixerDefinition\FixerDefinition;
11+
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
12+
use PhpCsFixer\FixerDefinition\VersionSpecification;
13+
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
14+
use PhpCsFixer\Tokenizer\CT;
15+
use PhpCsFixer\Tokenizer\Tokens;
16+
use SplFileInfo;
17+
18+
/**
19+
* TODO https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/pull/8695 wait for this be merged, and then use the official version.
20+
*/
21+
final class AttributesNewLineFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
22+
{
23+
#[Override]
24+
public function isCandidate(Tokens $tokens) : bool
25+
{
26+
return $tokens->isTokenKindFound(T_ATTRIBUTE);
27+
}
28+
29+
#[Override]
30+
public function getDefinition() : FixerDefinitionInterface
31+
{
32+
return new FixerDefinition(
33+
'Attributes should be on their own line.',
34+
[
35+
new VersionSpecificCodeSample(
36+
"<?php
37+
#[Foo] #[Bar] class Baz
38+
{
39+
}\n",
40+
new VersionSpecification(8_00_00),
41+
),
42+
new VersionSpecificCodeSample(
43+
"<?php
44+
#[Foo] class Bar
45+
{
46+
#[Baz] public function foo() {}
47+
}\n",
48+
new VersionSpecification(8_00_00),
49+
),
50+
new VersionSpecificCodeSample(
51+
"<?php
52+
#[Foo] class Bar
53+
{
54+
#[Test] public const TEST = 'Test';
55+
}\n",
56+
new VersionSpecification(8_00_00),
57+
),
58+
],
59+
);
60+
}
61+
62+
#[Override]
63+
protected function applyFix(SplFileInfo $file, Tokens $tokens) : void
64+
{
65+
$count = $tokens->count();
66+
for ($index = $count - 1; $index >= 0; --$index) {
67+
if ($tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
68+
$this->fixNewline($tokens, $index);
69+
}
70+
}
71+
}
72+
73+
private function fixNewline(Tokens $tokens, int $endIndex) : void
74+
{
75+
$nextIndex = $endIndex + 1;
76+
77+
if ($tokens[$nextIndex]->isWhitespace()) {
78+
$whitespace = $tokens[$nextIndex]->getContent();
79+
80+
if (str_contains($whitespace, "\n") || str_contains($whitespace, "\r")) {
81+
return;
82+
}
83+
84+
$tokens->clearAt($nextIndex);
85+
}
86+
87+
$indentation = $this->getIndentation($tokens, $endIndex);
88+
89+
$tokens->ensureWhitespaceAtIndex(
90+
$endIndex + 1,
91+
0,
92+
$this->whitespacesConfig->getLineEnding() . $indentation,
93+
);
94+
}
95+
96+
private function getIndentation(Tokens $tokens, int $attributeEndIndex) : string
97+
{
98+
$nextMeaningfulIndex = $tokens->getNextMeaningfulToken($attributeEndIndex);
99+
100+
if ($nextMeaningfulIndex === null || $tokens[$nextMeaningfulIndex]->isGivenKind([T_CLASS])) {
101+
return '';
102+
}
103+
104+
$searchIndex = $nextMeaningfulIndex;
105+
106+
do {
107+
$prevWhitespaceIndex = $tokens->getPrevTokenOfKind(
108+
$searchIndex,
109+
[[T_ENCAPSED_AND_WHITESPACE], [T_INLINE_HTML], [T_WHITESPACE]],
110+
);
111+
112+
$searchIndex = $prevWhitespaceIndex;
113+
} while ($prevWhitespaceIndex !== null
114+
&& ! str_contains($tokens[$prevWhitespaceIndex]->getContent(), "\n")
115+
);
116+
117+
if ($prevWhitespaceIndex === null) {
118+
return '';
119+
}
120+
121+
$whitespaceContent = $tokens[$prevWhitespaceIndex]->getContent();
122+
123+
if (str_contains($whitespaceContent, "\n")) {
124+
$lastNewLinePos = strrpos($whitespaceContent, "\n");
125+
126+
if ($lastNewLinePos === false) {
127+
return '';
128+
}
129+
130+
return substr($whitespaceContent, $lastNewLinePos + 1);
131+
}
132+
133+
return $whitespaceContent;
134+
}
135+
}

src/RuleSet/TicketSwapRuleSet.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symplify\CodingStandard\TokenRunner\Traverser\ArrayBlockInfoFinder;
2626
use Symplify\CodingStandard\TokenRunner\Whitespace\IndentResolver;
2727
use Symplify\CodingStandard\TokenRunner\Wrapper\FixerWrapper\ArrayWrapperFactory;
28+
use Ticketswap\PhpCsFixerConfig\Fixer\AttributesNewLineFixer;
2829
use Ticketswap\PhpCsFixerConfig\Fixers;
2930
use Ticketswap\PhpCsFixerConfig\NameWrapper;
3031
use Ticketswap\PhpCsFixerConfig\Rules;
@@ -54,6 +55,7 @@ public static function create() : RuleSet
5455
return new RuleSet(
5556
new Fixers(
5657
new LineBreakAfterStatementsFixer(),
58+
new NameWrapper(new AttributesNewLineFixer()),
5759
new NameWrapper(new ArrayListItemNewlineFixer($arrayItemNewliner, $arrayAnalyzer, $arrayBlockInfoFinder)),
5860
new NameWrapper(new ArrayOpenerAndCloserNewlineFixer($arrayBlockInfoFinder, $whitespacesFixerConfig, $arrayAnalyzer)),
5961
new NameWrapper(new StandaloneLineInMultilineArrayFixer($arrayWrapperFactory, $tokensNewliner, $blockfinder)),

0 commit comments

Comments
 (0)