diff --git a/src/lib/markdown.ts b/src/lib/markdown.ts index 45512df..abb1b1c 100644 --- a/src/lib/markdown.ts +++ b/src/lib/markdown.ts @@ -1,37 +1,53 @@ export function renderInlineMarkdown(text: string): string { if (!text) return ""; - // Helper function to escape HTML entities - const escapeHtml = (str: string): string => { - return str + const escapeHtml = (str: string): string => + str .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); - }; - // Process inline markdown patterns - let html = text - // Code: `text` - escape content inside backticks, then wrap in - .replace(/`([^`]+)`/g, (_, content) => `${escapeHtml(content)}`) + const pattern = /(`([^`]+)`)|(\*\*([^*]+)\*\*)|(__([^_]+)__)|(~~([^~]+)~~)|(? - .replace(/\*\*([^*]+)\*\*/g, (_, content) => `${escapeHtml(content)}`) - .replace(/__([^_]+)__/g, (_, content) => `${escapeHtml(content)}`) + let result = ""; + let lastIndex = 0; - // Italic: *text* or _text_ (but not part of bold) - escape content, then wrap in - .replace(/(? `${escapeHtml(content)}`) - .replace(/(? `${escapeHtml(content)}`) + for (const match of text.matchAll(pattern)) { + const matchIndex = match.index ?? 0; + if (matchIndex > lastIndex) { + result += escapeHtml(text.slice(lastIndex, matchIndex)); + } - // Strikethrough: ~~text~~ - escape content, then wrap in - .replace(/~~([^~]+)~~/g, (_, content) => `${escapeHtml(content)}`); + if (match[1]) { + // `code` + result += `${escapeHtml(match[2] ?? "")}`; + } else if (match[3]) { + // **bold** + result += `${escapeHtml(match[4] ?? "")}`; + } else if (match[5]) { + // __bold__ + result += `${escapeHtml(match[6] ?? "")}`; + } else if (match[7]) { + // ~~strikethrough~~ + result += `${escapeHtml(match[8] ?? "")}`; + } else if (match[9]) { + // *italic* + result += `${escapeHtml(match[9] ?? "")}`; + } else if (match[10]) { + // _italic_ + result += `${escapeHtml(match[10] ?? "")}`; + } - // Escape any remaining unprocessed text (text outside of markdown patterns) - // This is tricky because we need to avoid escaping the HTML we just created - // For now, we'll leave plain text unescaped since Astro should handle it + lastIndex = matchIndex + match[0].length; + } - return html; + if (lastIndex < text.length) { + result += escapeHtml(text.slice(lastIndex)); + } + + return result; } /**