feat: add example scripts for argparse, bytes, dataset, html, markdown, uuid, wdantic, and web chat modules
Add comprehensive demo scripts showcasing the usage of multiple Wren modules including argument parsing, byte manipulation, in-memory dataset operations, HTML encoding/slugification, markdown-to-HTML conversion, UUID generation/validation, schema validation with wdantic, and a full web chat application with REST endpoints.
2026-01-24 23:40:22 +01:00
|
|
|
// 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 <retoor@molodetz.nl>\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(\"<pre><code>\" + (safeMode ? Html.quote(codeBlockContent.join(\"\\n\")) : codeBlockContent.join(\"\\n\")) + \"</code></pre>\")\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(\"</blockquote>\")\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(\"<blockquote>\")\n"
|
|
|
|
|
" inBlockquote = true\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" result.add(\"<p>\" + processInline_(line[2..-1], safeMode) + \"</p>\")\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(\"<hr>\")\n"
|
|
|
|
|
" continue\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" var heading = parseHeading_(line)\n"
|
|
|
|
|
" if (heading) {\n"
|
|
|
|
|
" closeList_(result, inList, listType)\n"
|
|
|
|
|
" inList = false\n"
|
|
|
|
|
" result.add(\"<h%(heading[\"level\"])>\" + processInline_(heading[\"text\"], safeMode) + \"</h%(heading[\"level\"])>\")\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\" ? \"<ul>\" : \"<ol>\")\n"
|
|
|
|
|
" inList = true\n"
|
|
|
|
|
" listType = newType\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" result.add(\"<li>\" + processInline_(listItem[\"text\"], safeMode) + \"</li>\")\n"
|
|
|
|
|
" continue\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" closeList_(result, inList, listType)\n"
|
|
|
|
|
" inList = false\n"
|
|
|
|
|
" result.add(\"<p>\" + processInline_(line, safeMode) + \"</p>\")\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" closeList_(result, inList, listType)\n"
|
|
|
|
|
" if (inBlockquote) {\n"
|
|
|
|
|
" result.add(\"</blockquote>\")\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" if (inCodeBlock) {\n"
|
|
|
|
|
" result.add(\"<pre><code>\" + (safeMode ? Html.quote(codeBlockContent.join(\"\\n\")) : codeBlockContent.join(\"\\n\")) + \"</code></pre>\")\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" return result.join(\"\\n\")\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" static closeList_(result, inList, listType) {\n"
|
|
|
|
|
" if (inList) {\n"
|
|
|
|
|
" result.add(listType == \"ul\" ? \"</ul>\" : \"</ol>\")\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>\" + code + \"</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 + \"<strong>\" + content + \"</strong>\" + 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 + \"<strong>\" + content + \"</strong>\" + 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 + \"<em>\" + content + \"</em>\" + 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 + \"<del>\" + content + \"</del>\" + 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 + \"<a href=\\\"\" + url + \"\\\">\" + linkText + \"</a>\" + 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 + \"<img src=\\\"\" + url + \"\\\" alt=\\\"\" + alt + \"\\\">\" + after\n"
|
|
|
|
|
" } else {\n"
|
|
|
|
|
" break\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" } else {\n"
|
|
|
|
|
" break\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
feat: add merge_all_wren utility, strutil demo, and 7 new API manual pages
Add WrenFileReader class in apps/merge_all_wren.wren for recursive .wren file discovery and content printing. Introduce example/strutil_demo.wren demonstrating case conversion, hex encoding, SHA256 hashing, string repetition, padding, HTML/JSON escaping, and URL encoding/decoding. Create manual/api pages for argparse, dataset, html, markdown, uuid, wdantic, and web modules. Update manual/api/index.html sidebar and module count from 21 to 28, adding links and cards for the new modules.
2026-01-25 02:47:47 +01:00
|
|
|
"\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 = \"</\" + tag + \">\"\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 = \"\"\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"
|
feat: add example scripts for argparse, bytes, dataset, html, markdown, uuid, wdantic, and web chat modules
Add comprehensive demo scripts showcasing the usage of multiple Wren modules including argument parsing, byte manipulation, in-memory dataset operations, HTML encoding/slugification, markdown-to-HTML conversion, UUID generation/validation, schema validation with wdantic, and a full web chat application with REST endpoints.
2026-01-24 23:40:22 +01:00
|
|
|
"}\n";
|