quikdown 1.2.9 → 1.2.11

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 (68) hide show
  1. package/README.md +5 -5
  2. package/dist/quikdown.cjs +104 -5
  3. package/dist/quikdown.d.ts +12 -0
  4. package/dist/quikdown.dark.css +1 -1
  5. package/dist/quikdown.esm.js +104 -5
  6. package/dist/quikdown.esm.min.js +2 -2
  7. package/dist/quikdown.esm.min.js.gz +0 -0
  8. package/dist/quikdown.esm.min.js.map +1 -1
  9. package/dist/quikdown.light.css +1 -1
  10. package/dist/quikdown.umd.js +104 -5
  11. package/dist/quikdown.umd.min.js +2 -2
  12. package/dist/quikdown.umd.min.js.gz +0 -0
  13. package/dist/quikdown.umd.min.js.map +1 -1
  14. package/dist/quikdown_ast.cjs +16 -28
  15. package/dist/quikdown_ast.esm.js +16 -28
  16. package/dist/quikdown_ast.esm.min.js +2 -2
  17. package/dist/quikdown_ast.esm.min.js.gz +0 -0
  18. package/dist/quikdown_ast.esm.min.js.map +1 -1
  19. package/dist/quikdown_ast.umd.js +16 -28
  20. package/dist/quikdown_ast.umd.min.js +2 -2
  21. package/dist/quikdown_ast.umd.min.js.gz +0 -0
  22. package/dist/quikdown_ast.umd.min.js.map +1 -1
  23. package/dist/quikdown_ast_html.cjs +17 -29
  24. package/dist/quikdown_ast_html.esm.js +17 -29
  25. package/dist/quikdown_ast_html.esm.min.js +2 -2
  26. package/dist/quikdown_ast_html.esm.min.js.gz +0 -0
  27. package/dist/quikdown_ast_html.esm.min.js.map +1 -1
  28. package/dist/quikdown_ast_html.umd.js +17 -29
  29. package/dist/quikdown_ast_html.umd.min.js +2 -2
  30. package/dist/quikdown_ast_html.umd.min.js.gz +0 -0
  31. package/dist/quikdown_ast_html.umd.min.js.map +1 -1
  32. package/dist/quikdown_bd.cjs +104 -5
  33. package/dist/quikdown_bd.esm.js +104 -5
  34. package/dist/quikdown_bd.esm.min.js +2 -2
  35. package/dist/quikdown_bd.esm.min.js.gz +0 -0
  36. package/dist/quikdown_bd.esm.min.js.map +1 -1
  37. package/dist/quikdown_bd.umd.js +104 -5
  38. package/dist/quikdown_bd.umd.min.js +2 -2
  39. package/dist/quikdown_bd.umd.min.js.gz +0 -0
  40. package/dist/quikdown_bd.umd.min.js.map +1 -1
  41. package/dist/quikdown_edit.cjs +244 -12
  42. package/dist/quikdown_edit.esm.js +244 -12
  43. package/dist/quikdown_edit.esm.min.js +3 -3
  44. package/dist/quikdown_edit.esm.min.js.gz +0 -0
  45. package/dist/quikdown_edit.esm.min.js.map +1 -1
  46. package/dist/quikdown_edit.umd.js +244 -12
  47. package/dist/quikdown_edit.umd.min.js +3 -3
  48. package/dist/quikdown_edit.umd.min.js.gz +0 -0
  49. package/dist/quikdown_edit.umd.min.js.map +1 -1
  50. package/dist/quikdown_json.cjs +17 -29
  51. package/dist/quikdown_json.esm.js +17 -29
  52. package/dist/quikdown_json.esm.min.js +2 -2
  53. package/dist/quikdown_json.esm.min.js.gz +0 -0
  54. package/dist/quikdown_json.esm.min.js.map +1 -1
  55. package/dist/quikdown_json.umd.js +17 -29
  56. package/dist/quikdown_json.umd.min.js +2 -2
  57. package/dist/quikdown_json.umd.min.js.gz +0 -0
  58. package/dist/quikdown_json.umd.min.js.map +1 -1
  59. package/dist/quikdown_yaml.cjs +17 -29
  60. package/dist/quikdown_yaml.esm.js +17 -29
  61. package/dist/quikdown_yaml.esm.min.js +2 -2
  62. package/dist/quikdown_yaml.esm.min.js.gz +0 -0
  63. package/dist/quikdown_yaml.esm.min.js.map +1 -1
  64. package/dist/quikdown_yaml.umd.js +17 -29
  65. package/dist/quikdown_yaml.umd.min.js +2 -2
  66. package/dist/quikdown_yaml.umd.min.js.gz +0 -0
  67. package/dist/quikdown_yaml.umd.min.js.map +1 -1
  68. package/package.json +10 -10
Binary file
@@ -1 +1 @@
1
- {"version":3,"file":"quikdown_ast.esm.min.js","sources":["../src/quikdown_ast.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"],"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"],"mappings":"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"}
1
+ {"version":3,"file":"quikdown_ast.esm.min.js","sources":["../src/quikdown_ast.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 // 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 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 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 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 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 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 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 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 continue;\n }\n\n // Plain text - consume until next potential inline element or end\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 // 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"],"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","beforeBr","indexOf","beforeText","afterText","cleanText","parseInlineContent","imgMatch","alt","url","linkMatch","codeMatch","value","boldMatch","strikeMatch","emMatch","urlMatch","nextMarker","search","merged","mergeTextNodes","version","module","exports","window"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * quikdown_ast - AST Markdown Parser
3
- * @version 1.2.9
3
+ * @version 1.2.11
4
4
  * @license BSD-2-Clause
5
5
  * @copyright DeftIO 2025
6
6
  */
@@ -19,7 +19,7 @@
19
19
  */
20
20
 
21
21
  // Version will be injected at build time
22
- const quikdownVersion = '1.2.9';
22
+ const quikdownVersion = '1.2.11';
23
23
 
24
24
  // Safety limit to prevent infinite loops in list parsing
25
25
  const MAX_LOOP_ITERATIONS = 1000;
@@ -340,8 +340,6 @@
340
340
  let remaining = text;
341
341
 
342
342
  while (remaining.length > 0) {
343
- let matched = false;
344
-
345
343
  // Line break (1+ trailing spaces or explicit \n after processing)
346
344
  // Handle inline line breaks (two spaces at end of line or backslash before newline)
347
345
  const brMatch = remaining.match(/^(.+?)(?: {2}|\\\n|\n)/);
@@ -358,7 +356,6 @@
358
356
  }
359
357
  nodes.push({ type: 'br' });
360
358
  remaining = afterText;
361
- matched = true;
362
359
  continue;
363
360
  }
364
361
  }
@@ -372,7 +369,6 @@
372
369
  url: imgMatch[2].trim() // Forgiving: trim whitespace in URL
373
370
  });
374
371
  remaining = remaining.slice(imgMatch[0].length);
375
- matched = true;
376
372
  continue;
377
373
  }
378
374
 
@@ -385,7 +381,6 @@
385
381
  children: parseInlineContent(linkMatch[1])
386
382
  });
387
383
  remaining = remaining.slice(linkMatch[0].length);
388
- matched = true;
389
384
  continue;
390
385
  }
391
386
 
@@ -397,7 +392,6 @@
397
392
  value: codeMatch[1]
398
393
  });
399
394
  remaining = remaining.slice(codeMatch[0].length);
400
- matched = true;
401
395
  continue;
402
396
  }
403
397
 
@@ -409,7 +403,6 @@
409
403
  children: parseInlineContent(boldMatch[2])
410
404
  });
411
405
  remaining = remaining.slice(boldMatch[0].length);
412
- matched = true;
413
406
  continue;
414
407
  }
415
408
 
@@ -421,7 +414,6 @@
421
414
  children: parseInlineContent(strikeMatch[1])
422
415
  });
423
416
  remaining = remaining.slice(strikeMatch[0].length);
424
- matched = true;
425
417
  continue;
426
418
  }
427
419
 
@@ -433,7 +425,6 @@
433
425
  children: parseInlineContent(emMatch[2])
434
426
  });
435
427
  remaining = remaining.slice(emMatch[0].length);
436
- matched = true;
437
428
  continue;
438
429
  }
439
430
 
@@ -446,27 +437,24 @@
446
437
  children: [{ type: 'text', value: urlMatch[1] }]
447
438
  });
448
439
  remaining = remaining.slice(urlMatch[0].length);
449
- matched = true;
450
440
  continue;
451
441
  }
452
442
 
453
443
  // Plain text - consume until next potential inline element or end
454
- if (!matched) {
455
- // Find next potential inline marker
456
- const nextMarker = remaining.search(/[`*_~![\\n]|https?:\/\//);
457
- if (nextMarker === -1) {
458
- // No more markers, consume rest as text
459
- nodes.push({ type: 'text', value: remaining });
460
- break;
461
- } else if (nextMarker === 0) {
462
- // Current char is a marker but didn't match - consume it as text
463
- nodes.push({ type: 'text', value: remaining[0] });
464
- remaining = remaining.slice(1);
465
- } else {
466
- // Consume text up to next marker
467
- nodes.push({ type: 'text', value: remaining.slice(0, nextMarker) });
468
- remaining = remaining.slice(nextMarker);
469
- }
444
+ // Find next potential inline marker
445
+ const nextMarker = remaining.search(/[`*_~![\\n]|https?:\/\//);
446
+ if (nextMarker === -1) {
447
+ // No more markers, consume rest as text
448
+ nodes.push({ type: 'text', value: remaining });
449
+ break;
450
+ } else if (nextMarker === 0) {
451
+ // Current char is a marker but didn't match - consume it as text
452
+ nodes.push({ type: 'text', value: remaining[0] });
453
+ remaining = remaining.slice(1);
454
+ } else {
455
+ // Consume text up to next marker
456
+ nodes.push({ type: 'text', value: remaining.slice(0, nextMarker) });
457
+ remaining = remaining.slice(nextMarker);
470
458
  }
471
459
  }
472
460
 
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * quikdown_ast - AST Markdown Parser
3
- * @version 1.2.9
3
+ * @version 1.2.11
4
4
  * @license BSD-2-Clause
5
5
  * @copyright DeftIO 2025
6
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=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,s){const l=[],r=e.split("\n");let o=0;for(;o<r.length;){const e=r[o];if(""===e.trim()){o++;continue}const s=e.match(/^(```|~~~)(.*)$/);if(s){const[,e,t]=s,n=t.trim(),i=[];for(o++;o<r.length;){if(r[o].match(/^(```|~~~)\s*$/)){o++;break}i.push(r[o]),o++}l.push({type:"code_block",lang:n||null,content:i.join("\n"),fence:e});continue}if(/^---+\s*$/.test(e)||/^\*\*\*+\s*$/.test(e)||/^___+\s*$/.test(e)){l.push({type:"hr"}),o++;continue}const h=e.match(/^(#{1,6})\s*(.+?)\s*#*$/);if(h){const[,e,t]=h;l.push({type:"heading",level:e.length,children:c(t)}),o++;continue}if(e.includes("|")){const e=n(r,o);if(e){l.push(e.node),o=e.nextIndex;continue}}if(e.match(/^>\s*/)){const e=[];for(;o<r.length&&r[o].match(/^>\s*/);)e.push(r[o].replace(/^>\s*/,"")),o++;l.push({type:"blockquote",children:t(e.join("\n"))});continue}if(e.match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/)){const e=i(r,o);l.push(e.node),o=e.nextIndex;continue}const u=[];for(;o<r.length;){const e=r[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<r.length&&/^\|?[\s\-:|]+\|?$/.test(r[o+1]))break;u.push(e),o++}u.length>0&&l.push({type:"paragraph",children:c(u.join("\n"))})}return l}function n(e,t,n){if(t+1>=e.length)return null;const i=e[t],l=e[t+1];if(!/^\|?[\s\-:|]+\|?$/.test(l)||!l.includes("-"))return null;const r=s(i);if(0===r.length)return null;const o=s(l).map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"}),h=r.map(e=>c(e.trim())),u=[];let f=t+2;for(;f<e.length;){const t=e[f];if(!t.includes("|")||""===t.trim())break;const n=s(t);u.push(n.map(e=>c(e.trim()))),f++}return{node:{type:"table",headers:h,rows:u,alignments:o},nextIndex:f}}function s(e){let t=e.trim();return t.startsWith("|")&&(t=t.slice(1)),t.endsWith("|")&&(t=t.slice(0,-1)),t.split("|")}function i(e,t,n){const s=[];let l=t,r=0;const o=e[l].match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/),h=/^\d+\./.test(o[2]),u=o[1].length;for(;l<e.length&&r<1e3;){r++;const t=e[l].match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/);if(!t)break;const[,n,o,f]=t,p=n.length;if(p<u)break;const d=/^\d+\./.test(o);if(p===u&&d!==h)break;if(p>u){const t=[];let n=0;for(;l<e.length&&n<1e3;){n++;const s=e[l],i=s.match(/^(\s*)([*\-+]|\d+\.)\s+/);if(!i)break;if(i[1].length<u)break;if(i[1].length===u)break;t.push(s),l++}if(t.length>0&&s.length>0){const e=i(t,0),n=s[s.length-1];n.children?Array.isArray(n.children)||(n.children=[{type:"paragraph",children:n.children}]):n.children=[],n.children.push(e.node)}continue}const a={type:"list_item",checked:null,children:null},g=f.match(/^\[([x ])\]\s*(.*)$/i);g&&!h?(a.checked="x"===g[1].toLowerCase(),a.children=c(g[2])):a.children=c(f),s.push(a),l++}return{node:{type:"list",ordered:h,items:s},nextIndex:l}}function c(e,t){if(!e)return[];const n=[];let s=e;for(;s.length>0;){let e=!1;if(s.match(/^(.+?)(?: {2}|\\\n|\n)/)&&s.includes("\n")){const t=s.indexOf("\n"),i=s.slice(0,t),c=s.slice(t+1);if(i.endsWith(" ")||i.endsWith("\\")){const t=i.replace(/\\$/,"").replace(/ +$/,"");t&&n.push(...l(t)),n.push({type:"br"}),s=c,e=!0;continue}}const t=s.match(/^!\[([^\]]*)\]\(\s*([^)\s]+)\s*\)/);if(t){n.push({type:"image",alt:t[1],url:t[2].trim()}),s=s.slice(t[0].length),e=!0;continue}const i=s.match(/^\[([^\]]+)\]\(\s*([^)\s]+)\s*\)/);if(i){n.push({type:"link",url:i[2].trim(),children:l(i[1])}),s=s.slice(i[0].length),e=!0;continue}const c=s.match(/^`([^`]+)`/);if(c){n.push({type:"code",value:c[1]}),s=s.slice(c[0].length),e=!0;continue}const r=s.match(/^(\*\*|__)(.+?)\1/);if(r){n.push({type:"strong",children:l(r[2])}),s=s.slice(r[0].length),e=!0;continue}const o=s.match(/^~~(.+?)~~/);if(o){n.push({type:"del",children:l(o[1])}),s=s.slice(o[0].length),e=!0;continue}const h=s.match(/^(\*|_)(?!\1)(.+?)(?<!\1)\1(?!\1)/);if(h){n.push({type:"em",children:l(h[2])}),s=s.slice(h[0].length),e=!0;continue}const u=s.match(/^(https?:\/\/[^\s<>[\]]+)/);if(u)n.push({type:"link",url:u[1],children:[{type:"text",value:u[1]}]}),s=s.slice(u[0].length),e=!0;else if(!e){const e=s.search(/[`*_~![\\n]|https?:\/\//);if(-1===e){n.push({type:"text",value:s});break}0===e?(n.push({type:"text",value:s[0]}),s=s.slice(1)):(n.push({type:"text",value:s.slice(0,e)}),s=s.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 l(e,t){return c(e.replace(/\n/g," "))}return e.version="1.2.9","undefined"!=typeof module&&module.exports&&(module.exports=e),"undefined"!=typeof window&&(window.quikdown_ast=e),e});
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=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,s){const l=[],r=e.split("\n");let o=0;for(;o<r.length;){const e=r[o];if(""===e.trim()){o++;continue}const s=e.match(/^(```|~~~)(.*)$/);if(s){const[,e,t]=s,n=t.trim(),i=[];for(o++;o<r.length;){if(r[o].match(/^(```|~~~)\s*$/)){o++;break}i.push(r[o]),o++}l.push({type:"code_block",lang:n||null,content:i.join("\n"),fence:e});continue}if(/^---+\s*$/.test(e)||/^\*\*\*+\s*$/.test(e)||/^___+\s*$/.test(e)){l.push({type:"hr"}),o++;continue}const h=e.match(/^(#{1,6})\s*(.+?)\s*#*$/);if(h){const[,e,t]=h;l.push({type:"heading",level:e.length,children:c(t)}),o++;continue}if(e.includes("|")){const e=n(r,o);if(e){l.push(e.node),o=e.nextIndex;continue}}if(e.match(/^>\s*/)){const e=[];for(;o<r.length&&r[o].match(/^>\s*/);)e.push(r[o].replace(/^>\s*/,"")),o++;l.push({type:"blockquote",children:t(e.join("\n"))});continue}if(e.match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/)){const e=i(r,o);l.push(e.node),o=e.nextIndex;continue}const u=[];for(;o<r.length;){const e=r[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<r.length&&/^\|?[\s\-:|]+\|?$/.test(r[o+1]))break;u.push(e),o++}u.length>0&&l.push({type:"paragraph",children:c(u.join("\n"))})}return l}function n(e,t,n){if(t+1>=e.length)return null;const i=e[t],l=e[t+1];if(!/^\|?[\s\-:|]+\|?$/.test(l)||!l.includes("-"))return null;const r=s(i);if(0===r.length)return null;const o=s(l).map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"}),h=r.map(e=>c(e.trim())),u=[];let p=t+2;for(;p<e.length;){const t=e[p];if(!t.includes("|")||""===t.trim())break;const n=s(t);u.push(n.map(e=>c(e.trim()))),p++}return{node:{type:"table",headers:h,rows:u,alignments:o},nextIndex:p}}function s(e){let t=e.trim();return t.startsWith("|")&&(t=t.slice(1)),t.endsWith("|")&&(t=t.slice(0,-1)),t.split("|")}function i(e,t,n){const s=[];let l=t,r=0;const o=e[l].match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/),h=/^\d+\./.test(o[2]),u=o[1].length;for(;l<e.length&&r<1e3;){r++;const t=e[l].match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/);if(!t)break;const[,n,o,p]=t,d=n.length;if(d<u)break;const f=/^\d+\./.test(o);if(d===u&&f!==h)break;if(d>u){const t=[];let n=0;for(;l<e.length&&n<1e3;){n++;const s=e[l],i=s.match(/^(\s*)([*\-+]|\d+\.)\s+/);if(!i)break;if(i[1].length<u)break;if(i[1].length===u)break;t.push(s),l++}if(t.length>0&&s.length>0){const e=i(t,0),n=s[s.length-1];n.children?Array.isArray(n.children)||(n.children=[{type:"paragraph",children:n.children}]):n.children=[],n.children.push(e.node)}continue}const a={type:"list_item",checked:null,children:null},g=p.match(/^\[([x ])\]\s*(.*)$/i);g&&!h?(a.checked="x"===g[1].toLowerCase(),a.children=c(g[2])):a.children=c(p),s.push(a),l++}return{node:{type:"list",ordered:h,items:s},nextIndex:l}}function c(e,t){if(!e)return[];const n=[];let s=e;for(;s.length>0;){if(s.match(/^(.+?)(?: {2}|\\\n|\n)/)&&s.includes("\n")){const e=s.indexOf("\n"),t=s.slice(0,e),i=s.slice(e+1);if(t.endsWith(" ")||t.endsWith("\\")){const e=t.replace(/\\$/,"").replace(/ +$/,"");e&&n.push(...l(e)),n.push({type:"br"}),s=i;continue}}const e=s.match(/^!\[([^\]]*)\]\(\s*([^)\s]+)\s*\)/);if(e){n.push({type:"image",alt:e[1],url:e[2].trim()}),s=s.slice(e[0].length);continue}const t=s.match(/^\[([^\]]+)\]\(\s*([^)\s]+)\s*\)/);if(t){n.push({type:"link",url:t[2].trim(),children:l(t[1])}),s=s.slice(t[0].length);continue}const i=s.match(/^`([^`]+)`/);if(i){n.push({type:"code",value:i[1]}),s=s.slice(i[0].length);continue}const c=s.match(/^(\*\*|__)(.+?)\1/);if(c){n.push({type:"strong",children:l(c[2])}),s=s.slice(c[0].length);continue}const r=s.match(/^~~(.+?)~~/);if(r){n.push({type:"del",children:l(r[1])}),s=s.slice(r[0].length);continue}const o=s.match(/^(\*|_)(?!\1)(.+?)(?<!\1)\1(?!\1)/);if(o){n.push({type:"em",children:l(o[2])}),s=s.slice(o[0].length);continue}const h=s.match(/^(https?:\/\/[^\s<>[\]]+)/);if(h){n.push({type:"link",url:h[1],children:[{type:"text",value:h[1]}]}),s=s.slice(h[0].length);continue}const u=s.search(/[`*_~![\\n]|https?:\/\//);if(-1===u){n.push({type:"text",value:s});break}0===u?(n.push({type:"text",value:s[0]}),s=s.slice(1)):(n.push({type:"text",value:s.slice(0,u)}),s=s.slice(u))}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 l(e,t){return c(e.replace(/\n/g," "))}return e.version="1.2.11","undefined"!=typeof module&&module.exports&&(module.exports=e),"undefined"!=typeof window&&(window.quikdown_ast=e),e});
8
8
  //# sourceMappingURL=quikdown_ast.umd.min.js.map
Binary file
@@ -1 +1 @@
1
- {"version":3,"file":"quikdown_ast.umd.min.js","sources":["../src/quikdown_ast.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"],"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"],"mappings":"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"}
1
+ {"version":3,"file":"quikdown_ast.umd.min.js","sources":["../src/quikdown_ast.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 // 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 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 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 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 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 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 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 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 continue;\n }\n\n // Plain text - consume until next potential inline element or end\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 // 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"],"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","beforeBr","indexOf","beforeText","afterText","cleanText","parseInlineContent","imgMatch","alt","url","linkMatch","codeMatch","value","boldMatch","strikeMatch","emMatch","urlMatch","nextMarker","search","merged","mergeTextNodes","version","module","exports","window"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * quikdown_ast_html - AST to HTML Markdown Parser
3
- * @version 1.2.9
3
+ * @version 1.2.11
4
4
  * @license BSD-2-Clause
5
5
  * @copyright DeftIO 2025
6
6
  */
@@ -15,7 +15,7 @@
15
15
  */
16
16
 
17
17
  // Version will be injected at build time
18
- const quikdownVersion$1 = '1.2.9';
18
+ const quikdownVersion$1 = '1.2.11';
19
19
 
20
20
  // Safety limit to prevent infinite loops in list parsing
21
21
  const MAX_LOOP_ITERATIONS = 1000;
@@ -336,8 +336,6 @@ function parseInline(text, options) {
336
336
  let remaining = text;
337
337
 
338
338
  while (remaining.length > 0) {
339
- let matched = false;
340
-
341
339
  // Line break (1+ trailing spaces or explicit \n after processing)
342
340
  // Handle inline line breaks (two spaces at end of line or backslash before newline)
343
341
  const brMatch = remaining.match(/^(.+?)(?: {2}|\\\n|\n)/);
@@ -354,7 +352,6 @@ function parseInline(text, options) {
354
352
  }
355
353
  nodes.push({ type: 'br' });
356
354
  remaining = afterText;
357
- matched = true;
358
355
  continue;
359
356
  }
360
357
  }
@@ -368,7 +365,6 @@ function parseInline(text, options) {
368
365
  url: imgMatch[2].trim() // Forgiving: trim whitespace in URL
369
366
  });
370
367
  remaining = remaining.slice(imgMatch[0].length);
371
- matched = true;
372
368
  continue;
373
369
  }
374
370
 
@@ -381,7 +377,6 @@ function parseInline(text, options) {
381
377
  children: parseInlineContent(linkMatch[1])
382
378
  });
383
379
  remaining = remaining.slice(linkMatch[0].length);
384
- matched = true;
385
380
  continue;
386
381
  }
387
382
 
@@ -393,7 +388,6 @@ function parseInline(text, options) {
393
388
  value: codeMatch[1]
394
389
  });
395
390
  remaining = remaining.slice(codeMatch[0].length);
396
- matched = true;
397
391
  continue;
398
392
  }
399
393
 
@@ -405,7 +399,6 @@ function parseInline(text, options) {
405
399
  children: parseInlineContent(boldMatch[2])
406
400
  });
407
401
  remaining = remaining.slice(boldMatch[0].length);
408
- matched = true;
409
402
  continue;
410
403
  }
411
404
 
@@ -417,7 +410,6 @@ function parseInline(text, options) {
417
410
  children: parseInlineContent(strikeMatch[1])
418
411
  });
419
412
  remaining = remaining.slice(strikeMatch[0].length);
420
- matched = true;
421
413
  continue;
422
414
  }
423
415
 
@@ -429,7 +421,6 @@ function parseInline(text, options) {
429
421
  children: parseInlineContent(emMatch[2])
430
422
  });
431
423
  remaining = remaining.slice(emMatch[0].length);
432
- matched = true;
433
424
  continue;
434
425
  }
435
426
 
@@ -442,27 +433,24 @@ function parseInline(text, options) {
442
433
  children: [{ type: 'text', value: urlMatch[1] }]
443
434
  });
444
435
  remaining = remaining.slice(urlMatch[0].length);
445
- matched = true;
446
436
  continue;
447
437
  }
448
438
 
449
439
  // Plain text - consume until next potential inline element or end
450
- if (!matched) {
451
- // Find next potential inline marker
452
- const nextMarker = remaining.search(/[`*_~![\\n]|https?:\/\//);
453
- if (nextMarker === -1) {
454
- // No more markers, consume rest as text
455
- nodes.push({ type: 'text', value: remaining });
456
- break;
457
- } else if (nextMarker === 0) {
458
- // Current char is a marker but didn't match - consume it as text
459
- nodes.push({ type: 'text', value: remaining[0] });
460
- remaining = remaining.slice(1);
461
- } else {
462
- // Consume text up to next marker
463
- nodes.push({ type: 'text', value: remaining.slice(0, nextMarker) });
464
- remaining = remaining.slice(nextMarker);
465
- }
440
+ // Find next potential inline marker
441
+ const nextMarker = remaining.search(/[`*_~![\\n]|https?:\/\//);
442
+ if (nextMarker === -1) {
443
+ // No more markers, consume rest as text
444
+ nodes.push({ type: 'text', value: remaining });
445
+ break;
446
+ } else if (nextMarker === 0) {
447
+ // Current char is a marker but didn't match - consume it as text
448
+ nodes.push({ type: 'text', value: remaining[0] });
449
+ remaining = remaining.slice(1);
450
+ } else {
451
+ // Consume text up to next marker
452
+ nodes.push({ type: 'text', value: remaining.slice(0, nextMarker) });
453
+ remaining = remaining.slice(nextMarker);
466
454
  }
467
455
  }
468
456
 
@@ -520,7 +508,7 @@ if (typeof window !== 'undefined') {
520
508
 
521
509
 
522
510
  // Version will be injected at build time
523
- const quikdownVersion = '1.2.9';
511
+ const quikdownVersion = '1.2.11';
524
512
 
525
513
  // Constants
526
514
  const CLASS_PREFIX = 'quikdown-';