178 lines
4.4 KiB
JavaScript
178 lines
4.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Erzeugt aus DSGVO-Dokumentation.md eine PDF-Datei.
|
|
* Verwendung: node generate-dsgvo-pdf.js
|
|
*/
|
|
|
|
const PDFDocument = require('pdfkit');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const MARGIN = 50;
|
|
const PAGE_WIDTH = 595; // A4
|
|
const CONTENT_WIDTH = PAGE_WIDTH - 2 * MARGIN;
|
|
|
|
function stripBold(text) {
|
|
return text.replace(/\*\*([^*]+)\*\*/g, '$1');
|
|
}
|
|
|
|
function isTableRow(line) {
|
|
return /^\|.+\|$/.test(line.trim()) && !/^[\s|:-]+$/.test(line.replace(/\s/g, ''));
|
|
}
|
|
|
|
function parseTableRows(lines, startIndex) {
|
|
const rows = [];
|
|
let i = startIndex;
|
|
while (i < lines.length && isTableRow(lines[i])) {
|
|
const line = lines[i];
|
|
if (/^[\s|:-]+$/.test(line.replace(/\s/g, ''))) {
|
|
i++;
|
|
continue; // separator line
|
|
}
|
|
const cells = line.split('|').slice(1, -1).map(c => c.trim());
|
|
if (cells.some(c => c)) rows.push(cells);
|
|
i++;
|
|
}
|
|
return { rows, nextIndex: i };
|
|
}
|
|
|
|
function writeText(doc, text, options = {}) {
|
|
const opts = { width: CONTENT_WIDTH, ...options };
|
|
doc.text(text, opts);
|
|
}
|
|
|
|
function addParagraph(doc, line, fontSize = 10) {
|
|
doc.fontSize(fontSize).font('Helvetica');
|
|
const text = stripBold(line.trim());
|
|
if (!text) return;
|
|
writeText(doc, text);
|
|
doc.moveDown(0.5);
|
|
}
|
|
|
|
function addBullet(doc, line, fontSize = 10) {
|
|
doc.fontSize(fontSize).font('Helvetica');
|
|
const text = stripBold(line.replace(/^[-*]\s*/, '').trim());
|
|
if (!text) return;
|
|
doc.text('• ', { continued: true });
|
|
doc.text(text, { width: CONTENT_WIDTH - 20 });
|
|
doc.moveDown(0.4);
|
|
}
|
|
|
|
function addTable(doc, rows, fontSize = 9) {
|
|
if (rows.length === 0) return;
|
|
const colCount = rows[0].length;
|
|
const colWidth = CONTENT_WIDTH / colCount;
|
|
const rowHeight = fontSize * 1.4;
|
|
const startY = doc.y;
|
|
|
|
doc.fontSize(fontSize);
|
|
rows.forEach((row, rowIndex) => {
|
|
const isHeader = rowIndex === 0;
|
|
if (isHeader) doc.font('Helvetica-Bold');
|
|
if (doc.y > 750) {
|
|
doc.addPage();
|
|
doc.y = MARGIN;
|
|
}
|
|
let x = MARGIN;
|
|
row.forEach((cell, cellIndex) => {
|
|
doc.text(cell, x, doc.y, { width: colWidth - 4, align: 'left' });
|
|
x += colWidth;
|
|
});
|
|
doc.y += rowHeight;
|
|
if (isHeader) doc.font('Helvetica');
|
|
});
|
|
doc.moveDown(0.5);
|
|
}
|
|
|
|
function generateDSGVOPdf() {
|
|
const mdPath = path.join(__dirname, 'DSGVO-Dokumentation.md');
|
|
const outPath = path.join(__dirname, 'DSGVO-Dokumentation.pdf');
|
|
|
|
if (!fs.existsSync(mdPath)) {
|
|
console.error('Datei nicht gefunden: DSGVO-Dokumentation.md');
|
|
process.exit(1);
|
|
}
|
|
|
|
const content = fs.readFileSync(mdPath, 'utf8');
|
|
const lines = content.split(/\r?\n/);
|
|
|
|
const doc = new PDFDocument({ margin: MARGIN, size: 'A4' });
|
|
const stream = fs.createWriteStream(outPath);
|
|
doc.pipe(stream);
|
|
|
|
let i = 0;
|
|
while (i < lines.length) {
|
|
const line = lines[i];
|
|
const trimmed = line.trim();
|
|
|
|
// Neue Seite wenn nötig
|
|
if (doc.y > 750) doc.addPage();
|
|
|
|
if (trimmed.startsWith('# ')) {
|
|
doc.fontSize(22).font('Helvetica-Bold');
|
|
writeText(doc, trimmed.slice(2).trim(), { align: 'center' });
|
|
doc.moveDown(0.5);
|
|
doc.fontSize(12).text('Stundenerfassungssystem', { align: 'center' });
|
|
doc.moveDown(1);
|
|
doc.font('Helvetica');
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (trimmed.startsWith('## ')) {
|
|
doc.fontSize(16).font('Helvetica-Bold');
|
|
writeText(doc, trimmed.slice(3).trim());
|
|
doc.moveDown(0.5);
|
|
doc.font('Helvetica').fontSize(10);
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (trimmed.startsWith('### ')) {
|
|
doc.fontSize(13).font('Helvetica-Bold');
|
|
writeText(doc, trimmed.slice(4).trim());
|
|
doc.moveDown(0.4);
|
|
doc.font('Helvetica').fontSize(10);
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (trimmed === '---') {
|
|
doc.moveDown(0.5);
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (isTableRow(line)) {
|
|
const { rows, nextIndex } = parseTableRows(lines, i);
|
|
addTable(doc, rows);
|
|
i = nextIndex;
|
|
continue;
|
|
}
|
|
|
|
if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) {
|
|
addBullet(doc, trimmed);
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (trimmed) {
|
|
addParagraph(doc, trimmed);
|
|
} else {
|
|
doc.moveDown(0.3);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
doc.end();
|
|
stream.on('finish', () => {
|
|
console.log('PDF erstellt: ' + outPath);
|
|
});
|
|
stream.on('error', (err) => {
|
|
console.error('Fehler beim Schreiben der PDF:', err);
|
|
process.exit(1);
|
|
});
|
|
}
|
|
|
|
generateDSGVOPdf();
|