future

Finished
1function wrap(text, tag) {
2 return `<${tag}>${text}</${tag}>`;
3}
4
5function isTag(text, tag) {
6 return text.startsWith(`<${tag}>`);
7}
8
9function parser(markdown, delimiter, tag) {
10 const pattern = new RegExp(`${delimiter}(.+)${delimiter}`);
11 const replacement = `<${tag}>$1</${tag}>`;
12 return markdown.replace(pattern, replacement);
13}
14
15function parse__(markdown) {
16 return parser(markdown, '__', 'strong');
17}
18
19function parse_(markdown) {
20 return parser(markdown, '_', 'em');
21}
22
23function parseText(markdown, list) {
24 const parsedText = parse_(parse__(markdown));
25 if (list) {
26 return parsedText;
27 } else {
28 return wrap(parsedText, 'p');
29 }
30}
31
32function parseHeader(markdown, list) {
33 let count = 0;
34 for (let i = 0; i < markdown.length; i++) {
35 if (markdown[i] === '#') {
36 count += 1;
37 } else {
38 break;
1/**
2 * Parses Markdown text and converts it to HTML.
3 * Supports headers (# ## ### #### ##### ######),
4 * bold text (__text__), italic text (_text_),
5 * paragraphs, and unordered lists (* item).
6 *
7 * @param {string} markdown - The Markdown text to parse
8 * @returns {string} - The resulting HTML
9 */
10export function parse(markdown) {
11 const lines = markdown.split('\n');
12 let html = '';
13 let inList = false;
14
15 for (const line of lines) {
16 // Check for headers (# ## ### etc.)
17 const headerMatch = line.match(/^(#{1,6})\s+(.*)$/);
18 if (headerMatch) {
19 // Close list if we were in one
20 if (inList) {
21 html += '</ul>';
22 inList = false;
23 }
24
25 const level = headerMatch[1].length; // Number of # characters
26 const content = headerMatch[2];
27 const tag = `h${level}`;
28 html += `<${tag}>${parseInline(content)}</${tag}>`;
29 continue;
3930 }
40 }
41 if (count === 0 || count > 6) {
42 return [null, list];
43 }
44 const headerTag = `h${count}`;
45 const headerHtml = wrap(markdown.substring(count + 1), headerTag);
46 if (list) {
47 return [`</ul>${headerHtml}`, false];
48 } else {
49 return [headerHtml, false];
50 }
51}
52
53function parseLineItem(markdown, list) {
54 if (markdown.startsWith('*')) {
55 const innerHtml = wrap(parseText(markdown.substring(2), true), 'li');
56 if (list) {
57 return [innerHtml, true];
58 } else {
59 return [`<ul>${innerHtml}`, true];
31
32 // Check for list items (* item)
33 if (line.startsWith('* ')) {
34 const content = line.substring(2); // Remove '* ' prefix
35
36 // Open list if not already in one
37 if (!inList) {
38 html += '<ul>';
39 inList = true;
40 }
41
42 html += `<li>${parseInline(content)}</li>`;
43 continue;
44 }
45
46 // Close list if we were in one and this line is not a list item
47 if (inList) {
48 html += '</ul>';
49 inList = false;
50 }
51
52 // Treat as paragraph
53 if (line.trim() !== '') {
54 html += `<p>${parseInline(line)}</p>`;
6055 }
6156 }
62 return [null, list];
63}
64
65function parseParagraph(markdown, list) {
66 if (!list) {
67 return [parseText(markdown, false), false];
68 } else {
69 return [`</ul>${parseText(markdown, false)}`, false];
70 }
71}
72
73function parseLine(markdown, list) {
74 let [result, inListAfter] = parseHeader(markdown, list);
75 if (result === null) {
76 [result, inListAfter] = parseLineItem(markdown, list);
77 }
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');
57
58 // Close list if we finished while still in one
59 if (inList) {
60 html += '</ul>';
8361 }
84 return [result, inListAfter];
62
63 return html;
8564}
8665
8766/**
88 * @param {string} markdown
89 * @returns {string}
67 * Parses inline Markdown elements like bold (__text__) and italic (_text_)
68 * Replicates the original implementation's behavior exactly, including its regex patterns.
69 *
70 * @param {string} text - The text to parse
71 * @returns {string} - The resulting HTML with inline elements converted
9072 */
91export function parse(markdown) {
92 const lines = markdown.split('\n');
93 let result = '';
94 let list = false;
95 for (let i = 0; i < lines.length; i++) {
96 let [lineResult, newList] = parseLine(lines[i], list);
97 result += lineResult;
98 list = newList;
99 }
100 if (list) {
101 return result + '</ul>';
102 } else {
103 return result;
104 }
73function parseInline(text) {
74 // Parse bold (__text__) - using the same greedy regex as the original
75 const boldPattern = new RegExp('__(.+)__', 'g');
76 text = text.replace(boldPattern, '<strong>$1</strong>');
77
78 // Parse italic (_text_) - using the same greedy regex as the original
79 const italicPattern = new RegExp('_(.+)_', 'g');
80 text = text.replace(italicPattern, '<em>$1</em>');
81
82 return text;
10583}
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.