5
5
namespace Kauffinger \Codemap \Generator ;
6
6
7
7
use Kauffinger \Codemap \Dto \CodemapClassDto ;
8
+ use Kauffinger \Codemap \Dto \CodemapEnumDto ;
8
9
use Kauffinger \Codemap \Dto \CodemapMethodDto ;
9
10
use Kauffinger \Codemap \Dto \CodemapParameterDto ;
10
11
use Kauffinger \Codemap \Dto \CodemapPropertyDto ;
13
14
use PhpParser \Node \ComplexType ;
14
15
use PhpParser \Node \Stmt \Class_ ;
15
16
use PhpParser \Node \Stmt \ClassMethod ;
17
+ use PhpParser \Node \Stmt \Enum_ ;
18
+ use PhpParser \Node \Stmt \EnumCase ;
16
19
use PhpParser \Node \Stmt \Property ;
17
20
use PhpParser \NodeVisitorAbstract ;
18
21
19
22
/**
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 .
21
24
*/
22
- class ClassCollectionVisitor extends NodeVisitorAbstract
25
+ final class SymbolCollectionVisitor extends NodeVisitorAbstract
23
26
{
24
27
/**
25
28
* @var array<string, CodemapClassDto>
26
29
*/
27
30
public array $ collectedClasses = [];
28
31
32
+ /**
33
+ * @var array<string, CodemapEnumDto>
34
+ */
35
+ public array $ collectedEnums = [];
36
+
29
37
private ?string $ currentClassName = null ;
30
38
39
+ private ?string $ currentEnumName = null ;
40
+
31
41
#[Override]
32
42
public function enterNode (Node $ node ): null |int |Node |array
33
43
{
44
+ // Handle class
34
45
if ($ node instanceof Class_) {
35
- // Resolve class name (with namespace if available)
36
46
$ this ->currentClassName = $ node ->namespacedName
37
47
? $ node ->namespacedName ->toString ()
38
48
: (string ) $ node ->name ;
39
49
40
- // Initialize an empty CodemapClassDto for this class
41
50
$ this ->collectedClasses [$ this ->currentClassName ] = new CodemapClassDto ;
42
51
}
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
+ }
43
69
44
70
return null ;
45
71
}
46
72
47
73
#[Override]
48
74
public function leaveNode (Node $ node ): null |int |Node |array
49
75
{
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 ;
52
79
}
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 ;
58
83
}
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
+ }
62
97
}
63
98
64
99
return null ;
@@ -109,7 +144,6 @@ private function handleClassMethod(ClassMethod $node): void
109
144
$ methodParameters = [];
110
145
foreach ($ node ->getParams () as $ param ) {
111
146
$ paramType = $ this ->renderTypeNode ($ param ->type );
112
- /* @phpstan-ignore-next-line */
113
147
$ paramName = is_string ($ param ->var ->name ) ? $ param ->var ->name : 'unknown ' ;
114
148
$ methodParameters [] = new CodemapParameterDto ($ paramName , $ paramType );
115
149
}
@@ -121,7 +155,12 @@ private function handleClassMethod(ClassMethod $node): void
121
155
$ methodParameters
122
156
);
123
157
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
+ );
125
164
}
126
165
127
166
/**
@@ -142,33 +181,57 @@ private function handleProperty(Property $node): void
142
181
$ determinedPropertyType
143
182
);
144
183
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
+ );
146
190
}
147
191
}
148
192
149
193
/**
150
- * Updates the current class DTO by adding a new method .
194
+ * Processes an EnumCase node, adding each case to the current enum .
151
195
*/
152
- private function addMethodToCurrentClass ( CodemapMethodDto $ method ): void
196
+ private function handleEnumCase ( EnumCase $ node ): void
153
197
{
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
159
212
);
160
213
}
161
214
162
215
/**
163
- * Updates the current class DTO by adding a new property .
216
+ * Render an enum case's expression to string if possible (backed enums) .
164
217
*/
165
- private function addPropertyToCurrentClass ( CodemapPropertyDto $ property ): void
218
+ private function renderEnumCaseValue ( Node $ expr ): ? string
166
219
{
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 ;
173
236
}
174
237
}
0 commit comments