[DX] Remove MoveServicesBySuffixToDirectoryRector, better handle by PHPStan + PHPStorm refacor (#1834)

This commit is contained in:
Tomas Votruba 2022-02-18 09:22:26 +00:00 committed by GitHub
parent 323be2a5de
commit a4eff1e0ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 402 additions and 636 deletions

File diff suppressed because it is too large Load Diff

View File

@ -114,7 +114,6 @@
},
"classmap": [
"stubs",
"rules-tests/Autodiscovery/Rector/Class_/MoveServicesBySuffixToDirectoryRector/Expected",
"rules-tests/Autodiscovery/Rector/Interface_/MoveInterfacesToContractNamespaceDirectoryRector/Expected",
"rules-tests/CodingStyle/Rector/Namespace_/ImportFullyQualifiedNamesRector/Source",
"rules-tests/Renaming/Rector/Name/RenameClassRector/Source",

View File

@ -305,7 +305,11 @@ final class PhpDocInfo
$typeToRemove
): ?int {
if ($node instanceof PhpDocTagNode && is_a($node->value, $typeToRemove, true)) {
if (str_starts_with($node->name, '@psalm-') || str_starts_with($node->name, '@phpstan-')) {
if (str_starts_with($node->name, '@psalm-')) {
return null;
}
if (str_starts_with($node->name, '@phpstan-')) {
return null;
}

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Command;
final class BananaCommand
{
public function run()
{
return new \Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\Orange();
}
}

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller;
final class MissPlacedController
{
public function getSelf()
{
return new \Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\MissPlacedController();
}
}

View File

@ -1,8 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Mapper\Nested;
abstract class AbstractBaseMapper
{
}

View File

@ -1,8 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Mapper\Nested;
abstract class AbstractBaseWithSpaceMapper
{
}

View File

@ -1,9 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Mapper;
use Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\Nested\AbstractBaseMapper;
final class UserMapper extends \Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\Nested\AbstractBaseMapper
{
}

View File

@ -1,9 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Mapper;
use Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Mapper\Nested\AbstractBaseWithSpaceMapper;
final class UserWithSpaceMapper extends \Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Mapper\Nested\AbstractBaseWithSpaceMapper
{
}

View File

@ -1,8 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Repository;
class AppleRepository
{
}

View File

@ -1,2 +0,0 @@
services:
Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Mapper\Nested\AbstractBaseMapper: null

View File

@ -1,97 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector;
use Iterator;
use Rector\FileSystemRector\ValueObject\AddedFileWithContent;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
use Symplify\SmartFileSystem\SmartFileSystem;
final class MoveServicesBySuffixToDirectoryRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $originalFileInfo, AddedFileWithContent $expectedAddedFileWithContent): void
{
$this->doTestFileInfo($originalFileInfo);
$this->assertFileWasAdded($expectedAddedFileWithContent);
}
/**
* @return Iterator<SmartFileInfo|AddedFileWithContent>
*/
public function provideData(): Iterator
{
$smartFileSystem = new SmartFileSystem();
yield [
new SmartFileInfo(__DIR__ . '/Source/Entity/AppleRepository.php'),
new AddedFileWithContent(
$this->getFixtureTempDirectory() . '/Repository/AppleRepository.php',
$smartFileSystem->readFile(__DIR__ . '/Expected/Repository/ExpectedAppleRepository.php')
),
];
yield [
new SmartFileInfo(__DIR__ . '/Source/Controller/BananaCommand.php'),
new AddedFileWithContent(
$this->getFixtureTempDirectory() . '/Command/BananaCommand.php',
$smartFileSystem->readFile(__DIR__ . '/Expected/Command/ExpectedBananaCommand.php')
),
];
yield [
new SmartFileInfo(__DIR__ . '/Source/Command/MissPlacedController.php'),
new AddedFileWithContent(
$this->getFixtureTempDirectory() . '/Controller/MissPlacedController.php',
$smartFileSystem->readFile(__DIR__ . '/Expected/Controller/MissPlacedController.php')
),
];
yield [
new SmartFileInfo(__DIR__ . '/Source/Controller/Nested/AbstractBaseWithSpaceMapper.php'),
new AddedFileWithContent(
$this->getFixtureTempDirectory() . '/Mapper/AbstractBaseWithSpaceMapper.php',
$smartFileSystem->readFile(__DIR__ . '/Expected/Mapper/Nested/AbstractBaseWithSpaceMapper.php.inc')
),
];
// inversed order, but should have the same effect
yield [
new SmartFileInfo(__DIR__ . '/Source/Entity/UserMapper.php'),
new AddedFileWithContent(
$this->getFixtureTempDirectory() . '/Mapper/UserMapper.php',
$smartFileSystem->readFile(__DIR__ . '/Expected/Mapper/UserMapper.php.inc')
),
];
}
/**
* @dataProvider provideDataSkipped()
*/
public function testSkipped(SmartFileInfo $originalFileInfo): void
{
$this->doTestFileInfo($originalFileInfo);
// no change - file should have the original location
$this->assertFileWasNotChanged($this->originalTempFileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideDataSkipped(): Iterator
{
// nothing changes
yield [new SmartFileInfo(__DIR__ . '/Source/Mapper/SkipCorrectMapper.php'), null];
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Command;
final class MissPlacedController
{
public function getSelf()
{
return new MissPlacedController;
}
}

View File

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller;
final class BananaCommand
{
public function run()
{
return new Orange();
}
}

View File

@ -1,9 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\Nested;
abstract class AbstractBaseMapper
{
}

View File

@ -1,9 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\Nested;
abstract class AbstractBaseWithSpaceMapper
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller;
final class Orange
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Entity;
class AppleRepository
{
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Entity;
use Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\Nested\AbstractBaseMapper;
final class UserMapper extends AbstractBaseMapper
{
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Entity;
use Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\Nested\AbstractBaseWithSpaceMapper;
final class UserWithSpaceMapper extends AbstractBaseWithSpaceMapper
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\SkipAlreadyMoved\Source\Mapper;
final class SkipCorrectMapper
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Repository;
class AppleRepository
{
}

View File

@ -1,2 +0,0 @@
services:
Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\Source\Controller\Nested\AbstractBaseMapper: null

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(MoveServicesBySuffixToDirectoryRector::class)
->configure(['Repository', 'Command', 'Mapper', 'Controller']);
};

View File

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Autodiscovery\FileLocation;
final class ExpectedFileLocationResolver
{
/**
* Resolves if is suffix in the same category, e.g. "Exception/SomeException.php"
*/
public function resolve(string $escapedGroupName, string $suffixPattern): string
{
$escapedGroupName = preg_quote($escapedGroupName, '#');
$escapedSuffixPattern = preg_quote($suffixPattern, '#');
return sprintf('#\/%s\/.+%s#', $escapedGroupName, $escapedSuffixPattern);
}
}

View File

@ -1,153 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Autodiscovery\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Autodiscovery\FileLocation\ExpectedFileLocationResolver;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StringUtils;
use Rector\Core\ValueObject\Application\File;
use Rector\FileSystemRector\ValueObject\AddedFileWithNodes;
use Rector\FileSystemRector\ValueObjectFactory\AddedFileWithNodesFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Symplify\SmartFileSystem\SmartFileInfo;
use Webmozart\Assert\Assert;
/**
* Inspiration @see https://github.com/rectorphp/rector/pull/1865/files#diff-0d18e660cdb626958662641b491623f8
*
* @see \Rector\Tests\Autodiscovery\Rector\Class_\MoveServicesBySuffixToDirectoryRector\MoveServicesBySuffixToDirectoryRectorTest
*/
final class MoveServicesBySuffixToDirectoryRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var string[]
*/
private array $groupNamesBySuffix = [];
public function __construct(
private readonly ExpectedFileLocationResolver $expectedFileLocationResolver,
private readonly AddedFileWithNodesFactory $addedFileWithNodesFactory
) {
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Move classes by their suffix to their own group/directory', [
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
// file: app/Entity/ProductRepository.php
namespace App\Entity;
class ProductRepository
{
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
// file: app/Repository/ProductRepository.php
namespace App\Repository;
class ProductRepository
{
}
CODE_SAMPLE
,
['Repository']
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
$this->processGroupNamesBySuffix($this->file->getSmartFileInfo(), $this->groupNamesBySuffix);
return null;
}
/**
* @param mixed[] $configuration
*/
public function configure(array $configuration): void
{
Assert::allString($configuration);
$this->groupNamesBySuffix = $configuration;
}
/**
* A. Match classes by suffix and move them to group namespace
*
* E.g. "App\Controller\SomeException"
*
* "App\Exception\SomeException"
*
* @param string[] $groupNamesBySuffix
*/
private function processGroupNamesBySuffix(SmartFileInfo $smartFileInfo, array $groupNamesBySuffix): void
{
foreach ($groupNamesBySuffix as $groupNames) {
// has class suffix
$suffixPattern = '\w+' . $groupNames . '(Test)?\.php$';
if (! StringUtils::isMatch($smartFileInfo->getRealPath(), '#' . $suffixPattern . '#')) {
continue;
}
if ($this->isLocatedInExpectedLocation($groupNames, $suffixPattern, $smartFileInfo)) {
continue;
}
// file is already in the group
if (StringUtils::isMatch($smartFileInfo->getPath(), '#' . $groupNames . '$#')) {
continue;
}
$this->moveFileToGroupName($smartFileInfo, $this->file, $groupNames);
return;
}
}
private function isLocatedInExpectedLocation(
string $groupName,
string $suffixPattern,
SmartFileInfo $smartFileInfo
): bool {
$expectedLocationFilePattern = $this->expectedFileLocationResolver->resolve($groupName, $suffixPattern);
return StringUtils::isMatch($smartFileInfo->getRealPath(), $expectedLocationFilePattern);
}
private function moveFileToGroupName(SmartFileInfo $fileInfo, File $file, string $desiredGroupName): void
{
$addedFileWithNodes = $this->addedFileWithNodesFactory->createWithDesiredGroup(
$fileInfo,
$file,
$desiredGroupName
);
if (! $addedFileWithNodes instanceof AddedFileWithNodes) {
return;
}
$this->removedAndAddedFilesCollector->removeFile($fileInfo);
$this->removedAndAddedFilesCollector->addAddedFile($addedFileWithNodes);
}
}