| 1 | // ============================================================================= |
| 2 | // UTILITY FUNCTIONS |
| 3 | // ============================================================================= |
| 4 | |
| 5 | /** |
| 6 | * Wraps text in an HTML tag |
| 7 | * @param {string} text - The text to wrap |
| 8 | * @param {string} tag - The HTML tag name |
| 9 | * @returns {string} The wrapped text |
| 10 | */ |
| 1 | 11 | function wrap(text, tag) { |
| 2 | 12 | return `<${tag}>${text}</${tag}>`; |
| 3 | 13 | } |
| 4 | 14 | |
| 15 | /** |
| 16 | * Checks if text starts with a specific HTML tag |
| 17 | * @param {string} text - The text to check |
| 18 | * @param {string} tag - The tag name to check for |
| 19 | * @returns {boolean} True if text starts with the tag |
| 20 | */ |
| 5 | 21 | function isTag(text, tag) { |
| 6 | 22 | return text.startsWith(`<${tag}>`); |
| 7 | 23 | } |
| 8 | 24 | |
| 9 | 25 | function parser(markdown, delimiter, tag) { |
| 10 | | const pattern = new RegExp(`${delimiter}(.+)${delimiter}`); |
| 26 | // Use non-greedy matching and word boundaries to avoid over-matching |
| 27 | const pattern = new RegExp(`${delimiter}([^${delimiter}]+)${delimiter}`, 'g'); |
| 11 | 28 | const replacement = `<${tag}>$1</${tag}>`; |
| 12 | 29 | return markdown.replace(pattern, replacement); |
| 13 | 30 | } |
| 14 | 31 | |
| 15 | | function parse__(markdown) { |
| 32 | function parseAsteriskBold(markdown) { |
| 33 | // Parse **bold** text |
| 34 | return parser(markdown, '\\\*\\\*', 'strong'); |
| 35 | } |
| 36 | |
| 37 | function parseAsteriskItalic(markdown) { |
| 38 | // Parse *italic* text |
| 39 | return parser(markdown, '\\\*', 'em'); |
| 40 | } |
| 41 | |
| 42 | function parseUnderscoreBold(markdown) { |
| 43 | // Parse __bold__ text |
| 16 | 44 | return parser(markdown, '__', 'strong'); |
| 17 | 45 | } |
| 18 | 46 | |
| 19 | | function parse_(markdown) { |
| 47 | function parseUnderscoreItalic(markdown) { |
| 48 | // Parse _italic_ text |
| 20 | 49 | return parser(markdown, '_', 'em'); |
| 21 | 50 | } |
| 22 | 51 | |
| 23 | 52 | function parseText(markdown, list) { |
| 24 | | const parsedText = parse_(parse__(markdown)); |
| 53 | // Parse emphasis and bold formatting |
| 54 | // Order matters: parse bold before italic to handle nested formatting correctly |
| 55 | let parsedText = markdown; |
| 56 | |
| 57 | // Parse bold formatting first (** and __) |
| 58 | parsedText = parseAsteriskBold(parsedText); |
| 59 | parsedText = parseUnderscoreBold(parsedText); |
| 60 | |
| 61 | // Then parse italic formatting (* and _) |
| 62 | parsedText = parseAsteriskItalic(parsedText); |
| 63 | parsedText = parseUnderscoreItalic(parsedText); |
| 64 | |
| 25 | 65 | if (list) { |
| 26 | 66 | return parsedText; |
| 27 | 67 | } else { |