Skip to content

fix(table): reject a non-delimiter second row instead of eating it#467

Open
chuenchen309 wants to merge 1 commit into
lepture:mainfrom
chuenchen309:fix/table-delimiter-validation
Open

fix(table): reject a non-delimiter second row instead of eating it#467
chuenchen309 wants to merge 1 commit into
lepture:mainfrom
chuenchen309:fix/table-delimiter-validation

Conversation

@chuenchen309

Copy link
Copy Markdown
Contributor

The bug

Three lines of ordinary pipe-separated text get turned into a table, and the middle line silently disappears:

import mistune
md = mistune.create_markdown(plugins=['table'])
print(md("Name | Age\nJohn | 30\nJane | 25\n"))

Today this renders as a <table> whose header is Name | Age, whose body is Jane | 25, and where John | 30 is gone — it was consumed as the "delimiter" row.

Cause

_process_thead checks that the alignment row has the same cell count as the header, but it never checks that the cells are actually delimiters. A cell that isn't a dash rule falls through to aligns.append(None):

if ALIGN_CENTER.match(v):
    aligns.append("center")
elif ALIGN_LEFT.match(v):
    aligns.append("left")
elif ALIGN_RIGHT.match(v):
    aligns.append("right")
else:
    aligns.append(None)   # <- also catches "30", "bar", ... , not just "---"

None is the legitimate value for a no-align --- column, so a row like John | 30 is accepted as a valid no-align delimiter, and the block becomes a table with that line eaten.

Fix

Require each alignment cell to be a dash rule (optionally colon-flanked) or empty. Anything else means the second line isn't a delimiter row, so it isn't a table:

elif ALIGN_NONE.match(v) or not v.strip():
    aligns.append(None)
else:
    return None, None

Empty cells stay allowed, so existing tables such as

A |
- |
a | b

(the Misc Table fixture, where the delimiter cell is empty) keep working. This matches the delimiter-cell set from the php-markdown / GFM spec that the plugin follows.

Verification

  • Added two tests/fixtures/table.txt examples (a non-delimiter second row now stays a paragraph). They fail on main and pass with this change, across both the plain and speedup variants.
  • Full suite green: 1141 passed. No existing table fixture changed — every valid table (alignment, empty delimiter cells, escaped pipes, nptable, mismatch handling) renders as before.
  • ruff check clean.

Disclosure: this PR was authored by an AI coding agent (Claude Code) running on this account: the AI found the bug, ran the repro, wrote the tests, and wrote this description. The human account holder reviews every change and is accountable for it. The verification above is real and re-runnable from the diff. If this isn't the kind of contribution you want, say so and I'll close it.

`_process_thead` only checked that the alignment row had the same cell
count as the header; any cell that was not a dash rule fell through to
`aligns.append(None)` (a valid no-align column). A second line that is
ordinary pipe-separated text (no `---` delimiter) was therefore accepted
as the delimiter row, turning non-table text into a table and silently
dropping that line from the output.

Require every alignment cell to be a dash rule (optionally colon-flanked)
or empty; otherwise it is not a delimiter row and the block is not a
table. Empty cells stay allowed so existing tables like `- |` keep working.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@codecov

codecov Bot commented Jul 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.33%. Comparing base (719107f) to head (86f9fd1).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #467   +/-   ##
=======================================
  Coverage   91.32%   91.33%           
=======================================
  Files          34       34           
  Lines        3515     3518    +3     
  Branches      697      698    +1     
=======================================
+ Hits         3210     3213    +3     
  Misses        184      184           
  Partials      121      121           
Flag Coverage Δ
unittests 91.30% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant