diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 075e0bd..77f8a41 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -45,8 +45,8 @@ jobs: run: | composer install --no-progress --prefer-dist --optimize-autoloader - #- name: Run Tests - # run: php vendor/bin/phpunit --coverage-text + - name: Run Tests + run: php vendor/bin/phpunit --coverage-text coding-standard: name: Coding Standard diff --git a/src/NodeVisitor/ClassConstant.php b/src/NodeVisitor/ClassConstant.php index 7e5ca6d..8ea8f58 100644 --- a/src/NodeVisitor/ClassConstant.php +++ b/src/NodeVisitor/ClassConstant.php @@ -10,9 +10,11 @@ namespace OpenCodeModeling\CodeAst\NodeVisitor; +use OpenCodeModeling\CodeAst\Code\ClassConstGenerator; use OpenCodeModeling\CodeAst\Code\IdentifierGenerator; use PhpParser\Node; use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\Namespace_; use PhpParser\NodeVisitorAbstract; final class ClassConstant extends NodeVisitorAbstract @@ -27,53 +29,62 @@ public function __construct(IdentifierGenerator $lineGenerator) $this->lineGenerator = $lineGenerator; } - public function enterNode(Node $node) + public static function forClassConstant( + string $constantName, + string $constantValue, + int $flags = ClassConstGenerator::FLAG_PUBLIC + ): ClassConstant { + return new self( + new IdentifierGenerator( + $constantName, + new ClassConstGenerator($constantName, $constantValue, $flags) + ) + ); + } + + public function afterTraverse(array $nodes): ?array { - if ($node instanceof Class_) { - if ($definitions = $this->constant($node)) { + $newNodes = []; + + foreach ($nodes as $node) { + $newNodes[] = $node; + + if ($node instanceof Namespace_) { + foreach ($node->stmts as $stmt) { + if ($stmt instanceof Class_) { + if ($this->checkConstantExists($stmt)) { + return null; + } + $stmt->stmts = \array_merge( + $this->lineGenerator->generate(), + $stmt->stmts + ); + } + } + } elseif ($node instanceof Class_) { + if ($this->checkConstantExists($node)) { + return null; + } $node->stmts = \array_merge( - $definitions, + $this->lineGenerator->generate(), $node->stmts ); - - return $node; } } - return null; + return $newNodes; } - private function isAlreadyDefined( - string $lineIdentifier, - Class_ $node - ): bool { - $alreadyDefined = false; - + private function checkConstantExists(Class_ $node): bool + { foreach ($node->stmts as $stmt) { - if (! $stmt instanceof Node\Stmt\ClassConst) { - continue; - } - - if ($lineIdentifier === $stmt->consts[0]->name->name) { - $alreadyDefined = true; - break; + if ($stmt instanceof Node\Stmt\ClassConst + && $stmt->consts[0]->name->name === $this->lineGenerator->getIdentifier() + ) { + return true; } } - return $alreadyDefined; - } - - private function constant(Class_ $node): ?array - { - $isAlreadyDefined = $this->isAlreadyDefined( - $this->lineGenerator->getIdentifier(), - $node - ); - - if ($isAlreadyDefined === false) { - return $this->lineGenerator->generate(); - } - - return null; + return false; } } diff --git a/tests/NodeVisitor/ClassConstantTest.php b/tests/NodeVisitor/ClassConstantTest.php new file mode 100644 index 0000000..992285e --- /dev/null +++ b/tests/NodeVisitor/ClassConstantTest.php @@ -0,0 +1,144 @@ +parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7); + $this->printer = new Standard(['shortArraySyntax' => true]); + } + + /** + * @test + */ + public function it_generates_constant_for_class_for_empty_file(): void + { + $ast = $this->parser->parse(''); + + $nodeTraverser = new NodeTraverser(); + $nodeTraverser->addVisitor(new StrictType()); + $nodeTraverser->addVisitor(new ClassFile(new ClassGenerator('TestClass'))); + $nodeTraverser->addVisitor(ClassConstant::forClassConstant('TYPE_STRING', 'string')); + + $expected = <<<'EOF' +assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($ast))); + } + + /** + * @test + */ + public function it_generates_constant_for_class_for_existing_file(): void + { + $ast = $this->parser->parse('addVisitor(ClassConstant::forClassConstant('TYPE_STRING', 'string', ClassConstGenerator::FLAG_PRIVATE)); + + $expected = <<<'EOF' +assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($ast))); + } + + /** + * @test + */ + public function it_generates_constant_for_class_with_namespace_for_empty_file(): void + { + $ast = $this->parser->parse(''); + + $nodeTraverser = new NodeTraverser(); + $nodeTraverser->addVisitor(new StrictType()); + $nodeTraverser->addVisitor(new ClassNamespace('My\\Awesome\\Service')); + $nodeTraverser->addVisitor(new ClassFile(new ClassGenerator('TestClass'))); + $nodeTraverser->addVisitor(ClassConstant::forClassConstant('TYPE_STRING', 'string')); + + $expected = <<<'EOF' +assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($ast))); + } + + /** + * @test + */ + public function it_generates_constant_for_class_with_namespace_for_existing_file(): void + { + $code = <<<'PHP' +parser->parse($code); + + $nodeTraverser = new NodeTraverser(); + $nodeTraverser->addVisitor(ClassConstant::forClassConstant('TYPE_STRING', 'string', ClassConstGenerator::FLAG_PRIVATE)); + + $expected = <<<'EOF' +assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($ast))); + } +}