quikdown 1.0.2 → 1.0.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.
- package/README.md +114 -17
- package/dist/quikdown-lex.cjs +810 -0
- package/dist/quikdown-lex.esm.js +808 -0
- package/dist/quikdown-lex.esm.min.js +8 -0
- package/dist/quikdown-lex.esm.min.js.map +1 -0
- package/dist/quikdown-lex.umd.js +816 -0
- package/dist/quikdown-lex.umd.min.js +8 -0
- package/dist/quikdown-lex.umd.min.js.map +1 -0
- package/dist/quikdown.cjs +164 -169
- package/dist/quikdown.d.ts +70 -0
- package/dist/quikdown.dark.css +115 -56
- package/dist/quikdown.dark.min.css +2 -0
- package/dist/quikdown.esm.js +164 -169
- package/dist/quikdown.esm.min.js +2 -2
- package/dist/quikdown.esm.min.js.map +1 -1
- package/dist/quikdown.light.css +84 -52
- package/dist/quikdown.light.min.css +2 -0
- package/dist/quikdown.umd.js +164 -169
- package/dist/quikdown.umd.min.js +2 -2
- package/dist/quikdown.umd.min.js.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* quikdown-lex - Lightweight Markdown Parser (Lexer Implementation)
|
|
3
|
+
* @version 1.0.3dev4
|
|
4
|
+
* @license BSD-2-Clause
|
|
5
|
+
* @copyright DeftIO 2025
|
|
6
|
+
*/
|
|
7
|
+
const e={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"},t={"&":"&","<":"<",">":">",'"':""","'":"'"};function n(s,r={}){if(!s||"string"!=typeof s)return"";const l={inline_styles:r.inline_styles||!1,class_prefix:r.class_prefix||"quikdown-",allow_unsafe_urls:r.allow_unsafe_urls||!1,fence_plugin:r.fence_plugin||null},o=s.split("\n"),i=[];let a=0,c=null,h=[],u=[];const f=(t,n="")=>{if(l.inline_styles){const s=e[t]||"",r=n?s?`${s};${n}`:n:s;return r?` style="${r}"`:""}return` class="${l.class_prefix}${t}"`},p=e=>e.replace(/[&<>"']/g,e=>t[e]),d=e=>{if(!e)return"";if(l.allow_unsafe_urls)return e;const t=e.trim(),n=t.toLowerCase();return/^(javascript|vbscript|data):/i.test(n)?/^data:image\//i.test(n)?t:"#":t},g=e=>{if(!e)return"";const t=[];return e=e.replace(/`([^`]+)`/g,(e,n)=>(t.push(p(n)),`${t.length-1}`)),e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=p(e)).replace(/!\[([^\]]*)\]\(([^)]+)\)/g,(e,t,n)=>`<img${f("img")} src="${d(n)}" alt="${t}">`)).replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,t,n)=>{const s=d(n),r=/^https?:\/\//i.test(s)?' rel="noopener noreferrer"':"";return`<a${f("a")} href="${s}"${r}>${t}</a>`})).replace(/(^|\s)(https?:\/\/[^\s<]+)/g,(e,t,n)=>`${t}<a${f("a")} href="${d(n)}" rel="noopener noreferrer">${n}</a>`)).replace(/\*\*(.+?)\*\*/g,`<strong${f("strong")}>$1</strong>`)).replace(/__(.+?)__/g,`<strong${f("strong")}>$1</strong>`)).replace(/(?<!\*)\*(?!\*)([^*]+)\*(?!\*)/g,`<em${f("em")}>$1</em>`)).replace(/(?<!_)_(?!_)([^_]+)_(?!_)/g,`<em${f("em")}>$1</em>`)).replace(/~~(.+?)~~/g,`<del${f("del")}>$1</del>`)).replace(/ $/gm,`<br${f("br")}>`)).replace(/\x01(\d+)\x02/g,(e,n)=>`<code${f("code")}>${t[n]}</code>`)},m=e=>{const t=e.trim();if(!t)return 0;switch(t[0]){case"#":if(/^#{1,6}\s+/.test(t))return 1;break;case"-":case"*":case"_":if(/^[-*_](\s*[-*_]){2,}$/.test(t))return 2;if(/^[*+-]\s+/.test(t))return 5;break;case"+":if(/^\+\s+/.test(t))return 5;break;case"`":case"~":if(/^[`~]{3,}/.test(t))return 3;break;case">":return 4;case"|":return/^\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?$/.test(t)?8:7;default:if(/^\d+\.\s+/.test(t))return 6;if(t.includes("|"))return/^\s*:?-+:?\s*(\|\s*:?-+:?\s*)+\s*$/.test(t)?8:7}return/^\s+[*+-]\s+/.test(e)?5:/^\s+\d+\.\s+/.test(e)?6:9},$=()=>{if(h.length>0){const e=h.join("\n");i.push(`<p>${g(e)}</p>`),h=[]}},b=()=>{if(u.length>0){const e=u.join("\n").trim();if(1!==u.length||e.includes("\n"))if(2!==u.length||""!==u[1]||u[0].includes("\n")){const t=u.filter(e=>""!==e);if(0===t.length);else if(2===t.length&&t.every(e=>!e.includes("\n")&&e.trim().length>0))i.push(`<blockquote${f("blockquote")}>${g(t[0])}</blockquote>`),i.push(`<blockquote${f("blockquote")}>${g(t[1])}</blockquote>`);else{const t=n(e,l);i.push(`<blockquote${f("blockquote")}>${t}</blockquote>`)}}else i.push(`<blockquote${f("blockquote")}>${g(u[0])}</blockquote>`);else i.push(`<blockquote${f("blockquote")}>${g(e)}</blockquote>`);u=[]}},k=e=>{const t=[];let n=e;for(;n<o.length;){const e=o[n].match(/^(\s*)([*+-]|\d+\.)\s+(.+)$/);if(!e)break;const[,s,r,a]=e,c=Math.floor(s.length/2),h=/^\d+\./.test(r),u=h?"ol":"ul";let p=a,d=f("li");if(!h){const e=a.match(/^\[([x ])\]\s+(.*)$/i);if(e){const t="x"===e[1].toLowerCase(),n=l.inline_styles?' style="margin-right:.5em"':` class="${l.class_prefix}task-checkbox"`;d=l.inline_styles?' style="list-style:none"':` class="${l.class_prefix}task-item"`,p=`<input type="checkbox"${n}${t?" checked":""} disabled> ${e[2]}`}}for(;t.length>0&&c<t[t.length-1].indent;){const e=t.pop();e.items.push(`\n</${e.type}>`)}if(0===t.length||c>t[t.length-1].indent){const e={type:u,indent:c,items:c>0?[`\n<${u}${f(u)}>`]:[`<${u}${f(u)}>`]};c>0&&t.length>0&&(t[t.length-1].items.push(e.items[0]),e.items=[]),t.push(e)}else if(t[t.length-1].type!==u){const e=t.pop();e.items.push(`\n</${e.type}>`),t.length>0?t[t.length-1].items.push(e.items.join("")):i.push(e.items.join(""));const n={type:u,indent:c,items:[`<${u}${f(u)}>`]};t.push(n)}t[t.length-1].items.push(`\n<li${d}>${g(p)}</li>`),n++}for(;t.length>1;){const e=t.pop();e.items.push(`\n</${e.type}>`),t[t.length-1].items.push(e.items.join(""))}if(t.length>0){const e=t[0];e.items.push(`\n</${e.type}>`),i.push(e.items.join(""))}return n},x=e=>{let t=e;const n=[];let s=null;const r=[],l=o[t].trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(e=>e.trim());if(n.push(...l),t++,!(t<o.length))return e;if(8!==m(o[t]))return e;{const e=o[t].trim().replace(/^\|/,"").replace(/\|$/,"").split("|");s=e.map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"}),t++}for(;t<o.length;){const e=m(o[t]);if(7!==e&&8!==e)break;const n=o[t].trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(e=>e.trim());r.push(n),t++}let a=`<table${f("table")}>`;return n.length>0&&(a+=`\n<thead${f("thead")}>\n<tr${f("tr")}>\n`,n.forEach((e,t)=>{const n=s&&"left"!==s[t]?`text-align:${s[t]}`:"";a+=`<th${f("th",n)}>${g(e)}</th>\n`}),a+="</tr>\n</thead>"),r.length>0&&(a+=`\n<tbody${f("tbody")}>\n`,r.forEach(e=>{a+=`<tr${f("tr")}>\n`,e.forEach((e,t)=>{const n=s&&"left"!==s[t]?`text-align:${s[t]}`:"";a+=`<td${f("td",n)}>${g(e)}</td>\n`}),a+="</tr>\n"}),a+="</tbody>"),a+="\n</table>",i.push(a),t};let _=0;for(;_<o.length;){const e=o[_],t=m(e);switch(a){case 0:switch(t){case 0:_++;break;case 1:const t=e.trim().match(/^(#{1,6})\s+(.+?)(?:\s*#*)?$/);if(t){const e=t[1].length,n=t[2];i.push(`<h${e}${f("h"+e)}>${g(n)}</h${e}>`)}_++;break;case 2:i.push(`<hr${f("hr")}>`),_++;break;case 3:const n=e.trim().match(/^([`~]{3,})(.*)$/);n&&(a=1,c={marker:n[1][0],count:n[1].length,lang:(n[2]||"").trim(),lines:[]}),_++;break;case 4:a=4,u=[e.replace(/^\s*>\s?/,"")],_++;break;case 5:case 6:_=k(_);break;case 7:case 8:const s=x(_);s===_?(a=5,h=[e],_++):_=s;break;default:a=5,h=[e],_++}break;case 1:const n=e.trim();if(new RegExp(`^${c.marker}{${c.count},}\\s*$`).test(n)){const e=c.lines.join("\n");let t="";if(l.fence_plugin&&(t=l.fence_plugin(e,c.lang)),!t||void 0===t){const n=!l.inline_styles&&c.lang?` class="language-${c.lang}"`:"",s=l.inline_styles?f("code"):n;t=`<pre${f("pre")}><code${s}>${p(e)}</code></pre>`}i.push(t),a=0,c=null}else c.lines.push(e);_++;break;case 5:switch(t){case 0:$(),a=0,_++;break;case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:$(),a=0;break;default:h.push(e),_++}break;case 4:4===t?(u.push(e.replace(/^\s*>\s?/,"")),_++):0===t&&_+1<o.length&&4===m(o[_+1])?(u.push(""),_++):(b(),a=0)}}return $(),b(),i.join("").trim()}n.emitStyles=function(t="quikdown-",n="light"){const s=e,r={"#f4f4f4":"#2a2a2a","#f0f0f0":"#2a2a2a","#f2f2f2":"#2a2a2a","#ddd":"#3a3a3a","#06c":"#6db3f2",_textColor:"#e0e0e0"},l={_textColor:"#333"};let o="";for(const[e,i]of Object.entries(s))if(i){let s=i;if("dark"===n&&r){for(const[e,t]of Object.entries(r))e.startsWith("_")||(s=s.replace(new RegExp(e,"g"),t));["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(e)&&(s+=`;color:${r._textColor}`)}else if("light"===n&&l){["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(e)&&(s+=`;color:${l._textColor}`)}o+=`.${t}${e} { ${s} }\n`}return o},n.configure=function(e){return function(t){return n(t,e)}},n.version="1.0.3dev4","undefined"!=typeof module&&module.exports&&(module.exports=n),"undefined"!=typeof window&&(window.quikdown=n);export{n as default};
|
|
8
|
+
//# sourceMappingURL=quikdown-lex.esm.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quikdown-lex.esm.min.js","sources":["../src/quikdown-lex.js"],"sourcesContent":["/**\n * quikdown-lex - Hand-coded lexer/parser implementation\n * \n * This is a state-machine based markdown parser that processes input\n * line-by-line with explicit state tracking. The approach trades regex\n * complexity for hand-coded state transitions, resulting in smaller\n * minified size and more predictable performance.\n * \n * Architecture:\n * 1. Line-by-line processing with lookahead\n * 2. Explicit state tracking (NORMAL, FENCE, TABLE, LIST, BLOCKQUOTE)\n * 3. Single-pass inline processing\n * 4. Direct HTML generation (no intermediate AST)\n * \n * @version __QUIKDOWN_VERSION__\n */\n\n// ===========================================================================\n// CONSTANTS & CONFIGURATION\n// ===========================================================================\n\n// Compact style map - keys match HTML tags, values are CSS strings\n// Optimized: no spaces after colons, decimal values shortened\nconst 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// HTML escape map for XSS prevention\nconst ESC_MAP = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n};\n\n// Line type constants for state machine\nconst LINE_BLANK = 0;\nconst LINE_HEADING = 1;\nconst LINE_HR = 2;\nconst LINE_FENCE = 3;\nconst LINE_BLOCKQUOTE = 4;\nconst LINE_LIST_UNORDERED = 5;\nconst LINE_LIST_ORDERED = 6;\nconst LINE_TABLE = 7;\nconst LINE_TABLE_SEP = 8;\nconst LINE_TEXT = 9;\n\n// Parser states\nconst STATE_NORMAL = 0;\nconst STATE_FENCE = 1;\nconst STATE_LIST = 2;\nconst STATE_TABLE = 3;\nconst STATE_BLOCKQUOTE = 4;\nconst STATE_PARAGRAPH = 5;\n\n// ===========================================================================\n// MAIN PARSER FUNCTION\n// ===========================================================================\n\nfunction quikdown(markdown, options = {}) {\n // Early return for invalid input\n if (!markdown || typeof markdown !== 'string') return '';\n \n // Parse options with defaults\n const opts = {\n inline_styles: options.inline_styles || false,\n class_prefix: options.class_prefix || 'quikdown-',\n allow_unsafe_urls: options.allow_unsafe_urls || false,\n fence_plugin: options.fence_plugin || null\n };\n \n // Split into lines for processing\n const lines = markdown.split('\\n');\n const output = [];\n \n // Parser state\n let state = STATE_NORMAL;\n let stateData = null; // Holds state-specific data\n \n // Buffers for accumulating content\n let paragraphBuffer = [];\n let blockquoteBuffer = [];\n \n // ===========================================================================\n // HELPER FUNCTIONS\n // ===========================================================================\n \n /**\n * Generate HTML attribute (class or inline style)\n * @param {string} tag - HTML tag name\n * @param {string} extraStyle - Additional inline styles\n * @returns {string} HTML attribute string\n */\n const getAttr = (tag, extraStyle = '') => {\n if (opts.inline_styles) {\n const baseStyle = STYLES[tag] || '';\n const combined = extraStyle \n ? (baseStyle ? `${baseStyle};${extraStyle}` : extraStyle)\n : baseStyle;\n return combined ? ` style=\"${combined}\"` : '';\n }\n return ` class=\"${opts.class_prefix}${tag}\"`;\n };\n \n /**\n * Escape HTML entities to prevent XSS\n * @param {string} str - Input string\n * @returns {string} Escaped string\n */\n const escapeHtml = (str) => {\n return str.replace(/[&<>\"']/g, m => ESC_MAP[m]);\n };\n \n /**\n * Sanitize URLs to prevent XSS attacks\n * @param {string} url - Input URL\n * @returns {string} Sanitized URL or '#' if dangerous\n */\n const sanitizeUrl = (url) => {\n if (!url) return '';\n if (opts.allow_unsafe_urls) return url;\n \n const trimmed = url.trim();\n const lower = trimmed.toLowerCase();\n \n // Block dangerous protocols except data:image\n if (/^(javascript|vbscript|data):/i.test(lower)) {\n if (/^data:image\\//i.test(lower)) return trimmed;\n return '#';\n }\n \n return trimmed;\n };\n \n /**\n * Process inline markdown elements (bold, italic, links, etc.)\n * Single-pass processing with minimal allocations\n * @param {string} text - Input text\n * @returns {string} HTML with inline formatting\n */\n const processInline = (text) => {\n if (!text) return '';\n \n // Step 1: Protect inline code by extracting it\n const codes = [];\n text = text.replace(/`([^`]+)`/g, (_, code) => {\n codes.push(escapeHtml(code));\n return `\\x01${codes.length - 1}\\x02`; // Use control chars as markers\n });\n \n // Step 2: Escape HTML entities\n text = escapeHtml(text);\n \n // Step 3: Process images (must come before links)\n text = text.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (_, alt, src) => {\n return `<img${getAttr('img')} src=\"${sanitizeUrl(src)}\" alt=\"${alt}\">`;\n });\n \n // Step 4: Process links\n text = text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_, label, href) => {\n const url = sanitizeUrl(href);\n const isExternal = /^https?:\\/\\//i.test(url);\n const rel = isExternal ? ' rel=\"noopener noreferrer\"' : '';\n return `<a${getAttr('a')} href=\"${url}\"${rel}>${label}</a>`;\n });\n \n // Step 5: Process autolinks\n text = text.replace(/(^|\\s)(https?:\\/\\/[^\\s<]+)/g, (_, prefix, url) => {\n return `${prefix}<a${getAttr('a')} href=\"${sanitizeUrl(url)}\" rel=\"noopener noreferrer\">${url}</a>`;\n });\n \n // Step 6: Process bold (** and __)\n text = text.replace(/\\*\\*(.+?)\\*\\*/g, `<strong${getAttr('strong')}>$1</strong>`);\n text = text.replace(/__(.+?)__/g, `<strong${getAttr('strong')}>$1</strong>`);\n \n // Step 7: Process italic (* and _) - using lookahead/behind\n text = text.replace(/(?<!\\*)\\*(?!\\*)([^*]+)\\*(?!\\*)/g, `<em${getAttr('em')}>$1</em>`);\n text = text.replace(/(?<!_)_(?!_)([^_]+)_(?!_)/g, `<em${getAttr('em')}>$1</em>`);\n \n // Step 8: Process strikethrough\n text = text.replace(/~~(.+?)~~/g, `<del${getAttr('del')}>$1</del>`);\n \n // Step 9: Process line breaks (two spaces at end of line)\n text = text.replace(/ $/gm, `<br${getAttr('br')}>`);\n \n // Step 10: Restore inline code\n text = text.replace(/\\x01(\\d+)\\x02/g, (_, idx) => {\n return `<code${getAttr('code')}>${codes[idx]}</code>`;\n });\n \n return text;\n };\n \n /**\n * Identify line type using optimized checks\n * @param {string} line - Input line\n * @returns {number} Line type constant\n */\n const getLineType = (line) => {\n const trimmed = line.trim();\n \n // Empty line\n if (!trimmed) return LINE_BLANK;\n \n // Use first character for quick discrimination\n const firstChar = trimmed[0];\n \n switch (firstChar) {\n case '#':\n // Heading: # through ######\n if (/^#{1,6}\\s+/.test(trimmed)) return LINE_HEADING;\n break;\n \n case '-':\n case '*':\n case '_':\n // Could be HR or list\n if (/^[-*_](\\s*[-*_]){2,}$/.test(trimmed)) return LINE_HR;\n if (/^[*+-]\\s+/.test(trimmed)) return LINE_LIST_UNORDERED;\n break;\n \n case '+':\n // Unordered list with +\n if (/^\\+\\s+/.test(trimmed)) return LINE_LIST_UNORDERED;\n break;\n \n case '`':\n case '~':\n // Fence marker (3+ backticks or tildes)\n if (/^[`~]{3,}/.test(trimmed)) return LINE_FENCE;\n break;\n \n case '>':\n // Blockquote\n return LINE_BLOCKQUOTE;\n \n case '|':\n // Table (starts with pipe)\n if (/^\\|?\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)*\\|?$/.test(trimmed)) {\n return LINE_TABLE_SEP;\n }\n return LINE_TABLE;\n \n default:\n // Check for ordered list (digit)\n if (/^\\d+\\.\\s+/.test(trimmed)) return LINE_LIST_ORDERED;\n \n // Check for table without leading pipe\n if (trimmed.includes('|')) {\n if (/^\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)+\\s*$/.test(trimmed)) {\n return LINE_TABLE_SEP;\n }\n return LINE_TABLE;\n }\n }\n \n // Check indented list items\n if (/^\\s+[*+-]\\s+/.test(line)) return LINE_LIST_UNORDERED;\n if (/^\\s+\\d+\\.\\s+/.test(line)) return LINE_LIST_ORDERED;\n \n return LINE_TEXT;\n };\n \n /**\n * Flush accumulated paragraph buffer to output\n */\n const flushParagraph = () => {\n if (paragraphBuffer.length > 0) {\n const content = paragraphBuffer.join('\\n');\n output.push(`<p>${processInline(content)}</p>`);\n paragraphBuffer = [];\n }\n };\n \n /**\n * Flush accumulated blockquote buffer to output\n */\n const flushBlockquote = () => {\n if (blockquoteBuffer.length > 0) {\n const innerContent = blockquoteBuffer.join('\\n').trim();\n \n // Check if it's a simple single-line blockquote without block elements\n if (blockquoteBuffer.length === 1 && !innerContent.includes('\\n')) {\n // Simple blockquote - just process inline\n output.push(`<blockquote${getAttr('blockquote')}>${processInline(innerContent)}</blockquote>`);\n } else if (blockquoteBuffer.length === 2 && blockquoteBuffer[1] === '' && !blockquoteBuffer[0].includes('\\n')) {\n // Two lines but second is empty - treat as single line\n output.push(`<blockquote${getAttr('blockquote')}>${processInline(blockquoteBuffer[0])}</blockquote>`);\n } else {\n // Multi-line blockquote - treat all lines as single block\n const lines = blockquoteBuffer.filter(line => line !== '');\n if (lines.length === 0) {\n // All empty lines, skip\n } else if (lines.length === 2 && lines.every(line => !line.includes('\\n') && line.trim().length > 0)) {\n // Two consecutive lines - keep them separate as two blockquotes\n output.push(`<blockquote${getAttr('blockquote')}>${processInline(lines[0])}</blockquote>`);\n output.push(`<blockquote${getAttr('blockquote')}>${processInline(lines[1])}</blockquote>`);\n } else {\n // Complex content - recursively parse\n const innerHtml = quikdown(innerContent, opts);\n output.push(`<blockquote${getAttr('blockquote')}>${innerHtml}</blockquote>`);\n }\n }\n blockquoteBuffer = [];\n }\n };\n \n /**\n * Process a list starting at current position\n * @param {number} startIdx - Starting line index\n * @returns {number} Next line index to process\n */\n const processList = (startIdx) => {\n const listStack = []; // Stack of { type, indent, items }\n let i = startIdx;\n \n while (i < lines.length) {\n const line = lines[i];\n const match = line.match(/^(\\s*)([*+-]|\\d+\\.)\\s+(.+)$/);\n \n if (!match) {\n // Not a list item, end list processing\n break;\n }\n \n const [, spaces, marker, content] = match;\n const indent = Math.floor(spaces.length / 2);\n const isOrdered = /^\\d+\\./.test(marker);\n const listType = isOrdered ? 'ol' : 'ul';\n \n // Process task list syntax\n let itemContent = content;\n let itemAttr = getAttr('li');\n \n if (!isOrdered) {\n const taskMatch = content.match(/^\\[([x ])\\]\\s+(.*)$/i);\n if (taskMatch) {\n const checked = taskMatch[1].toLowerCase() === 'x';\n const checkboxAttr = opts.inline_styles \n ? ' style=\"margin-right:.5em\"' \n : ` class=\"${opts.class_prefix}task-checkbox\"`;\n itemAttr = opts.inline_styles \n ? ' style=\"list-style:none\"' \n : ` class=\"${opts.class_prefix}task-item\"`;\n itemContent = `<input type=\"checkbox\"${checkboxAttr}${checked ? ' checked' : ''} disabled> ${taskMatch[2]}`;\n }\n }\n \n // Manage list stack based on indentation\n while (listStack.length > 0 && indent < listStack[listStack.length - 1].indent) {\n // Close deeper lists\n const closed = listStack.pop();\n closed.items.push(`\\n</${closed.type}>`);\n }\n \n if (listStack.length === 0 || indent > listStack[listStack.length - 1].indent) {\n // Start new list level\n const newList = {\n type: listType,\n indent: indent,\n items: indent > 0 ? [`\\n<${listType}${getAttr(listType)}>`] : [`<${listType}${getAttr(listType)}>`]\n };\n if (indent > 0 && listStack.length > 0) {\n // Nested list - add to parent's items\n listStack[listStack.length - 1].items.push(newList.items[0]);\n newList.items = [];\n }\n listStack.push(newList);\n } else if (listStack[listStack.length - 1].type !== listType) {\n // Different list type at same level - close and open new\n const closed = listStack.pop();\n closed.items.push(`\\n</${closed.type}>`);\n if (listStack.length > 0) {\n listStack[listStack.length - 1].items.push(closed.items.join(''));\n } else {\n output.push(closed.items.join(''));\n }\n const newList = {\n type: listType,\n indent: indent,\n items: [`<${listType}${getAttr(listType)}>`]\n };\n listStack.push(newList);\n }\n \n // Add list item to current list\n listStack[listStack.length - 1].items.push(\n `\\n<li${itemAttr}>${processInline(itemContent)}</li>`\n );\n \n i++;\n }\n \n // Close all open lists\n while (listStack.length > 1) {\n const closed = listStack.pop();\n closed.items.push(`\\n</${closed.type}>`);\n listStack[listStack.length - 1].items.push(closed.items.join(''));\n }\n \n if (listStack.length > 0) {\n const finalList = listStack[0];\n finalList.items.push(`\\n</${finalList.type}>`);\n output.push(finalList.items.join(''));\n }\n \n return i;\n };\n \n /**\n * Process a table starting at current position\n * @param {number} startIdx - Starting line index\n * @returns {number} Next line index to process\n */\n const processTable = (startIdx) => {\n let i = startIdx;\n const headerCells = [];\n let alignments = null;\n const bodyRows = [];\n \n // Parse first row as potential header\n const firstLine = lines[i].trim();\n const firstCells = firstLine.replace(/^\\|/, '').replace(/\\|$/, '').split('|').map(c => c.trim());\n headerCells.push(...firstCells);\n i++;\n \n // Check for separator line - REQUIRED for valid table\n if (i < lines.length) {\n const lineType = getLineType(lines[i]);\n if (lineType === LINE_TABLE_SEP) {\n // Parse alignments from separator\n const sepLine = lines[i].trim();\n const sepCells = sepLine.replace(/^\\|/, '').replace(/\\|$/, '').split('|');\n alignments = sepCells.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 i++;\n } else {\n // No separator, not a valid table - return without processing\n return startIdx;\n }\n } else {\n // End of input without separator - not a valid table\n return startIdx;\n }\n \n // Parse body rows\n while (i < lines.length) {\n const lineType = getLineType(lines[i]);\n if (lineType !== LINE_TABLE && lineType !== LINE_TABLE_SEP) break;\n \n const line = lines[i].trim();\n const cells = line.replace(/^\\|/, '').replace(/\\|$/, '').split('|').map(c => c.trim());\n bodyRows.push(cells);\n i++;\n }\n \n // Generate table HTML\n let html = `<table${getAttr('table')}>`;\n \n // Add header if present\n if (headerCells.length > 0) {\n html += `\\n<thead${getAttr('thead')}>\\n<tr${getAttr('tr')}>\\n`;\n headerCells.forEach((cell, idx) => {\n const align = alignments && alignments[idx] !== 'left' \n ? `text-align:${alignments[idx]}` \n : '';\n html += `<th${getAttr('th', align)}>${processInline(cell)}</th>\\n`;\n });\n html += `</tr>\\n</thead>`;\n }\n \n // Add body rows\n if (bodyRows.length > 0) {\n html += `\\n<tbody${getAttr('tbody')}>\\n`;\n bodyRows.forEach(row => {\n html += `<tr${getAttr('tr')}>\\n`;\n row.forEach((cell, idx) => {\n const align = alignments && alignments[idx] !== 'left' \n ? `text-align:${alignments[idx]}` \n : '';\n html += `<td${getAttr('td', align)}>${processInline(cell)}</td>\\n`;\n });\n html += `</tr>\\n`;\n });\n html += `</tbody>`;\n }\n \n html += `\\n</table>`;\n output.push(html);\n \n return i;\n };\n \n // ===========================================================================\n // MAIN PARSING LOOP - STATE MACHINE\n // ===========================================================================\n \n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n const lineType = getLineType(line);\n \n // STATE MACHINE - Handle current state and line type\n switch (state) {\n \n // -----------------------------------------------------------------------\n // NORMAL STATE - Can transition to any other state\n // -----------------------------------------------------------------------\n case STATE_NORMAL:\n switch (lineType) {\n case LINE_BLANK:\n // Blank line - just skip\n i++;\n break;\n \n case LINE_HEADING:\n // Parse heading\n const headingMatch = line.trim().match(/^(#{1,6})\\s+(.+?)(?:\\s*#*)?$/);\n if (headingMatch) {\n const level = headingMatch[1].length;\n const text = headingMatch[2];\n output.push(`<h${level}${getAttr('h' + level)}>${processInline(text)}</h${level}>`);\n }\n i++;\n break;\n \n case LINE_HR:\n // Horizontal rule\n output.push(`<hr${getAttr('hr')}>`);\n i++;\n break;\n \n case LINE_FENCE:\n // Start fence block\n const fenceMatch = line.trim().match(/^([`~]{3,})(.*)$/);\n if (fenceMatch) {\n state = STATE_FENCE;\n stateData = {\n marker: fenceMatch[1][0],\n count: fenceMatch[1].length,\n lang: (fenceMatch[2] || '').trim(),\n lines: []\n };\n }\n i++;\n break;\n \n case LINE_BLOCKQUOTE:\n // Start blockquote\n state = STATE_BLOCKQUOTE;\n blockquoteBuffer = [line.replace(/^\\s*>\\s?/, '')];\n i++;\n break;\n \n case LINE_LIST_UNORDERED:\n case LINE_LIST_ORDERED:\n // Process entire list\n i = processList(i);\n break;\n \n case LINE_TABLE:\n case LINE_TABLE_SEP:\n // Process entire table\n const newIdx = processTable(i);\n if (newIdx === i) {\n // Not a valid table, treat as text\n state = STATE_PARAGRAPH;\n paragraphBuffer = [line];\n i++;\n } else {\n i = newIdx;\n }\n break;\n \n case LINE_TEXT:\n default:\n // Start paragraph\n state = STATE_PARAGRAPH;\n paragraphBuffer = [line];\n i++;\n break;\n }\n break;\n \n // -----------------------------------------------------------------------\n // FENCE STATE - Inside a code fence\n // -----------------------------------------------------------------------\n case STATE_FENCE:\n // Check for closing fence\n const trimmed = line.trim();\n const closePattern = new RegExp(`^${stateData.marker}{${stateData.count},}\\\\s*$`);\n \n if (closePattern.test(trimmed)) {\n // End fence - output code block\n const code = stateData.lines.join('\\n');\n let output_html = '';\n \n // Try fence plugin first\n if (opts.fence_plugin) {\n output_html = opts.fence_plugin(code, stateData.lang);\n }\n \n // Fall back to default rendering\n if (!output_html || output_html === undefined) {\n const langAttr = !opts.inline_styles && stateData.lang \n ? ` class=\"language-${stateData.lang}\"` \n : '';\n const codeAttr = opts.inline_styles ? getAttr('code') : langAttr;\n output_html = `<pre${getAttr('pre')}><code${codeAttr}>${escapeHtml(code)}</code></pre>`;\n }\n \n output.push(output_html);\n state = STATE_NORMAL;\n stateData = null;\n } else {\n // Continue accumulating fence content\n stateData.lines.push(line);\n }\n i++;\n break;\n \n // -----------------------------------------------------------------------\n // PARAGRAPH STATE - Accumulating paragraph lines\n // -----------------------------------------------------------------------\n case STATE_PARAGRAPH:\n switch (lineType) {\n case LINE_BLANK:\n // End paragraph\n flushParagraph();\n state = STATE_NORMAL;\n i++;\n break;\n \n case LINE_HEADING:\n case LINE_HR:\n case LINE_FENCE:\n case LINE_BLOCKQUOTE:\n case LINE_LIST_UNORDERED:\n case LINE_LIST_ORDERED:\n case LINE_TABLE:\n case LINE_TABLE_SEP:\n // End paragraph and process new block\n flushParagraph();\n state = STATE_NORMAL;\n // Don't increment i - reprocess this line in NORMAL state\n break;\n \n case LINE_TEXT:\n default:\n // Continue paragraph\n paragraphBuffer.push(line);\n i++;\n break;\n }\n break;\n \n // -----------------------------------------------------------------------\n // BLOCKQUOTE STATE - Accumulating blockquote lines\n // -----------------------------------------------------------------------\n case STATE_BLOCKQUOTE:\n if (lineType === LINE_BLOCKQUOTE) {\n // Continue blockquote\n blockquoteBuffer.push(line.replace(/^\\s*>\\s?/, ''));\n i++;\n } else if (lineType === LINE_BLANK && i + 1 < lines.length && \n getLineType(lines[i + 1]) === LINE_BLOCKQUOTE) {\n // Blank line within blockquote\n blockquoteBuffer.push('');\n i++;\n } else {\n // End blockquote\n flushBlockquote();\n state = STATE_NORMAL;\n // Don't increment i - reprocess this line\n }\n break;\n }\n }\n \n // Flush any remaining content\n flushParagraph();\n flushBlockquote();\n \n return output.join('').trim();\n}\n\n// ===========================================================================\n// STATIC METHODS\n// ===========================================================================\n\n/**\n * Emit CSS styles for all quikdown elements\n * @param {string} prefix - Class prefix (default: 'quikdown-')\n * @param {string} theme - Optional theme: 'light' (default) or 'dark'\n * @returns {string} CSS stylesheet\n */\nquikdown.emitStyles = function(prefix = 'quikdown-', theme = 'light') {\n const styles = STYLES;\n \n // Define theme color overrides\n const themeOverrides = {\n dark: {\n '#f4f4f4': '#2a2a2a', // pre background\n '#f0f0f0': '#2a2a2a', // code background\n '#f2f2f2': '#2a2a2a', // th background\n '#ddd': '#3a3a3a', // borders\n '#06c': '#6db3f2', // links\n _textColor: '#e0e0e0'\n },\n light: {\n _textColor: '#333' // Explicit text color for light theme\n }\n };\n \n let css = '';\n for (const [tag, style] of Object.entries(styles)) {\n if (style) {\n let themedStyle = style;\n \n // Apply theme overrides if dark theme\n if (theme === 'dark' && themeOverrides.dark) {\n // Replace colors\n for (const [oldColor, newColor] of Object.entries(themeOverrides.dark)) {\n if (!oldColor.startsWith('_')) {\n themedStyle = themedStyle.replace(new RegExp(oldColor, 'g'), newColor);\n }\n }\n \n // Add text color for certain elements in dark theme\n const needsTextColor = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td', 'li', 'blockquote'];\n if (needsTextColor.includes(tag)) {\n themedStyle += `;color:${themeOverrides.dark._textColor}`;\n }\n } else if (theme === 'light' && themeOverrides.light) {\n // Add explicit text color for light theme elements too\n const needsTextColor = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td', 'li', 'blockquote'];\n if (needsTextColor.includes(tag)) {\n themedStyle += `;color:${themeOverrides.light._textColor}`;\n }\n }\n \n css += `.${prefix}${tag} { ${themedStyle} }\\n`;\n }\n }\n \n return css;\n};\n\n/**\n * Create a configured parser function\n * @param {Object} options - Parser options\n * @returns {Function} Configured parser\n */\nquikdown.configure = function(options) {\n return function(markdown) {\n return quikdown(markdown, options);\n };\n};\n\n/**\n * Version string\n */\nquikdown.version = '__QUIKDOWN_VERSION__';\n\n// ===========================================================================\n// EXPORTS\n// ===========================================================================\n\n// CommonJS\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = quikdown;\n}\n\n// Browser global\nif (typeof window !== 'undefined') {\n window.quikdown = quikdown;\n}\n\n// ES6 default export\nexport default quikdown;"],"names":["STYLES","h1","h2","h3","h4","h5","h6","pre","code","blockquote","table","th","td","hr","img","a","strong","em","del","ul","ol","li","ESC_MAP","quikdown","markdown","options","opts","inline_styles","class_prefix","allow_unsafe_urls","fence_plugin","lines","split","output","state","stateData","paragraphBuffer","blockquoteBuffer","getAttr","tag","extraStyle","baseStyle","combined","escapeHtml","str","replace","m","sanitizeUrl","url","trimmed","trim","lower","toLowerCase","test","processInline","text","codes","_","push","length","alt","src","label","href","rel","prefix","idx","getLineType","line","includes","flushParagraph","content","join","flushBlockquote","innerContent","filter","every","innerHtml","processList","startIdx","listStack","i","match","spaces","marker","indent","Math","floor","isOrdered","listType","itemContent","itemAttr","taskMatch","checked","checkboxAttr","closed","pop","items","type","newList","finalList","processTable","headerCells","alignments","bodyRows","firstCells","map","c","sepCells","cell","startsWith","endsWith","lineType","cells","html","forEach","align","row","headingMatch","level","fenceMatch","count","lang","newIdx","RegExp","output_html","undefined","langAttr","codeAttr","emitStyles","theme","styles","themeOverrides","_textColor","css","style","Object","entries","themedStyle","oldColor","newColor","configure","version","module","exports","window"],"mappings":"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"}
|