Skip to content

Commit

Permalink
[Enum] Add DowngradeEnumToConstantListClassRector
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Jun 2, 2022
1 parent a73dafd commit 372cd32
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 0 deletions.
1 change: 1 addition & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,4 @@ parameters:
# optional rule for PHP 8.0
- '#Register "Rector\\Php80\\Rector\\Class_\\ConstantListClassToEnumRector" service to "php80\.php" config set#'
- '#Rule Rector\\Php80\\Rector\\Class_\\ConstantListClassToEnumRector must implements Rector\\VersionBonding\\Contract\\MinPhpVersionInterface#'
- '#Register "Rector\\DowngradePhp80\\Rector\\Enum_\\DowngradeEnumToConstantListClassRector" service to "downgrade\-php80\.php" config set#'
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\DowngradePhp80\Rector\Enum_\DowngradeEnumToConstantListClassRector;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

final class DowngradeEnumToConstantListClassRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}

/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Rector\Tests\DowngradePhp80\Rector\Enum_\DowngradeEnumToConstantListClassRector\Fixture;

enum Direction
{
case LEFT;

case RIGHT;
}

?>
-----
<?php

namespace Rector\Tests\DowngradePhp80\Rector\Enum_\DowngradeEnumToConstantListClassRector\Fixture;

class Direction
{
public const LEFT = 'left';
public const RIGHT = 'right';
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\DowngradePhp80\Rector\Enum_\DowngradeEnumToConstantListClassRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rule(DowngradeEnumToConstantListClassRector::class);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Rector\DowngradePhp80\Rector\Enum_;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Enum_;
use Rector\Core\Rector\AbstractRector;
use Rector\Php81\NodeFactory\ClassFromEnumFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \Rector\Tests\DowngradePhp80\Rector\Enum_\DowngradeEnumToConstantListClassRector\DowngradeEnumToConstantListClassRectorTest
*/
final class DowngradeEnumToConstantListClassRector extends AbstractRector
{
public function __construct(
private readonly ClassFromEnumFactory $classFromEnumFactory
) {
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Downgrade enum to constant list class', [
new CodeSample(
<<<'CODE_SAMPLE'
enum Direction
{
case LEFT;
case RIGHT;
}
CODE_SAMPLE

,
<<<'CODE_SAMPLE'
class Direction
{
public const LEFT = 'left';
public const RIGHT = 'right';
}
CODE_SAMPLE
),
]);
}

/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Enum_::class];
}

/**
* @param Enum_ $node
*/
public function refactor(Node $node): Class_
{
return $this->classFromEnumFactory->createFromEnum($node);
}
}
62 changes: 62 additions & 0 deletions rules/Php81/NodeFactory/ClassFromEnumFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace Rector\Php81\NodeFactory;

use PhpParser\Node\Const_;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\Enum_;
use PhpParser\Node\Stmt\EnumCase;
use Rector\Core\ValueObject\Visibility;
use Rector\NodeNameResolver\NodeNameResolver;

final class ClassFromEnumFactory
{
public function __construct(
private readonly NodeNameResolver $nodeNameResolver
) {
}

public function createFromEnum(Enum_ $enum): Class_
{
$shortClassName = $this->nodeNameResolver->getShortName($enum);

$classConsts = [];
foreach ($enum->stmts as $stmt) {
if (! $stmt instanceof EnumCase) {
continue;
}

$constValue = $this->createConstValue($stmt);

$classConsts[] = new ClassConst([new Const_($stmt->name, $constValue)], Visibility::PUBLIC);
}

$class = new Class_($shortClassName, [
'stmts' => $classConsts,
]);

$class->namespacedName = $enum->namespacedName;

return $class;
}

private function createConstValue(EnumCase $enumCase): Expr
{
if ($enumCase->expr instanceof Expr) {
return $enumCase->expr;
}

/** @var string $enumName */
$enumName = $this->nodeNameResolver->getName($enumCase);

// minimal convention
$lowercasedEnumValue = strtolower($enumName);

return new String_($lowercasedEnumValue);
}
}

0 comments on commit 372cd32

Please sign in to comment.