Skip to content

Commit e9c4324

Browse files
Chris Xuclaude
andcommitted
fix(decoder): handle nested list-format arrays correctly (#7)
The decoder was incorrectly parsing nested list-format arrays like `[[[1]]]` because it couldn't distinguish between inline arrays (`[N]: val1,val2`) and list-format array headers (`[N]:` with nested content below). Changes: - Updated regex patterns to require content after `: ` for inline arrays - Added new case for list-format array headers ending with `:$` - Added `parse_nested_list_array` function using existing helpers - Consolidated edge_cases_test.exs into roundtrip_test.exs - Renamed test file to roundtrip_test.exs (more idiomatic name) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 2b052b8 commit e9c4324

File tree

3 files changed

+395
-90
lines changed

3 files changed

+395
-90
lines changed

lib/toon/decode/structural_parser.ex

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,8 +582,9 @@ defmodule Toon.Decode.StructuralParser do
582582
parse_list_items(rest, expected_indent, opts, acc)
583583
end
584584

585-
# Inline array item (check before general list marker)
586-
String.match?(line.content, ~r/^\s*- \[.*\]:/) ->
585+
# Inline array item with values on same line: - [N]: val1,val2
586+
# (must have content after ": ", otherwise it's a list-format array header)
587+
String.match?(line.content, ~r/^\s*- \[.*\]: .+/) ->
587588
{item, remaining} = parse_inline_array_item(line, rest, expected_indent, opts)
588589
parse_list_items(remaining, expected_indent, opts, [item | acc])
589590

@@ -614,10 +615,14 @@ defmodule Toon.Decode.StructuralParser do
614615
trimmed == "" or String.trim(trimmed) == "" ->
615616
{%{}, rest}
616617

617-
String.match?(trimmed, ~r/^\[.*?\]:/) ->
618-
# This is an inline array within a list item
618+
# Inline array with values on same line: [N]: val1,val2 (has content after ": ")
619+
String.match?(trimmed, ~r/^\[.*?\]: .+/) ->
619620
parse_inline_array_from_line(trimmed, rest)
620621

622+
# List-format array header only: [N]: (no content after colon, nested items below)
623+
String.match?(trimmed, ~r/^\[#?\d+[^\]]*\]:$/) ->
624+
parse_nested_list_array(trimmed, rest, line, expected_indent, opts)
625+
621626
# Tabular array as first field: key[N]{fields}: (with optional quoted key)
622627
String.match?(trimmed, ~r/^(?:"[^"]*"|\w+)\[#?\d+.*\]\{[^}]+\}:$/) ->
623628
parse_list_item_with_array(trimmed, rest, line, expected_indent, opts, :tabular)
@@ -962,6 +967,21 @@ defmodule Toon.Decode.StructuralParser do
962967
end
963968
end
964969

970+
# Parse nested list-format array within a list item (e.g., "- [1]:" with nested items)
971+
defp parse_nested_list_array(_trimmed, rest, _line, expected_indent, opts) do
972+
array_lines = take_nested_lines(rest, expected_indent)
973+
974+
if Enum.empty?(array_lines) do
975+
{[], rest}
976+
else
977+
nested_indent = get_first_content_indent(array_lines)
978+
array_items = parse_list_items(array_lines, nested_indent, opts, [])
979+
{rest_after_array, _} = skip_nested_lines(rest, expected_indent)
980+
981+
{array_items, rest_after_array}
982+
end
983+
end
984+
965985
# Parse inline array item in list
966986
defp parse_inline_array_item(%{content: content}, rest, _expected_indent, _opts) do
967987
trimmed = String.trim_leading(content) |> String.replace_prefix("- ", "")

test/toon/edge_cases_test.exs

Lines changed: 0 additions & 86 deletions
This file was deleted.

0 commit comments

Comments
 (0)