armor

Finished
1function wrap(text, tag) {
1// REFACTORING: Improved HTML wrapping utility with clearer naming
2function wrapTextInTag(text, tag) {
23 return `<${tag}>${text}</${tag}>`;
34}
45
5function isTag(text, tag) {
6// REFACTORING: Renamed isTag to be more descriptive - though this function appears unused
7function textStartsWithTag(text, tag) {
68 return text.startsWith(`<${tag}>`);
79}
810
9function parser(markdown, delimiter, tag) {
11// REFACTORING: More specific function for emphasis parsing with clearer intent
12function parseEmphasis(markdown, delimiter, htmlTag) {
1013 const pattern = new RegExp(`${delimiter}(.+)${delimiter}`);
11 const replacement = `<${tag}>$1</${tag}>`;
14 const replacement = `<${htmlTag}>$1</${htmlTag}>`;
1215 return markdown.replace(pattern, replacement);
1316}
1417
15function parse__(markdown) {
16 return parser(markdown, '__', 'strong');
18// REFACTORING: Specific functions for bold and italic with descriptive names
19function parseBoldText(markdown) {
20 return parseEmphasis(markdown, '__', 'strong');
1721}
1822
19function parse_(markdown) {
20 return parser(markdown, '_', 'em');
23function parseItalicText(markdown) {
24 return parseEmphasis(markdown, '_', 'em');
2125}
2226
23function parseText(markdown, list) {
24 const parsedText = parse_(parse__(markdown));
25 if (list) {
26 return parsedText;
27// REFACTORING: Improved parseText function with clearer logic and new function names
28function parseTextContent(markdown, isInsideList) {
29 // Apply emphasis parsing in order: bold first, then italic
30 const parsedText = parseItalicText(parseBoldText(markdown));
31
32 if (isInsideList) {
33 return parsedText; // Don't wrap in paragraph tags if inside a list
2734 } else {
28 return wrap(parsedText, 'p');
35 return wrapTextInTag(parsedText, 'p'); // Wrap in paragraph tags
2936 }
3037}
3138
32function parseHeader(markdown, list) {
33 let count = 0;
39// REFACTORING: Improved header parsing with clearer logic and variable names
40function parseHeaderLine(markdown, isCurrentlyInList) {
41 // Count consecutive # characters at the start of the line
42 let headerLevel = 0;
3443 for (let i = 0; i < markdown.length; i++) {
3544 if (markdown[i] === '#') {
36 count += 1;
45 headerLevel += 1;
3746 } else {
3847 break;
3948 }
4049 }
41 if (count === 0 || count > 6) {
42 return [null, list];
50
51 // Valid headers have 1-6 # characters
52 if (headerLevel === 0 || headerLevel > 6) {
53 return [null, isCurrentlyInList];
4354 }
44 const headerTag = `h${count}`;
45 const headerHtml = wrap(markdown.substring(count + 1), headerTag);
46 if (list) {
55
56 // Extract header content (skip the # characters and the following space)
57 const headerContent = markdown.substring(headerLevel + 1);
58 const headerTag = `h${headerLevel}`;
59 const headerHtml = wrapTextInTag(headerContent, headerTag);
60
61 // If we were in a list, close it before starting the header
62 if (isCurrentlyInList) {
4763 return [`</ul>${headerHtml}`, false];
4864 } else {
4965 return [headerHtml, false];
5066 }
5167}
5268
53function parseLineItem(markdown, list) {
69// REFACTORING: Improved list item parsing with clearer logic and naming
70function parseListItem(markdown, isCurrentlyInList) {
71 // List items start with '* '
5472 if (markdown.startsWith('*')) {
55 const innerHtml = wrap(parseText(markdown.substring(2), true), 'li');
56 if (list) {
57 return [innerHtml, true];
73 // Extract the list item content (skip '* ')
74 const itemContent = markdown.substring(2);
75 // Parse the content and wrap in list item tags
76 const listItemHtml = wrapTextInTag(parseTextContent(itemContent, true), 'li');
77
78 if (isCurrentlyInList) {
79 // Already in a list, just add the item
80 return [listItemHtml, true];
5881 } else {
59 return [`<ul>${innerHtml}`, true];
82 // Starting a new list, open ul tag
83 return [`<ul>${listItemHtml}`, true];
6084 }
6185 }
62 return [null, list];
86
87 // Not a list item
88 return [null, isCurrentlyInList];
6389}
6490
65function parseParagraph(markdown, list) {
66 if (!list) {
67 return [parseText(markdown, false), false];
91// REFACTORING: Improved paragraph parsing with clearer logic
92function parseParagraphLine(markdown, isCurrentlyInList) {
93 if (!isCurrentlyInList) {
94 // Not in a list, parse as regular paragraph
95 return [parseTextContent(markdown, false), false];
6896 } else {
69 return [`</ul>${parseText(markdown, false)}`, false];
97 // Was in a list, close it and start a new paragraph
98 return [`</ul>${parseTextContent(markdown, false)}`, false];
7099 }
71100}
72101
73function parseLine(markdown, list) {
74 let [result, inListAfter] = parseHeader(markdown, list);
102// REFACTORING: Improved line parsing with clearer logic flow
103function parseMarkdownLine(markdown, isCurrentlyInList) {
104 // Try to parse as header first
105 let [result, newListState] = parseHeaderLine(markdown, isCurrentlyInList);
106
107 // If not a header, try to parse as list item
75108 if (result === null) {
76 [result, inListAfter] = parseLineItem(markdown, list);
109 [result, newListState] = parseListItem(markdown, isCurrentlyInList);
77110 }
111
112 // If neither header nor list item, parse as paragraph
78113 if (result === null) {
79 [result, inListAfter] = parseParagraph(markdown, list);
114 [result, newListState] = parseParagraphLine(markdown, isCurrentlyInList);
80115 }
116
117 // This should never happen with valid markdown
81118 if (result === null) {
82 throw new Error('Remove this line and implement the function');
119 throw new Error('Unable to parse markdown line: ' + markdown);
83120 }
84 return [result, inListAfter];
121
122 return [result, newListState];
85123}
86124
87125/**
88 * @param {string} markdown
89 * @returns {string}
126 * Parse markdown text and convert it to HTML
127 * @param {string} markdown - The markdown text to parse
128 * @returns {string} - The resulting HTML
90129 */
91130export function parse(markdown) {
131 // Split the markdown into individual lines
92132 const lines = markdown.split('\n');
93 let result = '';
94 let list = false;
133 let htmlResult = '';
134 let isInList = false; // Track if we're currently inside a list
135
136 // Process each line of markdown
95137 for (let i = 0; i < lines.length; i++) {
96 let [lineResult, newList] = parseLine(lines[i], list);
97 result += lineResult;
98 list = newList;
138 // Parse the current line and get the HTML result and updated list state
139 let [lineHtml, updatedListState] = parseMarkdownLine(lines[i], isInList);
140 htmlResult += lineHtml;
141 isInList = updatedListState;
99142 }
100 if (list) {
101 return result + '</ul>';
143
144 // If we're still in a list at the end, close it
145 if (isInList) {
146 return htmlResult + '</ul>';
102147 } else {
103 return result;
148 return htmlResult;
104149 }
105150}
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.