|
12 | 12 | - Key classes: |
13 | 13 | - `ClassDiagram`: Aggregates nodes and relationships; renders Mermaid text. |
14 | 14 | - `ClassDiagramBuilder`: Facade to parse and assemble nodes/relationships. |
15 | | - - `Node/*`: Type representations (`Class_`, `AbstractClass_`, `Interface_`, `Enum_`) and the common abstract `Node`, plus the `Nodes` collection. |
16 | | - - `Node/Relationship/*`: Relationship representations (`Inheritance`, `Realization`, `Composition`, `Dependency`). |
| 15 | + - `Node/*`: Type representations (`Class_`, `AbstractClass_`, `Interface_`, `Enum_`, `Trait_`) with common abstract `Node`, and the `Nodes` collection. |
| 16 | + - `Node/Relationship/*`: Relationship representations (`Inheritance`, `Realization`, `Composition`, `Dependency`, `TraitUsage`) and the `Relationships` collection. |
17 | 17 | - `Node/Connector/*`: Extract relationship information from the AST and connect `Node`s on `Nodes`. |
18 | 18 | - `Node/NodeParser`: Uses Finder to collect files, PHP-Parser to build AST, and Connectors to extract relationships. |
| 19 | + - `TraitRenderMode`: Rendering strategy for traits (WithTraits or Flatten). |
| 20 | + - `ClassDiagramDumper`: Debug utility to dump YAML-like structure of nodes/relationships (via reflection). |
19 | 21 | - `Console/Command/GenerateCommand.php`: Symfony Console command (`generate --path`). |
20 | 22 | - `mermaid-class-diagram`: Executable binary that boots the Console app. |
21 | 23 | - `tests/`: PHPUnit tests and fixtures (`tests/data/Project/*`). |
22 | 24 |
|
23 | 25 | ## Domain Model |
24 | 26 | ### Nodes (types) |
25 | | -- `Node` (abstract) |
| 27 | + - `Node` (abstract) |
26 | 28 | - Minimal representation of a type with `$name`. |
27 | 29 | - Holds source collections for relationships: |
28 | 30 | - `$extends`, `$implements`, `$properties` (composition), `$depends` (dependency) |
29 | 31 | - `relationships()`: Builds an array of `Relationship` objects from the above collections. |
30 | 32 | - De-duplicates and filters: removes conflicts (e.g., dependency also present as composition/inheritance/realization) and self references. |
31 | 33 | - `sortNodes(array &$nodes)`: Sorts by node name (ascending). |
32 | 34 | - Concrete types |
33 | | - - `Class_`, `AbstractClass_`, `Interface_`, `Enum_` |
34 | | - - `render()`: Outputs Mermaid `class` syntax; stereotypes `<<abstract>>`, `<<interface>>`, `<<enum>>` when applicable. |
35 | | -- `Nodes` |
36 | | - - Dictionary-like collection keyed by node name. |
37 | | - - Provides `add()`, `findByName()`, `getAllNodes()`. |
| 35 | + - `Class_`, `AbstractClass_`, `Interface_`, `Enum_`, `Trait_` |
| 36 | + - `render()`: Outputs Mermaid `class` syntax; stereotypes `<<abstract>>`, `<<interface>>`, `<<enum>>`, `<<trait>>` when applicable. |
| 37 | + - `Nodes` |
| 38 | + - Dictionary-like collection keyed by node name. |
| 39 | + - Provides `add()`, `findByName()`, `getAll()` and `sort()`. |
| 40 | + - `optimize(RenderOptions $options)`: view-time pruning (e.g., hide trait nodes in Flatten mode). Internally uses a private filter. |
38 | 41 |
|
39 | 42 | ### Relationships |
40 | 43 | - `Relationship` (abstract): Holds `from` and `to`; `render()` outputs Mermaid edges. |
|
53 | 56 | - Input: `--path` may be a directory (glob `*.php`) or a single file (`Symfony\Component\Finder\Finder`). |
54 | 57 | - Preparation: Build AST with `PhpParser`; run `NameResolver` and `ParentConnectingVisitor`. |
55 | 58 | - Class-like detection: |
56 | | - - Gather `Stmt\ClassLike` (Class/Interface/Enum) and also `Stmt\Trait_` nodes, but only Class/Interface/Enum become `Node`s. |
| 59 | + - Gather `Stmt\ClassLike` (Class/Interface/Enum) and also `Stmt\Trait_` nodes; Class, Interface, Enum, and Trait all become `Node`s. |
57 | 60 | - If no valid class-like found in a file, skip via `CannnotParseToClassLikeException`. |
58 | 61 | - Two-phase processing: |
59 | 62 | - Phase 1: Create `Node` (`Class_`/`AbstractClass_`/`Interface_`/`Enum_`) for each valid class-like and add to `Nodes`. |
|
72 | 75 | - Method return types of `Name` are dependencies. |
73 | 76 | - `new` expressions (`Expr\New_`) add dependencies. |
74 | 77 | - Filters out `self` and de-duplicates. |
| 78 | + - `TraitUsageConnector` |
| 79 | + - Records `use TraitName;` for class-like nodes (classes and traits). |
| 80 | + - Enables render-time merging/flattening of trait-derived associations into the using node. |
75 | 81 |
|
76 | 82 | ## Rendering |
77 | 83 | - `ClassDiagram::render()` |
78 | | - - Sorts nodes by name; sorts relationships by `from to`. |
| 84 | + - Applies `Nodes::optimize($options)->sort()` and `Relationships::optimize($options)->sort()`. |
79 | 85 | - Emits nodes first, then a blank line, then relationships. |
80 | 86 | - Header line `classDiagram`; each subsequent line is indented by 4 spaces. |
81 | 87 | - Examples |
|
88 | 94 | - `includeCompositions`: show/hide `Composition` edges (properties/constructor promotion/FQCN properties) |
89 | 95 | - `includeInheritances`: show/hide `Inheritance` edges (`extends`) |
90 | 96 | - `includeRealizations`: show/hide `Realization` edges (`implements`) |
| 97 | + - `traitRenderMode` (`TraitRenderMode`): trait rendering policy (default Flatten). |
| 98 | + |
| 99 | +#### Trait rendering modes |
| 100 | +- `WithTraits`: |
| 101 | + - Show trait nodes and `use` edges. |
| 102 | + - Keep trait-origin composition/dependency edges attached to the trait. |
| 103 | + - Suppress duplicate class-level composition/dependency when already provided by a used trait. |
| 104 | +- `Flatten`: |
| 105 | + - Hide trait nodes and `use` edges. |
| 106 | + - Reassign trait-origin composition/dependency edges to the using classes. |
| 107 | + - Transitive flattening: handles trait→trait→class chains (reassign to final class users), with deduplication. |
| 108 | + - Apply `include*` filters after optimization. |
| 109 | + |
| 110 | +### Relationships optimization |
| 111 | +- `Relationships::optimize(RenderOptions $options)` performs view-time transformations before rendering: |
| 112 | + - Delegates to private implementations per mode: |
| 113 | + - `optimizeWithTraitsInternal()`: keep traits/`use`, suppress class-level duplicates for comp/dep. |
| 114 | + - `optimizeFlattenInternal()`: hide traits/`use`, reassign trait-origin edges to class users (including transitive chains), deduplicate. |
| 115 | + - Applies include flags via private `filterByOptions()`. |
| 116 | + |
| 117 | +### Debug dumper |
| 118 | +- `ClassDiagramDumper::toYaml(RenderOptions $options = null): string` |
| 119 | + - Uses reflection to access the diagram’s internals and emits a YAML-like structure for debugging. |
| 120 | + - Mirrors `render()`’s optimize/sort policy so the dump matches what would be rendered under the same options. |
91 | 121 |
|
92 | 122 | ## CLI |
93 | 123 | - Entry: `mermaid-class-diagram` |
|
104 | 134 | - `symfony/finder` (^7.0): File discovery. |
105 | 135 | - `symfony/console` (^7.0): CLI framework. |
106 | 136 | - Dev |
107 | | - - `phpunit/phpunit` (^9.5): Unit tests. |
| 137 | + - `phpunit/phpunit`: Unit tests. |
108 | 138 |
|
109 | 139 | ## Notes and Trade-offs |
110 | 140 | - Type resolution simplifications |
|
114 | 144 | - Types referenced but not defined in the scan scope are synthesized as minimal `Node`s so relationships still render. |
115 | 145 | - This may produce nodes in the output with empty bodies. |
116 | 146 | - Traits |
117 | | - - Traits are detected in AST collection but not rendered as nodes; only Class/Interface/Enum are supported. |
| 147 | + - Participates fully in AST analysis and can be rendered as nodes depending on `TraitRenderMode`. |
| 148 | + - WithTraits: show trait nodes and `use` edges, suppress duplicate class-level comp/dep provided by traits. |
| 149 | + - Flatten: hide trait nodes and `use` edges; reassign trait-origin comp/dep to using classes, including transitive trait chains; deduplicate. |
118 | 150 | - Safety |
119 | 151 | - Never executes target PHP; analysis is static and AST-based. |
120 | 152 | - CLI does not currently validate `--path` beyond being required. |
|
125 | 157 | - Compare `ClassDiagram`/`ClassDiagramBuilder` output against precise expected strings. |
126 | 158 | - Fixtures |
127 | 159 | - `tests/data/Project/*` provides a small pseudo-app to cover common patterns. |
| 160 | + - `tests/data/TraitChain/*` covers trait→trait chains and flattening behavior. |
128 | 161 |
|
129 | 162 | ## Extensibility |
130 | 163 | - New relationships |
|
0 commit comments