Skip to content

Commit

Permalink
Config - Ignored classes from vendor
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasJancar committed Oct 9, 2024
1 parent 2da4064 commit c7f6304
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 272 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php declare(strict_types = 1);

namespace BrandEmbassyCodingStandard\Rector\MabeEnumMethodCallToEnumConstRector;

use PhpParser\Node;
use PHPStan\Type\TypeWithClassName;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;

/**
* @final
*/
class ClassNameProvider
{
public function __construct(
private readonly NodeTypeResolver $nodeTypeResolver,
private readonly NodeNameResolver $nodeNameResolver,
) {
}


/**
* @return class-string|null
*/
public function getClassNameFromVar(Node $node): ?string
{
$type = $this->nodeTypeResolver->getType($node);

if (!$type instanceof TypeWithClassName) {
return null;
}

/** @var class-string $className */
$className = $type->getClassName();

return $className;
}


/**
* @return class-string|null
*/
public function getClassNameFromClass(Node $node): ?string
{
/** @var class-string|null $name */
$name = $this->nodeNameResolver->getName($node);

return $name;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
<?php declare(strict_types = 1);

namespace BrandEmbassyCodingStandard\Rector\MabeEnumMethodCallToEnumConstRector;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\ArrayItem as ArrayItemNode;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Scalar\String_;
use PHPStan\Type\ObjectType;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\PhpParser\Node\NodeFactory;
use ReflectionClass;
use function array_map;
use function str_contains;
use function strtoupper;

/**
* @final
*/
class MabeEnumFactory
{
private const MABE_ENUM_CLASS_NAME = 'MabeEnum\\Enum';

private NodeFactory $nodeFactory;

private NodeTypeResolver $nodeTypeResolver;

private NodeNameResolver $nodeNameResolver;

private ClassNameProvider $classNameProvider;

private bool $ignoredClassFromVendor = true;


public function __construct(
NodeFactory $nodeFactory,
NodeTypeResolver $nodeTypeResolver,
NodeNameResolver $nodeNameResolver,
ClassNameProvider $classNameProvider,
) {
$this->nodeFactory = $nodeFactory;
$this->nodeTypeResolver = $nodeTypeResolver;
$this->nodeNameResolver = $nodeNameResolver;
$this->classNameProvider = $classNameProvider;
}


public function createFromNode(StaticCall|MethodCall|Array_ $node, bool $ignoreClassesFromVendor = true): ?Expr
{
$this->ignoredClassFromVendor = $ignoreClassesFromVendor;

if ($node instanceof Array_) {
return $this->refactorArray($node);
}

if ($node->name instanceof Expr) {
return null;
}

$enumCaseName = $this->nodeNameResolver->getName($node->name);
if ($enumCaseName === null) {
return null;
}

if ($node instanceof StaticCall) {
return $this->refactorStaticCall($node, $enumCaseName);
}

return $this->refactorMethodCall($node, $enumCaseName);
}


private function refactorArray(Array_ $array): ?Expr
{
if ($array->items === []) {
return null;
}

/** @var ArrayItem[] $arrayItems */
$arrayItems = $array->items;

/** @var ArrayItemNode[] $refactoredArrayItems */
$refactoredArrayItems = array_map(fn(
ArrayItem $arrayItem
): ArrayItem => $this->refactorArrayItemKeys($arrayItem), $arrayItems);

$array->items = $refactoredArrayItems;

return $array;
}


private function refactorArrayItemKeys(ArrayItem $arrayItem): ArrayItem
{
$key = $arrayItem->key;

if ($key === null) {
return $arrayItem;
}

if ($key instanceof ClassConstFetch && $this->isMabeEnum($key->class)) {
$key = $this->createPropertyValueFetch($key);
$arrayItem->key = $key;
}

return $arrayItem;
}


private function createPropertyValueFetch(Expr $expr): PropertyFetch
{
return $this->nodeFactory->createPropertyFetch($expr, 'value');
}


private function refactorStaticCall(StaticCall $staticCall, string $staticCallName): ?Expr
{
$className = $this->classNameProvider->getClassNameFromClass($staticCall->class);

if ($className === null) {
return null;
}

if ($this->isClassIgnored($className)) {
return null;
}

if (strtoupper($staticCallName) === $staticCallName) {
return $this->nodeFactory->createClassConstFetch($className, $staticCallName);
}

if ($staticCallName === 'get') {
return $this->refactorGetStaticCall($staticCall);
}

if ($staticCallName === 'getEnumerators') {
return $this->nodeFactory->createStaticCall($className, 'cases');
}

return null;
}


private function refactorMethodCall(MethodCall $methodCall, string $methodName): ?Expr
{
if (!$this->isMabeEnum($methodCall->var)) {
return null;
}

$className = $this->classNameProvider->getClassNameFromVar($methodCall->var);

if ($className === null) {
return null;
}

if ($this->isClassIgnored($className)) {
return null;
}

if ($methodName === 'is') {
return $this->refactorIsMethodCall($methodCall);
}

if ($methodName === 'getValue') {
return $this->createPropertyValueFetch($methodCall->var);
}

if ($methodName === 'getName') {
return $this->nodeFactory->createPropertyFetch($methodCall->var, 'name');
}

return null;
}


private function refactorGetStaticCall(StaticCall $staticCall): ?Expr
{
$value = $staticCall->getArgs()[0]->value;

if ($value instanceof ClassConstFetch) {
$name = $value->name;

if (!$name instanceof Identifier) {
return null;
}

$className = $this->nodeNameResolver->getName($value->class);

if ($className === null) {
return null;
}

return $this->nodeFactory->createClassConstFetch(
$className,
$name->name,
);
}

if ($value instanceof String_ || $value instanceof Variable) {
$className = $this->nodeNameResolver->getName($staticCall->class);

if ($className === null) {
return null;
}

return $this->nodeFactory->createStaticCall($className, 'from', [$value]);
}

return null;
}


private function refactorIsMethodCall(MethodCall $methodCall): ?Identical
{
$expr = $methodCall->var;

if ($expr instanceof StaticCall) {
$expr = $expr->getArgs()[0]->value;
}

$arg = $methodCall->getArgs()[0] ?? null;
if (!$arg instanceof Arg) {
return null;
}

$right = $arg->value;
if ($right instanceof StaticCall) {
$right = $right->getArgs()[0]->value;
}

if ($arg->value instanceof ClassConstFetch) {
$right = $arg->value;
}

return new Identical($expr, $right);
}


/**
* @param class-string $className
*/
private function isClassIgnored(string $className): bool
{
return $this->ignoredClassFromVendor && $this->isClassFromVendor($className);
}


private function isMabeEnum(Node $node): bool
{
return $this->nodeTypeResolver->isObjectType(
$node,
new ObjectType(self::MABE_ENUM_CLASS_NAME),
);
}


/**
* @param class-string $className
*/
private function isClassFromVendor(string $className): bool
{
$classReflection = new ReflectionClass($className);

return $classReflection->getFileName() !== false && str_contains($classReflection->getFileName(), 'vendor');
}
}
Loading

0 comments on commit c7f6304

Please sign in to comment.