quikdown 1.1.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +39 -7
  2. package/dist/quikdown.cjs +23 -10
  3. package/dist/quikdown.dark.css +1 -1
  4. package/dist/quikdown.esm.js +23 -10
  5. package/dist/quikdown.esm.min.js +2 -2
  6. package/dist/quikdown.esm.min.js.gz +0 -0
  7. package/dist/quikdown.esm.min.js.map +1 -1
  8. package/dist/quikdown.light.css +1 -1
  9. package/dist/quikdown.umd.js +23 -10
  10. package/dist/quikdown.umd.min.js +2 -2
  11. package/dist/quikdown.umd.min.js.gz +0 -0
  12. package/dist/quikdown.umd.min.js.map +1 -1
  13. package/dist/quikdown_ast.cjs +513 -0
  14. package/dist/quikdown_ast.d.ts +227 -0
  15. package/dist/quikdown_ast.esm.js +511 -0
  16. package/dist/quikdown_ast.esm.min.js +8 -0
  17. package/dist/quikdown_ast.esm.min.js.gz +0 -0
  18. package/dist/quikdown_ast.esm.min.js.map +1 -0
  19. package/dist/quikdown_ast.umd.js +519 -0
  20. package/dist/quikdown_ast.umd.min.js +8 -0
  21. package/dist/quikdown_ast.umd.min.js.gz +0 -0
  22. package/dist/quikdown_ast.umd.min.js.map +1 -0
  23. package/dist/quikdown_ast_html.cjs +1058 -0
  24. package/dist/quikdown_ast_html.d.ts +68 -0
  25. package/dist/quikdown_ast_html.esm.js +1056 -0
  26. package/dist/quikdown_ast_html.esm.min.js +8 -0
  27. package/dist/quikdown_ast_html.esm.min.js.gz +0 -0
  28. package/dist/quikdown_ast_html.esm.min.js.map +1 -0
  29. package/dist/quikdown_ast_html.umd.js +1064 -0
  30. package/dist/quikdown_ast_html.umd.min.js +8 -0
  31. package/dist/quikdown_ast_html.umd.min.js.gz +0 -0
  32. package/dist/quikdown_ast_html.umd.min.js.map +1 -0
  33. package/dist/quikdown_bd.cjs +38 -19
  34. package/dist/quikdown_bd.esm.js +38 -19
  35. package/dist/quikdown_bd.esm.min.js +2 -2
  36. package/dist/quikdown_bd.esm.min.js.gz +0 -0
  37. package/dist/quikdown_bd.esm.min.js.map +1 -1
  38. package/dist/quikdown_bd.umd.js +38 -19
  39. package/dist/quikdown_bd.umd.min.js +2 -2
  40. package/dist/quikdown_bd.umd.min.js.gz +0 -0
  41. package/dist/quikdown_bd.umd.min.js.map +1 -1
  42. package/dist/quikdown_edit.cjs +836 -117
  43. package/dist/quikdown_edit.d.ts +123 -131
  44. package/dist/quikdown_edit.esm.js +836 -117
  45. package/dist/quikdown_edit.esm.min.js +3 -3
  46. package/dist/quikdown_edit.esm.min.js.gz +0 -0
  47. package/dist/quikdown_edit.esm.min.js.map +1 -1
  48. package/dist/quikdown_edit.umd.js +836 -117
  49. package/dist/quikdown_edit.umd.min.js +3 -3
  50. package/dist/quikdown_edit.umd.min.js.gz +0 -0
  51. package/dist/quikdown_edit.umd.min.js.map +1 -1
  52. package/dist/quikdown_json.cjs +556 -0
  53. package/dist/quikdown_json.d.ts +48 -0
  54. package/dist/quikdown_json.esm.js +554 -0
  55. package/dist/quikdown_json.esm.min.js +8 -0
  56. package/dist/quikdown_json.esm.min.js.gz +0 -0
  57. package/dist/quikdown_json.esm.min.js.map +1 -0
  58. package/dist/quikdown_json.umd.js +562 -0
  59. package/dist/quikdown_json.umd.min.js +8 -0
  60. package/dist/quikdown_json.umd.min.js.gz +0 -0
  61. package/dist/quikdown_json.umd.min.js.map +1 -0
  62. package/dist/quikdown_yaml.cjs +717 -0
  63. package/dist/quikdown_yaml.d.ts +51 -0
  64. package/dist/quikdown_yaml.esm.js +715 -0
  65. package/dist/quikdown_yaml.esm.min.js +8 -0
  66. package/dist/quikdown_yaml.esm.min.js.gz +0 -0
  67. package/dist/quikdown_yaml.esm.min.js.map +1 -0
  68. package/dist/quikdown_yaml.umd.js +723 -0
  69. package/dist/quikdown_yaml.umd.min.js +8 -0
  70. package/dist/quikdown_yaml.umd.min.js.gz +0 -0
  71. package/dist/quikdown_yaml.umd.min.js.map +1 -0
  72. package/package.json +100 -45
@@ -0,0 +1,8 @@
1
+ /**
2
+ * quikdown_ast_html - AST to HTML Markdown Parser
3
+ * @version 1.2.3
4
+ * @license BSD-2-Clause
5
+ * @copyright DeftIO 2025
6
+ */
7
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).quikdown_ast_html=t()}(this,function(){"use strict";function e(e,n={}){if(!e||"string"!=typeof e)return{type:"document",children:[]};return{type:"document",children:t(e.replace(/\r\n/g,"\n").replace(/\r/g,"\n"))}}function t(e,i){const c=[],l=e.split("\n");let o=0;for(;o<l.length;){const e=l[o];if(""===e.trim()){o++;continue}const i=e.match(/^(```|~~~)(.*)$/);if(i){const[,e,t]=i,n=t.trim(),r=[];for(o++;o<l.length;){if(l[o].match(/^(```|~~~)\s*$/)){o++;break}r.push(l[o]),o++}c.push({type:"code_block",lang:n||null,content:r.join("\n"),fence:e});continue}if(/^---+\s*$/.test(e)||/^\*\*\*+\s*$/.test(e)||/^___+\s*$/.test(e)){c.push({type:"hr"}),o++;continue}const a=e.match(/^(#{1,6})\s*(.+?)\s*#*$/);if(a){const[,e,t]=a;c.push({type:"heading",level:e.length,children:s(t)}),o++;continue}if(e.includes("|")){const e=n(l,o);if(e){c.push(e.node),o=e.nextIndex;continue}}if(e.match(/^>\s*/)){const e=[];for(;o<l.length&&l[o].match(/^>\s*/);)e.push(l[o].replace(/^>\s*/,"")),o++;c.push({type:"blockquote",children:t(e.join("\n"))});continue}if(e.match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/)){const e=r(l,o);c.push(e.node),o=e.nextIndex;continue}const u=[];for(;o<l.length;){const e=l[o];if(""===e.trim())break;if(/^(```|~~~)/.test(e))break;if(/^#{1,6}\s/.test(e))break;if(/^---+\s*$/.test(e)||/^\*\*\*+\s*$/.test(e)||/^___+\s*$/.test(e))break;if(/^>\s*/.test(e))break;if(/^(\s*)([*\-+]|\d+\.)\s+/.test(e))break;if(e.includes("|")&&o+1<l.length&&/^\|?[\s\-:|]+\|?$/.test(l[o+1]))break;u.push(e),o++}u.length>0&&c.push({type:"paragraph",children:s(u.join("\n"))})}return c}function n(e,t,n){if(t+1>=e.length)return null;const r=e[t],c=e[t+1];if(!/^\|?[\s\-:|]+\|?$/.test(c)||!c.includes("-"))return null;const l=i(r);if(0===l.length)return null;const o=i(c).map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"}),a=l.map(e=>s(e.trim())),u=[];let d=t+2;for(;d<e.length;){const t=e[d];if(!t.includes("|")||""===t.trim())break;const n=i(t);u.push(n.map(e=>s(e.trim()))),d++}return{node:{type:"table",headers:a,rows:u,alignments:o},nextIndex:d}}function i(e){let t=e.trim();return t.startsWith("|")&&(t=t.slice(1)),t.endsWith("|")&&(t=t.slice(0,-1)),t.split("|")}function r(e,t,n){const i=[];let c=t,l=0;const o=e[c].match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/),a=/^\d+\./.test(o[2]),u=o[1].length;for(;c<e.length&&l<1e3;){l++;const t=e[c].match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/);if(!t)break;const[,n,o,d]=t,h=n.length;if(h<u)break;const f=/^\d+\./.test(o);if(h===u&&f!==a)break;if(h>u){const t=[];let n=0;for(;c<e.length&&n<1e3;){n++;const i=e[c],r=i.match(/^(\s*)([*\-+]|\d+\.)\s+/);if(!r)break;if(r[1].length<u)break;if(r[1].length===u)break;t.push(i),c++}if(t.length>0&&i.length>0){const e=r(t,0),n=i[i.length-1];n.children?Array.isArray(n.children)||(n.children=[{type:"paragraph",children:n.children}]):n.children=[],n.children.push(e.node)}continue}const p={type:"list_item",checked:null,children:null},m=d.match(/^\[([x ])\]\s*(.*)$/i);m&&!a?(p.checked="x"===m[1].toLowerCase(),p.children=s(m[2])):p.children=s(d),i.push(p),c++}return{node:{type:"list",ordered:a,items:i},nextIndex:c}}function s(e,t){if(!e)return[];const n=[];let i=e;for(;i.length>0;){let e=!1;if(i.match(/^(.+?)(?: {2}|\\\n|\n)/)&&i.includes("\n")){const t=i.indexOf("\n"),r=i.slice(0,t),s=i.slice(t+1);if(r.endsWith(" ")||r.endsWith("\\")){const t=r.replace(/\\$/,"").replace(/ +$/,"");t&&n.push(...c(t)),n.push({type:"br"}),i=s,e=!0;continue}}const t=i.match(/^!\[([^\]]*)\]\(\s*([^)\s]+)\s*\)/);if(t){n.push({type:"image",alt:t[1],url:t[2].trim()}),i=i.slice(t[0].length),e=!0;continue}const r=i.match(/^\[([^\]]+)\]\(\s*([^)\s]+)\s*\)/);if(r){n.push({type:"link",url:r[2].trim(),children:c(r[1])}),i=i.slice(r[0].length),e=!0;continue}const s=i.match(/^`([^`]+)`/);if(s){n.push({type:"code",value:s[1]}),i=i.slice(s[0].length),e=!0;continue}const l=i.match(/^(\*\*|__)(.+?)\1/);if(l){n.push({type:"strong",children:c(l[2])}),i=i.slice(l[0].length),e=!0;continue}const o=i.match(/^~~(.+?)~~/);if(o){n.push({type:"del",children:c(o[1])}),i=i.slice(o[0].length),e=!0;continue}const a=i.match(/^(\*|_)(?!\1)(.+?)(?<!\1)\1(?!\1)/);if(a){n.push({type:"em",children:c(a[2])}),i=i.slice(a[0].length),e=!0;continue}const u=i.match(/^(https?:\/\/[^\s<>[\]]+)/);if(u)n.push({type:"link",url:u[1],children:[{type:"text",value:u[1]}]}),i=i.slice(u[0].length),e=!0;else if(!e){const e=i.search(/[`*_~![\\n]|https?:\/\//);if(-1===e){n.push({type:"text",value:i});break}0===e?(n.push({type:"text",value:i[0]}),i=i.slice(1)):(n.push({type:"text",value:i.slice(0,e)}),i=i.slice(e))}}return function(e){const t=[];for(const n of e)"text"===n.type&&t.length>0&&"text"===t[t.length-1].type?t[t.length-1].value+=n.value:t.push(n);return t}(n)}function c(e,t){return s(e.replace(/\n/g," "))}e.version="1.2.3","undefined"!=typeof module&&module.exports&&(module.exports=e),"undefined"!=typeof window&&(window.quikdown_ast=e);const l="quikdown-",o={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},a={h1:"font-size:2em;font-weight:600;margin:.67em 0;text-align:left",h2:"font-size:1.5em;font-weight:600;margin:.83em 0",h3:"font-size:1.25em;font-weight:600;margin:1em 0",h4:"font-size:1em;font-weight:600;margin:1.33em 0",h5:"font-size:.875em;font-weight:600;margin:1.67em 0",h6:"font-size:.85em;font-weight:600;margin:2em 0",pre:"background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0",code:"background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace",blockquote:"border-left:4px solid #ddd;margin-left:0;padding-left:1em",table:"border-collapse:collapse;width:100%;margin:1em 0",th:"border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left",td:"border:1px solid #ddd;padding:8px;text-align:left",hr:"border:none;border-top:1px solid #ddd;margin:1em 0",img:"max-width:100%;height:auto",a:"color:#06c;text-decoration:underline",strong:"font-weight:bold",em:"font-style:italic",del:"text-decoration:line-through",ul:"margin:.5em 0;padding-left:2em",ol:"margin:.5em 0;padding-left:2em",li:"margin:.25em 0","task-item":"list-style:none","task-checkbox":"margin-right:.5em"};function u(e){return e?String(e).replace(/[&<>"']/g,e=>o[e]):""}function d(e){if(!e)return"";const t=e.trim(),n=t.toLowerCase(),i=["javascript:","vbscript:","data:"];for(const e of i)if(n.startsWith(e))return"data:"===e&&n.startsWith("data:image/")?t:"#";return t}function h(t,n={}){if(!t)return{type:"document",children:[]};if("object"==typeof t&&t.type)return t;if("string"==typeof t){const i=t.trim();if(i.startsWith("{")||i.startsWith("["))try{const e=JSON.parse(i);return"document"===e.type?e:Array.isArray(e)?{type:"document",children:e}:e}catch(e){}if(i.includes("type:")&&(i.includes("children:")||i.includes("value:")))try{const e=f(i.split("\n"),0,0).value;if(e&&e.type)return e}catch(e){}return e(t,n)}return{type:"document",children:[]}}function f(e,t,n){if(t>=e.length)return{value:null,nextLine:t};const i=e[t],r=i.trim();if(""===r)return f(e,t+1,n);const s=i.search(/\S/);if(s<n&&s>=0)return{value:null,nextLine:t};if(r.startsWith("- "))return function(e,t,n){const i=[];let r=t;for(;r<e.length;){const t=e[r],s=t.trim();if(""===s){r++;continue}const c=t.search(/\S/);if(c<n&&c>=0)break;if(c>n&&i.length>0){r++;continue}if(!s.startsWith("- "))break;const l=s.slice(2);if(l.includes(":")){const t={},s=l.indexOf(":"),o=l.slice(0,s).trim(),a=l.slice(s+1).trim();if(""===a||a.startsWith("\n")){const n=f(e,r+1,c+2);t[o]=n.value,r=n.nextLine}else t[o]=p(a),r++;for(;r<e.length;){const i=e[r],s=i.trim();if(""===s){r++;continue}const c=i.search(/\S/);if(c<=n)break;if(s.startsWith("- "))break;const l=s.indexOf(":");if(l>0){const n=s.slice(0,l).trim(),i=s.slice(l+1).trim();if(""===i||i.startsWith("\n")){const i=f(e,r+1,c+2);t[n]=i.value,r=i.nextLine}else t[n]=p(i),r++}else r++}i.push(t)}else i.push(p(l)),r++}return{value:i,nextLine:r}}(e,t,s);if("[]"===r)return{value:[],nextLine:t+1};if("{}"===r)return{value:{},nextLine:t+1};return r.indexOf(":")>0?function(e,t,n){const i={};let r=t;for(;r<e.length;){const t=e[r],s=t.trim();if(""===s){r++;continue}const c=t.search(/\S/);if(c<n&&c>=0)break;const l=s.indexOf(":");if(l<=0){r++;continue}const o=s.slice(0,l).trim(),a=s.slice(l+1).trim();if(""===a||"|"===a||">"===a){const t=f(e,r+1,c+2);i[o]=t.value,r=t.nextLine}else i[o]=p(a),r++}return{value:i,nextLine:r}}(e,t,s):{value:p(r),nextLine:t+1}}function p(e){if(!e)return null;const t=e.trim();return"null"===t||"~"===t?null:"true"===t||"false"!==t&&(t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\n/g,"\n").replace(/\\"/g,'"').replace(/\\\\/g,"\\"):/^-?\d+$/.test(t)?parseInt(t,10):/^-?\d+\.\d+$/.test(t)?parseFloat(t):t)}function m(e,t={}){return g(h(e,t),t)}function g(e,t={}){if(!e)return"";const{inline_styles:n=!1}=t,i=function(e){return function(t,n=""){if(e){let e=a[t];return e||n?(n&&n.includes("text-align")&&e&&e.includes("text-align")&&(e=e.replace(/text-align:[^;]+;?/,"").trim(),e&&!e.endsWith(";")&&(e+=";")),` style="${n?e?`${e}${n}`:n:e}"`):""}{const e=` class="${l}${t}"`;return n?`${e} style="${n}"`:e}}}(n);return $(e,i,t)}function $(e,t,n){if(!e)return"";switch(e.type){case"document":return y(e.children,t,n);case"paragraph":return`<p>${y(e.children,t,n)}</p>`;case"heading":const i=e.level||1;return`<h${i}${t("h"+i)}>${y(e.children,t,n)}</h${i}>`;case"code_block":const r=!n.inline_styles&&e.lang?` class="language-${e.lang}"`:"",s=n.inline_styles?t("code"):r;return`<pre${t("pre")}><code${s}>${u(e.content)}</code></pre>`;case"blockquote":return`<blockquote${t("blockquote")}>${y(e.children,t,n)}</blockquote>`;case"list":const c=e.ordered?"ol":"ul",o=(e.items||[]).map(e=>$(e,t,n)).join("");return`<${c}${t(c)}>${o}</${c}>`;case"list_item":if(null!==e.checked&&void 0!==e.checked){const i=n.inline_styles?' style="margin-right:.5em"':` class="${l}task-checkbox"`,r=e.checked?" checked":"";return`<li${n.inline_styles?' style="list-style:none"':` class="${l}task-item"`}><input type="checkbox"${i}${r} disabled> ${y(e.children,t,n)}</li>`}return`<li${t("li")}>${y(e.children,t,n)}</li>`;case"table":return function(e,t,n){const i=e.alignments||[];let r=`<table${t("table")}>\n`;e.headers&&e.headers.length>0&&(r+="<thead>\n<tr>\n",e.headers.forEach((e,s)=>{const c=i[s]&&"left"!==i[s]?`text-align:${i[s]}`:"";r+=`<th${t("th",c)}>${y(e,t,n)}</th>\n`}),r+="</tr>\n</thead>\n");e.rows&&e.rows.length>0&&(r+="<tbody>\n",e.rows.forEach(e=>{r+="<tr>\n",e.forEach((e,s)=>{const c=i[s]&&"left"!==i[s]?`text-align:${i[s]}`:"";r+=`<td${t("td",c)}>${y(e,t,n)}</td>\n`}),r+="</tr>\n"}),r+="</tbody>\n");return r+="</table>",r}(e,t,n);case"hr":return`<hr${t("hr")}>`;case"text":return u(e.value||"");case"strong":return`<strong${t("strong")}>${y(e.children,t,n)}</strong>`;case"em":return`<em${t("em")}>${y(e.children,t,n)}</em>`;case"del":return`<del${t("del")}>${y(e.children,t,n)}</del>`;case"code":return`<code${t("code")}>${u(e.value||"")}</code>`;case"link":const a=d(e.url),h=/^https?:\/\//i.test(a)?' rel="noopener noreferrer"':"";return`<a${t("a")} href="${a}"${h}>${y(e.children,t,n)}</a>`;case"image":const f=d(e.url);return`<img${t("img")} src="${f}" alt="${u(e.alt||"")}">`;case"br":return"<br>";default:return e.children?y(e.children,t,n):void 0!==e.value?u(String(e.value)):""}}function y(e,t,n){return e?Array.isArray(e)?e.map(e=>$(e,t,n)).join(""):$(e,t,n):""}return m.toAst=h,m.renderAst=g,m.version="1.2.3","undefined"!=typeof module&&module.exports&&(module.exports=m),"undefined"!=typeof window&&(window.quikdown_ast_html=m),m});
8
+ //# sourceMappingURL=quikdown_ast_html.umd.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quikdown_ast_html.umd.min.js","sources":["../src/quikdown_ast.js","../src/quikdown_ast_html.js"],"sourcesContent":["/**\n * quikdown_ast - Forgiving markdown to AST parser\n * Converts markdown to a structured Abstract Syntax Tree\n * @param {string} markdown - The markdown source text\n * @param {Object} options - Optional configuration object\n * @returns {Object} - The AST object\n */\n\n// Version will be injected at build time\nconst quikdownVersion = '__QUIKDOWN_VERSION__';\n\n// Safety limit to prevent infinite loops in list parsing\nconst MAX_LOOP_ITERATIONS = 1000;\n\n/**\n * Parse markdown into an AST\n * @param {string} markdown - The markdown source text\n * @param {Object} options - Optional configuration object\n * @returns {Object} - The AST object\n */\nfunction quikdown_ast(markdown, options = {}) {\n if (!markdown || typeof markdown !== 'string') {\n return { type: 'document', children: [] };\n }\n\n // Normalize line endings (handle CRLF, CR, LF uniformly)\n const text = markdown.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n\n const children = parseBlocks(text, options);\n\n return {\n type: 'document',\n children\n };\n}\n\n/**\n * Parse block-level elements\n */\nfunction parseBlocks(text, options) {\n const blocks = [];\n const lines = text.split('\\n');\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // Empty line - skip\n if (line.trim() === '') {\n i++;\n continue;\n }\n\n // Fenced code block (``` or ~~~)\n const fenceMatch = line.match(/^(```|~~~)(.*)$/);\n if (fenceMatch) {\n const [, openFence, langPart] = fenceMatch;\n const lang = langPart.trim();\n const codeLines = [];\n i++;\n\n // Find closing fence (forgiving: accept mismatched fences or EOF)\n while (i < lines.length) {\n const closingMatch = lines[i].match(/^(```|~~~)\\s*$/);\n if (closingMatch) {\n i++;\n break;\n }\n codeLines.push(lines[i]);\n i++;\n }\n\n blocks.push({\n type: 'code_block',\n lang: lang || null,\n content: codeLines.join('\\n'),\n fence: openFence\n });\n continue;\n }\n\n // Horizontal rule\n if (/^---+\\s*$/.test(line) || /^\\*\\*\\*+\\s*$/.test(line) || /^___+\\s*$/.test(line)) {\n blocks.push({ type: 'hr' });\n i++;\n continue;\n }\n\n // Heading (forgiving: accept #heading without space)\n const headingMatch = line.match(/^(#{1,6})\\s*(.+?)\\s*#*$/);\n if (headingMatch) {\n const [, hashes, content] = headingMatch;\n blocks.push({\n type: 'heading',\n level: hashes.length,\n children: parseInline(content, options)\n });\n i++;\n continue;\n }\n\n // Table (look for separator line)\n if (line.includes('|')) {\n const tableResult = tryParseTable(lines, i, options);\n if (tableResult) {\n blocks.push(tableResult.node);\n i = tableResult.nextIndex;\n continue;\n }\n }\n\n // Blockquote\n if (line.match(/^>\\s*/)) {\n const quoteLines = [];\n while (i < lines.length && lines[i].match(/^>\\s*/)) {\n quoteLines.push(lines[i].replace(/^>\\s*/, ''));\n i++;\n }\n blocks.push({\n type: 'blockquote',\n children: parseBlocks(quoteLines.join('\\n'), options)\n });\n continue;\n }\n\n // List (ordered or unordered)\n const listMatch = line.match(/^(\\s*)([*\\-+]|\\d+\\.)\\s+(.*)$/);\n if (listMatch) {\n const listResult = parseList(lines, i, options);\n blocks.push(listResult.node);\n i = listResult.nextIndex;\n continue;\n }\n\n // Paragraph - collect lines until empty line or block element\n const paragraphLines = [];\n while (i < lines.length) {\n const pLine = lines[i];\n\n // Stop on empty line\n if (pLine.trim() === '') break;\n\n // Stop on block elements\n if (/^(```|~~~)/.test(pLine)) break;\n if (/^#{1,6}\\s/.test(pLine)) break;\n if (/^---+\\s*$/.test(pLine) || /^\\*\\*\\*+\\s*$/.test(pLine) || /^___+\\s*$/.test(pLine)) break;\n if (/^>\\s*/.test(pLine)) break;\n if (/^(\\s*)([*\\-+]|\\d+\\.)\\s+/.test(pLine)) break;\n if (pLine.includes('|') && i + 1 < lines.length && /^\\|?[\\s\\-:|]+\\|?$/.test(lines[i + 1])) break;\n\n paragraphLines.push(pLine);\n i++;\n }\n\n if (paragraphLines.length > 0) {\n blocks.push({\n type: 'paragraph',\n children: parseInline(paragraphLines.join('\\n'), options)\n });\n }\n }\n\n return blocks;\n}\n\n/**\n * Try to parse a table starting at the given line\n */\nfunction tryParseTable(lines, startIndex, options) {\n // Need at least 2 lines (header + separator)\n if (startIndex + 1 >= lines.length) return null;\n\n const headerLine = lines[startIndex];\n const separatorLine = lines[startIndex + 1];\n\n // Check if separator line is valid\n if (!/^\\|?[\\s\\-:|]+\\|?$/.test(separatorLine) || !separatorLine.includes('-')) {\n return null;\n }\n\n // Parse header\n const headerCells = parseTableRow(headerLine);\n if (headerCells.length === 0) return null;\n\n // Parse alignments from separator\n const separatorCells = parseTableRow(separatorLine);\n const alignments = separatorCells.map(cell => {\n const trimmed = cell.trim();\n if (trimmed.startsWith(':') && trimmed.endsWith(':')) return 'center';\n if (trimmed.endsWith(':')) return 'right';\n return 'left';\n });\n\n // Parse headers with inline formatting\n const headers = headerCells.map(cell => parseInline(cell.trim(), options));\n\n // Parse body rows\n const rows = [];\n let i = startIndex + 2;\n while (i < lines.length) {\n const rowLine = lines[i];\n if (!rowLine.includes('|') || rowLine.trim() === '') break;\n\n const cells = parseTableRow(rowLine);\n rows.push(cells.map(cell => parseInline(cell.trim(), options)));\n i++;\n }\n\n return {\n node: {\n type: 'table',\n headers,\n rows,\n alignments\n },\n nextIndex: i\n };\n}\n\n/**\n * Parse a table row into cells\n */\nfunction parseTableRow(line) {\n // Handle pipes at start/end or not\n let trimmed = line.trim();\n if (trimmed.startsWith('|')) trimmed = trimmed.slice(1);\n if (trimmed.endsWith('|')) trimmed = trimmed.slice(0, -1);\n return trimmed.split('|');\n}\n\n/**\n * Parse a list starting at the given line\n */\nfunction parseList(lines, startIndex, options) {\n const items = [];\n let i = startIndex;\n let loopCount = 0;\n\n // Determine initial list type\n const firstMatch = lines[i].match(/^(\\s*)([*\\-+]|\\d+\\.)\\s+(.*)$/);\n const isOrdered = /^\\d+\\./.test(firstMatch[2]);\n const baseIndent = firstMatch[1].length;\n\n while (i < lines.length && loopCount < MAX_LOOP_ITERATIONS) {\n loopCount++;\n const line = lines[i];\n const match = line.match(/^(\\s*)([*\\-+]|\\d+\\.)\\s+(.*)$/);\n\n if (!match) break;\n\n const [, indent, marker, content] = match;\n const indentLevel = indent.length;\n\n // If less indented than base, stop\n if (indentLevel < baseIndent) break;\n\n // If same indentation but different list type, stop\n const itemIsOrdered = /^\\d+\\./.test(marker);\n if (indentLevel === baseIndent && itemIsOrdered !== isOrdered) break;\n\n // If more indented, it's a nested list - handle by collecting sub-lines\n if (indentLevel > baseIndent) {\n // This is a nested list item, collect and parse as sublist\n const subLines = [];\n let subLoopCount = 0;\n while (i < lines.length && subLoopCount < MAX_LOOP_ITERATIONS) {\n subLoopCount++;\n const subLine = lines[i];\n const subMatch = subLine.match(/^(\\s*)([*\\-+]|\\d+\\.)\\s+/);\n if (!subMatch) break;\n if (subMatch[1].length < baseIndent) break;\n if (subMatch[1].length === baseIndent) break;\n subLines.push(subLine);\n i++;\n }\n\n if (subLines.length > 0 && items.length > 0) {\n // Add nested list to last item\n const nestedResult = parseList(subLines, 0, options);\n const lastItem = items[items.length - 1];\n if (!lastItem.children) {\n lastItem.children = [];\n } else if (!Array.isArray(lastItem.children)) {\n lastItem.children = [{ type: 'paragraph', children: lastItem.children }];\n }\n lastItem.children.push(nestedResult.node);\n }\n continue;\n }\n\n // Parse list item\n const itemNode = {\n type: 'list_item',\n checked: null,\n children: null\n };\n\n // Check for task list syntax\n const taskMatch = content.match(/^\\[([x ])\\]\\s*(.*)$/i);\n if (taskMatch && !isOrdered) {\n itemNode.checked = taskMatch[1].toLowerCase() === 'x';\n itemNode.children = parseInline(taskMatch[2], options);\n } else {\n itemNode.children = parseInline(content, options);\n }\n\n items.push(itemNode);\n i++;\n }\n\n return {\n node: {\n type: 'list',\n ordered: isOrdered,\n items\n },\n nextIndex: i\n };\n}\n\n/**\n * Parse inline elements\n */\nfunction parseInline(text, options) {\n if (!text) return [];\n\n const nodes = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n let matched = false;\n\n // Line break (1+ trailing spaces or explicit \\n after processing)\n // Handle inline line breaks (two spaces at end of line or backslash before newline)\n const brMatch = remaining.match(/^(.+?)(?: {2}|\\\\\\n|\\n)/);\n if (brMatch && remaining.includes('\\n')) {\n const beforeBr = remaining.indexOf('\\n');\n const beforeText = remaining.slice(0, beforeBr);\n const afterText = remaining.slice(beforeBr + 1);\n\n // Check if line break is significant (2+ trailing spaces or backslash)\n if (beforeText.endsWith(' ') || beforeText.endsWith('\\\\')) {\n const cleanText = beforeText.replace(/\\\\$/, '').replace(/ +$/, '');\n if (cleanText) {\n nodes.push(...parseInlineContent(cleanText, options));\n }\n nodes.push({ type: 'br' });\n remaining = afterText;\n matched = true;\n continue;\n }\n }\n\n // Images: ![alt](url)\n const imgMatch = remaining.match(/^!\\[([^\\]]*)\\]\\(\\s*([^)\\s]+)\\s*\\)/);\n if (imgMatch) {\n nodes.push({\n type: 'image',\n alt: imgMatch[1],\n url: imgMatch[2].trim() // Forgiving: trim whitespace in URL\n });\n remaining = remaining.slice(imgMatch[0].length);\n matched = true;\n continue;\n }\n\n // Links: [text](url)\n const linkMatch = remaining.match(/^\\[([^\\]]+)\\]\\(\\s*([^)\\s]+)\\s*\\)/);\n if (linkMatch) {\n nodes.push({\n type: 'link',\n url: linkMatch[2].trim(), // Forgiving: trim whitespace in URL\n children: parseInlineContent(linkMatch[1], options)\n });\n remaining = remaining.slice(linkMatch[0].length);\n matched = true;\n continue;\n }\n\n // Inline code: `code`\n const codeMatch = remaining.match(/^`([^`]+)`/);\n if (codeMatch) {\n nodes.push({\n type: 'code',\n value: codeMatch[1]\n });\n remaining = remaining.slice(codeMatch[0].length);\n matched = true;\n continue;\n }\n\n // Bold: **text** or __text__\n const boldMatch = remaining.match(/^(\\*\\*|__)(.+?)\\1/);\n if (boldMatch) {\n nodes.push({\n type: 'strong',\n children: parseInlineContent(boldMatch[2], options)\n });\n remaining = remaining.slice(boldMatch[0].length);\n matched = true;\n continue;\n }\n\n // Strikethrough: ~~text~~\n const strikeMatch = remaining.match(/^~~(.+?)~~/);\n if (strikeMatch) {\n nodes.push({\n type: 'del',\n children: parseInlineContent(strikeMatch[1], options)\n });\n remaining = remaining.slice(strikeMatch[0].length);\n matched = true;\n continue;\n }\n\n // Italic: *text* or _text_ (not at word boundary for underscores)\n const emMatch = remaining.match(/^(\\*|_)(?!\\1)(.+?)(?<!\\1)\\1(?!\\1)/);\n if (emMatch) {\n nodes.push({\n type: 'em',\n children: parseInlineContent(emMatch[2], options)\n });\n remaining = remaining.slice(emMatch[0].length);\n matched = true;\n continue;\n }\n\n // Autolinks: URLs starting with http:// or https://\n const urlMatch = remaining.match(/^(https?:\\/\\/[^\\s<>[\\]]+)/);\n if (urlMatch) {\n nodes.push({\n type: 'link',\n url: urlMatch[1],\n children: [{ type: 'text', value: urlMatch[1] }]\n });\n remaining = remaining.slice(urlMatch[0].length);\n matched = true;\n continue;\n }\n\n // Plain text - consume until next potential inline element or end\n if (!matched) {\n // Find next potential inline marker\n const nextMarker = remaining.search(/[`*_~![\\\\n]|https?:\\/\\//);\n if (nextMarker === -1) {\n // No more markers, consume rest as text\n nodes.push({ type: 'text', value: remaining });\n break;\n } else if (nextMarker === 0) {\n // Current char is a marker but didn't match - consume it as text\n nodes.push({ type: 'text', value: remaining[0] });\n remaining = remaining.slice(1);\n } else {\n // Consume text up to next marker\n nodes.push({ type: 'text', value: remaining.slice(0, nextMarker) });\n remaining = remaining.slice(nextMarker);\n }\n }\n }\n\n // Merge adjacent text nodes\n return mergeTextNodes(nodes);\n}\n\n/**\n * Parse inline content (recursive helper for nested inline elements)\n */\nfunction parseInlineContent(text, options) {\n // For simple nested content, use parseInline\n // But handle newlines as spaces for inline content\n const normalized = text.replace(/\\n/g, ' ');\n return parseInline(normalized, options);\n}\n\n/**\n * Merge adjacent text nodes\n */\nfunction mergeTextNodes(nodes) {\n const merged = [];\n for (const node of nodes) {\n if (node.type === 'text' && merged.length > 0 && merged[merged.length - 1].type === 'text') {\n merged[merged.length - 1].value += node.value;\n } else {\n merged.push(node);\n }\n }\n return merged;\n}\n\n// Attach version\nquikdown_ast.version = quikdownVersion;\n\n// Export for both CommonJS and ES6\n/* istanbul ignore next */\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = quikdown_ast;\n}\n\n// For browser global\n/* istanbul ignore next */\nif (typeof window !== 'undefined') {\n window.quikdown_ast = quikdown_ast;\n}\n\nexport default quikdown_ast;\n","/**\n * quikdown_ast_html - AST to HTML converter\n * Converts AST (or markdown/JSON/YAML) to HTML\n * @param {string|Object} input - Markdown string, AST object, JSON string, or YAML string\n * @param {Object} options - Optional configuration object\n * @returns {string} - HTML string\n */\n\nimport quikdown_ast from './quikdown_ast.js';\n\n// Version will be injected at build time\nconst quikdownVersion = '__QUIKDOWN_VERSION__';\n\n// Constants\nconst CLASS_PREFIX = 'quikdown-';\n\n// Escape map for HTML\nconst ESC_MAP = {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'};\n\n// Style definitions (matching quikdown.js)\nconst QUIKDOWN_STYLES = {\n h1: 'font-size:2em;font-weight:600;margin:.67em 0;text-align:left',\n h2: 'font-size:1.5em;font-weight:600;margin:.83em 0',\n h3: 'font-size:1.25em;font-weight:600;margin:1em 0',\n h4: 'font-size:1em;font-weight:600;margin:1.33em 0',\n h5: 'font-size:.875em;font-weight:600;margin:1.67em 0',\n h6: 'font-size:.85em;font-weight:600;margin:2em 0',\n pre: 'background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0',\n code: 'background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace',\n blockquote: 'border-left:4px solid #ddd;margin-left:0;padding-left:1em',\n table: 'border-collapse:collapse;width:100%;margin:1em 0',\n th: 'border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left',\n td: 'border:1px solid #ddd;padding:8px;text-align:left',\n hr: 'border:none;border-top:1px solid #ddd;margin:1em 0',\n img: 'max-width:100%;height:auto',\n a: 'color:#06c;text-decoration:underline',\n strong: 'font-weight:bold',\n em: 'font-style:italic',\n del: 'text-decoration:line-through',\n ul: 'margin:.5em 0;padding-left:2em',\n ol: 'margin:.5em 0;padding-left:2em',\n li: 'margin:.25em 0',\n 'task-item': 'list-style:none',\n 'task-checkbox': 'margin-right:.5em'\n};\n\n/**\n * Escape HTML entities\n */\nfunction escapeHtml(text) {\n if (!text) return '';\n return String(text).replace(/[&<>\"']/g, m => ESC_MAP[m]);\n}\n\n/**\n * Create attribute string generator\n */\nfunction createGetAttr(inline_styles) {\n return function(tag, additionalStyle = '') {\n if (inline_styles) {\n let style = QUIKDOWN_STYLES[tag];\n if (!style && !additionalStyle) return '';\n\n if (additionalStyle && additionalStyle.includes('text-align') && style && style.includes('text-align')) {\n style = style.replace(/text-align:[^;]+;?/, '').trim();\n if (style && !style.endsWith(';')) style += ';';\n }\n\n const fullStyle = additionalStyle ? (style ? `${style}${additionalStyle}` : additionalStyle) : style;\n return ` style=\"${fullStyle}\"`;\n } else {\n const classAttr = ` class=\"${CLASS_PREFIX}${tag}\"`;\n if (additionalStyle) {\n return `${classAttr} style=\"${additionalStyle}\"`;\n }\n return classAttr;\n }\n };\n}\n\n/**\n * Sanitize URLs\n */\nfunction sanitizeUrl(url) {\n if (!url) return '';\n const trimmedUrl = url.trim();\n const lowerUrl = trimmedUrl.toLowerCase();\n\n const dangerousProtocols = ['javascript:', 'vbscript:', 'data:'];\n for (const protocol of dangerousProtocols) {\n if (lowerUrl.startsWith(protocol)) {\n if (protocol === 'data:' && lowerUrl.startsWith('data:image/')) {\n return trimmedUrl;\n }\n return '#';\n }\n }\n\n return trimmedUrl;\n}\n\n/**\n * Convert input to AST\n * Accepts markdown string, AST object, JSON string, or YAML string\n */\nfunction toAst(input, options = {}) {\n if (!input) {\n return { type: 'document', children: [] };\n }\n\n // Already an AST object\n if (typeof input === 'object' && input.type) {\n return input;\n }\n\n if (typeof input === 'string') {\n const trimmed = input.trim();\n\n // Try JSON first (starts with { or [)\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n try {\n const parsed = JSON.parse(trimmed);\n if (parsed.type === 'document') {\n return parsed;\n }\n // If it's an array, wrap it as document children\n if (Array.isArray(parsed)) {\n return { type: 'document', children: parsed };\n }\n return parsed;\n } catch (_e) {\n // Not valid JSON, fall through to markdown\n }\n }\n\n // Try YAML detection (has type: and children: patterns typical of AST)\n if (trimmed.includes('type:') && (trimmed.includes('children:') || trimmed.includes('value:'))) {\n try {\n const parsed = parseYaml(trimmed);\n if (parsed && parsed.type) {\n return parsed;\n }\n } catch (_e) {\n // Not valid YAML AST, fall through to markdown\n }\n }\n\n // Treat as markdown\n return quikdown_ast(input, options);\n }\n\n return { type: 'document', children: [] };\n}\n\n/**\n * Simple YAML parser for AST format\n * Only handles the subset needed for quikdown AST\n */\nfunction parseYaml(yaml) {\n const lines = yaml.split('\\n');\n return parseYamlNode(lines, 0, 0).value;\n}\n\n/**\n * Parse a YAML node starting at given line and indent\n */\nfunction parseYamlNode(lines, startLine, minIndent) {\n if (startLine >= lines.length) {\n return { value: null, nextLine: startLine };\n }\n\n const line = lines[startLine];\n const trimmed = line.trim();\n\n // Skip empty lines\n if (trimmed === '') {\n return parseYamlNode(lines, startLine + 1, minIndent);\n }\n\n // Get current indent\n const indent = line.search(/\\S/);\n if (indent < minIndent && indent >= 0) {\n return { value: null, nextLine: startLine };\n }\n\n // Array item\n if (trimmed.startsWith('- ')) {\n return parseYamlArray(lines, startLine, indent);\n }\n\n // Empty array\n if (trimmed === '[]') {\n return { value: [], nextLine: startLine + 1 };\n }\n\n // Empty object\n if (trimmed === '{}') {\n return { value: {}, nextLine: startLine + 1 };\n }\n\n // Key-value pair\n const colonIndex = trimmed.indexOf(':');\n if (colonIndex > 0) {\n return parseYamlObject(lines, startLine, indent);\n }\n\n // Scalar value\n return { value: parseYamlScalar(trimmed), nextLine: startLine + 1 };\n}\n\n/**\n * Parse YAML array\n */\nfunction parseYamlArray(lines, startLine, baseIndent) {\n const items = [];\n let i = startLine;\n\n while (i < lines.length) {\n const line = lines[i];\n const trimmed = line.trim();\n\n if (trimmed === '') {\n i++;\n continue;\n }\n\n const indent = line.search(/\\S/);\n if (indent < baseIndent && indent >= 0) break;\n if (indent > baseIndent && items.length > 0) {\n // Continuation of previous item\n i++;\n continue;\n }\n\n if (!trimmed.startsWith('- ')) break;\n\n // Parse the item after \"- \"\n const itemContent = trimmed.slice(2);\n\n if (itemContent.includes(':')) {\n // Object item - parse inline and following properties\n const obj = {};\n const colonIdx = itemContent.indexOf(':');\n const key = itemContent.slice(0, colonIdx).trim();\n const value = itemContent.slice(colonIdx + 1).trim();\n\n if (value === '' || value.startsWith('\\n')) {\n // Value on next lines\n const result = parseYamlNode(lines, i + 1, indent + 2);\n obj[key] = result.value;\n i = result.nextLine;\n } else {\n obj[key] = parseYamlScalar(value);\n i++;\n }\n\n // Parse remaining properties at same indent\n while (i < lines.length) {\n const nextLine = lines[i];\n const nextTrimmed = nextLine.trim();\n if (nextTrimmed === '') {\n i++;\n continue;\n }\n\n const nextIndent = nextLine.search(/\\S/);\n if (nextIndent <= baseIndent) break;\n if (nextTrimmed.startsWith('- ')) break;\n\n const nextColonIdx = nextTrimmed.indexOf(':');\n if (nextColonIdx > 0) {\n const nextKey = nextTrimmed.slice(0, nextColonIdx).trim();\n const nextValue = nextTrimmed.slice(nextColonIdx + 1).trim();\n\n if (nextValue === '' || nextValue.startsWith('\\n')) {\n const result = parseYamlNode(lines, i + 1, nextIndent + 2);\n obj[nextKey] = result.value;\n i = result.nextLine;\n } else {\n obj[nextKey] = parseYamlScalar(nextValue);\n i++;\n }\n } else {\n i++;\n }\n }\n\n items.push(obj);\n } else {\n items.push(parseYamlScalar(itemContent));\n i++;\n }\n }\n\n return { value: items, nextLine: i };\n}\n\n/**\n * Parse YAML object\n */\nfunction parseYamlObject(lines, startLine, baseIndent) {\n const obj = {};\n let i = startLine;\n\n while (i < lines.length) {\n const line = lines[i];\n const trimmed = line.trim();\n\n if (trimmed === '') {\n i++;\n continue;\n }\n\n const indent = line.search(/\\S/);\n if (indent < baseIndent && indent >= 0) break;\n\n const colonIdx = trimmed.indexOf(':');\n if (colonIdx <= 0) {\n i++;\n continue;\n }\n\n const key = trimmed.slice(0, colonIdx).trim();\n const value = trimmed.slice(colonIdx + 1).trim();\n\n if (value === '' || value === '|' || value === '>') {\n // Value on next lines\n const result = parseYamlNode(lines, i + 1, indent + 2);\n obj[key] = result.value;\n i = result.nextLine;\n } else {\n obj[key] = parseYamlScalar(value);\n i++;\n }\n }\n\n return { value: obj, nextLine: i };\n}\n\n/**\n * Parse YAML scalar value\n */\nfunction parseYamlScalar(str) {\n if (!str) return null;\n\n const trimmed = str.trim();\n\n if (trimmed === 'null' || trimmed === '~') return null;\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n\n // Quoted string\n if ((trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))) {\n return trimmed.slice(1, -1)\n .replace(/\\\\n/g, '\\n')\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, '\\\\');\n }\n\n // Number\n if (/^-?\\d+$/.test(trimmed)) return parseInt(trimmed, 10);\n if (/^-?\\d+\\.\\d+$/.test(trimmed)) return parseFloat(trimmed);\n\n return trimmed;\n}\n\n/**\n * Convert AST (or any valid input) to HTML\n * @param {string|Object} input - Markdown, AST, JSON, or YAML\n * @param {Object} options - Configuration options\n * @returns {string} - HTML string\n */\nfunction quikdown_ast_html(input, options = {}) {\n const ast = toAst(input, options);\n return renderAst(ast, options);\n}\n\n/**\n * Render an AST node to HTML\n */\nfunction renderAst(node, options = {}) {\n if (!node) return '';\n\n const { inline_styles = false } = options;\n const getAttr = createGetAttr(inline_styles);\n\n return renderNode(node, getAttr, options);\n}\n\n/**\n * Render a single node\n */\nfunction renderNode(node, getAttr, options) {\n if (!node) return '';\n\n switch (node.type) {\n case 'document':\n return renderChildren(node.children, getAttr, options);\n\n case 'paragraph':\n return `<p>${renderChildren(node.children, getAttr, options)}</p>`;\n\n case 'heading':\n const level = node.level || 1;\n return `<h${level}${getAttr('h' + level)}>${renderChildren(node.children, getAttr, options)}</h${level}>`;\n\n case 'code_block':\n const langClass = !options.inline_styles && node.lang ? ` class=\"language-${node.lang}\"` : '';\n const codeAttr = options.inline_styles ? getAttr('code') : langClass;\n return `<pre${getAttr('pre')}><code${codeAttr}>${escapeHtml(node.content)}</code></pre>`;\n\n case 'blockquote':\n return `<blockquote${getAttr('blockquote')}>${renderChildren(node.children, getAttr, options)}</blockquote>`;\n\n case 'list':\n const listTag = node.ordered ? 'ol' : 'ul';\n const items = (node.items || []).map(item => renderNode(item, getAttr, options)).join('');\n return `<${listTag}${getAttr(listTag)}>${items}</${listTag}>`;\n\n case 'list_item':\n // Handle task list items\n if (node.checked !== null && node.checked !== undefined) {\n const checkboxAttr = options.inline_styles\n ? ' style=\"margin-right:.5em\"'\n : ` class=\"${CLASS_PREFIX}task-checkbox\"`;\n const checked = node.checked ? ' checked' : '';\n const itemAttr = options.inline_styles\n ? ' style=\"list-style:none\"'\n : ` class=\"${CLASS_PREFIX}task-item\"`;\n return `<li${itemAttr}><input type=\"checkbox\"${checkboxAttr}${checked} disabled> ${renderChildren(node.children, getAttr, options)}</li>`;\n }\n return `<li${getAttr('li')}>${renderChildren(node.children, getAttr, options)}</li>`;\n\n case 'table':\n return renderTable(node, getAttr, options);\n\n case 'hr':\n return `<hr${getAttr('hr')}>`;\n\n case 'text':\n return escapeHtml(node.value || '');\n\n case 'strong':\n return `<strong${getAttr('strong')}>${renderChildren(node.children, getAttr, options)}</strong>`;\n\n case 'em':\n return `<em${getAttr('em')}>${renderChildren(node.children, getAttr, options)}</em>`;\n\n case 'del':\n return `<del${getAttr('del')}>${renderChildren(node.children, getAttr, options)}</del>`;\n\n case 'code':\n return `<code${getAttr('code')}>${escapeHtml(node.value || '')}</code>`;\n\n case 'link':\n const sanitizedHref = sanitizeUrl(node.url);\n const isExternal = /^https?:\\/\\//i.test(sanitizedHref);\n const rel = isExternal ? ' rel=\"noopener noreferrer\"' : '';\n return `<a${getAttr('a')} href=\"${sanitizedHref}\"${rel}>${renderChildren(node.children, getAttr, options)}</a>`;\n\n case 'image':\n const sanitizedSrc = sanitizeUrl(node.url);\n return `<img${getAttr('img')} src=\"${sanitizedSrc}\" alt=\"${escapeHtml(node.alt || '')}\">`;\n\n case 'br':\n return '<br>';\n\n default:\n // Unknown node type - try to render children if present\n if (node.children) {\n return renderChildren(node.children, getAttr, options);\n }\n if (node.value !== undefined) {\n return escapeHtml(String(node.value));\n }\n return '';\n }\n}\n\n/**\n * Render children array\n */\nfunction renderChildren(children, getAttr, options) {\n if (!children) return '';\n if (!Array.isArray(children)) {\n return renderNode(children, getAttr, options);\n }\n return children.map(child => renderNode(child, getAttr, options)).join('');\n}\n\n/**\n * Render a table node\n */\nfunction renderTable(node, getAttr, options) {\n const alignments = node.alignments || [];\n\n let html = `<table${getAttr('table')}>\\n`;\n\n // Headers\n if (node.headers && node.headers.length > 0) {\n html += '<thead>\\n<tr>\\n';\n node.headers.forEach((header, i) => {\n const alignStyle = alignments[i] && alignments[i] !== 'left' ? `text-align:${alignments[i]}` : '';\n html += `<th${getAttr('th', alignStyle)}>${renderChildren(header, getAttr, options)}</th>\\n`;\n });\n html += '</tr>\\n</thead>\\n';\n }\n\n // Body\n if (node.rows && node.rows.length > 0) {\n html += '<tbody>\\n';\n node.rows.forEach(row => {\n html += '<tr>\\n';\n row.forEach((cell, i) => {\n const alignStyle = alignments[i] && alignments[i] !== 'left' ? `text-align:${alignments[i]}` : '';\n html += `<td${getAttr('td', alignStyle)}>${renderChildren(cell, getAttr, options)}</td>\\n`;\n });\n html += '</tr>\\n';\n });\n html += '</tbody>\\n';\n }\n\n html += '</table>';\n return html;\n}\n\n// Expose helper functions\nquikdown_ast_html.toAst = toAst;\nquikdown_ast_html.renderAst = renderAst;\n\n// Attach version\nquikdown_ast_html.version = quikdownVersion;\n\n// Export for both CommonJS and ES6\n/* istanbul ignore next */\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = quikdown_ast_html;\n}\n\n// For browser global\n/* istanbul ignore next */\nif (typeof window !== 'undefined') {\n window.quikdown_ast_html = quikdown_ast_html;\n}\n\nexport default quikdown_ast_html;\n"],"names":["quikdown_ast","markdown","options","type","children","parseBlocks","replace","text","blocks","lines","split","i","length","line","trim","fenceMatch","match","openFence","langPart","lang","codeLines","push","content","join","fence","test","headingMatch","hashes","level","parseInline","includes","tableResult","tryParseTable","node","nextIndex","quoteLines","listResult","parseList","paragraphLines","pLine","startIndex","headerLine","separatorLine","headerCells","parseTableRow","alignments","map","cell","trimmed","startsWith","endsWith","headers","rows","rowLine","cells","slice","items","loopCount","firstMatch","isOrdered","baseIndent","indent","marker","indentLevel","itemIsOrdered","subLines","subLoopCount","subLine","subMatch","nestedResult","lastItem","Array","isArray","itemNode","checked","taskMatch","toLowerCase","ordered","nodes","remaining","matched","beforeBr","indexOf","beforeText","afterText","cleanText","parseInlineContent","imgMatch","alt","url","linkMatch","codeMatch","value","boldMatch","strikeMatch","emMatch","urlMatch","nextMarker","search","merged","mergeTextNodes","version","module","exports","window","CLASS_PREFIX","ESC_MAP","QUIKDOWN_STYLES","h1","h2","h3","h4","h5","h6","pre","code","blockquote","table","th","td","hr","img","a","strong","em","del","ul","ol","li","escapeHtml","String","m","sanitizeUrl","trimmedUrl","lowerUrl","dangerousProtocols","protocol","toAst","input","parsed","JSON","parse","_e","parseYamlNode","startLine","minIndent","nextLine","itemContent","obj","colonIdx","key","result","parseYamlScalar","nextTrimmed","nextIndent","nextColonIdx","nextKey","nextValue","parseYamlArray","parseYamlObject","str","parseInt","parseFloat","quikdown_ast_html","renderAst","inline_styles","getAttr","tag","additionalStyle","style","classAttr","createGetAttr","renderNode","renderChildren","langClass","codeAttr","listTag","item","undefined","checkboxAttr","html","forEach","header","alignStyle","row","renderTable","sanitizedHref","rel","sanitizedSrc","child"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * quikdown_bd - Bidirectional Markdown Parser
3
- * @version 1.1.1
3
+ * @version 1.2.3
4
4
  * @license BSD-2-Clause
5
5
  * @copyright DeftIO 2025
6
6
  */
@@ -20,7 +20,7 @@
20
20
  */
21
21
 
22
22
  // Version will be injected at build time
23
- const quikdownVersion = '1.1.1';
23
+ const quikdownVersion = '1.2.3';
24
24
 
25
25
  // Constants for reuse
26
26
  const CLASS_PREFIX = 'quikdown-';
@@ -68,6 +68,11 @@ function createGetAttr(inline_styles, styles) {
68
68
  // Remove default text-align if we're adding a different alignment
69
69
  if (additionalStyle && additionalStyle.includes('text-align') && style && style.includes('text-align')) {
70
70
  style = style.replace(/text-align:[^;]+;?/, '').trim();
71
+ // Ensure trailing semicolon before concatenating additionalStyle.
72
+ // Both short-circuit paths of this guard (empty `style` or
73
+ // already-has-`;`) are defensive and unreachable with the
74
+ // current QUIKDOWN_STYLES values — istanbul ignore next.
75
+ /* istanbul ignore next */
71
76
  if (style && !style.endsWith(';')) style += ';';
72
77
  }
73
78
 
@@ -99,9 +104,12 @@ function quikdown(markdown, options = {}) {
99
104
  return text.replace(/[&<>"']/g, m => ESC_MAP[m]);
100
105
  }
101
106
 
102
- // Helper to add data-qd attributes for bidirectional support
107
+ // Helper to add data-qd attributes for bidirectional support.
108
+ // The non-bidirectional branch is a trivial no-op arrow; it's exercised in
109
+ // the core bundle but never in quikdown_bd (which always sets bidirectional=true).
110
+ /* istanbul ignore next - trivial no-op fallback */
103
111
  const dataQd = bidirectional ? (marker) => ` data-qd="${escapeHtml(marker)}"` : () => '';
104
-
112
+
105
113
  // Sanitize URLs to prevent XSS attacks
106
114
  function sanitizeUrl(url, allowUnsafe = false) {
107
115
  /* istanbul ignore next - defensive programming, regex ensures url is never empty */
@@ -270,7 +278,7 @@ function quikdown(markdown, options = {}) {
270
278
  html = '<p>' + html + '</p>';
271
279
  } else {
272
280
  // Standard: two spaces at end of line for line breaks
273
- html = html.replace(/ $/gm, `<br${getAttr('br')}>`);
281
+ html = html.replace(/ {2}$/gm, `<br${getAttr('br')}>`);
274
282
 
275
283
  // Paragraphs (double newlines)
276
284
  // Don't add </p> after block elements (they're not in paragraphs)
@@ -299,7 +307,7 @@ function quikdown(markdown, options = {}) {
299
307
  [/(<\/table>)<\/p>/g, '$1'],
300
308
  [/<p>(<pre[^>]*>)/g, '$1'],
301
309
  [/(<\/pre>)<\/p>/g, '$1'],
302
- [new RegExp(`<p>(${PLACEHOLDER_CB}\\d+§)<\/p>`, 'g'), '$1']
310
+ [new RegExp(`<p>(${PLACEHOLDER_CB}\\d+§)</p>`, 'g'), '$1']
303
311
  ];
304
312
 
305
313
  cleanupPatterns.forEach(([pattern, replacement]) => {
@@ -505,10 +513,15 @@ function processLists(text, getAttr, inline_styles, bidirectional) {
505
513
 
506
514
  const lines = text.split('\n');
507
515
  const result = [];
508
- let listStack = []; // Track nested lists
516
+ const listStack = []; // Track nested lists
509
517
 
510
- // Helper to escape HTML for data-qd attributes
511
- const escapeHtml = (text) => text.replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[m]);
518
+ // Helper to escape HTML for data-qd attributes. List markers (`-`, `*`,
519
+ // `+`, `1.`, etc.) never contain HTML-special chars, so the replace
520
+ // callback is defensive-only and never actually fires in practice.
521
+ const escapeHtml = (text) => text.replace(/[&<>"']/g,
522
+ /* istanbul ignore next - defensive: list markers never contain HTML specials */
523
+ m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[m]);
524
+ /* istanbul ignore next - trivial no-op fallback; not exercised via bd bundle */
512
525
  const dataQd = bidirectional ? (marker) => ` data-qd="${escapeHtml(marker)}"` : () => '';
513
526
 
514
527
  for (let i = 0; i < lines.length; i++) {
@@ -680,8 +693,11 @@ function quikdown_bd(markdown, options = {}) {
680
693
  return quikdown(markdown, { ...options, bidirectional: true });
681
694
  }
682
695
 
683
- // Copy all properties and methods from quikdown (including version)
696
+ // Copy all properties and methods from quikdown (including version).
697
+ // Skip `configure` — quikdown_bd provides its own override below, so the
698
+ // inner quikdown.configure is dead code in this bundle.
684
699
  Object.keys(quikdown).forEach(key => {
700
+ if (key === 'configure') return;
685
701
  quikdown_bd[key] = quikdown[key];
686
702
  });
687
703
 
@@ -715,7 +731,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
715
731
 
716
732
  // Process children with context
717
733
  let childContent = '';
718
- for (let child of node.childNodes) {
734
+ for (const child of node.childNodes) {
719
735
  childContent += walkNode(child, { parentTag: tag, ...parentContext });
720
736
  }
721
737
 
@@ -949,7 +965,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
949
965
  let index = 1;
950
966
  const indent = ' '.repeat(depth);
951
967
 
952
- for (let child of listNode.children) {
968
+ for (const child of listNode.children) {
953
969
  if (child.tagName !== 'LI') continue;
954
970
 
955
971
  const dataQd = child.getAttribute('data-qd');
@@ -962,7 +978,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
962
978
  marker = '-';
963
979
  // Get text without the checkbox
964
980
  let text = '';
965
- for (let node of child.childNodes) {
981
+ for (const node of child.childNodes) {
966
982
  if (node.nodeType === Node.TEXT_NODE) {
967
983
  text += node.textContent;
968
984
  } else if (node.tagName && node.tagName !== 'INPUT') {
@@ -973,7 +989,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
973
989
  } else {
974
990
  let itemContent = '';
975
991
 
976
- for (let node of child.childNodes) {
992
+ for (const node of child.childNodes) {
977
993
  if (node.tagName === 'UL' || node.tagName === 'OL') {
978
994
  itemContent += walkList(node, node.tagName === 'OL', depth + 1);
979
995
  } else {
@@ -1002,7 +1018,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
1002
1018
  const headerRow = thead.querySelector('tr');
1003
1019
  if (headerRow) {
1004
1020
  const headers = [];
1005
- for (let th of headerRow.querySelectorAll('th')) {
1021
+ for (const th of headerRow.querySelectorAll('th')) {
1006
1022
  headers.push(th.textContent.trim());
1007
1023
  }
1008
1024
  result += '| ' + headers.join(' | ') + ' |\n';
@@ -1021,9 +1037,9 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
1021
1037
  // Process body
1022
1038
  const tbody = table.querySelector('tbody');
1023
1039
  if (tbody) {
1024
- for (let row of tbody.querySelectorAll('tr')) {
1040
+ for (const row of tbody.querySelectorAll('tr')) {
1025
1041
  const cells = [];
1026
- for (let td of row.querySelectorAll('td')) {
1042
+ for (const td of row.querySelectorAll('td')) {
1027
1043
  cells.push(td.textContent.trim());
1028
1044
  }
1029
1045
  if (cells.length > 0) {
@@ -1045,10 +1061,13 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
1045
1061
  return markdown;
1046
1062
  };
1047
1063
 
1048
- // Override the configure method to return a bidirectional version
1064
+ // Override the configure method to return a bidirectional version.
1065
+ // We delegate to the inner quikdown.configure so the shared closure
1066
+ // machinery is exercised in both bundles (no dead code).
1049
1067
  quikdown_bd.configure = function(options) {
1068
+ const innerParser = quikdown.configure({ ...options, bidirectional: true });
1050
1069
  return function(markdown) {
1051
- return quikdown_bd(markdown, options);
1070
+ return innerParser(markdown);
1052
1071
  };
1053
1072
  };
1054
1073
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * quikdown_bd - Bidirectional Markdown Parser
3
- * @version 1.1.1
3
+ * @version 1.2.3
4
4
  * @license BSD-2-Clause
5
5
  * @copyright DeftIO 2025
6
6
  */
@@ -18,7 +18,7 @@
18
18
  */
19
19
 
20
20
  // Version will be injected at build time
21
- const quikdownVersion = '1.1.1';
21
+ const quikdownVersion = '1.2.3';
22
22
 
23
23
  // Constants for reuse
24
24
  const CLASS_PREFIX = 'quikdown-';
@@ -66,6 +66,11 @@ function createGetAttr(inline_styles, styles) {
66
66
  // Remove default text-align if we're adding a different alignment
67
67
  if (additionalStyle && additionalStyle.includes('text-align') && style && style.includes('text-align')) {
68
68
  style = style.replace(/text-align:[^;]+;?/, '').trim();
69
+ // Ensure trailing semicolon before concatenating additionalStyle.
70
+ // Both short-circuit paths of this guard (empty `style` or
71
+ // already-has-`;`) are defensive and unreachable with the
72
+ // current QUIKDOWN_STYLES values — istanbul ignore next.
73
+ /* istanbul ignore next */
69
74
  if (style && !style.endsWith(';')) style += ';';
70
75
  }
71
76
 
@@ -97,9 +102,12 @@ function quikdown(markdown, options = {}) {
97
102
  return text.replace(/[&<>"']/g, m => ESC_MAP[m]);
98
103
  }
99
104
 
100
- // Helper to add data-qd attributes for bidirectional support
105
+ // Helper to add data-qd attributes for bidirectional support.
106
+ // The non-bidirectional branch is a trivial no-op arrow; it's exercised in
107
+ // the core bundle but never in quikdown_bd (which always sets bidirectional=true).
108
+ /* istanbul ignore next - trivial no-op fallback */
101
109
  const dataQd = bidirectional ? (marker) => ` data-qd="${escapeHtml(marker)}"` : () => '';
102
-
110
+
103
111
  // Sanitize URLs to prevent XSS attacks
104
112
  function sanitizeUrl(url, allowUnsafe = false) {
105
113
  /* istanbul ignore next - defensive programming, regex ensures url is never empty */
@@ -268,7 +276,7 @@ function quikdown(markdown, options = {}) {
268
276
  html = '<p>' + html + '</p>';
269
277
  } else {
270
278
  // Standard: two spaces at end of line for line breaks
271
- html = html.replace(/ $/gm, `<br${getAttr('br')}>`);
279
+ html = html.replace(/ {2}$/gm, `<br${getAttr('br')}>`);
272
280
 
273
281
  // Paragraphs (double newlines)
274
282
  // Don't add </p> after block elements (they're not in paragraphs)
@@ -297,7 +305,7 @@ function quikdown(markdown, options = {}) {
297
305
  [/(<\/table>)<\/p>/g, '$1'],
298
306
  [/<p>(<pre[^>]*>)/g, '$1'],
299
307
  [/(<\/pre>)<\/p>/g, '$1'],
300
- [new RegExp(`<p>(${PLACEHOLDER_CB}\\d+§)<\/p>`, 'g'), '$1']
308
+ [new RegExp(`<p>(${PLACEHOLDER_CB}\\d+§)</p>`, 'g'), '$1']
301
309
  ];
302
310
 
303
311
  cleanupPatterns.forEach(([pattern, replacement]) => {
@@ -503,10 +511,15 @@ function processLists(text, getAttr, inline_styles, bidirectional) {
503
511
 
504
512
  const lines = text.split('\n');
505
513
  const result = [];
506
- let listStack = []; // Track nested lists
514
+ const listStack = []; // Track nested lists
507
515
 
508
- // Helper to escape HTML for data-qd attributes
509
- const escapeHtml = (text) => text.replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[m]);
516
+ // Helper to escape HTML for data-qd attributes. List markers (`-`, `*`,
517
+ // `+`, `1.`, etc.) never contain HTML-special chars, so the replace
518
+ // callback is defensive-only and never actually fires in practice.
519
+ const escapeHtml = (text) => text.replace(/[&<>"']/g,
520
+ /* istanbul ignore next - defensive: list markers never contain HTML specials */
521
+ m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[m]);
522
+ /* istanbul ignore next - trivial no-op fallback; not exercised via bd bundle */
510
523
  const dataQd = bidirectional ? (marker) => ` data-qd="${escapeHtml(marker)}"` : () => '';
511
524
 
512
525
  for (let i = 0; i < lines.length; i++) {
@@ -678,8 +691,11 @@ function quikdown_bd(markdown, options = {}) {
678
691
  return quikdown(markdown, { ...options, bidirectional: true });
679
692
  }
680
693
 
681
- // Copy all properties and methods from quikdown (including version)
694
+ // Copy all properties and methods from quikdown (including version).
695
+ // Skip `configure` — quikdown_bd provides its own override below, so the
696
+ // inner quikdown.configure is dead code in this bundle.
682
697
  Object.keys(quikdown).forEach(key => {
698
+ if (key === 'configure') return;
683
699
  quikdown_bd[key] = quikdown[key];
684
700
  });
685
701
 
@@ -713,7 +729,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
713
729
 
714
730
  // Process children with context
715
731
  let childContent = '';
716
- for (let child of node.childNodes) {
732
+ for (const child of node.childNodes) {
717
733
  childContent += walkNode(child, { parentTag: tag, ...parentContext });
718
734
  }
719
735
 
@@ -947,7 +963,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
947
963
  let index = 1;
948
964
  const indent = ' '.repeat(depth);
949
965
 
950
- for (let child of listNode.children) {
966
+ for (const child of listNode.children) {
951
967
  if (child.tagName !== 'LI') continue;
952
968
 
953
969
  const dataQd = child.getAttribute('data-qd');
@@ -960,7 +976,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
960
976
  marker = '-';
961
977
  // Get text without the checkbox
962
978
  let text = '';
963
- for (let node of child.childNodes) {
979
+ for (const node of child.childNodes) {
964
980
  if (node.nodeType === Node.TEXT_NODE) {
965
981
  text += node.textContent;
966
982
  } else if (node.tagName && node.tagName !== 'INPUT') {
@@ -971,7 +987,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
971
987
  } else {
972
988
  let itemContent = '';
973
989
 
974
- for (let node of child.childNodes) {
990
+ for (const node of child.childNodes) {
975
991
  if (node.tagName === 'UL' || node.tagName === 'OL') {
976
992
  itemContent += walkList(node, node.tagName === 'OL', depth + 1);
977
993
  } else {
@@ -1000,7 +1016,7 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
1000
1016
  const headerRow = thead.querySelector('tr');
1001
1017
  if (headerRow) {
1002
1018
  const headers = [];
1003
- for (let th of headerRow.querySelectorAll('th')) {
1019
+ for (const th of headerRow.querySelectorAll('th')) {
1004
1020
  headers.push(th.textContent.trim());
1005
1021
  }
1006
1022
  result += '| ' + headers.join(' | ') + ' |\n';
@@ -1019,9 +1035,9 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
1019
1035
  // Process body
1020
1036
  const tbody = table.querySelector('tbody');
1021
1037
  if (tbody) {
1022
- for (let row of tbody.querySelectorAll('tr')) {
1038
+ for (const row of tbody.querySelectorAll('tr')) {
1023
1039
  const cells = [];
1024
- for (let td of row.querySelectorAll('td')) {
1040
+ for (const td of row.querySelectorAll('td')) {
1025
1041
  cells.push(td.textContent.trim());
1026
1042
  }
1027
1043
  if (cells.length > 0) {
@@ -1043,10 +1059,13 @@ quikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {
1043
1059
  return markdown;
1044
1060
  };
1045
1061
 
1046
- // Override the configure method to return a bidirectional version
1062
+ // Override the configure method to return a bidirectional version.
1063
+ // We delegate to the inner quikdown.configure so the shared closure
1064
+ // machinery is exercised in both bundles (no dead code).
1047
1065
  quikdown_bd.configure = function(options) {
1066
+ const innerParser = quikdown.configure({ ...options, bidirectional: true });
1048
1067
  return function(markdown) {
1049
- return quikdown_bd(markdown, options);
1068
+ return innerParser(markdown);
1050
1069
  };
1051
1070
  };
1052
1071
 
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * quikdown_bd - Bidirectional Markdown Parser
3
- * @version 1.1.1
3
+ * @version 1.2.3
4
4
  * @license BSD-2-Clause
5
5
  * @copyright DeftIO 2025
6
6
  */
7
- const e="quikdown-",t="§CB",n={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},r={h1:"font-size:2em;font-weight:600;margin:.67em 0;text-align:left",h2:"font-size:1.5em;font-weight:600;margin:.83em 0",h3:"font-size:1.25em;font-weight:600;margin:1em 0",h4:"font-size:1em;font-weight:600;margin:1.33em 0",h5:"font-size:.875em;font-weight:600;margin:1.67em 0",h6:"font-size:.85em;font-weight:600;margin:2em 0",pre:"background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0",code:"background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace",blockquote:"border-left:4px solid #ddd;margin-left:0;padding-left:1em",table:"border-collapse:collapse;width:100%;margin:1em 0",th:"border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left",td:"border:1px solid #ddd;padding:8px;text-align:left",hr:"border:none;border-top:1px solid #ddd;margin:1em 0",img:"max-width:100%;height:auto",a:"color:#06c;text-decoration:underline",strong:"font-weight:bold",em:"font-style:italic",del:"text-decoration:line-through",ul:"margin:.5em 0;padding-left:2em",ol:"margin:.5em 0;padding-left:2em",li:"margin:.25em 0","task-item":"list-style:none","task-checkbox":"margin-right:.5em"};function o(o,a={}){if(!o||"string"!=typeof o)return"";const{fence_plugin:l,inline_styles:i=!1,bidirectional:s=!1,lazy_linefeeds:d=!1}=a,u=function(t,n){return function(r,o=""){if(t){let e=n[r];return e||o?(o&&o.includes("text-align")&&e&&e.includes("text-align")&&(e=e.replace(/text-align:[^;]+;?/,"").trim(),e&&!e.endsWith(";")&&(e+=";")),` style="${o?e?`${e}${o}`:o:e}"`):""}{const t=` class="${e}${r}"`;return o?`${t} style="${o}"`:t}}}(i,r);function $(e){return e.replace(/[&<>"']/g,e=>n[e])}const f=s?e=>` data-qd="${$(e)}"`:()=>"";function g(e,t=!1){if(!e)return"";if(t)return e;const n=e.trim(),r=n.toLowerCase(),o=["javascript:","vbscript:","data:"];for(const e of o)if(r.startsWith(e))return"data:"===e&&r.startsWith("data:image/")?n:"#";return n}let p=o;const h=[],m=[];p=p.replace(/^(```|~~~)([^\n]*)\n([\s\S]*?)^\1$/gm,(e,n,r,o)=>{const a=`${t}${h.length}§`,c=r?r.trim():"";return l&&l.render&&"function"==typeof l.render?h.push({lang:c,code:o.trimEnd(),custom:!0,fence:n,hasReverse:!!l.reverse}):h.push({lang:c,code:$(o.trimEnd()),custom:!1,fence:n}),a}),p=p.replace(/`([^`]+)`/g,(e,t)=>{const n=`§IC${m.length}§`;return m.push($(t)),n}),p=$(p),p=function(e,t){const n=e.split("\n"),r=[];let o=!1,a=[];for(let e=0;e<n.length;e++){const l=n[e].trim();if(l.includes("|")&&(l.startsWith("|")||/[^\\|]/.test(l)))o||(o=!0,a=[]),a.push(l);else{if(o){const e=c(a,t);e?r.push(e):r.push(...a),o=!1,a=[]}r.push(n[e])}}if(o&&a.length>0){const e=c(a,t);e?r.push(e):r.push(...a)}return r.join("\n")}(p,u),p=p.replace(/^(#{1,6})\s+(.+?)\s*#*$/gm,(e,t,n)=>{const r=t.length;return`<h${r}${u("h"+r)}${f(t)}>${n}</h${r}>`}),p=p.replace(/^&gt;\s+(.+)$/gm,`<blockquote${u("blockquote")}>$1</blockquote>`),p=p.replace(/<\/blockquote>\n<blockquote>/g,"\n"),p=p.replace(/^---+\s*$/gm,`<hr${u("hr")}>`),p=function(t,n,r,o){const a=t.split("\n"),c=[];let l=[];const i=e=>e.replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[e])),s=o?e=>` data-qd="${i(e)}"`:()=>"";for(let t=0;t<a.length;t++){const o=a[t],i=o.match(/^(\s*)([*\-+]|\d+\.)\s+(.+)$/);if(i){const[,t,o,a]=i,d=Math.floor(t.length/2),u=/^\d+\./.test(o),$=u?"ol":"ul";let f=a,g="";const p=a.match(/^\[([x ])\]\s+(.*)$/i);if(p&&!u){const[,t,n]=p,o="x"===t.toLowerCase();f=`<input type="checkbox"${r?' style="margin-right:.5em"':` class="${e}task-checkbox"`}${o?" checked":""} disabled> ${n}`,g=r?' style="list-style:none"':` class="${e}task-item"`}for(;l.length>d+1;){const e=l.pop();c.push(`</${e.type}>`)}if(l.length===d)l.push({type:$,level:d}),c.push(`<${$}${n($)}>`);else if(l.length===d+1){const e=l[l.length-1];e.type!==$&&(c.push(`</${e.type}>`),l.pop(),l.push({type:$,level:d}),c.push(`<${$}${n($)}>`))}const h=g||n("li");c.push(`<li${h}${s(o)}>${f}</li>`)}else{for(;l.length>0;){const e=l.pop();c.push(`</${e.type}>`)}c.push(o)}}for(;l.length>0;){const e=l.pop();c.push(`</${e.type}>`)}return c.join("\n")}(p,u,i,s),p=p.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,(e,t,n)=>{const r=g(n,a.allow_unsafe_urls),o=s&&t?` data-qd-alt="${$(t)}"`:"",c=s?` data-qd-src="${$(n)}"`:"";return`<img${u("img")} src="${r}" alt="${t}"${o}${c}${f("!")}>`}),p=p.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,t,n)=>{const r=g(n,a.allow_unsafe_urls),o=/^https?:\/\//i.test(r)?' rel="noopener noreferrer"':"",c=s?` data-qd-text="${$(t)}"`:"";return`<a${u("a")} href="${r}"${o}${c}${f("[")}>${t}</a>`}),p=p.replace(/(^|\s)(https?:\/\/[^\s<]+)/g,(e,t,n)=>{const r=g(n,a.allow_unsafe_urls);return`${t}<a${u("a")} href="${r}" rel="noopener noreferrer">${n}</a>`});if([[/\*\*(.+?)\*\*/g,"strong","**"],[/__(.+?)__/g,"strong","__"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em","*"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em","_"],[/~~(.+?)~~/g,"del","~~"]].forEach(([e,t,n])=>{p=p.replace(e,`<${t}${u(t)}${f(n)}>$1</${t}>`)}),d){const e=[];let t=0;p=p.replace(/<(table|[uo]l)[^>]*>[\s\S]*?<\/\1>/g,n=>(e[t]=n,`§B${t++}§`)),p=p.replace(/\n\n+/g,"§P§").replace(/(<\/(?:h[1-6]|blockquote|pre)>)\n/g,"$1§N§").replace(/(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)\n/g,"$1§N§").replace(/\n(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)/g,"§N§$1").replace(/\n(§B\d+§)/g,"§N§$1").replace(/(§B\d+§)\n/g,"$1§N§").replace(/\n/g,`<br${u("br")}>`).replace(/§N§/g,"\n").replace(/§P§/g,"</p><p>"),e.forEach((e,t)=>p=p.replace(`§B${t}§`,e)),p="<p>"+p+"</p>"}else p=p.replace(/ $/gm,`<br${u("br")}>`),p=p.replace(/\n\n+/g,(e,t)=>p.substring(0,t).match(/<\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)?"<p>":"</p><p>"),p="<p>"+p+"</p>";return[[/<p><\/p>/g,""],[/<p>(<h[1-6][^>]*>)/g,"$1"],[/(<\/h[1-6]>)<\/p>/g,"$1"],[/<p>(<blockquote[^>]*>)/g,"$1"],[/(<\/blockquote>)<\/p>/g,"$1"],[/<p>(<ul[^>]*>|<ol[^>]*>)/g,"$1"],[/(<\/ul>|<\/ol>)<\/p>/g,"$1"],[/<p>(<hr[^>]*>)<\/p>/g,"$1"],[/<p>(<table[^>]*>)/g,"$1"],[/(<\/table>)<\/p>/g,"$1"],[/<p>(<pre[^>]*>)/g,"$1"],[/(<\/pre>)<\/p>/g,"$1"],[new RegExp(`<p>(${t}\\d+§)</p>`,"g"),"$1"]].forEach(([e,t])=>{p=p.replace(e,t)}),p=p.replace(/(<\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\n([^<])/g,"$1\n<p>$2"),h.forEach((e,n)=>{let r;if(e.custom&&l&&l.render)if(r=l.render(e.code,e.lang),void 0===r){const t=!i&&e.lang?` class="language-${e.lang}"`:"",n=i?u("code"):t,o=s&&e.lang?` data-qd-lang="${$(e.lang)}"`:"",a=s?` data-qd-fence="${$(e.fence)}"`:"";r=`<pre${u("pre")}${a}${o}><code${n}>${$(e.code)}</code></pre>`}else s&&(r=r.replace(/^<(\w+)/,`<$1 data-qd-fence="${$(e.fence)}" data-qd-lang="${$(e.lang)}" data-qd-source="${$(e.code)}"`));else{const t=!i&&e.lang?` class="language-${e.lang}"`:"",n=i?u("code"):t,o=s&&e.lang?` data-qd-lang="${$(e.lang)}"`:"",a=s?` data-qd-fence="${$(e.fence)}"`:"";r=`<pre${u("pre")}${a}${o}><code${n}>${e.code}</code></pre>`}const o=`${t}${n}§`;p=p.replace(o,r)}),m.forEach((e,t)=>{const n=`§IC${t}§`;p=p.replace(n,`<code${u("code")}${f("`")}>${e}</code>`)}),p.trim()}function a(e,t){return[[/\*\*(.+?)\*\*/g,"strong"],[/__(.+?)__/g,"strong"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em"],[/~~(.+?)~~/g,"del"],[/`([^`]+)`/g,"code"]].forEach(([n,r])=>{e=e.replace(n,`<${r}${t(r)}>$1</${r}>`)}),e}function c(e,t){if(e.length<2)return null;let n=-1;for(let t=1;t<e.length;t++)if(/^\|?[\s\-:|]+\|?$/.test(e[t])&&e[t].includes("-")){n=t;break}if(-1===n)return null;const r=e.slice(0,n),o=e.slice(n+1),c=e[n].trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"});let l=`<table${t("table")}>\n`;return l+=`<thead${t("thead")}>\n`,r.forEach(e=>{l+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=c[n]&&"left"!==c[n]?`text-align:${c[n]}`:"",o=a(e.trim(),t);l+=`<th${t("th",r)}>${o}</th>\n`}),l+="</tr>\n"}),l+="</thead>\n",o.length>0&&(l+=`<tbody${t("tbody")}>\n`,o.forEach(e=>{l+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=c[n]&&"left"!==c[n]?`text-align:${c[n]}`:"",o=a(e.trim(),t);l+=`<td${t("td",r)}>${o}</td>\n`}),l+="</tr>\n"}),l+="</tbody>\n"),l+="</table>",l}function l(e,t={}){return o(e,{...t,bidirectional:!0})}o.emitStyles=function(e="quikdown-",t="light"){const n=r,o={"#f4f4f4":"#2a2a2a","#f0f0f0":"#2a2a2a","#f2f2f2":"#2a2a2a","#ddd":"#3a3a3a","#06c":"#6db3f2",_textColor:"#e0e0e0"},a={_textColor:"#333"};let c="";for(const[r,l]of Object.entries(n)){let n=l;if("dark"===t&&o){for(const[e,t]of Object.entries(o))e.startsWith("_")||(n=n.replace(new RegExp(e,"g"),t));["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(r)&&(n+=`;color:${o._textColor}`)}else if("light"===t&&a){["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(r)&&(n+=`;color:${a._textColor}`)}c+=`.${e}${r} { ${n} }\n`}return c},o.configure=function(e){return function(t){return o(t,e)}},o.version="1.1.1","undefined"!=typeof module&&module.exports&&(module.exports=o),"undefined"!=typeof window&&(window.quikdown=o),Object.keys(o).forEach(e=>{l[e]=o[e]}),l.toMarkdown=function(e,t={}){let n;if("string"==typeof e)n=document.createElement("div"),n.innerHTML=e;else{if(!(e instanceof Element))return"";n=e}function r(e,n={}){if(e.nodeType===Node.TEXT_NODE)return e.textContent;if(e.nodeType!==Node.ELEMENT_NODE)return"";const a=e.tagName.toLowerCase(),c=e.getAttribute("data-qd");let l="";for(let t of e.childNodes)l+=r(t,{parentTag:a,...n});switch(a){case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":const n=parseInt(a[1]);return`${c||"#".repeat(n)} ${l.trim()}\n\n`;case"strong":case"b":if(!l)return"";const r=c||"**";return`${r}${l}${r}`;case"em":case"i":if(!l)return"";const i=c||"*";return`${i}${l}${i}`;case"del":case"s":case"strike":if(!l)return"";const s=c||"~~";return`${s}${l}${s}`;case"code":if(!l)return"";const d=c||"`";return`${d}${l}${d}`;case"pre":const u=e.getAttribute("data-qd-fence")||c||"```",$=e.getAttribute("data-qd-lang")||"";if(t.fence_plugin&&t.fence_plugin.reverse&&$)try{const n=t.fence_plugin.reverse(e);if(n&&n.content){const e=n.fence||u;return`${e}${n.lang||$}\n${n.content}\n${e}\n\n`}}catch(e){console.warn("Fence reverse handler error:",e)}const f=e.getAttribute("data-qd-source");if(f)return`${u}${$}\n${f}\n${u}\n\n`;const g=e.querySelector("code");return`${u}${$}\n${(g?g.textContent:l).trimEnd()}\n${u}\n\n`;case"blockquote":const p=c||">";return l.trim().split("\n").map(e=>`${p} ${e}`).join("\n")+"\n\n";case"hr":return`${c||"---"}\n\n`;case"br":return`${c||" "}\n`;case"a":const h=e.getAttribute("data-qd-text")||l.trim(),m=e.getAttribute("href")||"";return h!==m||c?`[${h}](${m})`:`<${m}>`;case"img":return`${c||"!"}[${e.getAttribute("data-qd-alt")||e.getAttribute("alt")||""}](${e.getAttribute("data-qd-src")||e.getAttribute("src")||""})`;case"ul":case"ol":return o(e,"ol"===a)+"\n";case"li":case"span":default:return l;case"table":return function(e){let t="";const n=e.getAttribute("data-qd-align"),r=n?n.split(","):[],o=e.querySelector("thead");if(o){const e=o.querySelector("tr");if(e){const n=[];for(let t of e.querySelectorAll("th"))n.push(t.textContent.trim());t+="| "+n.join(" | ")+" |\n";t+="| "+n.map((e,t)=>{const n=r[t]||"left";return"center"===n?":---:":"right"===n?"---:":"---"}).join(" | ")+" |\n"}}const a=e.querySelector("tbody");if(a)for(let e of a.querySelectorAll("tr")){const n=[];for(let t of e.querySelectorAll("td"))n.push(t.textContent.trim());n.length>0&&(t+="| "+n.join(" | ")+" |\n")}return t.trim()}(e)+"\n\n";case"p":if(l.trim()){const e=l.split("\n");let t=l.trim();if(e.length>1){let n=0;for(let t=e.length-1;t>=0&&""===e[t].trim();t--)n++;if(n>0)return t+="\n ",t+"\n"}return t+"\n\n"}return"";case"div":const b=e.getAttribute("data-qd-lang"),q=e.getAttribute("data-qd-fence");if(b&&t.fence_plugin&&t.fence_plugin.reverse)try{const n=t.fence_plugin.reverse(e);if(n&&n.content){const e=n.fence||q||"```";return`${e}${n.lang||b}\n${n.content}\n${e}\n\n`}}catch(e){console.warn("Fence reverse handler error:",e)}const x=e.getAttribute("data-qd-source");if(x&&q)return`${q}${b||""}\n${x}\n${q}\n\n`;if(e.classList&&e.classList.contains("mermaid-container")){const t=e.getAttribute("data-qd-fence")||"```",n=e.getAttribute("data-qd-lang")||"mermaid",r=e.getAttribute("data-qd-source");if(r){const e=document.createElement("textarea");e.innerHTML=r;return`${t}${n}\n${e.value}\n${t}\n\n`}const o=e.querySelector("pre.mermaid");if(o){const e=o.getAttribute("data-qd-source");if(e){const r=document.createElement("textarea");r.innerHTML=e;return`${t}${n}\n${r.value}\n${t}\n\n`}}const a=e.querySelector(".mermaid-source");if(a){const e=document.createElement("div");e.innerHTML=a.innerHTML;return`${t}${n}\n${e.textContent}\n${t}\n\n`}const c=e.querySelector(".mermaid");if(c&&c.textContent.includes("graph"))return`${t}${n}\n${c.textContent.trim()}\n${t}\n\n`}if(e.classList&&e.classList.contains("mermaid")){const t=e.getAttribute("data-qd-fence")||"```";return`${t}${e.getAttribute("data-qd-lang")||"mermaid"}\n${e.textContent.trim()}\n${t}\n\n`}return l}}function o(e,t,n=0){let a="",c=1;const l=" ".repeat(n);for(let i of e.children){if("LI"!==i.tagName)continue;let e=i.getAttribute("data-qd")||(t?`${c}.`:"-");const s=i.querySelector('input[type="checkbox"]');if(s){const t=s.checked?"x":" ";e="-";let n="";for(let e of i.childNodes)e.nodeType===Node.TEXT_NODE?n+=e.textContent:e.tagName&&"INPUT"!==e.tagName&&(n+=r(e));a+=`${l}${e} [${t}] ${n.trim()}\n`}else{let t="";for(let e of i.childNodes)"UL"===e.tagName||"OL"===e.tagName?t+=o(e,"OL"===e.tagName,n+1):t+=r(e);a+=`${l}${e} ${t.trim()}\n`}c++}return a}let a=r(n);return a=a.replace(/\n{3,}/g,"\n\n"),a=a.trim(),a},l.configure=function(e){return function(t){return l(t,e)}},"undefined"!=typeof module&&module.exports&&(module.exports=l),"undefined"!=typeof window&&(window.quikdown_bd=l);export{l as default};
7
+ const e="quikdown-",t="§CB",n={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},r={h1:"font-size:2em;font-weight:600;margin:.67em 0;text-align:left",h2:"font-size:1.5em;font-weight:600;margin:.83em 0",h3:"font-size:1.25em;font-weight:600;margin:1em 0",h4:"font-size:1em;font-weight:600;margin:1.33em 0",h5:"font-size:.875em;font-weight:600;margin:1.67em 0",h6:"font-size:.85em;font-weight:600;margin:2em 0",pre:"background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0",code:"background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace",blockquote:"border-left:4px solid #ddd;margin-left:0;padding-left:1em",table:"border-collapse:collapse;width:100%;margin:1em 0",th:"border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left",td:"border:1px solid #ddd;padding:8px;text-align:left",hr:"border:none;border-top:1px solid #ddd;margin:1em 0",img:"max-width:100%;height:auto",a:"color:#06c;text-decoration:underline",strong:"font-weight:bold",em:"font-style:italic",del:"text-decoration:line-through",ul:"margin:.5em 0;padding-left:2em",ol:"margin:.5em 0;padding-left:2em",li:"margin:.25em 0","task-item":"list-style:none","task-checkbox":"margin-right:.5em"};function o(o,c={}){if(!o||"string"!=typeof o)return"";const{fence_plugin:l,inline_styles:i=!1,bidirectional:s=!1,lazy_linefeeds:d=!1}=c,u=function(t,n){return function(r,o=""){if(t){let e=n[r];return e||o?(o&&o.includes("text-align")&&e&&e.includes("text-align")&&(e=e.replace(/text-align:[^;]+;?/,"").trim(),e&&!e.endsWith(";")&&(e+=";")),` style="${o?e?`${e}${o}`:o:e}"`):""}{const t=` class="${e}${r}"`;return o?`${t} style="${o}"`:t}}}(i,r);function $(e){return e.replace(/[&<>"']/g,e=>n[e])}const f=s?e=>` data-qd="${$(e)}"`:()=>"";function g(e,t=!1){if(!e)return"";if(t)return e;const n=e.trim(),r=n.toLowerCase(),o=["javascript:","vbscript:","data:"];for(const e of o)if(r.startsWith(e))return"data:"===e&&r.startsWith("data:image/")?n:"#";return n}let p=o;const h=[],m=[];p=p.replace(/^(```|~~~)([^\n]*)\n([\s\S]*?)^\1$/gm,(e,n,r,o)=>{const c=`${t}${h.length}§`,a=r?r.trim():"";return l&&l.render&&"function"==typeof l.render?h.push({lang:a,code:o.trimEnd(),custom:!0,fence:n,hasReverse:!!l.reverse}):h.push({lang:a,code:$(o.trimEnd()),custom:!1,fence:n}),c}),p=p.replace(/`([^`]+)`/g,(e,t)=>{const n=`§IC${m.length}§`;return m.push($(t)),n}),p=$(p),p=function(e,t){const n=e.split("\n"),r=[];let o=!1,c=[];for(let e=0;e<n.length;e++){const l=n[e].trim();if(l.includes("|")&&(l.startsWith("|")||/[^\\|]/.test(l)))o||(o=!0,c=[]),c.push(l);else{if(o){const e=a(c,t);e?r.push(e):r.push(...c),o=!1,c=[]}r.push(n[e])}}if(o&&c.length>0){const e=a(c,t);e?r.push(e):r.push(...c)}return r.join("\n")}(p,u),p=p.replace(/^(#{1,6})\s+(.+?)\s*#*$/gm,(e,t,n)=>{const r=t.length;return`<h${r}${u("h"+r)}${f(t)}>${n}</h${r}>`}),p=p.replace(/^&gt;\s+(.+)$/gm,`<blockquote${u("blockquote")}>$1</blockquote>`),p=p.replace(/<\/blockquote>\n<blockquote>/g,"\n"),p=p.replace(/^---+\s*$/gm,`<hr${u("hr")}>`),p=function(t,n,r,o){const c=t.split("\n"),a=[],l=[],i=e=>e.replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[e])),s=o?e=>` data-qd="${i(e)}"`:()=>"";for(let t=0;t<c.length;t++){const o=c[t],i=o.match(/^(\s*)([*\-+]|\d+\.)\s+(.+)$/);if(i){const[,t,o,c]=i,d=Math.floor(t.length/2),u=/^\d+\./.test(o),$=u?"ol":"ul";let f=c,g="";const p=c.match(/^\[([x ])\]\s+(.*)$/i);if(p&&!u){const[,t,n]=p,o="x"===t.toLowerCase();f=`<input type="checkbox"${r?' style="margin-right:.5em"':` class="${e}task-checkbox"`}${o?" checked":""} disabled> ${n}`,g=r?' style="list-style:none"':` class="${e}task-item"`}for(;l.length>d+1;){const e=l.pop();a.push(`</${e.type}>`)}if(l.length===d)l.push({type:$,level:d}),a.push(`<${$}${n($)}>`);else if(l.length===d+1){const e=l[l.length-1];e.type!==$&&(a.push(`</${e.type}>`),l.pop(),l.push({type:$,level:d}),a.push(`<${$}${n($)}>`))}const h=g||n("li");a.push(`<li${h}${s(o)}>${f}</li>`)}else{for(;l.length>0;){const e=l.pop();a.push(`</${e.type}>`)}a.push(o)}}for(;l.length>0;){const e=l.pop();a.push(`</${e.type}>`)}return a.join("\n")}(p,u,i,s),p=p.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,(e,t,n)=>{const r=g(n,c.allow_unsafe_urls),o=s&&t?` data-qd-alt="${$(t)}"`:"",a=s?` data-qd-src="${$(n)}"`:"";return`<img${u("img")} src="${r}" alt="${t}"${o}${a}${f("!")}>`}),p=p.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,t,n)=>{const r=g(n,c.allow_unsafe_urls),o=/^https?:\/\//i.test(r)?' rel="noopener noreferrer"':"",a=s?` data-qd-text="${$(t)}"`:"";return`<a${u("a")} href="${r}"${o}${a}${f("[")}>${t}</a>`}),p=p.replace(/(^|\s)(https?:\/\/[^\s<]+)/g,(e,t,n)=>{const r=g(n,c.allow_unsafe_urls);return`${t}<a${u("a")} href="${r}" rel="noopener noreferrer">${n}</a>`});if([[/\*\*(.+?)\*\*/g,"strong","**"],[/__(.+?)__/g,"strong","__"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em","*"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em","_"],[/~~(.+?)~~/g,"del","~~"]].forEach(([e,t,n])=>{p=p.replace(e,`<${t}${u(t)}${f(n)}>$1</${t}>`)}),d){const e=[];let t=0;p=p.replace(/<(table|[uo]l)[^>]*>[\s\S]*?<\/\1>/g,n=>(e[t]=n,`§B${t++}§`)),p=p.replace(/\n\n+/g,"§P§").replace(/(<\/(?:h[1-6]|blockquote|pre)>)\n/g,"$1§N§").replace(/(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)\n/g,"$1§N§").replace(/\n(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)/g,"§N§$1").replace(/\n(§B\d+§)/g,"§N§$1").replace(/(§B\d+§)\n/g,"$1§N§").replace(/\n/g,`<br${u("br")}>`).replace(/§N§/g,"\n").replace(/§P§/g,"</p><p>"),e.forEach((e,t)=>p=p.replace(`§B${t}§`,e)),p="<p>"+p+"</p>"}else p=p.replace(/ {2}$/gm,`<br${u("br")}>`),p=p.replace(/\n\n+/g,(e,t)=>p.substring(0,t).match(/<\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)?"<p>":"</p><p>"),p="<p>"+p+"</p>";return[[/<p><\/p>/g,""],[/<p>(<h[1-6][^>]*>)/g,"$1"],[/(<\/h[1-6]>)<\/p>/g,"$1"],[/<p>(<blockquote[^>]*>)/g,"$1"],[/(<\/blockquote>)<\/p>/g,"$1"],[/<p>(<ul[^>]*>|<ol[^>]*>)/g,"$1"],[/(<\/ul>|<\/ol>)<\/p>/g,"$1"],[/<p>(<hr[^>]*>)<\/p>/g,"$1"],[/<p>(<table[^>]*>)/g,"$1"],[/(<\/table>)<\/p>/g,"$1"],[/<p>(<pre[^>]*>)/g,"$1"],[/(<\/pre>)<\/p>/g,"$1"],[new RegExp(`<p>(${t}\\d+§)</p>`,"g"),"$1"]].forEach(([e,t])=>{p=p.replace(e,t)}),p=p.replace(/(<\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\n([^<])/g,"$1\n<p>$2"),h.forEach((e,n)=>{let r;if(e.custom&&l&&l.render)if(r=l.render(e.code,e.lang),void 0===r){const t=!i&&e.lang?` class="language-${e.lang}"`:"",n=i?u("code"):t,o=s&&e.lang?` data-qd-lang="${$(e.lang)}"`:"",c=s?` data-qd-fence="${$(e.fence)}"`:"";r=`<pre${u("pre")}${c}${o}><code${n}>${$(e.code)}</code></pre>`}else s&&(r=r.replace(/^<(\w+)/,`<$1 data-qd-fence="${$(e.fence)}" data-qd-lang="${$(e.lang)}" data-qd-source="${$(e.code)}"`));else{const t=!i&&e.lang?` class="language-${e.lang}"`:"",n=i?u("code"):t,o=s&&e.lang?` data-qd-lang="${$(e.lang)}"`:"",c=s?` data-qd-fence="${$(e.fence)}"`:"";r=`<pre${u("pre")}${c}${o}><code${n}>${e.code}</code></pre>`}const o=`${t}${n}§`;p=p.replace(o,r)}),m.forEach((e,t)=>{const n=`§IC${t}§`;p=p.replace(n,`<code${u("code")}${f("`")}>${e}</code>`)}),p.trim()}function c(e,t){return[[/\*\*(.+?)\*\*/g,"strong"],[/__(.+?)__/g,"strong"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em"],[/~~(.+?)~~/g,"del"],[/`([^`]+)`/g,"code"]].forEach(([n,r])=>{e=e.replace(n,`<${r}${t(r)}>$1</${r}>`)}),e}function a(e,t){if(e.length<2)return null;let n=-1;for(let t=1;t<e.length;t++)if(/^\|?[\s\-:|]+\|?$/.test(e[t])&&e[t].includes("-")){n=t;break}if(-1===n)return null;const r=e.slice(0,n),o=e.slice(n+1),a=e[n].trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"});let l=`<table${t("table")}>\n`;return l+=`<thead${t("thead")}>\n`,r.forEach(e=>{l+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=a[n]&&"left"!==a[n]?`text-align:${a[n]}`:"",o=c(e.trim(),t);l+=`<th${t("th",r)}>${o}</th>\n`}),l+="</tr>\n"}),l+="</thead>\n",o.length>0&&(l+=`<tbody${t("tbody")}>\n`,o.forEach(e=>{l+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=a[n]&&"left"!==a[n]?`text-align:${a[n]}`:"",o=c(e.trim(),t);l+=`<td${t("td",r)}>${o}</td>\n`}),l+="</tr>\n"}),l+="</tbody>\n"),l+="</table>",l}function l(e,t={}){return o(e,{...t,bidirectional:!0})}o.emitStyles=function(e="quikdown-",t="light"){const n=r,o={"#f4f4f4":"#2a2a2a","#f0f0f0":"#2a2a2a","#f2f2f2":"#2a2a2a","#ddd":"#3a3a3a","#06c":"#6db3f2",_textColor:"#e0e0e0"},c={_textColor:"#333"};let a="";for(const[r,l]of Object.entries(n)){let n=l;if("dark"===t&&o){for(const[e,t]of Object.entries(o))e.startsWith("_")||(n=n.replace(new RegExp(e,"g"),t));["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(r)&&(n+=`;color:${o._textColor}`)}else if("light"===t&&c){["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(r)&&(n+=`;color:${c._textColor}`)}a+=`.${e}${r} { ${n} }\n`}return a},o.configure=function(e){return function(t){return o(t,e)}},o.version="1.2.3","undefined"!=typeof module&&module.exports&&(module.exports=o),"undefined"!=typeof window&&(window.quikdown=o),Object.keys(o).forEach(e=>{"configure"!==e&&(l[e]=o[e])}),l.toMarkdown=function(e,t={}){let n;if("string"==typeof e)n=document.createElement("div"),n.innerHTML=e;else{if(!(e instanceof Element))return"";n=e}function r(e,n={}){if(e.nodeType===Node.TEXT_NODE)return e.textContent;if(e.nodeType!==Node.ELEMENT_NODE)return"";const c=e.tagName.toLowerCase(),a=e.getAttribute("data-qd");let l="";for(const t of e.childNodes)l+=r(t,{parentTag:c,...n});switch(c){case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":const n=parseInt(c[1]);return`${a||"#".repeat(n)} ${l.trim()}\n\n`;case"strong":case"b":if(!l)return"";const r=a||"**";return`${r}${l}${r}`;case"em":case"i":if(!l)return"";const i=a||"*";return`${i}${l}${i}`;case"del":case"s":case"strike":if(!l)return"";const s=a||"~~";return`${s}${l}${s}`;case"code":if(!l)return"";const d=a||"`";return`${d}${l}${d}`;case"pre":const u=e.getAttribute("data-qd-fence")||a||"```",$=e.getAttribute("data-qd-lang")||"";if(t.fence_plugin&&t.fence_plugin.reverse&&$)try{const n=t.fence_plugin.reverse(e);if(n&&n.content){const e=n.fence||u;return`${e}${n.lang||$}\n${n.content}\n${e}\n\n`}}catch(e){console.warn("Fence reverse handler error:",e)}const f=e.getAttribute("data-qd-source");if(f)return`${u}${$}\n${f}\n${u}\n\n`;const g=e.querySelector("code");return`${u}${$}\n${(g?g.textContent:l).trimEnd()}\n${u}\n\n`;case"blockquote":const p=a||">";return l.trim().split("\n").map(e=>`${p} ${e}`).join("\n")+"\n\n";case"hr":return`${a||"---"}\n\n`;case"br":return`${a||" "}\n`;case"a":const h=e.getAttribute("data-qd-text")||l.trim(),m=e.getAttribute("href")||"";return h!==m||a?`[${h}](${m})`:`<${m}>`;case"img":return`${a||"!"}[${e.getAttribute("data-qd-alt")||e.getAttribute("alt")||""}](${e.getAttribute("data-qd-src")||e.getAttribute("src")||""})`;case"ul":case"ol":return o(e,"ol"===c)+"\n";case"li":case"span":default:return l;case"table":return function(e){let t="";const n=e.getAttribute("data-qd-align"),r=n?n.split(","):[],o=e.querySelector("thead");if(o){const e=o.querySelector("tr");if(e){const n=[];for(const t of e.querySelectorAll("th"))n.push(t.textContent.trim());t+="| "+n.join(" | ")+" |\n";t+="| "+n.map((e,t)=>{const n=r[t]||"left";return"center"===n?":---:":"right"===n?"---:":"---"}).join(" | ")+" |\n"}}const c=e.querySelector("tbody");if(c)for(const e of c.querySelectorAll("tr")){const n=[];for(const t of e.querySelectorAll("td"))n.push(t.textContent.trim());n.length>0&&(t+="| "+n.join(" | ")+" |\n")}return t.trim()}(e)+"\n\n";case"p":if(l.trim()){const e=l.split("\n");let t=l.trim();if(e.length>1){let n=0;for(let t=e.length-1;t>=0&&""===e[t].trim();t--)n++;if(n>0)return t+="\n ",t+"\n"}return t+"\n\n"}return"";case"div":const b=e.getAttribute("data-qd-lang"),q=e.getAttribute("data-qd-fence");if(b&&t.fence_plugin&&t.fence_plugin.reverse)try{const n=t.fence_plugin.reverse(e);if(n&&n.content){const e=n.fence||q||"```";return`${e}${n.lang||b}\n${n.content}\n${e}\n\n`}}catch(e){console.warn("Fence reverse handler error:",e)}const x=e.getAttribute("data-qd-source");if(x&&q)return`${q}${b||""}\n${x}\n${q}\n\n`;if(e.classList&&e.classList.contains("mermaid-container")){const t=e.getAttribute("data-qd-fence")||"```",n=e.getAttribute("data-qd-lang")||"mermaid",r=e.getAttribute("data-qd-source");if(r){const e=document.createElement("textarea");e.innerHTML=r;return`${t}${n}\n${e.value}\n${t}\n\n`}const o=e.querySelector("pre.mermaid");if(o){const e=o.getAttribute("data-qd-source");if(e){const r=document.createElement("textarea");r.innerHTML=e;return`${t}${n}\n${r.value}\n${t}\n\n`}}const c=e.querySelector(".mermaid-source");if(c){const e=document.createElement("div");e.innerHTML=c.innerHTML;return`${t}${n}\n${e.textContent}\n${t}\n\n`}const a=e.querySelector(".mermaid");if(a&&a.textContent.includes("graph"))return`${t}${n}\n${a.textContent.trim()}\n${t}\n\n`}if(e.classList&&e.classList.contains("mermaid")){const t=e.getAttribute("data-qd-fence")||"```";return`${t}${e.getAttribute("data-qd-lang")||"mermaid"}\n${e.textContent.trim()}\n${t}\n\n`}return l}}function o(e,t,n=0){let c="",a=1;const l=" ".repeat(n);for(const i of e.children){if("LI"!==i.tagName)continue;let e=i.getAttribute("data-qd")||(t?`${a}.`:"-");const s=i.querySelector('input[type="checkbox"]');if(s){const t=s.checked?"x":" ";e="-";let n="";for(const e of i.childNodes)e.nodeType===Node.TEXT_NODE?n+=e.textContent:e.tagName&&"INPUT"!==e.tagName&&(n+=r(e));c+=`${l}${e} [${t}] ${n.trim()}\n`}else{let t="";for(const e of i.childNodes)"UL"===e.tagName||"OL"===e.tagName?t+=o(e,"OL"===e.tagName,n+1):t+=r(e);c+=`${l}${e} ${t.trim()}\n`}a++}return c}let c=r(n);return c=c.replace(/\n{3,}/g,"\n\n"),c=c.trim(),c},l.configure=function(e){const t=o.configure({...e,bidirectional:!0});return function(e){return t(e)}},"undefined"!=typeof module&&module.exports&&(module.exports=l),"undefined"!=typeof window&&(window.quikdown_bd=l);export{l as default};
8
8
  //# sourceMappingURL=quikdown_bd.esm.min.js.map
Binary file