fix duplicate documentation homepage content
This commit is contained in:
@@ -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.
|
`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.
|
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.
|
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.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { tmpdir } from 'node:os'
|
|||||||
import { join } from 'node:path'
|
import { join } from 'node:path'
|
||||||
import { afterEach, describe, expect, it } from 'vitest'
|
import { afterEach, describe, expect, it } from 'vitest'
|
||||||
import { docsPages, type DocsPage } from '../website/docs.ts'
|
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[] = []
|
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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -268,6 +268,26 @@ export function addProjectionFrontmatter(markdown: string, sourcePath: string):
|
|||||||
return `---\n${field}\n---\n\n${markdown}`
|
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. */
|
/** Canonical Markdown files watched by the local VitePress dev server. */
|
||||||
export function docsSourceFiles(): string[] {
|
export function docsSourceFiles(): string[] {
|
||||||
return [...new Set(docsPages.map(page => resolve(root, page.source)))]
|
return [...new Set(docsPages.map(page => resolve(root, page.source)))]
|
||||||
@@ -297,6 +317,6 @@ export function projectDocs(): void {
|
|||||||
repoRoot: root,
|
repoRoot: root,
|
||||||
repositoryRef,
|
repositoryRef,
|
||||||
})
|
})
|
||||||
writeFileSync(output, addProjectionFrontmatter(projected, page.source))
|
writeFileSync(output, addProjectionFrontmatter(projectedPageContent(projected, page), page.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user