Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
AddMissingClassPhpDocRector
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
3 / 3
6
100.00% covered (success)
100.00%
1 / 1
 getRuleDefinition
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getNodeTypes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 refactor
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5/**
6 * This file is part of fast-forward/dev-tools.
7 *
8 * This source file is subject to the license bundled
9 * with this source code in the file LICENSE.
10 *
11 * @copyright Copyright (c) 2026 Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
12 * @license   https://opensource.org/licenses/MIT MIT License
13 *
14 * @see       https://github.com/php-fast-forward/dev-tools
15 * @see       https://github.com/php-fast-forward
16 * @see       https://datatracker.ietf.org/doc/html/rfc2119
17 */
18
19namespace FastForward\DevTools\Rector;
20
21use PhpParser\Comment\Doc;
22use PhpParser\Node;
23use Rector\Rector\AbstractRector;
24use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
25use PhpParser\Node\Stmt\Class_;
26
27/**
28 * Provides automated refactoring to prepend basic PHPDoc comments on classes missing them.
29 * This rule MUST adhere to AST standards and SHALL traverse `Class_` nodes exclusively.
30 */
31final class AddMissingClassPhpDocRector extends AbstractRector
32{
33    /**
34     * Resolves the definition describing this rule for documentation generation.
35     *
36     * The method MUST return a properly instantiated RuleDefinition stating its purpose.
37     *
38     * @return RuleDefinition the description entity for the given Rector rule
39     */
40    public function getRuleDefinition(): RuleDefinition
41    {
42        return new RuleDefinition('Add basic PHPDoc to classes without docblock', [
43            new \Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample(
44                'class SomeClass {}',
45                "/**\n * SomeClass\n */\nclass SomeClass {}"
46            )
47        ]);
48    }
49
50    /**
51     * Declares the types of Abstract Syntax Tree nodes that trigger this refactoring run.
52     *
53     * The method MUST identify `Class_` nodes reliably. It SHALL define the interception target.
54     *
55     * @return array<int, class-string<Node>> an array containing registered node class references
56     */
57    public function getNodeTypes(): array
58    {
59        return [Class_::class];
60    }
61
62    /**
63     * Triggers the modification process against a matched AST node.
64     *
65     * The method MUST verify the absence of an existing PHPDoc header accurately.
66     * It SHOULD append a basic boilerplate PHPDoc comment if applicable.
67     * If the node is unchanged, it SHALL return null.
68     *
69     * @param Node $node the current active syntax instance parsed by the framework
70     *
71     * @return Node|null the modified active syntax state, or null if untouched
72     */
73    public function refactor(Node $node): ?Node
74    {
75        if (! $node instanceof Class_) {
76            return null;
77        }
78
79        if ($node->getDocComment() instanceof Doc) {
80            return null;
81        }
82
83        $className = $this->getName($node->name) ?? 'Class';
84        $namespace = $node->namespacedName?->slice(0, -1)
85            ->toString() ?? '';
86
87        $lines = ['/**'];
88        $lines[] = \sprintf(' * %s', $className);
89
90        if ('' !== $namespace) {
91            $lines[] = ' *';
92            $lines[] = \sprintf(' * @package %s', $namespace);
93        }
94
95        $lines[] = ' */';
96
97        $node->setDocComment(new Doc(implode("\n", $lines)));
98
99        return $node;
100    }
101}