From fe2475c49def53455fa36ddded1746c73d6a7560 Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 7 Jun 2026 04:04:03 +0000 Subject: [PATCH] content: TOC rendering (toc.sx) + 8 tests (594/594) Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/content/conformance.sh | 3 +- lib/content/scoreboard.json | 5 +-- lib/content/scoreboard.md | 3 +- lib/content/tests/toc.sx | 63 ++++++++++++++++++++++++++++++++++ lib/content/toc.sx | 68 +++++++++++++++++++++++++++++++++++++ plans/content-on-sx.md | 8 ++++- 6 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 lib/content/tests/toc.sx create mode 100644 lib/content/toc.sx diff --git a/lib/content/conformance.sh b/lib/content/conformance.sh index 4697c991..b2bf0974 100755 --- a/lib/content/conformance.sh +++ b/lib/content/conformance.sh @@ -15,7 +15,7 @@ if [ ! -x "$SX_SERVER" ]; then fi fi -SUITES=(block doc render api meta page page-full markdown text section compose tree-edit clone query transform stats table data wire validate store snapshot crdt crdt-store sync md-import md-doc fed) +SUITES=(block doc render api meta page page-full markdown text section compose tree-edit clone query toc transform stats table data wire validate store snapshot crdt crdt-store sync md-import md-doc fed) OUT_JSON="lib/content/scoreboard.json" OUT_MD="lib/content/scoreboard.md" @@ -49,6 +49,7 @@ run_suite() { (load "lib/content/tree-edit.sx") (load "lib/content/clone.sx") (load "lib/content/query.sx") +(load "lib/content/toc.sx") (load "lib/content/transform.sx") (load "lib/content/stats.sx") (load "lib/content/table.sx") diff --git a/lib/content/scoreboard.json b/lib/content/scoreboard.json index 9f9b976b..76d76f3f 100644 --- a/lib/content/scoreboard.json +++ b/lib/content/scoreboard.json @@ -14,6 +14,7 @@ "tree-edit": {"pass": 17, "fail": 0}, "clone": {"pass": 10, "fail": 0}, "query": {"pass": 13, "fail": 0}, + "toc": {"pass": 8, "fail": 0}, "transform": {"pass": 12, "fail": 0}, "stats": {"pass": 17, "fail": 0}, "table": {"pass": 15, "fail": 0}, @@ -29,7 +30,7 @@ "md-doc": {"pass": 12, "fail": 0}, "fed": {"pass": 20, "fail": 0} }, - "total_pass": 586, + "total_pass": 594, "total_fail": 0, - "total": 586 + "total": 594 } diff --git a/lib/content/scoreboard.md b/lib/content/scoreboard.md index e1d94b7e..d1fe2e50 100644 --- a/lib/content/scoreboard.md +++ b/lib/content/scoreboard.md @@ -18,6 +18,7 @@ _Generated by `lib/content/conformance.sh`_ | tree-edit | 17 | 0 | 17 | | clone | 10 | 0 | 10 | | query | 13 | 0 | 13 | +| toc | 8 | 0 | 8 | | transform | 12 | 0 | 12 | | stats | 17 | 0 | 17 | | table | 15 | 0 | 15 | @@ -32,4 +33,4 @@ _Generated by `lib/content/conformance.sh`_ | md-import | 38 | 0 | 38 | | md-doc | 12 | 0 | 12 | | fed | 20 | 0 | 20 | -| **Total** | **586** | **0** | **586** | +| **Total** | **594** | **0** | **594** | diff --git a/lib/content/tests/toc.sx b/lib/content/tests/toc.sx new file mode 100644 index 00000000..5181e081 --- /dev/null +++ b/lib/content/tests/toc.sx @@ -0,0 +1,63 @@ +;; Extension — table-of-contents rendering. + +(st-bootstrap-classes!) +(content/bootstrap!) +(content-bootstrap-section!) + +(define nl (str "\n")) + +(define + d + (doc-append + (doc-append + (doc-append + (doc-append (doc-empty "d") (mk-heading "intro" 1 "Intro")) + (mk-text "p" "x")) + (mk-heading "bg" 2 "Background")) + (mk-section "s" (list (mk-heading "deep" 2 "Details"))))) + +;; ── markdown TOC (indented by level) ── +(content-test + "toc markdown" + (content/toc-markdown d) + (str + "- [Intro](#intro)" + nl + " - [Background](#bg)" + nl + " - [Details](#deep)")) + +;; ── html TOC (anchor links) ── +(content-test + "toc html" + (content/toc-html d) + "") + +;; ── html escapes heading text ── +(content-test + "toc html escapes" + (content/toc-html + (doc-append (doc-empty "d") (mk-heading "h" 1 "A < B"))) + "") + +;; ── empty / no headings ── +(content-test "toc html empty" (content/toc-html (doc-empty "e")) "") +(content-test "toc markdown empty" (content/toc-markdown (doc-empty "e")) "") +(content-test + "toc no headings" + (content/toc-html (doc-append (doc-empty "d") (mk-text "p" "just text"))) + "") + +;; ── single heading ── +(content-test + "toc single md" + (content/toc-markdown + (doc-append (doc-empty "d") (mk-heading "h" 1 "Only"))) + "- [Only](#h)") + +;; ── deep level indentation ── +(content-test + "toc deep indent" + (content/toc-markdown + (doc-append (doc-empty "d") (mk-heading "h" 3 "Deep"))) + " - [Deep](#h)") diff --git a/lib/content/toc.sx b/lib/content/toc.sx new file mode 100644 index 00000000..eb4c8c03 --- /dev/null +++ b/lib/content/toc.sx @@ -0,0 +1,68 @@ +;; content-on-sx — table-of-contents rendering. +;; +;; Turns content/headings into a user-facing TOC: a Markdown bullet list indented +;; by heading level, and an HTML