Skip to content

Commit 0ee7694

Browse files
committed
feat: enums
1 parent 5f8847e commit 0ee7694

File tree

6 files changed

+144
-43
lines changed

6 files changed

+144
-43
lines changed

codemap.txt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ File: Dto/CodemapMethodDto.php
1212

1313
File: Dto/CodemapFileDto.php
1414
Class: Kauffinger\Codemap\Dto\CodemapFileDto
15-
public function __construct(array $classesInFile): mixed
15+
public function __construct(array $classesInFile, array $enumsInFile): mixed
1616

1717
File: Dto/CodemapParameterDto.php
1818
Class: Kauffinger\Codemap\Dto\CodemapParameterDto
1919
public function __construct(string $parameterName, string $parameterType): mixed
2020

21+
File: Dto/CodemapEnumDto.php
22+
Class: Kauffinger\Codemap\Dto\CodemapEnumDto
23+
public function __construct(string $enumName, ?string $backingType, array $cases): mixed
24+
2125
File: Config/CodemapConfig.php
2226
Class: Kauffinger\Codemap\Config\CodemapConfig
2327
private function __construct(): mixed
@@ -28,18 +32,25 @@ File: Config/CodemapConfig.php
2832
public function getConfiguredPhpVersion(): ?Kauffinger\Codemap\Enum\PhpVersion
2933

3034
File: Enum/PhpVersion.php
35+
Enum: Kauffinger\Codemap\Enum\PhpVersion: string
36+
case PHP_8_0 = '8.0'
37+
case PHP_8_1 = '8.1'
38+
case PHP_8_2 = '8.2'
39+
case PHP_8_3 = '8.3'
40+
case PHP_8_4 = '8.4'
3141

32-
File: Generator/ClassCollectionVisitor.php
33-
Class: Kauffinger\Codemap\Generator\ClassCollectionVisitor
42+
File: Generator/SymbolCollectionVisitor.php
43+
Class: Kauffinger\Codemap\Generator\SymbolCollectionVisitor
3444
public function enterNode(PhpParser\Node $node): null|int|PhpParser\Node|array
3545
public function leaveNode(PhpParser\Node $node): null|int|PhpParser\Node|array
3646
private function renderTypeNode(?PhpParser\Node $typeNode): string
3747
private function renderComplexType(PhpParser\Node\ComplexType $node): string
3848
private function handleClassMethod(PhpParser\Node\Stmt\ClassMethod $node): void
3949
private function handleProperty(PhpParser\Node\Stmt\Property $node): void
40-
private function addMethodToCurrentClass(Kauffinger\Codemap\Dto\CodemapMethodDto $method): void
41-
private function addPropertyToCurrentClass(Kauffinger\Codemap\Dto\CodemapPropertyDto $property): void
50+
private function handleEnumCase(PhpParser\Node\Stmt\EnumCase $node): void
51+
private function renderEnumCaseValue(PhpParser\Node $expr): ?string
4252
public property array $collectedClasses
53+
public property array $collectedEnums
4354

4455
File: Generator/CodemapGenerator.php
4556
Class: Kauffinger\Codemap\Generator\CodemapGenerator

src/Dto/CodemapEnumDto.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kauffinger\Codemap\Dto;
6+
7+
final class CodemapEnumDto
8+
{
9+
/**
10+
* @param array<string, string|null> $cases Array of caseName => caseValue|null
11+
*/
12+
public function __construct(
13+
public string $enumName,
14+
public ?string $backingType = null,
15+
public array $cases = []
16+
) {}
17+
}

src/Dto/CodemapFileDto.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
{
99
/**
1010
* @param array<string, CodemapClassDto> $classesInFile Map of FQCN => CodemapClassDto
11+
* @param array<string, CodemapEnumDto> $enumsInFile Map of FQCN => CodemapEnumDto
1112
*/
1213
public function __construct(
13-
public array $classesInFile = []
14+
public array $classesInFile = [],
15+
public array $enumsInFile = [],
1416
) {}
1517
}

src/Formatter/TextCodemapFormatter.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ public function format(array $codemapData): string
3232
}
3333
}
3434
}
35+
36+
foreach ($fileData->enumsInFile as $enumName => $enumDto) {
37+
$backingInfo = $enumDto->backingType ? ": {$enumDto->backingType}" : '';
38+
$lines[] = " Enum: {$enumName}{$backingInfo}";
39+
foreach ($enumDto->cases as $caseName => $caseValue) {
40+
$lines[] = $caseValue === null ? " case {$caseName}" : " case {$caseName} = {$caseValue}";
41+
}
42+
}
43+
3544
$lines[] = '';
3645
}
3746

src/Generator/CodemapGenerator.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use Kauffinger\Codemap\Dto\CodemapFileDto;
1010
use PhpParser\Error;
1111
use PhpParser\NodeTraverser;
12-
use PhpParser\NodeVisitor\NameResolver;
1312
use PhpParser\ParserFactory;
1413
use PhpParser\PhpVersion;
1514
use RecursiveDirectoryIterator;
@@ -190,13 +189,13 @@ private function processSingleFile(string $filePath): CodemapFileDto
190189
throw new RuntimeException("Parse error in '$filePath': ".$parseError->getMessage(), $parseError->getCode(), $parseError);
191190
}
192191

193-
$classCollectionVisitor = new ClassCollectionVisitor;
192+
$symbolCollectionVisitor = new SymbolCollectionVisitor;
194193

195194
$nodeTraverser = new NodeTraverser;
196-
$nodeTraverser->addVisitor(new NameResolver);
197-
$nodeTraverser->addVisitor($classCollectionVisitor);
195+
$nodeTraverser->addVisitor(new \PhpParser\NodeVisitor\NameResolver);
196+
$nodeTraverser->addVisitor($symbolCollectionVisitor);
198197
$nodeTraverser->traverse((array) $abstractSyntaxTree);
199198

200-
return new CodemapFileDto($classCollectionVisitor->collectedClasses);
199+
return new CodemapFileDto($symbolCollectionVisitor->collectedClasses, $symbolCollectionVisitor->collectedEnums);
201200
}
202201
}

src/Generator/ClassCollectionVisitor.php renamed to src/Generator/SymbolCollectionVisitor.php

Lines changed: 95 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Kauffinger\Codemap\Generator;
66

77
use Kauffinger\Codemap\Dto\CodemapClassDto;
8+
use Kauffinger\Codemap\Dto\CodemapEnumDto;
89
use Kauffinger\Codemap\Dto\CodemapMethodDto;
910
use Kauffinger\Codemap\Dto\CodemapParameterDto;
1011
use Kauffinger\Codemap\Dto\CodemapPropertyDto;
@@ -13,52 +14,86 @@
1314
use PhpParser\Node\ComplexType;
1415
use PhpParser\Node\Stmt\Class_;
1516
use PhpParser\Node\Stmt\ClassMethod;
17+
use PhpParser\Node\Stmt\Enum_;
18+
use PhpParser\Node\Stmt\EnumCase;
1619
use PhpParser\Node\Stmt\Property;
1720
use PhpParser\NodeVisitorAbstract;
1821

1922
/**
20-
* A node visitor that collects class definitions (plus methods, properties) into CodemapClassDto objects.
23+
* A node visitor that collects both classes and enums into DTOs.
2124
*/
22-
class ClassCollectionVisitor extends NodeVisitorAbstract
25+
final class SymbolCollectionVisitor extends NodeVisitorAbstract
2326
{
2427
/**
2528
* @var array<string, CodemapClassDto>
2629
*/
2730
public array $collectedClasses = [];
2831

32+
/**
33+
* @var array<string, CodemapEnumDto>
34+
*/
35+
public array $collectedEnums = [];
36+
2937
private ?string $currentClassName = null;
3038

39+
private ?string $currentEnumName = null;
40+
3141
#[Override]
3242
public function enterNode(Node $node): null|int|Node|array
3343
{
44+
// Handle class
3445
if ($node instanceof Class_) {
35-
// Resolve class name (with namespace if available)
3646
$this->currentClassName = $node->namespacedName
3747
? $node->namespacedName->toString()
3848
: (string) $node->name;
3949

40-
// Initialize an empty CodemapClassDto for this class
4150
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto;
4251
}
52+
// Handle enum
53+
elseif ($node instanceof Enum_) {
54+
$this->currentEnumName = $node->namespacedName
55+
? $node->namespacedName->toString()
56+
: (string) $node->name;
57+
58+
// Check if this is a backed enum
59+
$backingType = null;
60+
if ($node->scalarType !== null) {
61+
$backingType = $this->renderTypeNode($node->scalarType);
62+
}
63+
64+
$this->collectedEnums[$this->currentEnumName] = new CodemapEnumDto(
65+
$this->currentEnumName,
66+
$backingType
67+
);
68+
}
4369

4470
return null;
4571
}
4672

4773
#[Override]
4874
public function leaveNode(Node $node): null|int|Node|array
4975
{
50-
if ($this->currentClassName === null) {
51-
return null;
76+
// End of a class
77+
if ($node instanceof Class_ && $this->currentClassName !== null) {
78+
$this->currentClassName = null;
5279
}
53-
54-
if ($node instanceof ClassMethod) {
55-
$this->handleClassMethod($node);
56-
} elseif ($node instanceof Property) {
57-
$this->handleProperty($node);
80+
// End of an enum
81+
elseif ($node instanceof Enum_ && $this->currentEnumName !== null) {
82+
$this->currentEnumName = null;
5883
}
59-
60-
if ($node instanceof Class_) {
61-
$this->currentClassName = null;
84+
// Inside a class
85+
elseif ($this->currentClassName !== null) {
86+
if ($node instanceof ClassMethod) {
87+
$this->handleClassMethod($node);
88+
} elseif ($node instanceof Property) {
89+
$this->handleProperty($node);
90+
}
91+
}
92+
// Inside an enum
93+
elseif ($this->currentEnumName !== null) {
94+
if ($node instanceof EnumCase) {
95+
$this->handleEnumCase($node);
96+
}
6297
}
6398

6499
return null;
@@ -109,7 +144,6 @@ private function handleClassMethod(ClassMethod $node): void
109144
$methodParameters = [];
110145
foreach ($node->getParams() as $param) {
111146
$paramType = $this->renderTypeNode($param->type);
112-
/* @phpstan-ignore-next-line */
113147
$paramName = is_string($param->var->name) ? $param->var->name : 'unknown';
114148
$methodParameters[] = new CodemapParameterDto($paramName, $paramType);
115149
}
@@ -121,7 +155,12 @@ private function handleClassMethod(ClassMethod $node): void
121155
$methodParameters
122156
);
123157

124-
$this->addMethodToCurrentClass($newMethod);
158+
$oldClassDto = $this->collectedClasses[$this->currentClassName];
159+
$updatedMethods = [...$oldClassDto->classMethods, $newMethod];
160+
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
161+
$updatedMethods,
162+
$oldClassDto->classProperties
163+
);
125164
}
126165

127166
/**
@@ -142,33 +181,57 @@ private function handleProperty(Property $node): void
142181
$determinedPropertyType
143182
);
144183

145-
$this->addPropertyToCurrentClass($newProperty);
184+
$oldClassDto = $this->collectedClasses[$this->currentClassName];
185+
$updatedProperties = [...$oldClassDto->classProperties, $newProperty];
186+
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
187+
$oldClassDto->classMethods,
188+
$updatedProperties
189+
);
146190
}
147191
}
148192

149193
/**
150-
* Updates the current class DTO by adding a new method.
194+
* Processes an EnumCase node, adding each case to the current enum.
151195
*/
152-
private function addMethodToCurrentClass(CodemapMethodDto $method): void
196+
private function handleEnumCase(EnumCase $node): void
153197
{
154-
$oldClassDto = $this->collectedClasses[$this->currentClassName];
155-
$updatedMethods = [...$oldClassDto->classMethods, $method];
156-
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
157-
$updatedMethods,
158-
$oldClassDto->classProperties
198+
$enumDto = $this->collectedEnums[$this->currentEnumName];
199+
$caseName = $node->name->toString();
200+
201+
// Attempt to determine the case value for backed enums
202+
$caseValue = null;
203+
if ($node->expr !== null) {
204+
$caseValue = $this->renderEnumCaseValue($node->expr);
205+
}
206+
207+
$enumDto->cases[$caseName] = $caseValue;
208+
$this->collectedEnums[$this->currentEnumName] = new CodemapEnumDto(
209+
$enumDto->enumName,
210+
$enumDto->backingType,
211+
$enumDto->cases
159212
);
160213
}
161214

162215
/**
163-
* Updates the current class DTO by adding a new property.
216+
* Render an enum case's expression to string if possible (backed enums).
164217
*/
165-
private function addPropertyToCurrentClass(CodemapPropertyDto $property): void
218+
private function renderEnumCaseValue(Node $expr): ?string
166219
{
167-
$oldClassDto = $this->collectedClasses[$this->currentClassName];
168-
$updatedProperties = [...$oldClassDto->classProperties, $property];
169-
$this->collectedClasses[$this->currentClassName] = new CodemapClassDto(
170-
$oldClassDto->classMethods,
171-
$updatedProperties
172-
);
220+
if ($expr instanceof Node\Scalar\LNumber) {
221+
return (string) $expr->value;
222+
}
223+
if ($expr instanceof Node\Scalar\String_) {
224+
// Put quotes around string literals
225+
return "'".$expr->value."'";
226+
}
227+
if ($expr instanceof Node\Expr\ClassConstFetch) {
228+
$className = $expr->class->toString();
229+
$constName = $expr->name->toString();
230+
231+
return $className.'::'.$constName;
232+
}
233+
234+
// For other expressions, fallback to null
235+
return null;
173236
}
174237
}

0 commit comments

Comments
 (0)