3 declare(strict_types=1);
5 namespace CuyZ\Valinor\QA\PHPStan\Extension;
8 use PHPStan\Analyser\Scope;
9 use PHPStan\Node\InClassNode;
10 use PHPStan\Rules\Rule;
11 use PHPStan\Rules\RuleErrorBuilder;
13 use function str_starts_with;
16 * @implements Rule<InClassNode>
18 final class ApiAndInternalAnnotationCheck implements Rule
20 public function getNodeType(): string
22 return InClassNode::class;
25 public function processNode(Node $node, Scope $scope): array
27 $reflection = $scope->getClassReflection();
33 if ($reflection->isAnonymous()) {
37 if (str_starts_with($reflection->getName(), 'CuyZ\Valinor\Tests')
38 || str_starts_with($reflection->getName(), 'SimpleNamespace')
43 if (str_starts_with($reflection->getName(), 'CuyZ\Valinor\QA')) {
47 if (! preg_match('/@(api|internal)\s+/', $reflection->getResolvedPhpDoc()?->getPhpDocString() ?? '')) {
49 RuleErrorBuilder::message(
50 'Missing annotation `@api` or `@internal`.'