Skip to content

Commit 399636e

Browse files
committed
Fix markdown table parser consuming lines without pipes as table rows
The TableRow rule in the PEG grammar allowed rows with zero pipe characters (TableItem2*). This caused lines like `<br>` immediately following a table to be parsed as single-cell table rows, producing spurious `<td><br></td>` in the rendered HTML. Change TableItem2* to TableItem2+ so that rows not starting with `|` must contain at least one `|` to be recognized as table rows.
1 parent 92b07d6 commit 399636e

3 files changed

Lines changed: 40 additions & 9 deletions

File tree

lib/rdoc/markdown.kpeg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1270,7 +1270,7 @@ Table = &{ github? }
12701270
TableHead = TableItem2+:items "|"? @Newline
12711271
{ items }
12721272

1273-
TableRow = ( ( TableItem:item1 TableItem2*:items { [item1, *items] } ):row | TableItem2+:row ) "|"? @Newline
1273+
TableRow = ( ( TableItem:item1 TableItem2+:items { [item1, *items] } ):row | TableItem2+:row ) "|"? @Newline
12741274
{ row }
12751275
TableItem2 = "|" TableItem
12761276
TableItem = < /(?:\\.|[^|\n])+/ >

lib/rdoc/markdown.rb

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15937,7 +15937,7 @@ def _TableHead
1593715937
return _tmp
1593815938
end
1593915939

15940-
# TableRow = ((TableItem:item1 TableItem2*:items { [item1, *items] }):row | TableItem2+:row) "|"? @Newline { row }
15940+
# TableRow = ((TableItem:item1 TableItem2+:items { [item1, *items] }):row | TableItem2+:row) "|"? @Newline { row }
1594115941
def _TableRow
1594215942

1594315943
_save = self.pos
@@ -15954,14 +15954,21 @@ def _TableRow
1595415954
self.pos = _save2
1595515955
break
1595615956
end
15957+
_save3 = self.pos
1595715958
_ary = []
15958-
while true
15959-
_tmp = apply(:_TableItem2)
15960-
_ary << @result if _tmp
15961-
break unless _tmp
15959+
_tmp = apply(:_TableItem2)
15960+
if _tmp
15961+
_ary << @result
15962+
while true
15963+
_tmp = apply(:_TableItem2)
15964+
_ary << @result if _tmp
15965+
break unless _tmp
15966+
end
15967+
_tmp = true
15968+
@result = _ary
15969+
else
15970+
self.pos = _save3
1596215971
end
15963-
_tmp = true
15964-
@result = _ary
1596515972
items = @result
1596615973
unless _tmp
1596715974
self.pos = _save2
@@ -16666,7 +16673,7 @@ def _DefinitionListDefinition
1666616673
Rules[:_CodeFence] = rule_info("CodeFence", "&{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim }")
1666716674
Rules[:_Table] = rule_info("Table", "&{ github? } TableHead:header TableLine:line TableRow+:body { table = RDoc::Markup::Table.new(header, line, body) parse_table_cells(table) }")
1666816675
Rules[:_TableHead] = rule_info("TableHead", "TableItem2+:items \"|\"? @Newline { items }")
16669-
Rules[:_TableRow] = rule_info("TableRow", "((TableItem:item1 TableItem2*:items { [item1, *items] }):row | TableItem2+:row) \"|\"? @Newline { row }")
16676+
Rules[:_TableRow] = rule_info("TableRow", "((TableItem:item1 TableItem2+:items { [item1, *items] }):row | TableItem2+:row) \"|\"? @Newline { row }")
1667016677
Rules[:_TableItem2] = rule_info("TableItem2", "\"|\" TableItem")
1667116678
Rules[:_TableItem] = rule_info("TableItem", "< /(?:\\\\.|[^|\\n])+/ > { text.strip.gsub(/\\\\([|])/, '\\1') }")
1667216679
Rules[:_TableLine] = rule_info("TableLine", "((TableAlign:align1 TableAlign2*:aligns {[align1, *aligns] }):line | TableAlign2+:line) \"|\"? @Newline { line }")

test/rdoc/rdoc_markdown_test.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,30 @@ def test_gfm_table_with_links_and_code
13101310
assert_equal expected, doc
13111311
end
13121312

1313+
def test_gfm_table_does_not_consume_following_line_without_pipe
1314+
doc = parse <<~MD
1315+
| Command | Shows |
1316+
|---------|-------|
1317+
| ri File | Document for Ruby class File. |
1318+
<br>
1319+
1320+
Following paragraph.
1321+
MD
1322+
1323+
head = %w[Command Shows]
1324+
align = [nil, nil]
1325+
body = [
1326+
['ri File', 'Document for Ruby class File.'],
1327+
]
1328+
expected = doc(
1329+
@RM::Table.new(head, align, body),
1330+
para('<br>'),
1331+
para('Following paragraph.')
1332+
)
1333+
1334+
assert_equal expected, doc
1335+
end
1336+
13131337
def test_gfm_table_with_backslashes_in_code_spans
13141338
doc = parse <<~MD
13151339
Plain text: `$\\\\` and `$\\\\ ` should work.

0 commit comments

Comments
 (0)