Spaces:
Paused
Paused
| import { escapeRegExp } from "../utils.js"; | |
| /** | |
| * Convert standard Markdown formatting to WhatsApp-compatible markup. | |
| * | |
| * WhatsApp uses its own formatting syntax: | |
| * bold: *text* | |
| * italic: _text_ | |
| * strikethrough: ~text~ | |
| * monospace: ```text``` | |
| * | |
| * Standard Markdown uses: | |
| * bold: **text** or __text__ | |
| * italic: *text* or _text_ | |
| * strikethrough: ~~text~~ | |
| * code: `text` (inline) or ```text``` (block) | |
| * | |
| * The conversion preserves fenced code blocks and inline code, | |
| * then converts bold and strikethrough markers. | |
| */ | |
| /** Placeholder tokens used during conversion to protect code spans. */ | |
| const FENCE_PLACEHOLDER = "\x00FENCE"; | |
| const INLINE_CODE_PLACEHOLDER = "\x00CODE"; | |
| /** | |
| * Convert standard Markdown bold/italic/strikethrough to WhatsApp formatting. | |
| * | |
| * Order of operations matters: | |
| * 1. Protect fenced code blocks (```...```) β already WhatsApp-compatible | |
| * 2. Protect inline code (`...`) β leave as-is | |
| * 3. Convert **bold** β *bold* and __bold__ β *bold* | |
| * 4. Convert ~~strike~~ β ~strike~ | |
| * 5. Restore protected spans | |
| * | |
| * Italic *text* and _text_ are left alone since WhatsApp uses _text_ for italic | |
| * and single * is already WhatsApp bold β no conversion needed for single markers. | |
| */ | |
| export function markdownToWhatsApp(text: string): string { | |
| if (!text) { | |
| return text; | |
| } | |
| // 1. Extract and protect fenced code blocks | |
| const fences: string[] = []; | |
| let result = text.replace(/```[\s\S]*?```/g, (match) => { | |
| fences.push(match); | |
| return `${FENCE_PLACEHOLDER}${fences.length - 1}`; | |
| }); | |
| // 2. Extract and protect inline code | |
| const inlineCodes: string[] = []; | |
| result = result.replace(/`[^`\n]+`/g, (match) => { | |
| inlineCodes.push(match); | |
| return `${INLINE_CODE_PLACEHOLDER}${inlineCodes.length - 1}`; | |
| }); | |
| // 3. Convert **bold** β *bold* and __bold__ β *bold* | |
| result = result.replace(/\*\*(.+?)\*\*/g, "*$1*"); | |
| result = result.replace(/__(.+?)__/g, "*$1*"); | |
| // 4. Convert ~~strikethrough~~ β ~strikethrough~ | |
| result = result.replace(/~~(.+?)~~/g, "~$1~"); | |
| // 5. Restore inline code | |
| result = result.replace( | |
| new RegExp(`${escapeRegExp(INLINE_CODE_PLACEHOLDER)}(\\d+)`, "g"), | |
| (_, idx) => inlineCodes[Number(idx)] ?? "", | |
| ); | |
| // 6. Restore fenced code blocks | |
| result = result.replace( | |
| new RegExp(`${escapeRegExp(FENCE_PLACEHOLDER)}(\\d+)`, "g"), | |
| (_, idx) => fences[Number(idx)] ?? "", | |
| ); | |
| return result; | |
| } | |