#!/usr/bin/env node /** * sync-server-docs.mjs — STILLGELEGT (2026-10-17). * * Grund: Der Sync kopierte die englischen Server-Docs nach src/content/docs/server/ und die * Nova-Docs nach src/content/docs/admin/. Diese Ziele stehen nicht in der Sidebar, es entstanden * verwaiste Seiten, die nie verlinkt wurden. Die deutschen Handseiten sind seither kanonisch. * * Nicht mehr aufrufen (kein npm-Script mehr). Datei bleibt nur als Nachweis/Referenz liegen. * * ALT: 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/admin/ (+ 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', 'admin'); 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 }); }