From 95a086903b3b35eb57ed2ecf9927e7f463130eba Mon Sep 17 00:00:00 2001 From: Yeqi Huang Date: Thu, 12 Mar 2026 14:42:46 +0000 Subject: [PATCH] fix: fix 404 on version switch from index.html and strip pandoc heading IDs (#496) Two fixes: 1. version-selector.js: Simplify basePath() to determine site root from the URL prefix (/ or /docs/) instead of trying to strip path segments. Previously, visiting /index.html caused basePath to compute /index.html/v1/ (404) because it didn't strip the filename first. 2. prepare_mdbook.py: Strip pandoc-style heading IDs ({#label}) from both extracted titles (used in SUMMARY.md sidebar) and rendered markdown content. Fixes "Model Deployment {#ch:deploy}" showing raw in the sidebar and page headings. Co-authored-by: Claude Opus 4.6 --- books/zh/theme/version-selector.js | 9 +++++---- theme/version-selector.js | 9 +++++---- tools/prepare_mdbook.py | 9 +++++++-- v1/books/zh/theme/version-selector.js | 9 +++++---- v1/en_chapters/SUMMARY.md | 2 +- v1/theme/version-selector.js | 9 +++++---- v2/books/zh/theme/version-selector.js | 9 +++++---- v2/theme/version-selector.js | 9 +++++---- 8 files changed, 38 insertions(+), 27 deletions(-) diff --git a/books/zh/theme/version-selector.js b/books/zh/theme/version-selector.js index 46e5da8..65858d2 100644 --- a/books/zh/theme/version-selector.js +++ b/books/zh/theme/version-selector.js @@ -15,11 +15,12 @@ currentLang = "zh"; } - // Build base paths + // Build base paths — always navigate to root of target version function basePath(version, lang) { - var docsRoot = path.replace(/\/v1\/.*/, "/").replace(/\/cn\/.*/, "/"); - docsRoot = docsRoot.replace(/(\/docs\/?).*/, "/docs/"); - if (!docsRoot.endsWith("/")) docsRoot += "/"; + // Determine site root: everything before /v1/, /cn/, or first path segment after /docs/ + var root = "/"; + var docsMatch = path.match(/^(\/docs\/)/); + if (docsMatch) root = docsMatch[1]; var p = docsRoot; if (version === "v1") p += "v1/"; diff --git a/theme/version-selector.js b/theme/version-selector.js index 46e5da8..65858d2 100644 --- a/theme/version-selector.js +++ b/theme/version-selector.js @@ -15,11 +15,12 @@ currentLang = "zh"; } - // Build base paths + // Build base paths — always navigate to root of target version function basePath(version, lang) { - var docsRoot = path.replace(/\/v1\/.*/, "/").replace(/\/cn\/.*/, "/"); - docsRoot = docsRoot.replace(/(\/docs\/?).*/, "/docs/"); - if (!docsRoot.endsWith("/")) docsRoot += "/"; + // Determine site root: everything before /v1/, /cn/, or first path segment after /docs/ + var root = "/"; + var docsMatch = path.match(/^(\/docs\/)/); + if (docsMatch) root = docsMatch[1]; var p = docsRoot; if (version === "v1") p += "v1/"; diff --git a/tools/prepare_mdbook.py b/tools/prepare_mdbook.py index bbc7e31..9ef248d 100644 --- a/tools/prepare_mdbook.py +++ b/tools/prepare_mdbook.py @@ -136,6 +136,10 @@ def is_placeholder_markdown(markdown: str, placeholder_prefix: str | None = None return stripped.startswith(placeholder_prefix) and stripped.endswith("]") +def _strip_pandoc_heading_id(heading: str) -> str: + return re.sub(r"\s+\{#[^}]+\}\s*$", "", heading) + + def extract_title(markdown: str, fallback: str = "Untitled") -> str: lines = markdown.splitlines() @@ -146,13 +150,13 @@ def extract_title(markdown: str, fallback: str = "Untitled") -> str: if stripped.startswith("#"): heading = stripped.lstrip("#").strip() if heading: - return heading + return _strip_pandoc_heading_id(heading) next_index = index + 1 if next_index < len(lines): underline = lines[next_index].strip() if underline and set(underline) <= {"=", "-"}: - return stripped + return _strip_pandoc_heading_id(stripped) return fallback @@ -904,6 +908,7 @@ def rewrite_markdown( fig_number_map=fig_number_map, ) result = process_citations(result, bib_db or {}, bibliography_title=bibliography_title) + result = re.sub(r"^(#{1,6}\s+.*?)\s+\{#[^}]+\}\s*$", r"\1", result, flags=re.MULTILINE) return result diff --git a/v1/books/zh/theme/version-selector.js b/v1/books/zh/theme/version-selector.js index 46e5da8..65858d2 100644 --- a/v1/books/zh/theme/version-selector.js +++ b/v1/books/zh/theme/version-selector.js @@ -15,11 +15,12 @@ currentLang = "zh"; } - // Build base paths + // Build base paths — always navigate to root of target version function basePath(version, lang) { - var docsRoot = path.replace(/\/v1\/.*/, "/").replace(/\/cn\/.*/, "/"); - docsRoot = docsRoot.replace(/(\/docs\/?).*/, "/docs/"); - if (!docsRoot.endsWith("/")) docsRoot += "/"; + // Determine site root: everything before /v1/, /cn/, or first path segment after /docs/ + var root = "/"; + var docsMatch = path.match(/^(\/docs\/)/); + if (docsMatch) root = docsMatch[1]; var p = docsRoot; if (version === "v1") p += "v1/"; diff --git a/v1/en_chapters/SUMMARY.md b/v1/en_chapters/SUMMARY.md index 25f6e31..97f1716 100644 --- a/v1/en_chapters/SUMMARY.md +++ b/v1/en_chapters/SUMMARY.md @@ -10,7 +10,7 @@ [AI Compiler Backend](chapter_backend_and_runtime/index.md) [Hardware Accelerator](chapter_accelerator/index.md) [Data Processing Framework](chapter_data_processing/index.md) -[Model Deployment {#ch:deploy}](chapter_model_deployment/index.md) +[Model Deployment](chapter_model_deployment/index.md) [Distributed Training](chapter_distributed_training/index.md) [Part II Application Scenarios](chapter_preface_extension/index.md) [Recommender System](chapter_recommender_system/index.md) diff --git a/v1/theme/version-selector.js b/v1/theme/version-selector.js index 46e5da8..65858d2 100644 --- a/v1/theme/version-selector.js +++ b/v1/theme/version-selector.js @@ -15,11 +15,12 @@ currentLang = "zh"; } - // Build base paths + // Build base paths — always navigate to root of target version function basePath(version, lang) { - var docsRoot = path.replace(/\/v1\/.*/, "/").replace(/\/cn\/.*/, "/"); - docsRoot = docsRoot.replace(/(\/docs\/?).*/, "/docs/"); - if (!docsRoot.endsWith("/")) docsRoot += "/"; + // Determine site root: everything before /v1/, /cn/, or first path segment after /docs/ + var root = "/"; + var docsMatch = path.match(/^(\/docs\/)/); + if (docsMatch) root = docsMatch[1]; var p = docsRoot; if (version === "v1") p += "v1/"; diff --git a/v2/books/zh/theme/version-selector.js b/v2/books/zh/theme/version-selector.js index 46e5da8..65858d2 100644 --- a/v2/books/zh/theme/version-selector.js +++ b/v2/books/zh/theme/version-selector.js @@ -15,11 +15,12 @@ currentLang = "zh"; } - // Build base paths + // Build base paths — always navigate to root of target version function basePath(version, lang) { - var docsRoot = path.replace(/\/v1\/.*/, "/").replace(/\/cn\/.*/, "/"); - docsRoot = docsRoot.replace(/(\/docs\/?).*/, "/docs/"); - if (!docsRoot.endsWith("/")) docsRoot += "/"; + // Determine site root: everything before /v1/, /cn/, or first path segment after /docs/ + var root = "/"; + var docsMatch = path.match(/^(\/docs\/)/); + if (docsMatch) root = docsMatch[1]; var p = docsRoot; if (version === "v1") p += "v1/"; diff --git a/v2/theme/version-selector.js b/v2/theme/version-selector.js index 46e5da8..65858d2 100644 --- a/v2/theme/version-selector.js +++ b/v2/theme/version-selector.js @@ -15,11 +15,12 @@ currentLang = "zh"; } - // Build base paths + // Build base paths — always navigate to root of target version function basePath(version, lang) { - var docsRoot = path.replace(/\/v1\/.*/, "/").replace(/\/cn\/.*/, "/"); - docsRoot = docsRoot.replace(/(\/docs\/?).*/, "/docs/"); - if (!docsRoot.endsWith("/")) docsRoot += "/"; + // Determine site root: everything before /v1/, /cn/, or first path segment after /docs/ + var root = "/"; + var docsMatch = path.match(/^(\/docs\/)/); + if (docsMatch) root = docsMatch[1]; var p = docsRoot; if (version === "v1") p += "v1/";