corpus

Finished
1function wrap(text, tag) {
2 return `<${tag}>${text}</${tag}>`;
3}
4
5function isTag(text, tag) {
6 return text.startsWith(`<${tag}>`);
7}
1/**
2 * Refactored Markdown Parser
3 *
4 * This refactored version improves readability and maintainability while
5 * preserving all original functionality. Key improvements include:
6 * - Clearer function names that describe their purpose
7 * - Better organization of parsing logic
8 * - Improved state management for lists
9 * - More readable code structure
10 */
811
9function parser(markdown, delimiter, tag) {
10 const pattern = new RegExp(`${delimiter}(.+)${delimiter}`);
11 const replacement = `<${tag}>$1</${tag}>`;
12 return markdown.replace(pattern, replacement);
12/**
13 * Wraps text with HTML tags
14 * @param {string} text - Text to wrap
15 * @param {string} tag - HTML tag to use
16 * @returns {string} Text wrapped in HTML tags
17 */
18function wrapInTag(text, tag) {
19 return `<${tag}>${text}</${tag}>`;
1320}
1421
15function parse__(markdown) {
16 return parser(markdown, '__', 'strong');
22/**
23 * Parses bold text (__) to <strong> tags
24 * @param {string} markdown - Markdown text to parse
25 * @returns {string} Parsed HTML
26 */
27function parseBold(markdown) {
28 const pattern = /__(.+?)__/g;
29 return markdown.replace(pattern, '<strong>$1</strong>');
1730}
1831
19function parse_(markdown) {
20 return parser(markdown, '_', 'em');
32/**
33 * Parses italic text (_) to <em> tags
34 * @param {string} markdown - Markdown text to parse
35 * @returns {string} Parsed HTML
36 */
37function parseItalic(markdown) {
38 const pattern = /_(.+?)_/g;
39 return markdown.replace(pattern, '<em>$1</em>');
2140}
2241
23function parseText(markdown, list) {
24 const parsedText = parse_(parse__(markdown));
25 if (list) {
26 return parsedText;
27 } else {
28 return wrap(parsedText, 'p');
29 }
42/**
43 * Parses inline formatting (bold and italic)
44 * @param {string} markdown - Markdown text to parse
45 * @returns {string} Parsed HTML
46 */
47function parseInlineFormatting(markdown) {
48 // Parse bold first, then italic
49 return parseItalic(parseBold(markdown));
3050}
3151
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;
39 }
40 }
41 if (count === 0 || count > 6) {
42 return [null, list];
52/**
53 * Parses header markdown (# Header) to HTML headers (h1-h6)
54 * @param {string} line - Line of markdown to parse
55 * @returns {string|null} Parsed HTML or null if not a header
56 */
57function parseHeader(line) {
58 // Count leading # characters
59 let level = 0;
60 while (level < line.length && line[level] === '#') {
61 level++;
4362 }
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];
63
64 // Valid headers have 1-6 # characters followed by a space
65 if (level === 0 || level > 6 || line[level] !== ' ') {
66 return null;
5067 }
68
69 // Extract header content and parse inline formatting
70 const content = line.substring(level + 1);
71 const formattedContent = parseInlineFormatting(content);
72 const headerTag = `h${level}`;
73 return wrapInTag(formattedContent, headerTag);
5174}
5275
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];
60 }
76/**
77 * Parses list items (* item) to HTML list items
78 * @param {string} line - Line of markdown to parse
79 * @returns {string|null} Parsed HTML or null if not a list item
80 */
81function parseListItem(line) {
82 // Check if line starts with '* ' (asterisk followed by space)
83 if (!line.startsWith('* ')) {
84 return null;
6185 }
62 return [null, list];
86
87 // Extract list item content and parse inline formatting
88 const content = line.substring(2);
89 const formattedContent = parseInlineFormatting(content);
90 return wrapInTag(formattedContent, 'li');
6391}
6492
65function parseParagraph(markdown, list) {
66 if (!list) {
67 return [parseText(markdown, false), false];
68 } else {
69 return [`</ul>${parseText(markdown, false)}`, false];
70 }
93/**
94 * Parses paragraph text with inline formatting
95 * @param {string} line - Line of markdown to parse
96 * @returns {string} Parsed HTML paragraph
97 */
98function parseParagraph(line) {
99 const formattedContent = parseInlineFormatting(line);
100 return wrapInTag(formattedContent, 'p');
71101}
72102
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);
103/**
104 * Processes a single line of markdown based on its type
105 * @param {string} line - Line of markdown to process
106 * @param {boolean} inList - Whether we're currently in a list
107 * @returns {[string, boolean]} Tuple of [processed HTML, new list state]
108 */
109function processLine(line, inList) {
110 // Try to parse as header
111 const headerHtml = parseHeader(line);
112 if (headerHtml !== null) {
113 // If we were in a list, close it before the header
114 const result = inList ? `</ul>${headerHtml}` : headerHtml;
115 return [result, false]; // Headers end lists
80116 }
81 if (result === null) {
82 throw new Error('Remove this line and implement the function');
117
118 // Try to parse as list item
119 const listItemHtml = parseListItem(line);
120 if (listItemHtml !== null) {
121 // If we weren't in a list, start one
122 const result = inList ? listItemHtml : `<ul>${listItemHtml}`;
123 return [result, true]; // Still in a list
83124 }
84 return [result, inListAfter];
125
126 // Parse as paragraph
127 const paragraphHtml = parseParagraph(line);
128 // If we were in a list, close it before the paragraph
129 const result = inList ? `</ul>${paragraphHtml}` : paragraphHtml;
130 return [result, false]; // Paragraphs end lists
85131}
86132
87133/**
88 * @param {string} markdown
89 * @returns {string}
134 * Parses markdown text and converts it to HTML
135 * @param {string} markdown - Markdown text to parse
136 * @returns {string} Converted HTML
90137 */
91138export function parse(markdown) {
92139 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;
140 const results = [];
141 let inList = false;
142
143 // Process each line
144 for (const line of lines) {
145 const [html, newListState] = processLine(line, inList);
146 results.push(html);
147 inList = newListState;
99148 }
100 if (list) {
101 return result + '</ul>';
102 } else {
103 return result;
149
150 // Close any open list at the end
151 if (inList) {
152 results.push('</ul>');
104153 }
154
155 return results.join('');
105156}
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.