@@ -26,8 +26,11 @@ public function convert(array $data): Document
2626 $ nodes = [];
2727 $ position = new Position (1 , 1 , 0 );
2828
29- // Categorize data into root entries, tables, and table arrays
30- [$ rootEntries , $ tables , $ tableArrays ] = $ this ->categorizeData ($ data );
29+ // Flatten the data structure to handle nested tables
30+ $ flatData = $ this ->flattenData ($ data );
31+
32+ // Categorize flattened data into root entries, tables, and table arrays
33+ [$ rootEntries , $ tables , $ tableArrays ] = $ this ->categorizeData ($ flatData );
3134
3235 // Root key-value pairs first
3336 foreach ($ rootEntries as $ key => $ value ) {
@@ -49,6 +52,65 @@ public function convert(array $data): Document
4952 return new Document ($ nodes , $ position );
5053 }
5154
55+ /**
56+ * Flattens nested array structure into dotted keys.
57+ *
58+ * Example:
59+ * ['github' => ['token' => ['key' => 'val']]]
60+ * becomes:
61+ * ['github.token' => ['key' => 'val']]
62+ *
63+ * @param array<string, mixed> $data
64+ * @param string $prefix
65+ * @return array<string, mixed>
66+ */
67+ private function flattenData (array $ data , string $ prefix = '' ): array
68+ {
69+ $ result = [];
70+
71+ foreach ($ data as $ key => $ value ) {
72+ if (!\is_string ($ key )) {
73+ throw new \InvalidArgumentException ('TOML keys must be strings, got: ' . \get_debug_type ($ key ));
74+ }
75+
76+ $ fullKey = $ prefix === '' ? $ key : $ prefix . '. ' . $ key ;
77+
78+ if (!\is_array ($ value )) {
79+ // Scalar value
80+ $ result [$ fullKey ] = $ value ;
81+ } elseif ($ this ->isTableArray ($ value )) {
82+ // Table array - keep as is
83+ $ result [$ fullKey ] = $ value ;
84+ } elseif ($ this ->isAssociativeArray ($ value )) {
85+ // Check if this table has only scalar/array values (leaf table)
86+ // or if it has nested tables
87+ $ hasNestedTables = false ;
88+ foreach ($ value as $ subValue ) {
89+ if (\is_array ($ subValue ) && $ this ->isAssociativeArray ($ subValue ) && !$ this ->isTableArray ($ subValue )) {
90+ $ hasNestedTables = true ;
91+ break ;
92+ }
93+ }
94+
95+ if ($ hasNestedTables ) {
96+ // Recursively flatten nested tables
97+ $ flattened = $ this ->flattenData ($ value , $ fullKey );
98+ foreach ($ flattened as $ flatKey => $ flatValue ) {
99+ $ result [$ flatKey ] = $ flatValue ;
100+ }
101+ } else {
102+ // Leaf table - keep as is
103+ $ result [$ fullKey ] = $ value ;
104+ }
105+ } else {
106+ // Simple array (list of scalars)
107+ $ result [$ fullKey ] = $ value ;
108+ }
109+ }
110+
111+ return $ result ;
112+ }
113+
52114 /**
53115 * Categorizes data into root entries, tables, and table arrays.
54116 *
@@ -102,18 +164,14 @@ private function createTable(string $name, array $data): Table
102164 $ entries = [];
103165 $ position = new Position (0 , 0 , 0 );
104166
105- // Categorize table data
106- [ $ rootEntries , $ nestedTables , $ nestedTableArrays ] = $ this -> categorizeData ( $ data );
107-
108- // Add root entries
109- foreach ( $ rootEntries as $ key => $ value ) {
167+ // Add all entries ( data is already flattened, so no nested tables here)
168+ foreach ( $ data as $ key => $ value ) {
169+ if (! \is_string ( $ key )) {
170+ throw new \ InvalidArgumentException ( ' TOML keys must be strings, got: ' . \get_debug_type ( $ key ));
171+ }
110172 $ entries [] = $ this ->createEntry ($ key , $ value );
111173 }
112174
113- // Nested tables and table arrays will be handled at document level
114- // For now, we only handle simple table entries
115- // TODO: Handle nested structures properly
116-
117175 return new Table ($ keyNode , $ entries , null , $ position );
118176 }
119177
0 commit comments