viola

Finished
1// REFACTORING NOTES:
2// 1. Improved inline formatting parsing to handle both * and ** for italics/bold
3// 2. Fixed regex patterns to be non-greedy and handle multiple elements correctly
4// 3. Better separation of concerns and clearer function names
5// 4. Added comprehensive comments for maintainability
6
7/**
8 * Wraps text in HTML tags
9 * @param {string} text - The text to wrap
10 * @param {string} tag - The HTML tag name
11 * @returns {string} The wrapped text
12 */
113function wrap(text, tag) {
214 return `<${tag}>${text}</${tag}>`;
315}
416
17/**
18 * Checks if text starts with a specific HTML tag
19 * @param {string} text - The text to check
20 * @param {string} tag - The tag to look for
21 * @returns {boolean} True if text starts with the tag
22 */
523function isTag(text, tag) {
624 return text.startsWith(`<${tag}>`);
725}
826
9function parser(markdown, delimiter, tag) {
10 const pattern = new RegExp(`${delimiter}(.+)${delimiter}`);
27/**
28 * Parses inline formatting (bold/italic) using regex
29 * @param {string} markdown - The markdown text
30 * @param {string} delimiter - The delimiter to search for
31 * @param {string} tag - The HTML tag to replace with
32 * @returns {string} The parsed text
33 */
34function parseInlineFormatting(markdown, delimiter, tag) {
35 // Escape special regex characters in delimiter
36 const escapedDelimiter = delimiter.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
37 // Use non-greedy matching to handle multiple elements correctly
38 const pattern = new RegExp(`${escapedDelimiter}([^${delimiter}]+?)${escapedDelimiter}`, 'g');
1139 const replacement = `<${tag}>$1</${tag}>`;
1240 return markdown.replace(pattern, replacement);
1341}
1442
15function parse__(markdown) {
16 return parser(markdown, '__', 'strong');
43/**
44 * Parses bold text (both ** and __)
45 * @param {string} markdown - The markdown text
46 * @returns {string} The text with bold formatting applied
47 */
48function parseBold(markdown) {
49 // Handle **bold** first, then __bold__
50 let result = parseInlineFormatting(markdown, '**', 'strong');
51 result = parseInlineFormatting(result, '__', 'strong');
52 return result;
1753}
1854
19function parse_(markdown) {
20 return parser(markdown, '_', 'em');
55/**
56 * Parses italic text (both * and _)
57 * @param {string} markdown - The markdown text
58 * @returns {string} The text with italic formatting applied
59 */
60function parseItalic(markdown) {
61 // Handle *italic* first, then _italic_
62 let result = parseInlineFormatting(markdown, '*', 'em');
63 result = parseInlineFormatting(result, '_', 'em');
64 return result;
65}
66
67/**
68 * Parses all inline formatting (bold and italic)
69 * @param {string} markdown - The markdown text
70 * @returns {string} The text with all inline formatting applied
71 */
72function parseInlineFormattingAll(markdown) {
73 // Parse bold first, then italic to avoid conflicts
74 let result = parseBold(markdown);
75 result = parseItalic(result);
76 return result;
2177}
2278
79/**
80 * Parses text content with inline formatting
81 * @param {string} markdown - The markdown text
82 * @param {boolean} list - Whether this is part of a list
83 * @returns {string} The parsed text
84 */
2385function parseText(markdown, list) {
24 const parsedText = parse_(parse__(markdown));
86 const parsedText = parseInlineFormattingAll(markdown);
2587 if (list) {
2688 return parsedText;
2789 } else {
42104 return [null, list];
43105 }
44106 const headerTag = `h${count}`;
45 const headerHtml = wrap(markdown.substring(count + 1), headerTag);
107 const headerContent = parseInlineFormattingAll(markdown.substring(count + 1));
108 const headerHtml = wrap(headerContent, headerTag);
46109 if (list) {
47110 return [`</ul>${headerHtml}`, false];
48111 } else {
50113 }
51114}
52115
116/**
117 * Parses list items (lines starting with * followed by space)
118 * @param {string} markdown - The markdown text
119 * @param {boolean} list - Whether we're currently in a list
120 * @returns {Array} [result, inListAfter]
121 */
53122function parseLineItem(markdown, list) {
54 if (markdown.startsWith('*')) {
123 // Only treat as list item if it starts with '* ' (asterisk followed by space)
124 // This prevents conflicts with *italic* or **bold** at line start
125 if (markdown.startsWith('* ')) {
55126 const innerHtml = wrap(parseText(markdown.substring(2), true), 'li');
56127 if (list) {
57128 return [innerHtml, true];
Test NameStatus
parses normal text as a paragraph
Pass
parsing italics
Pass
parsing bold text
Pass
mixed normal, italics and bold text
Pass
with h1 header level
Pass
with h2 header level
Pass
with h3 header level
Pass
with h4 header level
Pass
with h5 header level
Pass
with h6 header level
Pass
with h7 header level
Pass
unordered lists
Pass
with a little bit of everything
Pass
with markdown symbols in the header text that should not be interpreted
Pass
with markdown symbols in the list item text that should not be interpreted
Pass
with markdown symbols in the paragraph text that should not be interpreted
Pass
unordered lists close properly with preceding and following lines
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.