mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-17 00:22:24 +00:00
Merge pull request #315 from rectorphp/annotation-replacer
[PHPUnit] Scenario Annotation replacer Rector
This commit is contained in:
commit
3e8644fec1
32
README.md
32
README.md
|
@ -259,29 +259,53 @@ rectors:
|
||||||
rectors:
|
rectors:
|
||||||
Rector\Rector\Dynamic\ValueObjectRemoverRector:
|
Rector\Rector\Dynamic\ValueObjectRemoverRector:
|
||||||
# type: new simple type
|
# type: new simple type
|
||||||
'ValueObjects\Name': 'string'
|
'ValueObject\Name': 'string'
|
||||||
```
|
```
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- $value = new ValueObjects\Name('Tomas');
|
- $value = new ValueObject\Name('Tomas');
|
||||||
+ $value = 'Tomas';
|
+ $value = 'Tomas';
|
||||||
```
|
```
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
/**
|
/**
|
||||||
-* @var ValueObjects\Name
|
-* @var ValueObject\Name
|
||||||
+* @var string
|
+* @var string
|
||||||
*/
|
*/
|
||||||
private $name;
|
private $name;
|
||||||
```
|
```
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- public function someMethod(ValueObjects\Name $name) { ...
|
- public function someMethod(ValueObject\Name $name) { ...
|
||||||
+ public function someMethod(string $name) { ...
|
+ public function someMethod(string $name) { ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Replace Property and Method Annotations
|
||||||
|
|
||||||
|
```yml
|
||||||
|
rectors:
|
||||||
|
Rector\Rector\Dynamic\AnnotationReplacerRector:
|
||||||
|
# type
|
||||||
|
PHPUnit\Framework\TestCase:
|
||||||
|
# old annotation: new annotation
|
||||||
|
scenario: test
|
||||||
|
```
|
||||||
|
|
||||||
|
```diff
|
||||||
|
final class SomeTest extends PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
- * @scenario
|
||||||
|
+ * @test
|
||||||
|
*/
|
||||||
|
public function test()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Turn Magic to Methods
|
## Turn Magic to Methods
|
||||||
|
|
||||||
### Replace `get/set` magic methods with real ones
|
### Replace `get/set` magic methods with real ones
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Rector\ReflectionDocBlock\NodeAnalyzer;
|
namespace Rector\ReflectionDocBlock\NodeAnalyzer;
|
||||||
|
|
||||||
|
use Nette\Utils\Strings;
|
||||||
use phpDocumentor\Reflection\DocBlock;
|
use phpDocumentor\Reflection\DocBlock;
|
||||||
use phpDocumentor\Reflection\DocBlock\Tag;
|
use phpDocumentor\Reflection\DocBlock\Tag;
|
||||||
use phpDocumentor\Reflection\DocBlock\Tags\Param;
|
use phpDocumentor\Reflection\DocBlock\Tags\Param;
|
||||||
|
@ -60,6 +61,19 @@ final class DocBlockAnalyzer
|
||||||
$this->saveNewDocBlockToNode($node, $docBlock);
|
$this->saveNewDocBlockToNode($node, $docBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function replaceAnnotationInNode(Node $node, string $oldAnnotation, string $newAnnotation): void
|
||||||
|
{
|
||||||
|
if (! $node->getDocComment()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$oldContent = $node->getDocComment()->getText();
|
||||||
|
$newContent = Strings::replace($oldContent, sprintf('#@%s#', $oldAnnotation), '@' . $newAnnotation);
|
||||||
|
|
||||||
|
$doc = new Doc($newContent);
|
||||||
|
$node->setDocComment($doc);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string[]|null
|
* @return string[]|null
|
||||||
*/
|
*/
|
||||||
|
|
104
src/Rector/Dynamic/AnnotationReplacerRector.php
Normal file
104
src/Rector/Dynamic/AnnotationReplacerRector.php
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Rector\Dynamic;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt\ClassMethod;
|
||||||
|
use PhpParser\Node\Stmt\Property;
|
||||||
|
use Rector\Node\Attribute;
|
||||||
|
use Rector\Rector\AbstractPHPUnitRector;
|
||||||
|
use Rector\ReflectionDocBlock\NodeAnalyzer\DocBlockAnalyzer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before:
|
||||||
|
* - @scenario
|
||||||
|
*
|
||||||
|
* After:
|
||||||
|
* - @test
|
||||||
|
*/
|
||||||
|
final class AnnotationReplacerRector extends AbstractPHPUnitRector
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[][]
|
||||||
|
*/
|
||||||
|
private $classToAnnotationMap = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DocBlockAnalyzer
|
||||||
|
*/
|
||||||
|
private $docBlockAnalyzer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $activeAnnotationMap = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[][] $classToAnnotationMap
|
||||||
|
*/
|
||||||
|
public function __construct(array $classToAnnotationMap, DocBlockAnalyzer $docBlockAnalyzer)
|
||||||
|
{
|
||||||
|
$this->docBlockAnalyzer = $docBlockAnalyzer;
|
||||||
|
$this->classToAnnotationMap = $classToAnnotationMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isCandidate(Node $node): bool
|
||||||
|
{
|
||||||
|
if ($this->shouldSkip($node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
|
||||||
|
foreach ($this->classToAnnotationMap as $type => $annotationMap) {
|
||||||
|
if (! in_array($type, $parentNode->getAttribute(Attribute::TYPES), true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->activeAnnotationMap = $annotationMap;
|
||||||
|
|
||||||
|
if ($this->hasAnyAnnotation($node)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ClassMethod|Property $node
|
||||||
|
*/
|
||||||
|
public function refactor(Node $node): ?Node
|
||||||
|
{
|
||||||
|
foreach ($this->activeAnnotationMap as $oldAnnotation => $newAnnotation) {
|
||||||
|
$this->docBlockAnalyzer->replaceAnnotationInNode($node, $oldAnnotation, $newAnnotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shouldSkip(Node $node): bool
|
||||||
|
{
|
||||||
|
if (! $node instanceof ClassMethod && ! $node instanceof Property) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Node|null $parentNode */
|
||||||
|
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
|
||||||
|
if (! $parentNode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasAnyAnnotation(Node $node): bool
|
||||||
|
{
|
||||||
|
foreach ($this->activeAnnotationMap as $oldAnnotation => $newAnnotation) {
|
||||||
|
if ($this->docBlockAnalyzer->hasAnnotation($node, $oldAnnotation)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
4
src/config/level/phpunit/phpunit70.yml
Normal file
4
src/config/level/phpunit/phpunit70.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
rectors:
|
||||||
|
Rector\Rector\Dynamic\AnnotationReplacerRector:
|
||||||
|
PHPUnit\Framework\TestCase:
|
||||||
|
scenario: test
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
final class MyTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function test()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\Rector\Dynamic\AnnotationReplacerRector;
|
||||||
|
|
||||||
|
use Rector\Rector\Dynamic\AnnotationReplacerRector;
|
||||||
|
use Rector\Testing\PHPUnit\AbstractConfigurableRectorTestCase;
|
||||||
|
|
||||||
|
final class ScenarioToTestAnnotationRectorTest extends AbstractConfigurableRectorTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider provideWrongToFixedFiles()
|
||||||
|
*/
|
||||||
|
public function test(string $wrong, string $fixed): void
|
||||||
|
{
|
||||||
|
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[][]
|
||||||
|
*/
|
||||||
|
public function provideWrongToFixedFiles(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
protected function getRectorClasses(): array
|
||||||
|
{
|
||||||
|
return [AnnotationReplacerRector::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function provideConfig(): string
|
||||||
|
{
|
||||||
|
return __DIR__ . '/config/rector.yml';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
final class MyTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @scenario
|
||||||
|
*/
|
||||||
|
public function test()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
rectors:
|
||||||
|
Rector\Rector\Dynamic\AnnotationReplacerRector:
|
||||||
|
PHPUnit\Framework\TestCase:
|
||||||
|
scenario: test
|
Loading…
Reference in New Issue
Block a user