@pre-markdown/parser 0.2.0
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/LICENSE +21 -0
- package/dist/index.cjs +2001 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +167 -0
- package/dist/index.d.ts +167 -0
- package/dist/index.js +2013 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/block/parser.ts","../src/inline/parser.ts","../src/incremental.ts"],"sourcesContent":["/**\n * @pre-markdown/parser\n *\n * High-performance incremental Markdown parser.\n */\n\nexport { parseBlocks, parseBlockLines } from './block/parser.js'\nexport type { BlockParserOptions } from './block/parser.js'\nexport { parseInline } from './inline/index.js'\nexport { IncrementalParser } from './incremental.js'\nexport type { EditOperation, IncrementalParseResult } from './incremental.js'\n\nimport { parseBlocks } from './block/parser.js'\nimport type { BlockParserOptions } from './block/parser.js'\nimport type { Document } from '@pre-markdown/core'\n\n/**\n * Parse a complete Markdown document.\n *\n * @param input - The Markdown source text\n * @param options - Parser options\n * @returns A Document AST node\n */\nexport function parse(input: string, options?: BlockParserOptions): Document {\n return parseBlocks(input, options)\n}\n","/**\n * @pre-markdown/parser - Block-Level Parser\n *\n * Parses Markdown text into block-level AST nodes.\n * Implements CommonMark block structure algorithm with extensions.\n */\n\nimport type {\n Document,\n BlockNode,\n InlineNode,\n Heading,\n Paragraph,\n CodeBlock,\n Blockquote,\n List,\n ListItem,\n ThematicBreak,\n HtmlBlock,\n Table,\n TableAlign,\n TableRow,\n TableCell,\n FootnoteDefinition,\n MathBlock,\n Container,\n Details,\n TOC,\n} from '@pre-markdown/core'\n\nimport {\n createDocument,\n createHeading,\n createParagraph,\n createBlockquote,\n createList,\n createListItem,\n createCodeBlock,\n createThematicBreak,\n createHtmlBlock,\n createTable,\n createTableRow,\n createTableCell,\n createFootnoteDefinition,\n createMathBlock,\n createContainer,\n createDetails,\n createTOC,\n createText,\n} from '@pre-markdown/core'\n\nimport { parseInline } from '../inline/index.js'\n\n/** Parser options */\nexport interface BlockParserOptions {\n /** Enable GFM table parsing */\n gfmTables?: boolean\n /** Enable math block parsing */\n mathBlocks?: boolean\n /** Enable custom container parsing */\n containers?: boolean\n /** Enable TOC parsing */\n toc?: boolean\n /** Enable footnote definition parsing */\n footnotes?: boolean\n /** Lazy inline parsing: store raw text, defer parseInline to render time */\n lazyInline?: boolean\n}\n\nconst DEFAULT_OPTIONS: Required<BlockParserOptions> = {\n gfmTables: true,\n mathBlocks: true,\n containers: true,\n toc: true,\n footnotes: true,\n lazyInline: false,\n}\n\n/** ATX heading pattern: 1-6 # followed by space or end of line */\nconst RE_ATX_HEADING = /^(#{1,6})(?:\\s|$)/\n/** Setext heading underline */\nconst RE_SETEXT_H1 = /^ {0,3}={1,}[ \\t]*$/\nconst RE_SETEXT_H2 = /^ {0,3}-{1,}[ \\t]*$/\n/** Thematic break */\nconst RE_THEMATIC_BREAK = /^(?:\\*[ \\t]*){3,}$|^(?:-[ \\t]*){3,}$|^(?:_[ \\t]*){3,}$/\n/** Unordered list marker */\nconst RE_UL_MARKER = /^([*+-])(\\s+|$)/\n/** Ordered list marker */\nconst RE_OL_MARKER = /^(\\d{1,9})([.)])(\\s+|$)/\n/** Blockquote marker */\nconst RE_BLOCKQUOTE = /^>[ \\t]?/\n/** Fenced code block opening */\nconst RE_FENCE_OPEN = /^(`{3,}|~{3,})(?:\\s*(\\S+)?.*)?$/\n/** Fenced code block closing */\nconst RE_FENCE_CLOSE_BACKTICK = /^`{3,}\\s*$/\nconst RE_FENCE_CLOSE_TILDE = /^~{3,}\\s*$/\n/** Math block opening/closing */\nconst RE_MATH_OPEN = /^\\${2}\\s*$/\nconst RE_MATH_CLOSE = /^\\${2}\\s*$/\n/** Container opening */\nconst RE_CONTAINER_OPEN = /^:::[ \\t]*(\\w+)(?:[ \\t]+(.*))?$/\nconst RE_CONTAINER_CLOSE = /^:::[ \\t]*$/\n/** TOC — supports [toc], [[toc]], 【【toc】】 (Cherry-compatible) */\nconst RE_TOC = /^(?:\\[toc\\]|\\[\\[toc\\]\\]|【【toc】】)$/i\n/** GFM table delimiter row */\nconst RE_TABLE_DELIM = /^\\|?(?:\\s*:?-+:?\\s*\\|)+\\s*:?-+:?\\s*\\|?\\s*$/\n/** HTML block start patterns */\nconst RE_HTML_BLOCK_1 = /^<(?:script|pre|style|textarea)(?:\\s|>|$)/i\nconst RE_HTML_BLOCK_2 = /^<!--/ // HTML comment\nconst RE_HTML_BLOCK_3 = /^<\\?/ // Processing instruction\nconst RE_HTML_BLOCK_4 = /^<![A-Z]/ // Declaration\nconst RE_HTML_BLOCK_5 = /^<!\\[CDATA\\[/ // CDATA\nconst RE_HTML_BLOCK_6 = /^<\\/?(?:address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)(?:\\s|\\/?>|$)/i\n/** HTML block Type 7: open tag with attributes OR close tag (no attributes), on a line by itself */\nconst RE_HTML_BLOCK_7_OPEN = /^<[a-zA-Z][a-zA-Z0-9-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9_.:-]*(?:\\s*=\\s*(?:[^\\s\"'=<>`]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>[ \\t]*$/\nconst RE_HTML_BLOCK_7_CLOSE = /^<\\/[a-zA-Z][a-zA-Z0-9-]*\\s*>[ \\t]*$/\n/** Indented code block (4+ spaces) */\nconst RE_INDENT_CODE = /^(?: {4}|\\t)/\n/** Blank line */\nconst RE_BLANK = /^[ \\t]*$/\n/** Task list item */\nconst RE_TASK = /^\\[([ xX])\\]\\s+/\n/** Footnote definition */\nconst RE_FOOTNOTE_DEF = /^\\[\\^([^\\]]+)\\]:\\s+(.*)/\n/** Detail/collapsible block opening: +++ or +++- */\nconst RE_DETAIL_OPEN = /^\\+\\+\\+([-]?)\\s+(.+)$/\nconst RE_DETAIL_CLOSE = /^\\+\\+\\+\\s*$/\n/** FrontMatter opening: --- at start of document */\nconst RE_FRONTMATTER_OPEN = /^-{3,}\\s*$/\n\n/**\n * Fast indented code check. Line starts with 4+ spaces or a tab.\n */\nfunction isIndentCode(s: string): boolean {\n const c = s.charCodeAt(0)\n if (c === 9) return true // tab\n return c === 32 && s.charCodeAt(1) === 32 && s.charCodeAt(2) === 32 && s.charCodeAt(3) === 32\n}\n\n/**\n * Fast blank line check. Replaces `RE_BLANK.test(line)` — avoids regex overhead.\n */\nfunction isBlank(s: string): boolean {\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i)\n if (c !== 32 && c !== 9) return false // not space or tab\n }\n return true\n}\n\n/**\n * Strip up to 3 leading spaces from a line.\n * Replaces the frequently used `line.replace(/^ {0,3}/, '')` with a fast charCodeAt-based version.\n */\nfunction strip3(s: string): string {\n const c0 = s.charCodeAt(0)\n if (c0 !== 32) return s\n const c1 = s.charCodeAt(1)\n if (c1 !== 32) return s.slice(1)\n const c2 = s.charCodeAt(2)\n if (c2 !== 32) return s.slice(2)\n return s.slice(3)\n}\n\n/**\n * Parse a Markdown string into a Document AST.\n */\nexport function parseBlocks(input: string, options?: BlockParserOptions): Document {\n const opts = { ...DEFAULT_OPTIONS, ...options }\n const lines = input.split('\\n')\n const children = parseBlockLines(lines, 0, lines.length, opts)\n return createDocument(children)\n}\n\n/**\n * Parse a range of lines into block-level nodes.\n */\nfunction parseBlockLines(\n lines: string[],\n start: number,\n end: number,\n opts: Required<BlockParserOptions>,\n): BlockNode[] {\n const blocks: BlockNode[] = []\n let i = start\n\n while (i < end) {\n const line = lines[i]!\n\n // Skip blank lines\n if (isBlank(line)) {\n i++\n continue\n }\n\n let result: ParseResult | null\n\n // Fast path: use first non-space character to skip impossible rules\n const firstChar = line.charCodeAt(0)\n // Find first non-space index (replaces line.search(/\\S/))\n let trimStart = -1\n for (let k = 0; k < line.length; k++) {\n const c = line.charCodeAt(k)\n if (c !== 32 && c !== 9) { trimStart = k; break }\n }\n const fc = trimStart >= 0 ? line.charCodeAt(trimStart) : firstChar\n\n // 0. FrontMatter (only at start of document, first non-blank line)\n if (blocks.length === 0 && i === start && fc === 45) { // -\n result = tryFrontMatter(lines, i, end)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 1. ATX Heading — starts with # (or 1-3 spaces then #)\n if (fc === 35 || (firstChar === 32 && trimStart <= 3 && trimStart >= 0 && line.charCodeAt(trimStart) === 35)) { // #\n result = tryATXHeading(lines, i, opts)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 2. Thematic break — starts with *, -, _ (or 1-3 spaces then these)\n if (fc === 42 || fc === 45 || fc === 95) { // * - _\n result = tryThematicBreak(lines, i)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 3. Fenced code block — starts with ` or ~ (or 1-3 spaces then ` or ~)\n if (fc === 96 || fc === 126) { // ` ~\n result = tryFencedCode(lines, i, end)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 4. Math block — starts with $\n if (opts.mathBlocks && fc === 36) { // $\n result = tryMathBlock(lines, i, end)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 5. TOC — starts with [ or 【\n if (opts.toc && (fc === 91 || fc === 12304)) { // [ 【\n result = tryTOC(lines, i)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 5.5. Footnote definition — starts with [\n if (opts.footnotes && fc === 91) { // [\n result = tryFootnoteDefinition(lines, i, end, opts)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 6. Custom container — starts with :\n if (opts.containers && fc === 58) { // :\n result = tryContainer(lines, i, end, opts)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 6.5 Detail/collapsible block — starts with +\n if (fc === 43) { // +\n result = tryDetail(lines, i, end, opts)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 7. Blockquote — starts with >\n if (fc === 62) { // >\n result = tryBlockquote(lines, i, end, opts)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 8. List — starts with -, *, +, or digit\n if (fc === 45 || fc === 42 || fc === 43 || (fc >= 48 && fc <= 57)) { // - * + 0-9\n result = tryList(lines, i, end, opts)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 9. HTML block — starts with <\n if (fc === 60) { // <\n result = tryHtmlBlock(lines, i, end)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 10. GFM Table — line contains |\n if (opts.gfmTables && line.includes('|')) {\n result = tryTable(lines, i, end, opts)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 11. Indented code block — starts with 4+ spaces or tab\n if (firstChar === 32 || firstChar === 9) { // space or tab\n result = tryIndentedCode(lines, i, end)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n }\n\n // 12. Default: paragraph (with setext heading detection)\n result = tryParagraphOrSetext(lines, i, end, opts)\n if (result) {\n blocks.push(result.node)\n i = result.nextLine\n continue\n }\n\n // Shouldn't reach here, but advance to prevent infinite loop\n i++\n }\n\n return blocks\n}\n\ninterface ParseResult {\n node: BlockNode\n nextLine: number\n}\n\n// ============================================================\n// Block Parsers\n// ============================================================\n\n/** Helper: parse inline immediately or store raw text for lazy parsing */\nfunction inlineOrLazy(content: string, opts: Required<BlockParserOptions>): InlineNode[] {\n if (opts.lazyInline) return []\n return parseInline(content)\n}\n\nfunction tryATXHeading(\n lines: string[],\n i: number,\n _opts: Required<BlockParserOptions>,\n): ParseResult | null {\n let line = lines[i]!\n // Strip up to 3 leading spaces (CommonMark spec)\n const stripped = strip3(line)\n const match = RE_ATX_HEADING.exec(stripped)\n if (!match) return null\n\n const depth = match[1]!.length as 1 | 2 | 3 | 4 | 5 | 6\n // Get content after opening # + space\n let content = stripped.slice(match[0].length)\n // Remove optional closing #s: trailing space + one or more # + optional space\n content = content.replace(/\\s+#+\\s*$/, '')\n // If content is only # characters, it's a closing sequence → empty heading\n if (/^#+\\s*$/.test(content)) content = ''\n content = content.trim()\n const children = content ? inlineOrLazy(content, _opts) : []\n const node = createHeading(depth, children)\n if (_opts.lazyInline && content) node._raw = content\n\n return {\n node,\n nextLine: i + 1,\n }\n}\n\nfunction tryThematicBreak(lines: string[], i: number): ParseResult | null {\n const line = lines[i]!\n // Strip up to 3 leading spaces (CommonMark spec)\n const stripped = strip3(line)\n if (!RE_THEMATIC_BREAK.test(stripped)) return null\n\n return {\n node: createThematicBreak(),\n nextLine: i + 1,\n }\n}\n\nfunction tryFencedCode(lines: string[], i: number, end: number): ParseResult | null {\n const line = lines[i]!\n // Count up to 3 leading spaces\n let indent = 0\n while (indent < 3 && indent < line.length && line.charCodeAt(indent) === 32) indent++\n const stripped = line.slice(indent)\n const openMatch = RE_FENCE_OPEN.exec(stripped)\n if (!openMatch) return null\n\n const fence = openMatch[1]!\n const rawLang = openMatch[2] ?? undefined\n const isBacktick = fence[0] === '`'\n const fenceLen = fence.length\n\n // Backtick fences: the entire info string (everything after the opening fence) must not contain backticks (CommonMark spec)\n if (isBacktick) {\n const afterFence = stripped.slice(fenceLen)\n if (afterFence.includes('`')) return null\n }\n\n // Decode backslash escapes and HTML entities in info string\n const lang = rawLang ? decodeInfoString(rawLang) : undefined\n\n const contentLines: string[] = []\n let j = i + 1\n while (j < end) {\n const current = lines[j]!\n // Strip up to 3 leading spaces for close fence detection\n const closeStripped = strip3(current)\n // Check for closing fence (must be at least as long as opening, only fence chars + optional spaces)\n if (isBacktick && /^`{3,}\\s*$/.test(closeStripped) && closeStripped.trim().length >= fenceLen) {\n j++\n break\n }\n if (!isBacktick && /^~{3,}\\s*$/.test(closeStripped) && closeStripped.trim().length >= fenceLen) {\n j++\n break\n }\n // Strip indent from content lines (up to the fence indent)\n if (indent > 0 && current.length > 0) {\n let strip = 0\n for (let k = 0; k < indent && k < current.length && current[k] === ' '; k++) strip++\n contentLines.push(current.slice(strip))\n } else {\n contentLines.push(current)\n }\n j++\n }\n\n return {\n node: createCodeBlock(contentLines.join('\\n'), lang),\n nextLine: j,\n }\n}\n\nfunction tryMathBlock(lines: string[], i: number, end: number): ParseResult | null {\n const line = lines[i]!\n if (!RE_MATH_OPEN.test(line)) return null\n\n const contentLines: string[] = []\n let j = i + 1\n while (j < end) {\n if (RE_MATH_CLOSE.test(lines[j]!)) {\n j++\n break\n }\n contentLines.push(lines[j]!)\n j++\n }\n\n return {\n node: createMathBlock(contentLines.join('\\n')),\n nextLine: j,\n }\n}\n\nfunction tryTOC(lines: string[], i: number): ParseResult | null {\n const line = lines[i]!.trim()\n if (!RE_TOC.test(line)) return null\n\n return {\n node: createTOC(),\n nextLine: i + 1,\n }\n}\n\n/** Expand Cherry-style panel type shorthands (ref: Cherry Panel.js) */\nfunction expandContainerKind(raw: string): string {\n switch (raw.toLowerCase()) {\n case 'p': return 'primary'\n case 'i': return 'info'\n case 'w': return 'warning'\n case 'd': return 'danger'\n case 's': return 'success'\n case 'l': return 'left'\n case 'c': return 'center'\n case 'r': return 'right'\n case 'j': return 'justify'\n case 'tip': return 'info'\n default: return raw\n }\n}\n\nfunction tryContainer(\n lines: string[],\n i: number,\n end: number,\n opts: Required<BlockParserOptions>,\n): ParseResult | null {\n const line = lines[i]!\n const openMatch = RE_CONTAINER_OPEN.exec(line)\n if (!openMatch) return null\n\n const rawKind = openMatch[1]!\n const title = openMatch[2] ?? undefined\n\n // Cherry-compatible panel type shorthand (ref: Cherry Panel.js)\n const kind = expandContainerKind(rawKind)\n\n const contentLines: string[] = []\n let j = i + 1\n while (j < end) {\n if (RE_CONTAINER_CLOSE.test(lines[j]!)) {\n j++\n break\n }\n contentLines.push(lines[j]!)\n j++\n }\n\n // Recursively parse container content\n const children = parseBlockLines(contentLines, 0, contentLines.length, opts)\n\n return {\n node: createContainer(kind, children, title),\n nextLine: j,\n }\n}\n\nfunction tryBlockquote(\n lines: string[],\n i: number,\n end: number,\n opts: Required<BlockParserOptions>,\n): ParseResult | null {\n const line = lines[i]!\n // Strip up to 3 leading spaces\n const stripped = strip3(line)\n if (!RE_BLOCKQUOTE.test(stripped)) return null\n\n // Gather all consecutive blockquote lines\n const contentLines: string[] = []\n let j = i\n while (j < end) {\n const current = lines[j]!\n const curStripped = strip3(current)\n if (RE_BLOCKQUOTE.test(curStripped)) {\n contentLines.push(curStripped.replace(RE_BLOCKQUOTE, ''))\n j++\n } else if (\n !isBlank(current) &&\n contentLines.length > 0 &&\n // Don't lazily continue after a blank content line (empty > line)\n contentLines[contentLines.length - 1]!.trim().length > 0 &&\n // Don't lazily continue if the line starts a new block element\n // (reuse curStripped instead of re-computing strip3)\n !RE_ATX_HEADING.test(curStripped) &&\n !RE_THEMATIC_BREAK.test(curStripped) &&\n !RE_FENCE_OPEN.test(curStripped) &&\n !RE_UL_MARKER.test(curStripped) &&\n !RE_OL_MARKER.test(curStripped) &&\n !RE_HTML_BLOCK_1.test(current) &&\n !RE_HTML_BLOCK_6.test(current) &&\n // Only lazily continue paragraphs, not code blocks or other blocks\n // Check that last content line is not inside an open fenced code block\n !isInsideOpenFencedCode(contentLines) &&\n // Don't lazily continue if blockquote content ends with indented code\n // (i.e., last non-blank content line is indented code)\n !lastContentIsIndentedCode(contentLines)\n ) {\n // Lazy continuation\n contentLines.push(current)\n j++\n } else {\n break\n }\n }\n\n const children = parseBlockLines(contentLines, 0, contentLines.length, opts)\n\n return {\n node: createBlockquote(children),\n nextLine: j,\n }\n}\n\n/** Check if the accumulated content lines end inside an open (unclosed) fenced code block */\nfunction isInsideOpenFencedCode(contentLines: string[]): boolean {\n let insideFence = false\n let fenceChar = ''\n let fenceLen = 0\n for (const line of contentLines) {\n const stripped = strip3(line)\n if (!insideFence) {\n const openMatch = RE_FENCE_OPEN.exec(stripped)\n if (openMatch) {\n insideFence = true\n fenceChar = openMatch[1]![0]!\n fenceLen = openMatch[1]!.length\n }\n } else {\n // Check for close\n const closeStripped = stripped\n if (fenceChar === '`' && /^`{3,}\\s*$/.test(closeStripped) && closeStripped.trim().length >= fenceLen) {\n insideFence = false\n } else if (fenceChar === '~' && /^~{3,}\\s*$/.test(closeStripped) && closeStripped.trim().length >= fenceLen) {\n insideFence = false\n }\n }\n }\n return insideFence\n}\n\n/**\n * Check if the last block-level element in the blockquote content lines\n * would be an indented code block (4+ spaces).\n * If so, lazy continuation should be rejected.\n *\n * We walk backwards from the end of contentLines to find the last\n * non-blank line(s). If those lines all have 4+ space indent (indented code),\n * return true.\n */\nfunction lastContentIsIndentedCode(contentLines: string[]): boolean {\n // Walk backwards to find last non-blank line\n let idx = contentLines.length - 1\n while (idx >= 0 && isBlank(contentLines[idx]!)) {\n idx--\n }\n if (idx < 0) return false\n\n // Check if the last non-blank line is indented code (4+ spaces or tab)\n const lastLine = contentLines[idx]!\n return isIndentCode(lastLine)\n}\n\nfunction tryList(\n lines: string[],\n i: number,\n end: number,\n opts: Required<BlockParserOptions>,\n): ParseResult | null {\n const line = lines[i]!\n const ulMatch = RE_UL_MARKER.exec(line)\n const olMatch = RE_OL_MARKER.exec(line)\n\n if (!ulMatch && !olMatch) return null\n\n const ordered = !!olMatch\n const startNum = olMatch ? parseInt(olMatch[1]!, 10) : undefined\n\n const items: ListItem[] = []\n let j = i\n let spread = false\n\n while (j < end) {\n const currentLine = lines[j]!\n const currentUl = RE_UL_MARKER.exec(currentLine)\n const currentOl = RE_OL_MARKER.exec(currentLine)\n\n // Must match the same list type\n let isListItem = ordered ? !!currentOl : !!currentUl\n\n // A line that matches both a list marker and a thematic break\n // should be treated as a thematic break (CommonMark spec: thematic break takes precedence)\n if (isListItem && j > i) {\n const currentStripped = strip3(currentLine)\n if (RE_THEMATIC_BREAK.test(currentStripped)) {\n isListItem = false\n }\n }\n\n if (!isListItem && j > i) {\n // Thematic break interrupts a list (CommonMark spec)\n const currentStripped = strip3(currentLine)\n if (RE_THEMATIC_BREAK.test(currentStripped)) {\n break\n }\n // Check if it's continuation content (indented) or blank line within list\n if (isBlank(currentLine)) {\n // Check if next non-blank line is a list item\n let k = j + 1\n while (k < end && isBlank(lines[k]!)) k++\n if (k < end) {\n const nextUl = RE_UL_MARKER.exec(lines[k]!)\n const nextOl = RE_OL_MARKER.exec(lines[k]!)\n if (ordered ? !!nextOl : !!nextUl) {\n spread = true\n j++\n continue\n }\n }\n break\n }\n // Check for indented continuation\n if (/^(?: {2,}|\\t)/.test(currentLine)) {\n j++\n continue\n }\n break\n }\n\n if (!isListItem) break\n\n // Parse list item content\n const marker = ordered ? currentOl! : currentUl!\n const markerWidth = marker[0]!.length\n let content = currentLine.slice(markerWidth)\n\n // Check for task list\n let checked: boolean | undefined\n const taskMatch = RE_TASK.exec(content)\n if (taskMatch) {\n checked = taskMatch[1] !== ' '\n content = content.slice(taskMatch[0].length)\n }\n\n // Gather item content lines\n const itemLines: string[] = [content]\n j++\n while (j < end) {\n const itemLine = lines[j]!\n if (isBlank(itemLine)) {\n // Check if next line continues this item\n if (j + 1 < end && /^(?: {2,}|\\t)/.test(lines[j + 1]!)) {\n itemLines.push('')\n j++\n continue\n }\n break\n }\n // Check for new list item\n if ((ordered ? RE_OL_MARKER : RE_UL_MARKER).test(itemLine)) break\n // Check for thematic break interrupting the list item (CommonMark spec)\n if (RE_THEMATIC_BREAK.test(strip3(itemLine))) break\n // Check for indented continuation\n if (/^(?: {2,}|\\t)/.test(itemLine)) {\n itemLines.push(itemLine.replace(/^(?: {2,}|\\t)/, ''))\n j++\n continue\n }\n // Lazy continuation\n itemLines.push(itemLine)\n j++\n }\n\n const children = parseBlockLines(itemLines, 0, itemLines.length, opts)\n items.push(createListItem(children, false, checked))\n }\n\n if (items.length === 0) return null\n\n return {\n node: createList(ordered, spread, items, startNum),\n nextLine: j,\n }\n}\n\nfunction tryHtmlBlock(lines: string[], i: number, end: number): ParseResult | null {\n const line = lines[i]!\n // Strip up to 3 leading spaces for matching\n const stripped = strip3(line)\n\n // Type 1: <script>, <pre>, <style>, <textarea> — ends at closing tag\n if (RE_HTML_BLOCK_1.test(stripped)) {\n const htmlLines: string[] = []\n let j = i\n while (j < end) {\n htmlLines.push(lines[j]!)\n if (/<\\/(?:script|pre|style|textarea)>/i.test(lines[j]!)) {\n j++\n break\n }\n j++\n }\n return {\n node: createHtmlBlock(htmlLines.join('\\n')),\n nextLine: j,\n }\n }\n\n // Type 2: <!-- HTML comment --> — ends at -->\n if (RE_HTML_BLOCK_2.test(stripped)) {\n const htmlLines: string[] = []\n let j = i\n while (j < end) {\n htmlLines.push(lines[j]!)\n if (lines[j]!.includes('-->')) {\n j++\n break\n }\n j++\n }\n return {\n node: createHtmlBlock(htmlLines.join('\\n')),\n nextLine: j,\n }\n }\n\n // Type 3: <? processing instruction ?> — ends at ?>\n if (RE_HTML_BLOCK_3.test(stripped)) {\n const htmlLines: string[] = []\n let j = i\n while (j < end) {\n htmlLines.push(lines[j]!)\n if (lines[j]!.includes('?>')) { j++; break }\n j++\n }\n return { node: createHtmlBlock(htmlLines.join('\\n')), nextLine: j }\n }\n\n // Type 4: <!DECLARATION> — ends at >\n if (RE_HTML_BLOCK_4.test(stripped)) {\n const htmlLines: string[] = []\n let j = i\n while (j < end) {\n htmlLines.push(lines[j]!)\n if (lines[j]!.includes('>')) { j++; break }\n j++\n }\n return { node: createHtmlBlock(htmlLines.join('\\n')), nextLine: j }\n }\n\n // Type 5: <![CDATA[ — ends at ]]>\n if (RE_HTML_BLOCK_5.test(stripped)) {\n const htmlLines: string[] = []\n let j = i\n while (j < end) {\n htmlLines.push(lines[j]!)\n if (lines[j]!.includes(']]>')) { j++; break }\n j++\n }\n return { node: createHtmlBlock(htmlLines.join('\\n')), nextLine: j }\n }\n\n // Type 6: block-level HTML elements — ends at blank line\n if (RE_HTML_BLOCK_6.test(stripped)) {\n const htmlLines: string[] = []\n let j = i\n while (j < end) {\n if (j > i && isBlank(lines[j]!)) break\n htmlLines.push(lines[j]!)\n j++\n }\n return {\n node: createHtmlBlock(htmlLines.join('\\n')),\n nextLine: j,\n }\n }\n\n // Type 7: any open/close tag on a line by itself — ends at blank line\n if (RE_HTML_BLOCK_7_OPEN.test(stripped) || RE_HTML_BLOCK_7_CLOSE.test(stripped)) {\n const htmlLines: string[] = []\n let j = i\n while (j < end) {\n if (j > i && isBlank(lines[j]!)) break\n htmlLines.push(lines[j]!)\n j++\n }\n return {\n node: createHtmlBlock(htmlLines.join('\\n')),\n nextLine: j,\n }\n }\n\n return null\n}\n\nfunction tryTable(\n lines: string[],\n i: number,\n end: number,\n _opts: Required<BlockParserOptions>,\n): ParseResult | null {\n // Need at least 2 lines (header + delimiter)\n if (i + 1 >= end) return null\n\n const headerLine = lines[i]!\n const delimLine = lines[i + 1]!\n\n // Must have delimiter row\n if (!RE_TABLE_DELIM.test(delimLine)) return null\n // Header must contain pipe\n if (!headerLine.includes('|')) return null\n\n // Parse column alignments from delimiter row\n const align = parseTableAlign(delimLine)\n\n // Parse header\n const headerCells = parseTableRow(headerLine)\n const headerRow = createTableRow(\n true,\n headerCells.map((cellText) => {\n const cell = createTableCell(inlineOrLazy(cellText, _opts))\n if (_opts.lazyInline && cellText) cell._raw = cellText\n return cell\n }),\n )\n\n const rows: TableRow[] = [headerRow]\n\n // Parse body rows\n let j = i + 2\n while (j < end) {\n const rowLine = lines[j]!\n if (isBlank(rowLine)) break\n if (!rowLine.includes('|')) break\n\n const cells = parseTableRow(rowLine)\n rows.push(\n createTableRow(\n false,\n cells.map((cellText) => {\n const cell = createTableCell(inlineOrLazy(cellText, _opts))\n if (_opts.lazyInline && cellText) cell._raw = cellText\n return cell\n }),\n ),\n )\n j++\n }\n\n return {\n node: createTable(align, rows),\n nextLine: j,\n }\n}\n\nfunction parseTableAlign(delim: string): (TableAlign | null)[] {\n return delim\n .replace(/^\\||\\|$/g, '')\n .split('|')\n .map((cell) => {\n const trimmed = cell.trim()\n const left = trimmed.startsWith(':')\n const right = trimmed.endsWith(':')\n if (left && right) return 'center'\n if (right) return 'right'\n if (left) return 'left'\n return null\n })\n}\n\nfunction parseTableRow(line: string): string[] {\n // Remove leading/trailing pipes\n let trimmed = line.trim()\n if (trimmed.startsWith('|')) trimmed = trimmed.slice(1)\n if (trimmed.endsWith('|')) trimmed = trimmed.slice(0, -1)\n\n return trimmed.split('|').map((cell) => cell.trim())\n}\n\nfunction tryIndentedCode(lines: string[], i: number, end: number): ParseResult | null {\n const line = lines[i]!\n if (!isIndentCode(line)) return null\n\n const codeLines: string[] = []\n let j = i\n while (j < end) {\n const current = lines[j]!\n if (isIndentCode(current)) {\n codeLines.push(current.replace(/^(?: {4}|\\t)/, ''))\n j++\n } else if (isBlank(current)) {\n // Blank lines within indented code\n codeLines.push('')\n j++\n } else {\n break\n }\n }\n\n // Remove trailing blank lines\n while (codeLines.length > 0 && codeLines[codeLines.length - 1] === '') {\n codeLines.pop()\n }\n\n if (codeLines.length === 0) return null\n\n return {\n node: createCodeBlock(codeLines.join('\\n')),\n nextLine: j,\n }\n}\n\nfunction tryParagraphOrSetext(\n lines: string[],\n i: number,\n end: number,\n _opts: Required<BlockParserOptions>,\n): ParseResult | null {\n const paragraphLines: string[] = []\n let j = i\n\n while (j < end) {\n const current = lines[j]!\n\n if (isBlank(current)) break\n\n // Check for setext heading underline\n if (paragraphLines.length > 0) {\n if (RE_SETEXT_H1.test(current)) {\n const content = paragraphLines.join('\\n').trim()\n const node = createHeading(1, inlineOrLazy(content, _opts))\n if (_opts.lazyInline && content) node._raw = content\n return {\n node,\n nextLine: j + 1,\n }\n }\n if (RE_SETEXT_H2.test(current)) {\n const content = paragraphLines.join('\\n').trim()\n const node = createHeading(2, inlineOrLazy(content, _opts))\n if (_opts.lazyInline && content) node._raw = content\n return {\n node,\n nextLine: j + 1,\n }\n }\n }\n\n // Check for interrupt patterns (block elements that interrupt a paragraph)\n if (paragraphLines.length > 0) {\n // Strip up to 3 spaces for interrupt check\n const currentStripped = strip3(current)\n if (\n RE_ATX_HEADING.test(currentStripped) ||\n RE_THEMATIC_BREAK.test(currentStripped) ||\n RE_FENCE_OPEN.test(currentStripped) ||\n RE_BLOCKQUOTE.test(currentStripped) ||\n RE_HTML_BLOCK_1.test(currentStripped) ||\n RE_HTML_BLOCK_2.test(currentStripped) ||\n RE_HTML_BLOCK_3.test(currentStripped) ||\n RE_HTML_BLOCK_4.test(currentStripped) ||\n RE_HTML_BLOCK_5.test(currentStripped) ||\n RE_HTML_BLOCK_6.test(currentStripped)\n ) {\n break\n }\n }\n\n paragraphLines.push(current.replace(/^ {1,3}(?! )/, ''))\n j++\n }\n\n if (paragraphLines.length === 0) return null\n\n const content = paragraphLines.join('\\n').trim()\n const node = createParagraph(inlineOrLazy(content, _opts))\n if (_opts.lazyInline && content) node._raw = content\n return {\n node,\n nextLine: j,\n }\n}\n\n/** Parse FrontMatter --- yaml --- (ref: Cherry FrontMatter.js) */\nfunction tryFrontMatter(lines: string[], i: number, end: number): ParseResult | null {\n const line = lines[i]!\n if (!RE_FRONTMATTER_OPEN.test(line)) return null\n\n const contentLines: string[] = []\n let j = i + 1\n let foundClose = false\n while (j < end) {\n if (RE_FRONTMATTER_OPEN.test(lines[j]!)) {\n foundClose = true\n j++\n break\n }\n contentLines.push(lines[j]!)\n j++\n }\n\n // Must have closing --- and at least one non-blank content line\n if (!foundClose) return null\n const hasContent = contentLines.some((l) => l.trim().length > 0)\n if (!hasContent) return null\n // Content must look like YAML/JSON (contain : or { or [) — avoid matching thematic break sequences\n const looksLikeYaml = contentLines.some((l) => /[:{\\[]/.test(l))\n if (!looksLikeYaml) return null\n\n const content = contentLines.join('\\n')\n return {\n node: createHtmlBlock(`<!-- frontmatter\\n${content}\\n-->`),\n nextLine: j,\n }\n}\n\n/** Parse Detail/collapsible: +++title / +++ (ref: Cherry Detail.js) */\nfunction tryDetail(\n lines: string[],\n i: number,\n end: number,\n opts: Required<BlockParserOptions>,\n): ParseResult | null {\n const line = lines[i]!\n const openMatch = RE_DETAIL_OPEN.exec(line)\n if (!openMatch) return null\n\n const isOpen = openMatch[1] === '-'\n const summary = openMatch[2]!.trim()\n\n const contentLines: string[] = []\n let j = i + 1\n while (j < end) {\n if (RE_DETAIL_CLOSE.test(lines[j]!)) {\n j++\n break\n }\n contentLines.push(lines[j]!)\n j++\n }\n\n const children = parseBlockLines(contentLines, 0, contentLines.length, opts)\n\n // Use Details node — summary field stores the title\n // isOpen is encoded by prefixing summary with a marker\n const detailSummary = isOpen ? summary : summary\n\n return {\n node: createDetails(detailSummary, children),\n nextLine: j,\n }\n}\n\nfunction tryFootnoteDefinition(\n lines: string[],\n i: number,\n end: number,\n opts: Required<BlockParserOptions>,\n): ParseResult | null {\n const line = lines[i]!\n const match = RE_FOOTNOTE_DEF.exec(line)\n if (!match) return null\n\n const identifier = match[1]!\n const firstLineContent = match[2]!\n\n // Gather continuation lines (indented by at least 2 spaces or tab)\n const contentLines: string[] = [firstLineContent]\n let j = i + 1\n while (j < end) {\n const current = lines[j]!\n if (isBlank(current)) {\n // Check if next line continues the footnote (indented)\n if (j + 1 < end && /^(?: {2,}|\\t)/.test(lines[j + 1]!)) {\n contentLines.push('')\n j++\n continue\n }\n break\n }\n if (/^(?: {2,}|\\t)/.test(current)) {\n contentLines.push(current.replace(/^(?: {2,}|\\t)/, ''))\n j++\n continue\n }\n break\n }\n\n const children = parseBlockLines(contentLines, 0, contentLines.length, opts)\n\n return {\n node: createFootnoteDefinition(identifier, identifier, children),\n nextLine: j,\n }\n}\n\nexport { parseBlockLines }\n\n/** Decode backslash escapes and common HTML entities in code block info string */\nfunction decodeInfoString(str: string): string {\n let result = str.replace(/\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g, '$1')\n if (result.includes('&')) {\n result = result.replace(/&(?:#x([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/g, (match, hex, dec, name) => {\n if (hex) return String.fromCodePoint(parseInt(hex, 16) || 0xFFFD)\n if (dec) return String.fromCodePoint(parseInt(dec, 10) || 0xFFFD)\n const entities: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', ouml: '\\u00F6', uuml: '\\u00FC', auml: '\\u00E4' }\n return entities[name] ?? match\n })\n }\n return result\n}\n","/**\n * @pre-markdown/parser - Inline Parser\n *\n * Parses inline Markdown content into inline AST nodes.\n * Handles emphasis, links, images, code spans, and extensions.\n *\n * Performance: Uses sticky regex (y flag) + lastIndex to avoid input.slice() calls.\n */\n\nimport type { InlineNode } from '@pre-markdown/core'\n\nimport {\n createText,\n createEmphasis,\n createStrong,\n createStrikethrough,\n createInlineCode,\n createLink,\n createImage,\n createHtmlInline,\n createBreak,\n createSoftBreak,\n createMathInline,\n createHighlight,\n createSuperscript,\n createSubscript,\n createAutolink,\n createFootnoteReference,\n createFontColor,\n createFontSize,\n createFontBgColor,\n createRuby,\n createEmoji,\n createAudio,\n createVideo,\n createUnderline,\n} from '@pre-markdown/core'\n\n// ============================================================\n// Pre-compiled sticky regexes (avoid slice + re-creation)\n// ============================================================\n\nconst RE_ESCAPE = /[!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~]/\nconst RE_FOOTNOTE_REF = /\\[\\^([^\\]]+)\\]/y\nconst RE_AUTOLINK_URI = /<([a-zA-Z][a-zA-Z0-9+.\\-]{1,31}:[^\\s<>]*)>/y\nconst RE_AUTOLINK_EMAIL = /<([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/y\nconst RE_HTML_INLINE_OPEN = /<[a-zA-Z][a-zA-Z0-9-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9_.:-]*(?:\\s*=\\s*(?:[^\\s\"'=<>`]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>/y\nconst RE_HTML_INLINE_CLOSE = /<\\/[a-zA-Z][a-zA-Z0-9-]*\\s*>/y\n/** Inline HTML comment: <!-- ... --> (not <!--> or <!--->) */\nconst RE_HTML_COMMENT = /<!--(?!>)(?!->)[\\s\\S]*?-->/y\n/** Inline processing instruction: <? ... ?> */\nconst RE_HTML_PI = /<\\?[\\s\\S]*?\\?>/y\n/** Inline declaration: <!LETTER ... > */\nconst RE_HTML_DECL = /<![A-Z]+[^>]*>/y\n/** Inline CDATA: <![CDATA[ ... ]]> */\nconst RE_HTML_CDATA = /<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/y\nconst RE_CHERRY_COLOR = /!!(#[0-9a-zA-Z]{3,6}|[a-z]{3,20})\\s([\\w\\W]+?)!!/y\nconst RE_CHERRY_SIZE = /!([0-9]{1,2})\\s([\\w\\W]*?)!/y\nconst RE_CHERRY_BGCOLOR = /!!!(#[0-9a-zA-Z]{3,6}|[a-z]{3,10})\\s([\\w\\W]+?)!!!/y\nconst RE_FONT_COLOR = /\\{color:([^}]+)\\}/y\nconst RE_FONT_SIZE = /\\{size:([^}]+)\\}/y\nconst RE_FONT_BGCOLOR = /\\{bgcolor:([^}]+)\\}/y\nconst RE_EMOJI = /:([a-zA-Z0-9_+-]+):/y\nconst RE_AUDIO = /!audio\\[([^\\]]*)\\]\\(([^)]+)\\)/y\nconst RE_VIDEO = /!video\\[([^\\]]*)\\]\\(([^)]+)\\)/y\n\n/** HTML entity: &name; or &#decimal; or &#xhex; */\nconst RE_ENTITY = /&(?:#[xX]([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/y\n\n/** Common HTML5 named entities (subset covering CommonMark spec needs) */\nconst HTML_ENTITIES: Record<string, string> = {\n amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\",\n nbsp: '\\u00A0', copy: '\\u00A9', reg: '\\u00AE',\n AElig: '\\u00C6', Dcaron: '\\u010E', frac34: '\\u00BE',\n HilbertSpace: '\\u210B', DifferentialD: '\\u2146',\n ClockwiseContourIntegral: '\\u2232', ngE: '\\u2267\\u0338',\n ouml: '\\u00F6', uuml: '\\u00FC', auml: '\\u00E4',\n szlig: '\\u00DF', ntilde: '\\u00F1', eacute: '\\u00E9',\n Ouml: '\\u00D6', Uuml: '\\u00DC', Auml: '\\u00C4',\n mdash: '\\u2014', ndash: '\\u2013', lsquo: '\\u2018', rsquo: '\\u2019',\n ldquo: '\\u201C', rdquo: '\\u201D', bull: '\\u2022', hellip: '\\u2026',\n trade: '\\u2122', larr: '\\u2190', rarr: '\\u2192', uarr: '\\u2191', darr: '\\u2193',\n laquo: '\\u00AB', raquo: '\\u00BB', euro: '\\u20AC', pound: '\\u00A3', yen: '\\u00A5',\n cent: '\\u00A2', times: '\\u00D7', divide: '\\u00F7', plusmn: '\\u00B1',\n infin: '\\u221E', ne: '\\u2260', le: '\\u2264', ge: '\\u2265',\n deg: '\\u00B0', micro: '\\u00B5', para: '\\u00B6', sect: '\\u00A7',\n alpha: '\\u03B1', beta: '\\u03B2', gamma: '\\u03B3', delta: '\\u03B4',\n epsilon: '\\u03B5', pi: '\\u03C0', sigma: '\\u03C3', omega: '\\u03C9',\n hearts: '\\u2665', diams: '\\u2666', clubs: '\\u2663', spades: '\\u2660',\n iexcl: '\\u00A1', iquest: '\\u00BF', acute: '\\u00B4', cedil: '\\u00B8',\n ordf: '\\u00AA', ordm: '\\u00BA', sup1: '\\u00B9', sup2: '\\u00B2', sup3: '\\u00B3',\n frac12: '\\u00BD', frac14: '\\u00BC',\n}\n\n/** Execute a sticky regex at a given position, returns match or null */\nfunction execAt(re: RegExp, input: string, pos: number): RegExpExecArray | null {\n re.lastIndex = pos\n return re.exec(input)\n}\n\n/**\n * Parse inline content from a string.\n */\nexport function parseInline(input: string): InlineNode[] {\n const nodes: InlineNode[] = []\n const len = input.length\n let pos = 0\n let textStart = 0\n\n function flushText(): void {\n if (pos > textStart) {\n nodes.push(createText(input.slice(textStart, pos)))\n }\n }\n\n while (pos < len) {\n const ch = input.charCodeAt(pos)\n\n // Hard line break: two or more spaces before newline, or backslash before newline\n if (ch === 10) { // \\n\n const prevText = input.slice(textStart, pos)\n if (prevText.endsWith(' ') || prevText.endsWith('\\\\')) {\n const trimmed = prevText.charCodeAt(prevText.length - 1) === 92 // backslash\n ? prevText.slice(0, -1)\n : prevText.replace(/ +$/, '')\n if (trimmed) nodes.push(createText(trimmed))\n nodes.push(createBreak())\n } else {\n // Soft break: strip trailing spaces from current text\n const trimmedPrev = prevText.replace(/ +$/, '')\n if (trimmedPrev) nodes.push(createText(trimmedPrev))\n else flushText()\n nodes.push(createSoftBreak())\n }\n pos++\n // Skip leading spaces on next line (CommonMark spec)\n while (pos < len && input.charCodeAt(pos) === 32) pos++\n textStart = pos\n continue\n }\n\n // Escape: backslash followed by punctuation\n if (ch === 92 && pos + 1 < len) { // backslash\n const next = input[pos + 1]!\n if (RE_ESCAPE.test(next)) {\n flushText()\n pos++\n textStart = pos\n pos++\n continue\n }\n }\n\n // Inline code: backtick\n if (ch === 96) { // `\n const result = tryInlineCode(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Math inline: $...$\n if (ch === 36 && input.charCodeAt(pos + 1) !== 36) { // $\n const result = tryMathInline(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Cherry-style background color: !!!color text!!!\n if (ch === 33 && input.charCodeAt(pos + 1) === 33 && input.charCodeAt(pos + 2) === 33) { // !!!\n const match = execAt(RE_CHERRY_BGCOLOR, input, pos)\n if (match) {\n flushText()\n nodes.push(createFontBgColor(match[1]!, parseInlineFast(match[2]!)))\n pos = pos + match[0].length\n textStart = pos\n continue\n }\n }\n\n // Cherry-style font color: !!color text!!\n if (ch === 33 && input.charCodeAt(pos + 1) === 33 && input.charCodeAt(pos + 2) !== 33) { // !!\n const match = execAt(RE_CHERRY_COLOR, input, pos)\n if (match) {\n flushText()\n nodes.push(createFontColor(match[1]!, parseInlineFast(match[2]!)))\n pos = pos + match[0].length\n textStart = pos\n continue\n }\n }\n\n // Cherry-style font size: !size text!\n if (ch === 33) { // !\n const next = input.charCodeAt(pos + 1)\n if (next !== 33 && next !== 91 && next !== 97 && next !== 118) { // not !, [, a, v\n const match = execAt(RE_CHERRY_SIZE, input, pos)\n if (match) {\n flushText()\n nodes.push(createFontSize(match[1]! + 'px', parseInlineFast(match[2]!)))\n pos = pos + match[0].length\n textStart = pos\n continue\n }\n }\n }\n\n // Audio: !audio[title](url)\n if (ch === 33 && input.charCodeAt(pos + 1) === 97) { // !a\n const match = execAt(RE_AUDIO, input, pos)\n if (match) {\n flushText()\n nodes.push(createAudio(match[2]!, match[1] || undefined))\n pos = pos + match[0].length\n textStart = pos\n continue\n }\n }\n\n // Video: !video[title](url)\n if (ch === 33 && input.charCodeAt(pos + 1) === 118) { // !v\n const match = execAt(RE_VIDEO, input, pos)\n if (match) {\n flushText()\n nodes.push(createVideo(match[2]!, match[1] || undefined))\n pos = pos + match[0].length\n textStart = pos\n continue\n }\n }\n\n // Image: \n if (ch === 33 && input.charCodeAt(pos + 1) === 91) { //  or [^id]\n if (ch === 91) { // [\n if (input.charCodeAt(pos + 1) === 94) { // [^\n const match = execAt(RE_FOOTNOTE_REF, input, pos)\n if (match) {\n flushText()\n nodes.push(createFootnoteReference(match[1]!, match[1]!))\n pos = pos + match[0].length\n textStart = pos\n continue\n }\n }\n\n const result = tryLink(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Autolink: <url> or <email>\n if (ch === 60) { // <\n const uriMatch = execAt(RE_AUTOLINK_URI, input, pos)\n if (uriMatch) {\n flushText()\n nodes.push(createAutolink(uriMatch[1]!, false))\n pos = pos + uriMatch[0].length\n textStart = pos\n continue\n }\n\n const emailMatch = execAt(RE_AUTOLINK_EMAIL, input, pos)\n if (emailMatch) {\n flushText()\n nodes.push(createAutolink('mailto:' + emailMatch[1]!, true))\n pos = pos + emailMatch[0].length\n textStart = pos\n continue\n }\n\n // HTML inline tags: try all patterns in order, first match wins\n const htmlPatterns = [RE_HTML_INLINE_OPEN, RE_HTML_INLINE_CLOSE, RE_HTML_COMMENT, RE_HTML_PI, RE_HTML_CDATA, RE_HTML_DECL]\n let htmlMatched = false\n for (let hi = 0; hi < htmlPatterns.length; hi++) {\n const hm = execAt(htmlPatterns[hi]!, input, pos)\n if (hm) {\n flushText()\n nodes.push(createHtmlInline(hm[0]))\n pos = pos + hm[0].length\n textStart = pos\n htmlMatched = true\n break\n }\n }\n if (htmlMatched) continue\n }\n\n // Emphasis/Strong: * or _\n if (ch === 42 || ch === 95) { // * or _\n const result = tryEmphasis(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Strikethrough: ~~\n if (ch === 126 && input.charCodeAt(pos + 1) === 126) { // ~~\n const result = tryStrikethrough(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Highlight: ==\n if (ch === 61 && input.charCodeAt(pos + 1) === 61) { // ==\n const result = tryHighlight(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Superscript: ^text^\n if (ch === 94 && input.charCodeAt(pos + 1) !== 94) { // ^\n const result = trySuperscript(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Cherry-style subscript: ^^text^^\n if (ch === 94 && input.charCodeAt(pos + 1) === 94) { // ^^\n const result = tryCherrySubscript(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Subscript: ~text~\n if (ch === 126 && input.charCodeAt(pos + 1) !== 126) { // ~\n const result = trySubscript(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Font color/size/bgcolor: {color:red}text{/color} or Ruby: {text|ann}\n if (ch === 123) { // {\n const colorMatch = execAt(RE_FONT_COLOR, input, pos)\n if (colorMatch) {\n const closeTag = '{/color}'\n const closeIdx = input.indexOf(closeTag, pos + colorMatch[0].length)\n if (closeIdx !== -1) {\n const content = input.slice(pos + colorMatch[0].length, closeIdx)\n if (content.length > 0) {\n flushText()\n nodes.push(createFontColor(colorMatch[1]!, parseInlineFast(content)))\n pos = closeIdx + closeTag.length\n textStart = pos\n continue\n }\n }\n }\n\n const sizeMatch = execAt(RE_FONT_SIZE, input, pos)\n if (sizeMatch) {\n const closeTag = '{/size}'\n const closeIdx = input.indexOf(closeTag, pos + sizeMatch[0].length)\n if (closeIdx !== -1) {\n const content = input.slice(pos + sizeMatch[0].length, closeIdx)\n if (content.length > 0) {\n flushText()\n nodes.push(createFontSize(sizeMatch[1]!, parseInlineFast(content)))\n pos = closeIdx + closeTag.length\n textStart = pos\n continue\n }\n }\n }\n\n const bgMatch = execAt(RE_FONT_BGCOLOR, input, pos)\n if (bgMatch) {\n const closeTag = '{/bgcolor}'\n const closeIdx = input.indexOf(closeTag, pos + bgMatch[0].length)\n if (closeIdx !== -1) {\n const content = input.slice(pos + bgMatch[0].length, closeIdx)\n if (content.length > 0) {\n flushText()\n nodes.push(createFontBgColor(bgMatch[1]!, parseInlineFast(content)))\n pos = closeIdx + closeTag.length\n textStart = pos\n continue\n }\n }\n }\n\n // Ruby: {text|annotation} or {text}(annotation)\n const result = tryRuby(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Underline (Cherry-style): /text/\n if (ch === 47) { // /\n const result = tryUnderline(input, pos)\n if (result) {\n flushText()\n nodes.push(result.node)\n pos = result.end\n textStart = pos\n continue\n }\n }\n\n // Emoji shortcode: :smile:\n if (ch === 58) { // :\n const match = execAt(RE_EMOJI, input, pos)\n if (match) {\n const value = EMOJI_MAP[match[1]!]\n if (value) {\n flushText()\n nodes.push(createEmoji(match[1]!, value))\n pos = pos + match[0].length\n textStart = pos\n continue\n }\n }\n }\n\n // HTML entity: &name; &#decimal; &#xhex;\n if (ch === 38) { // &\n const match = execAt(RE_ENTITY, input, pos)\n if (match) {\n let decoded: string | undefined\n if (match[1]) {\n // &#xHEX;\n const code = parseInt(match[1], 16)\n decoded = code === 0 ? '\\uFFFD' : String.fromCodePoint(code)\n } else if (match[2]) {\n // &#DECIMAL;\n const code = parseInt(match[2], 10)\n decoded = code === 0 ? '\\uFFFD' : String.fromCodePoint(code)\n } else if (match[3]) {\n // &name;\n decoded = HTML_ENTITIES[match[3]]\n }\n if (decoded !== undefined) {\n flushText()\n nodes.push(createText(decoded))\n pos = pos + match[0].length\n textStart = pos\n continue\n }\n }\n }\n\n pos++\n }\n\n // Flush remaining text\n if (textStart < len) {\n nodes.push(createText(input.slice(textStart)))\n }\n\n return nodes\n}\n\n// ============================================================\n// Inline Parsers\n// ============================================================\n\ninterface InlineResult {\n node: InlineNode\n end: number\n}\n\n// Special chars that trigger inline parsing — if content has none, just return [Text]\nconst INLINE_SPECIAL_CHARS = /[`*_~\\[!<$\\\\={^:/{}\\n]/\n\n/** Fast path: if content has no special inline chars, return single Text node */\nfunction parseInlineFast(content: string): InlineNode[] {\n if (!INLINE_SPECIAL_CHARS.test(content)) {\n return content.length > 0 ? [createText(content)] : []\n }\n return parseInline(content)\n}\n\nfunction tryInlineCode(input: string, start: number): InlineResult | null {\n let pos = start\n let ticks = 0\n while (pos < input.length && input.charCodeAt(pos) === 96) {\n ticks++\n pos++\n }\n\n // Find closing backtick run of exactly `ticks` length using charCodeAt scan\n let searchPos = pos\n while (searchPos < input.length) {\n // Find next backtick\n while (searchPos < input.length && input.charCodeAt(searchPos) !== 96) searchPos++\n if (searchPos >= input.length) return null\n\n // Count consecutive backticks\n let runStart = searchPos\n while (searchPos < input.length && input.charCodeAt(searchPos) === 96) searchPos++\n const runLen = searchPos - runStart\n\n // Must match exactly `ticks` backticks\n if (runLen === ticks) {\n const content = input.slice(pos, runStart)\n // Replace newlines with spaces (CommonMark spec)\n let trimmed = content\n if (content.includes('\\n')) trimmed = content.replace(/\\n/g, ' ')\n // Strip one leading+trailing space if both present and content is not all spaces\n const normalized =\n trimmed.length > 0 && trimmed.charCodeAt(0) === 32 && trimmed.charCodeAt(trimmed.length - 1) === 32 && trimmed.trim().length > 0\n ? trimmed.slice(1, -1)\n : trimmed\n\n return {\n node: createInlineCode(normalized),\n end: runStart + ticks,\n }\n }\n // Otherwise keep scanning (searchPos already past the run)\n }\n\n return null\n}\n\nfunction tryMathInline(input: string, start: number): InlineResult | null {\n const pos = start + 1\n const closePos = input.indexOf('$', pos)\n if (closePos === -1 || closePos === pos) return null\n if (input.charCodeAt(pos) === 32 || input.charCodeAt(closePos - 1) === 32) return null\n\n return {\n node: createMathInline(input.slice(pos, closePos)),\n end: closePos + 1,\n }\n}\n\nfunction tryImage(input: string, start: number): InlineResult | null {\n const altClose = findClosingBracket(input, start + 1)\n if (altClose === -1 || input.charCodeAt(altClose + 1) !== 40) return null // (\n\n const alt = input.slice(start + 2, altClose)\n const urlResult = parseUrlAndTitle(input, altClose + 1)\n if (!urlResult) return null\n\n return {\n node: createImage(urlResult.url, alt, urlResult.title),\n end: urlResult.end,\n }\n}\n\nfunction tryLink(input: string, start: number): InlineResult | null {\n const textClose = findClosingBracket(input, start)\n if (textClose === -1 || input.charCodeAt(textClose + 1) !== 40) return null // (\n\n const text = input.slice(start + 1, textClose)\n const urlResult = parseUrlAndTitle(input, textClose + 1)\n if (!urlResult) return null\n\n return {\n node: createLink(urlResult.url, parseInlineFast(text), urlResult.title),\n end: urlResult.end,\n }\n}\n\nfunction tryEmphasis(input: string, start: number): InlineResult | null {\n const charCode = input.charCodeAt(start)\n let count = 1\n while (start + count < input.length && input.charCodeAt(start + count) === charCode) count++\n\n // CommonMark: handle runs of 1, 2, or 3 delimiter chars\n // For runs > 3, we try to match as ***...*** (strong+em) first, then ** (strong), then * (em)\n if (count > 3) count = 3\n\n const pos = start + count\n\n // Fast path: scan for closing delimiter using charCodeAt instead of indexOf + string creation\n let searchPos = pos\n while (searchPos < input.length) {\n // Find next occurrence of the delimiter character\n let closeIdx = -1\n for (let k = searchPos; k < input.length; k++) {\n if (input.charCodeAt(k) === charCode) { closeIdx = k; break }\n }\n if (closeIdx === -1) return null\n\n // Check if we have enough consecutive delimiter chars\n let closeCount = 1\n while (closeIdx + closeCount < input.length && input.charCodeAt(closeIdx + closeCount) === charCode) closeCount++\n\n // Closing delimiter run must have at least `count` chars and end exactly at `count`\n // (i.e., no extra same-char after the closing run, or the extra chars belong to a different run)\n if (closeCount < count) {\n searchPos = closeIdx + closeCount\n continue\n }\n\n // If the closing run is longer than needed, use exactly `count` from the end of the run\n // This follows CommonMark's rule: match the most inner delimiter first\n const actualCloseStart = closeIdx + closeCount - count\n const content = input.slice(pos, actualCloseStart)\n if (content.length === 0) {\n searchPos = closeIdx + closeCount\n continue\n }\n\n const children = parseInlineFast(content)\n const end = actualCloseStart + count\n\n if (count === 1) {\n return { node: createEmphasis(children), end }\n } else if (count === 2) {\n return { node: createStrong(children), end }\n } else {\n return { node: createStrong([createEmphasis(children)]), end }\n }\n }\n\n return null\n}\n\nfunction tryStrikethrough(input: string, start: number): InlineResult | null {\n // Find closing ~~ using charCodeAt\n for (let k = start + 2; k < input.length - 1; k++) {\n if (input.charCodeAt(k) === 126 && input.charCodeAt(k + 1) === 126) {\n const content = input.slice(start + 2, k)\n if (content.length === 0) return null\n return { node: createStrikethrough(parseInlineFast(content)), end: k + 2 }\n }\n }\n return null\n}\n\nfunction tryHighlight(input: string, start: number): InlineResult | null {\n // Find closing == using charCodeAt\n for (let k = start + 2; k < input.length - 1; k++) {\n if (input.charCodeAt(k) === 61 && input.charCodeAt(k + 1) === 61) {\n const content = input.slice(start + 2, k)\n if (content.length === 0) return null\n return { node: createHighlight(parseInlineFast(content)), end: k + 2 }\n }\n }\n return null\n}\n\nfunction trySuperscript(input: string, start: number): InlineResult | null {\n const closeIdx = input.indexOf('^', start + 1)\n if (closeIdx === -1 || closeIdx === start + 1) return null\n const content = input.slice(start + 1, closeIdx)\n if (content.includes(' ')) return null\n return { node: createSuperscript(parseInlineFast(content)), end: closeIdx + 1 }\n}\n\nfunction trySubscript(input: string, start: number): InlineResult | null {\n if (input.charCodeAt(start + 1) === 126) return null // ~~\n const closeIdx = input.indexOf('~', start + 1)\n if (closeIdx === -1 || closeIdx === start + 1) return null\n const content = input.slice(start + 1, closeIdx)\n if (content.includes(' ')) return null\n return { node: createSubscript(parseInlineFast(content)), end: closeIdx + 1 }\n}\n\nfunction tryCherrySubscript(input: string, start: number): InlineResult | null {\n const closeIdx = input.indexOf('^^', start + 2)\n if (closeIdx === -1) return null\n const content = input.slice(start + 2, closeIdx)\n if (content.length === 0) return null\n return { node: createSubscript(parseInlineFast(content)), end: closeIdx + 2 }\n}\n\n// ============================================================\n// Utility Functions\n// ============================================================\n\nfunction findClosingBracket(input: string, start: number): number {\n let depth = 0\n let pos = start\n while (pos < input.length) {\n const c = input.charCodeAt(pos)\n if (c === 91) depth++ // [\n else if (c === 93) { // ]\n depth--\n if (depth === 0) return pos\n } else if (c === 92) { // backslash\n pos++ // skip escaped character\n }\n pos++\n }\n return -1\n}\n\nfunction parseUrlAndTitle(\n input: string,\n start: number,\n): { url: string; title?: string; end: number } | null {\n if (input.charCodeAt(start) !== 40) return null // (\n\n let pos = start + 1\n // Skip whitespace\n while (pos < input.length && isWhitespace(input.charCodeAt(pos))) pos++\n\n // Parse URL\n let url = ''\n if (input.charCodeAt(pos) === 60) { // <\n const closeAngle = input.indexOf('>', pos + 1)\n if (closeAngle === -1) return null\n url = input.slice(pos + 1, closeAngle)\n pos = closeAngle + 1\n } else {\n let depth = 0\n const urlStart = pos\n while (pos < input.length) {\n const c = input.charCodeAt(pos)\n if (c === 40) depth++ // (\n else if (c === 41) { // )\n if (depth === 0) break\n depth--\n } else if (isWhitespace(c)) break\n pos++\n }\n url = input.slice(urlStart, pos)\n }\n\n // Skip whitespace\n while (pos < input.length && isWhitespace(input.charCodeAt(pos))) pos++\n\n // Parse optional title\n let title: string | undefined\n const tc = input.charCodeAt(pos)\n if (tc === 34 || tc === 39 || tc === 40) { // \" ' (\n const quote = tc === 40 ? 41 : tc // ) for (, same char otherwise\n const titleStart = pos + 1\n pos++\n while (pos < input.length && input.charCodeAt(pos) !== quote) {\n if (input.charCodeAt(pos) === 92) pos++ // backslash\n pos++\n }\n if (pos >= input.length) return null\n title = input.slice(titleStart, pos)\n pos++\n }\n\n // Skip whitespace and find closing paren\n while (pos < input.length && isWhitespace(input.charCodeAt(pos))) pos++\n if (pos >= input.length || input.charCodeAt(pos) !== 41) return null // )\n\n return { url: decodeEntities(decodeBackslashEscapes(url)), title: title ? decodeEntities(decodeBackslashEscapes(title)) : title, end: pos + 1 }\n}\n\nfunction isWhitespace(code: number): boolean {\n return code === 32 || code === 9 || code === 10 || code === 13\n}\n\n/** Decode backslash escapes in URL/title strings */\nconst RE_BACKSLASH_ESCAPE = /\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g\nfunction decodeBackslashEscapes(str: string): string {\n return str.replace(RE_BACKSLASH_ESCAPE, '$1')\n}\n\n/** Decode HTML entities in strings */\nfunction decodeEntities(str: string): string {\n if (!str.includes('&')) return str\n return str.replace(/&(?:#[xX]([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/g, (match, hex, dec, name) => {\n if (hex) {\n const code = parseInt(hex, 16)\n return code === 0 ? '\\uFFFD' : String.fromCodePoint(code)\n }\n if (dec) {\n const code = parseInt(dec, 10)\n return code === 0 ? '\\uFFFD' : String.fromCodePoint(code)\n }\n if (name && HTML_ENTITIES[name]) {\n return HTML_ENTITIES[name]\n }\n return match\n })\n}\n\nfunction tryRuby(input: string, start: number): InlineResult | null {\n const braceClose = input.indexOf('}', start + 1)\n if (braceClose === -1) return null\n\n const innerContent = input.slice(start + 1, braceClose)\n if (innerContent.length === 0) return null\n\n // Avoid matching font color/size/bgcolor patterns\n if (innerContent.charCodeAt(0) === 99 && innerContent.startsWith('color:')) return null // color:\n if (innerContent.charCodeAt(0) === 115 && innerContent.startsWith('size:')) return null // size:\n if (innerContent.charCodeAt(0) === 98 && innerContent.startsWith('bgcolor:')) return null // bgcolor:\n if (innerContent.charCodeAt(0) === 47) return null // /\n\n // Cherry format: {text|annotation}\n const pipeIdx = innerContent.indexOf('|')\n if (pipeIdx !== -1) {\n const base = innerContent.slice(0, pipeIdx)\n const annotation = innerContent.slice(pipeIdx + 1)\n if (base.length > 0 && annotation.length > 0) {\n return { node: createRuby(base, annotation), end: braceClose + 1 }\n }\n }\n\n // Our format: {base text}(annotation)\n if (input.charCodeAt(braceClose + 1) !== 40) return null // (\n const parenClose = input.indexOf(')', braceClose + 2)\n if (parenClose === -1) return null\n\n const annotation = input.slice(braceClose + 2, parenClose)\n if (annotation.length === 0) return null\n\n return { node: createRuby(innerContent, annotation), end: parenClose + 1 }\n}\n\nfunction tryUnderline(input: string, start: number): InlineResult | null {\n // Must be preceded by space or start of string\n if (start > 0 && input.charCodeAt(start - 1) !== 32 && input.charCodeAt(start - 1) !== 10) return null\n\n const closeIdx = input.indexOf('/', start + 1)\n if (closeIdx === -1 || closeIdx === start + 1) return null\n\n const content = input.slice(start + 1, closeIdx)\n if (content.includes('\\n')) return null\n\n // Must be followed by space or end of string\n if (closeIdx + 1 < input.length && input.charCodeAt(closeIdx + 1) !== 32 && input.charCodeAt(closeIdx + 1) !== 10) return null\n\n return { node: createUnderline(parseInlineFast(content)), end: closeIdx + 1 }\n}\n\n// ============================================================\n// Emoji Map\n// ============================================================\n\nconst EMOJI_MAP: Record<string, string> = {\n smile: '😄', laughing: '😆', blush: '😊', smiley: '😃', relaxed: '☺️',\n heart: '❤️', 'thumbsup': '👍', 'thumbsdown': '👎', ok_hand: '👌',\n wave: '👋', clap: '👏', raised_hands: '🙌', pray: '🙏',\n fire: '🔥', star: '⭐', sparkles: '✨', zap: '⚡',\n warning: '⚠️', x: '❌', white_check_mark: '✅', question: '❓',\n exclamation: '❗', bulb: '💡', memo: '📝', book: '📖',\n rocket: '🚀', tada: '🎉', eyes: '👀', thinking: '🤔',\n sob: '😭', joy: '😂', wink: '😉', grin: '😁',\n sweat_smile: '😅', sunglasses: '😎', heart_eyes: '😍',\n 100: '💯', boom: '💥', muscle: '💪', point_up: '☝️',\n point_down: '👇', point_left: '👈', point_right: '👉',\n see_no_evil: '🙈', hear_no_evil: '🙉', speak_no_evil: '🙊',\n coffee: '☕', beer: '🍺', pizza: '🍕', hamburger: '🍔',\n dog: '🐶', cat: '🐱', bug: '🐛', penguin: '🐧',\n checkered_flag: '🏁', trophy: '🏆', gem: '💎', wrench: '🔧',\n hammer: '🔨', gear: '⚙️', link: '🔗', lock: '🔒',\n key: '🔑', bell: '🔔', calendar: '📅', clock: '🕐',\n earth_americas: '🌎', sunny: '☀️', cloud: '☁️', umbrella: '☂️',\n snowflake: '❄️', rainbow: '🌈', ocean: '🌊',\n '+1': '👍', '-1': '👎',\n}\n","/**\n * @pre-markdown/parser - Incremental Parser\n *\n * Implements incremental parsing protocol:\n * 1. Detect changed line ranges from edit operations\n * 2. Partially reparse only affected blocks\n * 3. Merge changed blocks into existing AST\n * 4. Emit change events via EventBus\n *\n * Optimizations:\n * - Line-level hash fingerprints for fast change detection\n * - AST node reuse for unchanged blocks\n * - Block fingerprint cache for structural matching\n */\n\nimport type { Document, BlockNode } from '@pre-markdown/core'\nimport { createDocument, EventBus } from '@pre-markdown/core'\nimport type { EditorEvents } from '@pre-markdown/core'\nimport { parseBlocks, parseBlockLines } from './block/parser.js'\nimport type { BlockParserOptions } from './block/parser.js'\n\n/** Fast FNV-1a 32-bit hash for line fingerprinting */\nfunction fnv1a(str: string): number {\n let hash = 0x811c9dc5 | 0\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i)\n hash = (hash * 0x01000193) | 0\n }\n return hash >>> 0\n}\n\n/** Combine multiple hashes into one (for block fingerprint from line hashes) */\nfunction combineHashes(hashes: number[], from: number, to: number): number {\n let h = 0x811c9dc5 | 0\n for (let i = from; i < to; i++) {\n h ^= hashes[i]!\n h = (h * 0x01000193) | 0\n }\n return h >>> 0\n}\n\n/**\n * LRU cache mapping block fingerprints to previously parsed BlockNode subtrees.\n * When an edit only shifts blocks around without changing their content,\n * the fingerprint will match and we can reuse the old AST node (with already-\n * resolved inline content), avoiding a full reparse.\n *\n * Capacity is capped to prevent unbounded memory growth.\n */\nclass LRUBlockCache {\n private map = new Map<number, BlockNode>()\n private readonly capacity: number\n\n constructor(capacity: number = 256) {\n this.capacity = capacity\n }\n\n get(fingerprint: number): BlockNode | undefined {\n const node = this.map.get(fingerprint)\n if (node !== undefined) {\n // Move to end (most recently used) by re-inserting\n this.map.delete(fingerprint)\n this.map.set(fingerprint, node)\n }\n return node\n }\n\n set(fingerprint: number, node: BlockNode): void {\n // If already present, delete first to refresh insertion order\n if (this.map.has(fingerprint)) {\n this.map.delete(fingerprint)\n }\n this.map.set(fingerprint, node)\n // Evict oldest entries if over capacity\n if (this.map.size > this.capacity) {\n // Map iterator yields in insertion order — first key is the LRU entry\n const oldest = this.map.keys().next().value as number\n this.map.delete(oldest)\n }\n }\n\n /** Bulk-populate cache from an array of fingerprint→node pairs */\n populate(metas: BlockMeta[], nodes: BlockNode[]): void {\n for (let i = 0; i < metas.length; i++) {\n this.set(metas[i]!.fingerprint, nodes[i]!)\n }\n }\n\n clear(): void {\n this.map.clear()\n }\n\n get size(): number {\n return this.map.size\n }\n}\n\n/** Describes an edit operation */\nexport interface EditOperation {\n /** Start line index (0-based, inclusive) */\n fromLine: number\n /** End line index (0-based, exclusive) — lines being replaced */\n toLine: number\n /** New text to insert (may contain newlines) */\n newText: string\n}\n\n/** Result of incremental parse */\nexport interface IncrementalParseResult {\n /** Updated document AST */\n document: Document\n /** Range of lines that were reparsed */\n affectedRange: { from: number; to: number }\n /** Number of new blocks generated */\n newBlockCount: number\n /** Number of old blocks replaced */\n oldBlockCount: number\n /** Number of blocks reused from old AST */\n reusedBlockCount: number\n /** Parse duration in ms */\n duration: number\n}\n\n/** Block metadata for incremental tracking */\ninterface BlockMeta {\n /** Start line index (0-based) in the source */\n startLine: number\n /** End line index (0-based, exclusive) */\n endLine: number\n /** Combined hash of source lines [startLine, endLine) */\n fingerprint: number\n}\n\n/**\n * Incremental parser that maintains state between edits.\n *\n * Instead of re-parsing the entire document on every keystroke,\n * it detects the affected block range and only reparses that portion,\n * then splices the new blocks into the existing AST.\n */\nexport class IncrementalParser {\n private lines: string[] = []\n private lineHashes: number[] = []\n private document: Document\n private options: Required<BlockParserOptions>\n private eventBus: EventBus<EditorEvents> | null = null\n /** Per-block metadata tracking source line ranges and fingerprints */\n private blockMetas: BlockMeta[] = []\n /** LRU cache: block fingerprint → previously parsed BlockNode subtree */\n private blockCache = new LRUBlockCache(256)\n\n constructor(\n initialText: string = '',\n options?: BlockParserOptions,\n eventBus?: EventBus<EditorEvents>,\n ) {\n this.options = {\n gfmTables: true,\n mathBlocks: true,\n containers: true,\n toc: true,\n footnotes: true,\n lazyInline: false,\n ...options,\n }\n this.eventBus = eventBus ?? null\n this.lines = initialText.split('\\n')\n this.lineHashes = this.lines.map(fnv1a)\n this.document = parseBlocks(initialText, this.options)\n this.buildBlockMetas()\n }\n\n /** Get current document AST */\n getDocument(): Document {\n return this.document\n }\n\n /** Get current source text */\n getText(): string {\n return this.lines.join('\\n')\n }\n\n /** Get current lines */\n getLines(): readonly string[] {\n return this.lines\n }\n\n /** Get current line hashes (FNV-1a) */\n getLineHashes(): readonly number[] {\n return this.lineHashes\n }\n\n /** Get block metadata (for testing/debugging) */\n getBlockMetas(): readonly BlockMeta[] {\n return this.blockMetas\n }\n\n /**\n * Apply an edit and incrementally reparse.\n */\n applyEdit(edit: EditOperation): IncrementalParseResult {\n const startTime = performance.now()\n\n // 1. Apply the text edit to lines array and maintain hashes\n const newLines = edit.newText.split('\\n')\n const newHashes = newLines.map(fnv1a)\n const deletedLineCount = edit.toLine - edit.fromLine\n const insertedLineCount = newLines.length\n const lineDelta = insertedLineCount - deletedLineCount\n\n this.lines.splice(edit.fromLine, deletedLineCount, ...newLines)\n this.lineHashes.splice(edit.fromLine, deletedLineCount, ...newHashes)\n\n // 2. Find affected block range using block metas\n const { blockStart, blockEnd } = this.findAffectedBlockRangeFromMetas(\n edit.fromLine,\n edit.toLine,\n lineDelta,\n )\n\n // 3. Extract the lines to reparse\n const reparseFrom = blockStart < this.blockMetas.length\n ? this.blockMetas[blockStart]!.startLine\n : this.lines.length\n // Adjust blockEnd metas for line delta\n let reparseTo: number\n if (blockEnd < this.blockMetas.length) {\n reparseTo = this.blockMetas[blockEnd]!.startLine + lineDelta\n } else {\n reparseTo = this.lines.length\n }\n // Clamp\n reparseTo = Math.min(reparseTo, this.lines.length)\n const reparseFromClamped = Math.max(0, Math.min(reparseFrom, this.lines.length))\n\n const linesToReparse = this.lines.slice(reparseFromClamped, reparseTo)\n\n // 4. Reparse only the affected range\n const newBlocks = linesToReparse.length > 0\n ? parseBlockLines(linesToReparse, 0, linesToReparse.length, this.options)\n : []\n\n // 5. Splice new blocks into the existing AST, reusing unchanged blocks\n // For each newly parsed block, compute its fingerprint from the source lines.\n // If the fingerprint matches a cached block, reuse the old AST node\n // (which may already have resolved inline content from lazy parsing).\n const oldBlockCount = blockEnd - blockStart\n const oldChildren = this.document.children\n\n // Compute fingerprints for new blocks and attempt cache reuse\n let cacheHits = 0\n if (newBlocks.length > 0) {\n let newLineAcc = reparseFromClamped\n for (let bi = 0; bi < newBlocks.length; bi++) {\n const block = newBlocks[bi]!\n const blockLineCount = this.estimateBlockLineCount(block)\n const blockEndLine = Math.min(newLineAcc + blockLineCount, this.lines.length)\n const fp = combineHashes(this.lineHashes, newLineAcc, blockEndLine)\n // Try to reuse a cached block with the same fingerprint\n const cached = this.blockCache.get(fp)\n if (cached && cached.type === block.type) {\n newBlocks[bi] = cached\n cacheHits++\n }\n newLineAcc = blockEndLine\n }\n }\n\n // Blocks before the edit range are reused as-is (same object references)\n const beforeBlocks = oldChildren.slice(0, blockStart)\n // Blocks after the edit range are reused as-is\n const afterBlocks = oldChildren.slice(blockEnd)\n\n const updatedChildren = [\n ...beforeBlocks,\n ...newBlocks,\n ...afterBlocks,\n ]\n\n const reusedBlockCount = beforeBlocks.length + afterBlocks.length + cacheHits\n\n this.document = createDocument(updatedChildren)\n\n // 6. Rebuild block metas\n this.buildBlockMetas()\n\n const duration = performance.now() - startTime\n\n // 7. Emit events\n if (this.eventBus) {\n this.eventBus.emit('content:change', {\n text: this.getText(),\n from: edit.fromLine,\n to: edit.toLine,\n inserted: edit.newText,\n })\n this.eventBus.emit('parse:done', {\n documentId: this.document.id ?? 0,\n duration,\n })\n }\n\n return {\n document: this.document,\n affectedRange: { from: reparseFromClamped, to: reparseTo },\n newBlockCount: newBlocks.length,\n oldBlockCount,\n reusedBlockCount,\n duration,\n }\n }\n\n /**\n * Full reparse — used when edits are too complex for incremental update.\n */\n fullReparse(): Document {\n const startTime = performance.now()\n const text = this.lines.join('\\n')\n this.lineHashes = this.lines.map(fnv1a)\n this.document = parseBlocks(text, this.options)\n this.buildBlockMetas()\n const duration = performance.now() - startTime\n\n if (this.eventBus) {\n this.eventBus.emit('parse:done', {\n documentId: this.document.id ?? 0,\n duration,\n })\n }\n\n return this.document\n }\n\n /**\n * Build block metadata array from current document + lines.\n * Assigns each block its source line range and fingerprint.\n */\n private buildBlockMetas(): void {\n const children = this.document.children\n const metas: BlockMeta[] = new Array(children.length)\n let lineAcc = 0\n\n for (let i = 0; i < children.length; i++) {\n const lc = this.estimateBlockLineCount(children[i]!)\n const startLine = lineAcc\n const endLine = Math.min(lineAcc + lc, this.lines.length)\n const fingerprint = combineHashes(this.lineHashes, startLine, endLine)\n metas[i] = { startLine, endLine, fingerprint }\n // Populate LRU cache: fingerprint → block node\n this.blockCache.set(fingerprint, children[i]!)\n lineAcc = endLine\n }\n\n this.blockMetas = metas\n }\n\n /**\n * Find affected block range using block metas for precise mapping.\n * Returns [blockStart, blockEnd) — the half-open range of blocks to replace.\n */\n private findAffectedBlockRangeFromMetas(\n editFromLine: number,\n editToLine: number,\n _lineDelta: number,\n ): { blockStart: number; blockEnd: number } {\n const metas = this.blockMetas\n if (metas.length === 0) {\n return { blockStart: 0, blockEnd: 0 }\n }\n\n // Binary search for blockStart: first block whose endLine > editFromLine\n let blockStart = 0\n {\n let lo = 0, hi = metas.length - 1\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1\n if (metas[mid]!.endLine <= editFromLine) {\n lo = mid + 1\n } else {\n blockStart = mid\n hi = mid - 1\n }\n }\n }\n // Safety: include one block before for boundary effects\n blockStart = Math.max(0, blockStart - 1)\n\n // Binary search for blockEnd: first block whose startLine >= editToLine\n let blockEnd = metas.length\n {\n let lo = blockStart, hi = metas.length - 1\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1\n if (metas[mid]!.startLine < editToLine) {\n lo = mid + 1\n } else {\n blockEnd = mid\n hi = mid - 1\n }\n }\n }\n // Safety: include one block after for boundary effects\n blockEnd = Math.min(metas.length, blockEnd + 1)\n\n return { blockStart, blockEnd }\n }\n\n /**\n * Estimate how many source lines a block node spans.\n * This is a heuristic — precise tracking would require SourceLocation data.\n */\n private estimateBlockLineCount(node: BlockNode): number {\n switch (node.type) {\n case 'heading':\n return 2 // heading + blank line\n case 'paragraph': {\n // If lazy inline, use _raw for estimation\n if (node._raw) {\n const nlCount = node._raw.split('\\n').length\n return nlCount + 1\n }\n // Count newlines in children text\n let textLen = 0\n for (const child of node.children) {\n if (child.type === 'text') textLen += child.value.length\n if (child.type === 'softBreak') textLen += 1\n }\n return Math.max(2, Math.ceil(textLen / 80) + 1)\n }\n case 'codeBlock': {\n const lineCount = node.value.split('\\n').length\n return lineCount + 3 // opening fence + content + closing fence + blank line\n }\n case 'blockquote': {\n let count = 0\n for (const child of node.children) {\n count += this.estimateBlockLineCount(child)\n }\n return Math.max(2, count + 1)\n }\n case 'list': {\n let count = 0\n for (const item of node.children) {\n count += this.estimateBlockLineCount(item)\n }\n return count + 1\n }\n case 'listItem': {\n let count = 1\n for (const child of node.children) {\n count += this.estimateBlockLineCount(child) - 1\n }\n return Math.max(1, count)\n }\n case 'table': {\n return node.children.length + 2 // header + delimiter + rows + blank\n }\n case 'thematicBreak':\n return 2\n case 'mathBlock': {\n const lines = node.value.split('\\n').length\n return lines + 3\n }\n case 'container': {\n let count = 2 // open + close\n for (const child of node.children) {\n count += this.estimateBlockLineCount(child)\n }\n return count + 1\n }\n case 'details': {\n let count = 2 // open + close\n for (const child of node.children) {\n count += this.estimateBlockLineCount(child)\n }\n return count + 1\n }\n case 'footnoteDefinition': {\n let count = 1\n for (const child of node.children) {\n count += this.estimateBlockLineCount(child)\n }\n return count + 1\n }\n default:\n return 2\n }\n }\n}\n"],"mappings":"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","names":["import_core","annotation","content","node","import_core"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { BlockNode, Document, InlineNode, EventBus, EditorEvents } from '@pre-markdown/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @pre-markdown/parser - Block-Level Parser
|
|
5
|
+
*
|
|
6
|
+
* Parses Markdown text into block-level AST nodes.
|
|
7
|
+
* Implements CommonMark block structure algorithm with extensions.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Parser options */
|
|
11
|
+
interface BlockParserOptions {
|
|
12
|
+
/** Enable GFM table parsing */
|
|
13
|
+
gfmTables?: boolean;
|
|
14
|
+
/** Enable math block parsing */
|
|
15
|
+
mathBlocks?: boolean;
|
|
16
|
+
/** Enable custom container parsing */
|
|
17
|
+
containers?: boolean;
|
|
18
|
+
/** Enable TOC parsing */
|
|
19
|
+
toc?: boolean;
|
|
20
|
+
/** Enable footnote definition parsing */
|
|
21
|
+
footnotes?: boolean;
|
|
22
|
+
/** Lazy inline parsing: store raw text, defer parseInline to render time */
|
|
23
|
+
lazyInline?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse a Markdown string into a Document AST.
|
|
27
|
+
*/
|
|
28
|
+
declare function parseBlocks(input: string, options?: BlockParserOptions): Document;
|
|
29
|
+
/**
|
|
30
|
+
* Parse a range of lines into block-level nodes.
|
|
31
|
+
*/
|
|
32
|
+
declare function parseBlockLines(lines: string[], start: number, end: number, opts: Required<BlockParserOptions>): BlockNode[];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @pre-markdown/parser - Inline Parser
|
|
36
|
+
*
|
|
37
|
+
* Parses inline Markdown content into inline AST nodes.
|
|
38
|
+
* Handles emphasis, links, images, code spans, and extensions.
|
|
39
|
+
*
|
|
40
|
+
* Performance: Uses sticky regex (y flag) + lastIndex to avoid input.slice() calls.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Parse inline content from a string.
|
|
45
|
+
*/
|
|
46
|
+
declare function parseInline(input: string): InlineNode[];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @pre-markdown/parser - Incremental Parser
|
|
50
|
+
*
|
|
51
|
+
* Implements incremental parsing protocol:
|
|
52
|
+
* 1. Detect changed line ranges from edit operations
|
|
53
|
+
* 2. Partially reparse only affected blocks
|
|
54
|
+
* 3. Merge changed blocks into existing AST
|
|
55
|
+
* 4. Emit change events via EventBus
|
|
56
|
+
*
|
|
57
|
+
* Optimizations:
|
|
58
|
+
* - Line-level hash fingerprints for fast change detection
|
|
59
|
+
* - AST node reuse for unchanged blocks
|
|
60
|
+
* - Block fingerprint cache for structural matching
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/** Describes an edit operation */
|
|
64
|
+
interface EditOperation {
|
|
65
|
+
/** Start line index (0-based, inclusive) */
|
|
66
|
+
fromLine: number;
|
|
67
|
+
/** End line index (0-based, exclusive) — lines being replaced */
|
|
68
|
+
toLine: number;
|
|
69
|
+
/** New text to insert (may contain newlines) */
|
|
70
|
+
newText: string;
|
|
71
|
+
}
|
|
72
|
+
/** Result of incremental parse */
|
|
73
|
+
interface IncrementalParseResult {
|
|
74
|
+
/** Updated document AST */
|
|
75
|
+
document: Document;
|
|
76
|
+
/** Range of lines that were reparsed */
|
|
77
|
+
affectedRange: {
|
|
78
|
+
from: number;
|
|
79
|
+
to: number;
|
|
80
|
+
};
|
|
81
|
+
/** Number of new blocks generated */
|
|
82
|
+
newBlockCount: number;
|
|
83
|
+
/** Number of old blocks replaced */
|
|
84
|
+
oldBlockCount: number;
|
|
85
|
+
/** Number of blocks reused from old AST */
|
|
86
|
+
reusedBlockCount: number;
|
|
87
|
+
/** Parse duration in ms */
|
|
88
|
+
duration: number;
|
|
89
|
+
}
|
|
90
|
+
/** Block metadata for incremental tracking */
|
|
91
|
+
interface BlockMeta {
|
|
92
|
+
/** Start line index (0-based) in the source */
|
|
93
|
+
startLine: number;
|
|
94
|
+
/** End line index (0-based, exclusive) */
|
|
95
|
+
endLine: number;
|
|
96
|
+
/** Combined hash of source lines [startLine, endLine) */
|
|
97
|
+
fingerprint: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Incremental parser that maintains state between edits.
|
|
101
|
+
*
|
|
102
|
+
* Instead of re-parsing the entire document on every keystroke,
|
|
103
|
+
* it detects the affected block range and only reparses that portion,
|
|
104
|
+
* then splices the new blocks into the existing AST.
|
|
105
|
+
*/
|
|
106
|
+
declare class IncrementalParser {
|
|
107
|
+
private lines;
|
|
108
|
+
private lineHashes;
|
|
109
|
+
private document;
|
|
110
|
+
private options;
|
|
111
|
+
private eventBus;
|
|
112
|
+
/** Per-block metadata tracking source line ranges and fingerprints */
|
|
113
|
+
private blockMetas;
|
|
114
|
+
/** LRU cache: block fingerprint → previously parsed BlockNode subtree */
|
|
115
|
+
private blockCache;
|
|
116
|
+
constructor(initialText?: string, options?: BlockParserOptions, eventBus?: EventBus<EditorEvents>);
|
|
117
|
+
/** Get current document AST */
|
|
118
|
+
getDocument(): Document;
|
|
119
|
+
/** Get current source text */
|
|
120
|
+
getText(): string;
|
|
121
|
+
/** Get current lines */
|
|
122
|
+
getLines(): readonly string[];
|
|
123
|
+
/** Get current line hashes (FNV-1a) */
|
|
124
|
+
getLineHashes(): readonly number[];
|
|
125
|
+
/** Get block metadata (for testing/debugging) */
|
|
126
|
+
getBlockMetas(): readonly BlockMeta[];
|
|
127
|
+
/**
|
|
128
|
+
* Apply an edit and incrementally reparse.
|
|
129
|
+
*/
|
|
130
|
+
applyEdit(edit: EditOperation): IncrementalParseResult;
|
|
131
|
+
/**
|
|
132
|
+
* Full reparse — used when edits are too complex for incremental update.
|
|
133
|
+
*/
|
|
134
|
+
fullReparse(): Document;
|
|
135
|
+
/**
|
|
136
|
+
* Build block metadata array from current document + lines.
|
|
137
|
+
* Assigns each block its source line range and fingerprint.
|
|
138
|
+
*/
|
|
139
|
+
private buildBlockMetas;
|
|
140
|
+
/**
|
|
141
|
+
* Find affected block range using block metas for precise mapping.
|
|
142
|
+
* Returns [blockStart, blockEnd) — the half-open range of blocks to replace.
|
|
143
|
+
*/
|
|
144
|
+
private findAffectedBlockRangeFromMetas;
|
|
145
|
+
/**
|
|
146
|
+
* Estimate how many source lines a block node spans.
|
|
147
|
+
* This is a heuristic — precise tracking would require SourceLocation data.
|
|
148
|
+
*/
|
|
149
|
+
private estimateBlockLineCount;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @pre-markdown/parser
|
|
154
|
+
*
|
|
155
|
+
* High-performance incremental Markdown parser.
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Parse a complete Markdown document.
|
|
160
|
+
*
|
|
161
|
+
* @param input - The Markdown source text
|
|
162
|
+
* @param options - Parser options
|
|
163
|
+
* @returns A Document AST node
|
|
164
|
+
*/
|
|
165
|
+
declare function parse(input: string, options?: BlockParserOptions): Document;
|
|
166
|
+
|
|
167
|
+
export { type BlockParserOptions, type EditOperation, type IncrementalParseResult, IncrementalParser, parse, parseBlockLines, parseBlocks, parseInline };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { BlockNode, Document, InlineNode, EventBus, EditorEvents } from '@pre-markdown/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @pre-markdown/parser - Block-Level Parser
|
|
5
|
+
*
|
|
6
|
+
* Parses Markdown text into block-level AST nodes.
|
|
7
|
+
* Implements CommonMark block structure algorithm with extensions.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Parser options */
|
|
11
|
+
interface BlockParserOptions {
|
|
12
|
+
/** Enable GFM table parsing */
|
|
13
|
+
gfmTables?: boolean;
|
|
14
|
+
/** Enable math block parsing */
|
|
15
|
+
mathBlocks?: boolean;
|
|
16
|
+
/** Enable custom container parsing */
|
|
17
|
+
containers?: boolean;
|
|
18
|
+
/** Enable TOC parsing */
|
|
19
|
+
toc?: boolean;
|
|
20
|
+
/** Enable footnote definition parsing */
|
|
21
|
+
footnotes?: boolean;
|
|
22
|
+
/** Lazy inline parsing: store raw text, defer parseInline to render time */
|
|
23
|
+
lazyInline?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse a Markdown string into a Document AST.
|
|
27
|
+
*/
|
|
28
|
+
declare function parseBlocks(input: string, options?: BlockParserOptions): Document;
|
|
29
|
+
/**
|
|
30
|
+
* Parse a range of lines into block-level nodes.
|
|
31
|
+
*/
|
|
32
|
+
declare function parseBlockLines(lines: string[], start: number, end: number, opts: Required<BlockParserOptions>): BlockNode[];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @pre-markdown/parser - Inline Parser
|
|
36
|
+
*
|
|
37
|
+
* Parses inline Markdown content into inline AST nodes.
|
|
38
|
+
* Handles emphasis, links, images, code spans, and extensions.
|
|
39
|
+
*
|
|
40
|
+
* Performance: Uses sticky regex (y flag) + lastIndex to avoid input.slice() calls.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Parse inline content from a string.
|
|
45
|
+
*/
|
|
46
|
+
declare function parseInline(input: string): InlineNode[];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @pre-markdown/parser - Incremental Parser
|
|
50
|
+
*
|
|
51
|
+
* Implements incremental parsing protocol:
|
|
52
|
+
* 1. Detect changed line ranges from edit operations
|
|
53
|
+
* 2. Partially reparse only affected blocks
|
|
54
|
+
* 3. Merge changed blocks into existing AST
|
|
55
|
+
* 4. Emit change events via EventBus
|
|
56
|
+
*
|
|
57
|
+
* Optimizations:
|
|
58
|
+
* - Line-level hash fingerprints for fast change detection
|
|
59
|
+
* - AST node reuse for unchanged blocks
|
|
60
|
+
* - Block fingerprint cache for structural matching
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/** Describes an edit operation */
|
|
64
|
+
interface EditOperation {
|
|
65
|
+
/** Start line index (0-based, inclusive) */
|
|
66
|
+
fromLine: number;
|
|
67
|
+
/** End line index (0-based, exclusive) — lines being replaced */
|
|
68
|
+
toLine: number;
|
|
69
|
+
/** New text to insert (may contain newlines) */
|
|
70
|
+
newText: string;
|
|
71
|
+
}
|
|
72
|
+
/** Result of incremental parse */
|
|
73
|
+
interface IncrementalParseResult {
|
|
74
|
+
/** Updated document AST */
|
|
75
|
+
document: Document;
|
|
76
|
+
/** Range of lines that were reparsed */
|
|
77
|
+
affectedRange: {
|
|
78
|
+
from: number;
|
|
79
|
+
to: number;
|
|
80
|
+
};
|
|
81
|
+
/** Number of new blocks generated */
|
|
82
|
+
newBlockCount: number;
|
|
83
|
+
/** Number of old blocks replaced */
|
|
84
|
+
oldBlockCount: number;
|
|
85
|
+
/** Number of blocks reused from old AST */
|
|
86
|
+
reusedBlockCount: number;
|
|
87
|
+
/** Parse duration in ms */
|
|
88
|
+
duration: number;
|
|
89
|
+
}
|
|
90
|
+
/** Block metadata for incremental tracking */
|
|
91
|
+
interface BlockMeta {
|
|
92
|
+
/** Start line index (0-based) in the source */
|
|
93
|
+
startLine: number;
|
|
94
|
+
/** End line index (0-based, exclusive) */
|
|
95
|
+
endLine: number;
|
|
96
|
+
/** Combined hash of source lines [startLine, endLine) */
|
|
97
|
+
fingerprint: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Incremental parser that maintains state between edits.
|
|
101
|
+
*
|
|
102
|
+
* Instead of re-parsing the entire document on every keystroke,
|
|
103
|
+
* it detects the affected block range and only reparses that portion,
|
|
104
|
+
* then splices the new blocks into the existing AST.
|
|
105
|
+
*/
|
|
106
|
+
declare class IncrementalParser {
|
|
107
|
+
private lines;
|
|
108
|
+
private lineHashes;
|
|
109
|
+
private document;
|
|
110
|
+
private options;
|
|
111
|
+
private eventBus;
|
|
112
|
+
/** Per-block metadata tracking source line ranges and fingerprints */
|
|
113
|
+
private blockMetas;
|
|
114
|
+
/** LRU cache: block fingerprint → previously parsed BlockNode subtree */
|
|
115
|
+
private blockCache;
|
|
116
|
+
constructor(initialText?: string, options?: BlockParserOptions, eventBus?: EventBus<EditorEvents>);
|
|
117
|
+
/** Get current document AST */
|
|
118
|
+
getDocument(): Document;
|
|
119
|
+
/** Get current source text */
|
|
120
|
+
getText(): string;
|
|
121
|
+
/** Get current lines */
|
|
122
|
+
getLines(): readonly string[];
|
|
123
|
+
/** Get current line hashes (FNV-1a) */
|
|
124
|
+
getLineHashes(): readonly number[];
|
|
125
|
+
/** Get block metadata (for testing/debugging) */
|
|
126
|
+
getBlockMetas(): readonly BlockMeta[];
|
|
127
|
+
/**
|
|
128
|
+
* Apply an edit and incrementally reparse.
|
|
129
|
+
*/
|
|
130
|
+
applyEdit(edit: EditOperation): IncrementalParseResult;
|
|
131
|
+
/**
|
|
132
|
+
* Full reparse — used when edits are too complex for incremental update.
|
|
133
|
+
*/
|
|
134
|
+
fullReparse(): Document;
|
|
135
|
+
/**
|
|
136
|
+
* Build block metadata array from current document + lines.
|
|
137
|
+
* Assigns each block its source line range and fingerprint.
|
|
138
|
+
*/
|
|
139
|
+
private buildBlockMetas;
|
|
140
|
+
/**
|
|
141
|
+
* Find affected block range using block metas for precise mapping.
|
|
142
|
+
* Returns [blockStart, blockEnd) — the half-open range of blocks to replace.
|
|
143
|
+
*/
|
|
144
|
+
private findAffectedBlockRangeFromMetas;
|
|
145
|
+
/**
|
|
146
|
+
* Estimate how many source lines a block node spans.
|
|
147
|
+
* This is a heuristic — precise tracking would require SourceLocation data.
|
|
148
|
+
*/
|
|
149
|
+
private estimateBlockLineCount;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @pre-markdown/parser
|
|
154
|
+
*
|
|
155
|
+
* High-performance incremental Markdown parser.
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Parse a complete Markdown document.
|
|
160
|
+
*
|
|
161
|
+
* @param input - The Markdown source text
|
|
162
|
+
* @param options - Parser options
|
|
163
|
+
* @returns A Document AST node
|
|
164
|
+
*/
|
|
165
|
+
declare function parse(input: string, options?: BlockParserOptions): Document;
|
|
166
|
+
|
|
167
|
+
export { type BlockParserOptions, type EditOperation, type IncrementalParseResult, IncrementalParser, parse, parseBlockLines, parseBlocks, parseInline };
|