Coverage for src / pyTRLCConverter / marko / gfm2rst_renderer.py: 88%
57 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 12:20 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 12:20 +0000
1"""reStructuredText renderer for Marko.
2 It is used to convert GitHub Flavored Markdown AST to reStructuredText format.
4 Author: Andreas Merkle (andreas.merkle@newtec.de)
5"""
7# pyTRLCConverter - A tool to convert TRLC files to specific formats.
8# Copyright (c) 2024 - 2026 NewTec GmbH
9#
10# This file is part of pyTRLCConverter program.
11#
12# The pyTRLCConverter program is free software: you can redistribute it and/or modify it under
13# the terms of the GNU General Public License as published by the Free Software Foundation,
14# either version 3 of the License, or (at your option) any later version.
15#
16# The pyTRLCConverter program is distributed in the hope that it will be useful, but
17# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License along with pyTRLCConverter.
21# If not, see <https://www.gnu.org/licenses/>.
23# Imports **********************************************************************
25from __future__ import annotations
26from typing import TYPE_CHECKING, Any, cast
27from pyTRLCConverter.marko.md2rst_renderer import Md2RstRenderer
29if TYPE_CHECKING:
30 from . import block, inline
32# Variables ********************************************************************
34# Classes **********************************************************************
36# pylint: disable-next=too-many-public-methods
37class Gfm2RstRenderer(Md2RstRenderer):
38 # lobster-trace: SwRequirements.sw_req_rst_render_gfm
39 """
40 Renderer for reStructuredText output.
41 It is used to convert GitHub Flavored Markdown to reStructuredText format.
42 """
44 # Inherit all CommonMark rendering behavior from Md2RstRenderer and override only GFM additions.
46 def render_list_item(self, element: block.ListItem, marker="-") -> str:
47 """
48 Renders a list item element.
50 Args:
51 element (block.ListItem): The list item element to render.
52 marker (str, optional): The marker to use for the list item. Defaults to "*".
54 Returns:
55 str: The rendered list item as a string.
56 """
57 indent = 2
58 content = self.render_children(element)
60 # GitHub Flavored Markdown task-list items expose a "checked" flag in the paragraph node.
61 # Prefix the rendered item text to preserve the task state in reStructuredText output.
62 if 0 < len(element.children):
63 first_child = element.children[0]
64 checked = getattr(first_child, "checked", None)
65 if checked is True:
66 content = "[x] " + content.lstrip()
67 elif checked is False:
68 content = "[ ] " + content.lstrip()
70 return f"{' ' * indent * (self._list_indent_level - 1)}{marker} {content}"
72 def render_table(self, element: Any) -> str:
73 """Renders a GitHub Flavored Markdown table as a reStructuredText grid table.
75 Args:
76 element (Any): The GFM table element.
78 Returns:
79 str: The rendered grid table as a string.
80 """
81 if not element.children:
82 return ""
84 header_row = element.children[0]
85 body_rows = element.children[1:]
87 header_values = [self.render_children(cell).strip() for cell in header_row.children]
88 row_values = []
90 for row in body_rows:
91 row_values.append([self.render_children(cell).strip() for cell in row.children])
93 return self._rst_create_grid_table(header_values, row_values)
95 def render_table_row(self, element: Any) -> str:
96 """Renders a GitHub Flavored Markdown table row.
98 Args:
99 element (Any): The table row element.
101 Returns:
102 str: The rendered row as a string.
103 """
104 return " | ".join(self.render_children(cell).strip() for cell in element.children)
106 def render_table_cell(self, element: Any) -> str:
107 """Renders a GitHub Flavored Markdown table cell.
109 Args:
110 element (Any): The table cell element.
112 Returns:
113 str: The rendered table cell as a string.
114 """
115 return self.render_children(element)
117 def render_strikethrough(self, element: Any) -> str:
118 """Renders a GitHub Flavored Markdown strikethrough element.
120 Args:
121 element (Any): The strikethrough element.
123 Returns:
124 str: The rendered strikethrough text.
125 """
126 return f"~~{self.render_children(element)}~~"
128 def render_url(self, element: Any) -> str:
129 """Renders a GitHub Flavored Markdown URL element.
131 Args:
132 element (Any): The URL element.
134 Returns:
135 str: The rendered URL as an RST link.
136 """
137 return self.render_link(cast("inline.Link", element))
139 @staticmethod
140 def _rst_table_append_border(char: str, max_widths: list[int]) -> str:
141 """
142 Appends a table border line for the grid table.
144 Args:
145 char (str): The character to use for the border line.
146 max_widths (list[int]): The maximum widths of the table columns.
148 Returns:
149 str: The rendered border line as a string.
150 """
151 return "+" + "+".join(char * (width + 2) for width in max_widths) + "+\n"
153 @staticmethod
154 def _rst_table_append_row(values: list[str], max_widths: list[int]) -> str:
155 """
156 Appends a table row for the grid table.
158 Args:
159 values (list[str]): The values for the row.
160 max_widths (list[int]): The maximum widths of the table columns.
162 Returns:
163 str: The rendered row as a string.
164 """
165 padded = [f" {value.ljust(max_widths[index])} " for index, value in enumerate(values)]
167 return "|" + "|".join(padded) + "|\n"
169 @staticmethod
170 def _rst_create_grid_table(headers: list[str], rows: list[list[str]]) -> str:
171 """Create a reStructuredText grid table.
173 Args:
174 headers (list[str]): Header row values.
175 rows (list[list[str]]): Body row values.
177 Returns:
178 str: The rendered grid table including trailing newline.
179 """
180 if len(headers) == 0:
181 return ""
183 max_widths = [len(value) for value in headers]
185 for row in rows:
186 for index, value in enumerate(row):
187 max_widths[index] = max(max_widths[index], len(value))
189 table = ""
190 table += Gfm2RstRenderer._rst_table_append_border("-", max_widths)
191 table += Gfm2RstRenderer._rst_table_append_row(headers, max_widths)
192 table += Gfm2RstRenderer._rst_table_append_border("=", max_widths)
194 for row in rows:
195 table += Gfm2RstRenderer._rst_table_append_row(row, max_widths)
196 table += Gfm2RstRenderer._rst_table_append_border("-", max_widths)
198 table += "\n"
200 return table
202# Functions ********************************************************************
204# Main *************************************************************************