73 lines
2.7 KiB
JavaScript
73 lines
2.7 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* sync-server-docs.mjs — Single Source bleibt in den Quell-Repos,
|
|
* diese Doku rendert nur. Kopiert:
|
|
* - ../tibi-server/docs/*.md -> src/content/docs/server/ (ohne uebersicht.md zu überschreiben)
|
|
* - ../tibi-admin-nova/docs/*.md -> src/content/docs/nova/ (+ test-plans/)
|
|
* Fügt fehlendes Starlight-Frontmatter (title) aus Dateinamen/H1 hinzu.
|
|
*/
|
|
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const serverSrc = join(root, '..', 'tibi-server', 'docs');
|
|
const novaSrc = join(root, '..', 'tibi-admin-nova', 'docs');
|
|
const serverDst = join(root, 'src', 'content', 'docs', 'server');
|
|
const novaDst = join(root, 'src', 'content', 'docs', 'nova');
|
|
|
|
const titleFromName = (f) =>
|
|
f.replace(/\.md$/, '').replace(/^\d+-/, '').split('-')
|
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
|
|
function ensureFrontmatter(file, fallbackTitle) {
|
|
let text = readFileSync(file, 'utf8');
|
|
if (text.startsWith('---')) return; // hat schon Frontmatter
|
|
const h1 = text.match(/^#\s+(.+)$/m)?.[1]?.trim() ?? fallbackTitle;
|
|
writeFileSync(file, `---\ntitle: '${h1.replace(/'/g, "''")}'\n---\n\n${text}`);
|
|
}
|
|
|
|
function syncTree(srcDir, dstDir, keep) {
|
|
let n = 0;
|
|
for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
|
|
if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;
|
|
const s = join(srcDir, entry.name);
|
|
const d = join(dstDir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
mkdirSync(d, { recursive: true });
|
|
n += syncTree(s, d, []);
|
|
} else if (entry.name.endsWith('.md')) {
|
|
if (keep.includes(entry.name)) continue;
|
|
cpSync(s, d);
|
|
ensureFrontmatter(d, titleFromName(entry.name));
|
|
n++;
|
|
} else {
|
|
cpSync(s, d);
|
|
n++;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
function syncDir(src, dst, { keep = [] } = {}) {
|
|
if (!existsSync(src)) {
|
|
console.warn(`[sync] Quelle fehlt, übersprungen: ${src}`);
|
|
return 0;
|
|
}
|
|
mkdirSync(dst, { recursive: true });
|
|
return syncTree(src, dst, keep);
|
|
}
|
|
|
|
// Alte Sync-Artefakte aufräumen (nur generierte, eigene uebersicht/konzept bleiben via keep)
|
|
const n1 = syncDir(serverSrc, serverDst, { keep: ['uebersicht.md'] });
|
|
const n2 = syncDir(novaSrc, novaDst, { keep: ['konzept.md'] });
|
|
console.log(`[sync] ${n1} Server-Dateien, ${n2} Nova-Dateien synchronisiert.`);
|
|
|
|
// Scaffold-Reste entfernen, falls vorhanden
|
|
for (const stale of [
|
|
join(root, 'src', 'content', 'docs', 'guides'),
|
|
join(root, 'src', 'content', 'docs', 'reference', 'example.md'),
|
|
]) {
|
|
if (existsSync(stale)) rmSync(stale, { recursive: true, force: true });
|
|
}
|