@pierre/words 0.0.0-stage → 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-BAclEeRf.js","names":[],"sources":["../html/render.ts","../html/dom.ts"],"sourcesContent":["import { createHtmlSession } from '@pierre/words';\nimport type { HtmlUpdate } from '@pierre/words';\n\nimport type {\n CodeHighlighterSession,\n CodeHighlightUpdate,\n HtmlOptions,\n} from './types';\n\n/** Changed lines of the open code fence, for the DOM renderer. */\nexport interface CodeHtmlUpdate extends Omit<CodeHighlightUpdate, 'fullHtml'> {\n /** Changes when the markup around the fence lines changes. */\n key: number;\n lastLine: number;\n /** Lines shown in the gutter, or undefined without line numbers. */\n numbers: number | undefined;\n /** The whole pending HTML, built on first read. */\n readonly pending: string;\n}\n\ntype RenderedHtmlUpdate = HtmlUpdate & { code?: CodeHtmlUpdate };\n\nconst lineGroup = '<span data-markdown=\"code-lines\">';\n\n/**\n * Wrap code in groups of 64 lines, so the browser lays out only the last group\n * when a streamed line changes. Each LF stays inside its group, so `textContent`\n * does not change. An LF inside an element never splits a group.\n */\nfunction groupLines(body: string): string {\n let result = '';\n let start = 0;\n let lines = 0;\n let depth = 0;\n let tag = body.indexOf('<');\n for (\n let at = body.indexOf('\\n');\n at !== -1;\n at = body.indexOf('\\n', at + 1)\n ) {\n for (; tag !== -1 && tag < at; tag = body.indexOf('<', tag + 1))\n if (body.charCodeAt(tag + 1) === 47) depth--;\n else if (body.charCodeAt(body.indexOf('>', tag) - 1) !== 47) depth++;\n if (++lines >= 64 && depth === 0) {\n result += lineGroup + body.slice(start, at + 1) + '</span>';\n start = at + 1;\n lines = 0;\n }\n }\n return result === '' || start < body.length\n ? result + lineGroup + body.slice(start) + '</span>'\n : result;\n}\n\n/** Gutter line numbers, in the same 64-line groups as the code. */\nfunction lineNumbers(count: number): string {\n let html = '';\n for (let line = 1; line <= count; line += 64) {\n html += lineGroup + line;\n for (let next = line + 1; next < line + 64 && next <= count; next++)\n html += '\\n' + next;\n html += (line + 64 <= count ? '\\n' : '') + '</span>';\n }\n return html;\n}\n\n/** The code buttons as bits: 1 for copy, 2 for download. Equal inline option objects give equal bits. */\nexport const controlFlags = (controls: HtmlOptions['controls']): number => {\n const code = typeof controls === 'object' ? controls.code : controls;\n return code === false\n ? 0\n : typeof code === 'object'\n ? (code.copy === false ? 0 : 1) | (code.download === false ? 0 : 2)\n : 3;\n};\n\n/** The HTML before and after the code of a fenced block. */\nfunction codeWrapper(\n attributes: string,\n language: string,\n incomplete: boolean,\n numbers: number | undefined,\n options: HtmlOptions\n): [string, string] {\n const flags = controlFlags(options.controls);\n const button = (action: string): string =>\n `<button type=\"button\" data-code-action=\"${action.toLowerCase()}\" aria-label=\"${action} code\"${incomplete ? ' disabled=\"\"' : ''}>${action}</button>`;\n return [\n `<div data-markdown=\"code-block\" data-language=\"${escapeHtml(language)}\"${incomplete ? ' data-incomplete=\"true\"' : ''}><div data-markdown=\"code-header\"><span>${escapeHtml(language)}</span><span>${(flags & 1) !== 0 ? button('Copy') : ''}${(flags & 2) !== 0 ? button('Download') : ''}</span></div><pre dir=\"ltr\">${numbers === undefined ? '' : `<span data-markdown=\"line-numbers\" aria-hidden=\"true\">${lineNumbers(numbers)}</span>`}<code${attributes}>`,\n '</code></pre></div>',\n ];\n}\n\n/** Escape text for use in HTML. */\nexport function escapeHtml(value: string): string {\n let result = '';\n let from = 0;\n for (let at = 0; at < value.length; at++) {\n let entity: string;\n switch (value.charCodeAt(at)) {\n case 34:\n entity = '&quot;';\n break;\n case 38:\n entity = '&amp;';\n break;\n case 39:\n entity = '&#39;';\n break;\n case 60:\n entity = '&lt;';\n break;\n case 62:\n entity = '&gt;';\n break;\n default:\n continue;\n }\n result += value.slice(from, at) + entity;\n from = at + 1;\n }\n return from === 0 ? value : result + value.slice(from);\n}\n\n/** Decode only the entities that Wasm writes. The result is text, not HTML. */\nfunction decodeHtml(value: string): string {\n let result = '';\n let from = 0;\n for (\n let at = value.indexOf('&');\n at !== -1;\n at = value.indexOf('&', at + 1)\n ) {\n let character: string;\n // The `;` of these entities is three to five characters after the `&`.\n let end = at + 3;\n while (end < at + 6 && value.charCodeAt(end) !== 59) end++;\n switch (value.slice(at + 1, end)) {\n case 'amp':\n character = '&';\n break;\n case 'lt':\n character = '<';\n break;\n case 'gt':\n character = '>';\n break;\n case 'quot':\n character = '\"';\n break;\n case '#39':\n case '#x27':\n character = \"'\";\n break;\n default:\n continue;\n }\n result += value.slice(from, at) + character;\n from = end + 1;\n }\n return from === 0 ? value : result + value.slice(from);\n}\n\n/** Hooks can come from untyped code, and a non-string would print as text. */\nfunction hookHtml(html: unknown): string {\n if (typeof html !== 'string')\n throw new TypeError('HTML hooks must return strings');\n return html;\n}\n\n/**\n * Return `url` if it is relative or uses http, https, mailto, tel, or a scheme\n * the parser autolinks (ftp, xmpp). Reject network paths.\n */\nexport function defaultUrlTransform(url: string): string | undefined {\n // Browsers ignore spaces and control characters in URLs.\n let normalized = '';\n let from = 0;\n for (let at = 0; at < url.length; at++) {\n const code = url.charCodeAt(at);\n if (code <= 32 || (code >= 127 && code <= 159)) {\n normalized += url.slice(from, at);\n from = at + 1;\n }\n }\n normalized = from === 0 ? url : normalized + url.slice(from);\n // Browsers read `\\` as `/`, so `/\\host` and `\\\\host` are network paths too.\n const second = normalized.charCodeAt(1);\n if (\n normalized.charCodeAt(0) === 92 ||\n (normalized.charCodeAt(0) === 47 && (second === 47 || second === 92))\n )\n return undefined;\n // The scheme ends at the last `:` before the path, query, or fragment.\n let colon = -1;\n scheme: for (let at = 0; at < normalized.length; at++)\n switch (normalized.charCodeAt(at)) {\n case 35:\n case 47:\n case 63:\n break scheme;\n case 58:\n colon = at;\n }\n if (colon >= 0)\n switch (normalized.slice(0, colon).toLowerCase()) {\n case 'http':\n case 'https':\n case 'ftp':\n case 'mailto':\n case 'tel':\n case 'xmpp':\n break;\n default:\n return undefined;\n }\n return url;\n}\n\nconst voidTags = new Set(['br', 'hr', 'img', 'input']);\n\n/** Whether the tag at [at, end) of Wasm HTML is void. All but `<input>` end with ` />`. */\nconst isVoidAt = (html: string, at: number, end: number): boolean =>\n html.charCodeAt(end - 2) === 47 || html.startsWith('<input', at);\n\n/** Whether a character code continues a tag name, as `\\w` does. */\nconst isNameCode = (code: number): boolean =>\n (code >= 48 && code <= 57) ||\n (code >= 65 && code <= 90) ||\n code === 95 ||\n (code >= 97 && code <= 122);\n\n/** The language of a fence from the attributes of its `<code>`. */\nfunction codeLanguage(attributes: string): string {\n const at = attributes.indexOf('class=\"language-');\n return at < 0\n ? 'text'\n : decodeHtml(attributes.slice(at + 16, attributes.indexOf('\"', at + 16)));\n}\n\n/**\n * Run `transform` on each `tag` element, without a syntax tree. Inner elements\n * run first, and each element runs once.\n */\nfunction mapElements(\n html: string,\n tag: string,\n transform: (html: string) => string\n): string {\n const expression = new RegExp(`<(/?)${tag}\\\\b[^>]*>`, 'g');\n const isVoid = voidTags.has(tag);\n const open: string[] = [];\n let result = '';\n let cursor = 0;\n for (\n let match = expression.exec(html);\n match !== null;\n match = expression.exec(html)\n ) {\n let piece = html.slice(cursor, match.index);\n cursor = expression.lastIndex;\n if (match[1] === '' && !isVoid) {\n if (open.length === 0) result += piece;\n else open[open.length - 1] += piece;\n open.push(match[0]);\n continue;\n }\n if (match[1] !== '' && (isVoid || open.length === 0)) piece += match[0];\n else {\n const replacement = hookHtml(\n transform(match[1] === '' ? match[0] : open.pop()! + piece + match[0])\n );\n piece = match[1] === '' ? piece + replacement : replacement;\n }\n if (open.length === 0) result += piece;\n else open[open.length - 1] += piece;\n }\n return result + open.join('') + html.slice(cursor);\n}\n\n/** Apply element filters and URL checks to HTML from Wasm, and add `data-markdown`. Runs before hooks. */\nfunction decorate(html: string, options: HtmlOptions): string {\n const { allowedElements, disallowedElements } = options;\n if (allowedElements !== undefined && disallowedElements !== undefined)\n throw new Error('Use either allowedElements or disallowedElements');\n const filtered =\n allowedElements !== undefined || disallowedElements !== undefined;\n const excluded = (tag: string): boolean =>\n allowedElements !== undefined\n ? !allowedElements.includes(tag)\n : disallowedElements!.includes(tag);\n let result = '';\n let from = 0;\n // Tags open inside an excluded element, which is dropped whole.\n let dropped = 0;\n // Wasm writes strict tags and escapes `<` in text, so each `<` starts a tag.\n for (\n let at = html.indexOf('<'), end = 0;\n at !== -1;\n at = html.indexOf('<', end)\n ) {\n const closing = html.charCodeAt(at + 1) === 47;\n // A closing tag stays as it is, unless a filter can drop it.\n if (closing && !filtered) {\n end = at + 2;\n continue;\n }\n end = html.indexOf('>', at) + 1;\n if (end === 0) break;\n if (dropped > 0) {\n if (!closing) dropped += isVoidAt(html, at, end) ? 0 : 1;\n else if (--dropped === 0) from = end;\n continue;\n }\n if (closing) {\n if (\n options.unwrapDisallowed === true &&\n excluded(html.slice(at + 2, end - 1))\n ) {\n result += html.slice(from, at);\n from = end;\n }\n continue;\n }\n let space = at + 1;\n for (\n let code = html.charCodeAt(space);\n code !== 32 && code !== 62;\n code = html.charCodeAt(++space)\n );\n const tag = html.slice(at + 1, space);\n if (filtered && excluded(tag)) {\n result += html.slice(from, at);\n from = end;\n if (options.unwrapDisallowed !== true && !voidTags.has(tag)) dropped = 1;\n continue;\n }\n // Most tags have no attributes.\n if (space === end - 1) {\n result += html.slice(from, space) + ' data-markdown=\"' + tag + '\">';\n from = end;\n continue;\n }\n result += html.slice(from, at);\n from = end;\n // A void tag ends with ` /`, which HTML does not need.\n let stop = end - 1;\n if (html.charCodeAt(stop - 1) === 47)\n for (stop--; html.charCodeAt(stop - 1) === 32; stop--);\n const text = html.slice(space, stop);\n // Wasm marks a pending link with this attribute instead of a destination.\n const pending = tag === 'a' && text === ' data-markdown-incomplete';\n let attributes = '';\n if (!pending && text !== '') {\n // Values hold no `\"`, so only a real attribute follows a closing quote.\n const note = tag === 'a' ? text.indexOf('\" data-footnote-') : -1;\n const footnote = note > 0 && text.charCodeAt(note - 1) !== 61;\n let invalidImage = false;\n let copied = 0;\n // Warning: take whole attributes in order. A search for one name also\n // finds it in the text of a value, such as an `alt` that ends in\n // ` src=`, and the rewrite then moves the quotes of the attributes\n // after it.\n for (\n let equals = text.indexOf('=\"');\n equals !== -1;\n equals = text.indexOf('=\"', copied)\n ) {\n const start = text.lastIndexOf(' ', equals);\n const key = text.slice(start + 1, equals);\n const close = text.indexOf('\"', equals + 2);\n const value = text.slice(equals + 2, close);\n attributes += text.slice(copied, start);\n copied = close + 1;\n switch (key) {\n case 'align':\n attributes += ` style=\"text-align:${value}\"`;\n break;\n case 'id':\n attributes += ` id=\"${escapeHtml(options.idPrefix ?? '')}${value}\"`;\n break;\n case 'href':\n case 'src': {\n const decoded = decodeHtml(value);\n const transformed =\n options.urlTransform === undefined\n ? decoded\n : options.urlTransform(decoded, key);\n let url =\n transformed == null\n ? ''\n : (defaultUrlTransform(transformed) ?? '');\n if (url === '' && transformed !== '') {\n invalidImage ||= tag === 'img';\n break;\n }\n // Only generated footnote links target the prefixed footnote ids.\n if (footnote && url.startsWith('#'))\n url = '#' + (options.idPrefix ?? '') + url.slice(1);\n attributes += ` ${key}=\"${escapeHtml(url)}\"`;\n break;\n }\n default:\n attributes += text.slice(start, copied);\n }\n }\n if (invalidImage) continue;\n attributes += text.slice(copied);\n }\n if (tag === 'img') attributes += ' loading=\"lazy\"';\n else if (tag === 'input') attributes += ' readonly=\"\"';\n result += `<${tag} data-markdown=\"${pending ? 'incomplete-link' : tag}\"${attributes}>`;\n }\n return result + html.slice(from);\n}\n\n/** Format session output with HTML options. Keeps completed HTML and at most one live highlighter. */\nexport function createHtmlRenderer(options: HtmlOptions = {}) {\n let parser = createHtmlSession();\n // Formatted completed HTML and the Wasm HTML it was formatted from.\n let stable = '';\n let stableRaw = '';\n let nextCode = 0;\n let live:\n | { session: CodeHighlighterSession; index: number; language: string }\n | undefined;\n let liveUses = 0;\n let previousUpdate: HtmlUpdate | undefined;\n let result: RenderedHtmlUpdate | undefined;\n let revision = 0;\n let pendingRaw = '';\n let pendingInput: string | undefined;\n let pendingActive = false;\n let pendingCode = -1;\n let pendingHtml = '';\n let pendingFence: CodeHtmlUpdate | undefined;\n // Completed fence HTML by language and code. Resets keep only the fences they reuse.\n let codeCache = new Map<string, string>();\n let oldCodeCache = new Map<string, string>();\n // The open fence, the formatted HTML around it, and its previous escaped and decoded code.\n let fenceKey = 0;\n let fence:\n | {\n key: number;\n prefix: string;\n suffix: string;\n attributes: string;\n firstCode: number;\n index: number;\n before: string;\n after: string;\n highlighted: boolean;\n escaped: string | undefined;\n start: number;\n line: number;\n code: string;\n codeStart: number;\n }\n | undefined;\n const dispose = (): void => {\n const session = live?.session;\n live = undefined;\n session?.dispose();\n };\n\n /** Drop all state after an option change or a hook error, so the next render starts clean. */\n const resetState = (): void => {\n dispose();\n parser = createHtmlSession();\n stable = '';\n stableRaw = '';\n nextCode = 0;\n previousUpdate = undefined;\n result = undefined;\n pendingInput = undefined;\n pendingHtml = '';\n pendingActive = false;\n pendingCode = -1;\n pendingFence = undefined;\n codeCache = new Map();\n oldCodeCache = new Map();\n fence = undefined;\n };\n\n const format = (\n input: string,\n firstCode: number,\n active: boolean\n ): [string, number] => {\n const decorated = decorate(input, options);\n let html = '';\n let index = firstCode;\n let cursor = 0;\n // A fence is `<pre ...><code ...>`, escaped code, then `</code></pre>`.\n for (\n let at = decorated.indexOf('<pre '), scan = 0;\n at !== -1;\n at = decorated.indexOf('<pre ', scan)\n ) {\n const pre = decorated.indexOf('>', at);\n scan = pre;\n if (!decorated.startsWith('<code ', pre + 1)) continue;\n const open = decorated.indexOf('>', pre + 1);\n const end = decorated.indexOf('</code></pre>', open);\n if (end < 0) break;\n const codeAttributes = decorated.slice(pre + 6, open);\n const content = decorated.slice(open + 1, end);\n const code = decodeHtml(content);\n const language = codeLanguage(codeAttributes);\n const isIncomplete =\n active && decorated.slice(at, pre).includes('data-markdown-incomplete');\n const number = index++;\n html += decorated.slice(cursor, at);\n cursor = scan = end + 13;\n const custom = options.plugins?.renderers?.find((renderer) =>\n typeof renderer.language === 'string'\n ? renderer.language === language\n : renderer.language.includes(language)\n );\n if (custom !== undefined) {\n html += hookHtml(custom.render({ code, language, isIncomplete }));\n continue;\n }\n const plugin = options.plugins?.code;\n // Only a different open fence replaces the live highlighter.\n if (isIncomplete) {\n if (\n live !== undefined &&\n (live.index !== number || live.language !== language)\n )\n dispose();\n if (live === undefined) {\n const session = plugin?.createSession?.();\n if (session !== undefined)\n live = { session, index: number, language };\n }\n }\n let highlighted: string | null | undefined;\n if (live !== undefined && live.index === number) {\n liveUses++;\n highlighted = live.session.highlight({ code, language, isIncomplete });\n } else if (plugin !== undefined) {\n const key = language + '\\0' + code;\n highlighted = isIncomplete\n ? undefined\n : (codeCache.get(key) ?? oldCodeCache.get(key));\n if (highlighted === undefined) {\n highlighted = plugin.highlight({ code, language, isIncomplete });\n if (!isIncomplete && typeof highlighted === 'string')\n codeCache.set(key, highlighted);\n } else codeCache.set(key, highlighted);\n }\n if (highlighted != null && typeof highlighted !== 'string')\n throw new TypeError('Code highlighters must return HTML strings');\n if (!isIncomplete && live?.index === number) dispose();\n let count = 1;\n for (\n let line = code.indexOf('\\n');\n line !== -1 && line < code.length - 1;\n line = code.indexOf('\\n', line + 1)\n )\n count++;\n const [before, after] = codeWrapper(\n codeAttributes,\n language,\n isIncomplete,\n options.lineNumbers === false ? undefined : count,\n options\n );\n html += before + groupLines(highlighted ?? content) + after;\n }\n html += decorated.slice(cursor);\n for (const [tag, render] of Object.entries(options.components ?? {})) {\n // An element hook has a tag name: lowercase letters, then digits too.\n let named = tag !== '';\n for (let at = 0; named && at < tag.length; at++) {\n const code = tag.charCodeAt(at);\n named =\n (code >= 97 && code <= 122) || (at > 0 && code >= 48 && code <= 57);\n }\n if (render === undefined || (!named && tag !== 'inlineCode')) continue;\n const inline = tag === 'inlineCode';\n if (\n !inline &&\n (tag !== 'code' || options.components?.inlineCode === undefined)\n ) {\n html = mapElements(html, tag, render);\n continue;\n }\n // `inlineCode` sees the code outside `<pre>`, so `code` then sees only\n // the code inside it. The leftmost `<pre` or `<code` starts an element\n // when its first closing tag follows.\n let result = '';\n let from = 0;\n let pre = html.indexOf('<pre');\n let code = inline ? html.indexOf('<code') : -1;\n while (inline ? code !== -1 : pre !== -1) {\n const isPre = pre !== -1 && (!inline || pre < code);\n const at = isPre ? pre : code;\n const name = at + (isPre ? 4 : 5);\n const open = isNameCode(html.charCodeAt(name))\n ? -1\n : html.indexOf('>', name);\n const close =\n open < 0 ? -1 : html.indexOf(isPre ? '</pre>' : '</code>', open + 1);\n const next = close < 0 ? name : close + (isPre ? 6 : 7);\n if (close >= 0 && isPre !== inline) {\n const element = html.slice(at, next);\n result +=\n html.slice(from, at) +\n (inline\n ? hookHtml(render(element))\n : mapElements(element, 'code', render));\n from = next;\n }\n if (pre !== -1 && pre < next) pre = html.indexOf('<pre', next);\n if (inline && code < next) code = html.indexOf('<code', next);\n }\n html = result + html.slice(from);\n }\n return [html, index];\n };\n\n /**\n * Format the last open fence as changed lines when no hook or filter needs\n * its full element. The HTML around the fence is reused while it is unchanged,\n * so this also works for a fence in a list or quote.\n */\n const formatFence = (\n input: string,\n firstCode: number,\n active: boolean\n ): CodeHtmlUpdate | undefined => {\n if (\n !active ||\n options.allowedElements !== undefined ||\n options.disallowedElements !== undefined ||\n (options.components !== undefined &&\n Object.values(options.components).some((hook) => hook !== undefined))\n )\n return;\n // Wasm marks only the fence that is still open at the end of the source.\n const start = input.indexOf('<pre data-markdown-incomplete');\n if (start < 0) return;\n const open = input.indexOf('>', start) + 1;\n const body = input.indexOf('>', open) + 1;\n // Escaped code holds no `<`, so the next one starts `</code></pre>`.\n const end = input.indexOf('<', body);\n if (!input.startsWith('<code', open) || end < 0) return;\n const attributes = input.slice(open + 5, body - 1);\n const language = codeLanguage(attributes);\n if (\n options.plugins?.renderers?.some((renderer) =>\n typeof renderer.language === 'string'\n ? renderer.language === language\n : renderer.language.includes(language)\n ) === true\n )\n return;\n const plugin = options.plugins?.code;\n const prefix = input.slice(0, start);\n const suffix = input.slice(end + 13);\n if (\n fence === undefined ||\n prefix !== fence.prefix ||\n suffix !== fence.suffix ||\n attributes !== fence.attributes ||\n firstCode !== fence.firstCode\n ) {\n const [before, index] = format(prefix, firstCode, active);\n fence = {\n key: ++fenceKey,\n prefix,\n suffix,\n attributes,\n firstCode,\n index,\n before,\n after: format(suffix, index + 1, active)[0],\n highlighted: false,\n escaped: undefined,\n start: 0,\n line: 0,\n code: '',\n codeStart: 0,\n };\n }\n if (\n live !== undefined &&\n (live.index !== fence.index || live.language !== language)\n )\n dispose();\n if (live === undefined && plugin !== undefined) {\n const session = plugin.createSession?.();\n if (session !== undefined)\n live = { session, index: fence.index, language };\n }\n // Plugins without line updates re-highlight the whole fence through format().\n if (plugin !== undefined && live?.session.highlightLines === undefined)\n return;\n // Appended source changes the escaped code only from its previous last\n // line, so decode and count lines from there. V8 compares slices with\n // memcmp, but its startsWith reads each character.\n const escaped = input.slice(body, end);\n const length = escaped.endsWith('\\n') ? escaped.length - 1 : escaped.length;\n const lastStart =\n length === 0 ? 0 : escaped.lastIndexOf('\\n', length - 1) + 1;\n const unchanged = escaped === fence.escaped;\n const from =\n fence.escaped !== undefined &&\n lastStart >= fence.start &&\n escaped.slice(0, fence.start) === fence.escaped.slice(0, fence.start)\n ? fence.start\n : 0;\n const firstLine = from === 0 ? 0 : fence.line;\n let lineCount = firstLine + 1;\n for (\n let at = escaped.indexOf('\\n', from);\n at !== -1;\n at = escaped.indexOf('\\n', at + 1)\n )\n lineCount++;\n let code = escaped;\n let codeStart = lastStart;\n if (plugin !== undefined) {\n const head =\n (from === 0 ? '' : fence.code.slice(0, fence.codeStart)) +\n decodeHtml(escaped.slice(from, lastStart));\n code = head + decodeHtml(escaped.slice(lastStart));\n codeStart = head.length;\n }\n if (live !== undefined) liveUses++;\n let lines =\n live?.session.highlightLines?.({ code, language, isIncomplete: true }) ??\n null;\n // Highlighted and plain lines are different markup for the same code.\n if (fence.highlighted !== (lines !== null)) {\n fence.highlighted = lines !== null;\n fence.key = ++fenceKey;\n }\n lines ??= {\n firstLine: unchanged ? lineCount : firstLine,\n lineCount,\n html: unchanged ? '' : escaped.slice(from),\n lastLineOffset: unchanged ? 0 : lastStart - from,\n fullHtml: escaped,\n };\n fence.escaped = escaped;\n fence.start = lastStart;\n fence.line = Math.max(0, lineCount - (escaped.endsWith('\\n') ? 2 : 1));\n fence.code = code;\n fence.codeStart = codeStart;\n const update = lines;\n const count = Math.max(1, update.lineCount - (code.endsWith('\\n') ? 1 : 0));\n const numbers = options.lineNumbers === false ? undefined : count;\n const context = fence;\n const renderOptions = options;\n let fullPending: string | undefined;\n return {\n key: context.key,\n firstLine: update.firstLine,\n lineCount: update.lineCount,\n lastLine: Math.max(0, update.lineCount - (code.endsWith('\\n') ? 2 : 1)),\n lastLineOffset: update.lastLineOffset,\n html: update.html,\n numbers,\n get pending() {\n if (fullPending !== undefined) return fullPending;\n const [before, after] = codeWrapper(\n decorate(`<code${attributes}>`, renderOptions).slice(5, -1),\n language,\n true,\n numbers,\n renderOptions\n );\n return (fullPending =\n context.before +\n before +\n groupLines(update.fullHtml) +\n after +\n context.after);\n },\n };\n };\n\n return {\n /** Change options. A reset drops caches, so completed output is formatted again. */\n configure(next: HtmlOptions, reset = true): void {\n if (reset) resetState();\n options = next;\n },\n render(\n source: string,\n incomplete: boolean,\n active = false\n ): RenderedHtmlUpdate {\n try {\n const update = parser.render(source, { incomplete });\n if (\n update === previousUpdate &&\n active === pendingActive &&\n result !== undefined\n )\n return result;\n const changed = update !== previousUpdate;\n let reset = false;\n let addition = '';\n if (changed && previousUpdate?.stable === stableRaw && !update.reset) {\n if (update.addition !== '') {\n [addition, nextCode] = format(update.addition, nextCode, active);\n stable += addition;\n }\n stableRaw = update.stable;\n pendingRaw = update.pending;\n } else if (changed) {\n const raw = update.stable + update.pending;\n if (\n previousUpdate === undefined ||\n raw.slice(0, stableRaw.length) !== stableRaw\n ) {\n reset = true;\n dispose();\n pendingInput = undefined;\n fence = undefined;\n stable = '';\n stableRaw = '';\n nextCode = 0;\n oldCodeCache = codeCache;\n codeCache = new Map();\n }\n // Link definitions reset every update. Keep whole top-level blocks\n // that did not change since the previous update as completed HTML,\n // so only the changing tail is formatted and patched.\n let cut = Math.max(update.stable.length, stableRaw.length);\n if (update.reset && cut === stableRaw.length) {\n const previousRaw =\n previousUpdate === undefined\n ? ''\n : previousUpdate.stable + previousUpdate.pending;\n let same = cut;\n // An open fence formats differently once the stream is inactive.\n const open = raw.indexOf('<pre data-markdown-incomplete', cut);\n const limit = Math.min(\n open < 0 ? raw.length : open,\n previousRaw.length\n );\n while (\n same < limit &&\n raw.charCodeAt(same) === previousRaw.charCodeAt(same)\n )\n same++;\n let depth = 0;\n // Identical HTML does not show that the last block has closed.\n for (\n let at = same < raw.length ? raw.indexOf('<', cut) : -1, end = 0;\n at !== -1;\n at = raw.indexOf('<', end)\n ) {\n end = raw.indexOf('>', at) + 1;\n if (end === 0 || end >= same) break;\n if (raw.charCodeAt(at + 1) === 47) depth--;\n else if (!isVoidAt(raw, at, end)) depth++;\n if (depth === 0 && raw.charCodeAt(end) === 10) cut = end + 1;\n }\n }\n if (cut > stableRaw.length) {\n [addition, nextCode] = format(\n raw.slice(stableRaw.length, cut),\n nextCode,\n active\n );\n stable += addition;\n }\n stableRaw =\n cut === update.stable.length ? update.stable : raw.slice(0, cut);\n pendingRaw = raw.slice(cut);\n }\n previousUpdate = update;\n if (\n pendingInput !== pendingRaw ||\n pendingActive !== active ||\n pendingCode !== nextCode\n ) {\n const uses = liveUses;\n pendingFence = formatFence(pendingRaw, nextCode, active);\n if (pendingFence === undefined)\n [pendingHtml] = format(pendingRaw, nextCode, active);\n // Release the live highlighter once its fence is no longer pending.\n if (liveUses === uses) dispose();\n pendingInput = pendingRaw;\n pendingActive = active;\n pendingCode = nextCode;\n }\n const completedHtml = stable;\n const code = pendingFence;\n const pending = pendingHtml;\n let fullPending: string | undefined;\n let fullHtml: string | undefined;\n result = {\n get html() {\n return (fullHtml ??= completedHtml + (code?.pending ?? pending));\n },\n stable: completedHtml,\n addition,\n get pending() {\n return (fullPending ??= code?.pending ?? pending);\n },\n code,\n reset,\n revision: ++revision,\n };\n return result;\n } catch (error) {\n resetState();\n throw error;\n }\n },\n dispose,\n };\n}\n","import { controlFlags, createHtmlRenderer } from './render';\nimport type { AnimateOptions, HtmlOptions, PluginConfig } from './types';\n\nconst isFade = (node: Node): node is HTMLElement =>\n node.nodeType === 1 &&\n (node as Element).getAttribute('data-markdown') === 'token';\nconst isText = (node: Node): boolean => node.nodeType === 3 || isFade(node);\nconst passiveText =\n '[data-markdown=\"token\"], [data-markdown=\"code-header\"], [data-markdown=\"line-numbers\"], [data-markdown=\"caret\"]';\n\n/** Wrap new text in fade spans, and unwrap each span when its animation ends. */\nfunction createFades(root: HTMLElement) {\n const pending = new Map<HTMLElement, number>();\n const document = root.ownerDocument;\n const query = document.defaultView?.matchMedia?.(\n '(prefers-reduced-motion: reduce)'\n );\n let timer: ReturnType<typeof setTimeout> | undefined;\n let timerDeadline = Infinity;\n let requested = false;\n let duration = 180;\n const enabled = (): boolean =>\n requested && duration > 0 && query?.matches !== true;\n const arm = (next: number): void => {\n if (Number.isFinite(next) && timer !== undefined && next >= timerDeadline)\n return;\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n timerDeadline = next;\n if (Number.isFinite(next))\n timer = setTimeout(() => flush(), Math.max(0, next - performance.now()));\n };\n const flush = (all = false): void => {\n timer = undefined;\n timerDeadline = Infinity;\n const now = performance.now();\n const parents = new Set<Node>();\n let next = Infinity;\n for (const [span, deadline] of pending) {\n if (!all && deadline > now) {\n next = Math.min(next, deadline);\n continue;\n }\n const parent = span.parentNode;\n pending.delete(span);\n if (parent !== null && root.contains(span)) {\n while (span.firstChild !== null)\n parent.insertBefore(span.firstChild, span);\n parent.removeChild(span);\n parents.add(parent);\n }\n }\n for (const parent of parents) parent.normalize();\n arm(next);\n };\n const stop = (): void => {\n arm(Infinity);\n if (pending.size > 0) flush(true);\n };\n const motionChanged = (): void => {\n if (query?.matches === true) stop();\n };\n const animate = (text: Text): void => {\n if (!enabled() || text.data.trim() === '' || text.parentElement === null)\n return;\n // An open fence line ends with LF. Keep the LF outside the span, so the\n // next chunk can extend the same line.\n if (\n text.data.endsWith('\\n') &&\n text.data.length > 1 &&\n text.parentElement.closest('pre code') !== null\n )\n text.splitText(text.data.length - 1);\n if (text.parentElement.closest(passiveText) !== null) return;\n const span = document.createElement('span');\n span.dataset.markdown = 'token';\n span.dataset.animated = 'true';\n span.style.animationDuration = `${duration}ms`;\n text.replaceWith(span);\n span.append(text);\n pending.set(span, performance.now() + duration);\n };\n return {\n connect(): void {\n query?.addEventListener('change', motionChanged);\n },\n disconnect(): void {\n stop();\n query?.removeEventListener('change', motionChanged);\n },\n // Runs once per DOM patch, not once per text run.\n finish(): void {\n let next = Infinity;\n for (const [span, deadline] of pending) {\n if (!root.contains(span)) pending.delete(span);\n else next = Math.min(next, deadline);\n }\n arm(next);\n },\n update(active: boolean, options: boolean | AnimateOptions): void {\n requested = active && options !== false;\n const value =\n typeof options === 'object' ? (options.duration ?? 180) : 180;\n duration = Number.isFinite(value) ? Math.max(0, value) : 180;\n if (!enabled()) stop();\n },\n tree(node: Node): void {\n if (!enabled()) return;\n if (node.nodeType === 3) animate(node as Text);\n else {\n const walker = document.createTreeWalker(node, 4);\n let text = walker.nextNode();\n while (text !== null) {\n const next = walker.nextNode();\n animate(text as Text);\n text = next;\n }\n }\n },\n append(parent: Node, value: string, before: Node | null): void {\n const previous =\n before === null ? parent.lastChild : before.previousSibling;\n const animateHere =\n enabled() &&\n value.trim() !== '' &&\n parent.nodeType === 1 &&\n (parent as Element).closest(passiveText) === null;\n if (!animateHere && previous?.nodeType === 3) {\n (previous as Text).appendData(value);\n return;\n }\n const text = document.createTextNode(value);\n parent.insertBefore(text, before);\n animate(text);\n },\n };\n}\n\ntype Fades = ReturnType<typeof createFades>;\n\n/** Patch `parent` to match `incoming`, and reuse nodes. A fade span counts as text. Returns the node at `committed`. */\nfunction patchChildren(\n parent: Node,\n incoming: Node,\n first: Node | null,\n fades: Fades,\n committed = -1,\n marker?: Comment,\n revising = false\n): Node | null {\n // A late definition can change the markup around visible text. Compare with\n // the old text on these full reparses, so existing words do not fade in again.\n const previousText = revising ? (parent.textContent ?? '') : undefined;\n let current = first;\n let target = incoming.firstChild;\n let index = 0;\n let firstPending: Node | null = null;\n while (target !== null) {\n const nextTarget = target.nextSibling;\n let actual: Node;\n if (target === marker) {\n // The marker is always inserted. It never replaces an existing node.\n actual = target;\n parent.insertBefore(target, current);\n } else if (target.nodeType === 3) {\n const value = target.nodeValue ?? '';\n let previous = '';\n let end = current;\n while (end !== null && isText(end)) {\n previous += end.textContent ?? '';\n end = end.nextSibling;\n }\n const append = value.startsWith(previous);\n const lineAppend =\n !append &&\n previous.endsWith('\\n') &&\n value.endsWith('\\n') &&\n value.slice(0, -1).startsWith(previous.slice(0, -1));\n if (current !== end && (append || lineAppend)) {\n actual = current!;\n const suffix = append\n ? value.slice(previous.length)\n : value.slice(previous.length - 1, -1);\n if (suffix !== '') {\n const lead = current!.previousSibling;\n let before = end;\n if (lineAppend) {\n // Insert before the run's final LF, split out of its text node or fade span.\n let last = end === null ? parent.lastChild : end.previousSibling;\n while (last !== null && last.nodeType === 1) last = last.lastChild;\n if (last !== null) {\n const text = last as Text;\n before =\n text.length === 1 ? text : text.splitText(text.length - 1);\n if (before.parentNode !== parent)\n parent.insertBefore(before, end);\n }\n }\n fades.append(parent, suffix, before);\n // A run that was only its final LF now starts at the new text.\n actual = (lead === null ? parent.firstChild : lead.nextSibling)!;\n }\n } else {\n while (current !== end) {\n const next = current!.nextSibling;\n parent.removeChild(current!);\n current = next;\n }\n actual = target;\n parent.insertBefore(target, end);\n // Text that replaces other text does not fade in.\n if (previous === '') {\n if (\n previousText === undefined ||\n !previousText.includes(target.textContent ?? '')\n )\n fades.tree(target);\n actual = target.parentNode === parent ? target : target.parentNode!;\n }\n }\n current = end;\n } else if (\n current?.nodeType === 1 &&\n target.nodeType === 1 &&\n (current as Element).tagName === (target as Element).tagName &&\n !isFade(current)\n ) {\n actual = current;\n const element = current as Element;\n const wanted = target as Element;\n // A native deep compare skips an unchanged element. The last element\n // holds the open end of the stream, so it is patched without the compare.\n if (wanted.nextElementSibling === null || !element.isEqualNode(wanted)) {\n for (let at = element.attributes.length - 1; at >= 0; at--) {\n const attribute = element.attributes[at];\n if (!wanted.hasAttribute(attribute.name))\n element.removeAttribute(attribute.name);\n }\n for (const attribute of wanted.attributes)\n if (element.getAttribute(attribute.name) !== attribute.value)\n element.setAttribute(attribute.name, attribute.value);\n patchChildren(\n element,\n wanted,\n element.firstChild,\n fades,\n -1,\n marker,\n revising\n );\n }\n current = element.nextSibling;\n } else {\n actual = target;\n const next = current?.nextSibling ?? null;\n parent.insertBefore(target, current);\n if (current !== null) parent.removeChild(current);\n if (\n previousText === undefined ||\n !previousText.includes(target.textContent ?? '')\n )\n fades.tree(target);\n current = next;\n }\n if (index === committed) firstPending = actual;\n index++;\n target = nextTarget;\n }\n while (current !== null) {\n const next = current.nextSibling;\n parent.removeChild(current);\n current = next;\n }\n return firstPending;\n}\n\n/** Insert a comment before the last code line, so later updates patch only that line. */\nfunction markLastCodeLine(code: Element, trailingNewline: boolean): Comment {\n let before = code.firstChild;\n for (let node = code.lastChild; node !== null; node = node.previousSibling) {\n if (node.nodeType !== 3) continue;\n const text = node as Text;\n let end = text.data.length;\n if (trailingNewline && text.data.endsWith('\\n')) {\n end--;\n trailingNewline = false;\n }\n if (end === 0) continue;\n const at = text.data.lastIndexOf('\\n', end - 1);\n if (at < 0) continue;\n before =\n at + 1 === text.data.length ? text.nextSibling : text.splitText(at + 1);\n break;\n }\n const marker = code.ownerDocument.createComment('markdown-code');\n code.insertBefore(marker, before);\n return marker;\n}\n\n/** Render Markdown into `root`, and patch its DOM nodes on each update. */\nexport function createDomRenderer(\n root: HTMLElement,\n options: HtmlOptions = {},\n formatter = createHtmlRenderer(options)\n) {\n const document = root.ownerDocument;\n const checkpoint = document.createComment('markdown');\n const template = document.createElement('template');\n const tail = document.createElement('template');\n const caret = document.createElement('span');\n const fades = createFades(root);\n let revision = 0;\n let initialized = false;\n let previousCaret: 'block' | 'circle' | undefined;\n let codeState:\n | {\n code: Element;\n marker: Comment;\n line: number;\n key: number;\n numbers: Element | null;\n numberCount: number;\n }\n | undefined;\n root.dataset.markdown = 'root';\n root.insertBefore(checkpoint, root.firstChild);\n caret.dataset.markdown = 'caret';\n caret.setAttribute('aria-hidden', 'true');\n\n const click = (event: Event): void => {\n const target = event.target as Element | null;\n const button = target?.closest<HTMLButtonElement>(\n 'button[data-code-action]'\n );\n if (button == null || button.disabled || !root.contains(button)) return;\n const block = button.closest('[data-markdown=\"code-block\"]');\n const code = block?.querySelector('pre code')?.textContent ?? '';\n if (button.dataset.codeAction === 'copy') {\n void document.defaultView?.navigator.clipboard\n ?.writeText(code)\n .then(() => {\n button.textContent = 'Copied';\n setTimeout(() => {\n button.textContent = 'Copy';\n }, 2000);\n })\n .catch(() => {\n button.textContent = 'Copy';\n });\n } else {\n const url = URL.createObjectURL(\n new Blob([code], { type: 'text/plain;charset=utf-8' })\n );\n const link = document.createElement('a');\n link.href = url;\n // Only letters and digits make a file extension.\n let language = block?.getAttribute('data-language') ?? '';\n for (let at = 0; at < language.length; at++) {\n const code = language.charCodeAt(at);\n if (((code | 32) < 97 || (code | 32) > 122) && (code < 48 || code > 57))\n language = '';\n }\n link.download = `code.${language === '' ? 'txt' : language}`;\n link.click();\n // Some browsers cancel a download whose URL is revoked during the click.\n setTimeout(() => URL.revokeObjectURL(url), 30_000);\n }\n };\n\n return {\n connect(): void {\n fades.connect();\n root.addEventListener('click', click);\n },\n disconnect(): void {\n fades.disconnect();\n formatter.dispose();\n root.removeEventListener('click', click);\n },\n /**\n * Reformat completed output only when an option value changes, so inline\n * option objects stay cheap. New hook and `urlTransform` functions apply to\n * later output. A changed set of hook names reformats everything. Plugins\n * compare by their parts, because a wrapper object is often written inline.\n */\n configure(next: HtmlOptions): void {\n if (next === options) return;\n const hooks = (value: HtmlOptions['components']): string =>\n Object.keys(value ?? {})\n .filter((tag) => value?.[tag] !== undefined)\n .join(' ');\n const samePlugins = (a?: PluginConfig, b?: PluginConfig): boolean => {\n const left = a?.renderers ?? [];\n const right = b?.renderers ?? [];\n return (\n a?.code === b?.code &&\n left.length === right.length &&\n left.every(\n (renderer, at) =>\n renderer.render === right[at].render &&\n String(renderer.language) === String(right[at].language)\n )\n );\n };\n let reset = false;\n const keys = new Set([...Object.keys(options), ...Object.keys(next)]);\n for (const key of keys as Set<keyof HtmlOptions>) {\n const previous = options[key];\n const value = next[key];\n reset ||= !(\n previous === value ||\n (key === 'controls'\n ? controlFlags(previous as HtmlOptions['controls']) ===\n controlFlags(value as HtmlOptions['controls'])\n : key === 'components'\n ? hooks(previous as HtmlOptions['components']) ===\n hooks(value as HtmlOptions['components'])\n : key === 'urlTransform'\n ? (previous === undefined) === (value === undefined)\n : key === 'plugins'\n ? samePlugins(\n previous as PluginConfig | undefined,\n value as PluginConfig | undefined\n )\n : Array.isArray(previous) &&\n Array.isArray(value) &&\n previous.length === value.length &&\n previous.every((tag, at) => tag === value[at]))\n );\n }\n formatter.configure(next, reset);\n options = next;\n },\n update(\n source: string,\n incomplete: boolean,\n active = false,\n animated: boolean | AnimateOptions = false,\n shape?: 'block' | 'circle'\n ): void {\n root.toggleAttribute('data-streaming', active);\n const update = formatter.render(source, incomplete, active);\n const changed = update.revision !== revision;\n const reset =\n !initialized ||\n (changed && (update.reset || update.revision !== revision + 1));\n fades.update(active, animated);\n const nextCaret = active ? shape : undefined;\n if (!changed && nextCaret === previousCaret) return;\n // Remove the caret first, so patches never see it.\n caret.remove();\n const codeUpdate = update.code;\n if (\n changed &&\n !reset &&\n codeUpdate !== undefined &&\n codeState !== undefined &&\n update.addition === '' &&\n codeState.key === codeUpdate.key &&\n root.contains(codeState.marker) &&\n (codeUpdate.firstLine === codeUpdate.lineCount ||\n (codeUpdate.firstLine === codeState.line &&\n codeUpdate.firstLine <= codeUpdate.lastLine)) &&\n (codeUpdate.numbers === undefined) === (codeState.numbers === null) &&\n (codeUpdate.numbers ?? 0) >= codeState.numberCount\n ) {\n if (codeUpdate.firstLine < codeUpdate.lineCount) {\n // Balanced per-line HTML lets the browser parse just the changed\n // lines. Lines fill the last 64-line group, then open new groups.\n const { html, lastLineOffset } = codeUpdate;\n const marker = document.createComment('markdown-code');\n let group = codeState.marker.parentNode as Element | null;\n let first = codeState.marker.nextSibling;\n codeState.marker.remove();\n for (let start = 0, line = codeUpdate.firstLine; ; ) {\n let end = start;\n let left = 64 - (line % 64);\n for (; left > 0; left--) {\n const at = html.indexOf('\\n', end);\n if (at < 0) break;\n end = at + 1;\n }\n if (left > 0) end = html.length;\n if (group === null) {\n if (start === end) break;\n group = document.createElement('span');\n group.setAttribute('data-markdown', 'code-lines');\n codeState.code.append(group);\n first = null;\n }\n const at =\n lastLineOffset >= start &&\n (lastLineOffset < end || end === html.length)\n ? lastLineOffset\n : -1;\n template.innerHTML = html.slice(start, at < 0 ? end : at);\n const fragment = template.content;\n if (at >= 0) {\n fragment.append(marker);\n tail.innerHTML = html.slice(at, end);\n fragment.append(tail.content);\n }\n patchChildren(\n group,\n fragment,\n first,\n fades,\n -1,\n at < 0 ? undefined : marker\n );\n if (end === html.length) break;\n line += 64 - (line % 64);\n start = end;\n group = null;\n }\n codeState.marker = marker;\n codeState.line = codeUpdate.lastLine;\n }\n const count = codeUpdate.numbers ?? 0;\n if (codeState.numbers !== null && count > codeState.numberCount) {\n let group = codeState.numbers.lastElementChild!;\n const append = (text: string): void => {\n const last = group.lastChild;\n if (last?.nodeType === 3) (last as Text).appendData(text);\n else group.append(text);\n };\n let text = '';\n for (let line = codeState.numberCount + 1; line <= count; line++) {\n if (line % 64 !== 1) {\n text += '\\n' + line;\n continue;\n }\n append(text + '\\n');\n group = document.createElement('span');\n group.setAttribute('data-markdown', 'code-lines');\n codeState.numbers.append(group);\n text = String(line);\n }\n append(text);\n codeState.numberCount = count;\n }\n } else if (changed) {\n // The first render and skipped revisions need the full prefix. Other\n // updates use only the addition.\n codeState?.marker.remove();\n codeState = undefined;\n if (reset) {\n if (checkpoint.parentNode !== null) root.removeChild(checkpoint);\n root.insertBefore(checkpoint, root.firstChild);\n }\n template.innerHTML = reset ? update.stable : update.addition;\n const fragment = template.content;\n const count = fragment.childNodes.length;\n tail.innerHTML = update.pending;\n // Only the open fence block is incomplete; footnotes after it may hold other fences.\n const incomingCode =\n codeUpdate === undefined\n ? null\n : tail.content.querySelector('[data-incomplete] > pre > code');\n // Add the marker before insertion, because fades wrap multi-line text.\n const codeMarker =\n incomingCode === null || codeUpdate === undefined\n ? undefined\n : markLastCodeLine(\n incomingCode.lastElementChild ?? incomingCode,\n codeUpdate.lastLine < codeUpdate.lineCount - 1\n );\n fragment.append(tail.content);\n const firstPending = patchChildren(\n root,\n fragment,\n checkpoint.nextSibling,\n fades,\n count,\n codeMarker,\n initialized && reset\n );\n if (checkpoint.nextSibling !== firstPending)\n root.insertBefore(checkpoint, firstPending);\n if (codeUpdate !== undefined && codeMarker?.parentNode != null) {\n const code = codeMarker.parentNode.parentNode as Element;\n const numbers = code.previousElementSibling;\n codeState = {\n code,\n marker: codeMarker,\n line: codeUpdate.lastLine,\n key: codeUpdate.key,\n numbers:\n numbers?.getAttribute('data-markdown') === 'line-numbers'\n ? numbers\n : null,\n numberCount: codeUpdate.numbers ?? 0,\n };\n }\n if (!initialized) {\n initialized = true;\n fades.tree(root);\n }\n }\n revision = update.revision;\n previousCaret = nextCaret;\n if (nextCaret !== undefined) {\n caret.dataset.shape = nextCaret;\n // Place the caret after the last text, inside the deepest last block,\n // and before the final LF of a code fence. Its glyph is CSS content,\n // so block and code text stay unchanged for copy and hooks.\n let parent: Node = root;\n let before: Node | null = null;\n for (let node = root.lastChild; node !== null; ) {\n if (\n node.nodeType === 8 ||\n (node.nodeType === 3 && (node as Text).data.trim() === '') ||\n (node.nodeType === 1 &&\n (node as Element).hasAttribute('data-footnotes'))\n ) {\n node = node.previousSibling;\n continue;\n }\n let block = false;\n if (node.nodeType === 1)\n switch (node.nodeName) {\n case 'BLOCKQUOTE':\n case 'DIV':\n case 'H1':\n case 'H2':\n case 'H3':\n case 'H4':\n case 'H5':\n case 'H6':\n case 'LI':\n case 'OL':\n case 'P':\n case 'PRE':\n case 'SECTION':\n case 'TABLE':\n case 'TBODY':\n case 'TD':\n case 'TH':\n case 'THEAD':\n case 'TR':\n case 'UL':\n block = true;\n }\n if (!block) {\n before = node.nextSibling;\n break;\n }\n parent = node;\n if (node.nodeName === 'PRE') {\n const code = (node as Element).lastElementChild;\n parent = code?.lastElementChild ?? code ?? node;\n let last = parent.lastChild;\n while (last?.nodeType === 1 && last.lastChild !== null)\n last = last.lastChild;\n if (last?.nodeType === 3 && (last as Text).data.endsWith('\\n')) {\n const text = last as Text;\n before = text.length > 1 ? text.splitText(text.length - 1) : text;\n parent = before.parentNode!;\n }\n break;\n }\n node = node.lastChild;\n }\n parent.insertBefore(caret, before);\n }\n fades.finish();\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { r as CodeHighlighterPlugin } from "./types-JH3jubk_.js";
2
+ import { CodeToHtmlBaseOptions, ThemeOptions } from "@pierre/highlights";
3
+ //#region react/highlights.d.ts
4
+ /** Highlight code with `@pierre/highlights`. An open fence keeps a live tokenizer. */
5
+ declare function createHighlightsPlugin(options: Omit<CodeToHtmlBaseOptions, 'lang'> & ThemeOptions): CodeHighlighterPlugin;
6
+ //#endregion
7
+ export { createHighlightsPlugin };
8
+ //# sourceMappingURL=highlights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlights.d.ts","names":[],"sources":["../react/highlights.ts"],"mappings":";;;;iBAgBgB,uBACd,SAAS,KAAK,iCAAiC,eAC9C"}
@@ -0,0 +1,151 @@
1
+ import { LiveTokenizer, codeToHtml, isSupportedLanguage } from "@pierre/highlights";
2
+ //#region react/highlights.ts
3
+ const decoder = new TextDecoder();
4
+ /** Highlight code with `@pierre/highlights`. An open fence keeps a live tokenizer. */
5
+ function createHighlightsPlugin(options) {
6
+ const highlight = ({ code, language }) => {
7
+ if (!isSupportedLanguage(language)) return null;
8
+ const html = decoder.decode(codeToHtml(code, {
9
+ ...options,
10
+ lang: language
11
+ }));
12
+ const start = html.indexOf("<code>") + 6;
13
+ return html.slice(start, html.lastIndexOf("</code>"));
14
+ };
15
+ return {
16
+ highlight,
17
+ createSession() {
18
+ let tokenizer;
19
+ let previous = "";
20
+ let language = "";
21
+ let lines = [];
22
+ let prefixHtml = "";
23
+ let prefixLineCount = 0;
24
+ let result;
25
+ const dispose = () => {
26
+ tokenizer?.dispose();
27
+ tokenizer = void 0;
28
+ previous = "";
29
+ lines = [];
30
+ prefixHtml = "";
31
+ prefixLineCount = 0;
32
+ result = void 0;
33
+ };
34
+ /** Keep the HTML of finished lines, and return only the changed lines. */
35
+ const highlightLines = ({ code, language: nextLanguage, isIncomplete }) => {
36
+ if (!isSupportedLanguage(nextLanguage)) {
37
+ dispose();
38
+ return null;
39
+ }
40
+ if (code.includes("\r")) code = code.replace(/\r\n?/g, "\n");
41
+ if (language !== nextLanguage) {
42
+ dispose();
43
+ language = nextLanguage;
44
+ }
45
+ let first = 0;
46
+ const previousLineCount = lines.length;
47
+ const previousContentLine = Math.max(0, previousLineCount - (previous.endsWith("\n") ? 2 : 1));
48
+ if (code === previous && result !== void 0) {
49
+ const unchanged = result;
50
+ return {
51
+ firstLine: lines.length,
52
+ lineCount: lines.length,
53
+ html: "",
54
+ lastLineOffset: 0,
55
+ get fullHtml() {
56
+ return unchanged.fullHtml;
57
+ }
58
+ };
59
+ }
60
+ let ansiLines;
61
+ if (nextLanguage.toLowerCase() === "ansi") {
62
+ ansiLines = highlight({
63
+ code,
64
+ language: nextLanguage,
65
+ isIncomplete
66
+ }).split("\n");
67
+ const head = previous.endsWith("\n") ? previous.slice(0, -1) : previous;
68
+ if (code.slice(0, head.length) === head) first = previousContentLine;
69
+ } else if (tokenizer === void 0) tokenizer = new LiveTokenizer({
70
+ ...options,
71
+ lang: nextLanguage,
72
+ code
73
+ });
74
+ else if (code.slice(0, previous.length) === previous) {
75
+ const line = tokenizer.lineCount - 1;
76
+ const end = {
77
+ line,
78
+ character: tokenizer.getLineLength(line)
79
+ };
80
+ first = tokenizer.applyEdits([{
81
+ range: {
82
+ start: end,
83
+ end
84
+ },
85
+ newText: code.slice(previous.length)
86
+ }]).lineChanges[0]?.newStartLine ?? tokenizer.lineCount;
87
+ first = Math.min(first, previousContentLine);
88
+ } else if (previous.endsWith("\n") && code.slice(0, previous.length - 1) === previous.slice(0, -1)) {
89
+ const line = tokenizer.lineCount - 2;
90
+ const update = tokenizer.applyEdits([{
91
+ range: {
92
+ start: {
93
+ line,
94
+ character: tokenizer.getLineLength(line)
95
+ },
96
+ end: {
97
+ line: line + 1,
98
+ character: 0
99
+ }
100
+ },
101
+ newText: code.slice(previous.length - 1)
102
+ }]);
103
+ first = Math.min(update.lineChanges[0]?.newStartLine ?? tokenizer.lineCount, previousContentLine);
104
+ } else tokenizer.reset(code);
105
+ const lineCount = ansiLines?.length ?? tokenizer.lineCount;
106
+ const lastContentLine = Math.max(0, lineCount - (code.endsWith("\n") ? 2 : 1));
107
+ first = Math.min(first, lastContentLine);
108
+ if (first < prefixLineCount) {
109
+ prefixHtml = "";
110
+ prefixLineCount = 0;
111
+ }
112
+ for (let line = prefixLineCount; line < first; line++) prefixHtml += lines[line] + "\n";
113
+ prefixLineCount = first;
114
+ lines.length = first;
115
+ let html = "";
116
+ let lastLineOffset = 0;
117
+ for (let line = first; line < lineCount; line++) {
118
+ const value = ansiLines?.[line] ?? tokenizer.getLineHtml(line);
119
+ lines.push(value);
120
+ if (line > first) html += "\n";
121
+ if (line === lastContentLine) lastLineOffset = html.length;
122
+ html += value;
123
+ }
124
+ previous = code;
125
+ const prefix = prefixHtml;
126
+ let fullHtml;
127
+ result = {
128
+ firstLine: first,
129
+ lineCount,
130
+ html,
131
+ lastLineOffset,
132
+ get fullHtml() {
133
+ return fullHtml ??= prefix + html;
134
+ }
135
+ };
136
+ return result;
137
+ };
138
+ return {
139
+ dispose,
140
+ highlightLines,
141
+ highlight(options) {
142
+ return highlightLines(options)?.fullHtml ?? null;
143
+ }
144
+ };
145
+ }
146
+ };
147
+ }
148
+ //#endregion
149
+ export { createHighlightsPlugin };
150
+
151
+ //# sourceMappingURL=highlights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlights.js","names":[],"sources":["../react/highlights.ts"],"sourcesContent":["import {\n codeToHtml,\n isSupportedLanguage,\n LiveTokenizer,\n} from '@pierre/highlights';\nimport type { CodeToHtmlBaseOptions, ThemeOptions } from '@pierre/highlights';\n\nimport type {\n CodeHighlighterPlugin,\n CodeHighlightUpdate,\n CodeOptions,\n} from '../html/types';\n\nconst decoder = new TextDecoder();\n\n/** Highlight code with `@pierre/highlights`. An open fence keeps a live tokenizer. */\nexport function createHighlightsPlugin(\n options: Omit<CodeToHtmlBaseOptions, 'lang'> & ThemeOptions\n): CodeHighlighterPlugin {\n const highlight = ({ code, language }: CodeOptions): string | null => {\n if (!isSupportedLanguage(language)) return null;\n const html = decoder.decode(\n codeToHtml(code, { ...options, lang: language })\n );\n const start = html.indexOf('<code>') + 6;\n return html.slice(start, html.lastIndexOf('</code>'));\n };\n return {\n highlight,\n createSession() {\n let tokenizer: LiveTokenizer | undefined;\n let previous = '';\n let language = '';\n let lines: string[] = [];\n let prefixHtml = '';\n let prefixLineCount = 0;\n let result: CodeHighlightUpdate | undefined;\n const dispose = (): void => {\n tokenizer?.dispose();\n tokenizer = undefined;\n previous = '';\n lines = [];\n prefixHtml = '';\n prefixLineCount = 0;\n result = undefined;\n };\n /** Keep the HTML of finished lines, and return only the changed lines. */\n const highlightLines = ({\n code,\n language: nextLanguage,\n isIncomplete,\n }: CodeOptions): CodeHighlightUpdate | null => {\n if (!isSupportedLanguage(nextLanguage)) {\n dispose();\n return null;\n }\n if (code.includes('\\r')) code = code.replace(/\\r\\n?/g, '\\n');\n if (language !== nextLanguage) {\n dispose();\n language = nextLanguage;\n }\n let first = 0;\n const previousLineCount = lines.length;\n const previousContentLine = Math.max(\n 0,\n previousLineCount - (previous.endsWith('\\n') ? 2 : 1)\n );\n if (code === previous && result !== undefined) {\n const unchanged = result;\n return {\n firstLine: lines.length,\n lineCount: lines.length,\n html: '',\n lastLineOffset: 0,\n get fullHtml() {\n return unchanged.fullHtml;\n },\n };\n }\n // The prefix checks below compare slices: V8 uses memcmp for them, but\n // its startsWith reads each character.\n let ansiLines: string[] | undefined;\n if (nextLanguage.toLowerCase() === 'ansi') {\n // Warning: LiveTokenizer keeps escape sequences as text, so ANSI\n // renders the whole fence. Appends can change only the last line.\n ansiLines = highlight({\n code,\n language: nextLanguage,\n isIncomplete,\n })!.split('\\n');\n const head = previous.endsWith('\\n')\n ? previous.slice(0, -1)\n : previous;\n if (code.slice(0, head.length) === head) first = previousContentLine;\n } else if (tokenizer === undefined) {\n tokenizer = new LiveTokenizer({\n ...options,\n lang: nextLanguage,\n code,\n });\n } else if (code.slice(0, previous.length) === previous) {\n const line = tokenizer.lineCount - 1;\n const end = { line, character: tokenizer.getLineLength(line) };\n const update = tokenizer.applyEdits([\n {\n range: { start: end, end },\n newText: code.slice(previous.length),\n },\n ]);\n first = update.lineChanges[0]?.newStartLine ?? tokenizer.lineCount;\n first = Math.min(first, previousContentLine);\n } else if (\n previous.endsWith('\\n') &&\n code.slice(0, previous.length - 1) === previous.slice(0, -1)\n ) {\n // Wasm supplies a final LF even while the source's last code line is still growing.\n const line = tokenizer.lineCount - 2;\n const update = tokenizer.applyEdits([\n {\n range: {\n start: { line, character: tokenizer.getLineLength(line) },\n end: { line: line + 1, character: 0 },\n },\n newText: code.slice(previous.length - 1),\n },\n ]);\n first = Math.min(\n update.lineChanges[0]?.newStartLine ?? tokenizer.lineCount,\n previousContentLine\n );\n } else tokenizer.reset(code);\n\n const lineCount = ansiLines?.length ?? tokenizer!.lineCount;\n const lastContentLine = Math.max(\n 0,\n lineCount - (code.endsWith('\\n') ? 2 : 1)\n );\n // Code that lost its final empty line ends before the changed lines.\n first = Math.min(first, lastContentLine);\n // Keep strings, not the line cache, so older lazy results stay valid.\n if (first < prefixLineCount) {\n prefixHtml = '';\n prefixLineCount = 0;\n }\n for (let line = prefixLineCount; line < first; line++)\n prefixHtml += lines[line] + '\\n';\n prefixLineCount = first;\n lines.length = first;\n let html = '';\n let lastLineOffset = 0;\n for (let line = first; line < lineCount; line++) {\n const value = ansiLines?.[line] ?? tokenizer!.getLineHtml(line);\n lines.push(value);\n if (line > first) html += '\\n';\n if (line === lastContentLine) lastLineOffset = html.length;\n html += value;\n }\n previous = code;\n const prefix = prefixHtml;\n let fullHtml: string | undefined;\n result = {\n firstLine: first,\n lineCount,\n html,\n lastLineOffset,\n get fullHtml() {\n return (fullHtml ??= prefix + html);\n },\n };\n return result;\n };\n return {\n dispose,\n highlightLines,\n highlight(options: CodeOptions) {\n return highlightLines(options)?.fullHtml ?? null;\n },\n };\n },\n };\n}\n"],"mappings":"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"}
package/dist/html.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import { a as CodeOptions, c as HtmlOptions, i as CodeHighlighterSession, l as PluginConfig, n as CodeHighlightUpdate, o as Components, r as CodeHighlighterPlugin, s as ControlsConfig, t as AnimateOptions } from "./types-JH3jubk_.js";
2
+ import { n as defaultUrlTransform, r as escapeHtml, t as createHtmlRenderer } from "./render-y9ZqP3xY.js";
3
+ //#region html/dom.d.ts
4
+ /** Render Markdown into `root`, and patch its DOM nodes on each update. */
5
+ declare function createDomRenderer(root: HTMLElement, options?: HtmlOptions, formatter?: {
6
+ configure(next: HtmlOptions, reset?: boolean): void;
7
+ render(source: string, incomplete: boolean, active?: boolean): any;
8
+ dispose: () => void;
9
+ }): {
10
+ connect(): void;
11
+ disconnect(): void;
12
+ /**
13
+ * Reformat completed output only when an option value changes, so inline
14
+ * option objects stay cheap. New hook and `urlTransform` functions apply to
15
+ * later output. A changed set of hook names reformats everything. Plugins
16
+ * compare by their parts, because a wrapper object is often written inline.
17
+ */
18
+ configure(next: HtmlOptions): void;
19
+ update(source: string, incomplete: boolean, active?: boolean, animated?: boolean | AnimateOptions, shape?: 'block' | 'circle'): void;
20
+ };
21
+ //#endregion
22
+ export { type AnimateOptions, type CodeHighlightUpdate, type CodeHighlighterPlugin, type CodeHighlighterSession, type CodeOptions, type Components, type ControlsConfig, type HtmlOptions, type PluginConfig, createDomRenderer, createHtmlRenderer, defaultUrlTransform, escapeHtml };
23
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","names":[],"sources":["../html/dom.ts"],"mappings":";;;;iBA4SgB,kBACd,MAAM,aACN,UAAS,aACT;;;;;EAmEE;EAIA;;;;;;;EAWA,UAAS,MAAO;EAgDhB,OAAM,gBACU,qBACK,kBAAA,qBAEC,gBAAc"}
package/dist/html.js ADDED
@@ -0,0 +1,2 @@
1
+ import { i as escapeHtml, n as createHtmlRenderer, r as defaultUrlTransform, t as createDomRenderer } from "./dom-BAclEeRf.js";
2
+ export { createDomRenderer, createHtmlRenderer, defaultUrlTransform, escapeHtml };
@@ -0,0 +1,3 @@
1
+ import { AnsiOptions, Frontmatter, HtmlSessionOptions, HtmlUpdate, RenderOptions } from "./types.js";
2
+ import { createHtmlSession, init, renderToAnsi, renderToHtml } from "./core.js";
3
+ export { type AnsiOptions, type Frontmatter, type HtmlSessionOptions, type HtmlUpdate, type RenderOptions, createHtmlSession, init, renderToAnsi, renderToHtml };
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import { createHtmlSession, init, renderToAnsi, renderToHtml } from "./core.js";
2
+ import wasmBytes from "./md.wasm.mjs";
3
+ //#region lib/index.ts
4
+ init(new WebAssembly.Module(wasmBytes));
5
+ //#endregion
6
+ export { createHtmlSession, init, renderToAnsi, renderToHtml };
7
+
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../lib/index.ts"],"sourcesContent":["import { init } from './core.ts';\nimport wasmBytes from './md.wasm.mjs';\n\ninit(new WebAssembly.Module(wasmBytes));\n\nexport * from './core.ts';\n"],"mappings":";;;AAGA,KAAK,IAAI,YAAY,OAAO,SAAS,CAAC"}
package/dist/md.wasm ADDED
Binary file