Skip to content

Commit

Permalink
feat: allow just 1 dash in Table delimiter cells (#131)
Browse files Browse the repository at this point in the history
In or around [#371](github/markup#371), GFM relaxed constraints on the minimal number of required dashes in table delimiter row.

So we relax the constraints as well. To "compensate" for this change,
we check the format of the delimiter row more thoroughly (although
we still do *not* check number of cells in the delimiter row).
  • Loading branch information
pbodnar committed Dec 14, 2023
1 parent fb231b1 commit 54f6c21
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 16 deletions.
22 changes: 13 additions & 9 deletions mistletoe/block_token.py
Expand Up @@ -676,7 +676,7 @@ def read(cls, lines, prev_marker=None):

class Table(BlockToken):
"""
Table token.
Table token. See its GFM definition at <https://github.github.com/gfm/#tables-extension->.
This is a container block token. Its children are TableRow tokens.
Class attributes:
Expand All @@ -690,20 +690,24 @@ class Table(BlockToken):
repr_attributes = BlockToken.repr_attributes + ("column_align",)
interrupt_paragraph = True

_column_align = r':?-+:?'
column_align_pattern = re.compile(_column_align)
delimiter_row_pattern = re.compile(r'\s*\|?\s*' + _column_align + '\s*(\|\s*' + _column_align + '\s*)*\|?\s*')

def __init__(self, match):
lines, start_line = match
if '---' in lines[1]:
# note: the following condition is currently always true, because read() guarantees the presence of the delimiter row
if '-' in lines[1]:
self.column_align = [self.parse_align(column)
for column in self.split_delimiter(lines[1])]
self.header = TableRow(lines[0], self.column_align, start_line)
self.children = [TableRow(line, self.column_align, start_line + offset) for offset, line in enumerate(lines[2:], start=2)]
else:
# note: not reachable, because read() guarantees the presence of three dashes
self.column_align = [None]
self.children = [TableRow(line, line_number=start_line + offset) for offset, line in enumerate(lines)]

@staticmethod
def split_delimiter(delimiter):
@classmethod
def split_delimiter(cls, delimiter_row):
"""
Helper function; returns a list of align options.
Expand All @@ -713,7 +717,7 @@ def split_delimiter(delimiter):
Returns:
a list of align options (None, 0 or 1).
"""
return re.findall(r':?---+:?', delimiter)
return cls.column_align_pattern.findall(delimiter_row)

@staticmethod
def parse_align(column):
Expand All @@ -740,14 +744,14 @@ def check_interrupts_paragraph(cls, lines):
lines.set_pos(anchor)
return result

@staticmethod
def read(lines):
@classmethod
def read(cls, lines):
anchor = lines.get_pos()
line_buffer = [next(lines)]
start_line = lines.line_number()
while lines.peek() is not None and '|' in lines.peek():
line_buffer.append(next(lines))
if len(line_buffer) < 2 or '---' not in line_buffer[1]:
if len(line_buffer) < 2 or not cls.delimiter_row_pattern.fullmatch(line_buffer[1]):
lines.set_pos(anchor)
return None
return line_buffer, start_line
Expand Down
21 changes: 14 additions & 7 deletions test/test_block_token.py
@@ -1,6 +1,8 @@
import unittest
from unittest.mock import call, patch

from parameterized import parameterized

from mistletoe import block_token, block_tokenizer, span_token


Expand Down Expand Up @@ -375,17 +377,22 @@ def test_parse_align(self):
self.assertEqual(test_func('------:'), 1)

def test_parse_delimiter(self):
test_func = block_token.Table.split_delimiter
self.assertEqual(list(test_func('| :--- | :---: | ---:|\n')),
[':---', ':---:', '---:'])

def test_match(self):
test_func = lambda s : block_token.Table.split_delimiter(s)
self.assertEqual(list(test_func('|-| :--- | :---: | ---:|\n')),
['-', ':---', ':---:', '---:'])

@parameterized.expand([
('| --- | --- | --- |\n'),
('| - | - | - |\n'),
('|-|-|-- \n'),
])
def test_match(self, delimiter_line):
lines = ['| header 1 | header 2 | header 3 |\n',
'| --- | --- | --- |\n',
delimiter_line,
'| cell 1 | cell 2 | cell 3 |\n',
'| more 1 | more 2 | more 3 |\n']
with patch('mistletoe.block_token.TableRow') as mock:
token = next(iter(block_token.tokenize(lines)))
token, = block_token.tokenize(lines)
self.assertIsInstance(token, block_token.Table)
self.assertTrue(hasattr(token, 'header'))
self.assertEqual(token.column_align, [None, None, None])
Expand Down

0 comments on commit 54f6c21

Please sign in to comment.