gilded / client /src /utils /markdown.js
OmegaOne
Upload 41 files
0a8fe79 verified
function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
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(/^&gt;\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(
/(?<!="|&#039;|&quot;)(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;
}