mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 13:28:18 +01:00
[NodeTraverser] use it instead of Dispatcher and own solution
This commit is contained in:
parent
e32453e2be
commit
3a6eee57f3
@ -9,8 +9,8 @@ This tool will *reconstruct* (change) your code - **run it only in a new clean g
|
||||
|
||||
## All Reconstructors
|
||||
|
||||
- `InjectAnnotationToConstructorReconstructor` ([Nette](https://github.com/nette/))
|
||||
- `NamedServicesToConstructorReconstructor` ([Symfony](https://github.com/symfony/))
|
||||
- `InjectAnnotationToConstructorNodeTraverser` ([Nette](https://github.com/nette/))
|
||||
- `NamedServicesToConstructorNodeTraverser` ([Symfony](https://github.com/symfony/))
|
||||
|
||||
|
||||
## Install
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace Rector\Application;
|
||||
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\Parser;
|
||||
use Rector\Dispatcher\NodeDispatcher;
|
||||
use Rector\Printer\CodeStyledPrinter;
|
||||
use SplFileInfo;
|
||||
|
||||
@ -14,21 +14,21 @@ final class FileProcessor
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* @var NodeDispatcher
|
||||
*/
|
||||
private $nodeDispatcher;
|
||||
|
||||
/**
|
||||
* @var CodeStyledPrinter
|
||||
*/
|
||||
private $codeStyledPrinter;
|
||||
|
||||
public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, NodeDispatcher $nodeDispatcher)
|
||||
/**
|
||||
* @var NodeTraverser
|
||||
*/
|
||||
private $nodeTraverser;
|
||||
|
||||
public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, NodeTraverser $nodeTraverser)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
$this->nodeDispatcher = $nodeDispatcher;
|
||||
$this->codeStyledPrinter = $codeStyledPrinter;
|
||||
$this->nodeTraverser = $nodeTraverser;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,9 +51,9 @@ final class FileProcessor
|
||||
|
||||
$originalNodes = $this->cloneArrayOfObjects($nodes);
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
$this->nodeDispatcher->dispatch($node);
|
||||
}
|
||||
|
||||
$this->nodeTraverser->traverse($nodes);
|
||||
|
||||
|
||||
$this->codeStyledPrinter->printToFile($file, $originalNodes, $nodes);
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Contract\Dispatcher;
|
||||
|
||||
use PhpParser\Node;
|
||||
|
||||
interface ReconstructorInterface
|
||||
{
|
||||
public function isCandidate(Node $node): bool;
|
||||
|
||||
public function reconstruct(Node $classNode): void;
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Rector\DependencyInjection\CompilerPass;
|
||||
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitor;
|
||||
use Rector\Contract\Dispatcher\ReconstructorInterface;
|
||||
use Rector\Dispatcher\NodeDispatcher;
|
||||
use Symfony\Component\Console\Application;
|
||||
@ -15,7 +17,7 @@ final class CollectorCompilerPass implements CompilerPassInterface
|
||||
public function process(ContainerBuilder $containerBuilder): void
|
||||
{
|
||||
$this->collectCommandsToConsoleApplication($containerBuilder);
|
||||
$this->collectReconstructorsToNodeDispatcher($containerBuilder);
|
||||
$this->collectNodeVisitorsToTraverser($containerBuilder);
|
||||
}
|
||||
|
||||
private function collectCommandsToConsoleApplication(ContainerBuilder $containerBuilder): void
|
||||
@ -28,13 +30,13 @@ final class CollectorCompilerPass implements CompilerPassInterface
|
||||
);
|
||||
}
|
||||
|
||||
private function collectReconstructorsToNodeDispatcher(ContainerBuilder $containerBuilder): void
|
||||
private function collectNodeVisitorsToTraverser(ContainerBuilder $containerBuilder): void
|
||||
{
|
||||
DefinitionCollector::loadCollectorWithType(
|
||||
$containerBuilder,
|
||||
NodeDispatcher::class,
|
||||
ReconstructorInterface::class,
|
||||
'addReconstructor'
|
||||
NodeTraverser::class,
|
||||
NodeVisitor::class,
|
||||
'addVisitor'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Dispatcher;
|
||||
|
||||
use PhpParser\Node;
|
||||
use Rector\Contract\Dispatcher\ReconstructorInterface;
|
||||
|
||||
final class NodeDispatcher
|
||||
{
|
||||
/**
|
||||
* @var ReconstructorInterface[]
|
||||
*/
|
||||
private $reconstructors;
|
||||
|
||||
public function addReconstructor(ReconstructorInterface $reconstructor): void
|
||||
{
|
||||
$this->reconstructors[] = $reconstructor;
|
||||
}
|
||||
|
||||
public function dispatch(Node $node): void
|
||||
{
|
||||
// todo: build hash map
|
||||
foreach ($this->reconstructors as $reconstructor) {
|
||||
if ($reconstructor->isCandidate($node)) {
|
||||
$reconstructor->reconstruct($node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Reconstructor\DependencyInjection;
|
||||
namespace Rector\NodeVisitor\DependencyInjection;
|
||||
|
||||
use PhpCsFixer\DocBlock\DocBlock;
|
||||
use PhpParser\Comment\Doc;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use Rector\Builder\ConstructorMethodBuilder;
|
||||
use Rector\Contract\Dispatcher\ReconstructorInterface;
|
||||
|
||||
final class InjectAnnotationToConstructorReconstructor implements ReconstructorInterface
|
||||
final class InjectAnnotationToConstructorNodeVisitor extends NodeVisitorAbstract
|
||||
{
|
||||
/**
|
||||
* @var ConstructorMethodBuilder
|
||||
@ -75,4 +76,53 @@ final class InjectAnnotationToConstructorReconstructor implements ReconstructorI
|
||||
|
||||
$propertyNode->setDocComment(new Doc($propertyDocBlock->getContent()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when entering a node.
|
||||
*
|
||||
* Return value semantics:
|
||||
* * null
|
||||
* => $node stays as-is
|
||||
* * NodeTraverser::DONT_TRAVERSE_CHILDREN
|
||||
* => Children of $node are not traversed. $node stays as-is
|
||||
* * NodeTraverser::STOP_TRAVERSAL
|
||||
* => Traversal is aborted. $node stays as-is
|
||||
* * otherwise
|
||||
* => $node is set to the return value
|
||||
*
|
||||
* @return null|int|Node Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Class_) {
|
||||
$this->reconstruct($node);
|
||||
return $node;
|
||||
}
|
||||
|
||||
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when leaving a node.
|
||||
*
|
||||
* Return value semantics:
|
||||
* * null
|
||||
* => $node stays as-is
|
||||
* * NodeTraverser::REMOVE_NODE
|
||||
* => $node is removed from the parent array
|
||||
* * NodeTraverser::STOP_TRAVERSAL
|
||||
* => Traversal is aborted. $node stays as-is
|
||||
* * array (of Nodes)
|
||||
* => The return value is merged into the parent array (at the position of the $node)
|
||||
* * otherwise
|
||||
* => $node is set to the return value
|
||||
*
|
||||
* @param Node $node Node
|
||||
*
|
||||
* @return null|int|Node|Node[] Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
// TODO: Implement leaveNode() method.
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Reconstructor\DependencyInjection;
|
||||
namespace Rector\NodeVisitor\DependencyInjection;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
@ -11,16 +11,16 @@ use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use Rector\Analyzer\ClassAnalyzer;
|
||||
use Rector\Builder\ConstructorMethodBuilder;
|
||||
use Rector\Builder\Naming\NameResolver;
|
||||
use Rector\Builder\PropertyBuilder;
|
||||
use Rector\Contract\Dispatcher\ReconstructorInterface;
|
||||
use Rector\Tests\Reconstructor\DependencyInjection\NamedServicesToConstructorReconstructor\Source\LocalKernel;
|
||||
use Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor\Source\LocalKernel;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
final class NamedServicesToConstructorReconstructor implements ReconstructorInterface
|
||||
final class NamedServicesToConstructorNodeVisitor extends NodeVisitorAbstract
|
||||
{
|
||||
/**
|
||||
* @var ConstructorMethodBuilder
|
||||
@ -54,7 +54,7 @@ final class NamedServicesToConstructorReconstructor implements ReconstructorInte
|
||||
$this->classAnalyzer = $classAnalyzer;
|
||||
}
|
||||
|
||||
public function isCandidate(Node $node): bool
|
||||
private function isCandidate(Node $node): bool
|
||||
{
|
||||
// OR? Maybe listen on MethodCall... $this-> +get('...')
|
||||
|
||||
@ -208,4 +208,26 @@ final class NamedServicesToConstructorReconstructor implements ReconstructorInte
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when entering a node.
|
||||
*
|
||||
* Return value semantics:
|
||||
* * null
|
||||
* => $node stays as-is
|
||||
* * NodeTraverser::DONT_TRAVERSE_CHILDREN
|
||||
* => Children of $node are not traversed. $node stays as-is
|
||||
* * NodeTraverser::STOP_TRAVERSAL
|
||||
* => Traversal is aborted. $node stays as-is
|
||||
* * otherwise
|
||||
* => $node is set to the return value
|
||||
*
|
||||
* @param Node $node Node
|
||||
*
|
||||
* @return null|int|Node Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
return $this->isCandidate($node);
|
||||
}
|
||||
}
|
@ -5,10 +5,8 @@ namespace Rector\Testing\Application;
|
||||
use PhpParser\Lexer;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitor\CloningVisitor;
|
||||
use PhpParser\NodeVisitor;
|
||||
use PhpParser\Parser;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
use Rector\Contract\Dispatcher\ReconstructorInterface;
|
||||
use Rector\Printer\CodeStyledPrinter;
|
||||
use SplFileInfo;
|
||||
|
||||
@ -26,17 +24,23 @@ final class FileReconstructor
|
||||
/**
|
||||
* @var Lexer
|
||||
*/
|
||||
private $lexer;
|
||||
|
||||
public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, Lexer $lexer)
|
||||
private $lexer;
|
||||
/**
|
||||
* @var NodeTraverser
|
||||
*/
|
||||
private $nodeTraverser;
|
||||
|
||||
public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, Lexer $lexer, NodeTraverser $nodeTraverser)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
$this->codeStyledPrinter = $codeStyledPrinter;
|
||||
$this->lexer = $lexer;
|
||||
$this->nodeTraverser = $nodeTraverser;
|
||||
}
|
||||
|
||||
# ref: https://github.com/nikic/PHP-Parser/issues/344#issuecomment-298162516
|
||||
public function processFileWithReconstructor(SplFileInfo $file, ReconstructorInterface $reconstructor): string
|
||||
public function processFileWithReconstructor(SplFileInfo $file, NodeVisitor $nodeVisitor): string
|
||||
{
|
||||
$fileContent = file_get_contents($file->getRealPath());
|
||||
|
||||
@ -47,18 +51,9 @@ final class FileReconstructor
|
||||
|
||||
// keep format printer
|
||||
$oldTokens = $this->lexer->getTokens();
|
||||
$traverser = new NodeTraverser;
|
||||
$traverser->addVisitor(new CloningVisitor);
|
||||
$newStmts = $traverser->traverse($oldStmts);
|
||||
|
||||
foreach ($oldStmts as $node) {
|
||||
if ($reconstructor->isCandidate($node)) {
|
||||
$reconstructor->reconstruct($node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// after reconstruct evnet?
|
||||
$this->nodeTraverser->addVisitor($nodeVisitor);
|
||||
$newStmts = $this->nodeTraverser->traverse($oldStmts);
|
||||
|
||||
return $this->codeStyledPrinter->printToString($oldStmts, $newStmts, $oldTokens);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Rector\Testing\PHPUnit;
|
||||
|
||||
use PhpParser\NodeVisitor;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Rector\Contract\Dispatcher\ReconstructorInterface;
|
||||
@ -38,7 +39,7 @@ abstract class AbstractReconstructorTestCase extends TestCase
|
||||
|
||||
abstract protected function getReconstructorClass(): string;
|
||||
|
||||
private function getReconstructor(): ReconstructorInterface
|
||||
private function getReconstructor(): NodeVisitor
|
||||
{
|
||||
return $this->container->get($this->getReconstructorClass());
|
||||
}
|
||||
|
@ -16,4 +16,9 @@ services:
|
||||
PhpParser\Lexer:
|
||||
factory: ['@Rector\Parser\LexerFactory', 'create']
|
||||
PhpParser\BuilderFactory: ~
|
||||
|
||||
# Traverser
|
||||
PhpParser\NodeTraverser: ~
|
||||
# Printer
|
||||
PhpParser\NodeVisitor\CloningVisitor: ~
|
||||
PhpParser\PrettyPrinter\Standard: ~
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Reconstructor\DependencyInjection\InjectAnnotationToConstructorReconstructor;
|
||||
namespace Rector\Tests\NodeVisitor\DependencyInjection\InjectAnnotationToConstructorReconstructor;
|
||||
|
||||
use Rector\Reconstructor\DependencyInjection\InjectAnnotationToConstructorReconstructor;
|
||||
use Rector\NodeVisitor\DependencyInjection\InjectAnnotationToConstructorNodeVisitor;
|
||||
use Rector\Testing\PHPUnit\AbstractReconstructorTestCase;
|
||||
|
||||
final class Test extends AbstractReconstructorTestCase
|
||||
@ -17,7 +17,7 @@ final class Test extends AbstractReconstructorTestCase
|
||||
|
||||
protected function getReconstructorClass(): string
|
||||
{
|
||||
return InjectAnnotationToConstructorReconstructor::class;
|
||||
return InjectAnnotationToConstructorNodeVisitor::class;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Reconstructor\DependencyInjection\NamedServicesToConstructorReconstructor\Source;
|
||||
namespace Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor\Source;
|
||||
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
@ -1,8 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Reconstructor\DependencyInjection\NamedServicesToConstructorReconstructor;
|
||||
namespace Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor;
|
||||
|
||||
use Rector\Reconstructor\DependencyInjection\NamedServicesToConstructorReconstructor;
|
||||
use Rector\NodeVisitor\DependencyInjection\NamedServicesToConstructorNodeVisitor;
|
||||
use Rector\Testing\PHPUnit\AbstractReconstructorTestCase;
|
||||
|
||||
final class Test extends AbstractReconstructorTestCase
|
||||
@ -17,6 +17,6 @@ final class Test extends AbstractReconstructorTestCase
|
||||
|
||||
protected function getReconstructorClass(): string
|
||||
{
|
||||
return NamedServicesToConstructorReconstructor::class;
|
||||
return NamedServicesToConstructorNodeVisitor::class;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user