seahawk

Finished
1// REFACTORING SUMMARY:
2// This markdown parser has been refactored to improve readability and maintainability:
3// 1. Renamed functions with descriptive names:
4// - parse__ -> parseStrongText (bold text with __)
5// - parse_ -> parseEmphasizedText (italic text with _)
6// - parseText -> parseInlineText (handles inline formatting)
7// - parseHeader -> parseHeaderLine (parses # headers)
8// - parseLineItem -> parseListItem (parses * list items)
9// - parseParagraph -> parseParagraphLine (parses regular paragraphs)
10// - parseLine -> parseMarkdownLine (main line parser)
11// 2. Added comprehensive JSDoc documentation for all functions
12// 3. Improved code organization with logical grouping
13// 4. Added explanatory comments for complex logic
14// 5. Maintained exact functionality while improving readability
15
16// REFACTORING: Utility functions for HTML tag manipulation
17
18/**
19 * Wraps text in an HTML tag
20 * @param {string} text - The text to wrap
21 * @param {string} tag - The HTML tag name
22 * @returns {string} The wrapped text
23 */
124function wrap(text, tag) {
225 return `<${tag}>${text}</${tag}>`;
326}
427
28/**
29 * Checks if text starts with a specific HTML tag
30 * @param {string} text - The text to check
31 * @param {string} tag - The HTML tag name
32 * @returns {boolean} True if text starts with the tag
33 */
534function isTag(text, tag) {
635 return text.startsWith(`<${tag}>`);
736}
837
38/**
39 * Generic parser for markdown delimiters (emphasis, strong, etc.)
40 * @param {string} markdown - The markdown text to parse
41 * @param {string} delimiter - The delimiter pattern (e.g., '_' or '__')
42 * @param {string} tag - The HTML tag to replace with (e.g., 'em' or 'strong')
43 * @returns {string} The parsed HTML
44 */
945function parser(markdown, delimiter, tag) {
1046 const pattern = new RegExp(`${delimiter}(.+)${delimiter}`);
1147 const replacement = `<${tag}>$1</${tag}>`;
1248 return markdown.replace(pattern, replacement);
1349}
1450
15function parse__(markdown) {
51/**
52 * Parses strong (bold) text marked with double underscores
53 * @param {string} markdown - The markdown text to parse
54 * @returns {string} The parsed HTML with strong tags
55 */
56function parseStrongText(markdown) {
1657 return parser(markdown, '__', 'strong');
1758}
1859
19function parse_(markdown) {
60/**
61 * Parses emphasized (italic) text marked with single underscores
62 * @param {string} markdown - The markdown text to parse
63 * @returns {string} The parsed HTML with em tags
64 */
65function parseEmphasizedText(markdown) {
2066 return parser(markdown, '_', 'em');
2167}
2268
23function parseText(markdown, list) {
24 const parsedText = parse_(parse__(markdown));
69/**
70 * Parses inline markdown elements (emphasis, strong) and wraps in paragraph tags if not in a list
71 * @param {string} markdown - The markdown text to parse
72 * @param {boolean} list - Whether we're currently in a list context
73 * @returns {string} The parsed HTML
74 */
75function parseInlineText(markdown, list) {
76 const parsedText = parseEmphasizedText(parseStrongText(markdown));
2577 if (list) {
2678 return parsedText;
2779 } else {
2981 }
3082}
3183
32function parseHeader(markdown, list) {
84/**
85 * Parses header markdown (lines starting with #)
86 * @param {string} markdown - The markdown line to parse
87 * @param {boolean} list - Whether we're currently in a list context
88 * @returns {[string|null, boolean]} Tuple of [parsed HTML or null, new list state]
89 */
90function parseHeaderLine(markdown, list) {
3391 let count = 0;
3492 for (let i = 0; i < markdown.length; i++) {
3593 if (markdown[i] === '#') {
50108 }
51109}
52110
53function parseLineItem(markdown, list) {
111/**
112 * Parses list item markdown (lines starting with *)
113 * @param {string} markdown - The markdown line to parse
114 * @param {boolean} list - Whether we're currently in a list context
115 * @returns {[string|null, boolean]} Tuple of [parsed HTML or null, new list state]
116 */
117function parseListItem(markdown, list) {
54118 if (markdown.startsWith('*')) {
55 const innerHtml = wrap(parseText(markdown.substring(2), true), 'li');
119 const innerHtml = wrap(parseInlineText(markdown.substring(2), true), 'li');
56120 if (list) {
57121 return [innerHtml, true];
58122 } else {
62126 return [null, list];
63127}
64128
65function parseParagraph(markdown, list) {
129/**
130 * Parses paragraph markdown (regular text lines)
131 * @param {string} markdown - The markdown line to parse
132 * @param {boolean} list - Whether we're currently in a list context
133 * @returns {[string, boolean]} Tuple of [parsed HTML, new list state]
134 */
135function parseParagraphLine(markdown, list) {
66136 if (!list) {
67 return [parseText(markdown, false), false];
137 return [parseInlineText(markdown, false), false];
68138 } else {
69 return [`</ul>${parseText(markdown, false)}`, false];
139 return [`</ul>${parseInlineText(markdown, false)}`, false];
70140 }
71141}
72142
73function parseLine(markdown, list) {
74 let [result, inListAfter] = parseHeader(markdown, list);
143/**
144 * Parses a single line of markdown by trying different parsers in order
145 * @param {string} markdown - The markdown line to parse
146 * @param {boolean} list - Whether we're currently in a list context
147 * @returns {[string, boolean]} Tuple of [parsed HTML, new list state]
148 */
149function parseMarkdownLine(markdown, list) {
150 let [result, inListAfter] = parseHeaderLine(markdown, list);
75151 if (result === null) {
76 [result, inListAfter] = parseLineItem(markdown, list);
152 [result, inListAfter] = parseListItem(markdown, list);
77153 }
78154 if (result === null) {
79 [result, inListAfter] = parseParagraph(markdown, list);
155 [result, inListAfter] = parseParagraphLine(markdown, list);
80156 }
81157 if (result === null) {
82158 throw new Error('Remove this line and implement the function');
85161}
86162
87163/**
88 * @param {string} markdown
89 * @returns {string}
164 * Main markdown parser function - converts markdown string to HTML
165 * REFACTORING: This is the main entry point that orchestrates the parsing process
166 * @param {string} markdown - The markdown string to parse
167 * @returns {string} The resulting HTML
90168 */
91169export function parse(markdown) {
92170 const lines = markdown.split('\n');
93171 let result = '';
94172 let list = false;
173
174 // Process each line, maintaining list state across lines
95175 for (let i = 0; i < lines.length; i++) {
96 let [lineResult, newList] = parseLine(lines[i], list);
176 let [lineResult, newList] = parseMarkdownLine(lines[i], list);
97177 result += lineResult;
98178 list = newList;
99179 }
180
181 // Close any unclosed list
100182 if (list) {
101183 return result + '</ul>';
102184 } else {
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.