api

Finished
1// Helper utility functions
12function wrap(text, tag) {
23 return `<${tag}>${text}</${tag}>`;
34}
67 return text.startsWith(`<${tag}>`);
78}
89
9function parser(markdown, delimiter, tag) {
10// Emphasis parsing with clearer function names
11function parseEmphasis(markdown, delimiter, tag) {
1012 const pattern = new RegExp(`${delimiter}(.+)${delimiter}`);
1113 const replacement = `<${tag}>$1</${tag}>`;
1214 return markdown.replace(pattern, replacement);
1315}
1416
15function parse__(markdown) {
16 return parser(markdown, '__', 'strong');
17// Parse bold text (__bold__) - renamed from parse__
18function parseBold(markdown) {
19 return parseEmphasis(markdown, '__', 'strong');
1720}
1821
19function parse_(markdown) {
20 return parser(markdown, '_', 'em');
22// Parse italic text (_italic_) - renamed from parse_
23function parseItalic(markdown) {
24 return parseEmphasis(markdown, '_', 'em');
2125}
2226
23function parseText(markdown, list) {
24 const parsedText = parse_(parse__(markdown));
25 if (list) {
27// Parse inline formatting (bold and italic) in text
28function parseInlineFormatting(markdown, isListItem) {
29 const parsedText = parseItalic(parseBold(markdown));
30 if (isListItem) {
2631 return parsedText;
2732 } else {
2833 return wrap(parsedText, 'p');
2934 }
3035}
3136
32function parseHeader(markdown, list) {
33 let count = 0;
37// Header parsing with improved clarity
38function parseHeader(markdown, isInList) {
39 let headerLevel = 0;
40
41 // Count leading # characters to determine header level
3442 for (let i = 0; i < markdown.length; i++) {
3543 if (markdown[i] === '#') {
36 count += 1;
44 headerLevel += 1;
3745 } else {
3846 break;
3947 }
4048 }
41 if (count === 0 || count > 6) {
42 return [null, list];
49
50 // Only process if we have a valid header (1-6 levels)
51 if (headerLevel === 0 || headerLevel > 6) {
52 return [null, isInList];
4353 }
44 const headerTag = `h${count}`;
45 const headerHtml = wrap(markdown.substring(count + 1), headerTag);
46 if (list) {
54
55 const headerTag = `h${headerLevel}`;
56 const headerContent = markdown.substring(headerLevel + 1).trim();
57 const headerHtml = wrap(headerContent, headerTag);
58
59 // Close any open list before starting header
60 if (isInList) {
4761 return [`</ul>${headerHtml}`, false];
4862 } else {
4963 return [headerHtml, false];
5064 }
5165}
5266
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 }
67// List item parsing with better state management
68function parseListItem(markdown, isInList) {
69 if (!markdown.startsWith('*')) {
70 return [null, isInList];
71 }
72
73 const itemContent = markdown.substring(2).trim();
74 const listItemHtml = wrap(parseInlineFormatting(itemContent, true), 'li');
75
76 if (isInList) {
77 return [listItemHtml, true];
78 } else {
79 return [`<ul>${listItemHtml}`, true];
6180 }
62 return [null, list];
6381}
6482
65function parseParagraph(markdown, list) {
66 if (!list) {
67 return [parseText(markdown, false), false];
83// Paragraph parsing with cleaner list handling
84function parseParagraph(markdown, isInList) {
85 const paragraphHtml = parseInlineFormatting(markdown, false);
86
87 if (isInList) {
88 return [`</ul>${paragraphHtml}`, false];
6889 } else {
69 return [`</ul>${parseText(markdown, false)}`, false];
90 return [paragraphHtml, false];
7091 }
7192}
7293
73function parseLine(markdown, list) {
74 let [result, inListAfter] = parseHeader(markdown, list);
75 if (result === null) {
76 [result, inListAfter] = parseLineItem(markdown, list);
94// Line parsing using strategy pattern for better organization
95function parseLine(markdown, isInList) {
96 // Try parsing as header first
97 let [result, newListState] = parseHeader(markdown, isInList);
98 if (result !== null) {
99 return [result, newListState];
77100 }
78 if (result === null) {
79 [result, inListAfter] = parseParagraph(markdown, list);
101
102 // Try parsing as list item
103 [result, newListState] = parseListItem(markdown, isInList);
104 if (result !== null) {
105 return [result, newListState];
80106 }
81 if (result === null) {
82 throw new Error('Remove this line and implement the function');
107
108 // Default to paragraph
109 [result, newListState] = parseParagraph(markdown, isInList);
110 if (result !== null) {
111 return [result, newListState];
83112 }
84 return [result, inListAfter];
113
114 // This should never happen with valid markdown
115 throw new Error('Unable to parse markdown line');
85116}
86117
87118/**
88 * @param {string} markdown
89 * @returns {string}
119 * Main markdown parser function
120 * @param {string} markdown - The markdown string to parse
121 * @returns {string} - The resulting HTML
90122 */
91123export function parse(markdown) {
92124 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;
125 let htmlResult = '';
126 let isInList = false;
127
128 // Process each line of markdown
129 for (const line of lines) {
130 const [lineHtml, newInListState] = parseLine(line, isInList);
131 htmlResult += lineHtml;
132 isInList = newInListState;
99133 }
100 if (list) {
101 return result + '</ul>';
134
135 // Close any unclosed list at the end
136 if (isInList) {
137 return htmlResult + '</ul>';
102138 } else {
103 return result;
139 return htmlResult;
104140 }
105141}
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.