import MarkdownIt from 'markdown-it'; /** * Markdown wird beim Einlesen einmal nach HTML übersetzt und liegt dann fertig * im Speicher. Die Inhalte stammen aus dem Repository, sind also vertrauenswürdig * – trotzdem bleibt rohes HTML abgeschaltet, damit sich niemand daran gewöhnt. */ const uebersetzer = new MarkdownIt({ html: false, linkify: false, typographer: false, breaks: false, }); export function nachHtml(markdown: string): string { return uebersetzer.render(markdown).trim(); } export function nachHtmlInline(markdown: string): string { return uebersetzer.renderInline(markdown).trim(); } /** Entfernt Auszeichnung, damit der Text durchsucht werden kann. */ export function nurText(markdown: string): string { return markdown .replace(/```[\s\S]*?```/g, ' ') .replace(/`([^`]*)`/g, '$1') .replace(/!?\[([^\]]*)\]\([^)]*\)/g, '$1') .replace(/^[#>\-*+|]+\s?/gm, ' ') .replace(/[*_~]/g, '') .replace(/\s+/g, ' ') .trim(); } export type Abschnitt = { titel: string; markdown: string; html: string }; /** * Zerlegt den Rumpf eines Handouts an den Überschriften der zweiten Ebene. * Der feste Aufbau eines Handouts – Das Wesentliche, Übersicht, Prüfungsfrage – * wird dadurch für die Darstellung einzeln greifbar. */ export function inAbschnitte(rumpf: string): Abschnitt[] { const zeilen = rumpf.split('\n'); const abschnitte: Abschnitt[] = []; let titel = ''; let puffer: string[] = []; const ablegen = () => { const markdown = puffer.join('\n').trim(); if (titel || markdown) { abschnitte.push({ titel, markdown, html: nachHtml(markdown) }); } puffer = []; }; for (const zeile of zeilen) { const treffer = /^##\s+(.+?)\s*$/.exec(zeile); if (treffer) { ablegen(); titel = treffer[1]!; } else { puffer.push(zeile); } } ablegen(); return abschnitte.filter((a) => a.titel !== '' || a.markdown !== ''); } /** Sucht einen Abschnitt anhand seiner Überschrift, unabhängig von Groß- und Kleinschreibung. */ export function abschnitt(abschnitte: Abschnitt[], titel: string): Abschnitt | undefined { const gesucht = titel.toLocaleLowerCase('de-DE'); return abschnitte.find((a) => a.titel.toLocaleLowerCase('de-DE') === gesucht); }