seahawk

Finished
1212 return markdown.replace(pattern, replacement);
1313}
1414
15function parse__(markdown) {
15// Parse bold text (surrounded by double underscores)
16function parseBold(markdown) {
1617 return parser(markdown, '__', 'strong');
1718}
1819
19function parse_(markdown) {
20// Parse italic text (surrounded by single underscores)
21function parseItalic(markdown) {
2022 return parser(markdown, '_', 'em');
2123}
2224
25// Parse inline formatting (bold and italic) and wrap in paragraph tags if not in a list
2326function parseText(markdown, list) {
24 const parsedText = parse_(parse__(markdown));
27 const parsedText = parseItalic(parseBold(markdown));
2528 if (list) {
2629 return parsedText;
2730 } else {
2932 }
3033}
3134
35// Parse markdown headers (lines starting with # characters)
36// Returns [html, inList] tuple where html is the generated HTML or null if not a header
3237function parseHeader(markdown, list) {
33 let count = 0;
38 // Count leading # characters to determine header level
39 let headerLevel = 0;
3440 for (let i = 0; i < markdown.length; i++) {
3541 if (markdown[i] === '#') {
36 count += 1;
42 headerLevel += 1;
3743 } else {
3844 break;
3945 }
4046 }
41 if (count === 0 || count > 6) {
47
48 // Not a header if no # found or too many # (max h6)
49 if (headerLevel === 0 || headerLevel > 6) {
4250 return [null, list];
4351 }
44 const headerTag = `h${count}`;
45 const headerHtml = wrap(markdown.substring(count + 1), headerTag);
52
53 const headerTag = `h${headerLevel}`;
54 const headerContent = markdown.substring(headerLevel + 1).trim();
55 const headerHtml = wrap(headerContent, headerTag);
56
57 // Close any open list before adding header
4658 if (list) {
4759 return [`</ul>${headerHtml}`, false];
4860 } else {
5062 }
5163}
5264
65// Parse list items (lines starting with *)
66// Returns [html, inList] tuple where html is the generated HTML or null if not a list item
5367function parseLineItem(markdown, list) {
5468 if (markdown.startsWith('*')) {
55 const innerHtml = wrap(parseText(markdown.substring(2), true), 'li');
69 // Remove the '* ' prefix and parse the remaining text as a list item
70 const itemContent = markdown.substring(2);
71 const listItemHtml = wrap(parseText(itemContent, true), 'li');
72
5673 if (list) {
57 return [innerHtml, true];
74 // Already in a list, just add the list item
75 return [listItemHtml, true];
5876 } else {
59 return [`<ul>${innerHtml}`, true];
77 // Starting a new list, wrap in ul tags
78 return [`<ul>${listItemHtml}`, true];
6079 }
6180 }
6281 return [null, list];
6382}
6483
84// Parse regular paragraphs (fallback for lines that aren't headers or list items)
85// Always closes any open list before creating a paragraph
6586function parseParagraph(markdown, list) {
6687 if (!list) {
6788 return [parseText(markdown, false), false];
7091 }
7192}
7293
94// Parse a single line of markdown by trying different parsers in order
95// Returns [html, inList] tuple with the generated HTML and whether we're in a list
7396function parseLine(markdown, list) {
97 // Try parsing as header first
7498 let [result, inListAfter] = parseHeader(markdown, list);
75 if (result === null) {
76 [result, inListAfter] = parseLineItem(markdown, list);
99 if (result !== null) {
100 return [result, inListAfter];
77101 }
78 if (result === null) {
79 [result, inListAfter] = parseParagraph(markdown, list);
80 }
81 if (result === null) {
82 throw new Error('Remove this line and implement the function');
102
103 // Try parsing as list item
104 [result, inListAfter] = parseLineItem(markdown, list);
105 if (result !== null) {
106 return [result, inListAfter];
83107 }
108
109 // Fallback to paragraph parsing
110 [result, inListAfter] = parseParagraph(markdown, list);
84111 return [result, inListAfter];
112
113 // Note: The original code had an error throw here, but it should never be reached
114 // since parseParagraph always returns a result. This has been removed for clarity.
85115}
86116
87117/**
88 * @param {string} markdown
89 * @returns {string}
118 * Parse markdown text and convert it to HTML
119 * @param {string} markdown - The markdown text to parse
120 * @returns {string} - The resulting HTML
90121 */
91122export function parse(markdown) {
92123 const lines = markdown.split('\n');
93 let result = '';
94 let list = false;
124 let html = '';
125 let inList = false;
126
127 // Process each line of the markdown text
95128 for (let i = 0; i < lines.length; i++) {
96 let [lineResult, newList] = parseLine(lines[i], list);
97 result += lineResult;
98 list = newList;
129 const [lineHtml, newListState] = parseLine(lines[i], inList);
130 html += lineHtml;
131 inList = newListState;
99132 }
100 if (list) {
101 return result + '</ul>';
133
134 // Close any open list at the end of the document
135 if (inList) {
136 return html + '</ul>';
102137 } else {
103 return result;
138 return html;
104139 }
105140}
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.