const md2tokens = (markdown, newline) => { // Simple lexer and parser let i = 0; let current_string = ""; newline = newline == null ? true : newline; let newline_count = newline ? 1 : 0; let tokens = []; let match = (c) => { if (c == markdown[i]) { i++; return true; } return false; } let advance = () => { i++; if (i < markdown.length) return true return false } let capture_until = (c) => { let capture = ""; while (markdown[i] != c && markdown.length > i) { capture += markdown[i]; i++; } return capture; } let finish = (type) => { if (current_string.trim().length == 0) { current_string = ""; return; } tokens.push({ type: type == null ? "span" : type, content: current_string }) current_string = ""; } let def = () => { current_string += markdown[i]; newline = false; newline_count = 0; } while (i < markdown.length) { switch (markdown[i]) { case '\\': i++; current_string += markdown[i]; break; case '*': finish(); advance(); let depth_em = 1; let type = "em"; if (match("*")) { type = "bold"; depth_em = 2; } let found_match = () => { for (let j = 0; j < depth_em; j++) { if (markdown[i + j] != "*") return false } return true } while (!found_match()) { current_string += markdown[i]; if (!advance()) break; } advance(); finish(type); break; case "#": if (!newline) { def(); break; } finish(); let depth_he = 0; do { depth_he++; } while (match("#")); while (markdown[i] != "\n" && markdown.length > i) { current_string += markdown[i]; i++ } tokens.push({ type: "header", level: depth_he, content: current_string }); current_string = ""; break; case '!': if (markdown[i + 1] != "[") { def(); break; } finish(); advance(); advance(); let alt_text = capture_until("]"); advance(); if (!match("(")) { current_string = `![${alt_text}]`; def(); break; } let url = capture_until("\""); advance(); let title = capture_until("\""); advance(); if (!match(")")) { current_string = `![${alt_text}](${url} "${title}"`; def(); break; } tokens.push({type:"image", alt: alt_text, url: url, title: title}) break; case '-': if (!newline) { def(); break; } let items = []; advance(); do { let text = capture_until("\n"); advance(); items.push(md2tokens(text, false)); } while (match("-")); tokens.push({type:"ul", items: items}); break; case '\n': if (newline_count > 2) break; newline = true; newline_count++; finish(); tokens.push({ type: "newline" }) break; case '`': finish(); advance(); current_string = capture_until("`"); finish("inlinecode"); break; default: def() } i++; } finish(); console.log(tokens); return tokens; }; const tokens2html = (tokens) => { let output = ""; for (let token of tokens) { switch (token.type) { case "span": output += `${token.content}`; break case "bold": output += `${token.content}` break; case "em": output += `${token.content}` break; case "header": output += `${token.content}` break; case "newline": output += "
" break; case "image": output += `

${token.alt}

`; break case "ul": console.log(token); output += ""; break; case "inlinecode": output += `${token.content}`; break; } } return output; }