8000 Add rule for converting Enum cases to PascalCase naming · rectorphp/rector-src@65f2803 · GitHub
[go: up one dir, main page]

Skip to content

Commit 65f2803

Browse files
committed
Add rule for converting Enum cases to PascalCase naming
1 parent 3be6fd7 commit 65f2803

File tree

19 files changed

+453
-0
lines changed

19 files changed

+453
-0
lines changed

.github/workflows/e2e.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
- 'e2e/applied-rule-removed-node'
3333
- 'e2e/parallel with space'
3434
- 'e2e/different-path-over-skip-config'
35+
- 'e2e/enum-case-post-rector'
3536
- 'e2e/invalid-paths'
3637
- 'e2e/applied-polyfill-php80'
3738
- 'e2e/print-new-node'

e2e/enum-case-post-rector/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/vendor
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"require": {
3+
"php": "^8.1"
4+
}
5+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
3 files with changes
2+
====================
3+
4+
1) src/Module1/Status.php:4
5+
6+
---------- begin diff ----------
7+
@@ @@
8+
9+
enum Status
10+
{
11+
- case APPROVED;
12+
+ case Approved;
13+
}
14+
----------- end diff -----------
15+
16+
Applied rules:
17+
* EnumCaseToPascalCaseRector
18+
19+
20+
2) src/Module1/Usage1.php:6
21+
22+
---------- begin diff ----------
23+
@@ @@
24+
{
25+
public function isValid(Status $status): bool
26+
{
27+
- return $status === Status::APPROVED;
28+
+ return $status === Status::Approved;
29+
}
30+
}
31+
----------- end diff -----------
32+
33+
3) src/Module1/Usage1_with_alias.php:8
34+
35+
---------- begin diff ----------
36+
@@ @@
37+
{
38+
public function isValid(StatusAlias $status): bool
39+
{
40+
- return $status === StatusAlias::APPROVED;
41+
+ return $status === StatusAlias::Approved;
42+
}
43+
}
44+
----------- end diff -----------
45+
46+
[OK] 3 files would have been changed (dry-run) by Rector
47+

e2e/enum-case-post-rector/rector.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
7+
return static function (RectorConfig $rectorConfig): void {
8+
$rectorConfig->paths([
9+
__DIR__ . '/src/Module1',
10+
]);
11+
12+
$rectorConfig->rule(\Rector\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector::class);
13+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Rector\Tests\e2e\EnumCasePostRector\Module1;
4+
5+
enum Status
6+
{
7+
case APPROVED;
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Rector\Tests\e2e\EnumCasePostRector\Module1;
4+
5+
class Usage1
6+
{
7+
public function isValid(Status $status): bool
8+
{
9+
return $status === Status::APPROVED;
10+
}
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Rector\Tests\e2e\EnumCasePostRector\Module1;
4+
5+
use Rector\Tests\e2e\EnumCasePostRector\Module1\Status as StatusAlias;
6+
7+
class Usage1
8+
{
9+
public function isValid(StatusAlias $status): bool
10+
{
11+
return $status === StatusAlias::APPROVED;
12+
}
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Rector\Tests\e2e\EnumCasePostRector\Module1;
4+
5+
class Usage2
6+
{
7+
public function isValid(\Rector\Tests\e2e\EnumCasePostRector\Module2\Status $status): bool
8+
{
9+
return $status === \Rector\Tests\e2e\EnumCasePostRector\Module2\Status::APPROVED;
10+
}
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Rector\Tests\e2e\EnumCasePostRector\Module2;
4+
5+
enum Status
6+
{
7+
case APPROVED;
8+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class EnumCaseToPascalCaseRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 27 additions & 0 deletions
< F438 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
4+
5+
enum Status
6+
{
7+
case PENDING;
8+
case published;
9+
case IN_REVIEW;
10+
case waiting_for_approval;
11+
}
12+
13+
?>
14+
-----
15+
<?php
16+
17+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
18+
19+
enum Status
20+
{
21+
case Pending;
22+
case Published;
23+
case InReview;
24+
case WaitingForApproval;
25+
}
26+
27+
?>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
4+
5+
enum Status
6+
{
7+
case PENDING;
8+
}
9+
10+
class EnumUsage {
11+
public function isValid(Status $status): bool {
12+
return $status === Status::PENDING;
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
21+
22+
enum Status
23+
{
24+
case Pending;
25+
}
26+
27+
class EnumUsage {
28+
public function isValid(Status $status): bool {
29+
return $status === Status::Pending;
30+
}
31+
}
32+
33+
?>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
4+
5+
use Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture\Status as StatusAlias;
6+
7+
enum Status
8+
{
9+
case PENDING;
10+
}
11+
12+
class EnumUsage {
13+
public function isValid(StatusAlias $status): bool {
14+
return $status === StatusAlias::PENDING;
15+
}
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
23+
24+
use Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture\Status as StatusAlias;
25+
26+
enum Status
27+
{
28+
case Pending;
29+
}
30+
31+
class EnumUsage {
32+
public function isValid(StatusAlias $status): bool {
33+
return $status === StatusAlias::Pending;
34+
}
35+
}
36+
37+
?>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector;
6+
use Rector\Config\RectorConfig;
7+
8+
return RectorConfig::configure()
9+
->withRules([EnumCaseToPascalCaseRector::class]);
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\CodingStyle\Rector\Enum_;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Identifier;
9+
use PhpParser\Node\Stmt\Enum_;
10+
use PhpParser\Node\Stmt\EnumCase;
11+
use Rector\Rector\AbstractRector;
12+
use Rector\Renaming\Collector\RenamedEnumCaseCollector;
13+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
14+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
15+
16+
/**
17 10000 +
* @see \Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\EnumCaseToPascalCaseRectorTest
18+
*/
19+
final class EnumCaseToPascalCaseRector extends AbstractRector
20+
{
21+
public function __construct(
22+
private readonly RenamedEnumCaseCollector $renamedEnumCaseCollector,
23+
) {
24+
}
25+
26+
public function getRuleDefinition(): RuleDefinition
27+
{
28+
return new RuleDefinition(
29+
'Convert enum cases to PascalCase and update their usages',
30+
[
31+
new CodeSample(
32+
<<<'CODE_SAMPLE'
33+
enum Status
34+
{
35+
case PENDING;
36+
case published;
37+
case IN_REVIEW;
38+
case waiting_for_approval;
39+
}
40+
CODE_SAMPLE
41+
,
42+
<<<'CODE_SAMPLE'
43+
enum Status
44+
{
45+
case Pending;
46+
case Published;
47+
case InReview;
48+
case WaitingForApproval;
49+
}
50+
CODE_SAMPLE
51+
),
52+
]
53+
);
54+
}
55+
56+
public function getNodeTypes(): array
57+
{
58+
return [Enum_::class];
59+
}
60+
61+
/**
62 10000 +
* @param Enum_ $node
63+
*/
64+
public function refactor(Node $node): ?Node
65+
{
66+
$enumName = $this->getName($node);
67+
if ($enumName === null) {
68+
return null;
69+
}
70+
71+
$hasChanged = false;
72+
73+
foreach ($node->stmts as $stmt) {
74+
if (! $stmt instanceof EnumCase) {
75+
continue;
76+
}
77+
78+
$currentName = $stmt->name->toString();
79+
$pascalCaseName = $this->convertToPascalCase($currentName);
80+
81+
if ($currentName === $pascalCaseName) {
82+
continue;
83+
}
84+
85+
$stmt->name = new Identifier($pascalCaseName);
86+
$hasChanged = true;
87+
}
88+
89+
if ($hasChanged) {
90+
$this->renamedEnumCaseCollector->add($enumName);
91+
return $node;
92+
}
93+
94+
return null;
95+
}
96+
97+
private function convertToPascalCase(string $name): string
98+
{
99+
$parts = explode('_', strtolower($name));
100+
return implode('', array_map(ucfirst(...), $parts));
101+
}
102+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Renaming\Collector;
6+
7+
final class RenamedEnumCaseCollector
8+
{
9+
/**
10+
* @var string[]
11+
*/
12+
private array $names = [];
13+
14+
public function add(string $name): void
15+
{
16+
$this->names[] = $name;
17+
}
18+
19+
public function has(string $name): bool
20+
{
21+
return in_array($name, $this->names, true);
22+
}
23+
}

0 commit comments

Comments
 (0)
0