From b4646a885821beaa04d20308879d18118bea588e Mon Sep 17 00:00:00 2001 From: Tim Hatch Date: Wed, 29 Apr 2026 14:49:30 +0000 Subject: [PATCH] Fix nested array-of-tables generating wrong source map paths [[a.b]] and deeper nested AoTs were stored at /a/b/0 instead of /a/0/b/0 because _process_aot did not inject parent AoT indices. Two related fixes: - _process_aot: expand only the prefix segments (all but the last, which names the AoT being defined), so parent AoT indices are injected without the AoT injecting its own index into itself. - _expand_aot_segments: rewrite to walk segments left-to-right and insert an index after each segment that resolves to a known AoT pointer, instead of stopping after the first match. This correctly handles arbitrarily deep nesting. --- parse_errors/toml_source_map/__init__.py | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/parse_errors/toml_source_map/__init__.py b/parse_errors/toml_source_map/__init__.py index b3277de..4d0ab14 100644 --- a/parse_errors/toml_source_map/__init__.py +++ b/parse_errors/toml_source_map/__init__.py @@ -96,7 +96,10 @@ def _process_aot( src: bytes, ) -> None: key_node = _table_key(node) - segments = _key_segments(key_node) + raw_segments = _key_segments(key_node) + # Expand parent AoT indices into the prefix, but not the final segment + # (which names the AoT being defined, not a parent of it). + segments = _expand_aot_segments(raw_segments[:-1], aot_counts) + raw_segments[-1:] array_pointer = _to_pointer(segments) idx = aot_counts.get(array_pointer, 0) @@ -165,17 +168,23 @@ def _unquote(s: str) -> str: def _expand_aot_segments(segments: list[str], aot_counts: dict[str, int]) -> list[str]: - """If a prefix of segments matches a known AoT, splice in its current index. + """Splice the current AoT index after each segment that is a known AoT key. + + Walks segments left-to-right, building up the pointer incrementally. + After appending each segment, if the resulting pointer is a known AoT, + the current index (count - 1) is inserted before moving to the next segment. + This handles arbitrarily deep nesting. e.g. segments=[fruits, details] with aot_counts={/fruits: 1} → [fruits, 0, details] """ - for i in range(1, len(segments)): - prefix_pointer = _to_pointer(segments[:i]) - if prefix_pointer in aot_counts: - idx = aot_counts[prefix_pointer] - 1 - return segments[:i] + [str(idx)] + segments[i:] - return segments + result: list[str] = [] + for seg in segments: + result.append(seg) + candidate = _to_pointer(result) + if candidate in aot_counts: + result.append(str(aot_counts[candidate] - 1)) + return result def _to_pointer(segments: list[str]) -> str: