Initial: Tibi-Doku auf Starlight-Basis (Nova-Theme, Docker-Stack, Sync-Skripte)
This commit is contained in:
commit
58502aa3c8
78 files changed
+22860
No files matched your search
@@ -0,0 +1,72 @@
|
||||
#!/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 });
|
||||
}
|
||||
Reference in new issue
Block a user