Merge branch 'master' into feat/web-loader-plugin-inventory-settings

This commit is contained in:
Ziya
2026-08-12 14:35:46 +08:00
committed by GitHub
24 changed files with 579 additions and 133 deletions

View File

@@ -5,7 +5,7 @@ import { existsSync, globSync, mkdirSync, mkdtempSync, readFileSync, realpathSyn
import { tmpdir } from 'node:os'
import { basename, join, resolve } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { docsPages, type DocsPage } from '../website/docs.ts'
import { docsPages, landingLink, routeLink, sectionSpec, type DocsPage } from '../website/docs.ts'
import {
addProjectionFrontmatter, projectedPageContent, publishableImage, rewriteMarkdown,
} from './project-doc-site.ts'
@@ -364,6 +364,63 @@ describe('docsPages locale routes', () => {
})
})
describe('sidebar ordering', () => {
it('places every section a sidebar collection owns', () => {
for (const page of docsPages) {
if (page.sidebar === null) continue
expect(() => sectionSpec(page.locale, page.section), page.route).not.toThrow()
}
})
it('refuses a section with no declared placement', () => {
expect(() => sectionSpec('root', '数据结构'))
.toThrow('Sidebar section "数据结构" has no placement in the root locale.')
})
it('declares placements per locale rather than in one shared list', () => {
// `SDK` labels a group in both locales, so one shared list would have to
// rank it against `入门` and against `Guide` at the same position.
expect(sectionSpec('root', 'SDK').index).toBeGreaterThan(sectionSpec('root', '入门').index)
expect(sectionSpec('en', 'SDK').index).toBeGreaterThan(sectionSpec('en', 'Guide').index)
expect(() => sectionSpec('en', '入门')).toThrow()
expect(() => sectionSpec('root', 'Guide')).toThrow()
})
it('lands every navigation item on a page the manifest publishes', () => {
// The navigation bar named `/guide/` while the manifest published the guide's
// first page at `guide/quickstart.md`, so the item served a 404.
const collections = [
['root', 'zh-guide'], ['root', 'zh-develop'], ['root', 'zh-reference'],
['en', 'en-guide'], ['en', 'en-develop'], ['en', 'en-reference'],
] as const
const published = new Set(docsPages.map(page => routeLink(page.route)))
for (const [locale, collection] of collections) {
expect(published, `${locale}/${collection}`).toContain(landingLink(locale, collection))
}
})
it('collapses the subsystem groups and leaves the smaller ones open', () => {
expect(sectionSpec('root', '执行与工具').collapsed).toBe(true)
expect(sectionSpec('en', 'Execution and tools').collapsed).toBe(true)
expect(sectionSpec('root', '概念').collapsed).toBeUndefined()
})
it('gives each page its own position within a section', () => {
// Sidebar entries sort by order alone, so a shared value leaves the two
// pages ranked by whichever manifest block happens to be concatenated
// first rather than by an intent the manifest states.
const taken = new Map<string, string>()
const collisions: string[] = []
for (const page of docsPages) {
const slot = `${page.locale}/${String(page.sidebar)}/${page.section}#${page.order}`
const holder = taken.get(slot)
if (holder === undefined) taken.set(slot, page.label)
else collisions.push(`${slot}: ${holder} / ${page.label}`)
}
expect(collisions).toEqual([])
})
})
describe('addProjectionFrontmatter', () => {
it('adds frontmatter to an ordinary Markdown page', () => {
expect(addProjectionFrontmatter('# Guide\n', { source: 'docs/guide.md' })).toBe(
@@ -411,6 +468,25 @@ describe('projectedPageContent', () => {
expect(projectedPageContent(markdown, page('zh-guide'))).toBe(markdown)
})
it('drops the language switcher the navigation bar already offers', () => {
expect(projectedPageContent('# Guide\n\nEnglish | [中文](./en/guide)\n\nBody.\n', page('zh-guide')))
.toBe('# Guide\n\nBody.\n')
expect(projectedPageContent('# 指南\n\n[English](./en/guide) | 中文\n\n正文。\n', page('zh-guide')))
.toBe('# 指南\n\n正文。\n')
})
it('drops the repository badge every page links from its footer', () => {
const badge = '[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)'
expect(projectedPageContent(`# Guide\n\nBody.\n\n${badge}\n`, page('zh-guide')))
.toBe('# Guide\n\nBody.\n')
})
it('keeps a switcher-shaped line that is not the page header', () => {
// A tutorial showing the convention must still render the example.
const sample = '# Guide\n\nA\n\nB\n\nC\n\nD\n\nE\n\nEnglish | [中文](./x)\n'
expect(projectedPageContent(sample, page('zh-guide'))).toBe(sample)
})
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')

View File

@@ -292,6 +292,37 @@ export function addProjectionFrontmatter(markdown: string, page: Pick<DocsPage,
return `---\n${fields}\n---\n\n${markdown}`
}
/** The switcher line a canonical page carries so its GitHub reader can reach the other language. */
const LANGUAGE_SWITCHER = /^(?:English \| \[中文\]\([^)]*\)|\[English\]\([^)]*\) \| 中文)$/
/** The repository badge a canonical page carries for its GitHub reader. */
const REPOSITORY_BADGE = /^\[!\[[^\]]*\]\(https:\/\/img\.shields\.io\/[^)]*\)\]\([^)]*\)$/
/**
* Drop the lines that address a canonical page's GitHub reader.
*
* The site carries a locale switcher in its navigation bar and links the
* repository from every page, so projecting these lines would repeat both — the
* switcher as the first element under each heading.
*
* @param markdown Rewritten canonical Markdown content.
* @returns The content without the switcher line or the repository badge.
*/
function withoutRepositoryChrome(markdown: string): string {
const lines = markdown.split('\n')
const switcher = lines.findIndex(line => LANGUAGE_SWITCHER.test(line))
// Only the switcher introducing the page qualifies; further down the same
// text is prose or a sample rather than the page's own header.
if (switcher !== -1 && switcher < 8) {
lines.splice(switcher, lines[switcher + 1] === '' ? 2 : 1)
}
const badge = lines.findLastIndex(line => REPOSITORY_BADGE.test(line))
if (badge !== -1) {
lines.splice(lines[badge - 1] === '' ? badge - 1 : badge, lines[badge - 1] === '' ? 2 : 1)
}
return lines.join('\n')
}
/**
* Select the Markdown rendered for one published page.
*
@@ -300,7 +331,7 @@ export function addProjectionFrontmatter(markdown: string, page: Pick<DocsPage,
* @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 (page.sidebar !== null) return withoutRepositoryChrome(markdown)
if (!markdown.startsWith('---\n')) {
throw new Error(`project-doc-site: locale home source ${JSON.stringify(page.source)} must start with YAML frontmatter.`)
}