mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-03 05:08:53 +00:00
docs: синхронизировать английское руководство (#668)
Английская версия догнана до структуры и содержания русского руководства. Структурный гейт защищает H2-H4 и маркер актуальной версии от нового рассинхрона. Issue: #668 User-Visible: no
This commit is contained in:
committed by
claude[bot]
parent
cbc39cea7b
commit
85cba3d8b4
+827
-202
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url';
|
||||
import { DOC_SCREENSHOTS } from '../demo/docs/screenshots.mjs';
|
||||
import { visualFingerprint } from './source-fingerprint.mjs';
|
||||
import { freshnessSink, screenshotsMode } from './docs-freshness.mjs';
|
||||
import { guideParityErrors } from './user-guide-parity.mjs';
|
||||
|
||||
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const EXTERNAL = process.argv.includes('--external');
|
||||
@@ -184,6 +185,11 @@ for (const [en, ru, required] of [
|
||||
}
|
||||
}
|
||||
|
||||
errors.push(...guideParityErrors(
|
||||
canonicalText(resolve(ROOT, 'docs/USER-GUIDE.md')),
|
||||
canonicalText(resolve(ROOT, 'docs/USER-GUIDE.ru.md')),
|
||||
));
|
||||
|
||||
const staleTerms = [
|
||||
[/\bMarkup (?:tab|mode|editor)\b/gi, 'Plan'],
|
||||
[/(?:вкладка|режим|редактор) «Разметка»/gi, '«План»'],
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
const withoutFences = (text) => text.replace(/^```[^\n]*\n[\s\S]*?^```\s*$/gm, '');
|
||||
|
||||
export const guideHeadingProfile = (text) => withoutFences(text)
|
||||
.split(/\r?\n/)
|
||||
.flatMap((line) => {
|
||||
const match = line.match(/^(#{2,4})\s+(.+?)\s*#*\s*$/);
|
||||
if (!match) return [];
|
||||
const section = match[1].length === 2 ? match[2].match(/^(\d+)\./)?.[1] ?? null : null;
|
||||
return [{ level: match[1].length, section }];
|
||||
});
|
||||
|
||||
export const guideVersion = (text, language) => {
|
||||
const pattern = language === 'ru'
|
||||
? /^Актуально для \*\*(v[^*]+)\*\*\./m
|
||||
: /^Current for \*\*(v[^*]+)\*\*\./m;
|
||||
return text.match(pattern)?.[1] ?? null;
|
||||
};
|
||||
|
||||
export const guideParityErrors = (english, russian) => {
|
||||
const errors = [];
|
||||
const englishProfile = guideHeadingProfile(english);
|
||||
const russianProfile = guideHeadingProfile(russian);
|
||||
if (JSON.stringify(englishProfile) !== JSON.stringify(russianProfile)) {
|
||||
errors.push('docs/USER-GUIDE.md / docs/USER-GUIDE.ru.md: H2-H4 heading profiles differ');
|
||||
}
|
||||
|
||||
const englishVersion = guideVersion(english, 'en');
|
||||
const russianVersion = guideVersion(russian, 'ru');
|
||||
if (!englishVersion || !russianVersion) {
|
||||
errors.push('docs/USER-GUIDE.md / docs/USER-GUIDE.ru.md: current-version marker is missing');
|
||||
} else if (englishVersion !== russianVersion) {
|
||||
errors.push(`docs/USER-GUIDE.md / docs/USER-GUIDE.ru.md: current versions differ (${englishVersion} != ${russianVersion})`);
|
||||
}
|
||||
return errors;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
guideHeadingProfile,
|
||||
guideParityErrors,
|
||||
guideVersion,
|
||||
} from '../scripts/user-guide-parity.mjs';
|
||||
|
||||
const read = (path) => readFileSync(new URL(`../${path}`, import.meta.url), 'utf8');
|
||||
|
||||
test('#668: English and Russian user guides keep the same structure and version', () => {
|
||||
const english = read('docs/USER-GUIDE.md');
|
||||
const russian = read('docs/USER-GUIDE.ru.md');
|
||||
assert.deepEqual(guideParityErrors(english, russian), []);
|
||||
assert.equal(guideHeadingProfile(english).filter(({ section }) => section).length, 23);
|
||||
assert.equal(guideVersion(english, 'en'), guideVersion(russian, 'ru'));
|
||||
});
|
||||
|
||||
test('#668: removing a subsection makes the parity guard fail', () => {
|
||||
const english = '## 1. One\n### Detail\n## 2. Two\n';
|
||||
const russian = '## 1. Один\n## 2. Два\n';
|
||||
assert.match(guideParityErrors(english, russian).join('\n'), /heading profiles differ/);
|
||||
});
|
||||
|
||||
test('#668: changing a subsection level makes the parity guard fail', () => {
|
||||
const english = '## 1. One\n### Detail\n';
|
||||
const russian = '## 1. Один\n#### Деталь\n';
|
||||
assert.match(guideParityErrors(english, russian).join('\n'), /heading profiles differ/);
|
||||
});
|
||||
|
||||
test('#668: different guide version markers make the parity guard fail', () => {
|
||||
const english = 'Current for **v1.2.3**.\n';
|
||||
const russian = 'Актуально для **v1.2.4**.\n';
|
||||
assert.match(guideParityErrors(english, russian).join('\n'), /current versions differ/);
|
||||
});
|
||||
Reference in New Issue
Block a user