Ver código fonte

fix duplicate documentation homepage content

Yichen Jiang 1 mês atrás
pai
commit
99ce2ce8b4

+ 2 - 0
.agents/notes/implemented/process/2026-07-13-documentation-site-projection.md

@@ -14,6 +14,8 @@ Canonical Markdown remains in the repository tier that owns it. Product-facing g
 
 `scripts/project-doc-site.ts` projects the manifest into the ignored `website/.generated/` directory before VitePress starts or builds. The generated tree follows public routes so VitePress navigation, locale detection, and local search share the same route vocabulary. Each page receives an `editSource` frontmatter field pointing to its canonical repository file; the edit-link callback reads only that page data, so public URLs remain independent of the source layout.
 
+Locale home projections retain only the canonical YAML frontmatter. The repository-facing body can keep its H1 and bilingual source links, while the VitePress home theme owns the rendered hero and features and the site navigation owns locale switching.
+
 The projector parses Markdown links without reserializing the document. A link to another published source becomes a site-relative route; a link to an unpublished repository file becomes a GitHub source link; a repository image becomes a raw GitHub URL. Missing relative targets fail projection. Unit tests pin these transformations, and `docs:check` runs the projector tests plus a production VitePress build as part of `doc-sync` and the parallel documentation gates.
 
 Mermaid renders the canonical diagrams. The website workspace explicitly declares the five packages that `vitepress-plugin-mermaid` asks Vite to prebundle because pnpm's strict dependency isolation otherwise makes those transitive packages unavailable to the local development server; Knip records this runtime-only use as an intentional dependency exception.

+ 31 - 1
scripts/project-doc-site.spec.ts

@@ -5,7 +5,7 @@ import { tmpdir } from 'node:os'
 import { join } from 'node:path'
 import { afterEach, describe, expect, it } from 'vitest'
 import { docsPages, type DocsPage } from '../website/docs.ts'
-import { addProjectionFrontmatter, rewriteMarkdown } from './project-doc-site.ts'
+import { addProjectionFrontmatter, projectedPageContent, rewriteMarkdown } from './project-doc-site.ts'
 
 const roots: string[] = []
 
@@ -175,3 +175,33 @@ describe('addProjectionFrontmatter', () => {
     )
   })
 })
+
+describe('projectedPageContent', () => {
+  const page = (sidebar: DocsPage['sidebar']): DocsPage => ({
+    locale: 'root',
+    contentLocale: 'zh-CN',
+    source: 'docs/index.zh.md',
+    route: 'index.md',
+    label: 'Home',
+    sidebar,
+    section: 'Home',
+    order: 0,
+  })
+
+  it('omits the source-only body from locale home pages', () => {
+    expect(projectedPageContent(
+      '---\nlayout: home\nhero:\n  name: Harness\n---\n\n# Harness\n\n[English](index.md) | 中文\n',
+      page(null),
+    )).toBe('---\nlayout: home\nhero:\n  name: Harness\n---\n')
+  })
+
+  it('keeps the full body for ordinary pages', () => {
+    const markdown = '---\ntitle: Guide\n---\n\n# Guide\n'
+    expect(projectedPageContent(markdown, page('zh-guide'))).toBe(markdown)
+  })
+
+  it('rejects a locale home source without frontmatter', () => {
+    expect(() => projectedPageContent('# Harness\n', page(null)))
+      .toThrow('locale home source "docs/index.zh.md" must start with YAML frontmatter')
+  })
+})

+ 21 - 1
scripts/project-doc-site.ts

@@ -268,6 +268,26 @@ export function addProjectionFrontmatter(markdown: string, sourcePath: string):
   return `---\n${field}\n---\n\n${markdown}`
 }
 
+/**
+ * Select the Markdown rendered for one published page.
+ *
+ * @param markdown Rewritten canonical Markdown content.
+ * @param page Publication manifest entry for the content.
+ * @returns Full Markdown for ordinary pages or frontmatter-only Markdown for a locale home page.
+ */
+export function projectedPageContent(markdown: string, page: DocsPage): string {
+  if (page.sidebar !== null) return markdown
+  if (!markdown.startsWith('---\n')) {
+    throw new Error(`project-doc-site: locale home source ${JSON.stringify(page.source)} must start with YAML frontmatter.`)
+  }
+  const closingDelimiter = '\n---\n'
+  const closing = markdown.indexOf(closingDelimiter, 4)
+  if (closing === -1) {
+    throw new Error(`project-doc-site: locale home source ${JSON.stringify(page.source)} has unclosed YAML frontmatter.`)
+  }
+  return markdown.slice(0, closing + closingDelimiter.length)
+}
+
 /** Canonical Markdown files watched by the local VitePress dev server. */
 export function docsSourceFiles(): string[] {
   return [...new Set(docsPages.map(page => resolve(root, page.source)))]
@@ -297,6 +317,6 @@ export function projectDocs(): void {
       repoRoot: root,
       repositoryRef,
     })
-    writeFileSync(output, addProjectionFrontmatter(projected, page.source))
+    writeFileSync(output, addProjectionFrontmatter(projectedPageContent(projected, page), page.source))
   }
 }