mirror of
https://github.com/rectorphp/rector.git
synced 2025-03-11 02:49:42 +01:00
docs: update How to create own Rector tutorial
This commit is contained in:
parent
0abecd8087
commit
15bafc3d36
@ -94,12 +94,12 @@ vendor/bin/rector levels
|
||||
Let's say you pick `symfony40` level and you want to upgrade your `/src` directory:
|
||||
|
||||
```bash
|
||||
# show known changes to Symfony 4.0
|
||||
# show known changes in Symfony 4.0
|
||||
vendor/bin/rector process src --level symfony40 --dry-run
|
||||
```
|
||||
|
||||
```bash
|
||||
# apply known changes to Symfony 4.0
|
||||
# apply
|
||||
vendor/bin/rector process src --level symfony40
|
||||
```
|
||||
|
||||
|
@ -1186,7 +1186,7 @@ Changes rand, srand and getrandmax by new md_* alternatives.
|
||||
|
||||
- class: `Rector\Php\Rector\FuncCall\TrailingCommaArgumentsRector`
|
||||
|
||||
Adds trailing commas to function and methods calls
|
||||
Adds trailing commas to function and methods calls
|
||||
|
||||
```diff
|
||||
calling(
|
||||
|
@ -1,38 +1,122 @@
|
||||
## 6 Steps to Add New Rector
|
||||
# 4 Steps Create Own Rector
|
||||
|
||||
In case you need a transformation that you didn't find in General Rectors, you can create your own:
|
||||
First, make sure your needs is not covered by [any existing Rectors](/docs/AllRectorsOverview.md).
|
||||
|
||||
1. Just extend `Rector\Rector\AbstractRector` class. It will prepare **2 methods**:
|
||||
Let's say you want to prefix private method call names starting with "internal" with `_`. Not very practical, but it will show the Rector flow.
|
||||
|
||||
```php
|
||||
public function isCandidate(Node $node): bool
|
||||
{
|
||||
}
|
||||
## 1. New Class
|
||||
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
}
|
||||
```
|
||||
Create class that extends [`Rector\Rector\AbstractRector`](/src/Rector/AbstractRector.php). It has many useful methods for checking node type, name, add nodes or remove one. Just run `$this->` and let PHPStorm show you all possible methods.
|
||||
|
||||
2. Put it under `namespace Rector\Contrib\<set>;` namespace
|
||||
There 3 methods to implement:
|
||||
|
||||
```php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Contrib\Symfony;
|
||||
namespace App\Rector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
final class MyRector extends AbstractRector
|
||||
final class MyFirstRector extends AbstractRector
|
||||
{
|
||||
// ...
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
// what does this do?
|
||||
// minimalistic before/after sample - to explain in code
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
// what node types we look for?
|
||||
// String_? FuncCall?
|
||||
// pick any from https://github.com/nikic/PHP-Parser/tree/master/lib/PhpParser/Node
|
||||
return [];
|
||||
}
|
||||
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
// what will happen with the node?
|
||||
// common work flow:
|
||||
// - should skip? → return null;
|
||||
// - modify it? → do it, then return $node;
|
||||
// - remove/add nodes elsewhere? → do it, then return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Add a Test Case - [see PHPUnit example](https://github.com/rectorphp/rector/blob/master/tests/Rector/Contrib/PHPUnit/ExceptionAnnotationRector/Test.php)
|
||||
## 2. Add Methods
|
||||
|
||||
4. Add to specific level, e.g. [`/src/config/level/symfony/symfony33.yml`](/src/config/level/symfony/symfony33.yml)
|
||||
```php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
5. Submit PR
|
||||
namespace App\Rector;
|
||||
|
||||
6. :+1:
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
final class MyFirstRector extends AbstractRector
|
||||
{
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Add "_" to private method calls that start with "internal"', [
|
||||
new CodeSample('$this->internalMethod();', '$this->_internalMethod();')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [MethodCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MethodCall $node - we can add "MethodCall" type here, because only this node is in "getNodeTypes()"
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
// we only care about "internal*" method names
|
||||
if (! $this->nameStartsWith($node, 'internal')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->name = new Identifier('_' . $this->getName($node));
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Register it `rector.yml`
|
||||
|
||||
```diff
|
||||
services:
|
||||
+ App\Rector\MyFirstRector: ~
|
||||
```
|
||||
|
||||
## 4. Let Rector Refactor Your Code
|
||||
|
||||
```bash
|
||||
vendor/bin/rector process src --dry-run
|
||||
|
||||
# apply it
|
||||
vendor/bin/rector process src
|
||||
```
|
||||
|
||||
If you use `rector.yml` from another directory or another name, set it with `--config` option:
|
||||
|
||||
```bash
|
||||
vendor/bin/rector process src --config ../custom-rector.yml
|
||||
```
|
||||
|
||||
That's it!
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Rector\Rector;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
|
||||
@ -29,6 +30,11 @@ trait NameResolverTrait
|
||||
return $this->getName($node) === $name;
|
||||
}
|
||||
|
||||
public function nameStartsWith(Node $node, string $name): bool
|
||||
{
|
||||
return Strings::startsWith($this->getName($node), $name);
|
||||
}
|
||||
|
||||
public function isNameInsensitive(Node $node, string $name): bool
|
||||
{
|
||||
return strtolower((string) $this->getName($node)) === strtolower($name);
|
||||
|
Loading…
x
Reference in New Issue
Block a user