JiaYou

Finished
1// REFACTORING: Improved HTML generation utility
12function wrap(text, tag) {
23 return `<${tag}>${text}</${tag}>`;
34}
45
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}
6// REFACTORING: Removed unused isTag function
187
19function parse_(markdown) {
20 return parser(markdown, '_', 'em');
8// REFACTORING: Renamed and improved inline formatting parser
9function parseInlineFormatting(markdown) {
10 // Parse bold text first (double underscores)
11 const boldPattern = new RegExp(`__(.+)__`);
12 const boldReplacement = `<strong>$1</strong>`;
13 let result = markdown.replace(boldPattern, boldReplacement);
14
15 // Then parse italic text (single underscores)
16 const italicPattern = new RegExp(`_(.+)_`);
17 const italicReplacement = `<em>$1</em>`;
18 result = result.replace(italicPattern, italicReplacement);
19
20 return result;
2121}
2222
23function parseText(markdown, list) {
24 const parsedText = parse_(parse__(markdown));
25 if (list) {
26 return parsedText;
27 } else {
28 return wrap(parsedText, 'p');
23// REFACTORING: Simplified text processing with clear responsibility
24function processTextContent(markdown, isListItem = false) {
25 const processedText = parseInlineFormatting(markdown);
26
27 // Only wrap in paragraph tags if it's not a list item
28 if (isListItem) {
29 return processedText;
2930 }
31
32 return wrap(processedText, 'p');
3033}
3134
32function parseHeader(markdown, list) {
33 let count = 0;
34 for (let i = 0; i < markdown.length; i++) {
35 if (markdown[i] === '#') {
36 count += 1;
35// REFACTORING: Improved header parsing with clear logic
36function parseHeader(markdown, currentlyInList) {
37 // Count leading hash characters
38 let headerLevel = 0;
39 for (const char of markdown) {
40 if (char === '#') {
41 headerLevel++;
3742 } else {
3843 break;
3944 }
4045 }
41 if (count === 0 || count > 6) {
42 return [null, list];
46
47 // Not a header if no hashes or too many (max 6)
48 if (headerLevel === 0 || headerLevel > 6) {
49 return [null, currentlyInList];
4350 }
44 const headerTag = `h${count}`;
45 const headerHtml = wrap(markdown.substring(count + 1), headerTag);
46 if (list) {
51
52 // Extract header content (skip hashes and space)
53 const headerContent = markdown.substring(headerLevel + 1);
54 const headerHtml = wrap(headerContent, `h${headerLevel}`);
55
56 // Close list if we were in one
57 if (currentlyInList) {
4758 return [`</ul>${headerHtml}`, false];
48 } else {
49 return [headerHtml, false];
5059 }
60
61 return [headerHtml, false];
5162}
5263
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 }
64// REFACTORING: Improved list item parsing with clearer logic
65function parseListItem(markdown, currentlyInList) {
66 if (!markdown.startsWith('*')) {
67 return [null, currentlyInList];
6168 }
62 return [null, list];
69
70 // Extract list item content (skip '* ')
71 const itemContent = markdown.substring(2);
72 const processedContent = processTextContent(itemContent, true);
73 const listItemHtml = wrap(processedContent, 'li');
74
75 // Open list if we weren't already in one
76 if (!currentlyInList) {
77 return [`<ul>${listItemHtml}`, true];
78 }
79
80 return [listItemHtml, true];
6381}
6482
65function parseParagraph(markdown, list) {
66 if (!list) {
67 return [parseText(markdown, false), false];
68 } else {
69 return [`</ul>${parseText(markdown, false)}`, false];
83// REFACTORING: Simplified paragraph parsing
84function parseParagraph(markdown, currentlyInList) {
85 const paragraphHtml = processTextContent(markdown, false);
86
87 // Close list if we were in one
88 if (currentlyInList) {
89 return [`</ul>${paragraphHtml}`, false];
7090 }
91
92 return [paragraphHtml, false];
7193}
7294
73function parseLine(markdown, list) {
74 let [result, inListAfter] = parseHeader(markdown, list);
95// REFACTORING: Clearer parsing logic with explicit fallback chain
96function parseLine(markdown, currentlyInList) {
97 // Try parsing as header first
98 let [result, newListState] = parseHeader(markdown, currentlyInList);
99
100 // If not a header, try parsing as list item
75101 if (result === null) {
76 [result, inListAfter] = parseLineItem(markdown, list);
102 [result, newListState] = parseListItem(markdown, currentlyInList);
77103 }
104
105 // If neither header nor list item, treat as paragraph
78106 if (result === null) {
79 [result, inListAfter] = parseParagraph(markdown, list);
107 [result, newListState] = parseParagraph(markdown, currentlyInList);
80108 }
109
110 // This should never happen with valid input
81111 if (result === null) {
82 throw new Error('Remove this line and implement the function');
112 throw new Error('Unrecognized markdown line: ' + markdown);
83113 }
84 return [result, inListAfter];
114
115 return [result, newListState];
85116}
86117
87118/**
88 * @param {string} markdown
89 * @returns {string}
119 * REFACTORING: Main parser function with improved clarity
120 * Parses markdown text and returns HTML
121 * @param {string} markdown - The markdown text to parse
122 * @returns {string} The resulting HTML
90123 */
91export function parse(markdown) {
124function parse(markdown) {
92125 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;
126 let htmlResult = '';
127 let currentlyInList = false;
128
129 // Process each line of markdown
130 for (const line of lines) {
131 const [lineHtml, newListState] = parseLine(line, currentlyInList);
132 htmlResult += lineHtml;
133 currentlyInList = newListState;
99134 }
100 if (list) {
101 return result + '</ul>';
102 } else {
103 return result;
135
136 // Close any unclosed list
137 if (currentlyInList) {
138 htmlResult += '</ul>';
104139 }
140
141 return htmlResult;
105142}
143
144module.exports = { parse };
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.