/** * dsh-web-notes Markdown helpers — auto-detection of Markdown text in the note * editor and the sanitized preview renderer (marked + DOMPurify, both bundled * into the client artifact). Detection is deliberately conservative: plain * prose must not trigger the preview/edit toggle, while real Markdown (from * pasted AI answers, shell transcripts, notes) does. * @module dsh-web-notes/client/markdown */ import { marked } from 'marked' import DOMPurify from 'dompurify' /** Configure the renderer once: GFM on, soft line breaks as
. */ marked.setOptions({ gfm: true, breaks: true, }) /** * Conservative Markdown heuristics. Each pattern must be unambiguous enough * that everyday notes (commands, credentials, parameter values) stay free of * the preview toggle, while headings, lists, code fences, quotes, tables, * links, bold/italic and strikethrough light it up. */ const MD_PATTERNS: readonly RegExp[] = [ // ATX headings: # to ###### at line start (1-3 spaces allowed). /(^|\n)[ \t]{0,3}#{1,6}[ \t]+/, // Fenced code blocks. /(^|\n)[ \t]{0,3}(```|~~~)/, // Indented code blocks (4 spaces / tab). /(^|\n)[ \t]{4}\S/, // Block quotes. /(^|\n)[ \t]{0,3}>[ \t]?/, // Unordered list items ("- " / "* " / "+ " with a following space). /(^|\n)[ \t]{0,3}[-*+][ \t]+/, // Ordered list items ("1. " / "1) "). /(^|\n)[ \t]{0,3}\d{1,9}[.)][ \t]+/, // Thematic breaks (three or more - * _ alone on a line). /(^|\n)[ \t]{0,3}([-*_][ \t]*){3,}$/, // Markdown link syntax. /\[[^\]]+\]\([^)]+\)/, // Inline code spans. /`[^`\n]+`/, // Bold / strong (double asterisks or underscores around non-space text). /(\*\*|__)[^*_\n]+(\*\*|__)/, // Italic (single asterisks around non-space, non-asterisk text). /(?', '>') .replaceAll('"', '"') .replaceAll("'", ''') }