Spaces:
Sleeping
Sleeping
File size: 1,467 Bytes
0a8fe79 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
export function parseMarkdown(text) {
if (!text) return '';
// Escape HTML first to prevent XSS
let html = escapeHtml(text);
// Code blocks (``` ... ```)
html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (match, lang, code) => {
const cls = lang ? ` class="language-${lang}"` : '';
return `<pre><code${cls}>${code.trim()}</code></pre>`;
});
// Inline code
html = html.replace(/`([^`\n]+)`/g, '<code>$1</code>');
// Bold
html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
// Italic (avoid matching bold remnants)
html = html.replace(/(?<!\*)\*([^*\n]+)\*(?!\*)/g, '<em>$1</em>');
html = html.replace(/(?<!_)_([^_\n]+)_(?!_)/g, '<em>$1</em>');
// Blockquotes (lines starting with >)
html = html.replace(/^>\s?(.+)$/gm, '<blockquote>$1</blockquote>');
// @mentions
html = html.replace(/@(\w+)/g, '<span class="text-[#FFD700] font-semibold">@$1</span>');
// URLs — match http/https links
html = html.replace(
/(?<!="|'|")(https?:\/\/[^\s<]+)/g,
'<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>'
);
// Line breaks
html = html.replace(/\n/g, '<br />');
// Merge consecutive blockquotes
html = html.replace(/<\/blockquote><br \/><blockquote>/g, '<br />');
return html;
}
|