initial commit: codex draft
This commit is contained in:
62
src/markdown_utils.py
Normal file
62
src/markdown_utils.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
import markdown as md_lib
|
||||
|
||||
from .errors import ValidationIssue
|
||||
|
||||
|
||||
_HEADING_RE = re.compile(r"^(#{1,6})(\s+.*)$")
|
||||
|
||||
|
||||
def extract_title(markdown_text: str, level: int, strict: bool, context: str, issues: list[ValidationIssue]) -> tuple[str, str] | None:
|
||||
pattern = re.compile(rf"^{'#' * level}\s+(.*)$", re.MULTILINE)
|
||||
matches = list(pattern.finditer(markdown_text))
|
||||
if strict and len(matches) != 1:
|
||||
issues.append(
|
||||
ValidationIssue(
|
||||
f"Expected exactly one level-{level} heading, found {len(matches)}",
|
||||
context=context,
|
||||
)
|
||||
)
|
||||
return None
|
||||
if not matches:
|
||||
issues.append(ValidationIssue(f"Missing level-{level} heading", context=context))
|
||||
return None
|
||||
|
||||
match = matches[0]
|
||||
title = match.group(1).strip()
|
||||
if not title:
|
||||
issues.append(ValidationIssue("Heading title cannot be empty", context=context))
|
||||
return None
|
||||
|
||||
lines = markdown_text.splitlines()
|
||||
line_index = markdown_text[: match.start()].count("\n")
|
||||
lines.pop(line_index)
|
||||
body = "\n".join(lines)
|
||||
body = _promote_headings(body)
|
||||
return title, body
|
||||
|
||||
|
||||
def _promote_headings(text: str) -> str:
|
||||
promoted_lines = []
|
||||
for line in text.splitlines():
|
||||
match = _HEADING_RE.match(line)
|
||||
if not match:
|
||||
promoted_lines.append(line)
|
||||
continue
|
||||
hashes, rest = match.groups()
|
||||
level = len(hashes)
|
||||
if level > 1:
|
||||
level -= 1
|
||||
promoted_lines.append("#" * level + rest)
|
||||
return "\n".join(promoted_lines)
|
||||
|
||||
|
||||
def convert_markdown(markdown_text: str, context: str, issues: list[ValidationIssue]) -> str | None:
|
||||
try:
|
||||
return md_lib.markdown(markdown_text, extensions=["extra"], output_format="html5")
|
||||
except Exception as exc: # pragma: no cover - depends on markdown internals
|
||||
issues.append(ValidationIssue(f"Markdown conversion failed: {exc}", context=context))
|
||||
return None
|
||||
Reference in New Issue
Block a user