Skip to content

Commit 5c76254

Browse files
committed
feat: traits, extends & interfaces
1 parent 6e0fe17 commit 5c76254

9 files changed

+308
-29
lines changed

codemap.txt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
File: Dto/CodemapTraitDto.php
2+
Class: Kauffinger\Codemap\Dto\CodemapTraitDto
3+
public function __construct(string $traitName, array $traitMethods, array $traitProperties): mixed
4+
15
File: Dto/CodemapClassDto.php
26
Class: Kauffinger\Codemap\Dto\CodemapClassDto
3-
public function __construct(array $classMethods, array $classProperties): mixed
7+
public function __construct(array $classMethods, array $classProperties, array $usesTraits, ?string $extendsClass, array $implementsInterfaces): mixed
48

59
File: Dto/CodemapPropertyDto.php
610
Class: Kauffinger\Codemap\Dto\CodemapPropertyDto
@@ -12,7 +16,7 @@ File: Dto/CodemapMethodDto.php
1216

1317
File: Dto/CodemapFileDto.php
1418
Class: Kauffinger\Codemap\Dto\CodemapFileDto
15-
public function __construct(array $classesInFile, array $enumsInFile): mixed
19+
public function __construct(array $classesInFile, array $enumsInFile, array $traitsInFile): mixed
1620

1721
File: Dto/CodemapParameterDto.php
1822
Class: Kauffinger\Codemap\Dto\CodemapParameterDto
@@ -41,6 +45,10 @@ File: Enum/PhpVersion.php
4145

4246
File: Generator/SymbolCollectionVisitor.php
4347
Class: Kauffinger\Codemap\Generator\SymbolCollectionVisitor
48+
Extends: PhpParser\NodeVisitorAbstract
49+
public property array $collectedClasses
50+
public property array $collectedEnums
51+
public property array $collectedTraits
4452
public function enterNode(PhpParser\Node $node): null|int|PhpParser\Node|array
4553
public function leaveNode(PhpParser\Node $node): null|int|PhpParser\Node|array
4654
private function renderTypeNode(?PhpParser\Node $typeNode): string
@@ -49,8 +57,6 @@ File: Generator/SymbolCollectionVisitor.php
4957
private function handleProperty(PhpParser\Node\Stmt\Property $node): void
5058
private function handleEnumCase(PhpParser\Node\Stmt\EnumCase $node): void
5159
private function renderEnumCaseValue(PhpParser\Node $expr): ?string
52-
public property array $collectedClasses
53-
public property array $collectedEnums
5460

5561
File: Generator/CodemapGenerator.php
5662
Class: Kauffinger\Codemap\Generator\CodemapGenerator
@@ -72,11 +78,17 @@ File: Formatter/TextCodemapFormatter.php
7278

7379
File: Console/CodemapCommand.php
7480
Class: Kauffinger\Codemap\Console\CodemapCommand
81+
Extends: Symfony\Component\Console\Command\Command
7582
protected function configure(): void
7683
protected function execute(Symfony\Component\Console\Input\InputInterface $input, Symfony\Component\Console\Output\OutputInterface $output): int
7784
protected function handle(): int
85+
private function ensureConfigurationExists(): void
86+
private function loadConfiguration(): Kauffinger\Codemap\Config\CodemapConfig
87+
private function getPhpVersion(Kauffinger\Codemap\Config\CodemapConfig $config): ?Kauffinger\Codemap\Enum\PhpVersion
88+
private function generateCodemap(array $scanPaths, ?Kauffinger\Codemap\Enum\PhpVersion $phpVersion): array
89+
private function writeOutput(string $output, string $outputFile): void
7890
private function generateDefaultConfig(Kauffinger\Codemap\Enum\PhpVersion $mappedPhpVersion): string
7991
protected function info(string $message): void
8092
protected function error(string $message): void
8193
protected function argument(string $name): mixed
82-
protected function option(string $name): mixed
94+
protected function option(string $name): mixed

src/Dto/CodemapClassDto.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@
99
/**
1010
* @param CodemapMethodDto[] $classMethods
1111
* @param CodemapPropertyDto[] $classProperties
12+
* @param string[] $usesTraits Array of FQCNs of used traits
13+
* @param string|null $extendsClass FQCN of the extended class
14+
* @param string[] $implementsInterfaces Array of FQCNs of implemented interfaces
1215
*/
1316
public function __construct(
1417
public array $classMethods = [],
15-
public array $classProperties = []
18+
public array $classProperties = [],
19+
public array $usesTraits = [],
20+
public ?string $extendsClass = null,
21+
public array $implementsInterfaces = []
1622
) {}
1723
}

src/Dto/CodemapFileDto.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
/**
1010
* @param array<string, CodemapClassDto> $classesInFile Map of FQCN => CodemapClassDto
1111
* @param array<string, CodemapEnumDto> $enumsInFile Map of FQCN => CodemapEnumDto
12+
* @param array<string, CodemapTraitDto> $traitsInFile Map of FQCN => CodemapTraitDto
1213
*/
1314
public function __construct(
1415
public array $classesInFile = [],
1516
public array $enumsInFile = [],
17+
public array $traitsInFile = [],
1618
) {}
1719
}

src/Dto/CodemapTraitDto.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kauffinger\Codemap\Dto;
6+
7+
/**
8+
* Represents a single trait in the codemap.
9+
*/
10+
final readonly class CodemapTraitDto
11+
{
12+
/**
13+
* @param CodemapMethodDto[] $traitMethods
14+
* @param CodemapPropertyDto[] $traitProperties
15+
*/
16+
public function __construct(
17+
public string $traitName,
18+
public array $traitMethods = [],
19+
public array $traitProperties = []
20+
) {}
21+
}

src/Formatter/TextCodemapFormatter.php

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use Kauffinger\Codemap\Dto\CodemapParameterDto;
1010
use Kauffinger\Codemap\Dto\CodemapPropertyDto;
1111

12+
// Added
13+
1214
final class TextCodemapFormatter
1315
{
1416
/**
@@ -21,18 +23,34 @@ public function format(array $codemapData): string
2123
$lines = [];
2224
foreach ($codemapData as $fileName => $fileData) {
2325
$lines[] = "File: {$fileName}";
26+
27+
// Format Classes
2428
foreach ($fileData->classesInFile as $className => $classInformation) {
2529
$lines[] = " Class: {$className}";
26-
foreach ($classInformation->classMethods as $methodInformation) {
27-
$lines[] = $this->formatMethod($methodInformation);
30+
if ($classInformation->extendsClass) {
31+
$lines[] = " Extends: {$classInformation->extendsClass}";
32+
}
33+
if ($classInformation->implementsInterfaces !== []) {
34+
$lines[] = ' Implements: '.implode(', ', $classInformation->implementsInterfaces);
35+
}
36+
if ($classInformation->usesTraits !== []) {
37+
$lines[] = ' Uses: '.implode(', ', $classInformation->usesTraits);
2838
}
39+
40+
// Format Public Properties
2941
foreach ($classInformation->classProperties as $propertyInformation) {
3042
if ($propertyInformation->propertyVisibility === 'public') {
3143
$lines[] = $this->formatProperty($propertyInformation);
3244
}
3345
}
46+
// Format Public Methods
47+
foreach ($classInformation->classMethods as $methodInformation) {
48+
// Show all visibilities for methods, unlike properties
49+
$lines[] = $this->formatMethod($methodInformation);
50+
}
3451
}
3552

53+
// Format Enums
3654
foreach ($fileData->enumsInFile as $enumName => $enumDto) {
3755
$backingInfo = $enumDto->backingType ? ": {$enumDto->backingType}" : '';
3856
$lines[] = " Enum: {$enumName}{$backingInfo}";
@@ -41,7 +59,28 @@ public function format(array $codemapData): string
4159
}
4260
}
4361

44-
$lines[] = '';
62+
// Format Traits
63+
foreach ($fileData->traitsInFile as $traitName => $traitDto) {
64+
$lines[] = " Trait: {$traitName}";
65+
// Format Public Properties
66+
foreach ($traitDto->traitProperties as $propertyInformation) {
67+
if ($propertyInformation->propertyVisibility === 'public') {
68+
$lines[] = $this->formatProperty($propertyInformation);
69+
}
70+
}
71+
// Format Public Methods
72+
foreach ($traitDto->traitMethods as $methodInformation) {
73+
// Show all visibilities for methods
74+
$lines[] = $this->formatMethod($methodInformation);
75+
}
76+
}
77+
78+
$lines[] = ''; // Add a blank line after each file's details
79+
}
80+
81+
// Remove trailing blank line if present
82+
if (end($lines) === '') {
83+
array_pop($lines);
4584
}
4685

4786
return implode("\n", $lines);
@@ -74,7 +113,7 @@ private function formatParameters(array $parameters): string
74113
}
75114

76115
/**
77-
* Formats a property's details into a string, for public properties only.
116+
* Formats a property's details into a string.
78117
*/
79118
private function formatProperty(CodemapPropertyDto $propertyInformation): string
80119
{
@@ -86,6 +125,9 @@ private function formatProperty(CodemapPropertyDto $propertyInformation): string
86125
);
87126
}
88127

128+
/**
129+
* Formats an enum case's details into a string.
130+
*/
89131
private function formatEnumCase(?string $caseValue, int|string $caseName): string
90132
{
91133
return $caseValue === null ? " case {$caseName}" : " case {$caseName} = {$caseValue}";

src/Generator/CodemapGenerator.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ private function processSingleFile(string $filePath): CodemapFileDto
196196
$nodeTraverser->addVisitor($symbolCollectionVisitor);
197197
$nodeTraverser->traverse((array) $abstractSyntaxTree);
198198

199-
return new CodemapFileDto($symbolCollectionVisitor->collectedClasses, $symbolCollectionVisitor->collectedEnums);
199+
return new CodemapFileDto(
200+
$symbolCollectionVisitor->collectedClasses,
201+
$symbolCollectionVisitor->collectedEnums,
202+
$symbolCollectionVisitor->collectedTraits // <-- Add this parameter
203+
);
200204
}
201205
}

src/Generator/SymbolCollectionVisitor.php

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Kauffinger\Codemap\Dto\CodemapMethodDto;
1010
use Kauffinger\Codemap\Dto\CodemapParameterDto;
1111
use Kauffinger\Codemap\Dto\CodemapPropertyDto;
12+
use Kauffinger\Codemap\Dto\CodemapTraitDto;
1213
use Override;
1314
use PhpParser\Node;
1415
use PhpParser\Node\ComplexType;
@@ -17,10 +18,11 @@
1718
use PhpParser\Node\Stmt\Enum_;
1819
use PhpParser\Node\Stmt\EnumCase;
1920
use PhpParser\Node\Stmt\Property;
21+
use PhpParser\Node\Stmt\Trait_;
2022
use PhpParser\NodeVisitorAbstract;
2123

2224
/**
23-
* A node visitor that collects both classes and enums into DTOs.
25+
* A node visitor that collects classes, enums, and traits into DTOs.
2426
*/
2527
final class SymbolCollectionVisitor extends NodeVisitorAbstract
2628
{
@@ -34,10 +36,17 @@ final class SymbolCollectionVisitor extends NodeVisitorAbstract
3436
*/
3537
public array $collectedEnums = [];
3638

39+
/**
40+
* @var array<string, CodemapTraitDto>
41+
*/
42+
public array $collectedTraits = [];
43+
3744
private ?string $currentClassName = null;
3845

3946
private ?string $currentEnumName = null;
4047

48+
private ?string $currentTraitName = null;
49+
4150
#[Override]
4251
public function enterNode(Node $node): null|int|Node|array
4352
{
@@ -47,7 +56,24 @@ public function enterNode(Node $node): null|int|Node|array
4756
? $node->namespacedName->toString()
4857
: (string) $node->name;
4958

50-
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto;
59+
// Extract inheritance, implementation, and trait usage
60+
$extends = $node->extends ? $node->extends->toString() : null;
61+
$implements = array_map(fn (Node\Name $name) => $name->toString(), $node->implements);
62+
$uses = [];
63+
foreach ($node->getTraitUses() as $traitUse) {
64+
foreach ($traitUse->traits as $traitName) {
65+
$uses[] = $traitName->toString();
66+
}
67+
}
68+
69+
// Initialize DTO with structural info; methods/props added later
70+
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
71+
[], // Methods added later
72+
[], // Properties added later
73+
$uses,
74+
$extends,
75+
$implements
76+
);
5177
}
5278
// Handle enum
5379
elseif ($node instanceof Enum_) {
@@ -66,6 +92,14 @@ public function enterNode(Node $node): null|int|Node|array
6692
$backingType
6793
);
6894
}
95+
// Handle trait
96+
elseif ($node instanceof Trait_) {
97+
$this->currentTraitName = $node->namespacedName
98+
? $node->namespacedName->toString()
99+
: (string) $node->name; // Fallback, though namespacedName should exist after NameResolver
100+
101+
$this->collectedTraits[$this->currentTraitName] = new CodemapTraitDto($this->currentTraitName);
102+
}
69103

70104
return null;
71105
}
@@ -81,8 +115,12 @@ public function leaveNode(Node $node): null|int|Node|array
81115
elseif ($node instanceof Enum_ && $this->currentEnumName !== null) {
82116
$this->currentEnumName = null;
83117
}
84-
// Inside a class
85-
elseif ($this->currentClassName !== null) {
118+
// End of a trait
119+
elseif ($node instanceof Trait_ && $this->currentTraitName !== null) {
120+
$this->currentTraitName = null;
121+
}
122+
// Inside a class or trait
123+
elseif ($this->currentClassName !== null || $this->currentTraitName !== null) {
86124
if ($node instanceof ClassMethod) {
87125
$this->handleClassMethod($node);
88126
} elseif ($node instanceof Property) {
@@ -130,7 +168,7 @@ private function renderComplexType(ComplexType $node): string
130168
}
131169

132170
/**
133-
* Processes a ClassMethod node, building and adding its DTO to the current class.
171+
* Processes a ClassMethod node, building and adding its DTO to the current class or trait.
134172
*/
135173
private function handleClassMethod(ClassMethod $node): void
136174
{
@@ -156,16 +194,29 @@ private function handleClassMethod(ClassMethod $node): void
156194
$methodParameters
157195
);
158196

159-
$oldClassDto = $this->collectedClasses[$this->currentClassName];
160-
$updatedMethods = [...$oldClassDto->classMethods, $newMethod];
161-
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
162-
$updatedMethods,
163-
$oldClassDto->classProperties
164-
);
197+
if ($this->currentClassName !== null) {
198+
$oldClassDto = $this->collectedClasses[$this->currentClassName];
199+
$updatedMethods = [...$oldClassDto->classMethods, $newMethod];
200+
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
201+
$updatedMethods,
202+
$oldClassDto->classProperties,
203+
$oldClassDto->usesTraits,
204+
$oldClassDto->extendsClass,
205+
$oldClassDto->implementsInterfaces
206+
);
207+
} elseif ($this->currentTraitName !== null) {
208+
$oldTraitDto = $this->collectedTraits[$this->currentTraitName];
209+
$updatedMethods = [...$oldTraitDto->traitMethods, $newMethod];
210+
$this->collectedTraits[$this->currentTraitName] = new CodemapTraitDto(
211+
$oldTraitDto->traitName,
212+
$updatedMethods,
213+
$oldTraitDto->traitProperties
214+
);
215+
}
165216
}
166217

167218
/**
168-
* Processes a Property node, building and adding its DTO(s) to the current class.
219+
* Processes a Property node, building and adding its DTO(s) to the current class or trait.
169220
*/
170221
private function handleProperty(Property $node): void
171222
{
@@ -182,12 +233,25 @@ private function handleProperty(Property $node): void
182233
$determinedPropertyType
183234
);
184235

185-
$oldClassDto = $this->collectedClasses[$this->currentClassName];
186-
$updatedProperties = [...$oldClassDto->classProperties, $newProperty];
187-
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
188-
$oldClassDto->classMethods,
189-
$updatedProperties
190-
);
236+
if ($this->currentClassName !== null) {
237+
$oldClassDto = $this->collectedClasses[$this->currentClassName];
238+
$updatedProperties = [...$oldClassDto->classProperties, $newProperty];
239+
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
240+
$oldClassDto->classMethods,
241+
$updatedProperties,
242+
$oldClassDto->usesTraits,
243+
$oldClassDto->extendsClass,
244+
$oldClassDto->implementsInterfaces
245+
);
246+
} elseif ($this->currentTraitName !== null) {
247+
$oldTraitDto = $this->collectedTraits[$this->currentTraitName];
248+
$updatedProperties = [...$oldTraitDto->traitProperties, $newProperty];
249+
$this->collectedTraits[$this->currentTraitName] = new CodemapTraitDto(
250+
$oldTraitDto->traitName,
251+
$oldTraitDto->traitMethods,
252+
$updatedProperties
253+
);
254+
}
191255
}
192256
}
193257

0 commit comments

Comments
 (0)