• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rafalp / Misago / 13477591013

22 Feb 2025 11:40PM UTC coverage: 97.17%. Remained the same
13477591013

push

github

web-flow
Support tables in parser (#1877)

112 of 113 new or added lines in 8 files covered. (99.12%)

22 existing lines in 5 files now uncovered.

69455 of 71478 relevant lines covered (97.17%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.67
/misago/parser/patterns/table.py
1
from enum import StrEnum
1✔
2

3
from ..parser import Parser, Pattern
1✔
4

5
TABLE_PATTERN = (
1✔
6
    r"(\n|^)"  # Table is preceded by a new line or the start of the text
7
    r" *\|.+\n"  # Header row
8
    r" *(\| *:?-+:? *)+\|?"  # Header's underline
9
    r"(\n *\|.*)*"  # Remaining rows
10
)
11

12

13
class ColAlignment(StrEnum):
1✔
14
    LEFT = "left"
1✔
15
    CENTER = "center"
1✔
16
    RIGHT = "right"
1✔
17

18

19
Cell = tuple[ColAlignment, str]
1✔
20

21

22
class TableMarkdown(Pattern):
1✔
23
    pattern_type: str = "table"
1✔
24
    pattern: str = TABLE_PATTERN
1✔
25

26
    def parse(self, parser: Parser, match: str, parents: list[str]) -> list[dict]:
1✔
27
        data = match.strip().splitlines()
1✔
28

29
        header = [c for c in self.split_row(data[0]) if c]
1✔
30
        cols = self.parse_cols_row(data[1])
1✔
31
        rows = [self.split_row(r) for r in data[2:]]
1✔
32

33
        num_cols = len(cols)
1✔
34
        if len(header) != num_cols:
1✔
NEW
35
            return {
×
36
                "type": "paragraph",
37
                "children": parser.parse_inline(match, [], True),
38
            }
39

40
        ast = {
1✔
41
            "type": self.pattern_type,
42
            "header": [
43
                {
44
                    "type": "table-header",
45
                    "align": cols[i].value,
46
                    "children": (
47
                        parser.parse_inline(text, ["table", "table-header"], True)
48
                        if text
49
                        else []
50
                    ),
51
                }
52
                for i, text in enumerate(header)
53
            ],
54
            "children": [],
55
        }
56

57
        for row in rows:
1✔
58
            row_ast = {"type": "table-row", "children": []}
1✔
59
            row += [""] * (num_cols - len(row))
1✔
60
            for i, text in enumerate(row):
1✔
61
                row_ast["children"].append(
1✔
62
                    {
63
                        "type": "table-cell",
64
                        "align": cols[i].value,
65
                        "children": (
66
                            parser.parse_inline(text, ["table", "table-cell"], True)
67
                            if text
68
                            else []
69
                        ),
70
                    }
71
                )
72

73
            ast["children"].append(row_ast)
1✔
74

75
        return [ast]
1✔
76

77
    def parse_cols_row(self, row: str) -> list[ColAlignment]:
1✔
78
        cols: list[ColAlignment] = []
1✔
79
        for col in self.split_row(row):
1✔
80
            if col.startswith(":") and col.endswith(":"):
1✔
81
                cols.append(ColAlignment.CENTER)
1✔
82
            elif col.endswith(":"):
1✔
83
                cols.append(ColAlignment.RIGHT)
1✔
84
            else:
85
                cols.append(ColAlignment.LEFT)
1✔
86
        return cols
1✔
87

88
    def split_row(self, row: str) -> list[str]:
1✔
89
        row = row.strip()
1✔
90
        if row.startswith("|"):
1✔
91
            row = row[1:]
1✔
92
        if row.endswith("|"):
1✔
93
            row = row[:-1]
1✔
94
        return [s.strip() for s in row.split("|")]
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc