Skip to content

Commit

Permalink
[PHP 8.1] Add MyClabs enum to native ENUM (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba authored May 14, 2021
1 parent 903dfab commit f2c0023
Show file tree
Hide file tree
Showing 17 changed files with 422 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# testing Windows spaces - https://help.github.com/en/github/using-git/configuring-git-to-handle-line-endings
packages-tests/FileFormatter/ValueObject/Fixture/composer_carriage_return_line_feed.json json eol=crlf
2 changes: 1 addition & 1 deletion build/target-repository/.gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ docs/images export-ignore

# testing Windows spaces - https://help.github.com/en/github/using-git/configuring-git-to-handle-line-endings
packages/better-php-doc-parser/tests/PhpDocInfo/PhpDocInfoPrinter/FixtureBasic/with_spac.txt text eol=crlf
packages-tests/FileFormatter/ValueObject/Fixture/composer_carriage_return_line_feed.json json eol=crlf

1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"classmap": [
"stubs/Annotations",
"stubs/Nette",
"stubs/MyCLabs",
"rules-tests/Autodiscovery/Rector/Class_/MoveServicesBySuffixToDirectoryRector/Expected",
"rules-tests/Autodiscovery/Rector/Interface_/MoveInterfacesToContractNamespaceDirectoryRector/Expected",
"rules-tests/CodingStyle/Rector/Namespace_/ImportFullyQualifiedNamesRector/Source",
Expand Down
4 changes: 4 additions & 0 deletions config/set/php81.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

declare(strict_types=1);

use Rector\Php81\Rector\Class_\MyCLabsClassToEnumRector;
use Rector\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ReturnNeverTypeRector::class);
$services->set(MyCLabsClassToEnumRector::class);
$services->set(MyCLabsMethodCallToEnumConstRector::class);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Rector\Tests\Php81\Rector\Class_\MyCLabsClassToEnumRector\Fixture;

use MyCLabs\Enum\Enum;

/**
* @method static PrivateConstWithStaticMethod VIDEO()
*/
final class PrivateConstWithStaticMethod extends Enum
{
/**
* Some comment
*/
private const VIDEO = 'video';
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\Class_\MyCLabsClassToEnumRector\Fixture;

use MyCLabs\Enum\Enum;

enum PrivateConstWithStaticMethod
{
/**
* Some comment
*/
case VIDEO = 'video';
}

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

namespace Rector\Tests\Php81\Rector\Class_\MyCLabsClassToEnumRector\Fixture;

use MyCLabs\Enum\Enum;

final class SomeClass extends Enum
{
/**
* Some comment
*/
private const VIEW = 'view';

private const EDIT = 'edit';
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\Class_\MyCLabsClassToEnumRector\Fixture;

use MyCLabs\Enum\Enum;

enum SomeClass
{
/**
* Some comment
*/
case VIEW = 'view';
case EDIT = 'edit';
}

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

declare(strict_types=1);

namespace Rector\Tests\Php81\Rector\Class_\MyCLabsClassToEnumRector;

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

final class MyCLabsClassToEnumRectorTest 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,11 @@
<?php

declare(strict_types=1);

use Rector\Php81\Rector\Class_\MyCLabsClassToEnumRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(MyCLabsClassToEnumRector::class);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Fixture;

use Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum;

final class UsageOfConstant
{
public function run($value)
{
$compare = SomeEnum::VALUE()->getKey();
}
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Fixture;

use Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum;

final class UsageOfConstant
{
public function run($value)
{
$compare = \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::VALUE;
}
}

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

declare(strict_types=1);

namespace Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector;

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

final class MyCLabsMethodCallToEnumConstRectorTest 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,15 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source;

use MyCLabs\Enum\Enum;

/**
* @method SomeEnum VALUE()
*/
final class SomeEnum extends Enum
{
const VALUE = 'value';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

use Rector\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(MyCLabsMethodCallToEnumConstRector::class);
};
12 changes: 4 additions & 8 deletions rules/Composer/ValueObject/RenamePackage.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@

final class RenamePackage
{
private string $oldPackageName;

private string $newPackageName;

public function __construct(string $oldPackageName, string $newPackageName)
{
$this->oldPackageName = $oldPackageName;
$this->newPackageName = $newPackageName;
public function __construct(
private string $oldPackageName,
private string $newPackageName
) {
}

public function getOldPackageName(): string
Expand Down
45 changes: 45 additions & 0 deletions rules/Php81/NodeFactory/EnumFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace Rector\Php81\NodeFactory;

use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\Enum_;
use PhpParser\Node\Stmt\EnumCase;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;

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

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

// constant to cases
foreach ($class->getConstants() as $classConst) {
$enum->stmts[] = $this->createEnumCase($classConst);
}

return $enum;
}

private function createEnumCase(ClassConst $classConst): EnumCase
{
$constConst = $classConst->consts[0];
$enumCase = new EnumCase($constConst->name, $constConst->value);

// mirrow comments
$enumCase->setAttribute(AttributeKey::PHP_DOC_INFO, $classConst->getAttribute(AttributeKey::PHP_DOC_INFO));
$enumCase->setAttribute(AttributeKey::COMMENTS, $classConst->getAttribute(AttributeKey::COMMENTS));

return $enumCase;
}
}
73 changes: 73 additions & 0 deletions rules/Php81/Rector/Class_/MyCLabsClassToEnumRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

declare(strict_types=1);

namespace Rector\Php81\Rector\Class_;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use Rector\Core\Rector\AbstractRector;
use Rector\Php81\NodeFactory\EnumFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @changelog https://wiki.php.net/rfc/enumerations
* @changelog https://github.com/myclabs/php-enum
*
* @see \Rector\Tests\Php81\Rector\Class_\MyCLabsClassToEnumRector\MyCLabsClassToEnumRectorTest
*/
final class MyCLabsClassToEnumRector extends AbstractRector
{
public function __construct(
private EnumFactory $enumFactory
) {
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Refactor MyCLabs enum class to native Enum', [
new CodeSample(
<<<'CODE_SAMPLE'
use MyCLabs\Enum\Enum;
final class Action extends Enum
{
private const VIEW = 'view';
private const EDIT = 'edit';
}
CODE_SAMPLE

,
<<<'CODE_SAMPLE'
enum Action
{
case VIEW = 'view';
case EDIT = 'edit';
}
CODE_SAMPLE
),
]);
}

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

/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isObjectType($node, new ObjectType('MyCLabs\Enum\Enum'))) {
return null;
}

return $this->enumFactory->createFromClass($node);
}
}
Loading

0 comments on commit f2c0023

Please sign in to comment.