Skip to content

Commit

Permalink
Allows to convert Spatie enum names to snake upper case (#5435)
Browse files Browse the repository at this point in the history
* allows to convert Spatie enum names to snake upper case through toUpperSnakeCase configuration

* - adds a new Fixture for upper case enum names
- rebase main

* fix cs related errors

* fix phpstan related errors

* move regexp to a class constant and add links to regex101.com

* renames constant
  • Loading branch information
JoolsMcFly committed Jan 6, 2024
1 parent a8cc19a commit 86e7402
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

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

use Spatie\Enum\Enum;

/**
* @method static self isOK()
* @method static self needsReview()
* @method static self isV2()
* @method static self IS_OBSOLETE()
*/
class StatusEnum extends Enum
{
}

?>
-----
<?php

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

use Spatie\Enum\Enum;

enum StatusEnum : string
{
case ISOK = 'isOK';
case NEEDSREVIEW = 'needsReview';
case ISV2 = 'isV2';
case IS_OBSOLETE = 'IS_OBSOLETE';
}

?>
28 changes: 24 additions & 4 deletions rules/Php81/NodeFactory/EnumFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Rector\Php81\NodeFactory;

use Nette\Utils\Strings;
use PhpParser\BuilderFactory;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
Expand All @@ -26,6 +27,15 @@

final readonly class EnumFactory
{
/**
* @var string
* @see https://stackoverflow.com/a/2560017
* @see https://regex101.com/r/2xEQVj/1 for changing iso9001 to iso_9001
* @see https://regex101.com/r/Ykm6ub/1 for changing XMLParser to XML_Parser
* @see https://regex101.com/r/Zv4JhD/1 for changing needsReview to needs_Review
*/
private const PASCAL_CASE_TO_UNDERSCORE_REGEX = '/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[^A-Z])(?=[A-Z])|(?<=[A-Za-z])(?=[^A-Za-z])/';

public function __construct(
private NodeNameResolver $nodeNameResolver,
private PhpDocInfoFactory $phpDocInfoFactory,
Expand Down Expand Up @@ -65,7 +75,7 @@ public function createFromClass(Class_ $class): Enum_
return $enum;
}

public function createFromSpatieClass(Class_ $class): Enum_
public function createFromSpatieClass(Class_ $class, bool $enumNameInSnakeCase = false): Enum_
{
$shortClassName = $this->nodeNameResolver->getShortName($class);
$enum = new Enum_($shortClassName, [], [
Expand All @@ -84,7 +94,12 @@ public function createFromSpatieClass(Class_ $class): Enum_
$enum->scalarType = new Identifier($identifierType);

foreach ($docBlockMethods as $docBlockMethod) {
$enum->stmts[] = $this->createEnumCaseFromDocComment($docBlockMethod, $class, $mapping);
$enum->stmts[] = $this->createEnumCaseFromDocComment(
$docBlockMethod,
$class,
$mapping,
$enumNameInSnakeCase
);
}
}

Expand Down Expand Up @@ -117,12 +132,17 @@ private function createEnumCaseFromConst(ClassConst $classConst): EnumCase
private function createEnumCaseFromDocComment(
PhpDocTagNode $phpDocTagNode,
Class_ $class,
array $mapping = []
array $mapping = [],
bool $enumNameInSnakeCase = false,
): EnumCase {
/** @var MethodTagValueNode $nodeValue */
$nodeValue = $phpDocTagNode->value;
$enumValue = $mapping[$nodeValue->methodName] ?? $nodeValue->methodName;
$enumName = strtoupper($nodeValue->methodName);
if ($enumNameInSnakeCase) {
$enumName = strtoupper(Strings::replace($nodeValue->methodName, self::PASCAL_CASE_TO_UNDERSCORE_REGEX, '_$0'));
} else {
$enumName = strtoupper($nodeValue->methodName);
}
$enumExpr = $this->builderFactory->val($enumValue);

return new EnumCase(
Expand Down
15 changes: 13 additions & 2 deletions rules/Php81/Rector/Class_/SpatieEnumClassToEnumRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Enum_;
use PHPStan\Type\ObjectType;
use Rector\Contract\Rector\ConfigurableRectorInterface;
use Rector\Php81\NodeFactory\EnumFactory;
use Rector\Rector\AbstractRector;
use Rector\ValueObject\PhpVersionFeature;
Expand All @@ -21,8 +22,10 @@
*
* @see \Rector\Tests\Php81\Rector\Class_\SpatieEnumClassToEnumRector\SpatieEnumClassToEnumRectorTest
*/
final class SpatieEnumClassToEnumRector extends AbstractRector implements MinPhpVersionInterface
final class SpatieEnumClassToEnumRector extends AbstractRector implements MinPhpVersionInterface, ConfigurableRectorInterface
{
private bool $toUpperSnakeCase = false;

public function __construct(
private readonly EnumFactory $enumFactory
) {
Expand Down Expand Up @@ -80,6 +83,14 @@ public function refactor(Node $node): ?Enum_
return null;
}

return $this->enumFactory->createFromSpatieClass($node);
return $this->enumFactory->createFromSpatieClass($node, $this->toUpperSnakeCase);
}

/**
* @param mixed[] $configuration
*/
public function configure(array $configuration): void
{
$this->toUpperSnakeCase = true === ($configuration['toUpperSnakeCase'] ?? false);
}
}

0 comments on commit 86e7402

Please sign in to comment.