v0.3.6-pre.001-fix.001

This commit is contained in:
2026-09-01 10:43:09 +02:00
parent 6f2d0a092a
commit ecfc30a94b
25 changed files with 706 additions and 392 deletions

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# file: scripts/audit_markdown_tables.py
# version: 2
# version: 3
"""Validate KSP Markdown tables and vertical spacing for explicitly supplied files or directories."""
@@ -46,7 +46,28 @@ def _is_separator_row(line: str) -> bool:
if not _is_table_row(line):
return False
cells = _cells(line)
return bool(cells) and all(_SEPARATOR_CELL.fullmatch(cell) is not None for cell in cells)
return bool(cells) and all(_separator_marker(cell) is not None for cell in cells)
def _separator_marker(cell: str) -> str | None:
marker = cell.strip()
if _SEPARATOR_CELL.fullmatch(marker) is None:
return None
return marker
def _separator_alignment(marker: str) -> str:
if marker.startswith(":") and marker.endswith(":"):
return "center"
if marker.endswith(":"):
return "right"
return "left"
def _space_padding(cell: str) -> tuple[int, int]:
left = len(cell) - len(cell.lstrip(" "))
right = len(cell) - len(cell.rstrip(" "))
return left, right
def _validate_table(path: pathlib.Path, start_line: int, rows: list[str]) -> list[str]:
@@ -75,27 +96,46 @@ def _validate_table(path: pathlib.Path, start_line: int, rows: list[str]) -> lis
)
continue
content_cells = [cell for cell in raw_cells if _SEPARATOR_CELL.fullmatch(cell) is None]
content_cells = [cell for row_index, cell in enumerate(raw_cells) if row_index != 1]
if not content_cells:
errors.append(f"{path}:{start_line}: column {column_index + 1} has no header/data content")
continue
max_content_width = max(len(cell.strip()) for cell in content_cells)
required_width = max_content_width + 2
marker = _separator_marker(raw_cells[1])
if marker is None:
errors.append(f"{path}:{start_line + 1}: separator for column {column_index + 1} is malformed")
continue
minimum_separator_width = 3 + marker.count(":")
required_width = max(max_content_width + 2, minimum_separator_width)
if expected_width != required_width:
errors.append(
f"{path}:{start_line}: column {column_index + 1} width is {expected_width}; expected {required_width} "
"(longest content plus exactly one space on each side)"
"(longest content plus outer padding, or the minimum Markdown separator width)"
)
alignment = _separator_alignment(marker)
for cell in content_cells:
if len(cell) < 2 or not cell.startswith(" ") or cell.startswith(" ") or not cell.endswith(" "):
content_width = len(cell.strip())
left_padding, right_padding = _space_padding(cell)
if content_width + left_padding + right_padding != len(cell) or left_padding < 1 or right_padding < 1:
errors.append(
f"{path}:{start_line}: column {column_index + 1} content cells must start with exactly one space and use right padding only"
f"{path}:{start_line}: column {column_index + 1} content cells must use spaces only for outer alignment padding"
)
break
if len(cell.strip()) == max_content_width and cell.endswith(" "):
expected_padding = expected_width - content_width
if alignment == "left" and (left_padding != 1 or right_padding != expected_padding - 1):
errors.append(
f"{path}:{start_line}: column {column_index + 1} widest content must have exactly one space before the closing pipe"
f"{path}:{start_line}: column {column_index + 1} is left-aligned; content must use one leading space and right padding only"
)
break
if alignment == "right" and (right_padding != 1 or left_padding != expected_padding - 1):
errors.append(
f"{path}:{start_line}: column {column_index + 1} is right-aligned; content must use left padding and one trailing space"
)
break
if alignment == "center" and abs(left_padding - right_padding) > 1:
errors.append(
f"{path}:{start_line}: column {column_index + 1} is centered; left and right padding may differ by at most one space"
)
break