Skip to content

Commit 03d99ec

Browse files
authored
Add support for attributes on interfaces (#9)
1 parent e035b9a commit 03d99ec

File tree

6 files changed

+86
-2
lines changed

6 files changed

+86
-2
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.1.1](https://github.com/cspray/annotated-target/tree/v0.1.1) - 2022-06-08
9+
10+
### Fixed
11+
12+
- Fixed a bug where Attributes on interfaces were not properly parsed.
13+
814
## [0.1.0](https://github.com/cspray/annotated-target/tree/v0.1.0) - 2022-06-08
915

1016
### Added
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Cspray\AnnotatedTargetFixture\ClassOnlyAttributeSingleInterface;
4+
5+
use Cspray\AnnotatedTargetFixture\ClassOnly;
6+
7+
#[ClassOnly('foo')]
8+
interface FooInterface {
9+
10+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Cspray\AnnotatedTargetFixture;
4+
5+
use Cspray\Typiphy\ObjectType;
6+
use function Cspray\Typiphy\objectType;
7+
8+
class ClassOnlyAttributeSingleInterfaceFixture implements Fixture {
9+
10+
public function getPath() : string {
11+
return __DIR__ .'/ClassOnlyAttributeSingleInterface';
12+
}
13+
14+
public function fooInterface() : ObjectType {
15+
return objectType(ClassOnlyAttributeSingleInterface\FooInterface::class);
16+
}
17+
}

fixture_src/Fixtures.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,8 @@ public static function nonPhpFile() : NonPhpFileFixture {
7878
return new NonPhpFileFixture();
7979
}
8080

81+
public static function classOnlyAttributeSingleInterface() : ClassOnlyAttributeSingleInterfaceFixture {
82+
return new ClassOnlyAttributeSingleInterfaceFixture();
83+
}
84+
8185
}

src/PhpParserAnnotatedTargetParser.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public function leaveNode(Node $node) {
8383
if (!empty($this->filteredAttributes) && !in_array($attrType, $this->filteredAttributes)) {
8484
continue;
8585
}
86-
if ($node instanceof Node\Stmt\Class_) {
86+
if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Interface_) {
8787
($this->consumer)($this->getAnnotatedTargetFromClassNode($node, $index));
8888
} else if ($node instanceof Node\Stmt\Property) {
8989
foreach ($node->props as $prop) {
@@ -106,7 +106,7 @@ public function leaveNode(Node $node) {
106106
}
107107
}
108108

109-
private function getAnnotatedTargetFromClassNode(Node\Stmt\Class_ $class, int $index) : AnnotatedTarget {
109+
private function getAnnotatedTargetFromClassNode(Node\Stmt\Class_|Node\Stmt\Interface_ $class, int $index) : AnnotatedTarget {
110110
$classType = $class->namespacedName->toString();
111111
return $this->getAnnotatedTarget(fn() => new ReflectionClass($classType), $index);
112112
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Cspray\AnnotatedTarget\Unit;
4+
5+
use Cspray\AnnotatedTargetFixture\ClassOnly;
6+
use Cspray\AnnotatedTargetFixture\Fixtures;
7+
use function Cspray\Typiphy\objectType;
8+
9+
uses(AnnotatedTargetParserTestCase::class);
10+
11+
beforeEach()->withFixtures(Fixtures::classOnlyAttributeSingleInterface());
12+
13+
it('counts parsed targets for single class')
14+
->expect(fn() => $this->getTargets())
15+
->toHaveCount(1);
16+
17+
it('ensures all targets are correct type')
18+
->expect(fn() => $this->getTargets())
19+
->toContainOnlyAnnotatedTargets();
20+
21+
it('ensures all targets share target reflection')
22+
->expect(fn() => $this->getTargets())
23+
->toShareTargetReflection();
24+
25+
it('ensures all targets share attribute reflection')
26+
->expect(fn() => $this->getTargets())
27+
->toShareAttributeReflection();
28+
29+
it('ensures all targets share attribute instance')
30+
->expect(fn() => $this->getTargets())
31+
->toShareAttributeInstance();
32+
33+
it('includes target reflection class')
34+
->expect(fn() => $this->getTargets())
35+
->toContainTargetClass(Fixtures::classOnlyAttributeSingleInterface()->fooInterface());
36+
37+
it('includes attribute reflection class')
38+
->expect(fn() => $this->getTargets())
39+
->toContainTargetClassWithAttribute(Fixtures::classOnlyAttributeSingleInterface()->fooInterface(), objectType(ClassOnly::class));
40+
41+
it('includes attribute instance with correct value')
42+
->expect(fn() => $this->getTargets())
43+
->toContainTargetClassWithAttributeInstance(
44+
Fixtures::classOnlyAttributeSingleInterface()->fooInterface(),
45+
objectType(ClassOnly::class),
46+
fn(ClassOnly $classOnly) => $classOnly->value === 'foo'
47+
);

0 commit comments

Comments
 (0)