Mercurial
diff markdown_converter/markdown_to_html.js @ 64:a30944e5719e
Added vibe coded markdown to html script since it is useful for me. Updated Dowa so that it can be compiled without dirnet for windows.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Tue, 23 Dec 2025 15:18:46 -0800 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/markdown_converter/markdown_to_html.js Tue Dec 23 15:18:46 2025 -0800 @@ -0,0 +1,269 @@ +/** + * Simple Markdown to HTML Converter + * Supports: headers, bold, italic, links, lists, code blocks, line breaks + */ + +/** + * Create heading element (H1-H6) + * @param {string} text - The heading text + * @param {number} level - Heading level (1-6) + * @returns {HTMLElement} + */ +function createHeadingElement(text, level) { + const h = document.createElement(`H${level}`); + const t = document.createTextNode(text.trim()); + h.appendChild(t); + return h; +} + +/** + * Create paragraph element + * @param {string} text - The paragraph text + * @returns {HTMLElement} + */ +function createParagraphElement(text) { + const p = document.createElement("P"); + p.innerHTML = processInlineMarkdown(text.trim()); + return p; +} + +/** + * Create link element + * @param {string} text - Link text + * @param {string} url - Link URL + * @returns {HTMLElement} + */ +function createLinkElement(text, url) { + const a = document.createElement("A"); + a.href = url; + a.textContent = text; + return a; +} + +/** + * Create unordered list element + * @param {Array<string>} items - List items + * @returns {HTMLElement} + */ +function createUnorderedList(items) { + const ul = document.createElement("UL"); + items.forEach(item => { + const li = document.createElement("LI"); + li.innerHTML = processInlineMarkdown(item.trim()); + ul.appendChild(li); + }); + return ul; +} + +/** + * Create ordered list element + * @param {Array<string>} items - List items + * @returns {HTMLElement} + */ +function createOrderedList(items) { + const ol = document.createElement("OL"); + items.forEach(item => { + const li = document.createElement("LI"); + li.innerHTML = processInlineMarkdown(item.trim()); + ol.appendChild(li); + }); + return ol; +} + +/** + * Create code block element + * @param {string} code - Code content + * @returns {HTMLElement} + */ +function createCodeBlock(code) { + const pre = document.createElement("PRE"); + const codeEl = document.createElement("CODE"); + codeEl.textContent = code; + pre.appendChild(codeEl); + return pre; +} + +/** + * Create blockquote element + * @param {string} text - Quote text + * @returns {HTMLElement} + */ +function createBlockquote(text) { + const blockquote = document.createElement("BLOCKQUOTE"); + blockquote.innerHTML = processInlineMarkdown(text.trim()); + return blockquote; +} + +/** + * Create horizontal rule + * @returns {HTMLElement} + */ +function createHorizontalRule() { + return document.createElement("HR"); +} + +/** + * Process inline markdown (bold, italic, code, links) + * @param {string} text - Text with inline markdown + * @returns {string} HTML string + */ +function processInlineMarkdown(text) { + // Links: [text](url) + text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>'); + + // Images:  + text = text.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">'); + + // Bold: **text** or __text__ + text = text.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>'); + text = text.replace(/__([^_]+)__/g, '<strong>$1</strong>'); + + // Italic: *text* or _text_ + text = text.replace(/\*([^*]+)\*/g, '<em>$1</em>'); + text = text.replace(/_([^_]+)_/g, '<em>$1</em>'); + + // Inline code: `code` + const x = /`([^`]+)`/g; + text = text.replace(x, '<code>$1</code>'); + + // Strikethrough: ~~text~~ + text = text.replace(/~~([^~]+)~~/g, '<del>$1</del>'); + + // Line breaks: two spaces at end of line + text = text.replace(/ \n/g, '<br>\n'); + + return text; +} + +/** + * Main markdown converter function + * @param {string} value - Markdown string + * @returns {Array<HTMLElement>} Array of DOM elements + */ +function markdownConverter(value) { + const lines = value.split('\n'); + const domElements = []; + let i = 0; + + while (i < lines.length) { + const line = lines[i]; + const trimmedLine = line.trim(); + + // Skip empty lines + if (trimmedLine === '') { + i++; + continue; + } + + if (trimmedLine.startsWith('#')) + { + const match = trimmedLine.match(/^(#{1,6})\s+(.+)$/); + if (match) { + const level = match[1].length; + const text = match[2]; + domElements.push(createHeadingElement(text, level)); + i++; + continue; + } + } + + if (trimmedLine.startsWith('```')) { + let codeContent = ''; + i++; // Skip opening ``` + while (i < lines.length && !lines[i].trim().startsWith('```')) { + codeContent += lines[i] + '\n'; + i++; + } + domElements.push(createCodeBlock(codeContent)); + i++; // Skip closing ``` + continue; + } + + // Blockquote: > + if (trimmedLine.startsWith('>')) { + let quoteContent = ''; + while (i < lines.length && lines[i].trim().startsWith('>')) { + quoteContent += lines[i].trim().substring(1).trim() + ' '; + i++; + } + domElements.push(createBlockquote(quoteContent)); + continue; + } + + // Horizontal rule: ---, ***, ___ + if (trimmedLine.match(/^(-{3,}|\*{3,}|_{3,})$/)) { + domElements.push(createHorizontalRule()); + i++; + continue; + } + + // Unordered list: -, *, + + if (trimmedLine.match(/^[-*+]\s+/)) { + const listItems = []; + while (i < lines.length && lines[i].trim().match(/^[-*+]\s+/)) { + listItems.push(lines[i].trim().substring(2)); + i++; + } + domElements.push(createUnorderedList(listItems)); + continue; + } + + // Ordered list: 1., 2., etc. + if (trimmedLine.match(/^\d+\.\s+/)) { + const listItems = []; + while (i < lines.length && lines[i].trim().match(/^\d+\.\s+/)) { + listItems.push(lines[i].trim().replace(/^\d+\.\s+/, '')); + i++; + } + domElements.push(createOrderedList(listItems)); + continue; + } + + // Regular paragraph + let paragraphContent = ''; + while (i < lines.length && lines[i].trim() !== '' && + !lines[i].trim().match(/^(#{1,6}\s|[-*+]\s|\d+\.\s|>|```|---|\*\*\*|___)/)) { + paragraphContent += lines[i] + ' '; + i++; + } + if (paragraphContent.trim()) { + domElements.push(createParagraphElement(paragraphContent)); + } + } + + return domElements; +} + +/** + * Helper function to append all elements to a container + * @param {HTMLElement} container - Container element + * @param {string} markdown - Markdown string + */ +function renderMarkdown(container, markdown) { + const elements = markdownConverter(markdown); + elements.forEach(el => container.appendChild(el)); +} + +// Example usage: +// const markdown = ` +// # Heading 1 +// ## Heading 2 +// +// This is a paragraph with **bold** and *italic* text. +// +// - List item 1 +// - List item 2 +// +// 1. Ordered item 1 +// 2. Ordered item 2 +// +// [Link text](https://example.com) +// `; +// +// const container = document.getElementById('content'); +// renderMarkdown(container, markdown); + +// Export for use in other files +if (typeof module !== 'undefined' && module.exports) { + module.exports = { markdownConverter, renderMarkdown }; +}