[SymfonyPhpConfig] Add AddEmptyLineBetweenCallsInPhpConfigRector

This commit is contained in:
TomasVotruba 2020-07-22 23:31:42 +02:00
parent 54beea72f8
commit 78a0331708
12 changed files with 258 additions and 21 deletions

View File

@ -144,7 +144,8 @@
"Rector\\NetteUtilsCodeQuality\\": "rules/nette-utils-code-quality/src",
"Rector\\NetteCodeQuality\\": "rules/nette-code-quality/src",
"Rector\\Decomplex\\": "rules/decomplex/src",
"Rector\\Downgrade\\": "rules/downgrade/src"
"Rector\\Downgrade\\": "rules/downgrade/src",
"Rector\\SymfonyPhpConfig\\": "rules/symfony-php-config/src"
}
},
"autoload-dev": {
@ -223,7 +224,8 @@
"Rector\\NetteUtilsCodeQuality\\Tests\\": "rules/nette-utils-code-quality/tests",
"Rector\\NetteCodeQuality\\Tests\\": "rules/nette-code-quality/tests",
"Rector\\Decomplex\\Tests\\": "rules/decomplex/tests",
"Rector\\Downgrade\\Tests\\": "rules/downgrade/tests"
"Rector\\Downgrade\\Tests\\": "rules/downgrade/tests",
"Rector\\SymfonyPhpConfig\\Tests\\": "rules/symfony-php-config/tests"
},
"classmap": [
"rules/cakephp/tests/Rector/Name/ImplicitShortClassNameUseStatementRector/Source",

View File

@ -2,8 +2,11 @@
declare(strict_types=1);
use Rector\SymfonyPhpConfig\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(AddEmptyLineBetweenCallsInPhpConfigRector::class);
};

View File

@ -1,4 +1,4 @@
# All 530 Rectors Overview
# All 531 Rectors Overview
- [Projects](#projects)
- [General](#general)
@ -69,6 +69,7 @@
- [Symfony](#symfony) (33)
- [SymfonyCodeQuality](#symfonycodequality) (1)
- [SymfonyPHPUnit](#symfonyphpunit) (1)
- [SymfonyPhpConfig](#symfonyphpconfig) (1)
- [Twig](#twig) (1)
- [TypeDeclaration](#typedeclaration) (9)
@ -11491,6 +11492,27 @@ Move self::$container service fetching from test methods up to setUp method
<br><br>
## SymfonyPhpConfig
### `AddEmptyLineBetweenCallsInPhpConfigRector`
- class: [`Rector\SymfonyPhpConfig\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector`](/../master/rules/symfony-php-config/src/Rector/Closure/AddEmptyLineBetweenCallsInPhpConfigRector.php)
- [test fixtures](/../master/rules/symfony-php-config/tests/Rector/Closure/AddEmptyLineBetweenCallsInPhpConfigRector/Fixture)
Make calls in PHP Symfony config separated by newline
```diff
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
+
$parameters->set('key', 'value');
};
```
<br><br>
## Twig
### `SimpleFunctionAndFilterRector`

View File

@ -16,6 +16,7 @@ use PhpParser\Node\Stmt\Expression;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\SymfonyPhpConfig\NodeAnalyzer\SymfonyPhpConfigClosureAnalyzer;
final class AddNewServiceToSymfonyPhpConfigRector extends AbstractRector
{
@ -24,6 +25,16 @@ final class AddNewServiceToSymfonyPhpConfigRector extends AbstractRector
*/
private $rectorClass;
/**
* @var SymfonyPhpConfigClosureAnalyzer
*/
private $symfonyPhpConfigClosureAnalyzer;
public function __construct(SymfonyPhpConfigClosureAnalyzer $symfonyPhpConfigClosureAnalyzer)
{
$this->symfonyPhpConfigClosureAnalyzer = $symfonyPhpConfigClosureAnalyzer;
}
public function setRectorClass(string $rectorClass): void
{
$this->rectorClass = $rectorClass;
@ -46,7 +57,7 @@ final class AddNewServiceToSymfonyPhpConfigRector extends AbstractRector
return null;
}
if (! $this->isPhpConfigClosure($node)) {
if (! $this->symfonyPhpConfigClosureAnalyzer->isPhpConfigClosure($node)) {
return null;
}
@ -80,23 +91,6 @@ CODE_SAMPLE
]);
}
private function isPhpConfigClosure(Closure $closure): bool
{
if (count($closure->params) !== 1) {
return false;
}
$onlyParam = $closure->params[0];
if ($onlyParam->type === null) {
return false;
}
return $this->isName(
$onlyParam->type,
'Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator'
);
}
private function createServicesSetMethodCall(string $className): MethodCall
{
$servicesVariable = new Variable('services');

View File

@ -40,6 +40,7 @@ parameters:
old_to_preffered_classes:
# prevent PHPStorm autocomplete mess
'Symfony\Component\DependencyInjection\Variable': 'PhpParser\Node\Expr\Variable'
'Closure': 'PhpParser\Node\Expr\Closure'
# to allow installing with various phsptan versions without reporting old errors here
reportUnmatchedIgnoredErrors: false

View File

@ -29,6 +29,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
SetList::SOLID,
SetList::PRIVATIZATION,
SetList::NAMING,
SetList::SYMFONY_PHP_CONFIG,
]);
$parameters->set(Option::PATHS, [

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->defaults()
->public()
->autowire();
$services->load('Rector\SymfonyPhpConfig\\', __DIR__ . '/../src')
->exclude([__DIR__ . '/../src/Rector/**/*Rector.php']);
};

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Rector\SymfonyPhpConfig\NodeAnalyzer;
use PhpParser\Node\Expr\Closure;
use Rector\NodeNameResolver\NodeNameResolver;
final class SymfonyPhpConfigClosureAnalyzer
{
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
}
public function isPhpConfigClosure(Closure $closure): bool
{
if (count($closure->params) !== 1) {
return false;
}
$onlyParam = $closure->params[0];
if ($onlyParam->type === null) {
return false;
}
return $this->nodeNameResolver->isName(
$onlyParam->type,
'Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator'
);
}
}

View File

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace Rector\SymfonyPhpConfig\Rector\Closure;
use PhpParser\Node;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Stmt\Nop;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\SymfonyPhpConfig\NodeAnalyzer\SymfonyPhpConfigClosureAnalyzer;
/**
* @see \Rector\SymfonyPhpConfig\Tests\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector\AddEmptyLineBetweenCallsInPhpConfigRectorTest
*/
final class AddEmptyLineBetweenCallsInPhpConfigRector extends AbstractRector
{
/**
* @var SymfonyPhpConfigClosureAnalyzer
*/
private $symfonyPhpConfigClosureAnalyzer;
public function __construct(SymfonyPhpConfigClosureAnalyzer $symfonyPhpConfigClosureAnalyzer)
{
$this->symfonyPhpConfigClosureAnalyzer = $symfonyPhpConfigClosureAnalyzer;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Make calls in PHP Symfony config separated by newline', [
new CodeSample(
<<<'PHP'
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set('key', 'value');
};
PHP
,
<<<'PHP'
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set('key', 'value');
};
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Closure::class];
}
/**
* @param Closure $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->symfonyPhpConfigClosureAnalyzer->isPhpConfigClosure($node)) {
return null;
}
$originalStmts = $node->stmts;
$newStmts = [];
$previousLine = null;
foreach ($originalStmts as $stmt) {
if ($previousLine !== null && $previousLine + 1 === $stmt->getEndLine()) {
$newStmts[] = new Nop();
}
$newStmts[] = $stmt;
$previousLine = $stmt->getEndLine();
}
$node->stmts = $newStmts;
return $node;
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Rector\SymfonyPhpConfig\Tests\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\SymfonyPhpConfig\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class AddEmptyLineBetweenCallsInPhpConfigRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return AddEmptyLineBetweenCallsInPhpConfigRector::class;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Rector\SymfonyPhpConfig\Tests\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector\Fixture;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set('key', 'value');
};
?>
-----
<?php
namespace Rector\SymfonyPhpConfig\Tests\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector\Fixture;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set('key', 'value');
};
?>

View File

@ -0,0 +1,11 @@
<?php
namespace Rector\SymfonyPhpConfig\Tests\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector\Fixture;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set('key', 'value');
};