From 299b61375f418e96efb0327f40e8d38b6b75ac37 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 30 Oct 2026 00:23:04 +0700 Subject: [PATCH] chore: Bump StructArmed to ^0.20 and use ClassNode isApi/isInternal flags --- tools/structarmed/composer.json | 2 +- .../ClassMustDeclareApiOrInternalRule.php | 6 +- .../src/Rule/InternalClassMustBeFinalRule.php | 3 +- ...rnalMustNotLeakIntoPublicSignatureRule.php | 3 +- ...alNamespaceMustBeAnnotatedInternalRule.php | 3 +- .../src/Support/ClassAnnotations.php | 68 ------------------- 6 files changed, 5 insertions(+), 80 deletions(-) delete mode 100644 tools/structarmed/src/Support/ClassAnnotations.php diff --git a/tools/structarmed/composer.json b/tools/structarmed/composer.json index 87c2899a..d148bae6 100644 --- a/tools/structarmed/composer.json +++ b/tools/structarmed/composer.json @@ -1,6 +1,6 @@ { "require": { - "boundwize/structarmed": "^0.19.0" + "boundwize/structarmed": "^0.20.0" }, "autoload": { "psr-4": { diff --git a/tools/structarmed/src/Rule/ClassMustDeclareApiOrInternalRule.php b/tools/structarmed/src/Rule/ClassMustDeclareApiOrInternalRule.php index 63927705..24705f7f 100644 --- a/tools/structarmed/src/Rule/ClassMustDeclareApiOrInternalRule.php +++ b/tools/structarmed/src/Rule/ClassMustDeclareApiOrInternalRule.php @@ -7,7 +7,6 @@ use Boundwize\StructArmed\Analyser\ClassNode; use Boundwize\StructArmed\Rule\RuleInterface; use Boundwize\StructArmed\Rule\RuleViolation; -use Testo\Tools\StructArmed\Support\ClassAnnotations; /** * Every class-like must state its audience: @api (part of the public contract) or @@ -27,10 +26,7 @@ public function appliesTo(ClassNode $classNode): bool public function evaluate(ClassNode $classNode): ?RuleViolation { - if ( - ClassAnnotations::hasApi($classNode->file, $classNode->shortName()) - || ClassAnnotations::hasInternal($classNode->file, $classNode->shortName()) - ) { + if ($classNode->isApi || $classNode->isInternal) { return null; } diff --git a/tools/structarmed/src/Rule/InternalClassMustBeFinalRule.php b/tools/structarmed/src/Rule/InternalClassMustBeFinalRule.php index d015d619..4992bb59 100644 --- a/tools/structarmed/src/Rule/InternalClassMustBeFinalRule.php +++ b/tools/structarmed/src/Rule/InternalClassMustBeFinalRule.php @@ -7,7 +7,6 @@ use Boundwize\StructArmed\Analyser\ClassNode; use Boundwize\StructArmed\Rule\ExtendedClassAwareRuleInterface; use Boundwize\StructArmed\Rule\RuleViolation; -use Testo\Tools\StructArmed\Support\ClassAnnotations; /** * An @internal class with no subclasses must be final: nothing outside the package @@ -25,7 +24,7 @@ public function appliesTo(ClassNode $classNode): bool return $classNode->isClass() && ! $classNode->isAbstract && $classNode->isInLayer($this->layer) - && ClassAnnotations::hasInternal($classNode->file, $classNode->shortName()); + && $classNode->isInternal; } public function evaluate(ClassNode $classNode): ?RuleViolation diff --git a/tools/structarmed/src/Rule/InternalMustNotLeakIntoPublicSignatureRule.php b/tools/structarmed/src/Rule/InternalMustNotLeakIntoPublicSignatureRule.php index 4b1008b9..679fe1c8 100644 --- a/tools/structarmed/src/Rule/InternalMustNotLeakIntoPublicSignatureRule.php +++ b/tools/structarmed/src/Rule/InternalMustNotLeakIntoPublicSignatureRule.php @@ -8,7 +8,6 @@ use Boundwize\StructArmed\Rule\MultipleRuleViolationInterface; use Boundwize\StructArmed\Rule\RuleInterface; use Boundwize\StructArmed\Rule\RuleViolation; -use Testo\Tools\StructArmed\Support\ClassAnnotations; use Testo\Tools\StructArmed\Support\ClassSignatures; /** @@ -69,6 +68,6 @@ className: $classNode->className, private function isInternal(ClassNode $classNode): bool { return \str_contains($classNode->className, self::SEGMENT) - || ClassAnnotations::hasInternal($classNode->file, $classNode->shortName()); + || $classNode->isInternal; } } diff --git a/tools/structarmed/src/Rule/InternalNamespaceMustBeAnnotatedInternalRule.php b/tools/structarmed/src/Rule/InternalNamespaceMustBeAnnotatedInternalRule.php index 34957ed5..99da9d36 100644 --- a/tools/structarmed/src/Rule/InternalNamespaceMustBeAnnotatedInternalRule.php +++ b/tools/structarmed/src/Rule/InternalNamespaceMustBeAnnotatedInternalRule.php @@ -7,7 +7,6 @@ use Boundwize\StructArmed\Analyser\ClassNode; use Boundwize\StructArmed\Rule\RuleInterface; use Boundwize\StructArmed\Rule\RuleViolation; -use Testo\Tools\StructArmed\Support\ClassAnnotations; /** * Anything living under an `Internal` namespace segment is implementation detail and @@ -27,7 +26,7 @@ public function appliesTo(ClassNode $classNode): bool public function evaluate(ClassNode $classNode): ?RuleViolation { - return ClassAnnotations::hasInternal($classNode->file, $classNode->shortName()) ? null : new RuleViolation( + return $classNode->isInternal ? null : new RuleViolation( message: \sprintf('%s [%s] lives under an Internal namespace and must be annotated @internal', $classNode->getType(), $classNode->className), file: $classNode->file, line: $classNode->line, diff --git a/tools/structarmed/src/Support/ClassAnnotations.php b/tools/structarmed/src/Support/ClassAnnotations.php deleted file mode 100644 index 4f39f029..00000000 --- a/tools/structarmed/src/Support/ClassAnnotations.php +++ /dev/null @@ -1,68 +0,0 @@ -> file => short class name => docblock text */ - private static array $cache = []; - - public static function hasApi(string $file, string $shortName): bool - { - return self::hasTag(self::docblock($file, $shortName), 'api'); - } - - public static function hasInternal(string $file, string $shortName): bool - { - return self::hasTag(self::docblock($file, $shortName), 'internal'); - } - - private static function hasTag(string $docblock, string $tag): bool - { - return \preg_match('/@' . $tag . '\b/', $docblock) === 1; - } - - private static function docblock(string $file, string $shortName): string - { - return (self::$cache[$file] ??= self::parse($file))[$shortName] ?? ''; - } - - /** - * @return array - */ - private static function parse(string $file): array - { - $code = @\file_get_contents($file); - - if ($code === false) { - return []; - } - - try { - $ast = (new ParserFactory())->createForNewestSupportedVersion()->parse($code) ?? []; - } catch (\Throwable) { - return []; - } - - $docblocks = []; - - foreach ((new NodeFinder())->findInstanceOf($ast, ClassLike::class) as $node) { - $name = $node->name?->toString(); - - $name === null or $docblocks[$name] = $node->getDocComment()?->getText() ?? ''; - } - - return $docblocks; - } -}