fix(slack): guard blank-line list continuation on next-item lookahead

Refine the blank-line handling so a blank line only continues a list run
when the next non-blank line is another list item. This keeps a list ->
paragraph -> list sequence as three separate blocks and matches the
contiguous-list layout for mixed/nested lists (one rich_text block, split
into sub-lists by (indent, ordered)), rather than emitting a separate
block per item.

Adds regression tests for the mixed blank-separated layout and the
list->paragraph->list boundary.
This commit is contained in:
kshitijk4poor 2026-07-03 02:39:04 +05:30 committed by kshitij
parent d3c8a155cb
commit 033d7bf259
2 changed files with 41 additions and 4 deletions

View file

@ -451,10 +451,22 @@ def render_blocks(
indent, ordered, txt = items[-1]
items[-1] = (indent, ordered, txt + " " + lines[i].strip())
i += 1
elif not lines[i].strip():
# blank line — soft separator within a list run;
# skip so that ordered items stay in one rich_text_list.
i += 1
elif not lines[i].strip() and items:
# Blank line inside a list run. LLM-authored ordered
# lists commonly separate items with a blank line; if
# the next non-blank line is another list item, treat
# the blank(s) as a soft separator and keep the run
# going so the items stay in one rich_text_list (Slack
# numbers each list independently, so splitting would
# restart every item at "1."). Otherwise the blank
# ends the list.
j = i + 1
while j < n and not lines[j].strip():
j += 1
if j < n and (_BULLET_RE.match(lines[j]) or _ORDERED_RE.match(lines[j])):
i = j
else:
break
else:
break
blocks.append(_list_block(items))

View file

@ -106,6 +106,31 @@ class TestInlineFormatting:
items = lists[0]["elements"]
assert len(items) == 3
def test_blank_separated_mixed_list_matches_contiguous_layout(self):
"""A blank line between different list kinds must render like the
contiguous form: one rich_text block whose sub-lists split only on
(indent, ordered) changes not a separate block per item.
"""
rich = [b for b in render_blocks("1. a\n\n- b") if b["type"] == "rich_text"]
# Single rich_text block (matches contiguous "1. a\n- b"), two sub-lists
assert len(rich) == 1
styles = [e["style"] for e in rich[0]["elements"] if e["type"] == "rich_text_list"]
assert styles == ["ordered", "bullet"]
def test_blank_line_before_paragraph_ends_the_list(self):
"""A blank line followed by non-list content must still end the run,
so a list paragraph list sequence stays three separate blocks.
"""
blocks = render_blocks("1. a\n\nsome paragraph text\n\n1. b")
lists = [
e
for b in blocks
for e in b.get("elements", [])
if e.get("type") == "rich_text_list"
]
# Two independent single-item lists, not one merged three-item list
assert [len(e["elements"]) for e in lists] == [1, 1]
class TestTables:
def test_pipe_table_renders_native_table_block(self):