Skip to content

Commit 0152269

Browse files
committed
Support custom node visitors in class and interface builder - Close #65
1 parent e2f0df5 commit 0152269

File tree

3 files changed

+107
-2
lines changed

3 files changed

+107
-2
lines changed

src/Builder/ClassBuilder.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ final class ClassBuilder implements File
6464
/** @var ClassMethodBuilder[] */
6565
private array $methods = [];
6666

67+
/** @var NodeVisitor[] */
68+
private array $nodeVisitors = [];
69+
6770
private function __construct()
6871
{
6972
}
@@ -414,6 +417,18 @@ public function hasMethod(string $methodName): bool
414417
return isset($this->methods[$methodName]);
415418
}
416419

420+
public function setNodeVisitors(NodeVisitor ...$nodeVisitors): void
421+
{
422+
$this->nodeVisitors = $nodeVisitors;
423+
}
424+
425+
public function addNodeVisitor(NodeVisitor ...$nodeVisitors): void
426+
{
427+
foreach ($nodeVisitors as $nodeVisitor) {
428+
$this->nodeVisitors[] = $nodeVisitor;
429+
}
430+
}
431+
417432
public function getNamespace(): ?string
418433
{
419434
return $this->namespace;
@@ -649,7 +664,7 @@ static function (ClassMethodBuilder $method) use ($parser) {
649664
);
650665
}
651666

652-
return $visitors;
667+
return \array_merge($visitors, $this->nodeVisitors);
653668
}
654669

655670
private function unpackNode(Node $node): void

src/Builder/InterfaceBuilder.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ final class InterfaceBuilder implements File
4747
/** @var ClassMethodBuilder[] */
4848
private array $methods = [];
4949

50+
/** @var NodeVisitor[] */
51+
private array $nodeVisitors = [];
52+
5053
private function __construct()
5154
{
5255
}
@@ -265,6 +268,18 @@ public function hasMethod(string $methodName): bool
265268
return isset($this->methods[$methodName]);
266269
}
267270

271+
public function setNodeVisitors(NodeVisitor ...$nodeVisitors): void
272+
{
273+
$this->nodeVisitors = $nodeVisitors;
274+
}
275+
276+
public function addNodeVisitor(NodeVisitor ...$nodeVisitors): void
277+
{
278+
foreach ($nodeVisitors as $nodeVisitor) {
279+
$this->nodeVisitors[] = $nodeVisitor;
280+
}
281+
}
282+
268283
/**
269284
* Uses uasort internally
270285
*
@@ -402,7 +417,7 @@ static function (ClassMethodBuilder $method) use ($parser) {
402417
);
403418
}
404419

405-
return $visitors;
420+
return \array_merge($visitors, $this->nodeVisitors);
406421
}
407422

408423
private function unpackNode(Node $node): void

tests/Builder/ClassBuilderTest.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212

1313
use OpenCodeModeling\CodeAst\Builder\ClassBuilder;
1414
use OpenCodeModeling\CodeAst\Builder\ClassConstBuilder;
15+
use OpenCodeModeling\CodeAst\Builder\ClassMethodBuilder;
16+
use PhpParser\Node;
1517
use PhpParser\NodeTraverser;
18+
use PhpParser\NodeVisitor;
19+
use PhpParser\NodeVisitorAbstract;
1620
use PhpParser\Parser;
1721
use PhpParser\ParserFactory;
1822
use PhpParser\PrettyPrinter\Standard;
@@ -462,4 +466,75 @@ final class TestClass
462466

463467
$this->assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($this->parser->parse(''))));
464468
}
469+
470+
/**
471+
* @test
472+
*/
473+
public function it_supports_adding_of_node_visitors(): void
474+
{
475+
$ast = $this->parser->parse('');
476+
477+
$classFactory = ClassBuilder::fromScratch('TestClass', 'My\\Awesome\\Service');
478+
$classFactory->setMethods(
479+
ClassMethodBuilder::fromScratch('setActive')->setReturnType('void')->setStatic(true)
480+
);
481+
482+
$classFactory->addNodeVisitor($this->getSetActiveNodeVisitor());
483+
484+
$nodeTraverser = new NodeTraverser();
485+
$classFactory->injectVisitors($nodeTraverser, $this->parser);
486+
487+
$expected = <<<'EOF'
488+
<?php
489+
490+
declare (strict_types=1);
491+
namespace My\Awesome\Service;
492+
493+
class TestClass
494+
{
495+
public static function setActive() : void
496+
{
497+
$tmp = $this->get();
498+
}
499+
}
500+
EOF;
501+
502+
$this->assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($ast)));
503+
}
504+
505+
private function getSetActiveNodeVisitor(): NodeVisitor
506+
{
507+
$nodes = $this->parser->parse('<?php $tmp = $this->get();');
508+
509+
return new class($nodes) extends NodeVisitorAbstract {
510+
private $nodes;
511+
512+
public function __construct($nodes)
513+
{
514+
$this->nodes = $nodes;
515+
}
516+
517+
public function afterTraverse(array $nodes)
518+
{
519+
$newNodes = [];
520+
521+
foreach ($nodes as $node) {
522+
$newNodes[] = $node;
523+
524+
if (! $node instanceof Node\Stmt\Class_) {
525+
continue;
526+
}
527+
528+
if ($node->stmts[0] instanceof Node\Stmt\ClassMethod
529+
&& $node->stmts[0]->name instanceof Node\Identifier
530+
&& $node->stmts[0]->name->name === 'setActive'
531+
) {
532+
$node->stmts[0]->stmts = $this->nodes;
533+
}
534+
}
535+
536+
return $newNodes;
537+
}
538+
};
539+
}
465540
}

0 commit comments

Comments
 (0)