From 2b5e43a64fa967a697765222a780d3f36c8f86e9 Mon Sep 17 00:00:00 2001 From: Wong Ding Feng Date: Mon, 1 Jun 2026 00:01:23 +0800 Subject: [PATCH] feat: markdown API documentation rendering Co-Authored-By: Claude Sonnet 4.6 --- src/auto_reverse/doc/markdown.py | 29 +++++++++++++++++++++++++++++ tests/test_markdown.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/auto_reverse/doc/markdown.py create mode 100644 tests/test_markdown.py diff --git a/src/auto_reverse/doc/markdown.py b/src/auto_reverse/doc/markdown.py new file mode 100644 index 0000000..dc94abd --- /dev/null +++ b/src/auto_reverse/doc/markdown.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from collections import defaultdict +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from auto_reverse.models import EndpointRecord + + +def render_markdown(records: list[EndpointRecord], title: str) -> str: + groups: dict[str, list[EndpointRecord]] = defaultdict(list) + for rec in records: + groups[rec.tag or "General"].append(rec) + + lines = [f"# {title}", ""] + for tag in sorted(groups): + lines.append(f"## {tag}") + lines.append("") + for rec in sorted(groups[tag], key=lambda r: r.signature.path_template): + sig = rec.signature + lines.append(f"### `{sig.method} {sig.path_template}`") + if rec.summary: + lines.append(f"**{rec.summary}**") + if rec.description: + lines.append("") + lines.append(rec.description) + lines.append(f"\n_Seen {rec.sample_count} time(s)._") + lines.append("") + return "\n".join(lines) diff --git a/tests/test_markdown.py b/tests/test_markdown.py new file mode 100644 index 0000000..707c5ca --- /dev/null +++ b/tests/test_markdown.py @@ -0,0 +1,31 @@ +from auto_reverse.doc.markdown import render_markdown +from auto_reverse.models import EndpointRecord, Signature + + +def _rec(method, template, **kw): + rec = EndpointRecord(signature=Signature(method, "ex.com", template, "2xx")) + for k, v in kw.items(): + setattr(rec, k, v) + return rec + + +def test_renders_heading_and_endpoints(): + md = render_markdown([_rec("GET", "/api/users", summary="List users")], title="ex.com API") + assert "# ex.com API" in md + assert "`GET /api/users`" in md + assert "List users" in md + + +def test_groups_by_tag(): + records = [ + _rec("GET", "/api/users", tag="Users"), + _rec("GET", "/api/cart", tag="Cart"), + ] + md = render_markdown(records, title="x") + assert "## Users" in md + assert "## Cart" in md + + +def test_untagged_go_under_general(): + md = render_markdown([_rec("GET", "/api/x")], title="x") + assert "## General" in md