From f2575abefd0e8d502d4a97451f51d5f9d71d5b9b Mon Sep 17 00:00:00 2001 From: Peter Jeschke Date: Tue, 10 Mar 2026 13:44:01 +0100 Subject: [PATCH] Make heading IDs local to page Fixes #436 # Problem: If you check https://ghostty.org/docs/features/applescript, https://ghostty.org/docs/install/release-notes/1-3-0 or https://ghostty.org/docs/install/release-notes/1-0-1, two of the pages will have a broken link to "Security" in the navigation on the right. Which page is not broken is random and is decided during build-time, based on which page is built first. This because the heading id generator "remembers" ids to make sure they don't clash. If multiple headings have the same id, a counter is appended (e.g. security-2). However, there's a discrepancy: The heading id generator for the navigation only considers the headings on the current page when generating the navigation. However, the actual heading IDs are counted "globally" across all pages. As a result, two of the three example pages will have "security-2" and "security-3" as IDs, even though there is no other security heading on the page. # Solution The quick fix is to make sure that the "encounteredIDs" map is scoped to the page (the "node" in remark-heading-ids.mjs" is effectively a page). Every page will have its own map. Something to consider for the long-term would be to reduce the duplication of heading id generation. There are two separate implementations (one to generate the headings and one to generate the navigation), leading to this problem in the first place. # Proof that this didn't break anything To check whether the de-duplication still works, visit https://ghostty.org/docs/install/build (or rather, your local or staging equivalent). This page has two headings "Dependencies", both which still have their correct IDs assigned after this change. --- src/lib/docs/remark-heading-ids.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/docs/remark-heading-ids.mjs b/src/lib/docs/remark-heading-ids.mjs index b4e25957..b8d832e5 100644 --- a/src/lib/docs/remark-heading-ids.mjs +++ b/src/lib/docs/remark-heading-ids.mjs @@ -3,10 +3,10 @@ import { visit } from "unist-util-visit"; // remarkHeadingIds applies stable IDs and de-duplication indices to heading nodes. export default function remarkHeadingIds() { - // encounteredIDs tracks duplicate IDs so each heading receives a unique anchor. - const encounteredIDs = new Map(); - return (node) => { + // encounteredIDs tracks duplicate IDs so each heading receives a unique anchor. + const encounteredIDs = new Map(); + visit(node, "heading", (headingNode) => { if (!Array.isArray(headingNode.children) || headingNode.children.length === 0) { return;