So in the documentation you show us how to create your own rule, however I want to put my code in multiple rules like most of the more advanced stuff does here in rector by using sets.
How do we create our own set?
Set is bunch of rules in one config. You can use it like Symfony config (it is a Symfony config):
# my-custom-set.yaml
services:
FirstRector: null
SecondRector: null
vendor/bin/rector process src --config my-custom-set.yaml
Note: --set is basially shortcut for internal Rector configs. So instead of --config vendor/rector/rector/config/set/php71.yaml you can use only --set php71.
Ah, that makes sense. Thanks a lot @TomasVotruba!
So it is not possible yet to create a package which just gives the users a new set they can include in their config file?
Yes :+1:
Many framework-communities already to that, e.g. Drupal https://github.com/palantirnet/drupal-rector/tree/master/config/drupal-8 or Typo3 https://github.com/sabbelasichon/typo3-rector
Alright, thanks for the help 馃槃
@TomasVotruba Just a quick question, how do I make a rector return multiple nodes? I tried using $node->setAttribute('nextNode', $newNode); and $this->addNodeAfterNode($newNode, $node); in the refactor method, however none of them worked.
The $node is a new node I created in the refactor method, not the existing node from the function arguments.
$this->addNodeAfterNode usually does the job. Depends what exactly you're trying to do.
Could you share link to the rule on Github + failing test case? I'd be able to help you then
The $node is a new node I created in the refactor method, not the existing node from the function arguments.
This might be issue. The $node cannot be new node, it has to exist already.
@TomasVotruba Just to explain what I am trying to do. I am trying to convert PHPUnit test classes to PestPHP.
class PestRectorPHPUnitClass extends AbstractPHPUnitToPestRector
{
public function getNodeTypes(): array
{
return [Class_::class];
}
public function refactor(Node $node): ?Node
{
if (!$this->isObjectType($node, TestCase::class)) {
return null;
}
$methods = $this->betterNodeFinder->findInstanceOf($node, Node\Stmt\ClassMethod::class);
foreach ($methods as $method) {
$funcCall = $this->builderFactory->funcCall(
'it',
[
$this->getName($method),
new Node\Expr\Closure(['stmts' => $method->stmts]),
]
);
$newNode = $funcCall;
}
return $newNode ?? null;
}
}
Right now my approach is to just replace the whole class node with a new node. However I actually just found out that the method removeNode exists.
So my new approach which works is just doing
public function refactor(Node $node): ?Node
{
if (!$this->isObjectType($node, TestCase::class)) {
return null;
}
$methods = $this->betterNodeFinder->findInstanceOf($node, Node\Stmt\ClassMethod::class);
foreach ($methods as $method) {
$funcCall = $this->builderFactory->funcCall(
'it',
[
$this->getName($method),
new Node\Expr\Closure(['stmts' => $method->stmts]),
]
);
$this->addNodeAfterNode($funcCall, $node);
}
$this->removeNode($node);
return $node;
Could you provide minimal diff of before/after code, what you try to achieve?
E.g.
-echo 'hi';
+echo "hi";
-class CustomTestCase extends TestCase
-
- public function testCanCreateUser()
- {
- $user = factory(User::class)->create();
-
- $this->assertTrue($user->exist);
- }
-}
+it('testCanCreateUser', function () {
+ $user = factory(User::class)->create();
+ $this->assertTrue($user->exist);
+});
But the code I wrote before actually is able to achieve this now 馃槃
Ah, all's good then :)