55namespace Kauffinger \Codemap \Generator ;
66
77use Kauffinger \Codemap \Dto \CodemapClassDto ;
8+ use Kauffinger \Codemap \Dto \CodemapEnumDto ;
89use Kauffinger \Codemap \Dto \CodemapMethodDto ;
910use Kauffinger \Codemap \Dto \CodemapParameterDto ;
1011use Kauffinger \Codemap \Dto \CodemapPropertyDto ;
1314use PhpParser \Node \ComplexType ;
1415use PhpParser \Node \Stmt \Class_ ;
1516use PhpParser \Node \Stmt \ClassMethod ;
17+ use PhpParser \Node \Stmt \Enum_ ;
18+ use PhpParser \Node \Stmt \EnumCase ;
1619use PhpParser \Node \Stmt \Property ;
1720use 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