/** * Reusable markdown processing utility extracted from MessageBubble * for use in legal documents and other content */ function escapeHtml(input: string): string { return String(input) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } export const processMarkdown = (text: string): string => { let processed = text || ''; processed = processed.replace(/\\\[([\s\S]*?)\\\]/g, (_, math) => { const cleanMath = math.trim() .replace(/\\text\{([^}]+)\}/g, '$1') .replace(/\\,/g, ' ') .replace(/\\/g, ''); return `
${cleanMath}
`; }); processed = processed.replace(/\\\(([\s\S]*?)\\\)/g, (_, math) => { const cleanMath = math.trim() .replace(/\\text\{([^}]+)\}/g, '$1') .replace(/\\,/g, ' ') .replace(/\\/g, ''); return `${cleanMath}`; }); processed = processed.replace(/\$\$([^$]+)\$\$/g, (_, math) => { return `
${math.trim()}
`; }); processed = processed.replace(/\$([^$]+)\$/g, (_, math) => { return `${math}`; }); processed = processed.replace(/`([^`]+)`/g, (_, code) => { return `${escapeHtml( code )}`; }); processed = processed.replace(/\*\*([^*]+)\*\*/g, '$1'); processed = processed.replace(/__([^_]+)__/g, '$1'); processed = processed.replace(/\*([^*]+)\*/g, '$1'); processed = processed.replace(/_([^_]+)_/g, '$1'); processed = processed.replace( /!\[([^\]]*)\]\(([^)]+)\)/g, (_m, alt, url) => `${escapeHtml(alt)}` ); processed = processed.replace( /\[([^\]]+)\]\(([^)]+)\)/g, '$1' ); processed = processed.replace(/^#### (.*$)/gm, '

$1

'); processed = processed.replace(/^### (.*$)/gm, '

$1

'); processed = processed.replace(/^## (.*$)/gm, '

$1

'); processed = processed.replace(/^# (.*$)/gm, '

$1

'); processed = processed.replace( /(^|\n)((?:\s*[-*]\s+.+\n?)+)/gm, (_m: string, lead: string, block: string) => { const items = block .trimEnd() .split(/\n/) .filter(Boolean) .map((line: string) => line.replace(/^\s*[-*]\s+/, '')) .map((inner: string) => `
  • ${inner}
  • `) .join(''); return `${lead}`; } ); processed = processed.replace( /(^|\n)((?:\s*\d+\.\s+.+\n?)+)/gm, (_m: string, lead: string, block: string) => { const items = block .trimEnd() .split(/\n/) .filter(Boolean) .map((line: string) => line.replace(/^\s*\d+\.\s+/, '')) .map((inner: string) => `
  • ${inner}
  • `) .join(''); return `${lead}
      ${items}
    `; } ); processed = processed.replace(/\n{2,}/g, '

    '); processed = processed .replace(/<\/li>

    /g, '') .replace(/<\/ul>

    /g, '') .replace(/<\/ol>

    /g, ''); return processed; };