// Please do not edit this file. It has been generated automatically // from `src/module/markdown.wren` using `util/wren_to_c_string.py` static const char* markdownModuleSource = "// retoor \n" "\n" "import \"html\" for Html\n" "\n" "class Markdown {\n" " static toHtml(text) { toHtml(text, {}) }\n" "\n" " static toHtml(text, options) {\n" " var safeMode = options.containsKey(\"safeMode\") ? options[\"safeMode\"] : false\n" " var lines = text.split(\"\\n\")\n" " var result = []\n" " var inCodeBlock = false\n" " var codeBlockContent = []\n" " var inList = false\n" " var listType = null\n" " var inBlockquote = false\n" "\n" " for (i in 0...lines.count) {\n" " var line = lines[i]\n" "\n" " if (line.startsWith(\"```\")) {\n" " if (inCodeBlock) {\n" " result.add(\"
\" + (safeMode ? Html.quote(codeBlockContent.join(\"\\n\")) : codeBlockContent.join(\"\\n\")) + \"
\")\n" " codeBlockContent = []\n" " inCodeBlock = false\n" " } else {\n" " closeList_(result, inList, listType)\n" " inList = false\n" " inCodeBlock = true\n" " }\n" " continue\n" " }\n" "\n" " if (inCodeBlock) {\n" " codeBlockContent.add(line)\n" " continue\n" " }\n" "\n" " if (line.count == 0) {\n" " closeList_(result, inList, listType)\n" " inList = false\n" " if (inBlockquote) {\n" " result.add(\"\")\n" " inBlockquote = false\n" " }\n" " continue\n" " }\n" "\n" " if (line.startsWith(\"> \")) {\n" " closeList_(result, inList, listType)\n" " inList = false\n" " if (!inBlockquote) {\n" " result.add(\"
\")\n" " inBlockquote = true\n" " }\n" " result.add(\"

\" + processInline_(line[2..-1], safeMode) + \"

\")\n" " continue\n" " }\n" "\n" " if (line.startsWith(\"---\") || line.startsWith(\"***\") || line.startsWith(\"___\")) {\n" " var isHr = true\n" " for (c in line) {\n" " if (c != \"-\" && c != \"*\" && c != \"_\" && c != \" \") {\n" " isHr = false\n" " break\n" " }\n" " }\n" " if (isHr && line.count >= 3) {\n" " closeList_(result, inList, listType)\n" " inList = false\n" " result.add(\"
\")\n" " continue\n" " }\n" " }\n" "\n" " var heading = parseHeading_(line)\n" " if (heading) {\n" " closeList_(result, inList, listType)\n" " inList = false\n" " result.add(\"\" + processInline_(heading[\"text\"], safeMode) + \"\")\n" " continue\n" " }\n" "\n" " var listItem = parseListItem_(line)\n" " if (listItem) {\n" " var newType = listItem[\"type\"]\n" " if (!inList || listType != newType) {\n" " closeList_(result, inList, listType)\n" " result.add(newType == \"ul\" ? \"
\")\n" " }\n" " if (inCodeBlock) {\n" " result.add(\"
\" + (safeMode ? Html.quote(codeBlockContent.join(\"\\n\")) : codeBlockContent.join(\"\\n\")) + \"
\")\n" " }\n" "\n" " return result.join(\"\\n\")\n" " }\n" "\n" " static closeList_(result, inList, listType) {\n" " if (inList) {\n" " result.add(listType == \"ul\" ? \"\" : \"\")\n" " }\n" " }\n" "\n" " static parseHeading_(line) {\n" " var level = 0\n" " for (c in line) {\n" " if (c == \"#\") {\n" " level = level + 1\n" " } else {\n" " break\n" " }\n" " }\n" " if (level > 0 && level <= 6 && line.count > level && line[level] == \" \") {\n" " return {\"level\": level, \"text\": line[level + 1..-1]}\n" " }\n" " return null\n" " }\n" "\n" " static parseListItem_(line) {\n" " var trimmed = line\n" " var indent = 0\n" " while (trimmed.count > 0 && trimmed[0] == \" \") {\n" " trimmed = trimmed[1..-1]\n" " indent = indent + 1\n" " }\n" "\n" " if (trimmed.count >= 2 && (trimmed[0] == \"-\" || trimmed[0] == \"*\" || trimmed[0] == \"+\") && trimmed[1] == \" \") {\n" " return {\"type\": \"ul\", \"text\": trimmed[2..-1]}\n" " }\n" "\n" " var i = 0\n" " while (i < trimmed.count) {\n" " var c = trimmed[i].codePoints.toList[0]\n" " if (c < 48 || c > 57) break\n" " i = i + 1\n" " }\n" " if (i > 0 && i < trimmed.count - 1 && trimmed[i] == \".\" && trimmed[i + 1] == \" \") {\n" " return {\"type\": \"ol\", \"text\": trimmed[i + 2..-1]}\n" " }\n" "\n" " return null\n" " }\n" "\n" " static processInline_(text, safeMode) {\n" " if (safeMode) text = Html.quote(text)\n" " text = processCode_(text)\n" " text = processBold_(text)\n" " text = processItalic_(text)\n" " text = processStrikethrough_(text)\n" " text = processImages_(text)\n" " text = processLinks_(text)\n" " return text\n" " }\n" "\n" " static processCode_(text) {\n" " var result = \"\"\n" " var i = 0\n" " var chars = text.toList\n" " while (i < chars.count) {\n" " if (chars[i] == \"`\") {\n" " var end = i + 1\n" " while (end < chars.count && chars[end] != \"`\") {\n" " end = end + 1\n" " }\n" " if (end < chars.count) {\n" " var code = \"\"\n" " for (j in (i + 1)...end) {\n" " code = code + chars[j]\n" " }\n" " result = result + \"\" + code + \"\"\n" " i = end + 1\n" " } else {\n" " result = result + chars[i]\n" " i = i + 1\n" " }\n" " } else {\n" " result = result + chars[i]\n" " i = i + 1\n" " }\n" " }\n" " return result\n" " }\n" "\n" " static processBold_(text) {\n" " var result = text\n" " while (result.contains(\"**\")) {\n" " var start = result.indexOf(\"**\")\n" " var rest = result[start + 2..-1]\n" " var end = rest.indexOf(\"**\")\n" " if (end >= 0) {\n" " var before = result[0...start]\n" " var content = rest[0...end]\n" " var after = rest[end + 2..-1]\n" " result = before + \"\" + content + \"\" + after\n" " } else {\n" " break\n" " }\n" " }\n" " while (result.contains(\"__\")) {\n" " var start = result.indexOf(\"__\")\n" " var rest = result[start + 2..-1]\n" " var end = rest.indexOf(\"__\")\n" " if (end >= 0) {\n" " var before = result[0...start]\n" " var content = rest[0...end]\n" " var after = rest[end + 2..-1]\n" " result = before + \"\" + content + \"\" + after\n" " } else {\n" " break\n" " }\n" " }\n" " return result\n" " }\n" "\n" " static processItalic_(text) {\n" " var result = text\n" " while (result.contains(\"*\")) {\n" " var start = result.indexOf(\"*\")\n" " if (start > 0 && result[start - 1] == \"<\") {\n" " break\n" " }\n" " var rest = result[start + 1..-1]\n" " var end = rest.indexOf(\"*\")\n" " if (end >= 0 && end > 0) {\n" " var before = result[0...start]\n" " var content = rest[0...end]\n" " var after = rest[end + 1..-1]\n" " result = before + \"\" + content + \"\" + after\n" " } else {\n" " break\n" " }\n" " }\n" " return result\n" " }\n" "\n" " static processStrikethrough_(text) {\n" " var result = text\n" " while (result.contains(\"~~\")) {\n" " var start = result.indexOf(\"~~\")\n" " var rest = result[start + 2..-1]\n" " var end = rest.indexOf(\"~~\")\n" " if (end >= 0) {\n" " var before = result[0...start]\n" " var content = rest[0...end]\n" " var after = rest[end + 2..-1]\n" " result = before + \"\" + content + \"\" + after\n" " } else {\n" " break\n" " }\n" " }\n" " return result\n" " }\n" "\n" " static processLinks_(text) {\n" " var result = text\n" " while (result.contains(\"](\")) {\n" " var linkEnd = result.indexOf(\"](\")\n" " var textStart = linkEnd\n" " while (textStart > 0 && result[textStart - 1] != \"[\") {\n" " textStart = textStart - 1\n" " }\n" " if (textStart > 0 && result[textStart - 1] == \"[\") {\n" " var urlStart = linkEnd + 2\n" " var urlEnd = urlStart\n" " while (urlEnd < result.count && result[urlEnd] != \")\") {\n" " urlEnd = urlEnd + 1\n" " }\n" " if (urlEnd < result.count) {\n" " var before = result[0...textStart - 1]\n" " var linkText = result[textStart...linkEnd]\n" " var url = result[urlStart...urlEnd]\n" " var after = result[urlEnd + 1..-1]\n" " result = before + \"\" + linkText + \"\" + after\n" " } else {\n" " break\n" " }\n" " } else {\n" " break\n" " }\n" " }\n" " return result\n" " }\n" "\n" " static processImages_(text) {\n" " var result = text\n" " while (result.contains(\"![\")) {\n" " var start = result.indexOf(\"![\")\n" " var altEnd = start + 2\n" " while (altEnd < result.count && result[altEnd] != \"]\") {\n" " altEnd = altEnd + 1\n" " }\n" " if (altEnd < result.count && altEnd + 1 < result.count && result[altEnd + 1] == \"(\") {\n" " var urlStart = altEnd + 2\n" " var urlEnd = urlStart\n" " while (urlEnd < result.count && result[urlEnd] != \")\") {\n" " urlEnd = urlEnd + 1\n" " }\n" " if (urlEnd < result.count) {\n" " var before = result[0...start]\n" " var alt = result[start + 2...altEnd]\n" " var url = result[urlStart...urlEnd]\n" " var after = result[urlEnd + 1..-1]\n" " result = before + \"\\\"\"\" + after\n" " } else {\n" " break\n" " }\n" " } else {\n" " break\n" " }\n" " }\n" " return result\n" " }\n" "\n" " static fromHtml(html) { fromHtml(html, {}) }\n" "\n" " static fromHtml(html, options) {\n" " var stripUnknown = options.containsKey(\"stripUnknown\") ? options[\"stripUnknown\"] : true\n" " var text = html\n" "\n" " text = removeHiddenTags_(text)\n" " text = processBlockElements_(text)\n" " text = processInlineFromHtml_(text)\n" " text = Html.unquote(text)\n" " text = cleanupWhitespace_(text)\n" "\n" " return text.trim()\n" " }\n" "\n" " static removeHiddenTags_(html) {\n" " var result = html\n" " var tags = [\"script\", \"style\", \"head\", \"meta\", \"link\", \"noscript\"]\n" " for (tag in tags) {\n" " result = removeTagWithContent_(result, tag)\n" " }\n" " return result\n" " }\n" "\n" " static removeTagWithContent_(html, tag) {\n" " var result = html\n" " var openTag = \"<\" + tag\n" " var closeTag = \"\"\n" " while (true) {\n" " var startLower = result.indexOf(openTag)\n" " var startUpper = result.indexOf(\"<\" + tag[0].codePoints.toList[0].toString)\n" " var start = -1\n" "\n" " var i = 0\n" " while (i < result.count - openTag.count) {\n" " if (matchTagName_(result, i, tag)) {\n" " start = i\n" " break\n" " }\n" " i = i + 1\n" " }\n" "\n" " if (start < 0) break\n" "\n" " var tagEnd = start\n" " while (tagEnd < result.count && result[tagEnd] != \">\") {\n" " tagEnd = tagEnd + 1\n" " }\n" " if (tagEnd >= result.count) break\n" "\n" " if (result[tagEnd - 1] == \"/\") {\n" " result = result[0...start] + result[tagEnd + 1..-1]\n" " continue\n" " }\n" "\n" " var closeStart = findCloseTag_(result, tagEnd + 1, tag)\n" " if (closeStart < 0) {\n" " result = result[0...start] + result[tagEnd + 1..-1]\n" " } else {\n" " var closeEnd = closeStart\n" " while (closeEnd < result.count && result[closeEnd] != \">\") {\n" " closeEnd = closeEnd + 1\n" " }\n" " result = result[0...start] + result[closeEnd + 1..-1]\n" " }\n" " }\n" " return result\n" " }\n" "\n" " static matchTagName_(html, pos, tag) {\n" " if (pos >= html.count || html[pos] != \"<\") return false\n" " var rest = html[pos + 1..-1].trim()\n" " var tagLower = tag\n" " for (i in 0...tag.count) {\n" " if (i >= rest.count) return false\n" " var c1 = rest[i].codePoints.toList[0]\n" " var c2 = tag[i].codePoints.toList[0]\n" " if (c1 >= 65 && c1 <= 90) c1 = c1 + 32\n" " if (c2 >= 65 && c2 <= 90) c2 = c2 + 32\n" " if (c1 != c2) return false\n" " }\n" " if (tag.count < rest.count) {\n" " var next = rest[tag.count]\n" " if (next != \" \" && next != \">\" && next != \"/\" && next != \"\\t\" && next != \"\\n\") return false\n" " }\n" " return true\n" " }\n" "\n" " static findCloseTag_(html, start, tag) {\n" " var i = start\n" " while (i < html.count - tag.count - 2) {\n" " if (html[i] == \"<\" && html[i + 1] == \"/\") {\n" " var match = true\n" " for (j in 0...tag.count) {\n" " var c1 = html[i + 2 + j].codePoints.toList[0]\n" " var c2 = tag[j].codePoints.toList[0]\n" " if (c1 >= 65 && c1 <= 90) c1 = c1 + 32\n" " if (c2 >= 65 && c2 <= 90) c2 = c2 + 32\n" " if (c1 != c2) {\n" " match = false\n" " break\n" " }\n" " }\n" " if (match) return i\n" " }\n" " i = i + 1\n" " }\n" " return -1\n" " }\n" "\n" " static processBlockElements_(html) {\n" " var result = html\n" "\n" " result = processHeadingsFromHtml_(result)\n" " result = processCodeBlocksFromHtml_(result)\n" " result = processBlockquotesFromHtml_(result)\n" " result = processListsFromHtml_(result)\n" " result = processHrFromHtml_(result)\n" " result = processParagraphsFromHtml_(result)\n" " result = processBrFromHtml_(result)\n" " result = stripContainerTags_(result)\n" "\n" " return result\n" " }\n" "\n" " static processHeadingsFromHtml_(html) {\n" " var result = html\n" " for (level in 1..6) {\n" " var prefix = \"\"\n" " for (i in 0...level) prefix = prefix + \"#\"\n" " result = replaceTag_(result, \"h\" + level.toString, prefix + \" \", \"\\n\\n\")\n" " }\n" " return result\n" " }\n" "\n" " static processCodeBlocksFromHtml_(html) {\n" " var result = html\n" "\n" " while (true) {\n" " var preStart = findTagStart_(result, \"pre\")\n" " if (preStart < 0) break\n" "\n" " var preOpenEnd = preStart\n" " while (preOpenEnd < result.count && result[preOpenEnd] != \">\") {\n" " preOpenEnd = preOpenEnd + 1\n" " }\n" " if (preOpenEnd >= result.count) break\n" "\n" " var preCloseStart = findCloseTag_(result, preOpenEnd + 1, \"pre\")\n" " if (preCloseStart < 0) break\n" "\n" " var content = result[preOpenEnd + 1...preCloseStart]\n" "\n" " var codeStart = findTagStart_(content, \"code\")\n" " if (codeStart >= 0) {\n" " var codeOpenEnd = codeStart\n" " while (codeOpenEnd < content.count && content[codeOpenEnd] != \">\") {\n" " codeOpenEnd = codeOpenEnd + 1\n" " }\n" " var codeCloseStart = findCloseTag_(content, codeOpenEnd + 1, \"code\")\n" " if (codeCloseStart >= 0) {\n" " content = content[codeOpenEnd + 1...codeCloseStart]\n" " }\n" " }\n" "\n" " var preCloseEnd = preCloseStart\n" " while (preCloseEnd < result.count && result[preCloseEnd] != \">\") {\n" " preCloseEnd = preCloseEnd + 1\n" " }\n" "\n" " var before = result[0...preStart]\n" " var after = result[preCloseEnd + 1..-1]\n" " result = before + \"\\n```\\n\" + content.trim() + \"\\n```\\n\" + after\n" " }\n" "\n" " return result\n" " }\n" "\n" " static processBlockquotesFromHtml_(html) {\n" " var result = html\n" "\n" " while (true) {\n" " var start = findTagStart_(result, \"blockquote\")\n" " if (start < 0) break\n" "\n" " var openEnd = start\n" " while (openEnd < result.count && result[openEnd] != \">\") {\n" " openEnd = openEnd + 1\n" " }\n" " if (openEnd >= result.count) break\n" "\n" " var closeStart = findCloseTag_(result, openEnd + 1, \"blockquote\")\n" " if (closeStart < 0) break\n" "\n" " var content = result[openEnd + 1...closeStart].trim()\n" " var lines = content.split(\"\\n\")\n" " var quoted = []\n" " for (line in lines) {\n" " var trimmed = line.trim()\n" " if (trimmed.count > 0) {\n" " quoted.add(\"> \" + trimmed)\n" " }\n" " }\n" "\n" " var closeEnd = closeStart\n" " while (closeEnd < result.count && result[closeEnd] != \">\") {\n" " closeEnd = closeEnd + 1\n" " }\n" "\n" " var before = result[0...start]\n" " var after = result[closeEnd + 1..-1]\n" " result = before + \"\\n\" + quoted.join(\"\\n\") + \"\\n\" + after\n" " }\n" "\n" " return result\n" " }\n" "\n" " static processListsFromHtml_(html) {\n" " var result = html\n" " result = processListType_(result, \"ul\", \"-\")\n" " result = processListType_(result, \"ol\", \"1.\")\n" " return result\n" " }\n" "\n" " static processListType_(html, tag, marker) {\n" " var result = html\n" "\n" " while (true) {\n" " var start = findTagStart_(result, tag)\n" " if (start < 0) break\n" "\n" " var openEnd = start\n" " while (openEnd < result.count && result[openEnd] != \">\") {\n" " openEnd = openEnd + 1\n" " }\n" " if (openEnd >= result.count) break\n" "\n" " var closeStart = findCloseTag_(result, openEnd + 1, tag)\n" " if (closeStart < 0) break\n" "\n" " var content = result[openEnd + 1...closeStart]\n" " var items = extractListItems_(content)\n" " var mdItems = []\n" " var num = 1\n" " for (item in items) {\n" " if (tag == \"ol\") {\n" " mdItems.add(num.toString + \". \" + item.trim())\n" " num = num + 1\n" " } else {\n" " mdItems.add(marker + \" \" + item.trim())\n" " }\n" " }\n" "\n" " var closeEnd = closeStart\n" " while (closeEnd < result.count && result[closeEnd] != \">\") {\n" " closeEnd = closeEnd + 1\n" " }\n" "\n" " var before = result[0...start]\n" " var after = result[closeEnd + 1..-1]\n" " result = before + \"\\n\" + mdItems.join(\"\\n\") + \"\\n\" + after\n" " }\n" "\n" " return result\n" " }\n" "\n" " static extractListItems_(html) {\n" " var items = []\n" " var i = 0\n" " while (i < html.count) {\n" " var liStart = findTagStartFrom_(html, i, \"li\")\n" " if (liStart < 0) break\n" "\n" " var openEnd = liStart\n" " while (openEnd < html.count && html[openEnd] != \">\") {\n" " openEnd = openEnd + 1\n" " }\n" " if (openEnd >= html.count) break\n" "\n" " var closeStart = findCloseTag_(html, openEnd + 1, \"li\")\n" " var content = \"\"\n" " if (closeStart >= 0) {\n" " content = html[openEnd + 1...closeStart]\n" " var closeEnd = closeStart\n" " while (closeEnd < html.count && html[closeEnd] != \">\") {\n" " closeEnd = closeEnd + 1\n" " }\n" " i = closeEnd + 1\n" " } else {\n" " var nextLi = findTagStartFrom_(html, openEnd + 1, \"li\")\n" " if (nextLi >= 0) {\n" " content = html[openEnd + 1...nextLi]\n" " i = nextLi\n" " } else {\n" " content = html[openEnd + 1..-1]\n" " i = html.count\n" " }\n" " }\n" " items.add(stripAllTags_(content).trim())\n" " }\n" " return items\n" " }\n" "\n" " static findTagStartFrom_(html, start, tag) {\n" " var i = start\n" " while (i < html.count) {\n" " if (matchTagName_(html, i, tag)) return i\n" " i = i + 1\n" " }\n" " return -1\n" " }\n" "\n" " static processHrFromHtml_(html) {\n" " var result = html\n" " var i = 0\n" " while (i < result.count) {\n" " if (matchTagName_(result, i, \"hr\")) {\n" " var end = i\n" " while (end < result.count && result[end] != \">\") {\n" " end = end + 1\n" " }\n" " result = result[0...i] + \"\\n---\\n\" + result[end + 1..-1]\n" " }\n" " i = i + 1\n" " }\n" " return result\n" " }\n" "\n" " static processParagraphsFromHtml_(html) {\n" " var result = html\n" " result = replaceTag_(result, \"p\", \"\", \"\\n\\n\")\n" " return result\n" " }\n" "\n" " static processBrFromHtml_(html) {\n" " var result = html\n" " var i = 0\n" " while (i < result.count) {\n" " if (matchTagName_(result, i, \"br\")) {\n" " var end = i\n" " while (end < result.count && result[end] != \">\") {\n" " end = end + 1\n" " }\n" " result = result[0...i] + \"\\n\" + result[end + 1..-1]\n" " }\n" " i = i + 1\n" " }\n" " return result\n" " }\n" "\n" " static stripContainerTags_(html) {\n" " var result = html\n" " var tags = [\"div\", \"span\", \"section\", \"article\", \"main\", \"header\", \"footer\", \"nav\", \"html\", \"body\"]\n" " for (tag in tags) {\n" " result = replaceTag_(result, tag, \"\", \"\")\n" " }\n" " return result\n" " }\n" "\n" " static processInlineFromHtml_(html) {\n" " var result = html\n" "\n" " result = processStrongFromHtml_(result)\n" " result = processEmFromHtml_(result)\n" " result = processCodeFromHtml_(result)\n" " result = processDelFromHtml_(result)\n" " result = processLinksFromHtml_(result)\n" " result = processImagesFromHtml_(result)\n" "\n" " return result\n" " }\n" "\n" " static processStrongFromHtml_(html) {\n" " var result = html\n" " result = replaceTag_(result, \"strong\", \"**\", \"**\")\n" " result = replaceTag_(result, \"b\", \"**\", \"**\")\n" " return result\n" " }\n" "\n" " static processEmFromHtml_(html) {\n" " var result = html\n" " result = replaceTag_(result, \"em\", \"*\", \"*\")\n" " result = replaceTag_(result, \"i\", \"*\", \"*\")\n" " return result\n" " }\n" "\n" " static processCodeFromHtml_(html) {\n" " return replaceTag_(html, \"code\", \"`\", \"`\")\n" " }\n" "\n" " static processDelFromHtml_(html) {\n" " var result = html\n" " result = replaceTag_(result, \"del\", \"~~\", \"~~\")\n" " result = replaceTag_(result, \"s\", \"~~\", \"~~\")\n" " result = replaceTag_(result, \"strike\", \"~~\", \"~~\")\n" " return result\n" " }\n" "\n" " static processLinksFromHtml_(html) {\n" " var result = html\n" "\n" " while (true) {\n" " var start = findTagStart_(result, \"a\")\n" " if (start < 0) break\n" "\n" " var openEnd = start\n" " while (openEnd < result.count && result[openEnd] != \">\") {\n" " openEnd = openEnd + 1\n" " }\n" " if (openEnd >= result.count) break\n" "\n" " var tagContent = result[start...openEnd + 1]\n" " var href = extractAttr_(tagContent, \"href\")\n" "\n" " var closeStart = findCloseTag_(result, openEnd + 1, \"a\")\n" " if (closeStart < 0) break\n" "\n" " var linkText = result[openEnd + 1...closeStart]\n" "\n" " var closeEnd = closeStart\n" " while (closeEnd < result.count && result[closeEnd] != \">\") {\n" " closeEnd = closeEnd + 1\n" " }\n" "\n" " var before = result[0...start]\n" " var after = result[closeEnd + 1..-1]\n" "\n" " if (href != null && href.count > 0) {\n" " result = before + \"[\" + stripAllTags_(linkText) + \"](\" + href + \")\" + after\n" " } else {\n" " result = before + stripAllTags_(linkText) + after\n" " }\n" " }\n" "\n" " return result\n" " }\n" "\n" " static processImagesFromHtml_(html) {\n" " var result = html\n" " var i = 0\n" "\n" " while (i < result.count) {\n" " if (matchTagName_(result, i, \"img\")) {\n" " var end = i\n" " while (end < result.count && result[end] != \">\") {\n" " end = end + 1\n" " }\n" "\n" " var tagContent = result[i...end + 1]\n" " var src = extractAttr_(tagContent, \"src\")\n" " var alt = extractAttr_(tagContent, \"alt\")\n" "\n" " if (src == null) src = \"\"\n" " if (alt == null) alt = \"\"\n" "\n" " var mdImg = \"![\" + alt + \"](\" + src + \")\"\n" " result = result[0...i] + mdImg + result[end + 1..-1]\n" " i = i + mdImg.count\n" " } else {\n" " i = i + 1\n" " }\n" " }\n" "\n" " return result\n" " }\n" "\n" " static extractAttr_(tag, name) {\n" " var search = name + \"=\\\"\"\n" " var start = tag.indexOf(search)\n" " if (start < 0) {\n" " search = name + \"='\"\n" " start = tag.indexOf(search)\n" " }\n" " if (start < 0) return null\n" "\n" " var valueStart = start + search.count\n" " var quote = search[-1]\n" " var valueEnd = valueStart\n" " while (valueEnd < tag.count && tag[valueEnd] != quote) {\n" " valueEnd = valueEnd + 1\n" " }\n" "\n" " return tag[valueStart...valueEnd]\n" " }\n" "\n" " static replaceTag_(html, tag, prefix, suffix) {\n" " var result = html\n" "\n" " while (true) {\n" " var start = findTagStart_(result, tag)\n" " if (start < 0) break\n" "\n" " var openEnd = start\n" " while (openEnd < result.count && result[openEnd] != \">\") {\n" " openEnd = openEnd + 1\n" " }\n" " if (openEnd >= result.count) break\n" "\n" " if (result[openEnd - 1] == \"/\") {\n" " result = result[0...start] + result[openEnd + 1..-1]\n" " continue\n" " }\n" "\n" " var closeStart = findCloseTag_(result, openEnd + 1, tag)\n" " if (closeStart < 0) {\n" " result = result[0...start] + result[openEnd + 1..-1]\n" " continue\n" " }\n" "\n" " var content = result[openEnd + 1...closeStart]\n" "\n" " var closeEnd = closeStart\n" " while (closeEnd < result.count && result[closeEnd] != \">\") {\n" " closeEnd = closeEnd + 1\n" " }\n" "\n" " var before = result[0...start]\n" " var after = result[closeEnd + 1..-1]\n" " result = before + prefix + content + suffix + after\n" " }\n" "\n" " return result\n" " }\n" "\n" " static findTagStart_(html, tag) {\n" " return findTagStartFrom_(html, 0, tag)\n" " }\n" "\n" " static stripAllTags_(html) {\n" " var result = \"\"\n" " var inTag = false\n" " for (c in html) {\n" " if (c == \"<\") {\n" " inTag = true\n" " } else if (c == \">\") {\n" " inTag = false\n" " } else if (!inTag) {\n" " result = result + c\n" " }\n" " }\n" " return result\n" " }\n" "\n" " static cleanupWhitespace_(text) {\n" " var result = text\n" "\n" " while (result.contains(\"\\n\\n\\n\")) {\n" " result = result.replace(\"\\n\\n\\n\", \"\\n\\n\")\n" " }\n" "\n" " var lines = result.split(\"\\n\")\n" " var cleaned = []\n" " for (line in lines) {\n" " cleaned.add(line.trim())\n" " }\n" "\n" " return cleaned.join(\"\\n\")\n" " }\n" "}\n";