Bpistle/src/lib/markdown.ts
codytseng 6f779e8b24 fix: detect markdown image syntax ![alt](url) as strong signal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:57:39 +08:00

44 lines
1.3 KiB
TypeScript

/**
* Detects whether a string contains meaningful Markdown formatting.
* Strips URLs and nostr: references first to avoid false positives.
*/
export function containsMarkdown(content: string): boolean {
// Remove URLs and nostr: references to avoid false positives
const cleaned = content
.replace(/https?:\/\/[^\s)>\]]+/g, '')
.replace(/nostr:[a-z0-9]+/g, '')
// Strong signals — any single one triggers markdown
const strongPatterns = [
/^```/m, // code fence
/\|[\s]*:?-+:?[\s]*\|/, // table separator |---|
/!\[[^\]]*\]\(/ // image ![alt](
]
for (const pattern of strongPatterns) {
if (pattern.test(cleaned)) return true
}
// Medium signals — need 2+ different types
const mediumPatterns = [
/^#{1,6}\s+\S/m, // ATX heading (# text), not #hashtag
/\*\*[^*\n]+\*\*/, // bold **text**
/__[^_\n]+__/, // bold __text__
/\[[^\]]+\]\([^)]+\)/, // link [text](url)
/^>\s+\S/m, // blockquote > text
/^[-*]\s+\S/m, // unordered list - item or * item
/^\d+\.\s+\S/m, // ordered list 1. item
/^---$/m, // horizontal rule
/~~[^~\n]+~~/ // strikethrough ~~text~~
]
let matchCount = 0
for (const pattern of mediumPatterns) {
if (pattern.test(cleaned)) {
matchCount++
if (matchCount >= 2) return true
}
}
return false
}