mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
docs: enforce bilingual README coverage
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"requiredClasses": [
|
||||
"non-readme"
|
||||
"non-readme",
|
||||
"readme"
|
||||
],
|
||||
"requiredSince": "2026-07-14",
|
||||
"required": [
|
||||
|
||||
@@ -4,6 +4,7 @@ import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
datedDocumentDate,
|
||||
isIsoDate,
|
||||
isTranslationScopeFile,
|
||||
parseTranslationMarkdown,
|
||||
parseTranslationPairingManifest,
|
||||
requiresPairByDate,
|
||||
@@ -82,6 +83,45 @@ describe('document-class pairing frontier', () => {
|
||||
expect(requiresTranslationPair('docs/legacy/README.md', manifest)).toBe(true)
|
||||
expect(requiresTranslationPair('docs/new/README.md', manifest)).toBe(false)
|
||||
})
|
||||
|
||||
it('requires both document classes after the README frontier closes', () => {
|
||||
const closed = parseTranslationPairingManifest(JSON.stringify({
|
||||
...manifest,
|
||||
requiredClasses: ['non-readme', 'readme'],
|
||||
}))
|
||||
expect(requiresTranslationPair('docs/guide.md', closed)).toBe(true)
|
||||
expect(requiresTranslationPair('future/subtree/README.md', closed)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('translation scope discovery', () => {
|
||||
it.each([
|
||||
'README.md',
|
||||
'apps/cli/README.md',
|
||||
'future/subtree/readme.md',
|
||||
'packages/example/README.zh.md',
|
||||
'native/example/README.i18n.yaml',
|
||||
'.agents/notes/proposed/feature.md',
|
||||
'docs/guide.md',
|
||||
'python/guide.md',
|
||||
])('includes %s', (file) => {
|
||||
expect(isTranslationScopeFile(file)).toBe(true)
|
||||
})
|
||||
|
||||
it.each([
|
||||
'packages/example/guide.md',
|
||||
'examples/tutorial.md',
|
||||
'website/reference.md',
|
||||
'packages/example/README.txt',
|
||||
'vendor/example/README.md',
|
||||
'packages/example/node_modules/dependency/README.md',
|
||||
'packages/example/lib/README.md',
|
||||
'coverage/report/README.md',
|
||||
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-macos-arm64/README.md',
|
||||
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/README.md',
|
||||
])('excludes non-source or non-README path %s', (file) => {
|
||||
expect(isTranslationScopeFile(file)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('date-based pairing frontier', () => {
|
||||
|
||||
@@ -26,6 +26,63 @@ const TRANSLATION_DOCUMENT_CLASSES: TranslationDocumentClass[] = ['readme', 'non
|
||||
|
||||
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/
|
||||
const DATED_DOCUMENT = /(?:^|\/)(\d{4}-\d{2}-\d{2})-[^/]*\.md$/
|
||||
const README_ARTIFACT = /(?:^|\/)readme(?:\.md|\.zh\.md|\.i18n\.yaml)$/i
|
||||
const NON_SOURCE_DIRECTORIES = new Set([
|
||||
'node_modules',
|
||||
'lib',
|
||||
'.pnpm-store',
|
||||
'.cache',
|
||||
'coverage',
|
||||
'.sessions',
|
||||
'.storages',
|
||||
'tmp',
|
||||
'dist-exe',
|
||||
'__pycache__',
|
||||
'.pytest_cache',
|
||||
'.artifacts',
|
||||
'vendor',
|
||||
])
|
||||
|
||||
/** Glob traversal exclusions corresponding to the non-source path predicate. */
|
||||
export const TRANSLATION_SCOPE_GLOB_EXCLUDES = [
|
||||
'**/node_modules/**',
|
||||
'**/lib/**',
|
||||
'**/.pnpm-store/**',
|
||||
'**/.cache/**',
|
||||
'**/coverage/**',
|
||||
'**/.doc-typecheck-*/**',
|
||||
'**/.node-next-types-*/**',
|
||||
'**/.sessions/**',
|
||||
'**/.storages/**',
|
||||
'**/tmp/**',
|
||||
'**/dist-exe/**',
|
||||
'**/__pycache__/**',
|
||||
'**/.pytest_cache/**',
|
||||
'apps/web/dist/**',
|
||||
'.artifacts/**',
|
||||
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-*/**',
|
||||
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/**',
|
||||
'vendor/**',
|
||||
]
|
||||
|
||||
/** Whether a repository-relative path belongs to a dependency or generated tree. */
|
||||
function isTranslationSourceExcluded(file: string): boolean {
|
||||
const segments = file.split('/')
|
||||
return segments.some(segment => NON_SOURCE_DIRECTORIES.has(segment)
|
||||
|| segment.startsWith('.doc-typecheck-')
|
||||
|| segment.startsWith('.node-next-types-'))
|
||||
|| file.startsWith('apps/web/dist/')
|
||||
|| file.startsWith('python/sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-')
|
||||
|| file.startsWith('python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/')
|
||||
}
|
||||
|
||||
/** Whether one discovered Markdown or sidecar path belongs to the bilingual source corpus. */
|
||||
export function isTranslationScopeFile(file: string): boolean {
|
||||
return !isTranslationSourceExcluded(file) && (README_ARTIFACT.test(file)
|
||||
|| file.startsWith('.agents/notes/')
|
||||
|| file.startsWith('docs/')
|
||||
|| file.startsWith('python/'))
|
||||
}
|
||||
|
||||
/** Whether a string names one real calendar day in canonical ISO form. */
|
||||
export function isIsoDate(value: string): boolean {
|
||||
|
||||
@@ -15,7 +15,9 @@ import {
|
||||
linksTo,
|
||||
parseTranslationMarkdown,
|
||||
parseTranslationPairingManifest,
|
||||
isTranslationScopeFile,
|
||||
requiresTranslationPair,
|
||||
TRANSLATION_SCOPE_GLOB_EXCLUDES,
|
||||
translationDocumentClass,
|
||||
translationStructureDiff,
|
||||
translationStructureSignature,
|
||||
@@ -25,17 +27,12 @@ const root = resolve(import.meta.dirname, '..')
|
||||
const listMode = process.argv.includes('--list')
|
||||
const writeMode = process.argv.includes('--write')
|
||||
|
||||
/** Scope of the bilingual contract: root docs, Agent Notes, the docs tree, and the Python SDK tree. */
|
||||
/** Discover source Markdown and pairing sidecars before applying the corpus predicate. */
|
||||
const SCOPE_PATTERNS = [
|
||||
'README.md',
|
||||
'README.zh.md',
|
||||
'README.i18n.yaml',
|
||||
'**/*.md',
|
||||
'**/*.i18n.yaml',
|
||||
'.agents/notes/**/*.md',
|
||||
'.agents/notes/**/*.i18n.yaml',
|
||||
'docs/**/*.md',
|
||||
'docs/**/*.i18n.yaml',
|
||||
'python/**/*.md',
|
||||
'python/**/*.i18n.yaml',
|
||||
]
|
||||
|
||||
const manifest = parseTranslationPairingManifest(readFileSync(join(root, 'scripts/translation-pairing.manifest.json'), 'utf8'))
|
||||
@@ -93,7 +90,10 @@ function renderMeta(source: string, sourceHash: string, zh: string, zhHash: stri
|
||||
// Enumerate the scope once.
|
||||
const files = new Set<string>()
|
||||
for (const pattern of SCOPE_PATTERNS) {
|
||||
for (const match of globSync(pattern, { cwd: root })) files.add(match.split(sep).join('/'))
|
||||
for (const match of globSync(pattern, { cwd: root, exclude: TRANSLATION_SCOPE_GLOB_EXCLUDES })) {
|
||||
const normalized = match.split(sep).join('/')
|
||||
if (isTranslationScopeFile(normalized)) files.add(normalized)
|
||||
}
|
||||
}
|
||||
const translations = [...files].filter(f => f.endsWith('.zh.md')).sort()
|
||||
const metas = [...files].filter(f => f.endsWith('.i18n.yaml')).sort()
|
||||
|
||||
Reference in New Issue
Block a user