@portabletext/markdown 1.5.0 → 2.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.
- package/README.md +67 -9
- package/dist/index.d.ts +87 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1116 -280
- package/dist/index.js.map +1 -1
- package/package.json +10 -12
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/key-generator.ts","../src/from-portable-text/build-list-index-map.ts","../src/from-portable-text/render-node.ts","../src/from-portable-text/renderers/block-spacing.ts","../src/from-portable-text/renderers/hard-break.ts","../src/from-portable-text/renderers/list-item.ts","../src/escape.ts","../src/from-portable-text/renderers/marks.ts","../src/from-portable-text/renderers/style.ts","../src/from-portable-text/renderers/type.ts","../src/from-portable-text/portable-text-to-markdown.ts","../src/default-schema.ts","../src/to-portable-text/matchers.ts","../src/to-portable-text/markdown-to-portable-text.ts"],"sourcesContent":["export function defaultKeyGenerator() {\n return randomKey(12)\n}\n\nconst getByteHexTable = (() => {\n let table: any[]\n return () => {\n if (table) {\n return table\n }\n\n table = []\n for (let i = 0; i < 256; ++i) {\n table[i] = (i + 0x100).toString(16).slice(1)\n }\n return table\n }\n})()\n\n// WHATWG crypto RNG - https://w3c.github.io/webcrypto/Overview.html\nfunction whatwgRNG(length = 16) {\n const rnds8 = new Uint8Array(length)\n crypto.getRandomValues(rnds8)\n return rnds8\n}\n\nfunction randomKey(length?: number): string {\n const table = getByteHexTable()\n return whatwgRNG(length)\n .reduce((str, n) => str + table[n], '')\n .slice(0, length)\n}\n","import {\n compileSchema,\n defineSchema,\n isTextBlock,\n type PortableTextBlock,\n} from '@portabletext/schema'\nimport type {ArbitraryTypedObject, TypedObject} from '@portabletext/types'\nimport {defaultKeyGenerator} from '../key-generator'\n\nconst schema = compileSchema(defineSchema({}))\n\n/**\n * Builds a map of list item `_key`s to their index, and a map of list item\n * `_key`s to the depth they should be rendered at.\n *\n * The depth is not the same as the block's `level`. A list can start at a level\n * deeper than 1, and can skip levels, but Markdown has no way to express either:\n * indentation is relative to the list item above, and indenting a first item by\n * four spaces or more makes it a code block rather than a list. So each jump to a\n * deeper level counts as a single step of nesting, however many levels it spans.\n *\n * Mutates the blocks in place by adding a `_key` if necessary.\n */\nexport function buildListIndexMap<\n Block extends TypedObject = PortableTextBlock | ArbitraryTypedObject,\n>(\n blocks: Array<Block>,\n): {listIndexMap: Map<string, number>; listDepthMap: Map<string, number>} {\n const levelIndexMaps = new Map<string, Map<number, number>>()\n const listIndexMap = new Map<string, number>()\n const listDepthMap = new Map<string, number>()\n\n // Levels of the list items this one is nested inside, shallowest first\n let levelStack: Array<number> = []\n\n function depthOf(level: number): number {\n let deepest = levelStack.at(-1)\n\n while (deepest !== undefined && deepest > level) {\n levelStack.pop()\n deepest = levelStack.at(-1)\n }\n\n if (deepest !== level) {\n levelStack.push(level)\n }\n\n return levelStack.length - 1\n }\n\n let previousListItem:\n | {\n listItem: string\n depth: number\n }\n | undefined\n\n for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) {\n const block = blocks.at(blockIndex)\n\n if (block === undefined) {\n continue\n }\n\n if (!block._key) {\n block._key = defaultKeyGenerator()\n }\n\n // Clear the state if we encounter a non-text block\n if (!isTextBlock({schema}, block)) {\n levelIndexMaps.clear()\n previousListItem = undefined\n levelStack = []\n\n continue\n }\n\n // Clear the state if we encounter a non-list text block\n if (block.listItem === undefined || block.level === undefined) {\n levelIndexMaps.clear()\n previousListItem = undefined\n levelStack = []\n\n continue\n }\n\n const depth = depthOf(block.level)\n listDepthMap.set(block._key, depth)\n\n // If we encounter a new list item, we set the initial index to 1 for the\n // list type on that level.\n if (!previousListItem) {\n const listIndex = 1\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n levelIndexMap.set(depth, listIndex)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, listIndex)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n\n continue\n }\n\n // If the previous list item is of the same type but on a lower level, we\n // need to reset the level index map for that type.\n if (\n previousListItem.listItem === block.listItem &&\n previousListItem.depth < depth\n ) {\n const listIndex = 1\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n levelIndexMap.set(depth, listIndex)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, listIndex)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n\n continue\n }\n\n // Reset other list types at current depth and deeper\n levelIndexMaps.forEach((levelIndexMap, listItem) => {\n if (listItem === block.listItem) {\n return\n }\n\n // Reset all levels that are >= current level\n const depthsToDelete: number[] = []\n\n levelIndexMap.forEach((_, existingDepth) => {\n if (existingDepth >= depth) {\n depthsToDelete.push(existingDepth)\n }\n })\n\n depthsToDelete.forEach((depthToDelete) => {\n levelIndexMap.delete(depthToDelete)\n })\n })\n\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n const levelCounter = levelIndexMap.get(depth) ?? 0\n levelIndexMap.set(depth, levelCounter + 1)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, levelCounter + 1)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n }\n\n return {listIndexMap, listDepthMap}\n}\n","import {\n buildMarksTree,\n isPortableTextBlock,\n isPortableTextListItemBlock,\n isPortableTextToolkitSpan,\n isPortableTextToolkitTextNode,\n spanToPlainText,\n type ToolkitNestedPortableTextSpan,\n type ToolkitTextNode,\n} from '@portabletext/toolkit'\nimport type {\n PortableTextBlock,\n PortableTextListItemBlock,\n PortableTextMarkDefinition,\n PortableTextSpan,\n TypedObject,\n} from '@portabletext/types'\nimport {defaultKeyGenerator} from '../key-generator'\nimport type {PortableTextRenderers, RenderNode, Serializable} from './types'\n\ninterface SerializedBlock {\n _key: string\n children: string\n index: number\n isInline: boolean\n node: PortableTextBlock | PortableTextListItemBlock\n}\n\nexport const createRenderNode = (\n renderers: PortableTextRenderers,\n listIndexMap: Map<string, number>,\n listDepthMap: Map<string, number>,\n): RenderNode => {\n function renderNode<N extends TypedObject>(options: Serializable<N>): string {\n const {node, index, isInline} = options\n\n if (isPortableTextListItemBlock(node)) {\n return renderListItem(node, index)\n }\n\n if (isPortableTextToolkitSpan(node)) {\n return renderSpan(node)\n }\n\n if (isPortableTextBlock(node)) {\n return renderBlock(node, index, isInline)\n }\n\n if (isPortableTextToolkitTextNode(node)) {\n return renderText(node)\n }\n\n return renderCustomBlock(node, index, isInline)\n }\n\n function renderListItem(\n node: PortableTextListItemBlock<\n PortableTextMarkDefinition,\n PortableTextSpan\n >,\n index: number,\n ): string {\n const renderer = renderers.listItem\n const handler =\n typeof renderer === 'function' ? renderer : renderer[node.listItem]\n const itemHandler = handler || renderers.unknownListItem\n\n // Build the text content from the block\n const tree = buildMarksTree(node)\n const textContent = tree\n .map((child, i) => {\n return renderNode({node: child, isInline: true, index: i, renderNode})\n })\n .join('')\n\n let children = textContent\n\n if (node.style && node.style !== 'normal') {\n // Wrap any other style in whatever the block component says to use\n const {listItem: _listItem, ...blockNode} = node\n children = renderNode({\n node: blockNode,\n index,\n isInline: false,\n renderNode,\n })\n // Strip trailing newlines from block styles - list item component handles spacing\n children = children.replace(/\\n+$/, '')\n }\n\n return itemHandler({\n value: node,\n index,\n listIndex: node._key ? listIndexMap.get(node._key) : undefined,\n listDepth: node._key ? listDepthMap.get(node._key) : undefined,\n isInline: false,\n renderNode,\n children,\n })\n }\n\n function renderSpan(node: ToolkitNestedPortableTextSpan): string {\n const {markDef, markType, markKey} = node\n const span = renderers.marks[markType] || renderers.unknownMark\n const children = node.children.map((child, childIndex) =>\n renderNode({node: child, index: childIndex, isInline: true, renderNode}),\n )\n\n return span({\n text: spanToPlainText(node),\n value: markDef,\n markType,\n markKey,\n renderNode,\n children: children.join(''),\n })\n }\n\n function renderBlock(\n node: PortableTextBlock,\n index: number,\n isInline: boolean,\n ): string {\n const {_key, ...props} = serializeBlock({node, index, isInline, renderNode})\n const style = props.node.style || 'normal'\n const handler =\n typeof renderers.block === 'function'\n ? renderers.block\n : renderers.block[style]\n const block = handler || renderers.unknownBlockStyle\n\n return block({...props, value: props.node, renderNode})\n }\n\n function renderText(node: ToolkitTextNode): string {\n if (node.text === '\\n') {\n return renderers.hardBreak()\n }\n\n return node.text\n }\n\n function renderCustomBlock(\n value: TypedObject,\n index: number,\n isInline: boolean,\n ): string {\n const component = renderers.types[value._type] ?? renderers.unknownType\n\n return component({\n value,\n isInline,\n index,\n renderNode,\n })\n }\n\n return renderNode\n}\n\nfunction serializeBlock(\n options: Serializable<PortableTextBlock>,\n): SerializedBlock {\n const {node, index, isInline, renderNode} = options\n const tree = buildMarksTree(node)\n\n const renderedChildren = tree.map((child, i) =>\n renderNode({node: child, isInline: true, index: i, renderNode}),\n )\n\n return {\n _key: node._key || defaultKeyGenerator(),\n children: renderedChildren.join(''),\n index,\n isInline,\n node,\n }\n}\n","import {\n isPortableTextBlock,\n isPortableTextListItemBlock,\n} from '@portabletext/toolkit'\nimport type {TypedObject} from '@portabletext/types'\n\n/**\n * @public\n */\nexport type BlockSpacingRenderer = (options: {\n current: TypedObject\n next: TypedObject\n}) => string | undefined\n\n/**\n * @public\n */\nexport const DefaultBlockSpacingRenderer: BlockSpacingRenderer = ({\n current,\n next,\n}) => {\n if (\n isPortableTextListItemBlock(current) &&\n isPortableTextListItemBlock(next)\n ) {\n return '\\n'\n }\n\n if (\n isPortableTextBlock(current) &&\n isPortableTextBlock(next) &&\n current.style === 'blockquote' &&\n next.style === 'blockquote'\n ) {\n return '\\n>\\n'\n }\n\n return '\\n\\n'\n}\n","/**\n * @public\n */\nexport const DefaultHardBreakRenderer = (): string => ' \\n'\n","import type {PortableTextListItemRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultListItemRenderer: PortableTextListItemRenderer = ({\n children,\n value,\n listIndex,\n listDepth,\n}) => {\n const listStyle = value.listItem || 'bullet'\n const depth = listDepth ?? (value.level || 1) - 1\n const indent = ' '.repeat(depth)\n\n if (listStyle === 'number') {\n return `${indent}${listIndex ?? 1}. ${children}`\n }\n\n if (listStyle === 'task') {\n const checked =\n 'checked' in value && typeof value.checked === 'boolean'\n ? value.checked\n : false\n const marker = checked ? '[x]' : '[ ]'\n return `${indent}- ${marker} ${children}`\n }\n\n return `${indent}- ${children}`\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownListItemRenderer: PortableTextListItemRenderer = ({\n children,\n}) => {\n return `- ${children}\\n`\n}\n","/**\n * Escapes special characters in image alt texts and link texts.\n */\nexport function escapeImageAndLinkText(text: string): string {\n return text.replace(/([[\\]\\\\])/g, '\\\\$1')\n}\n\n/**\n * Unescapes special characters in image alt texts and link texts.\n */\nexport function unescapeImageAndLinkText(text: string): string {\n return text.replace(/\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g, '$1')\n}\n\n/**\n * Escapes special characters in image/link titles (the part inside quotes).\n */\nexport function escapeImageAndLinkTitle(text: string): string {\n return text.replace(/([\\\\\"])/g, '\\\\$1')\n}\n\n/**\n * Escapes characters that have special meaning at the row level of a GFM\n * table cell.\n *\n * A literal `|` ends the cell, so unescaped pipes are replaced with `\\|`.\n * Newlines end the row, so they are replaced with `<br>` to keep the\n * visible line break inside the cell. Already-escaped pipes (`\\|`) are\n * left intact so that escapes introduced by mark renderers survive the\n * pass.\n *\n * Backslashes are intentionally not escaped here so that other escapes\n * already in the rendered cell (such as `\\[` and `\\]` in link text) are\n * not double-escaped.\n */\nexport function escapeTableCell(text: string): string {\n return text.replace(/(?<!\\\\)\\|/g, '\\\\|').replace(/\\n/g, '<br>')\n}\n","import type {TypedObject} from '@portabletext/types'\nimport {escapeImageAndLinkText, escapeImageAndLinkTitle} from '../../escape'\nimport type {PortableTextMarkRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultEmRenderer: PortableTextMarkRenderer = ({children}) =>\n `_${children}_`\n\n/**\n * @public\n */\nexport const DefaultStrongRenderer: PortableTextMarkRenderer = ({children}) =>\n `**${children}**`\n\n/**\n * @public\n */\nexport const DefaultCodeRenderer: PortableTextMarkRenderer = ({children}) =>\n `\\`${children}\\``\n\n/**\n * @public\n */\nexport const DefaultUnderlineRenderer: PortableTextMarkRenderer = ({\n children,\n}) => `<u>${children}</u>`\n\n/**\n * @public\n */\nexport const DefaultStrikeThroughRenderer: PortableTextMarkRenderer = ({\n children,\n}) => `~~${children}~~`\n\ninterface DefaultLink extends TypedObject {\n _type: 'link'\n href: string\n title: string | undefined\n}\n\n/**\n * @public\n */\nexport const DefaultLinkRenderer: PortableTextMarkRenderer<DefaultLink> = ({\n children,\n value,\n}) => {\n const href = value?.href || ''\n const title = value?.title || ''\n const looksSafe = uriLooksSafe(href)\n\n if (looksSafe) {\n // Check if the URL looks like an HTML injection attempt\n // If it has quotes AND angle brackets, or other suspicious patterns, encode more aggressively\n const looksLikeInjection = /[\"'][^\"']*[<>]|[<>][^<>]*[\"']/.test(href)\n\n if (looksLikeInjection) {\n // Encode all special characters that could be used for injection\n const encodedHref = href.replace(/[\"<>() ]/g, (char) => {\n return `%${char.charCodeAt(0).toString(16).toUpperCase()}`\n })\n return `[${escapeImageAndLinkText(children)}](${encodedHref})`\n }\n\n // For normal URLs, don't encode parentheses - Markdown handles balanced parens fine\n return `[${escapeImageAndLinkText(children)}](${href}${title ? ` \"${escapeImageAndLinkTitle(title)}\"` : ''})`\n }\n\n // Return children without link when URL is unsafe\n return children\n}\n\nfunction uriLooksSafe(uri: string): boolean {\n const url = (uri || '').trim()\n const first = url.charAt(0)\n\n if (first === '#' || first === '/') {\n return true\n }\n\n const colonIndex = url.indexOf(':')\n if (colonIndex === -1) {\n return true\n }\n\n const allowedProtocols = ['http', 'https', 'mailto', 'tel']\n const proto = url.slice(0, colonIndex).toLowerCase()\n if (allowedProtocols.indexOf(proto) !== -1) {\n return true\n }\n\n const queryIndex = url.indexOf('?')\n if (queryIndex !== -1 && colonIndex > queryIndex) {\n return true\n }\n\n const hashIndex = url.indexOf('#')\n if (hashIndex !== -1 && colonIndex > hashIndex) {\n return true\n }\n\n return false\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownMarkRenderer: PortableTextMarkRenderer = ({\n children,\n}) => {\n return children\n}\n","import type {PortableTextBlock} from '@portabletext/types'\nimport type {PortableTextRenderer} from '../types'\n\ntype PortableTextBlockRenderer = PortableTextRenderer<PortableTextBlock>\n\n/**\n * @public\n */\nexport const DefaultNormalRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n // Empty blocks should not add extra spacing\n if (!children || children.trim() === '') {\n return ''\n }\n\n return children\n}\n\n/**\n * @public\n */\nexport const DefaultBlockquoteRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n // Prefix each line with \"> \" for proper blockquote formatting\n // This handles multi-line content and preserves empty lines\n if (!children) {\n return '>'\n }\n\n return children\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n')\n}\n\n/**\n * @public\n */\nexport const DefaultH1Renderer: PortableTextBlockRenderer = ({children}) =>\n `# ${children}`\n\n/**\n * @public\n */\nexport const DefaultH2Renderer: PortableTextBlockRenderer = ({children}) =>\n `## ${children}`\n\n/**\n * @public\n */\nexport const DefaultH3Renderer: PortableTextBlockRenderer = ({children}) =>\n `### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH4Renderer: PortableTextBlockRenderer = ({children}) =>\n `#### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH5Renderer: PortableTextBlockRenderer = ({children}) =>\n `##### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH6Renderer: PortableTextBlockRenderer = ({children}) =>\n `###### ${children}`\n\n/**\n * @public\n */\nexport const DefaultUnknownStyleRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n return children ?? ''\n}\n","import {isTypedObject} from '@portabletext/schema'\nimport type {PortableTextBlock, TypedObject} from '@portabletext/types'\nimport {\n escapeImageAndLinkText,\n escapeImageAndLinkTitle,\n escapeTableCell,\n} from '../../escape'\nimport type {PortableTextTypeRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultCodeBlockRenderer: PortableTextTypeRenderer<{\n _type: 'code'\n code: string\n language: string | undefined\n}> = (options) => {\n if (!isCodeShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n return `\\`\\`\\`${normalizeLanguage(options.value.language)}\\n${options.value.code}\\n\\`\\`\\``\n}\n\nfunction isCodeShaped(value: unknown): value is {code: string} {\n return typeof (value as {code?: unknown} | null)?.code === 'string'\n}\n\n/**\n * A fence info string is everything after the opening fence on the same\n * line, so a real `language` can never contain a newline, and the parser\n * only ever produces a string. Junk in this optional field should not send\n * an otherwise valid code block to the fenced-JSON path, so it is treated\n * as absent instead of guarded.\n */\nfunction normalizeLanguage(language: unknown): string {\n if (typeof language !== 'string' || language.includes('\\n')) {\n return ''\n }\n return language\n}\n\n/**\n * @public\n */\nexport const DefaultHorizontalRuleRenderer: PortableTextTypeRenderer = () => {\n return '---'\n}\n\n/**\n * @public\n */\nexport const DefaultHtmlRenderer: PortableTextTypeRenderer<{\n _type: 'html'\n html: string\n}> = (options) => {\n if (!isHtmlShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n return options.value.html\n}\n\nfunction isHtmlShaped(value: unknown): value is {html: string} {\n return typeof (value as {html?: unknown} | null)?.html === 'string'\n}\n\n/**\n * @public\n */\nexport const DefaultImageRenderer: PortableTextTypeRenderer<{\n _type: 'image'\n src: string\n alt: string | undefined\n title: string | undefined\n}> = (options) => {\n if (!isImageShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n const alt = escapeImageAndLinkText(options.value.alt ?? '')\n const title = options.value.title\n ? ` \"${escapeImageAndLinkTitle(options.value.title)}\"`\n : ''\n return ``\n}\n\nfunction isImageShaped(value: unknown): value is {\n src: string\n alt: string | null | undefined\n title: string | null | undefined\n} {\n const image = value as {src?: unknown; alt?: unknown; title?: unknown} | null\n return (\n typeof image?.src === 'string' &&\n // CMS payloads commonly store cleared optional strings as `null`; the\n // render body treats `null` like absent, so the guard must too\n (image.alt == null || typeof image.alt === 'string') &&\n (image.title == null || typeof image.title === 'string')\n )\n}\n\n/**\n * A table is table-shaped when everything the renderer dereferences is\n * there: `rows` an array of typed objects with a `cells` array, every cell\n * a typed object whose `value` array holds typed objects (`renderNode`'s\n * input contract). The predicate narrows to exactly what `renderTable`\n * consumes, so the renderer needs no casts. A malformed `table` value\n * (e.g. a consumer's differently-shaped `table` type) falls back to the\n * fenced-JSON path instead of throwing.\n */\nfunction isTableShaped(value: unknown): value is TableShaped {\n const rows = (value as {rows?: unknown} | null)?.rows\n return (\n Array.isArray(rows) &&\n rows.every(\n (row) =>\n isTypedObject(row) &&\n Array.isArray(row['cells']) &&\n row['cells'].every(\n (cell) =>\n isTypedObject(cell) &&\n Array.isArray(cell['value']) &&\n cell['value'].every(isTypedObject),\n ),\n )\n )\n}\n\ntype TableShaped = {\n headerRows?: unknown\n alignment?: unknown\n rows: Array<{cells: Array<{value: Array<TypedObject>}>}>\n}\n\n/**\n * Renders a Portable Text table block-object back to Markdown.\n *\n * The PT `headerRows` field decides the header. Missing `headerRows` and\n * `headerRows === 0` both render headerless: GFM has no headerless form, so\n * an empty header row is emitted and every row goes in the body (that empty\n * header reads back as `headerRows: 0` via `markdownToPortableText`).\n * `headerRows >= 1` promotes `rows[0]` to the header. GFM allows exactly one\n * header row, so header rows beyond the first flatten into the body, lossy,\n * but the extra rows stay on the Portable Text side.\n *\n * Asymmetric tables (rows of varying cell counts) are widened to match\n * the row with the most cells. Narrower rows are padded with empty cells\n * so a GFM parser doesn't silently drop the extra cells in wider rows.\n *\n * @public\n */\nexport const DefaultTableRenderer: PortableTextTypeRenderer<{\n _type: 'table'\n headerRows: number | undefined\n alignment: Array<'left' | 'center' | 'right' | null> | undefined\n rows: Array<{\n _key: string\n cells: Array<{\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n}> = (options) => {\n const {value, renderNode} = options\n\n if (!isTableShaped(value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n\n return renderTable(value, renderNode)\n}\n\nfunction renderTable(\n value: TableShaped,\n renderNode: Parameters<PortableTextTypeRenderer>[0]['renderNode'],\n): string {\n const rows = value.rows\n // `alignment` is an extension field, not part of the table shape: junk\n // here should not send an otherwise valid table to the fenced-JSON path,\n // so it is normalized away instead of guarded (`{}.at` would throw below).\n const alignment: ReadonlyArray<unknown> | undefined = Array.isArray(\n value.alignment,\n )\n ? value.alignment\n : undefined\n\n const headerRow = rows.at(0)\n\n if (!headerRow) {\n return ''\n }\n\n // Helper to extract text from cell blocks\n const getCellText = (cellBlocks: Array<TypedObject>): string => {\n return cellBlocks\n .map((block, index) =>\n renderNode({\n node: block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join(' ')\n .trim()\n }\n\n const lines: string[] = []\n\n // GFM requires every row to have the same number of cells as the header row\n // and the delimiter row. Parsers silently drop excess cells from body rows\n // that are wider than the header, so we widen the table to the widest row\n // and pad narrower rows with empty cells to keep all data visible.\n const columnCount = rows.reduce(\n (max, row) => Math.max(max, row.cells.length),\n 0,\n )\n\n const renderCells = (texts: Array<string>): string => {\n const padded = [...texts]\n while (padded.length < columnCount) {\n padded.push('')\n }\n return `| ${padded.join(' | ')} |`\n }\n\n const renderRow = (cells: typeof headerRow.cells): string =>\n renderCells(cells.map((cell) => escapeTableCell(getCellText(cell.value))))\n\n // Delimiter row, sized to the column count. Each cell's colons encode the\n // column's alignment as defined by `value.alignment[columnIndex]`.\n const separators = Array.from({length: columnCount}, (_, index) => {\n const align = alignment?.at(index)\n if (align === 'left') {\n return ' :--- '\n }\n if (align === 'center') {\n return ' :---: '\n }\n if (align === 'right') {\n return ' ---: '\n }\n return ' --- '\n })\n const delimiter = `|${separators.join('|')}|`\n\n const hasHeader = (Number(value.headerRows) || 0) >= 1\n\n if (!hasHeader) {\n // Headerless table: emit an empty header row and keep every row in the\n // body.\n lines.push(renderCells([]))\n lines.push(delimiter)\n for (const row of rows) {\n lines.push(renderRow(row.cells))\n }\n } else {\n // `rows[0]` is the header. Header rows beyond the first flatten into the\n // body (GFM has a single header row).\n lines.push(renderRow(headerRow.cells))\n lines.push(delimiter)\n for (let i = 1; i < rows.length; i++) {\n const row = rows.at(i)\n if (row) {\n lines.push(renderRow(row.cells))\n }\n }\n }\n\n return lines.join('\\n')\n}\n\n/**\n * @public\n */\nexport const DefaultCalloutRenderer: PortableTextTypeRenderer<{\n _type: 'callout'\n tone: string\n content: Array<PortableTextBlock>\n}> = (options) => {\n if (!isCalloutShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n const {renderNode} = options\n const renderedContent = options.value.content\n .map((block, index) =>\n renderNode({\n node: block._type === 'block' ? {...block, style: 'normal'} : block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join('\\n\\n')\n\n const prefixed = renderedContent\n .split('\\n')\n .map((line) => (line === '' ? '>' : `> ${line}`))\n .join('\\n')\n\n return `> [!${options.value.tone.toUpperCase()}]\\n${prefixed}`\n}\n\nfunction isCalloutShaped(\n value: unknown,\n): value is {tone: string; content: Array<TypedObject>} {\n const callout = value as {tone?: unknown; content?: unknown} | null\n return (\n typeof callout?.tone === 'string' &&\n Array.isArray(callout.content) &&\n callout.content.every(isTypedObject)\n )\n}\n\n/**\n * Renders a structural blockquote block-object (the `types.blockquote` shape\n * produced by `markdownToPortableText` when a `types.blockquote` matcher is\n * provided) back to Markdown. Each content block is rendered via the\n * recursive renderer pipeline, joined with blank lines, and every line is\n * prefixed with `> ` to form a Markdown blockquote.\n *\n * Distinct from `DefaultBlockquoteRenderer`, which renders flat-path text\n * blocks with `style: 'blockquote'`.\n *\n * @public\n */\nexport const DefaultBlockquoteObjectRenderer: PortableTextTypeRenderer<{\n _type: 'blockquote'\n content: Array<PortableTextBlock>\n}> = ({value, renderNode}) => {\n const renderedContent = value.content\n .map((block, index) =>\n renderNode({\n node: block._type === 'block' ? {...block, style: 'normal'} : block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join('\\n\\n')\n\n return renderedContent\n .split('\\n')\n .map((line) => (line === '' ? '>' : `> ${line}`))\n .join('\\n')\n}\n\n/**\n * Renders a structural list block-object (the `types.list` shape produced by\n * `markdownToPortableText` when a `types.list` matcher is provided) back to\n * Markdown. Items render as `- ` for `kind: 'bullet'`, `1. `/`2. ` for `'number'`,\n * and `- [x] ` / `- [ ] ` for `'task'`. Items can hold any blocks - text blocks,\n * code blocks, callouts, images, and nested lists - and content other than the\n * leading text block is indented to keep it inside the item.\n *\n * @public\n */\nexport const DefaultListRenderer: PortableTextTypeRenderer<{\n _type: 'list'\n kind: 'bullet' | 'number' | 'task'\n items: Array<{\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | TypedObject>\n }>\n}> = ({value, renderNode}) => {\n // A list is \"loose\" when any item carries multiple non-list-block\n // content entries (a continuation paragraph, a code block, etc).\n // CommonMark uses blank lines between items in loose lists; tight lists\n // pack items together with single newlines. A nested list as a second\n // child of an item does NOT make the list loose, so we ignore those when\n // counting.\n const isLoose = value.items.some((item) => {\n const nonNestedBlocks = item.content.filter(\n (block) => (block as TypedObject)._type !== 'list',\n )\n return nonNestedBlocks.length > 1\n })\n const itemSeparator = isLoose ? '\\n\\n' : '\\n'\n\n const lines = value.items.map((item, itemIndex) => {\n const marker = getListMarker(value.kind, itemIndex, item.checked)\n // Continuation indent matches the marker's width so that subsequent\n // blocks attach to this item under CommonMark's lazy-continuation rule.\n // Bullet `- ` indents to 2; ordered `1. ` indents to 3, `10. ` to 4.\n // Task `- [x] ` is conceptually `- ` + a `[x] ` content prefix at the\n // markdown-it level, so its continuation indent stays at 2.\n const indentWidth = value.kind === 'task' ? 2 : marker.length\n const indent = ' '.repeat(indentWidth)\n\n const renderedBlocks = item.content.map((block, blockIndex) => ({\n isNestedList: (block as TypedObject)._type === 'list',\n text: renderNode({\n node: block as TypedObject,\n index: blockIndex,\n isInline: false,\n renderNode,\n }),\n }))\n\n const [first, ...rest] = renderedBlocks\n // Trim trailing whitespace from empty items so `- ` becomes `-`.\n const head = `${marker}${first?.text ?? ''}`.trimEnd()\n if (rest.length === 0) {\n return head\n }\n\n const tail = rest\n .map((rendered) => {\n const indented = rendered.text\n .split('\\n')\n .map((line) => (line === '' ? '' : `${indent}${line}`))\n .join('\\n')\n // Nested lists hug the previous block (tight list); other content\n // gets a blank line separator (paragraph break).\n return rendered.isNestedList ? `\\n${indented}` : `\\n\\n${indented}`\n })\n .join('')\n\n return `${head}${tail}`\n })\n\n return lines.join(itemSeparator)\n}\n\nfunction getListMarker(\n kind: 'bullet' | 'number' | 'task',\n itemIndex: number,\n checked: boolean | undefined,\n): string {\n if (kind === 'number') {\n return `${itemIndex + 1}. `\n }\n if (kind === 'task') {\n return checked ? '- [x] ' : '- [ ] '\n }\n return '- '\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownTypeRenderer: PortableTextTypeRenderer = ({\n value,\n isInline,\n}) => {\n const json = `\\`\\`\\`json\\n${JSON.stringify(value, null, 2)}\\n\\`\\`\\``\n // For inline unknown types, add newlines to break them out of the text flow\n return isInline ? `\\n${json}\\n` : json\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n TypedObject,\n} from '@portabletext/types'\nimport {buildListIndexMap} from './build-list-index-map'\nimport {createRenderNode} from './render-node'\nimport {\n DefaultBlockSpacingRenderer,\n type BlockSpacingRenderer,\n} from './renderers/block-spacing'\nimport {DefaultHardBreakRenderer} from './renderers/hard-break'\nimport {\n DefaultListItemRenderer,\n DefaultUnknownListItemRenderer,\n} from './renderers/list-item'\nimport {\n DefaultCodeRenderer,\n DefaultEmRenderer,\n DefaultLinkRenderer,\n DefaultStrikeThroughRenderer,\n DefaultStrongRenderer,\n DefaultUnderlineRenderer,\n DefaultUnknownMarkRenderer,\n} from './renderers/marks'\nimport {\n DefaultBlockquoteRenderer,\n DefaultH1Renderer,\n DefaultH2Renderer,\n DefaultH3Renderer,\n DefaultH4Renderer,\n DefaultH5Renderer,\n DefaultH6Renderer,\n DefaultNormalRenderer,\n DefaultUnknownStyleRenderer,\n} from './renderers/style'\nimport {\n DefaultCalloutRenderer,\n DefaultCodeBlockRenderer,\n DefaultHorizontalRuleRenderer,\n DefaultHtmlRenderer,\n DefaultImageRenderer,\n DefaultTableRenderer,\n DefaultUnknownTypeRenderer,\n} from './renderers/type'\nimport type {PortableTextRenderers} from './types'\n\nconst defaultRenderers: PortableTextRenderers = {\n types: {\n 'callout': DefaultCalloutRenderer,\n 'code': DefaultCodeBlockRenderer,\n 'horizontal-rule': DefaultHorizontalRuleRenderer,\n 'html': DefaultHtmlRenderer,\n 'image': DefaultImageRenderer,\n 'table': DefaultTableRenderer,\n },\n\n block: {\n normal: DefaultNormalRenderer,\n blockquote: DefaultBlockquoteRenderer,\n h1: DefaultH1Renderer,\n h2: DefaultH2Renderer,\n h3: DefaultH3Renderer,\n h4: DefaultH4Renderer,\n h5: DefaultH5Renderer,\n h6: DefaultH6Renderer,\n },\n marks: {\n 'em': DefaultEmRenderer,\n 'strong': DefaultStrongRenderer,\n 'code': DefaultCodeRenderer,\n 'underline': DefaultUnderlineRenderer,\n 'strike-through': DefaultStrikeThroughRenderer,\n 'link': DefaultLinkRenderer,\n },\n listItem: DefaultListItemRenderer,\n hardBreak: DefaultHardBreakRenderer,\n\n unknownType: DefaultUnknownTypeRenderer,\n unknownMark: DefaultUnknownMarkRenderer,\n unknownListItem: DefaultUnknownListItemRenderer,\n unknownBlockStyle: DefaultUnknownStyleRenderer,\n}\n\ntype Options = Partial<PortableTextRenderers> & {\n blockSpacing?: BlockSpacingRenderer\n}\n\n/**\n * @public\n */\nexport function portableTextToMarkdown<\n Block extends TypedObject = PortableTextBlock | ArbitraryTypedObject,\n>(blocks: Array<Block>, options: Options = {}): string {\n const renderers = {\n block: {\n ...defaultRenderers.block,\n ...options.block,\n },\n listItem: options.listItem ?? defaultRenderers.listItem,\n marks: {\n ...defaultRenderers.marks,\n ...options.marks,\n },\n types: {\n ...defaultRenderers.types,\n ...options.types,\n },\n hardBreak: options.hardBreak ?? defaultRenderers.hardBreak,\n unknownType: options.unknownType ?? defaultRenderers.unknownType,\n unknownBlockStyle:\n options.unknownBlockStyle ?? defaultRenderers.unknownBlockStyle,\n unknownListItem:\n options.unknownListItem ?? defaultRenderers.unknownListItem,\n unknownMark: options.unknownMark ?? defaultRenderers.unknownMark,\n }\n const renderBlockSpacing = options.blockSpacing ?? DefaultBlockSpacingRenderer\n\n const {listIndexMap, listDepthMap} = buildListIndexMap(blocks)\n const renderNode = createRenderNode(renderers, listIndexMap, listDepthMap)\n\n return blocks\n .map((node, index) => {\n const renderedNode = renderNode({\n node,\n index,\n isInline: false,\n renderNode,\n })\n\n if (index === blocks.length - 1) {\n return renderedNode\n }\n\n const nextNode = blocks.at(index + 1)\n\n if (!nextNode) {\n return renderedNode\n }\n\n const blockSpacing =\n renderBlockSpacing({\n current: node,\n next: nextNode,\n }) ?? '\\n\\n'\n\n return `${renderedNode}${blockSpacing}`\n })\n .join('')\n}\n","import {\n compileSchema,\n defineSchema,\n type AnnotationDefinition,\n type BlockObjectDefinition,\n type DecoratorDefinition,\n type ListDefinition,\n type StyleDefinition,\n} from '@portabletext/schema'\n\n/********************\n * Default style definitions\n ********************/\n\nexport const normalStyleDefinition = {\n name: 'normal',\n} as const satisfies StyleDefinition\n\nexport const h1StyleDefinition = {\n name: 'h1',\n} as const satisfies StyleDefinition\n\nexport const h2StyleDefinition = {\n name: 'h2',\n} as const satisfies StyleDefinition\n\nexport const h3StyleDefinition = {\n name: 'h3',\n} as const satisfies StyleDefinition\n\nexport const h4StyleDefinition = {\n name: 'h4',\n} as const satisfies StyleDefinition\n\nexport const h5StyleDefinition = {\n name: 'h5',\n} as const satisfies StyleDefinition\n\nexport const h6StyleDefinition = {\n name: 'h6',\n} as const satisfies StyleDefinition\n\nexport const blockquoteStyleDefinition = {\n name: 'blockquote',\n} as const satisfies StyleDefinition\n\n/********************\n * Default list definitions\n ********************/\n\nexport const defaultOrderedListItemDefinition = {\n name: 'number',\n} as const satisfies ListDefinition\n\nexport const defaultUnorderedListItemDefinition = {\n name: 'bullet',\n} as const satisfies ListDefinition\n\nexport const defaultTaskListItemDefinition = {\n name: 'task',\n} as const satisfies ListDefinition\n\n/********************\n * Default decorator definitions\n ********************/\n\nexport const defaultStrongDecoratorDefinition = {\n name: 'strong',\n} as const satisfies DecoratorDefinition\n\nexport const defaultEmDecoratorDefinition = {\n name: 'em',\n} as const satisfies DecoratorDefinition\n\nexport const defaultCodeDecoratorDefinition = {\n name: 'code',\n} as const satisfies DecoratorDefinition\n\nexport const defaultStrikeThroughDecoratorDefinition = {\n name: 'strike-through',\n} as const satisfies DecoratorDefinition\n\n/********************\n * Default annotation definitions\n ********************/\n\nexport const defaultLinkObjectDefinition = {\n name: 'link',\n fields: [\n {name: 'href', type: 'string'},\n {name: 'title', type: 'string'},\n ],\n} as const satisfies AnnotationDefinition\n\n/********************\n * Default object definitions\n ********************/\n\nexport const defaultCodeObjectDefinition = {\n name: 'code',\n fields: [\n {name: 'language', type: 'string'},\n {name: 'code', type: 'string'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultImageObjectDefinition = {\n name: 'image',\n fields: [\n {name: 'src', type: 'string'},\n {name: 'alt', type: 'string'},\n {name: 'title', type: 'string'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultHorizontalRuleObjectDefinition = {\n name: 'horizontal-rule',\n} as const satisfies BlockObjectDefinition\n\nexport const defaultHtmlObjectDefinition = {\n name: 'html',\n fields: [{name: 'html', type: 'string'}],\n} as const satisfies BlockObjectDefinition\n\n/**\n * Mirrors the canonical shape `@portabletext/plugin-table` expects: `table`\n * (`headerRows`, `rows`), `row` (`cells`), `cell` (`value`, text blocks or\n * standalone `image` objects). `alignment` is a `@portabletext/markdown`\n * extension field; `@portabletext/plugin-table` ignores it. Keep this in\n * sync with `packages/plugin-table/src/table-config.ts`'s\n * `defaultTableConfig`.\n */\nexport const defaultTableObjectDefinition = {\n name: 'table',\n fields: [\n {name: 'headerRows', type: 'number'},\n {name: 'alignment', type: 'array'},\n {\n name: 'rows',\n type: 'array',\n of: [\n {\n type: 'object',\n name: 'row',\n fields: [\n {\n name: 'cells',\n type: 'array',\n of: [\n {\n type: 'object',\n name: 'cell',\n fields: [\n {\n name: 'value',\n type: 'array',\n of: [{type: 'block'}, {type: 'image'}],\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultCalloutObjectDefinition = {\n name: 'callout',\n fields: [\n {name: 'tone', type: 'string'},\n {name: 'content', type: 'array'},\n ],\n} as const satisfies BlockObjectDefinition\n\n/**\n * The default schema for converting markdown to Portable Text.\n *\n * @public\n */\nexport const defaultSchema = compileSchema(\n defineSchema({\n block: {\n fields: [{name: 'checked', type: 'boolean'}],\n },\n styles: [\n normalStyleDefinition,\n h1StyleDefinition,\n h2StyleDefinition,\n h3StyleDefinition,\n h4StyleDefinition,\n h5StyleDefinition,\n h6StyleDefinition,\n blockquoteStyleDefinition,\n ],\n lists: [\n defaultOrderedListItemDefinition,\n defaultUnorderedListItemDefinition,\n defaultTaskListItemDefinition,\n ],\n decorators: [\n defaultStrongDecoratorDefinition,\n defaultEmDecoratorDefinition,\n defaultCodeDecoratorDefinition,\n defaultStrikeThroughDecoratorDefinition,\n ],\n annotations: [defaultLinkObjectDefinition],\n blockObjects: [\n defaultCalloutObjectDefinition,\n defaultCodeObjectDefinition,\n defaultHorizontalRuleObjectDefinition,\n defaultHtmlObjectDefinition,\n defaultImageObjectDefinition,\n defaultTableObjectDefinition,\n ],\n inlineObjects: [defaultImageObjectDefinition],\n }),\n)\n","import type {\n PortableTextObject,\n Schema,\n SchemaDefinition,\n} from '@portabletext/schema'\n\n/**\n * Matcher function for mapping markdown elements to Portable Text block styles.\n *\n * @public\n */\nexport type StyleMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildStyleMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): StyleMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.styles.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown list items to Portable Text list types.\n *\n * @public\n */\nexport type ListItemMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildListItemMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): ListItemMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.lists.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown inline formatting to Portable Text decorators.\n *\n * @public\n */\nexport type DecoratorMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildDecoratorMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): DecoratorMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.decorators.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown links to Portable Text annotations.\n *\n * @public\n */\nexport type AnnotationMatcher<\n TValue extends Record<string, unknown> = Record<string, never>,\n> = ({\n context,\n value,\n}: {\n context: {schema: Schema; keyGenerator: () => string}\n value: TValue\n}) => PortableTextObject | undefined\n\nexport function buildAnnotationMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): AnnotationMatcher<ExtractValue<TDefinition>> {\n return ({context, value}) => {\n const schemaDefinition = context.schema.annotations.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n const filteredValue = schemaDefinition.fields.reduce<\n Record<string, unknown>\n >((filteredValue, field) => {\n const fieldValue = value[field.name as keyof typeof value]\n\n if (fieldValue !== undefined) {\n filteredValue[field.name] = fieldValue\n }\n\n return filteredValue\n }, {})\n\n return {\n _key: context.keyGenerator(),\n _type: schemaDefinition.name,\n ...filteredValue,\n }\n }\n}\n\n/**\n * Matcher function for mapping markdown objects to Portable Text block or inline objects.\n *\n * @public\n */\nexport type ObjectMatcher<\n TValue extends Record<string, unknown> = Record<string, never>,\n> = ({\n context,\n value,\n isInline,\n}: {\n context: {schema: Schema; keyGenerator: () => string}\n value: TValue\n isInline: boolean\n}) => PortableTextObject | undefined\n\nexport function buildObjectMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): ObjectMatcher<ExtractValue<TDefinition>> {\n return ({context, value, isInline}) => {\n const schemaCollection = isInline\n ? context.schema.inlineObjects\n : context.schema.blockObjects\n\n const schemaDefinition = schemaCollection.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n const filteredValue = schemaDefinition.fields.reduce<\n Record<string, unknown>\n >((filteredValue, field) => {\n const fieldValue = value[field.name as keyof typeof value]\n\n if (fieldValue !== undefined) {\n filteredValue[field.name] = fieldValue\n }\n\n return filteredValue\n }, {})\n\n return {\n _key: context.keyGenerator(),\n _type: schemaDefinition.name,\n ...filteredValue,\n }\n }\n}\n\nexport type ExtractValue<\n TDefinition extends NonNullable<SchemaDefinition['blockObjects']>[0],\n> = TDefinition extends {fields: ReadonlyArray<{name: infer TNames}>}\n ? Record<TNames & string, unknown>\n : Record<string, never>\n","import {alert} from '@mdit/plugin-alert'\nimport {\n isSpan,\n isTextBlock,\n type PortableTextBlock,\n type PortableTextObject,\n type PortableTextTextBlock,\n type Schema,\n} from '@portabletext/schema'\nimport markdownit from 'markdown-it'\nimport {\n blockquoteStyleDefinition,\n defaultCalloutObjectDefinition,\n defaultCodeDecoratorDefinition,\n defaultCodeObjectDefinition,\n defaultEmDecoratorDefinition,\n defaultHorizontalRuleObjectDefinition,\n defaultHtmlObjectDefinition,\n defaultImageObjectDefinition,\n defaultLinkObjectDefinition,\n defaultOrderedListItemDefinition,\n defaultSchema,\n defaultStrikeThroughDecoratorDefinition,\n defaultStrongDecoratorDefinition,\n defaultTableObjectDefinition,\n defaultTaskListItemDefinition,\n defaultUnorderedListItemDefinition,\n h1StyleDefinition,\n h2StyleDefinition,\n h3StyleDefinition,\n h4StyleDefinition,\n h5StyleDefinition,\n h6StyleDefinition,\n normalStyleDefinition,\n} from '../default-schema'\nimport {unescapeImageAndLinkText} from '../escape'\nimport {defaultKeyGenerator} from '../key-generator'\nimport {\n buildAnnotationMatcher,\n buildDecoratorMatcher,\n buildListItemMatcher,\n buildObjectMatcher,\n buildStyleMatcher,\n type AnnotationMatcher,\n type DecoratorMatcher,\n type ExtractValue,\n type ListItemMatcher,\n type ObjectMatcher,\n type StyleMatcher,\n} from './matchers'\n\ntype Options = {\n schema?: Schema\n keyGenerator?: () => string\n marks?: {\n strong?: DecoratorMatcher\n em?: DecoratorMatcher\n code?: DecoratorMatcher\n strikeThrough?: DecoratorMatcher\n link?: AnnotationMatcher<{href: string; title: string | undefined}>\n }\n block?: {\n normal?: StyleMatcher\n blockquote?: StyleMatcher\n h1?: StyleMatcher\n h2?: StyleMatcher\n h3?: StyleMatcher\n h4?: StyleMatcher\n h5?: StyleMatcher\n h6?: StyleMatcher\n }\n listItem?: {\n number?: ListItemMatcher\n bullet?: ListItemMatcher\n task?: ListItemMatcher\n }\n types?: {\n code?: ObjectMatcher<{language: string | undefined; code: string}>\n horizontalRule?: ObjectMatcher\n html?: ObjectMatcher<{html: string}>\n table?: ObjectMatcher<{\n headerRows: number | undefined\n alignment: Array<'left' | 'center' | 'right' | null> | undefined\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n }>\n image?: ObjectMatcher<{src: string; alt: string; title: string | undefined}>\n callout?: ObjectMatcher<{tone: string; content: Array<PortableTextBlock>}>\n blockquote?: ObjectMatcher<{content: Array<PortableTextBlock>}>\n list?: ObjectMatcher<{\n kind: 'bullet' | 'number' | 'task'\n items: Array<{\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | PortableTextObject>\n }>\n }>\n }\n html?: {\n /**\n * How to handle inline HTML.\n * - 'skip': Ignore inline HTML (default)\n * - 'text': Convert inline HTML to plain text\n *\n * @defaultValue 'skip'\n */\n inline?: 'skip' | 'text'\n }\n}\n\nconst codeBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultCodeObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultCodeObjectDefinition)\n const codeObject = defaultMatcher({context, value, isInline})\n\n if (!codeObject) {\n return undefined\n }\n\n if (!('code' in codeObject)) {\n return undefined\n }\n\n return codeObject\n}\n\nconst imageBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultImageObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultImageObjectDefinition)\n const imageObject = defaultMatcher({context, value, isInline})\n\n if (!imageObject) {\n return undefined\n }\n\n if (!('src' in imageObject)) {\n return undefined\n }\n\n return imageObject\n}\n\nconst tableBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultTableObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultTableObjectDefinition)\n const tableObject = defaultMatcher({context, value, isInline})\n\n if (!tableObject) {\n return undefined\n }\n\n if (!('rows' in tableObject)) {\n return undefined\n }\n\n return tableObject\n}\n\nconst defaultOptions = {\n schema: defaultSchema,\n keyGenerator: defaultKeyGenerator,\n html: {\n inline: 'skip',\n },\n block: {\n normal: buildStyleMatcher(normalStyleDefinition),\n blockquote: buildStyleMatcher(blockquoteStyleDefinition),\n h1: buildStyleMatcher(h1StyleDefinition),\n h2: buildStyleMatcher(h2StyleDefinition),\n h3: buildStyleMatcher(h3StyleDefinition),\n h4: buildStyleMatcher(h4StyleDefinition),\n h5: buildStyleMatcher(h5StyleDefinition),\n h6: buildStyleMatcher(h6StyleDefinition),\n },\n listItem: {\n number: buildListItemMatcher(defaultOrderedListItemDefinition),\n bullet: buildListItemMatcher(defaultUnorderedListItemDefinition),\n task: buildListItemMatcher(defaultTaskListItemDefinition),\n },\n marks: {\n strong: buildDecoratorMatcher(defaultStrongDecoratorDefinition),\n em: buildDecoratorMatcher(defaultEmDecoratorDefinition),\n code: buildDecoratorMatcher(defaultCodeDecoratorDefinition),\n strikeThrough: buildDecoratorMatcher(\n defaultStrikeThroughDecoratorDefinition,\n ),\n link: buildAnnotationMatcher(defaultLinkObjectDefinition),\n },\n types: {\n code: codeBlockMatcher,\n horizontalRule: buildObjectMatcher(defaultHorizontalRuleObjectDefinition),\n html: buildObjectMatcher(defaultHtmlObjectDefinition),\n image: imageBlockMatcher,\n callout: buildObjectMatcher(defaultCalloutObjectDefinition),\n table: tableBlockMatcher,\n },\n} as const satisfies Options\n\n/**\n * Reads GFM column alignment from a markdown-it cell token's `style`\n * attribute. Tolerates other CSS declarations sharing the value.\n */\nexport function extractAlignmentFromStyleAttr(\n styleAttr: string | null,\n): 'left' | 'center' | 'right' | null {\n if (!styleAttr) {\n return null\n }\n const match = styleAttr.match(/text-align\\s*:\\s*(left|center|right)/)\n if (!match) {\n return null\n }\n return match[1] as 'left' | 'center' | 'right'\n}\n\n/**\n * A table row is empty when every cell holds only blank spans, no non-empty\n * text, no inline objects, no non-text blocks. Used to detect a headerless\n * GFM table: `portableTextToMarkdown` emits an empty header row for\n * `headerRows: 0`, and an empty header must round-trip back to\n * `headerRows: 0` rather than a phantom header row.\n */\nfunction isEmptyTableRow(\n cells: Array<{value: Array<PortableTextBlock>}>,\n context: {schema: Schema},\n): boolean {\n return cells.every((cell) =>\n cell.value.every(\n (block) =>\n isTextBlock(context, block) &&\n block.children.every(\n (child) => isSpan(context, child) && (child.text ?? '').trim() === '',\n ),\n ),\n )\n}\n\n/**\n * Flattens a table structure by lifting all blocks from all cells.\n */\nfunction flattenTable(\n table: {\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n headerRows: number\n },\n portableText: Array<PortableTextBlock>,\n): void {\n // Flatten the table by lifting all blocks from all cells\n for (const row of table.rows) {\n for (const cell of row.cells) {\n for (const block of cell.value) {\n portableText.push(block)\n }\n }\n }\n}\n\n/**\n * Converts a markdown string to an array of Portable Text blocks.\n *\n * @public\n */\nexport function markdownToPortableText(\n markdown: string,\n options?: Options,\n): Array<PortableTextBlock> {\n const consolidatedOptions = {\n schema: options?.schema ?? defaultSchema,\n keyGenerator: options?.keyGenerator ?? defaultKeyGenerator,\n html: {\n inline: options?.html?.inline ?? 'skip',\n },\n marks: {\n ...defaultOptions.marks,\n ...options?.marks,\n },\n block: {\n ...defaultOptions.block,\n ...options?.block,\n },\n listItem: {\n ...defaultOptions.listItem,\n ...options?.listItem,\n },\n types: {\n ...defaultOptions.types,\n ...options?.types,\n },\n }\n\n const md = markdownit({\n html: true,\n linkify: true,\n typographer: false,\n })\n .enable(['strikethrough', 'table'])\n .use(alert)\n\n const tokens = md.parse(markdown, {})\n\n // Pre-pass: detect GFM task-list checkbox prefixes (`[ ]`, `[x]`, `[X]`)\n // on the first inline content of each list item. Strip the prefix from the\n // inline content and remember which list items are tasks (and their checked\n // state) so the main walk can apply `listItem: 'task'` and `checked` when\n // processing the corresponding `list_item_open` token.\n const taskCheckedByListItemIndex = new Map<number, boolean>()\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]\n if (token?.type !== 'list_item_open') {\n continue\n }\n // Find the first inline token within this list item.\n let inlineIndex = -1\n for (let j = i + 1; j < tokens.length; j++) {\n const candidate = tokens[j]\n if (!candidate) {\n continue\n }\n if (candidate.type === 'list_item_close') {\n break\n }\n if (candidate.type === 'inline') {\n inlineIndex = j\n break\n }\n }\n if (inlineIndex === -1) {\n continue\n }\n const inlineToken = tokens[inlineIndex]\n if (!inlineToken) {\n continue\n }\n const match = inlineToken.content.match(/^\\[([ xX])\\] /)\n if (!match) {\n continue\n }\n const checked = match[1] !== ' '\n taskCheckedByListItemIndex.set(i, checked)\n // Strip the prefix from the content and the first child text token so the\n // resulting span doesn't include the checkbox marker.\n inlineToken.content = inlineToken.content.slice(match[0].length)\n const firstChild = inlineToken.children?.[0]\n if (firstChild && typeof firstChild.content === 'string') {\n firstChild.content = firstChild.content.slice(match[0].length)\n }\n }\n\n const portableText: Array<PortableTextBlock> = []\n\n // State\n let currentBlock: PortableTextTextBlock | null = null\n const currentListStack: Array<string | null> = []\n const markDefRefs: Array<string> = [] // mark keys: 'strong', 'em', 'code', or link keys\n let currentMarkDefs: Array<PortableTextObject> = []\n let currentBlockquoteStyle: string | null = null // Track blockquote style when inside blockquote\n let inListItem = false // Track if we're inside a list item\n\n // Callout state\n let calloutStartIndex: number | null = null\n let calloutStartTarget: Array<PortableTextBlock | PortableTextObject> | null =\n null\n let calloutType: string | null = null\n\n // Blockquote container state. When `types.blockquote` is defined and the\n // parser enters a `blockquote_open`, a frame is pushed here. Block\n // emissions inside the surrounding open/close pair are captured and\n // spliced out at close to wrap them in a `blockquote` block-object.\n // Nested blockquotes push additional frames; `blockTarget()` already\n // routes correctly because the splice happens against the same target.\n const blockquoteStack: Array<{\n startTarget: Array<PortableTextBlock | PortableTextObject>\n startIndex: number\n }> = []\n\n // Table state\n let currentTable: {\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n headerRows: number\n emptyHeaderDropped: boolean\n alignment: Array<'left' | 'center' | 'right' | null>\n } | null = null\n let currentTableRow: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }> | null = null\n let inTableHead = false\n\n // List container state. When `types.list` is defined and the parser enters\n // a `bullet_list_open` / `ordered_list_open`, a structural-list frame is\n // pushed here. Block emissions inside the surrounding `list_item_open` /\n // `list_item_close` pair are diverted into the item's `content` array\n // instead of the top-level `portableText`. At list-close, the matcher is\n // called to materialize a `list` block-object, which is pushed into the\n // enclosing target (parent list item's content if nested, else top-level).\n type ListContainerItem = {\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | PortableTextObject>\n }\n type ListContainerFrame = {\n kind: 'bullet' | 'number' | 'task'\n items: Array<ListContainerItem>\n currentItem: ListContainerItem | null\n }\n // A null entry marks a list that is being handled by the flat path (either\n // because `types.list` is undefined, or because a nested list inside a\n // flat-path list should also stay flat). Parallel to `currentListStack`.\n const listContainerStack: Array<ListContainerFrame | null> = []\n\n /**\n * Returns the array that block emissions should land in. If the innermost\n * structural list frame has an open `currentItem`, blocks land in that\n * item's `content`. Otherwise blocks land at the top level.\n */\n const blockTarget = (): Array<PortableTextBlock | PortableTextObject> => {\n for (let i = listContainerStack.length - 1; i >= 0; i--) {\n const frame = listContainerStack[i]\n if (frame && frame.currentItem) {\n return frame.currentItem.content\n }\n }\n return portableText\n }\n\n /**\n * Pushes a block into the current target (innermost open list item, or\n * top-level `portableText` if none). Use instead of direct\n * `portableText.push(...)` for any block emission that should be captured\n * by an enclosing list container.\n */\n const pushBlock = (block: PortableTextBlock | PortableTextObject): void => {\n blockTarget().push(block as PortableTextBlock)\n }\n\n const startBlock = (style: string) => {\n flushBlock()\n currentBlock = {\n _type: 'block' as const,\n style,\n children: [],\n _key: consolidatedOptions.keyGenerator(),\n markDefs: [],\n }\n currentMarkDefs = []\n }\n\n const flushBlock = () => {\n if (!currentBlock) {\n return\n }\n\n // Text blocks must have at least one child span\n if (currentBlock.children.length === 0) {\n currentBlock.children.push({\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: '',\n marks: [],\n })\n }\n\n // Assign accumulated markDefs to the block\n currentBlock.markDefs = currentMarkDefs\n\n pushBlock(currentBlock)\n\n currentBlock = null\n currentMarkDefs = []\n }\n\n const addSpan = (text: string) => {\n if (text.length === 0) {\n return\n }\n\n if (!currentBlock) {\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n if (!currentBlock) {\n throw new Error('Expected current block')\n }\n\n const lastChild = currentBlock.children.at(-1)\n\n if (\n isSpan({schema: consolidatedOptions.schema}, lastChild) &&\n lastChild.marks?.every((mark) => markDefRefs.includes(mark)) &&\n markDefRefs.every((mark) => lastChild.marks?.includes(mark))\n ) {\n // Merge with previous span if marks match\n lastChild.text += text\n } else {\n currentBlock.children.push({\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: text,\n marks: [...markDefRefs],\n })\n }\n }\n\n // Helpers for lists\n const listLevel = () => currentListStack.length\n const ensureListBlock = (listItem: string, checked?: boolean) => {\n if (!currentBlock) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n if (!currentBlock) {\n throw new Error('Expected current block')\n }\n\n if (\n currentBlock.listItem !== listItem ||\n currentBlock.level !== listLevel()\n ) {\n currentBlock.listItem = listItem\n currentBlock.level = listLevel()\n }\n\n if (checked !== undefined) {\n ;(currentBlock as PortableTextTextBlock & {checked?: boolean}).checked =\n checked\n }\n }\n\n // Walk tokens\n for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {\n const token = tokens[tokenIndex]\n if (!token) {\n continue\n }\n\n switch (token.type) {\n // Paragraphs\n case 'paragraph_open': {\n // If we're in a list item but have no current block (e.g., after a code block),\n // we need to create a new list item block\n if (inListItem) {\n // Structural list path: start a plain text block; the paragraph\n // lands in the current list item's `content` via `pushBlock`.\n if (listContainerStack.at(-1)) {\n if (!currentBlock) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ??\n 'normal'\n startBlock(style)\n }\n break\n }\n\n // Flat list path: ensure the current text block carries\n // `listItem` + `level` fields.\n if (!currentBlock) {\n const listType = currentListStack.at(-1)\n\n if (listType) {\n ensureListBlock(listType)\n }\n }\n\n break\n }\n\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n break\n }\n\n startBlock(style)\n break\n }\n case 'paragraph_close':\n // In a flat list item: skip flushing, list_item_close will flush.\n // In a structural list item: flush so multiple paragraphs in one\n // item land as separate text blocks.\n if (inListItem) {\n if (listContainerStack.at(-1)) {\n flushBlock()\n }\n break\n }\n flushBlock()\n break\n\n // Headings\n case 'heading_open': {\n const level = Number(token?.tag?.slice(1))\n\n // Map level to the appropriate heading matcher\n const headingMatchers = {\n 1: consolidatedOptions.block.h1,\n 2: consolidatedOptions.block.h2,\n 3: consolidatedOptions.block.h3,\n 4: consolidatedOptions.block.h4,\n 5: consolidatedOptions.block.h5,\n 6: consolidatedOptions.block.h6,\n } as const\n\n const headingMatcher =\n headingMatchers[level as keyof typeof headingMatchers]\n\n const style =\n headingMatcher?.({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No heading style found, using \"normal\"')\n startBlock('normal')\n break\n }\n\n startBlock(style)\n break\n }\n case 'heading_close':\n flushBlock()\n break\n\n // Blockquote\n case 'blockquote_open': {\n // Flush any current block before entering blockquote\n flushBlock()\n\n // Structural-blockquote path: when the consumer registers a\n // `types.blockquote` matcher, plain blockquotes (NOT GFM alerts -\n // those use separate `alert_open`/`alert_close` tokens) become\n // block-objects with an explicit `content` array. Block emissions\n // inside the open/close pair are spliced out at close time and\n // wrapped in a `blockquote` block-object.\n if (consolidatedOptions.types.blockquote) {\n const startTarget = blockTarget()\n blockquoteStack.push({\n startTarget,\n startIndex: startTarget.length,\n })\n break\n }\n\n // Flat path: set the blockquote style for paragraphs inside the\n // blockquote so they emit text blocks with `style: 'blockquote'`.\n const style =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n currentBlockquoteStyle = style ?? 'normal'\n break\n }\n case 'blockquote_close': {\n // Flush any blockquote content before exiting\n flushBlock()\n\n // Structural path: pop the topmost frame and splice its captured\n // content into a `blockquote` block-object via the matcher. If the\n // matcher returns undefined, fall back to flat-style by re-emitting\n // the content blocks with `style: 'blockquote'`.\n if (\n consolidatedOptions.types.blockquote &&\n blockquoteStack.length > 0\n ) {\n const frame = blockquoteStack.pop()\n if (frame) {\n const contentBlocks = frame.startTarget.splice(\n frame.startIndex,\n ) as Array<PortableTextBlock>\n\n const blockquoteObject = consolidatedOptions.types.blockquote({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {content: contentBlocks},\n isInline: false,\n })\n\n if (blockquoteObject) {\n pushBlock(blockquoteObject)\n } else {\n // Matcher returned undefined: fall back to flat-style by\n // re-emitting each content block with `style: 'blockquote'`.\n const blockquoteStyle =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ??\n 'blockquote'\n for (const block of contentBlocks) {\n if (block._type === 'block') {\n pushBlock({\n ...(block as PortableTextTextBlock),\n style: blockquoteStyle,\n })\n } else {\n pushBlock(block)\n }\n }\n }\n }\n break\n }\n\n currentBlockquoteStyle = null\n break\n }\n // Lists\n case 'bullet_list_open': {\n flushBlock()\n\n // Structural-container path: when the consumer registers a\n // `types.list` matcher, lists become block-objects with explicit\n // `items` arrays. Block emissions inside list items are diverted\n // into `currentItem.content` via `blockTarget()`. Mirrors the\n // `types.table` pattern.\n if (consolidatedOptions.types.list) {\n listContainerStack.push({\n kind: 'bullet',\n items: [],\n currentItem: null,\n })\n currentListStack.push(null)\n break\n }\n\n // Flat path: lists are reconstructed from text blocks with\n // `listItem` + `level` fields at render time.\n const listItem = consolidatedOptions.listItem.bullet({\n context: {schema: consolidatedOptions.schema},\n })\n\n listContainerStack.push(null)\n if (!listItem) {\n currentListStack.push(null)\n break\n }\n currentListStack.push(listItem)\n break\n }\n case 'ordered_list_open': {\n flushBlock()\n\n if (consolidatedOptions.types.list) {\n listContainerStack.push({\n kind: 'number',\n items: [],\n currentItem: null,\n })\n currentListStack.push(null)\n break\n }\n\n const listItem = consolidatedOptions.listItem.number({\n context: {schema: consolidatedOptions.schema},\n })\n\n listContainerStack.push(null)\n if (!listItem) {\n currentListStack.push(null)\n break\n }\n currentListStack.push(listItem)\n break\n }\n case 'bullet_list_close':\n case 'ordered_list_close': {\n const frame = listContainerStack.pop()\n currentListStack.pop()\n\n // Structural close: materialize the list block-object and push it\n // into the enclosing target (parent list item's content if nested,\n // else top-level).\n if (frame && consolidatedOptions.types.list) {\n // Promote `kind` to 'task' if any item carries a checked state.\n const kind: 'bullet' | 'number' | 'task' = frame.items.some(\n (item) => 'checked' in item,\n )\n ? 'task'\n : frame.kind\n\n const listObject = consolidatedOptions.types.list({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {kind, items: frame.items},\n isInline: false,\n })\n\n if (listObject) {\n pushBlock(listObject)\n } else {\n // Matcher returned undefined: fall back to the flat path by\n // re-emitting each item's content. Text blocks get the same\n // `listItem` + `level` fields the flat path would produce so\n // adjacent blocks form a list at render time. Non-text-block\n // content (code blocks, etc.) gets pushed as-is, mirroring\n // how the flat path handles those when they appear inside a\n // list item.\n const flatListItem =\n (kind === 'task'\n ? consolidatedOptions.listItem.task?.({\n context: {schema: consolidatedOptions.schema},\n })\n : kind === 'number'\n ? consolidatedOptions.listItem.number({\n context: {schema: consolidatedOptions.schema},\n })\n : consolidatedOptions.listItem.bullet({\n context: {schema: consolidatedOptions.schema},\n })) ?? null\n // The just-popped list was nested at depth = remaining stack\n // length + 1 (since we already popped).\n const level = listContainerStack.length + 1\n for (const item of frame.items) {\n for (const block of item.content) {\n if (\n block._type === 'block' &&\n flatListItem !== null &&\n !('listItem' in block)\n ) {\n const flatBlock = {\n ...(block as PortableTextTextBlock),\n listItem: flatListItem,\n level,\n ...(item.checked === undefined\n ? {}\n : {checked: item.checked}),\n }\n pushBlock(flatBlock)\n } else {\n pushBlock(block)\n }\n }\n }\n }\n }\n break\n }\n case 'list_item_open': {\n const frame = listContainerStack.at(-1)\n\n // Flush any previous list item block before starting a new one\n // This is needed for proper separation of list items\n if (currentBlock) {\n flushBlock()\n }\n\n // Structural path: start a new `list-item` whose `content` becomes\n // the divert target for subsequent block emissions until\n // `list_item_close`.\n if (frame) {\n const taskChecked = taskCheckedByListItemIndex.get(tokenIndex)\n frame.currentItem = {\n _type: 'list-item',\n _key: consolidatedOptions.keyGenerator(),\n ...(taskChecked === undefined ? {} : {checked: taskChecked}),\n content: [],\n }\n inListItem = true\n break\n }\n\n // Flat path\n const baseListType = currentListStack.at(-1)\n\n if (baseListType === undefined) {\n throw new Error('Expected an open list')\n }\n\n // Resolve task list type and checked state for this specific item.\n // If the schema declares a `task` list definition, GFM checkboxes\n // (`- [ ]` / `- [x]`) override the surrounding list's type for this\n // item. Otherwise the prefix has already been stripped by the\n // pre-pass and we render as the surrounding list type.\n const taskChecked = taskCheckedByListItemIndex.get(tokenIndex)\n let listType = baseListType\n let checked: boolean | undefined\n if (taskChecked !== undefined) {\n const taskListType = consolidatedOptions.listItem.task?.({\n context: {schema: consolidatedOptions.schema},\n })\n if (taskListType) {\n listType = taskListType\n checked = taskChecked\n }\n }\n\n // If listType is null, it means there's no list definition in the schema\n // Just create a normal block without list properties\n if (listType === null) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n inListItem = true\n break\n }\n\n ensureListBlock(listType, checked)\n inListItem = true\n break\n }\n case 'list_item_close': {\n const frame = listContainerStack.at(-1)\n\n // Structural path: flush any current block into the item's content,\n // then push the completed item onto the frame.\n if (frame && frame.currentItem) {\n flushBlock()\n frame.items.push(frame.currentItem)\n frame.currentItem = null\n inListItem = false\n break\n }\n\n // Flat path\n inListItem = false\n flushBlock()\n break\n }\n\n // Code fences / blocks\n case 'fence': {\n flushBlock()\n\n const language = token.info.trim() || undefined\n // Remove trailing newline from code content\n const code = token.content.replace(/\\n$/, '')\n\n const codeObject = consolidatedOptions.types.code({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {language, code},\n isInline: false,\n })\n\n if (!codeObject) {\n // Code block not in schema, fall back to text block\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(code)\n flushBlock()\n break\n }\n\n pushBlock(codeObject)\n\n break\n }\n\n // Horizontal rule\n case 'hr': {\n flushBlock()\n\n const hrObject = consolidatedOptions.types.horizontalRule({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {},\n isInline: false,\n })\n\n if (!hrObject) {\n // If there's no break definition in the schema, parse as text\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan('---')\n flushBlock()\n break\n }\n\n pushBlock(hrObject)\n\n break\n }\n\n // HTML block\n case 'html_block': {\n flushBlock()\n\n const htmlContent = token.content.trim()\n\n if (!htmlContent) {\n break\n }\n\n const htmlObject = consolidatedOptions.types.html({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {html: htmlContent},\n isInline: false,\n })\n\n if (!htmlObject) {\n // If there's no HTML block definition in the schema, parse as text\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(htmlContent)\n flushBlock()\n break\n }\n\n pushBlock(htmlObject)\n\n break\n }\n\n case 'code_block': {\n flushBlock()\n\n // Remove trailing newline from code content\n const code = token.content.replace(/\\n$/, '')\n\n const codeObject = consolidatedOptions.types.code({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {language: undefined, code},\n isInline: false,\n })\n\n if (!codeObject) {\n // Code block not in schema, fall back to text block\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(code)\n flushBlock()\n } else {\n pushBlock(codeObject)\n }\n\n break\n }\n\n // Tables\n case 'table_open':\n flushBlock()\n currentTable = {\n rows: [],\n headerRows: 0,\n emptyHeaderDropped: false,\n alignment: [],\n }\n break\n\n case 'table_close': {\n if (!currentTable) {\n break\n }\n\n // Only create table object if table type is defined\n if (consolidatedOptions.types.table) {\n const hasAlignment = currentTable.alignment.some((a) => a !== null)\n const tableObject = consolidatedOptions.types.table({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {\n rows: currentTable.rows,\n headerRows:\n currentTable.headerRows > 0\n ? currentTable.headerRows\n : currentTable.emptyHeaderDropped\n ? 0\n : undefined,\n alignment: hasAlignment ? currentTable.alignment : undefined,\n },\n isInline: false,\n })\n\n if (tableObject) {\n pushBlock(tableObject)\n } else {\n // If table object couldn't be created, flatten the table\n flattenTable(\n currentTable,\n blockTarget() as Array<PortableTextBlock>,\n )\n }\n } else {\n // If there's no table definition in the schema, flatten the table\n flattenTable(currentTable, blockTarget() as Array<PortableTextBlock>)\n }\n\n currentTable = null\n break\n }\n\n case 'thead_open':\n inTableHead = true\n break\n\n case 'thead_close':\n inTableHead = false\n break\n\n case 'tbody_open':\n case 'tbody_close':\n // Just markers, no action needed\n break\n\n case 'tr_open':\n currentTableRow = []\n break\n\n case 'tr_close':\n if (currentTable && currentTableRow) {\n if (\n inTableHead &&\n isEmptyTableRow(currentTableRow, {\n schema: consolidatedOptions.schema,\n })\n ) {\n // An all-empty header row means \"no header\": drop it and leave\n // `headerRows` at 0 (recorded so `table_close` emits an explicit\n // 0, not `undefined`), so `portableTextToMarkdown`'s headerless\n // output round-trips back to `headerRows: 0`.\n currentTable.emptyHeaderDropped = true\n } else {\n currentTable.rows.push({\n _key: consolidatedOptions.keyGenerator(),\n _type: 'row',\n cells: currentTableRow,\n })\n if (inTableHead) {\n currentTable.headerRows++\n }\n }\n }\n currentTableRow = null\n break\n\n case 'th_open':\n case 'td_open': {\n // Alignment is per-column, set on every cell of that column. Read\n // from the header so each column contributes exactly one entry.\n if (currentTable && inTableHead && token.type === 'th_open') {\n currentTable.alignment.push(\n extractAlignmentFromStyleAttr(token.attrGet('style')),\n )\n }\n\n // Start a new block for the table cell\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n break\n }\n\n case 'th_close':\n case 'td_close': {\n // Flush the current block into the cell\n flushBlock()\n\n // Get all blocks that were added since this cell started\n // We need to extract them from the current target array\n const cellBlocks: Array<PortableTextBlock> = []\n const target = blockTarget()\n\n // Check if we have blocks to extract (added after table_open)\n if (target.length > 0) {\n const lastBlock = target.at(-1)\n if (lastBlock && lastBlock._type === 'block') {\n cellBlocks.push(target.pop()! as PortableTextBlock)\n }\n }\n\n // If no blocks were created (empty cell), create an empty block\n if (cellBlocks.length === 0) {\n cellBlocks.push({\n _type: 'block' as const,\n style:\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) || 'normal',\n children: [\n {\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: '',\n marks: [],\n },\n ],\n _key: consolidatedOptions.keyGenerator(),\n markDefs: [],\n })\n }\n\n // Check if the cell contains a single block with a single image child\n // If so, extract the image as a block-level image\n const firstBlock = cellBlocks[0]\n if (\n cellBlocks.length === 1 &&\n firstBlock &&\n firstBlock._type === 'block' &&\n 'children' in firstBlock &&\n Array.isArray(firstBlock.children) &&\n firstBlock.children.length === 1\n ) {\n const onlyChild = firstBlock.children[0]\n // Check if it's an image object (not a span)\n if (\n typeof onlyChild === 'object' &&\n onlyChild !== null &&\n '_type' in onlyChild &&\n onlyChild._type !== consolidatedOptions.schema.span.name &&\n onlyChild._type === 'image'\n ) {\n // Replace the block with just the image\n cellBlocks[0] = onlyChild as PortableTextBlock\n }\n }\n\n if (currentTableRow !== null) {\n currentTableRow.push({\n _type: 'cell',\n _key: consolidatedOptions.keyGenerator(),\n value: cellBlocks,\n })\n }\n break\n }\n\n // Inline container\n case 'inline': {\n // Check if we're in a table cell\n const inTableCell = currentTableRow !== null\n\n // Check if this is a standalone image (paragraph with only an image)\n if (\n token.children?.length === 1 &&\n token.children[0]?.type === 'image'\n ) {\n const imageToken = token.children[0]\n if (!imageToken) {\n break\n }\n\n const src =\n imageToken.attrs?.find(([name]) => name === 'src')?.at(1) || ''\n const alt = unescapeImageAndLinkText(imageToken.content || '')\n const title =\n imageToken.attrs?.find(([name]) => name === 'title')?.at(1) ||\n undefined\n\n const blockImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title},\n isInline: false,\n })\n\n if (blockImageObject) {\n if (inTableCell) {\n // In table cells, we can't push to portableText directly\n // The block image will be handled in th_close/td_close extraction logic\n // For now, add it as a child of the current block\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n blockImageObject as PortableTextObject,\n )\n }\n } else {\n // If the current block has content, flush it before adding the block image\n // Otherwise, discard the empty block that was created by paragraph_open\n const hasContent =\n currentBlock &&\n 'children' in currentBlock &&\n (currentBlock as PortableTextTextBlock).children.length > 0\n\n if (hasContent) {\n flushBlock()\n } else {\n currentBlock = null\n currentMarkDefs = []\n }\n pushBlock(blockImageObject)\n }\n break\n }\n\n // Block image not supported, try inline image as fallback\n const inlineImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title},\n isInline: true,\n })\n\n if (inlineImageObject) {\n // Ensure we have a block to add the inline image to\n if (!currentBlock) {\n if (inListItem) {\n // Structural list: start a plain text block; the image\n // lands in the current item's content via flushBlock.\n if (listContainerStack.at(-1)) {\n const style =\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ?? 'normal'\n startBlock(style)\n } else {\n const listType = currentListStack.at(-1)\n\n if (listType) {\n ensureListBlock(listType)\n }\n }\n } else {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (style) {\n startBlock(style)\n }\n }\n }\n\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n inlineImageObject as PortableTextObject,\n )\n }\n break\n }\n\n // Neither block nor inline image supported, fall back to text\n addSpan(``)\n break\n }\n\n // Walk its children for text/marks/links\n for (const childToken of token.children ?? []) {\n switch (childToken.type) {\n case 'text':\n addSpan(childToken.content)\n break\n case 'softbreak':\n case 'hardbreak':\n addSpan('\\n')\n break\n case 'code_inline': {\n const decorator = consolidatedOptions.marks.code({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n // No code decorator defined, just add the content without marks\n addSpan(childToken.content)\n break\n }\n\n markDefRefs.push(decorator)\n addSpan(childToken.content)\n\n // code_inline is self-contained, so we need to pop the decorator\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'strong_open': {\n const decorator = consolidatedOptions.marks.strong({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n break\n }\n case 'strong_close': {\n const decorator = consolidatedOptions.marks.strong({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'em_open': {\n const decorator = consolidatedOptions.marks.em({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n\n break\n }\n case 'em_close': {\n const decorator = consolidatedOptions.marks.em({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 's_open': {\n const decorator = consolidatedOptions.marks.strikeThrough({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n\n break\n }\n case 's_close': {\n const decorator = consolidatedOptions.marks.strikeThrough({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'link_open': {\n const href = childToken.attrs\n ?.find(([name]) => name === 'href')\n ?.at(1)\n\n if (!href) {\n break\n }\n\n const title = childToken.attrs\n ?.find(([name]) => name === 'title')\n ?.at(1)\n\n const linkObject = consolidatedOptions.marks.link({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {href, title},\n })\n\n if (!linkObject) {\n break\n }\n\n currentMarkDefs.push(linkObject)\n markDefRefs.push(linkObject._key)\n break\n }\n case 'link_close': {\n // remove the last link key\n const markDefKeys = new Set(currentMarkDefs.map((d) => d._key))\n let lastLinkIndex: number | undefined\n\n for (const markDefRef of markDefRefs.reverse()) {\n if (markDefKeys.has(markDefRef)) {\n lastLinkIndex = markDefRefs.indexOf(markDefRef)\n break\n }\n }\n\n if (lastLinkIndex !== undefined) {\n const realIndex = markDefRefs.length - 1 - lastLinkIndex\n markDefRefs.splice(realIndex, 1)\n }\n break\n }\n case 'image': {\n const src =\n childToken.attrs?.find(([name]) => name === 'src')?.at(1) || ''\n const alt = unescapeImageAndLinkText(childToken.content || '')\n\n // Try to create an inline image first\n const inlineImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title: undefined},\n isInline: true,\n })\n\n if (inlineImageObject) {\n // Inline image is supported - add it to current block\n if (!currentBlock) {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n // At this point currentBlock should exist\n if (!currentBlock) {\n throw new Error('Expected current block after startBlock')\n }\n\n // Add the image as an inline object (TypeScript assertion needed for type narrowing)\n ;(currentBlock as PortableTextTextBlock).children.push(\n inlineImageObject as PortableTextObject,\n )\n break\n }\n\n // Inline image not supported - try block image as fallback\n const blockImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title: undefined},\n isInline: false,\n })\n\n if (!blockImageObject) {\n // Neither inline nor block image supported\n addSpan(``)\n break\n }\n\n // Block image supported - flush current block and add as block-level\n // Skip if we're in a table cell (images in cells are handled differently)\n if (inTableCell) {\n // In table cells, add the image to current block (will be extracted later)\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n blockImageObject as PortableTextObject,\n )\n }\n break\n }\n\n // Not in table - flush current block, add image as block, start new block\n flushBlock()\n pushBlock(blockImageObject)\n\n // Start a new block for any remaining content\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (style) {\n startBlock(style)\n }\n\n break\n }\n case 'html_inline': {\n // Handle inline HTML based on configuration\n if (consolidatedOptions.html.inline === 'text') {\n addSpan(childToken.content)\n }\n // 'skip' - do nothing, ignore the HTML\n break\n }\n default:\n // Ignore other inline token types by default\n break\n }\n }\n break\n }\n\n // Callouts (GFM alerts)\n case 'alert_open': {\n flushBlock()\n calloutStartTarget = blockTarget()\n calloutStartIndex = calloutStartTarget.length\n calloutType = token.markup\n\n // Set blockquote style so content blocks inside the callout\n // get blockquote styling (used in fallback when callout type\n // is not in the schema)\n const style =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n currentBlockquoteStyle = style ?? 'normal'\n break\n }\n\n case 'alert_title': {\n // Type is already captured via alert_open's markup\n break\n }\n\n case 'alert_close': {\n flushBlock()\n\n if (\n calloutStartIndex !== null &&\n calloutType !== null &&\n calloutStartTarget !== null\n ) {\n const contentBlocks = calloutStartTarget.splice(\n calloutStartIndex,\n ) as Array<PortableTextBlock>\n\n const calloutObject = consolidatedOptions.types.callout?.({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {tone: calloutType, content: contentBlocks},\n isInline: false,\n })\n\n if (calloutObject) {\n pushBlock(calloutObject)\n } else {\n for (const block of contentBlocks) {\n pushBlock(block)\n }\n }\n }\n\n calloutStartIndex = null\n calloutStartTarget = null\n calloutType = null\n currentBlockquoteStyle = null\n break\n }\n\n default:\n break\n }\n }\n\n flushBlock()\n\n return portableText\n}\n"],"mappings":";;;;AAAA,SAAgB,sBAAsB;CACpC,OAAO,UAAU,EAAE;AACrB;AAEA,MAAM,yBAAyB;CAC7B,IAAI;CACJ,aAAa;EACX,IAAI,OACF,OAAO;EAGT,QAAQ,CAAC;EACT,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,EAAE,GACzB,MAAM,MAAM,IAAI,IAAA,CAAO,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;EAE7C,OAAO;CACT;AACF,EAAA,CAAG;AAGH,SAAS,UAAU,SAAS,IAAI;CAC9B,IAAM,QAAQ,IAAI,WAAW,MAAM;CAEnC,OADA,OAAO,gBAAgB,KAAK,GACrB;AACT;AAEA,SAAS,UAAU,QAAyB;CAC1C,IAAM,QAAQ,gBAAgB;CAC9B,OAAO,UAAU,MAAM,CAAC,CACrB,QAAQ,KAAK,MAAM,MAAM,MAAM,IAAI,EAAE,CAAC,CACtC,MAAM,GAAG,MAAM;AACpB;ACtBA,MAAM,SAAS,cAAc,aAAa,CAAC,CAAC,CAAC;;;;;;;;;;;;;AAc7C,SAAgB,kBAGd,QACwE;CACxE,IAAM,iCAAiB,IAAI,IAAiC,GACtD,+BAAe,IAAI,IAAoB,GACvC,+BAAe,IAAI,IAAoB,GAGzC,aAA4B,CAAC;CAEjC,SAAS,QAAQ,OAAuB;EACtC,IAAI,UAAU,WAAW,GAAG,EAAE;EAE9B,OAAO,YAAY,KAAA,KAAa,UAAU,QAExC,AADA,WAAW,IAAI,GACf,UAAU,WAAW,GAAG,EAAE;EAO5B,OAJI,YAAY,SACd,WAAW,KAAK,KAAK,GAGhB,WAAW,SAAS;CAC7B;CAEA,IAAI;CAOJ,KAAK,IAAI,aAAa,GAAG,aAAa,OAAO,QAAQ,cAAc;EACjE,IAAM,QAAQ,OAAO,GAAG,UAAU;EAElC,IAAI,UAAU,KAAA,GACZ;EAQF,IALA,AACE,MAAM,SAAO,oBAAoB,GAI/B,CAAC,YAAY,EAAC,OAAM,GAAG,KAAK,GAAG;GAGjC,AAFA,eAAe,MAAM,GACrB,mBAAmB,KAAA,GACnB,aAAa,CAAC;GAEd;EACF;EAGA,IAAI,MAAM,aAAa,KAAA,KAAa,MAAM,UAAU,KAAA,GAAW;GAG7D,AAFA,eAAe,MAAM,GACrB,mBAAmB,KAAA,GACnB,aAAa,CAAC;GAEd;EACF;EAEA,IAAM,QAAQ,QAAQ,MAAM,KAAK;EAKjC,IAJA,aAAa,IAAI,MAAM,MAAM,KAAK,GAI9B,CAAC,kBAAkB;GACrB,IACM,gBACJ,eAAe,IAAI,MAAM,QAAQ,qBAAK,IAAI,IAAoB;GAMhE,AALA,cAAc,IAAI,OAAO,CAAS,GAClC,eAAe,IAAI,MAAM,UAAU,aAAa,GAEhD,aAAa,IAAI,MAAM,MAAM,CAAS,GAEtC,mBAAmB;IACjB,UAAU,MAAM;IAChB;GACF;GAEA;EACF;EAIA,IACE,iBAAiB,aAAa,MAAM,YACpC,iBAAiB,QAAQ,OACzB;GACA,IACM,gBACJ,eAAe,IAAI,MAAM,QAAQ,qBAAK,IAAI,IAAoB;GAMhE,AALA,cAAc,IAAI,OAAO,CAAS,GAClC,eAAe,IAAI,MAAM,UAAU,aAAa,GAEhD,aAAa,IAAI,MAAM,MAAM,CAAS,GAEtC,mBAAmB;IACjB,UAAU,MAAM;IAChB;GACF;GAEA;EACF;EAGA,eAAe,SAAS,eAAe,aAAa;GAClD,IAAI,aAAa,MAAM,UACrB;GAIF,IAAM,iBAA2B,CAAC;GAQlC,AANA,cAAc,SAAS,GAAG,kBAAkB;IAC1C,AAAI,iBAAiB,SACnB,eAAe,KAAK,aAAa;GAErC,CAAC,GAED,eAAe,SAAS,kBAAkB;IACxC,cAAc,OAAO,aAAa;GACpC,CAAC;EACH,CAAC;EAED,IAAM,gBACJ,eAAe,IAAI,MAAM,QAAQ,qBAAK,IAAI,IAAoB,GAC1D,eAAe,cAAc,IAAI,KAAK,KAAK;EAMjD,AALA,cAAc,IAAI,OAAO,eAAe,CAAC,GACzC,eAAe,IAAI,MAAM,UAAU,aAAa,GAEhD,aAAa,IAAI,MAAM,MAAM,eAAe,CAAC,GAE7C,mBAAmB;GACjB,UAAU,MAAM;GAChB;EACF;CACF;CAEA,OAAO;EAAC;EAAc;CAAY;AACpC;ACzIA,MAAa,oBACX,WACA,cACA,iBACe;CACf,SAAS,WAAkC,SAAkC;EAC3E,IAAM,EAAC,MAAM,OAAO,aAAY;EAkBhC,OAhBI,4BAA4B,IAAI,IAC3B,eAAe,MAAM,KAAK,IAG/B,0BAA0B,IAAI,IACzB,WAAW,IAAI,IAGpB,oBAAoB,IAAI,IACnB,YAAY,MAAM,OAAO,QAAQ,IAGtC,8BAA8B,IAAI,IAC7B,WAAW,IAAI,IAGjB,kBAAkB,MAAM,OAAO,QAAQ;CAChD;CAEA,SAAS,eACP,MAIA,OACQ;EACR,IAAM,WAAW,UAAU,UAGrB,eADJ,OAAO,YAAa,aAAa,WAAW,SAAS,KAAK,cAC7B,UAAU,iBAUrC,WAPS,eAAe,IACL,CAAC,CACrB,KAAK,OAAO,MACJ,WAAW;GAAC,MAAM;GAAO,UAAU;GAAM,OAAO;GAAG;EAAU,CAAC,CACtE,CAAC,CACD,KAAK,EAEiB;EAEzB,IAAI,KAAK,SAAS,KAAK,UAAU,UAAU;GAEzC,IAAM,EAAC,UAAU,WAAW,GAAG,cAAa;GAQ5C,AAPA,WAAW,WAAW;IACpB,MAAM;IACN;IACA,UAAU;IACV;GACF,CAAC,GAED,WAAW,SAAS,QAAQ,QAAQ,EAAE;EACxC;EAEA,OAAO,YAAY;GACjB,OAAO;GACP;GACA,WAAW,KAAK,OAAO,aAAa,IAAI,KAAK,IAAI,IAAI,KAAA;GACrD,WAAW,KAAK,OAAO,aAAa,IAAI,KAAK,IAAI,IAAI,KAAA;GACrD,UAAU;GACV;GACA;EACF,CAAC;CACH;CAEA,SAAS,WAAW,MAA6C;EAC/D,IAAM,EAAC,SAAS,UAAU,YAAW,MAC/B,OAAO,UAAU,MAAM,aAAa,UAAU,aAC9C,WAAW,KAAK,SAAS,KAAK,OAAO,eACzC,WAAW;GAAC,MAAM;GAAO,OAAO;GAAY,UAAU;GAAM;EAAU,CAAC,CACzE;EAEA,OAAO,KAAK;GACV,MAAM,gBAAgB,IAAI;GAC1B,OAAO;GACP;GACA;GACA;GACA,UAAU,SAAS,KAAK,EAAE;EAC5B,CAAC;CACH;CAEA,SAAS,YACP,MACA,OACA,UACQ;EACR,IAAM,EAAC,MAAM,GAAG,UAAS,eAAe;GAAC;GAAM;GAAO;GAAU;EAAU,CAAC,GACrE,QAAQ,MAAM,KAAK,SAAS;EAOlC,SALE,OAAO,UAAU,SAAU,aACvB,UAAU,QACV,UAAU,MAAM,WACG,UAAU,kBAAA,CAEtB;GAAC,GAAG;GAAO,OAAO,MAAM;GAAM;EAAU,CAAC;CACxD;CAEA,SAAS,WAAW,MAA+B;EAKjD,OAJI,KAAK,SAAS,OACT,UAAU,UAAU,IAGtB,KAAK;CACd;CAEA,SAAS,kBACP,OACA,OACA,UACQ;EAGR,QAFkB,UAAU,MAAM,MAAM,UAAU,UAAU,YAAA,CAE3C;GACf;GACA;GACA;GACA;EACF,CAAC;CACH;CAEA,OAAO;AACT;AAEA,SAAS,eACP,SACiB;CACjB,IAAM,EAAC,MAAM,OAAO,UAAU,eAAc,SAGtC,mBAFO,eAAe,IAEA,CAAC,CAAC,KAAK,OAAO,MACxC,WAAW;EAAC,MAAM;EAAO,UAAU;EAAM,OAAO;EAAG;CAAU,CAAC,CAChE;CAEA,OAAO;EACL,MAAM,KAAK,QAAQ,oBAAoB;EACvC,UAAU,iBAAiB,KAAK,EAAE;EAClC;EACA;EACA;CACF;AACF;;;;AChKA,MAAa,+BAAqD,EAChE,SACA,WAGE,4BAA4B,OAAO,KACnC,4BAA4B,IAAI,IAEzB,OAIP,oBAAoB,OAAO,KAC3B,oBAAoB,IAAI,KACxB,QAAQ,UAAU,gBAClB,KAAK,UAAU,eAER,UAGF,QClCI,iCAAyC,QCEzC,2BAAyD,EACpE,UACA,OACA,WACA,gBACI;CACJ,IAAM,YAAY,MAAM,YAAY,UAC9B,QAAQ,cAAc,MAAM,SAAS,KAAK,GAC1C,SAAS,MAAM,OAAO,KAAK;CAejC,OAbI,cAAc,WACT,GAAG,SAAS,aAAa,EAAE,IAAI,aAGpC,cAAc,SAMT,GAAG,OAAO,IAJf,aAAa,SAAS,OAAO,MAAM,WAAY,aAC3C,MAAM,UAEa,QAAQ,MACL,GAAG,aAG1B,GAAG,OAAO,IAAI;AACvB,GAKa,kCAAgE,EAC3E,eAEO,KAAK,SAAS;;;;AClCvB,SAAgB,uBAAuB,MAAsB;CAC3D,OAAO,KAAK,QAAQ,cAAc,MAAM;AAC1C;;;;AAKA,SAAgB,yBAAyB,MAAsB;CAC7D,OAAO,KAAK,QAAQ,8CAA8C,IAAI;AACxE;;;;AAKA,SAAgB,wBAAwB,MAAsB;CAC5D,OAAO,KAAK,QAAQ,YAAY,MAAM;AACxC;;;;;;;;;;;;;;;AAgBA,SAAgB,gBAAgB,MAAsB;CACpD,OAAO,KAAK,QAAQ,OAAA,gBAAA,GAAW,GAAG,KAAK,CAAC,CAAC,QAAQ,OAAO,MAAM;AAChE;;;;AC9BA,MAAa,qBAA+C,EAAC,eAC3D,IAAI,SAAS,IAKF,yBAAmD,EAAC,eAC/D,KAAK,SAAS,KAKH,uBAAiD,EAAC,eAC7D,KAAK,SAAS,KAKH,4BAAsD,EACjE,eACI,MAAM,SAAS,OAKR,gCAA0D,EACrE,eACI,KAAK,SAAS,KAWP,uBAA8D,EACzE,UACA,YACI;CACJ,IAAM,OAAO,OAAO,QAAQ,IACtB,QAAQ,OAAO,SAAS;CAG9B,IAFkB,aAAa,IAEnB,GAAG;EAKb,IAF2B,gCAAgC,KAAK,IAE3C,GAAG;GAEtB,IAAM,cAAc,KAAK,QAAQ,cAAc,SACtC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,YAAY,GACxD;GACD,OAAO,IAAI,uBAAuB,QAAQ,EAAE,IAAI,YAAY;EAC9D;EAGA,OAAO,IAAI,uBAAuB,QAAQ,EAAE,IAAI,OAAO,QAAQ,KAAK,wBAAwB,KAAK,EAAE,KAAK,GAAG;CAC7G;CAGA,OAAO;AACT;AAEA,SAAS,aAAa,KAAsB;CAC1C,IAAM,OAAO,OAAO,GAAA,CAAI,KAAK,GACvB,QAAQ,IAAI,OAAO,CAAC;CAE1B,IAAI,UAAU,OAAO,UAAU,KAC7B,OAAO;CAGT,IAAM,aAAa,IAAI,QAAQ,GAAG;CAClC,IAAI,eAAe,IACjB,OAAO;CAGT,IAAM,mBAAmB;EAAC;EAAQ;EAAS;EAAU;CAAK,GACpD,QAAQ,IAAI,MAAM,GAAG,UAAU,CAAC,CAAC,YAAY;CACnD,IAAI,iBAAiB,QAAQ,KAAK,MAAM,IACtC,OAAO;CAGT,IAAM,aAAa,IAAI,QAAQ,GAAG;CAClC,IAAI,eAAe,MAAM,aAAa,YACpC,OAAO;CAGT,IAAM,YAAY,IAAI,QAAQ,GAAG;CAKjC,OAJI,cAAc,MAAM,aAAa;AAKvC;;;;AAKA,MAAa,8BAAwD,EACnE,eAEO,UCxGI,yBAAoD,EAC/D,eAGI,CAAC,YAAY,SAAS,KAAK,MAAM,KAC5B,KAGF,UAMI,6BAAwD,EACnE,eAIK,WAIE,SACJ,MAAM,IAAI,CAAC,CACX,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,KAAK,IAAI,IANH,KAYE,qBAAgD,EAAC,eAC5D,KAAK,YAKM,qBAAgD,EAAC,eAC5D,MAAM,YAKK,qBAAgD,EAAC,eAC5D,OAAO,YAKI,qBAAgD,EAAC,eAC5D,QAAQ,YAKG,qBAAgD,EAAC,eAC5D,SAAS,YAKE,qBAAgD,EAAC,eAC5D,UAAU,YAKC,+BAA0D,EACrE,eAEO,YAAY,ICnER,4BAIP,YACC,aAAa,QAAQ,KAAK,IAGxB,SAAS,kBAAkB,QAAQ,MAAM,QAAQ,EAAE,IAAI,QAAQ,MAAM,KAAK,YAFxE,2BAA2B,OAAO;AAK7C,SAAS,aAAa,OAAyC;CAC7D,OAAO,OAAQ,OAAmC,QAAS;AAC7D;;;;;;;;AASA,SAAS,kBAAkB,UAA2B;CAIpD,OAHI,OAAO,YAAa,YAAY,SAAS,SAAS,IAAI,IACjD,KAEF;AACT;;;;AAKA,MAAa,sCACJ,OAMI,uBAGP,YACC,aAAa,QAAQ,KAAK,IAGxB,QAAQ,MAAM,OAFZ,2BAA2B,OAAO;AAK7C,SAAS,aAAa,OAAyC;CAC7D,OAAO,OAAQ,OAAmC,QAAS;AAC7D;;;;AAKA,MAAa,wBAKP,YAAY;CAChB,IAAI,CAAC,cAAc,QAAQ,KAAK,GAC9B,OAAO,2BAA2B,OAAO;CAE3C,IAAM,MAAM,uBAAuB,QAAQ,MAAM,OAAO,EAAE,GACpD,QAAQ,QAAQ,MAAM,QACxB,KAAK,wBAAwB,QAAQ,MAAM,KAAK,EAAE,KAClD;CACJ,OAAO,KAAK,IAAI,IAAI,QAAQ,MAAM,MAAM,MAAM;AAChD;AAEA,SAAS,cAAc,OAIrB;CACA,IAAM,QAAQ;CACd,OACE,OAAO,OAAO,OAAQ,aAGrB,MAAM,OAAO,QAAQ,OAAO,MAAM,OAAQ,cAC1C,MAAM,SAAS,QAAQ,OAAO,MAAM,SAAU;AAEnD;;;;;;;;;;AAWA,SAAS,cAAc,OAAsC;CAC3D,IAAM,OAAQ,OAAmC;CACjD,OACE,MAAM,QAAQ,IAAI,KAClB,KAAK,OACF,QACC,cAAc,GAAG,KACjB,MAAM,QAAQ,IAAI,KAAQ,KAC1B,IAAI,MAAS,OACV,SACC,cAAc,IAAI,KAClB,MAAM,QAAQ,KAAK,KAAQ,KAC3B,KAAK,MAAS,MAAM,aAAa,CACrC,CACJ;AAEJ;;;;;;;;;;;;;;;;;;AAyBA,MAAa,wBAWP,YAAY;CAChB,IAAM,EAAC,OAAO,eAAc;CAM5B,OAJK,cAAc,KAAK,IAIjB,YAAY,OAAO,UAAU,IAH3B,2BAA2B,OAAO;AAI7C;AAEA,SAAS,YACP,OACA,YACQ;CACR,IAAM,OAAO,MAAM,MAIb,YAAgD,MAAM,QAC1D,MAAM,SACR,IACI,MAAM,YACN,KAAA,GAEE,YAAY,KAAK,GAAG,CAAC;CAE3B,IAAI,CAAC,WACH,OAAO;CAIT,IAAM,eAAe,eACZ,WACJ,KAAK,OAAO,UACX,WAAW;EACT,MAAM;EACN;EACA,UAAU;EACV;CACF,CAAC,CACH,CAAC,CACA,KAAK,GAAG,CAAC,CACT,KAAK,GAGJ,QAAkB,CAAC,GAMnB,cAAc,KAAK,QACtB,KAAK,QAAQ,KAAK,IAAI,KAAK,IAAI,MAAM,MAAM,GAC5C,CACF,GAEM,eAAe,UAAiC;EACpD,IAAM,SAAS,CAAC,GAAG,KAAK;EACxB,OAAO,OAAO,SAAS,cACrB,OAAO,KAAK,EAAE;EAEhB,OAAO,KAAK,OAAO,KAAK,KAAK,EAAE;CACjC,GAEM,aAAa,UACjB,YAAY,MAAM,KAAK,SAAS,gBAAgB,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,GAiBrE,YAAY,IAbC,MAAM,KAAK,EAAC,QAAQ,YAAW,IAAI,GAAG,UAAU;EACjE,IAAM,QAAQ,WAAW,GAAG,KAAK;EAUjC,OATI,UAAU,SACL,WAEL,UAAU,WACL,YAEL,UAAU,UACL,WAEF;CACT,CAC+B,CAAC,CAAC,KAAK,GAAG,EAAE;CAI3C,KAFmB,OAAO,MAAM,UAAU,KAAK,MAAM,GAU9C;EAIL,AADA,MAAM,KAAK,UAAU,UAAU,KAAK,CAAC,GACrC,MAAM,KAAK,SAAS;EACpB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,IAAM,MAAM,KAAK,GAAG,CAAC;GACrB,AAAI,OACF,MAAM,KAAK,UAAU,IAAI,KAAK,CAAC;EAEnC;CACF,OAnBgB;EAId,AADA,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC,GAC1B,MAAM,KAAK,SAAS;EACpB,KAAK,IAAM,OAAO,MAChB,MAAM,KAAK,UAAU,IAAI,KAAK,CAAC;CAEnC;CAaA,OAAO,MAAM,KAAK,IAAI;AACxB;;;;AAKA,MAAa,0BAIP,YAAY;CAChB,IAAI,CAAC,gBAAgB,QAAQ,KAAK,GAChC,OAAO,2BAA2B,OAAO;CAE3C,IAAM,EAAC,eAAc,SAYf,WAXkB,QAAQ,MAAM,QACnC,KAAK,OAAO,UACX,WAAW;EACT,MAAM,MAAM,UAAU,UAAU;GAAC,GAAG;GAAO,OAAO;EAAQ,IAAI;EAC9D;EACA,UAAU;EACV;CACF,CAAC,CACH,CAAC,CACA,KAAK,MAEuB,CAAC,CAC7B,MAAM,IAAI,CAAC,CACX,KAAK,SAAU,SAAS,KAAK,MAAM,KAAK,MAAO,CAAC,CAChD,KAAK,IAAI;CAEZ,OAAO,OAAO,QAAQ,MAAM,KAAK,YAAY,EAAE,KAAK;AACtD;AAEA,SAAS,gBACP,OACsD;CACtD,IAAM,UAAU;CAChB,OACE,OAAO,SAAS,QAAS,YACzB,MAAM,QAAQ,QAAQ,OAAO,KAC7B,QAAQ,QAAQ,MAAM,aAAa;AAEvC;;;;;;;;;;;;;AAcA,MAAa,mCAGP,EAAC,OAAO,iBACY,MAAM,QAC3B,KAAK,OAAO,UACX,WAAW;CACT,MAAM,MAAM,UAAU,UAAU;EAAC,GAAG;EAAO,OAAO;CAAQ,IAAI;CAC9D;CACA,UAAU;CACV;AACF,CAAC,CACH,CAAC,CACA,KAAK,MAEa,CAAC,CACnB,MAAM,IAAI,CAAC,CACX,KAAK,SAAU,SAAS,KAAK,MAAM,KAAK,MAAO,CAAC,CAChD,KAAK,IAAI,GAaD,uBASP,EAAC,OAAO,iBAAgB;CAa5B,IAAM,gBANU,MAAM,MAAM,MAAM,SACR,KAAK,QAAQ,QAClC,UAAW,MAAsB,UAAU,MAEzB,CAAC,CAAC,SAAS,CAEN,IAAI,SAAS;CA4CzC,OA1Cc,MAAM,MAAM,KAAK,MAAM,cAAc;EACjD,IAAM,SAAS,cAAc,MAAM,MAAM,WAAW,KAAK,OAAO,GAM1D,cAAc,MAAM,SAAS,SAAS,IAAI,OAAO,QACjD,SAAS,IAAI,OAAO,WAAW,GAY/B,CAAC,OAAO,GAAG,QAVM,KAAK,QAAQ,KAAK,OAAO,gBAAgB;GAC9D,cAAe,MAAsB,UAAU;GAC/C,MAAM,WAAW;IACf,MAAM;IACN,OAAO;IACP,UAAU;IACV;GACF,CAAC;EACH,EAEsC,GAEhC,OAAO,GAAG,SAAS,OAAO,QAAQ,KAAK,QAAQ;EAiBrD,OAhBI,KAAK,WAAW,IACX,OAeF,GAAG,OAZG,KACV,KAAK,aAAa;GACjB,IAAM,WAAW,SAAS,KACvB,MAAM,IAAI,CAAC,CACX,KAAK,SAAU,SAAS,KAAK,KAAK,GAAG,SAAS,MAAO,CAAC,CACtD,KAAK,IAAI;GAGZ,OAAO,SAAS,eAAe,KAAK,aAAa,OAAO;EAC1D,CAAC,CAAC,CACD,KAAK,EAEY;CACtB,CAEW,CAAC,CAAC,KAAK,aAAa;AACjC;AAEA,SAAS,cACP,MACA,WACA,SACQ;CAOR,OANI,SAAS,WACJ,GAAG,YAAY,EAAE,MAEtB,SAAS,SACJ,UAAU,WAAW,WAEvB;AACT;;;;AAKA,MAAa,8BAAwD,EACnE,OACA,eACI;CACJ,IAAM,OAAO,eAAe,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE;CAE3D,OAAO,WAAW,KAAK,KAAK,MAAM;AACpC,GCjZM,mBAA0C;CAC9C,OAAO;EACL,SAAW;EACX,MAAQ;EACR,mBAAmB;EACnB,MAAQ;EACR,OAAS;EACT,OAAS;CACX;CAEA,OAAO;EACL,QAAQ;EACR,YAAY;EACZ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,OAAO;EACL,IAAM;EACN,QAAU;EACV,MAAQ;EACR,WAAa;EACb,kBAAkB;EAClB,MAAQ;CACV;CACA,UAAU;CACV,WAAW;CAEX,aAAa;CACb,aAAa;CACb,iBAAiB;CACjB,mBAAmB;AACrB;;;;AASA,SAAgB,uBAEd,QAAsB,UAAmB,CAAC,GAAW;CACrD,IAAM,YAAY;EAChB,OAAO;GACL,GAAG,iBAAiB;GACpB,GAAG,QAAQ;EACb;EACA,UAAU,QAAQ,YAAY,iBAAiB;EAC/C,OAAO;GACL,GAAG,iBAAiB;GACpB,GAAG,QAAQ;EACb;EACA,OAAO;GACL,GAAG,iBAAiB;GACpB,GAAG,QAAQ;EACb;EACA,WAAW,QAAQ,aAAa,iBAAiB;EACjD,aAAa,QAAQ,eAAe,iBAAiB;EACrD,mBACE,QAAQ,qBAAqB,iBAAiB;EAChD,iBACE,QAAQ,mBAAmB,iBAAiB;EAC9C,aAAa,QAAQ,eAAe,iBAAiB;CACvD,GACM,qBAAqB,QAAQ,gBAAgB,6BAE7C,EAAC,cAAc,iBAAgB,kBAAkB,MAAM,GACvD,aAAa,iBAAiB,WAAW,cAAc,YAAY;CAEzE,OAAO,OACJ,KAAK,MAAM,UAAU;EACpB,IAAM,eAAe,WAAW;GAC9B;GACA;GACA,UAAU;GACV;EACF,CAAC;EAED,IAAI,UAAU,OAAO,SAAS,GAC5B,OAAO;EAGT,IAAM,WAAW,OAAO,GAAG,QAAQ,CAAC;EAYpC,OAVK,WAUE,GAAG,eALR,mBAAmB;GACjB,SAAS;GACT,MAAM;EACR,CAAC,KAAK,WAPC;CAUX,CAAC,CAAC,CACD,KAAK,EAAE;AACZ;;;;ACvIA,MAAa,wBAAwB,EACnC,MAAM,SACR,GAEa,oBAAoB,EAC/B,MAAM,KACR,GAEa,oBAAoB,EAC/B,MAAM,KACR,GAEa,oBAAoB,EAC/B,MAAM,KACR,GAEa,oBAAoB,EAC/B,MAAM,KACR,GAEa,oBAAoB,EAC/B,MAAM,KACR,GAEa,oBAAoB,EAC/B,MAAM,KACR,GAEa,4BAA4B,EACvC,MAAM,aACR,GAMa,mCAAmC,EAC9C,MAAM,SACR,GAEa,qCAAqC,EAChD,MAAM,SACR,GAEa,gCAAgC,EAC3C,MAAM,OACR,GAMa,mCAAmC,EAC9C,MAAM,SACR,GAEa,+BAA+B,EAC1C,MAAM,KACR,GAEa,iCAAiC,EAC5C,MAAM,OACR,GAEa,0CAA0C,EACrD,MAAM,iBACR,GAMa,8BAA8B;CACzC,MAAM;CACN,QAAQ,CACN;EAAC,MAAM;EAAQ,MAAM;CAAQ,GAC7B;EAAC,MAAM;EAAS,MAAM;CAAQ,CAChC;AACF,GAMa,8BAA8B;CACzC,MAAM;CACN,QAAQ,CACN;EAAC,MAAM;EAAY,MAAM;CAAQ,GACjC;EAAC,MAAM;EAAQ,MAAM;CAAQ,CAC/B;AACF,GAEa,+BAA+B;CAC1C,MAAM;CACN,QAAQ;EACN;GAAC,MAAM;GAAO,MAAM;EAAQ;EAC5B;GAAC,MAAM;GAAO,MAAM;EAAQ;EAC5B;GAAC,MAAM;GAAS,MAAM;EAAQ;CAChC;AACF,GAEa,wCAAwC,EACnD,MAAM,kBACR,GAEa,8BAA8B;CACzC,MAAM;CACN,QAAQ,CAAC;EAAC,MAAM;EAAQ,MAAM;CAAQ,CAAC;AACzC,GAUa,+BAA+B;CAC1C,MAAM;CACN,QAAQ;EACN;GAAC,MAAM;GAAc,MAAM;EAAQ;EACnC;GAAC,MAAM;GAAa,MAAM;EAAO;EACjC;GACE,MAAM;GACN,MAAM;GACN,IAAI,CACF;IACE,MAAM;IACN,MAAM;IACN,QAAQ,CACN;KACE,MAAM;KACN,MAAM;KACN,IAAI,CACF;MACE,MAAM;MACN,MAAM;MACN,QAAQ,CACN;OACE,MAAM;OACN,MAAM;OACN,IAAI,CAAC,EAAC,MAAM,QAAO,GAAG,EAAC,MAAM,QAAO,CAAC;MACvC,CACF;KACF,CACF;IACF,CACF;GACF,CACF;EACF;CACF;AACF,GAEa,iCAAiC;CAC5C,MAAM;CACN,QAAQ,CACN;EAAC,MAAM;EAAQ,MAAM;CAAQ,GAC7B;EAAC,MAAM;EAAW,MAAM;CAAO,CACjC;AACF,GAOa,gBAAgB,cAC3B,aAAa;CACX,OAAO,EACL,QAAQ,CAAC;EAAC,MAAM;EAAW,MAAM;CAAS,CAAC,EAC7C;CACA,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,OAAO;EACL;EACA;EACA;CACF;CACA,YAAY;EACV;EACA;EACA;EACA;CACF;CACA,aAAa,CAAC,2BAA2B;CACzC,cAAc;EACZ;EACA;EACA;EACA;EACA;EACA;CACF;CACA,eAAe,CAAC,4BAA4B;AAC9C,CAAC,CACH;AC1MA,SAAgB,kBACd,YACc;CACd,QAAQ,EAAC,cAAa;EACpB,IAAM,mBAAmB,QAAQ,OAAO,OAAO,MAC5C,SAAS,KAAK,SAAS,WAAW,IACrC;EAEK,sBAIL,OAAO,iBAAiB;CAC1B;AACF;AAaA,SAAgB,qBACd,YACiB;CACjB,QAAQ,EAAC,cAAa;EACpB,IAAM,mBAAmB,QAAQ,OAAO,MAAM,MAC3C,SAAS,KAAK,SAAS,WAAW,IACrC;EAEK,sBAIL,OAAO,iBAAiB;CAC1B;AACF;AAaA,SAAgB,sBACd,YACkB;CAClB,QAAQ,EAAC,cAAa;EACpB,IAAM,mBAAmB,QAAQ,OAAO,WAAW,MAChD,SAAS,KAAK,SAAS,WAAW,IACrC;EAEK,sBAIL,OAAO,iBAAiB;CAC1B;AACF;AAiBA,SAAgB,uBACd,YAC8C;CAC9C,QAAQ,EAAC,SAAS,YAAW;EAC3B,IAAM,mBAAmB,QAAQ,OAAO,YAAY,MACjD,SAAS,KAAK,SAAS,WAAW,IACrC;EAEA,IAAI,CAAC,kBACH;EAGF,IAAM,gBAAgB,iBAAiB,OAAO,QAE3C,eAAe,UAAU;GAC1B,IAAM,aAAa,MAAM,MAAM;GAM/B,OAJI,eAAe,KAAA,MACjB,cAAc,MAAM,QAAQ,aAGvB;EACT,GAAG,CAAC,CAAC;EAEL,OAAO;GACL,MAAM,QAAQ,aAAa;GAC3B,OAAO,iBAAiB;GACxB,GAAG;EACL;CACF;AACF;AAmBA,SAAgB,mBACd,YAC0C;CAC1C,QAAQ,EAAC,SAAS,OAAO,eAAc;EAKrC,IAAM,oBAJmB,WACrB,QAAQ,OAAO,gBACf,QAAQ,OAAO,aAAA,CAEuB,MACvC,SAAS,KAAK,SAAS,WAAW,IACrC;EAEA,IAAI,CAAC,kBACH;EAGF,IAAM,gBAAgB,iBAAiB,OAAO,QAE3C,eAAe,UAAU;GAC1B,IAAM,aAAa,MAAM,MAAM;GAM/B,OAJI,eAAe,KAAA,MACjB,cAAc,MAAM,QAAQ,aAGvB;EACT,GAAG,CAAC,CAAC;EAEL,OAAO;GACL,MAAM,QAAQ,aAAa;GAC3B,OAAO,iBAAiB;GACxB,GAAG;EACL;CACF;AACF;ACnEA,MAAM,oBAED,EAAC,SAAS,OAAO,eAAc;CAElC,IAAM,aADiB,mBAAmB,2BACV,CAAC,CAAC;EAAC;EAAS;EAAO;CAAQ,CAAC;CAEvD,kBAIC,UAAU,YAIhB,OAAO;AACT,GAEM,qBAED,EAAC,SAAS,OAAO,eAAc;CAElC,IAAM,cADiB,mBAAmB,4BACT,CAAC,CAAC;EAAC;EAAS;EAAO;CAAQ,CAAC;CAExD,mBAIC,SAAS,aAIf,OAAO;AACT,GAEM,qBAED,EAAC,SAAS,OAAO,eAAc;CAElC,IAAM,cADiB,mBAAmB,4BACT,CAAC,CAAC;EAAC;EAAS;EAAO;CAAQ,CAAC;CAExD,mBAIC,UAAU,aAIhB,OAAO;AACT,GAEM,iBAAiB;CACrB,QAAQ;CACR,cAAc;CACd,MAAM,EACJ,QAAQ,OACV;CACA,OAAO;EACL,QAAQ,kBAAkB,qBAAqB;EAC/C,YAAY,kBAAkB,yBAAyB;EACvD,IAAI,kBAAkB,iBAAiB;EACvC,IAAI,kBAAkB,iBAAiB;EACvC,IAAI,kBAAkB,iBAAiB;EACvC,IAAI,kBAAkB,iBAAiB;EACvC,IAAI,kBAAkB,iBAAiB;EACvC,IAAI,kBAAkB,iBAAiB;CACzC;CACA,UAAU;EACR,QAAQ,qBAAqB,gCAAgC;EAC7D,QAAQ,qBAAqB,kCAAkC;EAC/D,MAAM,qBAAqB,6BAA6B;CAC1D;CACA,OAAO;EACL,QAAQ,sBAAsB,gCAAgC;EAC9D,IAAI,sBAAsB,4BAA4B;EACtD,MAAM,sBAAsB,8BAA8B;EAC1D,eAAe,sBACb,uCACF;EACA,MAAM,uBAAuB,2BAA2B;CAC1D;CACA,OAAO;EACL,MAAM;EACN,gBAAgB,mBAAmB,qCAAqC;EACxE,MAAM,mBAAmB,2BAA2B;EACpD,OAAO;EACP,SAAS,mBAAmB,8BAA8B;EAC1D,OAAO;CACT;AACF;;;;;AAMA,SAAgB,8BACd,WACoC;CACpC,IAAI,CAAC,WACH,OAAO;CAET,IAAM,QAAQ,UAAU,MAAM,sCAAsC;CAIpE,OAHK,QAGE,MAAM,KAFJ;AAGX;;;;;;;;AASA,SAAS,gBACP,OACA,SACS;CACT,OAAO,MAAM,OAAO,SAClB,KAAK,MAAM,OACR,UACC,YAAY,SAAS,KAAK,KAC1B,MAAM,SAAS,OACZ,UAAU,OAAO,SAAS,KAAK,MAAM,MAAM,QAAQ,GAAA,CAAI,KAAK,MAAM,EACrE,CACJ,CACF;AACF;;;;AAKA,SAAS,aACP,OAYA,cACM;CAEN,KAAK,IAAM,OAAO,MAAM,MACtB,KAAK,IAAM,QAAQ,IAAI,OACrB,KAAK,IAAM,SAAS,KAAK,OACvB,aAAa,KAAK,KAAK;AAI/B;;;;;;AAOA,SAAgB,uBACd,UACA,SAC0B;CAC1B,IAAM,sBAAsB;EAC1B,QAAQ,SAAS,UAAU;EAC3B,cAAc,SAAS,gBAAgB;EACvC,MAAM,EACJ,QAAQ,SAAS,MAAM,UAAU,OACnC;EACA,OAAO;GACL,GAAG,eAAe;GAClB,GAAG,SAAS;EACd;EACA,OAAO;GACL,GAAG,eAAe;GAClB,GAAG,SAAS;EACd;EACA,UAAU;GACR,GAAG,eAAe;GAClB,GAAG,SAAS;EACd;EACA,OAAO;GACL,GAAG,eAAe;GAClB,GAAG,SAAS;EACd;CACF,GAUM,SARK,WAAW;EACpB,MAAM;EACN,SAAS;EACT,aAAa;CACf,CAAC,CAAC,CACC,OAAO,CAAC,iBAAiB,OAAO,CAAC,CAAC,CAClC,IAAI,KAES,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,GAO9B,6CAA6B,IAAI,IAAqB;CAC5D,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EAEtC,IADc,OAAO,EACZ,EAAE,SAAS,kBAClB;EAGF,IAAI,cAAc;EAClB,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;GAC1C,IAAM,YAAY,OAAO;GACpB,eAGL;QAAI,UAAU,SAAS,mBACrB;IAEF,IAAI,UAAU,SAAS,UAAU;KAC/B,cAAc;KACd;IACF;GALE;EAMJ;EACA,IAAI,gBAAgB,IAClB;EAEF,IAAM,cAAc,OAAO;EAC3B,IAAI,CAAC,aACH;EAEF,IAAM,QAAQ,YAAY,QAAQ,MAAM,eAAe;EACvD,IAAI,CAAC,OACH;EAEF,IAAM,UAAU,MAAM,OAAO;EAI7B,AAHA,2BAA2B,IAAI,GAAG,OAAO,GAGzC,YAAY,UAAU,YAAY,QAAQ,MAAM,MAAM,EAAE,CAAC,MAAM;EAC/D,IAAM,aAAa,YAAY,WAAW;EAC1C,AAAI,cAAc,OAAO,WAAW,WAAY,aAC9C,WAAW,UAAU,WAAW,QAAQ,MAAM,MAAM,EAAE,CAAC,MAAM;CAEjE;CAEA,IAAM,eAAyC,CAAC,GAG5C,eAA6C,MAC3C,mBAAyC,CAAC,GAC1C,cAA6B,CAAC,GAChC,kBAA6C,CAAC,GAC9C,yBAAwC,MACxC,aAAa,IAGb,oBAAmC,MACnC,qBACF,MACE,cAA6B,MAQ3B,kBAGD,CAAC,GAGF,eAaO,MACP,kBAIQ,MACR,cAAc,IAuBZ,qBAAuD,CAAC,GAOxD,oBAAmE;EACvE,KAAK,IAAI,IAAI,mBAAmB,SAAS,GAAG,KAAK,GAAG,KAAK;GACvD,IAAM,QAAQ,mBAAmB;GACjC,IAAI,SAAS,MAAM,aACjB,OAAO,MAAM,YAAY;EAE7B;EACA,OAAO;CACT,GAQM,aAAa,UAAwD;EACzE,YAAY,CAAC,CAAC,KAAK,KAA0B;CAC/C,GAEM,cAAc,UAAkB;EASpC,AARA,WAAW,GACX,eAAe;GACb,OAAO;GACP;GACA,UAAU,CAAC;GACX,MAAM,oBAAoB,aAAa;GACvC,UAAU,CAAC;EACb,GACA,kBAAkB,CAAC;CACrB,GAEM,mBAAmB;EAClB,iBAKD,aAAa,SAAS,WAAW,KACnC,aAAa,SAAS,KAAK;GACzB,OAAO,oBAAoB,OAAO,KAAK;GACvC,MAAM,oBAAoB,aAAa;GACvC,MAAM;GACN,OAAO,CAAC;EACV,CAAC,GAIH,aAAa,WAAW,iBAExB,UAAU,YAAY,GAEtB,eAAe,MACf,kBAAkB,CAAC;CACrB,GAEM,WAAW,SAAiB;EAChC,IAAI,KAAK,WAAW,GAClB;EAGF,IAAI,CAAC,cAAc;GACjB,IAAM,QACJ,0BACA,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;GAEH,AAAK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ;EAIvB;EAEA,IAAI,CAAC,cACH,MAAU,MAAM,wBAAwB;EAG1C,IAAM,YAAY,aAAa,SAAS,GAAG,EAAE;EAE7C,AACE,OAAO,EAAC,QAAQ,oBAAoB,OAAM,GAAG,SAAS,KACtD,UAAU,OAAO,OAAO,SAAS,YAAY,SAAS,IAAI,CAAC,KAC3D,YAAY,OAAO,SAAS,UAAU,OAAO,SAAS,IAAI,CAAC,IAG3D,UAAU,QAAQ,OAElB,aAAa,SAAS,KAAK;GACzB,OAAO,oBAAoB,OAAO,KAAK;GACvC,MAAM,oBAAoB,aAAa;GACjC;GACN,OAAO,CAAC,GAAG,WAAW;EACxB,CAAC;CAEL,GAGM,kBAAkB,iBAAiB,QACnC,mBAAmB,UAAkB,YAAsB;EAC/D,IAAI,CAAC,cAAc;GAEjB,IAAM,QACJ,0BACA,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;GAEH,AAAK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ;EAIvB;EAEA,IAAI,CAAC,cACH,MAAU,MAAM,wBAAwB;EAW1C,CAPE,aAAa,aAAa,YAC1B,aAAa,UAAU,UAAU,OAEjC,aAAa,WAAW,UACxB,aAAa,QAAQ,UAAU,IAG7B,YAAY,KAAA,MACb,aAA8D,UAC7D;CAEN;CAGA,KAAK,IAAI,aAAa,GAAG,aAAa,OAAO,QAAQ,cAAc;EACjE,IAAM,QAAQ,OAAO;EAChB,WAIL,QAAQ,MAAM,MAAd;GAEE,KAAK,kBAAkB;IAGrB,IAAI,YAAY;KAGd,IAAI,mBAAmB,GAAG,EAAE,GAAG;MAC7B,AAAK,gBAQH,WALE,0BACA,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KACD,QACc;MAElB;KACF;KAIA,IAAI,CAAC,cAAc;MACjB,IAAM,WAAW,iBAAiB,GAAG,EAAE;MAEvC,AAAI,YACF,gBAAgB,QAAQ;KAE5B;KAEA;IACF;IAGA,IAAM,QACJ,0BACA,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;IAEH,IAAI,CAAC,OAAO;KAEV,AADA,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ;KACnB;IACF;IAEA,WAAW,KAAK;IAChB;GACF;GACA,KAAK;IAIH,IAAI,YAAY;KACd,AAAI,mBAAmB,GAAG,EAAE,KAC1B,WAAW;KAEb;IACF;IACA,WAAW;IACX;GAGF,KAAK,gBAAgB;IACnB,IAAM,QAAQ,OAAO,OAAO,KAAK,MAAM,CAAC,CAAC,GAYnC,iBACJ;KATA,GAAG,oBAAoB,MAAM;KAC7B,GAAG,oBAAoB,MAAM;KAC7B,GAAG,oBAAoB,MAAM;KAC7B,GAAG,oBAAoB,MAAM;KAC7B,GAAG,oBAAoB,MAAM;KAC7B,GAAG,oBAAoB,MAAM;IAIf,EAAE,QAEZ,QACJ,iBAAiB,EACf,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KACD,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;IAEH,IAAI,CAAC,OAAO;KAEV,AADA,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ;KACnB;IACF;IAEA,WAAW,KAAK;IAChB;GACF;GACA,KAAK;IACH,WAAW;IACX;GAGF,KAAK;IAUH,IARA,WAAW,GAQP,oBAAoB,MAAM,YAAY;KACxC,IAAM,cAAc,YAAY;KAChC,gBAAgB,KAAK;MACnB;MACA,YAAY,YAAY;KAC1B,CAAC;KACD;IACF;IAYA,yBAPE,oBAAoB,MAAM,WAAW,EACnC,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KACD,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KAE+B;IAClC;GAEF,KAAK;IAQH,IANA,WAAW,GAOT,oBAAoB,MAAM,cAC1B,gBAAgB,SAAS,GACzB;KACA,IAAM,QAAQ,gBAAgB,IAAI;KAClC,IAAI,OAAO;MACT,IAAM,gBAAgB,MAAM,YAAY,OACtC,MAAM,UACR,GAEM,mBAAmB,oBAAoB,MAAM,WAAW;OAC5D,SAAS;QACP,QAAQ,oBAAoB;QAC5B,cAAc,oBAAoB;OACpC;OACA,OAAO,EAAC,SAAS,cAAa;OAC9B,UAAU;MACZ,CAAC;MAED,IAAI,kBACF,UAAU,gBAAgB;WACrB;OAGL,IAAM,kBACJ,oBAAoB,MAAM,WAAW,EACnC,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KACD,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KACD;OACF,KAAK,IAAM,SAAS,eAClB,AAAI,MAAM,UAAU,UAClB,UAAU;QACR,GAAI;QACJ,OAAO;OACT,CAAC,IAED,UAAU,KAAK;MAGrB;KACF;KACA;IACF;IAEA,yBAAyB;IACzB;GAGF,KAAK,oBAAoB;IAQvB,IAPA,WAAW,GAOP,oBAAoB,MAAM,MAAM;KAMlC,AALA,mBAAmB,KAAK;MACtB,MAAM;MACN,OAAO,CAAC;MACR,aAAa;KACf,CAAC,GACD,iBAAiB,KAAK,IAAI;KAC1B;IACF;IAIA,IAAM,WAAW,oBAAoB,SAAS,OAAO,EACnD,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;IAGD,IADA,mBAAmB,KAAK,IAAI,GACxB,CAAC,UAAU;KACb,iBAAiB,KAAK,IAAI;KAC1B;IACF;IACA,iBAAiB,KAAK,QAAQ;IAC9B;GACF;GACA,KAAK,qBAAqB;IAGxB,IAFA,WAAW,GAEP,oBAAoB,MAAM,MAAM;KAMlC,AALA,mBAAmB,KAAK;MACtB,MAAM;MACN,OAAO,CAAC;MACR,aAAa;KACf,CAAC,GACD,iBAAiB,KAAK,IAAI;KAC1B;IACF;IAEA,IAAM,WAAW,oBAAoB,SAAS,OAAO,EACnD,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;IAGD,IADA,mBAAmB,KAAK,IAAI,GACxB,CAAC,UAAU;KACb,iBAAiB,KAAK,IAAI;KAC1B;IACF;IACA,iBAAiB,KAAK,QAAQ;IAC9B;GACF;GACA,KAAK;GACL,KAAK,sBAAsB;IACzB,IAAM,QAAQ,mBAAmB,IAAI;IAMrC,IALA,iBAAiB,IAAI,GAKjB,SAAS,oBAAoB,MAAM,MAAM;KAE3C,IAAM,OAAqC,MAAM,MAAM,MACpD,SAAS,aAAa,IACzB,IACI,SACA,MAAM,MAEJ,aAAa,oBAAoB,MAAM,KAAK;MAChD,SAAS;OACP,QAAQ,oBAAoB;OAC5B,cAAc,oBAAoB;MACpC;MACA,OAAO;OAAC;OAAM,OAAO,MAAM;MAAK;MAChC,UAAU;KACZ,CAAC;KAED,IAAI,YACF,UAAU,UAAU;UACf;MAQL,IAAM,gBACH,SAAS,SACN,oBAAoB,SAAS,OAAO,EAClC,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,IACD,SAAS,WACP,oBAAoB,SAAS,OAAO,EAClC,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,IACD,oBAAoB,SAAS,OAAO,EAClC,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,MAAM,MAGT,QAAQ,mBAAmB,SAAS;MAC1C,KAAK,IAAM,QAAQ,MAAM,OACvB,KAAK,IAAM,SAAS,KAAK,SACvB,AACE,MAAM,UAAU,WAChB,iBAAiB,QACjB,EAAE,cAAc,SAUhB,UAAU;OAPR,GAAI;OACJ,UAAU;OACV;OACA,GAAI,KAAK,YAAY,KAAA,IACjB,CAAC,IACD,EAAC,SAAS,KAAK,QAAO;MAEV,CAAC,IAEnB,UAAU,KAAK;KAIvB;IACF;IACA;GACF;GACA,KAAK,kBAAkB;IACrB,IAAM,QAAQ,mBAAmB,GAAG,EAAE;IAWtC,IAPI,gBACF,WAAW,GAMT,OAAO;KACT,IAAM,cAAc,2BAA2B,IAAI,UAAU;KAO7D,AANA,MAAM,cAAc;MAClB,OAAO;MACP,MAAM,oBAAoB,aAAa;MACvC,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAC,SAAS,YAAW;MAC1D,SAAS,CAAC;KACZ,GACA,aAAa;KACb;IACF;IAGA,IAAM,eAAe,iBAAiB,GAAG,EAAE;IAE3C,IAAI,iBAAiB,KAAA,GACnB,MAAU,MAAM,uBAAuB;IAQzC,IAAM,cAAc,2BAA2B,IAAI,UAAU,GACzD,WAAW,cACX;IACJ,IAAI,gBAAgB,KAAA,GAAW;KAC7B,IAAM,eAAe,oBAAoB,SAAS,OAAO,EACvD,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;KACD,AAAI,iBACF,WAAW,cACX,UAAU;IAEd;IAIA,IAAI,aAAa,MAAM;KAErB,IAAM,QACJ,0BACA,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;KAQH,AANK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ,IAIrB,aAAa;KACb;IACF;IAGA,AADA,gBAAgB,UAAU,OAAO,GACjC,aAAa;IACb;GACF;GACA,KAAK,mBAAmB;IACtB,IAAM,QAAQ,mBAAmB,GAAG,EAAE;IAItC,IAAI,SAAS,MAAM,aAAa;KAI9B,AAHA,WAAW,GACX,MAAM,MAAM,KAAK,MAAM,WAAW,GAClC,MAAM,cAAc,MACpB,aAAa;KACb;IACF;IAIA,AADA,aAAa,IACb,WAAW;IACX;GACF;GAGA,KAAK,SAAS;IACZ,WAAW;IAEX,IAAM,WAAW,MAAM,KAAK,KAAK,KAAK,KAAA,GAEhC,OAAO,MAAM,QAAQ,QAAQ,OAAO,EAAE,GAEtC,aAAa,oBAAoB,MAAM,KAAK;KAChD,SAAS;MACP,QAAQ,oBAAoB;MAC5B,cAAc,oBAAoB;KACpC;KACA,OAAO;MAAC;MAAU;KAAI;KACtB,UAAU;IACZ,CAAC;IAED,IAAI,CAAC,YAAY;KAEf,IAAM,QAAQ,oBAAoB,MAAM,OAAO,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;KAUD,AARK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ,IAKrB,QAAQ,IAAI,GACZ,WAAW;KACX;IACF;IAEA,UAAU,UAAU;IAEpB;GACF;GAGA,KAAK,MAAM;IACT,WAAW;IAEX,IAAM,WAAW,oBAAoB,MAAM,eAAe;KACxD,SAAS;MACP,QAAQ,oBAAoB;MAC5B,cAAc,oBAAoB;KACpC;KACA,OAAO,CAAC;KACR,UAAU;IACZ,CAAC;IAED,IAAI,CAAC,UAAU;KAEb,IAAM,QAAQ,oBAAoB,MAAM,OAAO,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;KAUD,AARK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ,IAKrB,QAAQ,KAAK,GACb,WAAW;KACX;IACF;IAEA,UAAU,QAAQ;IAElB;GACF;GAGA,KAAK,cAAc;IACjB,WAAW;IAEX,IAAM,cAAc,MAAM,QAAQ,KAAK;IAEvC,IAAI,CAAC,aACH;IAGF,IAAM,aAAa,oBAAoB,MAAM,KAAK;KAChD,SAAS;MACP,QAAQ,oBAAoB;MAC5B,cAAc,oBAAoB;KACpC;KACA,OAAO,EAAC,MAAM,YAAW;KACzB,UAAU;IACZ,CAAC;IAED,IAAI,CAAC,YAAY;KAEf,IAAM,QAAQ,oBAAoB,MAAM,OAAO,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;KAUD,AARK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ,IAKrB,QAAQ,WAAW,GACnB,WAAW;KACX;IACF;IAEA,UAAU,UAAU;IAEpB;GACF;GAEA,KAAK,cAAc;IACjB,WAAW;IAGX,IAAM,OAAO,MAAM,QAAQ,QAAQ,OAAO,EAAE,GAEtC,aAAa,oBAAoB,MAAM,KAAK;KAChD,SAAS;MACP,QAAQ,oBAAoB;MAC5B,cAAc,oBAAoB;KACpC;KACA,OAAO;MAAC,UAAU,KAAA;MAAW;KAAI;KACjC,UAAU;IACZ,CAAC;IAED,IAAK,YAgBH,UAAU,UAAU;SAhBL;KAEf,IAAM,QAAQ,oBAAoB,MAAM,OAAO,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;KAUD,AARK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ,IAKrB,QAAQ,IAAI,GACZ,WAAW;IACb;IAIA;GACF;GAGA,KAAK;IAEH,AADA,WAAW,GACX,eAAe;KACb,MAAM,CAAC;KACP,YAAY;KACZ,oBAAoB;KACpB,WAAW,CAAC;IACd;IACA;GAEF,KAAK;IACH,IAAI,CAAC,cACH;IAIF,IAAI,oBAAoB,MAAM,OAAO;KACnC,IAAM,eAAe,aAAa,UAAU,MAAM,MAAM,MAAM,IAAI,GAC5D,cAAc,oBAAoB,MAAM,MAAM;MAClD,SAAS;OACP,QAAQ,oBAAoB;OAC5B,cAAc,oBAAoB;MACpC;MACA,OAAO;OACL,MAAM,aAAa;OACnB,YACE,aAAa,aAAa,IACtB,aAAa,aACb,aAAa,qBACX,IACA,KAAA;OACR,WAAW,eAAe,aAAa,YAAY,KAAA;MACrD;MACA,UAAU;KACZ,CAAC;KAED,AAAI,cACF,UAAU,WAAW,IAGrB,aACE,cACA,YAAY,CACd;IAEJ,OAEE,aAAa,cAAc,YAAY,CAA6B;IAGtE,eAAe;IACf;GAGF,KAAK;IACH,cAAc;IACd;GAEF,KAAK;IACH,cAAc;IACd;GAEF,KAAK;GACL,KAAK,eAEH;GAEF,KAAK;IACH,kBAAkB,CAAC;IACnB;GAEF,KAAK;IAwBH,AAvBI,gBAAgB,oBAEhB,eACA,gBAAgB,iBAAiB,EAC/B,QAAQ,oBAAoB,OAC9B,CAAC,IAMD,aAAa,qBAAqB,MAElC,aAAa,KAAK,KAAK;KACrB,MAAM,oBAAoB,aAAa;KACvC,OAAO;KACP,OAAO;IACT,CAAC,GACG,eACF,aAAa,gBAInB,kBAAkB;IAClB;GAEF,KAAK;GACL,KAAK,WAAW;IAGd,AAAI,gBAAgB,eAAe,MAAM,SAAS,aAChD,aAAa,UAAU,KACrB,8BAA8B,MAAM,QAAQ,OAAO,CAAC,CACtD;IAIF,IAAM,QAAQ,oBAAoB,MAAM,OAAO,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;IAED,AAAK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ;IAIrB;GACF;GAEA,KAAK;GACL,KAAK,YAAY;IAEf,WAAW;IAIX,IAAM,aAAuC,CAAC,GACxC,SAAS,YAAY;IAG3B,IAAI,OAAO,SAAS,GAAG;KACrB,IAAM,YAAY,OAAO,GAAG,EAAE;KAC9B,AAAI,aAAa,UAAU,UAAU,WACnC,WAAW,KAAK,OAAO,IAAI,CAAuB;IAEtD;IAGA,AAAI,WAAW,WAAW,KACxB,WAAW,KAAK;KACd,OAAO;KACP,OACE,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KAAK;KACR,UAAU,CACR;MACE,OAAO,oBAAoB,OAAO,KAAK;MACvC,MAAM,oBAAoB,aAAa;MACvC,MAAM;MACN,OAAO,CAAC;KACV,CACF;KACA,MAAM,oBAAoB,aAAa;KACvC,UAAU,CAAC;IACb,CAAC;IAKH,IAAM,aAAa,WAAW;IAC9B,IACE,WAAW,WAAW,KACtB,cACA,WAAW,UAAU,WACrB,cAAc,cACd,MAAM,QAAQ,WAAW,QAAQ,KACjC,WAAW,SAAS,WAAW,GAC/B;KACA,IAAM,YAAY,WAAW,SAAS;KAEtC,AACE,OAAO,aAAc,YACrB,aACA,WAAW,aACX,UAAU,UAAU,oBAAoB,OAAO,KAAK,QACpD,UAAU,UAAU,YAGpB,WAAW,KAAK;IAEpB;IAEA,AAAI,oBAAoB,QACtB,gBAAgB,KAAK;KACnB,OAAO;KACP,MAAM,oBAAoB,aAAa;KACvC,OAAO;IACT,CAAC;IAEH;GACF;GAGA,KAAK,UAAU;IAEb,IAAM,cAAc,oBAAoB;IAGxC,IACE,MAAM,UAAU,WAAW,KAC3B,MAAM,SAAS,EAAE,EAAE,SAAS,SAC5B;KACA,IAAM,aAAa,MAAM,SAAS;KAClC,IAAI,CAAC,YACH;KAGF,IAAM,MACJ,WAAW,OAAO,MAAM,CAAC,UAAU,SAAS,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,IACzD,MAAM,yBAAyB,WAAW,WAAW,EAAE,GACvD,QACJ,WAAW,OAAO,MAAM,CAAC,UAAU,SAAS,OAAO,CAAC,EAAE,GAAG,CAAC,KAC1D,KAAA,GAEI,mBAAmB,oBAAoB,MAAM,MAAM;MACvD,SAAS;OACP,QAAQ,oBAAoB;OAC5B,cAAc,oBAAoB;MACpC;MACA,OAAO;OAAC;OAAK;OAAK;MAAK;MACvB,UAAU;KACZ,CAAC;KAED,IAAI,kBAAkB;MACpB,AAAI,cAIE,gBAAgB,cAAc,gBAC/B,aAAwC,SAAS,KAChD,gBACF,KAMA,gBACA,cAAc,gBACb,aAAuC,SAAS,SAAS,IAG1D,WAAW,KAEX,eAAe,MACf,kBAAkB,CAAC,IAErB,UAAU,gBAAgB;MAE5B;KACF;KAGA,IAAM,oBAAoB,oBAAoB,MAAM,MAAM;MACxD,SAAS;OACP,QAAQ,oBAAoB;OAC5B,cAAc,oBAAoB;MACpC;MACA,OAAO;OAAC;OAAK;OAAK;MAAK;MACvB,UAAU;KACZ,CAAC;KAED,IAAI,mBAAmB;MAErB,IAAI,CAAC,cACH,IAAI,YAGF,IAAI,mBAAmB,GAAG,EAAE,GAK1B,WAHE,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KAAK,QACQ;WACX;OACL,IAAM,WAAW,iBAAiB,GAAG,EAAE;OAEvC,AAAI,YACF,gBAAgB,QAAQ;MAE5B;WACK;OACL,IAAM,QAAQ,oBAAoB,MAAM,OAAO,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;OAED,AAAI,SACF,WAAW,KAAK;MAEpB;MAGF,AAAI,gBAAgB,cAAc,gBAC/B,aAAwC,SAAS,KAChD,iBACF;MAEF;KACF;KAGA,QAAQ,KAAK,IAAI,IAAI,IAAI,EAAE;KAC3B;IACF;IAGA,KAAK,IAAM,cAAc,MAAM,YAAY,CAAC,GAC1C,QAAQ,WAAW,MAAnB;KACE,KAAK;MACH,QAAQ,WAAW,OAAO;MAC1B;KACF,KAAK;KACL,KAAK;MACH,QAAQ,IAAI;MACZ;KACF,KAAK,eAAe;MAClB,IAAM,YAAY,oBAAoB,MAAM,KAAK,EAC/C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;MAED,IAAI,CAAC,WAAW;OAEd,QAAQ,WAAW,OAAO;OAC1B;MACF;MAGA,AADA,YAAY,KAAK,SAAS,GAC1B,QAAQ,WAAW,OAAO;MAG1B,IAAM,QAAQ,YAAY,YAAY,SAAS;MAE/C,AAAI,UAAU,MACZ,YAAY,OAAO,OAAO,CAAC;MAG7B;KACF;KACA,KAAK,eAAe;MAClB,IAAM,YAAY,oBAAoB,MAAM,OAAO,EACjD,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;MAED,IAAI,CAAC,WACH;MAGF,YAAY,KAAK,SAAS;MAC1B;KACF;KACA,KAAK,gBAAgB;MACnB,IAAM,YAAY,oBAAoB,MAAM,OAAO,EACjD,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;MAED,IAAI,CAAC,WACH;MAGF,IAAM,QAAQ,YAAY,YAAY,SAAS;MAE/C,AAAI,UAAU,MACZ,YAAY,OAAO,OAAO,CAAC;MAG7B;KACF;KACA,KAAK,WAAW;MACd,IAAM,YAAY,oBAAoB,MAAM,GAAG,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;MAED,IAAI,CAAC,WACH;MAGF,YAAY,KAAK,SAAS;MAE1B;KACF;KACA,KAAK,YAAY;MACf,IAAM,YAAY,oBAAoB,MAAM,GAAG,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;MAED,IAAI,CAAC,WACH;MAGF,IAAM,QAAQ,YAAY,YAAY,SAAS;MAE/C,AAAI,UAAU,MACZ,YAAY,OAAO,OAAO,CAAC;MAG7B;KACF;KACA,KAAK,UAAU;MACb,IAAM,YAAY,oBAAoB,MAAM,cAAc,EACxD,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;MAED,IAAI,CAAC,WACH;MAGF,YAAY,KAAK,SAAS;MAE1B;KACF;KACA,KAAK,WAAW;MACd,IAAM,YAAY,oBAAoB,MAAM,cAAc,EACxD,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;MAED,IAAI,CAAC,WACH;MAGF,IAAM,QAAQ,YAAY,YAAY,SAAS;MAE/C,AAAI,UAAU,MACZ,YAAY,OAAO,OAAO,CAAC;MAG7B;KACF;KACA,KAAK,aAAa;MAChB,IAAM,OAAO,WAAW,OACpB,MAAM,CAAC,UAAU,SAAS,MAAM,CAAC,EACjC,GAAG,CAAC;MAER,IAAI,CAAC,MACH;MAGF,IAAM,QAAQ,WAAW,OACrB,MAAM,CAAC,UAAU,SAAS,OAAO,CAAC,EAClC,GAAG,CAAC,GAEF,aAAa,oBAAoB,MAAM,KAAK;OAChD,SAAS;QACP,QAAQ,oBAAoB;QAC5B,cAAc,oBAAoB;OACpC;OACA,OAAO;QAAC;QAAM;OAAK;MACrB,CAAC;MAED,IAAI,CAAC,YACH;MAIF,AADA,gBAAgB,KAAK,UAAU,GAC/B,YAAY,KAAK,WAAW,IAAI;MAChC;KACF;KACA,KAAK,cAAc;MAEjB,IAAM,cAAc,IAAI,IAAI,gBAAgB,KAAK,MAAM,EAAE,IAAI,CAAC,GAC1D;MAEJ,KAAK,IAAM,cAAc,YAAY,QAAQ,GAC3C,IAAI,YAAY,IAAI,UAAU,GAAG;OAC/B,gBAAgB,YAAY,QAAQ,UAAU;OAC9C;MACF;MAGF,IAAI,kBAAkB,KAAA,GAAW;OAC/B,IAAM,YAAY,YAAY,SAAS,IAAI;OAC3C,YAAY,OAAO,WAAW,CAAC;MACjC;MACA;KACF;KACA,KAAK,SAAS;MACZ,IAAM,MACJ,WAAW,OAAO,MAAM,CAAC,UAAU,SAAS,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,IACzD,MAAM,yBAAyB,WAAW,WAAW,EAAE,GAGvD,oBAAoB,oBAAoB,MAAM,MAAM;OACxD,SAAS;QACP,QAAQ,oBAAoB;QAC5B,cAAc,oBAAoB;OACpC;OACA,OAAO;QAAC;QAAK;QAAK,OAAO,KAAA;OAAS;OAClC,UAAU;MACZ,CAAC;MAED,IAAI,mBAAmB;OAErB,IAAI,CAAC,cAAc;QACjB,IAAM,QAAQ,oBAAoB,MAAM,OAAO,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;QAED,AAAK,QAIH,WAAW,KAAK,KAHhB,QAAQ,KAAK,0CAAwC,GACrD,WAAW,QAAQ;OAIvB;OAGA,IAAI,CAAC,cACH,MAAU,MAAM,yCAAyC;OAI1D,aAAwC,SAAS,KAChD,iBACF;OACA;MACF;MAGA,IAAM,mBAAmB,oBAAoB,MAAM,MAAM;OACvD,SAAS;QACP,QAAQ,oBAAoB;QAC5B,cAAc,oBAAoB;OACpC;OACA,OAAO;QAAC;QAAK;QAAK,OAAO,KAAA;OAAS;OAClC,UAAU;MACZ,CAAC;MAED,IAAI,CAAC,kBAAkB;OAErB,QAAQ,KAAK,IAAI,IAAI,IAAI,EAAE;OAC3B;MACF;MAIA,IAAI,aAAa;OAEf,AAAI,gBAAgB,cAAc,gBAC/B,aAAwC,SAAS,KAChD,gBACF;OAEF;MACF;MAIA,AADA,WAAW,GACX,UAAU,gBAAgB;MAG1B,IAAM,QAAQ,oBAAoB,MAAM,OAAO,EAC7C,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC;MAED,AAAI,SACF,WAAW,KAAK;MAGlB;KACF;KACA,KAAK,eAEH,AAAI,oBAAoB,KAAK,WAAW,UACtC,QAAQ,WAAW,OAAO;IAQhC;IAEF;GACF;GAGA,KAAK;IAiBH,AAhBA,WAAW,GACX,qBAAqB,YAAY,GACjC,oBAAoB,mBAAmB,QACvC,cAAc,MAAM,QAapB,yBAPE,oBAAoB,MAAM,WAAW,EACnC,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KACD,oBAAoB,MAAM,OAAO,EAC/B,SAAS,EAAC,QAAQ,oBAAoB,OAAM,EAC9C,CAAC,KAE+B;IAClC;GAGF,KAAK,eAEH;GAGF,KAAK;IAGH,IAFA,WAAW,GAGT,sBAAsB,QACtB,gBAAgB,QAChB,uBAAuB,MACvB;KACA,IAAM,gBAAgB,mBAAmB,OACvC,iBACF,GAEM,gBAAgB,oBAAoB,MAAM,UAAU;MACxD,SAAS;OACP,QAAQ,oBAAoB;OAC5B,cAAc,oBAAoB;MACpC;MACA,OAAO;OAAC,MAAM;OAAa,SAAS;MAAa;MACjD,UAAU;KACZ,CAAC;KAED,IAAI,eACF,UAAU,aAAa;UAEvB,KAAK,IAAM,SAAS,eAClB,UAAU,KAAK;IAGrB;IAKA,AAHA,oBAAoB,MACpB,qBAAqB,MACrB,cAAc,MACd,yBAAyB;EAM7B;CACF;CAIA,OAFA,WAAW,GAEJ;AACT"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/key-generator.ts","../src/from-portable-text/build-list-index-map.ts","../src/from-portable-text/escape-plain-text.ts","../src/from-portable-text/list-item-first-block.ts","../src/from-portable-text/render-node.ts","../src/from-portable-text/renderers/block-spacing.ts","../src/from-portable-text/renderers/hard-break.ts","../src/from-portable-text/renderers/list-item.ts","../src/escape.ts","../src/from-portable-text/renderers/marks.ts","../src/from-portable-text/renderers/style.ts","../src/from-portable-text/renderers/type.ts","../src/from-portable-text/portable-text-to-markdown.ts","../src/default-schema.ts","../src/to-portable-text/degradation-messages.ts","../src/to-portable-text/matchers.ts","../src/to-portable-text/markdown-to-portable-text.ts"],"sourcesContent":["export function defaultKeyGenerator() {\n return randomKey(12)\n}\n\nconst getByteHexTable = (() => {\n let table: any[]\n return () => {\n if (table) {\n return table\n }\n\n table = []\n for (let i = 0; i < 256; ++i) {\n table[i] = (i + 0x100).toString(16).slice(1)\n }\n return table\n }\n})()\n\n// WHATWG crypto RNG - https://w3c.github.io/webcrypto/Overview.html\nfunction whatwgRNG(length = 16) {\n const rnds8 = new Uint8Array(length)\n crypto.getRandomValues(rnds8)\n return rnds8\n}\n\nfunction randomKey(length?: number): string {\n const table = getByteHexTable()\n return whatwgRNG(length)\n .reduce((str, n) => str + table[n], '')\n .slice(0, length)\n}\n","import {\n compileSchema,\n defineSchema,\n isTextBlock,\n type PortableTextBlock,\n} from '@portabletext/schema'\nimport type {ArbitraryTypedObject, TypedObject} from '@portabletext/types'\nimport {defaultKeyGenerator} from '../key-generator'\n\nconst schema = compileSchema(defineSchema({}))\n\n/**\n * Builds a map of list item `_key`s to their index, and a map of list item\n * `_key`s to the depth they should be rendered at.\n *\n * The depth is not the same as the block's `level`. A list can start at a level\n * deeper than 1, and can skip levels, but Markdown has no way to express either:\n * indentation is relative to the list item above, and indenting a first item by\n * four spaces or more makes it a code block rather than a list. So each jump to a\n * deeper level counts as a single step of nesting, however many levels it spans.\n *\n * Mutates the blocks in place by adding a `_key` if necessary.\n */\nexport function buildListIndexMap<\n Block extends TypedObject = PortableTextBlock | ArbitraryTypedObject,\n>(\n blocks: Array<Block>,\n): {listIndexMap: Map<string, number>; listDepthMap: Map<string, number>} {\n const levelIndexMaps = new Map<string, Map<number, number>>()\n const listIndexMap = new Map<string, number>()\n const listDepthMap = new Map<string, number>()\n\n // Levels of the list items this one is nested inside, shallowest first\n let levelStack: Array<number> = []\n\n function depthOf(level: number): number {\n let deepest = levelStack.at(-1)\n\n while (deepest !== undefined && deepest > level) {\n levelStack.pop()\n deepest = levelStack.at(-1)\n }\n\n if (deepest !== level) {\n levelStack.push(level)\n }\n\n return levelStack.length - 1\n }\n\n let previousListItem:\n | {\n listItem: string\n depth: number\n }\n | undefined\n\n for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) {\n const block = blocks.at(blockIndex)\n\n if (block === undefined) {\n continue\n }\n\n if (!block._key) {\n block._key = defaultKeyGenerator()\n }\n\n // Clear the state if we encounter a non-text block\n if (!isTextBlock({schema}, block)) {\n levelIndexMaps.clear()\n previousListItem = undefined\n levelStack = []\n\n continue\n }\n\n // Clear the state if we encounter a non-list text block\n if (block.listItem === undefined || block.level === undefined) {\n levelIndexMaps.clear()\n previousListItem = undefined\n levelStack = []\n\n continue\n }\n\n const depth = depthOf(block.level)\n listDepthMap.set(block._key, depth)\n\n // If we encounter a new list item, we set the initial index to 1 for the\n // list type on that level.\n if (!previousListItem) {\n const listIndex = 1\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n levelIndexMap.set(depth, listIndex)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, listIndex)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n\n continue\n }\n\n // If the previous list item is of the same type but on a lower level, we\n // need to reset the level index map for that type.\n if (\n previousListItem.listItem === block.listItem &&\n previousListItem.depth < depth\n ) {\n const listIndex = 1\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n levelIndexMap.set(depth, listIndex)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, listIndex)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n\n continue\n }\n\n // Reset other list types at current depth and deeper\n levelIndexMaps.forEach((levelIndexMap, listItem) => {\n if (listItem === block.listItem) {\n return\n }\n\n // Reset all levels that are >= current level\n const depthsToDelete: number[] = []\n\n levelIndexMap.forEach((_, existingDepth) => {\n if (existingDepth >= depth) {\n depthsToDelete.push(existingDepth)\n }\n })\n\n depthsToDelete.forEach((depthToDelete) => {\n levelIndexMap.delete(depthToDelete)\n })\n })\n\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n const levelCounter = levelIndexMap.get(depth) ?? 0\n levelIndexMap.set(depth, levelCounter + 1)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, levelCounter + 1)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n }\n\n return {listIndexMap, listDepthMap}\n}\n","import {isPortableTextSpan} from '@portabletext/toolkit'\nimport type {\n ArbitraryTypedObject,\n PortableTextMarkDefinition,\n PortableTextSpan,\n} from '@portabletext/types'\nimport LinkifyIt from 'linkify-it'\n\n/**\n * The CommonMark ASCII punctuation set. Only these characters can be\n * backslash-escaped into a literal without changing the parsed text.\n */\nconst ASCII_PUNCTUATION = /[!-/:-@[-`{-~]/\n\nconst ENTITY_REFERENCE = /&(?:[a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#[xX][0-9a-fA-F]+);/g\nconst BACKSLASH_BEFORE_PUNCTUATION = new RegExp(\n `\\\\\\\\(?=${ASCII_PUNCTUATION.source})`,\n 'g',\n)\nconst TILDE_RUN = /~{2,}/g\nconst HTML_LIKE_ANGLE_BRACKET = /<(?=[a-zA-Z/!?])/g\nconst BRACKET_BEFORE_LINK_OPEN = /\\](?=[([])/g\n\n/**\n * markdown-it's own emphasis-flanking rule classifies a delimiter's\n * neighbor as punctuation using Unicode's `P` (Punctuation) and `S`\n * (Symbol) categories, not just ASCII: an emoji, an em dash, or a CJK\n * character flanks a `*`/`_` run exactly like an ASCII punctuation\n * character does, so testing ASCII alone would fabricate emphasis next to\n * non-ASCII text the real reparse wouldn't create. Matched against one\n * full code point at a time (a surrogate pair for an astral character\n * like an emoji), never a lone UTF-16 code unit, which the category\n * classes never match.\n */\nconst UNICODE_PUNCTUATION_OR_SYMBOL = /^(?:\\p{P}|\\p{S})$/u\n\n// Configured with no options, exactly like markdown-it constructs its own\n// `md.linkify` instance: same default schemas (http/https/ftp/'//'/mailto)\n// and the same built-in TLD list, so a range this reports as a link is a\n// range the real reparse will claim too.\nconst linkify = new LinkifyIt()\n\ntype LeafPiece =\n | {kind: 'text'; raw: string; isLinkLabel: boolean; markSignature: string}\n | {kind: 'hardBreak'}\n | {kind: 'opaque'}\n\n/**\n * Stands in for one opaque child (an inline object, or a leaf a custom\n * renderer will replace) in a joined line's text. It can never match a\n * hazard's trigger character, so it safely walls off an in-progress\n * construct (an ordered-list marker, a ref-def label) without needing a\n * dedicated flag, while still counting as real, non-whitespace content for\n * emphasis-flanking purposes.\n */\nconst OPAQUE_CHAR = '\\0'\n\n/** Which leaf (by index into the flat `pieces` list) a line character came\n * from, and at what offset into that leaf's *prepared* text (raw text, with\n * a link-label leaf's brackets/backslashes already doubled). `null` marks\n * an opaque character: it has no leaf-local home, so no edit can target it. */\ninterface LineChar {\n pieceIndex: number\n offset: number\n}\n\n/** A single-position splice against a joined line's raw text: remove\n * `deleteCount` characters at `at` and put `insert` in their place. A pure\n * insertion (a backslash escape) has `deleteCount: 0`. */\ninterface Edit {\n at: number\n deleteCount: number\n insert: string\n /**\n * Set for an entity-reference or backtick escape: both change what\n * markdown-it's inline parser hands to its linkify pass (an entity\n * decodes first, a backtick can open a code span first), so the linkify\n * mask - built from this line's raw, undecoded text - can never be\n * trusted to have already accounted for them. Kept regardless of any\n * linkify claim overlapping it.\n */\n bypassLinkifyMask?: boolean\n}\n\n/**\n * Plans the escaped replacement for every plain-text leaf a block's children\n * will produce, in the exact left-to-right order `renderText` visits them\n * (mirroring `buildMarksTree`'s own `text.split('\\n')` leaf splitting).\n *\n * Escaping runs ahead of rendering, over the flat span sequence: some\n * hazards only exist across a leaf boundary (an ordered-list marker, a\n * ref-def label, an emphasis run) because an annotation or decorator mark\n * that introduces no markup of its own splices its children in seamlessly.\n * The plan works line by line (a block's children joined into text, split\n * at hard breaks) rather than leaf by leaf: each line's leaves are joined\n * into one string first, opaque children (inline objects, or leaves a\n * custom renderer will replace) masked with a sentinel that can't match any\n * hazard, and every hazard - inline and line-start alike - is detected once\n * against that real, complete line, with true left/right context on both\n * sides. Detected hazards become position-tracked edits against the line's\n * raw text, which are then split back into each contributing leaf's own\n * escaped text; only that composition step is leaf-scoped.\n *\n * A joined line's text that markdown-it's own linkify pass (bundled as\n * `linkify-it`) would claim as a bare URL or email is masked from most\n * edits: the linkify carve-out promises that substring round-trips\n * byte-identical, gaining only a link mark, so escaping inside it would\n * corrupt text linkify is about to claim as a link's visible text. An\n * entity-reference or backtick escape is never masked (see `computeLinkifyMask`\n * for why), and a claim spliced across a decorator boundary is never masked\n * in the first place.\n *\n * `isHeading` is set for ATX headings: only the first joined line sits\n * inside the `# ` prefix an ATX heading can never be reparsed as a block\n * construct within, so line-leading hazards are skipped there; a hard\n * break's later lines are ordinary markdown lines and get the full\n * line-start battery. That first line carries a line-*end* hazard of its\n * own instead: a trailing `#`-run reads back as the heading's own optional\n * closing sequence.\n *\n * `isListItem` is set when the block renders as list-item content: a\n * `[ ] `/`[x] `/`[X] ` at the very start of the first joined line reads\n * back as a GFM task-list checkbox, regardless of the list's own item type.\n *\n * `hardBreakOutputHasNewline` says whether the renderer's actual hard-break\n * output contains a newline. A custom `hardBreak` can render to something\n * with no newline of its own (eg `() => '<br />'`), in which case the\n * leaves on either side of it land on the same rendered line, not two: a\n * hard break like that can't be planned as a line boundary, so it's walled\n * off as an opaque segment instead, the same protection an inline object's\n * unknown rendered text already gets.\n */\nexport function planLeafEscaping(\n children: ReadonlyArray<PortableTextSpan | ArbitraryTypedObject>,\n markDefs: ReadonlyArray<PortableTextMarkDefinition>,\n options: {\n isHeading: boolean\n isListItem: boolean\n hardBreakOutputHasNewline: boolean\n },\n): Array<string> {\n const linkMarkKeys = new Set(\n markDefs.filter((def) => def._type === 'link').map((def) => def._key),\n )\n // Every markDef key a span's marks can reference (any annotation, not\n // just link): what's left after removing those from a span's `marks` is\n // its decorator set, the only marks `buildMarksTree` reliably renders as\n // delimiters by default (an unregistered annotation type falls back to\n // passing its children through unchanged, same as an unknown decorator).\n const markDefKeys = new Set(markDefs.map((def) => def._key))\n const pieces: Array<LeafPiece> = []\n\n for (const child of children) {\n if (isPortableTextSpan(child)) {\n const isLinkLabel = (child.marks ?? []).some((mark) =>\n linkMarkKeys.has(mark),\n )\n // Sorted so two spans carrying the same decorators in a different\n // order still compare equal: `buildMarksTree` nests by decorator\n // identity, not by a span's own array order, so it produces the same\n // markup boundaries either way.\n const markSignature = (child.marks ?? [])\n .filter((mark) => !markDefKeys.has(mark))\n .sort()\n .join(',')\n const lines = child.text.split('\\n')\n lines.forEach((line, index) => {\n if (index > 0) {\n pieces.push(\n options.hardBreakOutputHasNewline\n ? {kind: 'hardBreak'}\n : {kind: 'opaque'},\n )\n }\n pieces.push({kind: 'text', raw: line, isLinkLabel, markSignature})\n })\n } else {\n pieces.push({kind: 'opaque'})\n }\n }\n\n const pieceOutputs: Array<string> = pieces.map(() => '')\n\n let lineIndex = 0\n let lineText = ''\n let lineChars: Array<LineChar | null> = []\n let lineIsLinkLabelChar: Array<boolean> = []\n let lineMarkSignature: Array<string> = []\n\n const flushLine = () => {\n processLine({\n text: lineText,\n chars: lineChars,\n isLinkLabelChar: lineIsLinkLabelChar,\n markSignature: lineMarkSignature,\n lineIndex,\n isHeading: options.isHeading,\n isListItem: options.isListItem,\n pieceOutputs,\n })\n lineIndex++\n lineText = ''\n lineChars = []\n lineIsLinkLabelChar = []\n lineMarkSignature = []\n }\n\n for (let pieceIndex = 0; pieceIndex < pieces.length; pieceIndex++) {\n const piece = pieces[pieceIndex]\n\n if (!piece || piece.kind === 'hardBreak') {\n flushLine()\n continue\n }\n\n if (piece.kind === 'opaque') {\n lineText += OPAQUE_CHAR\n lineChars.push(null)\n lineIsLinkLabelChar.push(false)\n lineMarkSignature.push('')\n continue\n }\n\n // A link label's brackets and backslashes are escaped unconditionally,\n // up front: a label must stay bracket-balanced regardless of context,\n // so this doesn't depend on anything the line-level hazard scan below\n // discovers.\n const prepared = piece.isLinkLabel\n ? escapeLinkLabelBrackets(piece.raw)\n : piece.raw\n\n for (let offset = 0; offset < prepared.length; offset++) {\n lineText += prepared[offset]\n lineChars.push({pieceIndex, offset})\n lineIsLinkLabelChar.push(piece.isLinkLabel)\n lineMarkSignature.push(piece.markSignature)\n }\n }\n flushLine()\n\n const escaped: Array<string> = []\n pieces.forEach((piece, index) => {\n if (piece.kind === 'text') {\n escaped.push(pieceOutputs[index] ?? '')\n }\n })\n return escaped\n}\n\nfunction processLine(args: {\n text: string\n chars: Array<LineChar | null>\n isLinkLabelChar: Array<boolean>\n markSignature: Array<string>\n lineIndex: number\n isHeading: boolean\n isListItem: boolean\n pieceOutputs: Array<string>\n}): void {\n const {text, chars, isLinkLabelChar, markSignature, pieceOutputs} = args\n\n const linkifyMask = computeLinkifyMask(\n text,\n chars,\n isLinkLabelChar,\n markSignature,\n )\n const edits = [\n ...collectInlineEdits(text, isLinkLabelChar),\n ...collectLineStartEdits(text, args),\n ].filter((edit) => edit.bypassLinkifyMask || !isMasked(edit, linkifyMask))\n\n applyEdits(text, chars, edits, pieceOutputs)\n}\n\n/**\n * Marks every character of this line that markdown-it's linkify pass would\n * claim as part of a bare URL or email. Link-label and opaque characters\n * are blanked out first: a link label's visible text sits inside `[...]`\n * markup real linkify never reconsiders, and an opaque child's rendered\n * text is unknown at plan time, so neither should join or seed a match.\n *\n * The probe only sees this line's raw, undecoded text, one hazard pass\n * ahead of markdown-it's own pipeline: it runs linkify against inline\n * tokenization and entity decoding, not before them. A claim survives only\n * if it lies entirely inside one run of identical decorator marks: a\n * decorator boundary crossing it splices that decorator's delimiters\n * (`**`, `` ` ``, ...) into the middle of the range real linkify would see,\n * which breaks the very claim being trusted. An annotation-only boundary\n * (a link's own label text is already excluded above; any other\n * annotation type falls back to rendering with no delimiters at all,\n * same as an unregistered decorator) never splices, so it can't invalidate\n * a claim either.\n */\nfunction computeLinkifyMask(\n text: string,\n chars: Array<LineChar | null>,\n isLinkLabelChar: Array<boolean>,\n markSignature: Array<string>,\n): Array<boolean> {\n const mask = new Array<boolean>(text.length).fill(false)\n\n // Every schema `linkify-it`'s default config recognizes - `http(s):`,\n // `ftp:`, `//`, `www.`, and a `user@host` email - needs a `.`, `:`, or\n // `@` somewhere in the line; skipping the match call on a line with\n // none of those is the cheap majority-case exit, not a heuristic that\n // could miss a real claim.\n if (!/[.:@]/.test(text)) {\n return mask\n }\n\n let probe = ''\n for (let index = 0; index < text.length; index++) {\n probe += chars[index] === null || isLinkLabelChar[index] ? ' ' : text[index]\n }\n\n const matches = linkify.match(probe) ?? []\n for (const match of matches) {\n if (match.schema === '') {\n // A fuzzy claim (`www.`, bare domain): markdown-it's emphasis pass\n // beats these on reparse, so paired `*`/`_`/`~~` inside one is\n // consumed as markup and the characters vanish. Only explicit-scheme\n // claims (`http:`, `mailto:`, ...) win whole against inline\n // constructs; fuzzy forms take normal escaping instead, trading\n // their link mark for text fidelity.\n continue\n }\n const signature = markSignature[match.index]\n let staysWithinOneMarkRun = true\n for (let index = match.index; index < match.lastIndex; index++) {\n if (markSignature[index] !== signature) {\n staysWithinOneMarkRun = false\n break\n }\n }\n if (!staysWithinOneMarkRun) {\n continue\n }\n for (let index = match.index; index < match.lastIndex; index++) {\n mask[index] = true\n }\n }\n return mask\n}\n\nfunction isMasked(edit: Edit, mask: ReadonlyArray<boolean>): boolean {\n const end = edit.at + Math.max(edit.deleteCount, 1)\n for (let index = edit.at; index < end; index++) {\n if (mask[index]) {\n return true\n }\n }\n return false\n}\n\n/** Rewrites a line's raw text into each contributing leaf's escaped text by\n * walking it once, left to right, applying at most one edit per position.\n * Every hazard is keyed off its own trigger character - a backslash, a\n * tilde, a backtick, an `&`, a `<`, a `*`/`_`, a `]`, or (line-start only,\n * one hazard per line) a `#`, `>`, `[`, `-`/`+`/`*`, the `.`/`)` after an\n * ordered-list marker's digits, `=`, 4 spaces, or a tab - and no two of\n * those characters coincide at one position, so two edits can never target\n * the same position. */\nfunction applyEdits(\n text: string,\n chars: ReadonlyArray<LineChar | null>,\n edits: ReadonlyArray<Edit>,\n pieceOutputs: Array<string>,\n): void {\n const editsByPosition = new Map<number, Edit>()\n for (const edit of edits) {\n if (editsByPosition.has(edit.at)) {\n throw new Error(\n `Two hazard edits targeted the same position (${edit.at}); ` +\n 'hazard trigger characters are assumed disjoint by construction.',\n )\n }\n editsByPosition.set(edit.at, edit)\n }\n\n let index = 0\n while (index < text.length) {\n const edit = editsByPosition.get(index)\n const owner = chars[index]\n\n if (edit) {\n if (owner) {\n pieceOutputs[owner.pieceIndex] =\n (pieceOutputs[owner.pieceIndex] ?? '') + edit.insert\n }\n if (edit.deleteCount > 0) {\n index += edit.deleteCount\n continue\n }\n }\n\n if (owner) {\n pieceOutputs[owner.pieceIndex] =\n (pieceOutputs[owner.pieceIndex] ?? '') + (text[index] ?? '')\n }\n index++\n }\n}\n\n/**\n * Hazards that can appear anywhere on a line: emphasis/strikethrough runs,\n * a backtick, an entity reference, an HTML/autolink-shaped `<`, a literal\n * backslash before punctuation, and a `]` immediately before `(`/`[`\n * (which would otherwise read back as a link/image open).\n */\nfunction collectInlineEdits(\n text: string,\n isLinkLabelChar: ReadonlyArray<boolean>,\n): Array<Edit> {\n const edits: Array<Edit> = []\n\n for (const match of text.matchAll(BACKSLASH_BEFORE_PUNCTUATION)) {\n const at = match.index ?? 0\n // A link label's backslashes were already doubled unconditionally\n // while preparing its text; doubling them again here would flip their\n // parity back to unescaped.\n if (!isLinkLabelChar[at]) {\n edits.push({at, deleteCount: 0, insert: '\\\\'})\n }\n }\n\n for (const match of text.matchAll(TILDE_RUN)) {\n const start = match.index ?? 0\n for (let index = start; index < start + match[0].length; index++) {\n edits.push({at: index, deleteCount: 0, insert: '\\\\'})\n }\n }\n\n for (let index = 0; index < text.length; index++) {\n if (text[index] === '`') {\n // Every backtick is escaped outright: even a lone one can pair with\n // another lone backtick elsewhere to open a code span, which the\n // linkify mask can't see coming - a code span forms during inline\n // tokenization, before linkify ever runs - so this bypasses it.\n edits.push({\n at: index,\n deleteCount: 0,\n insert: '\\\\',\n bypassLinkifyMask: true,\n })\n }\n }\n\n for (const match of text.matchAll(ENTITY_REFERENCE)) {\n // An entity reference decodes before linkify runs, so a masked range\n // built from this line's raw text can't already account for it.\n edits.push({\n at: match.index ?? 0,\n deleteCount: 0,\n insert: '\\\\',\n bypassLinkifyMask: true,\n })\n }\n\n for (const match of text.matchAll(HTML_LIKE_ANGLE_BRACKET)) {\n edits.push({at: match.index ?? 0, deleteCount: 0, insert: '\\\\'})\n }\n\n edits.push(...collectEmphasisEdits(text))\n\n for (const match of text.matchAll(BRACKET_BEFORE_LINK_OPEN)) {\n const at = match.index ?? 0\n // A link label's `]` was already escaped unconditionally while\n // preparing its text (`escapeLinkLabelBrackets`); escaping it again\n // here would double the backslash and reopen the label early on\n // reparse, same reasoning as the backslash rule above.\n if (!isLinkLabelChar[at]) {\n edits.push({at, deleteCount: 0, insert: '\\\\'})\n }\n }\n\n return edits\n}\n\nfunction isWhitespace(char: string | undefined): boolean {\n return char === undefined || /\\s/.test(char)\n}\n\nfunction isPunctuation(char: string | undefined): boolean {\n return char !== undefined && UNICODE_PUNCTUATION_OR_SYMBOL.test(char)\n}\n\n/**\n * The full code point sitting immediately before `index`: two UTF-16 code\n * units for an astral character (eg an emoji) whose low surrogate lands at\n * `index - 1`, one otherwise.\n */\nfunction codePointBefore(text: string, index: number): string | undefined {\n if (index <= 0) {\n return undefined\n }\n if (\n index >= 2 &&\n isLowSurrogate(text[index - 1]) &&\n isHighSurrogate(text[index - 2])\n ) {\n return text.slice(index - 2, index)\n }\n return text[index - 1]\n}\n\n/**\n * The full code point sitting immediately at `index`: two UTF-16 code units\n * for an astral character whose high surrogate lands at `index`, one\n * otherwise.\n */\nfunction codePointAt(text: string, index: number): string | undefined {\n if (index >= text.length) {\n return undefined\n }\n if (isHighSurrogate(text[index]) && isLowSurrogate(text[index + 1])) {\n return text.slice(index, index + 2)\n }\n return text[index]\n}\n\nfunction isHighSurrogate(char: string | undefined): boolean {\n if (char === undefined) {\n return false\n }\n const code = char.charCodeAt(0)\n return code >= 0xd800 && code <= 0xdbff\n}\n\nfunction isLowSurrogate(char: string | undefined): boolean {\n if (char === undefined) {\n return false\n }\n const code = char.charCodeAt(0)\n return code >= 0xdc00 && code <= 0xdfff\n}\n\nfunction isLeftFlanking(\n before: string | undefined,\n after: string | undefined,\n): boolean {\n if (isWhitespace(after)) {\n return false\n }\n return !isPunctuation(after) || isWhitespace(before) || isPunctuation(before)\n}\n\nfunction isRightFlanking(\n before: string | undefined,\n after: string | undefined,\n): boolean {\n if (isWhitespace(before)) {\n return false\n }\n return !isPunctuation(before) || isWhitespace(after) || isPunctuation(after)\n}\n\n/**\n * Finds `*`/`_` runs CommonMark would treat as flanking delimiters, using\n * each run's true neighbors on the joined line (the start/end of the line\n * itself counts as whitespace, matching the spec's treatment of line\n * boundaries).\n */\nfunction collectEmphasisEdits(text: string): Array<Edit> {\n const edits: Array<Edit> = []\n let index = 0\n\n while (index < text.length) {\n const char = text[index]\n\n if (char !== '*' && char !== '_') {\n index++\n continue\n }\n\n let end = index\n while (end < text.length && text[end] === char) {\n end++\n }\n\n const before = codePointBefore(text, index)\n const after = codePointAt(text, end)\n const leftFlanking = isLeftFlanking(before, after)\n const rightFlanking = isRightFlanking(before, after)\n\n const canOpen =\n char === '_'\n ? leftFlanking && (!rightFlanking || isPunctuation(before))\n : leftFlanking\n const canClose =\n char === '_'\n ? rightFlanking && (!leftFlanking || isPunctuation(after))\n : rightFlanking\n\n if (canOpen || canClose) {\n for (let position = index; position < end; position++) {\n edits.push({at: position, deleteCount: 0, insert: '\\\\'})\n }\n }\n\n index = end\n }\n\n return edits\n}\n\n/**\n * Hazards that only matter at the start (or, for a handful of whole-line\n * constructs, the start *and* end) of a line: headings, blockquotes, list\n * markers, ref-defs, setext underlines, thematic breaks, indented code, and\n * a list item's own GFM task-checkbox prefix. A fence needs no branch of\n * its own here: the inline backtick/tilde escaping every line already\n * neutralizes the run a fence needs, so it can never open one on reparse.\n * The remaining branches are mutually exclusive by construction\n * (each targets a disjoint leading character) and return as soon as one\n * matches, mirroring how CommonMark itself commits to one block-start\n * interpretation per line; the checkbox branch above is the one exception,\n * since a list item's checkbox prefix and, say, its heading marker are two\n * independent hazards that can both apply to the same first line.\n */\nfunction collectLineStartEdits(\n text: string,\n context: {isHeading: boolean; isListItem: boolean; lineIndex: number},\n): Array<Edit> {\n const edits: Array<Edit> = []\n const isFirstLine = context.lineIndex === 0\n\n // CommonMark allows up to 3 leading spaces before a block marker without\n // affecting how it's parsed, so every hazard below (including the GFM\n // task-checkbox the parser's own pre-pass looks for, after its own\n // leading-whitespace trim) checks what follows them; the escape itself\n // still has to land right before the marker, not at the front of those\n // spaces (a backslash-space isn't an escape).\n const leadingSpaces = /^ {0,3}/.exec(text)?.[0].length ?? 0\n const rest = text.slice(leadingSpaces)\n\n if (context.isListItem && isFirstLine && /^\\[[ xX]\\] /.test(rest)) {\n edits.push({at: leadingSpaces, deleteCount: 0, insert: '\\\\'})\n }\n\n if (context.isHeading && isFirstLine) {\n // A closing sequence must be preceded by a space, unless it's *all*\n // the heading has: then the space ATX headings require after their\n // opening `#`s stands in for it.\n const closingSequence = /^(?:(.*[ \\t]))?(#+[ \\t]*)$/.exec(text)\n if (closingSequence) {\n edits.push({\n at: closingSequence[1]?.length ?? 0,\n deleteCount: 0,\n insert: '\\\\',\n })\n }\n return edits\n }\n\n const orderedListMarker = /^ {0,3}(\\d{1,9})([.)])(?=[ \\t]|$)/.exec(text)\n if (orderedListMarker) {\n edits.push({\n at: orderedListMarker[0].length - 1,\n deleteCount: 0,\n insert: '\\\\',\n })\n return edits\n }\n\n if (/^#{1,6}(?:[ \\t]|$)/.test(rest)) {\n edits.push({at: leadingSpaces, deleteCount: 0, insert: '\\\\'})\n return edits\n }\n\n if (rest.startsWith('>')) {\n edits.push({at: leadingSpaces, deleteCount: 0, insert: '\\\\'})\n return edits\n }\n\n if (/^\\[[^\\]\\n]*\\]:/.test(rest)) {\n edits.push({at: leadingSpaces, deleteCount: 0, insert: '\\\\'})\n return edits\n }\n\n if (/^[-+*](?:[ \\t]|$)/.test(rest)) {\n edits.push({at: leadingSpaces, deleteCount: 0, insert: '\\\\'})\n return edits\n }\n\n // CommonMark 4.1 allows interior spaces/tabs between a thematic break's\n // delimiter characters.\n if (/^ {0,3}([-*_])(?:[ \\t]*\\1){2,}[ \\t]*$/.test(text)) {\n edits.push({at: leadingSpaces, deleteCount: 0, insert: '\\\\'})\n return edits\n }\n\n if (/^ {0,3}=+[ \\t]*$/.test(text)) {\n edits.push({at: leadingSpaces, deleteCount: 0, insert: '\\\\'})\n return edits\n }\n\n if (/^ {0,3}-+[ \\t]*$/.test(text)) {\n edits.push({at: leadingSpaces, deleteCount: 0, insert: '\\\\'})\n return edits\n }\n\n if (/^ {4}/.test(text)) {\n // A numeric character reference decodes to the same literal character\n // during inline parsing, after block structure (and its indented-code\n // -block rule, 4 columns of leading whitespace) has already been\n // decided.\n edits.push({at: 0, deleteCount: 1, insert: ' '})\n return edits\n }\n\n const tabIndent = /^ {0,3}\\t/.exec(text)\n if (tabIndent) {\n // A tab advances to the next multiple of 4 columns, so even 0-3\n // leading spaces before one reaches the indented-code-block\n // threshold; encoding the tab itself (not the spaces before it) is\n // enough to break that count.\n edits.push({at: tabIndent[0].length - 1, deleteCount: 1, insert: '	'})\n return edits\n }\n\n return edits\n}\n\n/**\n * Text rendered inside a link label needs every `[`, `]` and `\\` escaped\n * unconditionally, on top of the general-purpose hazard escaping every\n * line gets: a link label must stay bracket-balanced, and any literal\n * backslash in it needs protecting regardless of what follows (unlike\n * plain text, where only a backslash immediately before punctuation is a\n * hazard).\n */\nfunction escapeLinkLabelBrackets(text: string): string {\n return text.replace(/[[\\]\\\\]/g, (char) => `\\\\${char}`)\n}\n","import type {PortableTextBlock} from '@portabletext/types'\n\n/**\n * Blocks currently known to be a list item's first content block: it shares\n * its first line with the list marker (and, for a task item, its GFM\n * checkbox), which changes how `renderBlock` plans line-start hazard\n * escaping. Internal to this package so the signal never reaches the\n * public `Serializable`/`RenderNode` types a custom renderer's `.d.ts`\n * would otherwise expose it through.\n *\n * A block is marked right before rendering it; the `renderNode` call that\n * dispatches to `renderBlock` consumes the membership on the way past so a\n * later, unrelated render of the same object (still possible - `renderNode`\n * accepts any `TypedObject`) doesn't inherit a stale claim.\n */\nconst listItemFirstBlocks = new WeakSet<PortableTextBlock>()\n\nexport function markListItemFirstBlock(block: PortableTextBlock): void {\n listItemFirstBlocks.add(block)\n}\n\nexport function consumeListItemFirstBlock(block: PortableTextBlock): boolean {\n const isListItemFirstBlock = listItemFirstBlocks.has(block)\n listItemFirstBlocks.delete(block)\n return isListItemFirstBlock\n}\n","import {\n buildMarksTree,\n isPortableTextBlock,\n isPortableTextListItemBlock,\n isPortableTextToolkitSpan,\n isPortableTextToolkitTextNode,\n spanToPlainText,\n type ToolkitNestedPortableTextSpan,\n type ToolkitTextNode,\n} from '@portabletext/toolkit'\nimport type {\n PortableTextBlock,\n PortableTextListItemBlock,\n PortableTextMarkDefinition,\n PortableTextSpan,\n TypedObject,\n} from '@portabletext/types'\nimport {planLeafEscaping} from './escape-plain-text'\nimport {\n consumeListItemFirstBlock,\n markListItemFirstBlock,\n} from './list-item-first-block'\nimport type {PortableTextRenderers, RenderNode, Serializable} from './types'\n\n/**\n * ATX headings are single-line, inline-only leaf blocks: an ATX heading's\n * first line sits inside its `# ` prefix and can never be reparsed as a\n * block construct, so line-leading hazards never apply there. A hard\n * break's later lines are ordinary markdown lines outside that prefix and\n * get the full line-start battery, same as any other block's continuation.\n */\nconst HEADING_STYLES = new Set(['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])\n\nexport const createRenderNode = (\n renderers: PortableTextRenderers,\n listIndexMap: Map<string, number>,\n listDepthMap: Map<string, number>,\n): RenderNode => {\n // Keyed by the actual `@text` node objects `buildMarksTree` produces, not\n // by render order: a custom type/mark renderer can call `renderNode` with\n // a synthetic node of its own mid-block (eg to render a placeholder), and\n // that call must not shift which escaped string a later real leaf gets.\n // A synthetic node was never planned, so it's absent from the map and\n // renders its own raw text.\n const escapedTextByNode = new WeakMap<ToolkitTextNode, string>()\n\n // Computed once per document render: a custom `hardBreak` can render to\n // something with no newline of its own (eg `() => '<br />'`), in which\n // case a `\\n` inside a span's text is not a real line boundary in the\n // rendered output, and `planLeafEscaping` needs to know that up front.\n const hardBreakOutputHasNewline = renderers.hardBreak().includes('\\n')\n\n // Shared by `renderBlock` and `renderListItem`, whatever the block's\n // style: both flatten `node.children` into the same text/mark tree and\n // need it escaped and keyed before rendering it.\n function renderBlockChildren(\n node: PortableTextBlock | PortableTextListItemBlock,\n isHeading: boolean,\n isListItem = false,\n ): string {\n const chunks = planLeafEscaping(node.children ?? [], node.markDefs ?? [], {\n isHeading,\n isListItem,\n hardBreakOutputHasNewline,\n })\n const tree = buildMarksTree(node)\n assignEscapedText(tree, chunks)\n\n return tree\n .map((child, i) =>\n renderNode({node: child, isInline: true, index: i, renderNode}),\n )\n .join('')\n }\n\n // Walks the tree in the same left-to-right, opaque-object-skipping order\n // `planLeafEscaping` used to produce `chunks`, so each `@text` leaf gets\n // keyed to the chunk planned for it.\n function assignEscapedText(\n nodes: ReadonlyArray<\n ToolkitNestedPortableTextSpan | ToolkitTextNode | TypedObject\n >,\n chunks: ReadonlyArray<string>,\n ): void {\n let pointer = 0\n\n const visit = (\n node: ToolkitNestedPortableTextSpan | ToolkitTextNode | TypedObject,\n ) => {\n if (isPortableTextToolkitTextNode(node)) {\n if (node.text !== '\\n') {\n const escaped = chunks[pointer]\n if (escaped !== undefined) {\n escapedTextByNode.set(node, escaped)\n }\n pointer++\n }\n return\n }\n\n if (isPortableTextToolkitSpan(node)) {\n node.children.forEach(visit)\n }\n }\n\n nodes.forEach(visit)\n }\n\n function renderNode<N extends TypedObject>(options: Serializable<N>): string {\n const {node, index, isInline} = options\n\n if (isPortableTextListItemBlock(node)) {\n return renderListItem(node, index)\n }\n\n if (isPortableTextToolkitSpan(node)) {\n return renderSpan(node)\n }\n\n if (isPortableTextBlock(node)) {\n return renderBlock(node, index, isInline, consumeListItemFirstBlock(node))\n }\n\n if (isPortableTextToolkitTextNode(node)) {\n return renderText(node)\n }\n\n return renderCustomBlock(node, index, isInline)\n }\n\n function renderListItem(\n node: PortableTextListItemBlock<\n PortableTextMarkDefinition,\n PortableTextSpan\n >,\n index: number,\n ): string {\n const renderer = renderers.listItem\n const handler =\n typeof renderer === 'function' ? renderer : renderer[node.listItem]\n const itemHandler = handler || renderers.unknownListItem\n\n let children: string\n\n if (node.style && node.style !== 'normal') {\n // Wrap any other style in whatever the block component says to use.\n // `renderNode` would recurse straight back into `renderListItem` if\n // `blockNode` still carried `listItem`, so it's stripped from the\n // copy; `markListItemFirstBlock` restores the list-item context\n // (line-start hazard escaping, the GFM checkbox prefix) onto that\n // same copy so `renderBlock` picks it up via `consumeListItemFirstBlock`.\n const {listItem: _listItem, ...blockNode} = node\n markListItemFirstBlock(blockNode)\n children = renderNode({\n node: blockNode,\n index,\n isInline: false,\n renderNode,\n })\n // Strip trailing newlines from block styles - list item component handles spacing\n children = children.replace(/\\n+$/, '')\n } else {\n children = renderBlockChildren(node, false, true)\n }\n\n return itemHandler({\n value: node,\n index,\n listIndex: node._key ? listIndexMap.get(node._key) : undefined,\n listDepth: node._key ? listDepthMap.get(node._key) : undefined,\n isInline: false,\n renderNode,\n children,\n })\n }\n\n function renderSpan(node: ToolkitNestedPortableTextSpan): string {\n const {markDef, markType, markKey} = node\n const span = renderers.marks[markType] || renderers.unknownMark\n const children = node.children.map((child, childIndex) =>\n renderNode({node: child, index: childIndex, isInline: true, renderNode}),\n )\n\n return span({\n text: spanToPlainText(node),\n value: markDef,\n markType,\n markKey,\n renderNode,\n children: children.join(''),\n })\n }\n\n function renderBlock(\n node: PortableTextBlock,\n index: number,\n isInline: boolean,\n isListItem: boolean,\n ): string {\n const style = node.style || 'normal'\n const children = renderBlockChildren(\n node,\n HEADING_STYLES.has(style),\n isListItem,\n )\n const handler =\n typeof renderers.block === 'function'\n ? renderers.block\n : renderers.block[style]\n const block = handler || renderers.unknownBlockStyle\n\n return block({index, isInline, children, value: node, renderNode})\n }\n\n function renderText(node: ToolkitTextNode): string {\n if (node.text === '\\n') {\n return renderers.hardBreak()\n }\n\n return escapedTextByNode.get(node) ?? node.text\n }\n\n function renderCustomBlock(\n value: TypedObject,\n index: number,\n isInline: boolean,\n ): string {\n const component = renderers.types[value._type] ?? renderers.unknownType\n\n return component({\n value,\n isInline,\n index,\n renderNode,\n })\n }\n\n return renderNode\n}\n","import {\n isPortableTextBlock,\n isPortableTextListItemBlock,\n} from '@portabletext/toolkit'\nimport type {TypedObject} from '@portabletext/types'\n\n/**\n * @public\n */\nexport type BlockSpacingRenderer = (options: {\n current: TypedObject\n next: TypedObject\n}) => string | undefined\n\n/**\n * @public\n */\nexport const DefaultBlockSpacingRenderer: BlockSpacingRenderer = ({\n current,\n next,\n}) => {\n if (\n isPortableTextListItemBlock(current) &&\n isPortableTextListItemBlock(next)\n ) {\n return '\\n'\n }\n\n if (\n isPortableTextBlock(current) &&\n isPortableTextBlock(next) &&\n current.style === 'blockquote' &&\n next.style === 'blockquote'\n ) {\n return '\\n>\\n'\n }\n\n return '\\n\\n'\n}\n","/**\n * @public\n */\nexport const DefaultHardBreakRenderer = (): string => ' \\n'\n","import type {PortableTextListItemRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultListItemRenderer: PortableTextListItemRenderer = ({\n children,\n value,\n listIndex,\n listDepth,\n}) => {\n const listStyle = value.listItem || 'bullet'\n const depth = listDepth ?? (value.level || 1) - 1\n const indent = ' '.repeat(depth)\n\n if (listStyle === 'number') {\n return `${indent}${listIndex ?? 1}. ${children}`\n }\n\n if (listStyle === 'task') {\n const checked =\n 'checked' in value && typeof value.checked === 'boolean'\n ? value.checked\n : false\n const marker = checked ? '[x]' : '[ ]'\n return `${indent}- ${marker} ${children}`\n }\n\n return `${indent}- ${children}`\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownListItemRenderer: PortableTextListItemRenderer = ({\n children,\n}) => {\n return `- ${children}\\n`\n}\n","/**\n * Escapes special characters in image alt texts and link texts.\n */\nexport function escapeImageAndLinkText(text: string): string {\n return text.replace(/([[\\]\\\\])/g, '\\\\$1')\n}\n\n/**\n * Unescapes special characters in image alt texts and link texts.\n */\nexport function unescapeImageAndLinkText(text: string): string {\n return text.replace(/\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g, '$1')\n}\n\n/**\n * Escapes special characters in image/link titles (the part inside quotes).\n */\nexport function escapeImageAndLinkTitle(text: string): string {\n return text.replace(/([\\\\\"])/g, '\\\\$1')\n}\n\n/**\n * Escapes characters that have special meaning at the row level of a GFM\n * table cell.\n *\n * A literal `|` ends the cell, so a pipe preceded by an even number of\n * backslashes (including zero) gets one more: paired backslashes cancel\n * out to a literal backslash and leave the pipe live, so parity, not mere\n * presence, decides whether it is already escaped. Newlines end the row,\n * so they are replaced with `<br>` to keep the visible line break inside\n * the cell.\n *\n * Backslashes themselves are left alone here; only the parity check reads\n * them, so escapes already in the rendered cell (such as `\\[` and `\\]` in\n * link text) survive the pass untouched.\n */\nexport function escapeTableCell(text: string): string {\n return text\n .replace(/(\\\\*)\\|/g, (match, backslashes: string) =>\n backslashes.length % 2 === 0 ? `${backslashes}\\\\|` : match,\n )\n .replace(/\\n/g, '<br>')\n}\n","import type {TypedObject} from '@portabletext/types'\nimport {escapeImageAndLinkTitle} from '../../escape'\nimport type {PortableTextMarkRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultEmRenderer: PortableTextMarkRenderer = ({children}) =>\n `_${children}_`\n\n/**\n * @public\n */\nexport const DefaultStrongRenderer: PortableTextMarkRenderer = ({children}) =>\n `**${children}**`\n\n/**\n * Renders a `code` decorator from the raw span text, bypassing the escaped\n * `children`: code content is verbatim, never markdown syntax. The\n * backtick fence is widened past the longest run of backticks already in\n * the text (CommonMark: the fence must be longer than any run it encloses).\n *\n * A space is padded on each side when the content starts or ends with a\n * backtick, so the fence and the content's own backtick never merge into\n * one run, and also when the content starts and ends with a space and\n * isn't all whitespace (`text.trim() !== ''`; an all-space code span has\n * nothing else for CommonMark's strip rule to leave behind, so padding it\n * would only add visible spaces), because CommonMark itself would\n * otherwise strip one such space per side on reparse; the padding\n * pre-compensates for that strip.\n *\n * @public\n */\nexport const DefaultCodeRenderer: PortableTextMarkRenderer = ({text}) =>\n wrapInCodeSpan(text)\n\nexport function wrapInCodeSpan(text: string): string {\n const fence = '`'.repeat(longestBacktickRun(text) + 1)\n const touchesBacktick = text.startsWith('`') || text.endsWith('`')\n const wouldBeStripped =\n text.startsWith(' ') && text.endsWith(' ') && text.trim() !== ''\n const padding = touchesBacktick || wouldBeStripped ? ' ' : ''\n return `${fence}${padding}${text}${padding}${fence}`\n}\n\nfunction longestBacktickRun(text: string): number {\n let longest = 0\n for (const run of text.match(/`+/g) ?? []) {\n longest = Math.max(longest, run.length)\n }\n return longest\n}\n\n/**\n * @public\n */\nexport const DefaultUnderlineRenderer: PortableTextMarkRenderer = ({\n children,\n}) => `<u>${children}</u>`\n\n/**\n * @public\n */\nexport const DefaultStrikeThroughRenderer: PortableTextMarkRenderer = ({\n children,\n}) => `~~${children}~~`\n\ninterface DefaultLink extends TypedObject {\n _type: 'link'\n href: string\n title: string | undefined\n}\n\n/**\n * @public\n */\nexport const DefaultLinkRenderer: PortableTextMarkRenderer<DefaultLink> = ({\n children,\n value,\n}) => {\n const href = value?.href || ''\n const title = value?.title || ''\n const looksSafe = uriLooksSafe(href)\n\n if (looksSafe) {\n // Check if the URL looks like an HTML injection attempt\n // If it has quotes AND angle brackets, or other suspicious patterns, encode more aggressively\n const looksLikeInjection = /[\"'][^\"']*[<>]|[<>][^<>]*[\"']/.test(href)\n\n if (looksLikeInjection) {\n // Encode all special characters that could be used for injection\n const encodedHref = href.replace(/[\"<>() ]/g, (char) => {\n return `%${char.charCodeAt(0).toString(16).toUpperCase()}`\n })\n return `[${children}](${encodedHref})`\n }\n\n // For normal URLs, don't encode parentheses - Markdown handles balanced parens fine\n return `[${children}](${href}${title ? ` \"${escapeImageAndLinkTitle(title)}\"` : ''})`\n }\n\n // Return children without link when URL is unsafe\n return children\n}\n\nfunction uriLooksSafe(uri: string): boolean {\n const url = (uri || '').trim()\n const first = url.charAt(0)\n\n if (first === '#' || first === '/') {\n return true\n }\n\n const colonIndex = url.indexOf(':')\n if (colonIndex === -1) {\n return true\n }\n\n const allowedProtocols = ['http', 'https', 'mailto', 'tel']\n const proto = url.slice(0, colonIndex).toLowerCase()\n if (allowedProtocols.indexOf(proto) !== -1) {\n return true\n }\n\n const queryIndex = url.indexOf('?')\n if (queryIndex !== -1 && colonIndex > queryIndex) {\n return true\n }\n\n const hashIndex = url.indexOf('#')\n if (hashIndex !== -1 && colonIndex > hashIndex) {\n return true\n }\n\n return false\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownMarkRenderer: PortableTextMarkRenderer = ({\n children,\n}) => {\n return children\n}\n","import type {PortableTextBlock} from '@portabletext/types'\nimport type {PortableTextRenderer} from '../types'\n\ntype PortableTextBlockRenderer = PortableTextRenderer<PortableTextBlock>\n\n/**\n * @public\n */\nexport const DefaultNormalRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n // Empty blocks should not add extra spacing\n if (!children || children.trim() === '') {\n return ''\n }\n\n return children\n}\n\n/**\n * @public\n */\nexport const DefaultBlockquoteRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n // Prefix each line with \"> \" for proper blockquote formatting\n // This handles multi-line content and preserves empty lines\n if (!children) {\n return '>'\n }\n\n return children\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n')\n}\n\n/**\n * @public\n */\nexport const DefaultH1Renderer: PortableTextBlockRenderer = ({children}) =>\n `# ${children}`\n\n/**\n * @public\n */\nexport const DefaultH2Renderer: PortableTextBlockRenderer = ({children}) =>\n `## ${children}`\n\n/**\n * @public\n */\nexport const DefaultH3Renderer: PortableTextBlockRenderer = ({children}) =>\n `### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH4Renderer: PortableTextBlockRenderer = ({children}) =>\n `#### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH5Renderer: PortableTextBlockRenderer = ({children}) =>\n `##### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH6Renderer: PortableTextBlockRenderer = ({children}) =>\n `###### ${children}`\n\n/**\n * @public\n */\nexport const DefaultUnknownStyleRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n return children ?? ''\n}\n","import {isTypedObject} from '@portabletext/schema'\nimport {isPortableTextBlock} from '@portabletext/toolkit'\nimport type {PortableTextBlock, TypedObject} from '@portabletext/types'\nimport {\n escapeImageAndLinkText,\n escapeImageAndLinkTitle,\n escapeTableCell,\n} from '../../escape'\nimport {markListItemFirstBlock} from '../list-item-first-block'\nimport type {PortableTextTypeRenderer} from '../types'\nimport {wrapInCodeSpan} from './marks'\n\n/**\n * @public\n */\nexport const DefaultCodeBlockRenderer: PortableTextTypeRenderer<{\n _type: 'code'\n code: string\n language: string | undefined\n}> = (options) => {\n if (!isCodeShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n return `\\`\\`\\`${normalizeLanguage(options.value.language)}\\n${options.value.code}\\n\\`\\`\\``\n}\n\nfunction isCodeShaped(value: unknown): value is {code: string} {\n return typeof (value as {code?: unknown} | null)?.code === 'string'\n}\n\n/**\n * A fence info string is everything after the opening fence on the same\n * line, so a real `language` can never contain a newline, and the parser\n * only ever produces a string. Junk in this optional field should not send\n * an otherwise valid code block to the fenced-JSON path, so it is treated\n * as absent instead of guarded.\n */\nfunction normalizeLanguage(language: unknown): string {\n if (typeof language !== 'string' || language.includes('\\n')) {\n return ''\n }\n if (language === 'json:object') {\n // `json:object` is reserved as the object carrier: a code block\n // emitting it as its info string would re-parse as the embedded\n // object whenever its content happens to be typed JSON, destroying\n // the code block. The language degrades to absent instead.\n return ''\n }\n return language\n}\n\n/**\n * @public\n */\nexport const DefaultHorizontalRuleRenderer: PortableTextTypeRenderer = () => {\n return '---'\n}\n\n/**\n * @public\n */\nexport const DefaultHtmlRenderer: PortableTextTypeRenderer<{\n _type: 'html'\n html: string\n}> = (options) => {\n if (!isHtmlShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n return options.value.html\n}\n\nfunction isHtmlShaped(value: unknown): value is {html: string} {\n return typeof (value as {html?: unknown} | null)?.html === 'string'\n}\n\n/**\n * @public\n */\nexport const DefaultImageRenderer: PortableTextTypeRenderer<{\n _type: 'image'\n src: string\n alt: string | undefined\n title: string | undefined\n}> = (options) => {\n if (!isImageShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n const alt = escapeImageAndLinkText(options.value.alt ?? '')\n const title = options.value.title\n ? ` \"${escapeImageAndLinkTitle(options.value.title)}\"`\n : ''\n return ``\n}\n\nfunction isImageShaped(value: unknown): value is {\n src: string\n alt: string | null | undefined\n title: string | null | undefined\n} {\n const image = value as {src?: unknown; alt?: unknown; title?: unknown} | null\n return (\n typeof image?.src === 'string' &&\n // CMS payloads commonly store cleared optional strings as `null`; the\n // render body treats `null` like absent, so the guard must too\n (image.alt == null || typeof image.alt === 'string') &&\n (image.title == null || typeof image.title === 'string')\n )\n}\n\n/**\n * A table is table-shaped when everything the renderer dereferences is\n * there: `rows` an array of typed objects with a `cells` array, every cell\n * a typed object whose `value` array holds typed objects (`renderNode`'s\n * input contract). The predicate narrows to exactly what `renderTable`\n * consumes, so the renderer needs no casts. A malformed `table` value\n * (e.g. a consumer's differently-shaped `table` type) falls back to the\n * fenced-JSON path instead of throwing.\n */\nfunction isTableShaped(value: unknown): value is TableShaped {\n const rows = (value as {rows?: unknown} | null)?.rows\n return (\n Array.isArray(rows) &&\n rows.every(\n (row) =>\n isTypedObject(row) &&\n Array.isArray(row['cells']) &&\n row['cells'].every(\n (cell) =>\n isTypedObject(cell) &&\n Array.isArray(cell['value']) &&\n cell['value'].every(isTypedObject),\n ),\n )\n )\n}\n\ntype TableShaped = {\n headerRows?: unknown\n alignment?: unknown\n rows: Array<{cells: Array<{value: Array<TypedObject>}>}>\n}\n\n/**\n * Renders a Portable Text table block-object back to Markdown.\n *\n * The PT `headerRows` field decides the header. Missing `headerRows` and\n * `headerRows === 0` both render headerless: GFM has no headerless form, so\n * an empty header row is emitted and every row goes in the body (that empty\n * header reads back as `headerRows: 0` via `markdownToPortableText`).\n * `headerRows >= 1` promotes `rows[0]` to the header. GFM allows exactly one\n * header row, so header rows beyond the first flatten into the body, lossy,\n * but the extra rows stay on the Portable Text side.\n *\n * Asymmetric tables (rows of varying cell counts) are widened to match\n * the row with the most cells. Narrower rows are padded with empty cells\n * so a GFM parser doesn't silently drop the extra cells in wider rows.\n *\n * @public\n */\nexport const DefaultTableRenderer: PortableTextTypeRenderer<{\n _type: 'table'\n headerRows: number | undefined\n alignment: Array<'left' | 'center' | 'right' | null> | undefined\n rows: Array<{\n _key: string\n cells: Array<{\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n}> = (options) => {\n const {value, renderNode} = options\n\n if (!isTableShaped(value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n\n return renderTable(value, renderNode)\n}\n\nfunction renderTable(\n value: TableShaped,\n renderNode: Parameters<PortableTextTypeRenderer>[0]['renderNode'],\n): string {\n const rows = value.rows\n // `alignment` is an extension field, not part of the table shape: junk\n // here should not send an otherwise valid table to the fenced-JSON path,\n // so it is normalized away instead of guarded (`{}.at` would throw below).\n const alignment: ReadonlyArray<unknown> | undefined = Array.isArray(\n value.alignment,\n )\n ? value.alignment\n : undefined\n\n const headerRow = rows.at(0)\n\n if (!headerRow) {\n return ''\n }\n\n // Helper to extract text from cell blocks\n const getCellText = (cellBlocks: Array<TypedObject>): string => {\n return cellBlocks\n .map((block, index) =>\n renderNode({\n node: block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join(' ')\n .trim()\n }\n\n const lines: string[] = []\n\n // GFM requires every row to have the same number of cells as the header row\n // and the delimiter row. Parsers silently drop excess cells from body rows\n // that are wider than the header, so we widen the table to the widest row\n // and pad narrower rows with empty cells to keep all data visible.\n const columnCount = rows.reduce(\n (max, row) => Math.max(max, row.cells.length),\n 0,\n )\n\n const renderCells = (texts: Array<string>): string => {\n const padded = [...texts]\n while (padded.length < columnCount) {\n padded.push('')\n }\n return `| ${padded.join(' | ')} |`\n }\n\n const renderRow = (cells: typeof headerRow.cells): string =>\n renderCells(cells.map((cell) => escapeTableCell(getCellText(cell.value))))\n\n // Delimiter row, sized to the column count. Each cell's colons encode the\n // column's alignment as defined by `value.alignment[columnIndex]`.\n const separators = Array.from({length: columnCount}, (_, index) => {\n const align = alignment?.at(index)\n if (align === 'left') {\n return ' :--- '\n }\n if (align === 'center') {\n return ' :---: '\n }\n if (align === 'right') {\n return ' ---: '\n }\n return ' --- '\n })\n const delimiter = `|${separators.join('|')}|`\n\n const hasHeader = (Number(value.headerRows) || 0) >= 1\n\n if (!hasHeader) {\n // Headerless table: emit an empty header row and keep every row in the\n // body.\n lines.push(renderCells([]))\n lines.push(delimiter)\n for (const row of rows) {\n lines.push(renderRow(row.cells))\n }\n } else {\n // `rows[0]` is the header. Header rows beyond the first flatten into the\n // body (GFM has a single header row).\n lines.push(renderRow(headerRow.cells))\n lines.push(delimiter)\n for (let i = 1; i < rows.length; i++) {\n const row = rows.at(i)\n if (row) {\n lines.push(renderRow(row.cells))\n }\n }\n }\n\n return lines.join('\\n')\n}\n\n/**\n * @public\n */\nexport const DefaultCalloutRenderer: PortableTextTypeRenderer<{\n _type: 'callout'\n tone: string\n content: Array<PortableTextBlock>\n}> = (options) => {\n if (!isCalloutShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n const {renderNode} = options\n const renderedContent = options.value.content\n .map((block, index) =>\n renderNode({\n node: block._type === 'block' ? {...block, style: 'normal'} : block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join('\\n\\n')\n\n const prefixed = renderedContent\n .split('\\n')\n .map((line) => (line === '' ? '>' : `> ${line}`))\n .join('\\n')\n\n return `> [!${options.value.tone.toUpperCase()}]\\n${prefixed}`\n}\n\nfunction isCalloutShaped(\n value: unknown,\n): value is {tone: string; content: Array<TypedObject>} {\n const callout = value as {tone?: unknown; content?: unknown} | null\n return (\n typeof callout?.tone === 'string' &&\n Array.isArray(callout.content) &&\n callout.content.every(isTypedObject)\n )\n}\n\n/**\n * Renders a structural blockquote block-object (the `types.blockquote` shape\n * produced by `markdownToPortableText` when a `types.blockquote` matcher is\n * provided) back to Markdown. Each content block is rendered via the\n * recursive renderer pipeline, joined with blank lines, and every line is\n * prefixed with `> ` to form a Markdown blockquote.\n *\n * Distinct from `DefaultBlockquoteRenderer`, which renders flat-path text\n * blocks with `style: 'blockquote'`.\n *\n * @public\n */\nexport const DefaultBlockquoteObjectRenderer: PortableTextTypeRenderer<{\n _type: 'blockquote'\n content: Array<PortableTextBlock>\n}> = ({value, renderNode}) => {\n const renderedContent = value.content\n .map((block, index) =>\n renderNode({\n node: block._type === 'block' ? {...block, style: 'normal'} : block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join('\\n\\n')\n\n return renderedContent\n .split('\\n')\n .map((line) => (line === '' ? '>' : `> ${line}`))\n .join('\\n')\n}\n\n/**\n * Renders a structural list block-object (the `types.list` shape produced by\n * `markdownToPortableText` when a `types.list` matcher is provided) back to\n * Markdown. Items render as `- ` for `kind: 'bullet'`, `1. `/`2. ` for `'number'`,\n * and `- [x] ` / `- [ ] ` for `'task'`. Items can hold any blocks - text blocks,\n * code blocks, callouts, images, and nested lists - and content other than the\n * leading text block is indented to keep it inside the item.\n *\n * @public\n */\nexport const DefaultListRenderer: PortableTextTypeRenderer<{\n _type: 'list'\n kind: 'bullet' | 'number' | 'task'\n items: Array<{\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | TypedObject>\n }>\n}> = ({value, renderNode}) => {\n // A list is \"loose\" when any item carries multiple non-list-block\n // content entries (a continuation paragraph, a code block, etc).\n // CommonMark uses blank lines between items in loose lists; tight lists\n // pack items together with single newlines. A nested list as a second\n // child of an item does NOT make the list loose, so we ignore those when\n // counting.\n const isLoose = value.items.some((item) => {\n const nonNestedBlocks = item.content.filter(\n (block) => (block as TypedObject)._type !== 'list',\n )\n return nonNestedBlocks.length > 1\n })\n const itemSeparator = isLoose ? '\\n\\n' : '\\n'\n\n const lines = value.items.map((item, itemIndex) => {\n const marker = getListMarker(value.kind, itemIndex, item.checked)\n // Continuation indent matches the marker's width so that subsequent\n // blocks attach to this item under CommonMark's lazy-continuation rule.\n // Bullet `- ` indents to 2; ordered `1. ` indents to 3, `10. ` to 4.\n // Task `- [x] ` is conceptually `- ` + a `[x] ` content prefix at the\n // markdown-it level, so its continuation indent stays at 2.\n const indentWidth = value.kind === 'task' ? 2 : marker.length\n const indent = ' '.repeat(indentWidth)\n\n const renderedBlocks = item.content.map((block, blockIndex) => {\n // Only the first block shares its first line with the marker (and,\n // for a task item, its GFM checkbox); later blocks render on their\n // own indented lines.\n if (blockIndex === 0 && isPortableTextBlock(block)) {\n markListItemFirstBlock(block)\n }\n return {\n isNestedList: (block as TypedObject)._type === 'list',\n text: renderNode({\n node: block as TypedObject,\n index: blockIndex,\n isInline: false,\n renderNode,\n }),\n }\n })\n\n const [first, ...rest] = renderedBlocks\n // Trim trailing whitespace from empty items so `- ` becomes `-`.\n const head = `${marker}${first?.text ?? ''}`.trimEnd()\n if (rest.length === 0) {\n return head\n }\n\n const tail = rest\n .map((rendered) => {\n const indented = rendered.text\n .split('\\n')\n .map((line) => (line === '' ? '' : `${indent}${line}`))\n .join('\\n')\n // Nested lists hug the previous block (tight list); other content\n // gets a blank line separator (paragraph break).\n return rendered.isNestedList ? `\\n${indented}` : `\\n\\n${indented}`\n })\n .join('')\n\n return `${head}${tail}`\n })\n\n return lines.join(itemSeparator)\n}\n\nfunction getListMarker(\n kind: 'bullet' | 'number' | 'task',\n itemIndex: number,\n checked: boolean | undefined,\n): string {\n if (kind === 'number') {\n return `${itemIndex + 1}. `\n }\n if (kind === 'task') {\n return checked ? '- [x] ' : '- [ ] '\n }\n return '- '\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownTypeRenderer: PortableTextTypeRenderer = ({\n value,\n isInline,\n}) => {\n if (isInline) {\n // Single-line JSON: code spans turn newlines into spaces on\n // reparse, so a pretty-printed payload would still reconstruct but\n // would not survive byte-identically, breaking the fixpoint.\n return `json:object${wrapInCodeSpan(JSON.stringify(value))}`\n }\n return `\\`\\`\\`json:object\\n${JSON.stringify(value, null, 2)}\\n\\`\\`\\``\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n TypedObject,\n} from '@portabletext/types'\nimport {buildListIndexMap} from './build-list-index-map'\nimport {createRenderNode} from './render-node'\nimport {\n DefaultBlockSpacingRenderer,\n type BlockSpacingRenderer,\n} from './renderers/block-spacing'\nimport {DefaultHardBreakRenderer} from './renderers/hard-break'\nimport {\n DefaultListItemRenderer,\n DefaultUnknownListItemRenderer,\n} from './renderers/list-item'\nimport {\n DefaultCodeRenderer,\n DefaultEmRenderer,\n DefaultLinkRenderer,\n DefaultStrikeThroughRenderer,\n DefaultStrongRenderer,\n DefaultUnderlineRenderer,\n DefaultUnknownMarkRenderer,\n} from './renderers/marks'\nimport {\n DefaultBlockquoteRenderer,\n DefaultH1Renderer,\n DefaultH2Renderer,\n DefaultH3Renderer,\n DefaultH4Renderer,\n DefaultH5Renderer,\n DefaultH6Renderer,\n DefaultNormalRenderer,\n DefaultUnknownStyleRenderer,\n} from './renderers/style'\nimport {\n DefaultCalloutRenderer,\n DefaultCodeBlockRenderer,\n DefaultHorizontalRuleRenderer,\n DefaultHtmlRenderer,\n DefaultImageRenderer,\n DefaultTableRenderer,\n DefaultUnknownTypeRenderer,\n} from './renderers/type'\nimport type {PortableTextRenderers} from './types'\n\nconst defaultRenderers: PortableTextRenderers = {\n types: {\n 'callout': DefaultCalloutRenderer,\n 'code': DefaultCodeBlockRenderer,\n 'horizontal-rule': DefaultHorizontalRuleRenderer,\n 'html': DefaultHtmlRenderer,\n 'image': DefaultImageRenderer,\n 'table': DefaultTableRenderer,\n },\n\n block: {\n normal: DefaultNormalRenderer,\n blockquote: DefaultBlockquoteRenderer,\n h1: DefaultH1Renderer,\n h2: DefaultH2Renderer,\n h3: DefaultH3Renderer,\n h4: DefaultH4Renderer,\n h5: DefaultH5Renderer,\n h6: DefaultH6Renderer,\n },\n marks: {\n 'em': DefaultEmRenderer,\n 'strong': DefaultStrongRenderer,\n 'code': DefaultCodeRenderer,\n 'underline': DefaultUnderlineRenderer,\n 'strike-through': DefaultStrikeThroughRenderer,\n 'link': DefaultLinkRenderer,\n },\n listItem: DefaultListItemRenderer,\n hardBreak: DefaultHardBreakRenderer,\n\n unknownType: DefaultUnknownTypeRenderer,\n unknownMark: DefaultUnknownMarkRenderer,\n unknownListItem: DefaultUnknownListItemRenderer,\n unknownBlockStyle: DefaultUnknownStyleRenderer,\n}\n\ntype Options = Partial<PortableTextRenderers> & {\n blockSpacing?: BlockSpacingRenderer\n}\n\n/**\n * @public\n */\nexport function portableTextToMarkdown<\n Block extends TypedObject = PortableTextBlock | ArbitraryTypedObject,\n>(blocks: Array<Block>, options: Options = {}): string {\n const renderers = {\n block: {\n ...defaultRenderers.block,\n ...options.block,\n },\n listItem: options.listItem ?? defaultRenderers.listItem,\n marks: {\n ...defaultRenderers.marks,\n ...options.marks,\n },\n types: {\n ...defaultRenderers.types,\n ...options.types,\n },\n hardBreak: options.hardBreak ?? defaultRenderers.hardBreak,\n unknownType: options.unknownType ?? defaultRenderers.unknownType,\n unknownBlockStyle:\n options.unknownBlockStyle ?? defaultRenderers.unknownBlockStyle,\n unknownListItem:\n options.unknownListItem ?? defaultRenderers.unknownListItem,\n unknownMark: options.unknownMark ?? defaultRenderers.unknownMark,\n }\n const renderBlockSpacing = options.blockSpacing ?? DefaultBlockSpacingRenderer\n\n const {listIndexMap, listDepthMap} = buildListIndexMap(blocks)\n const renderNode = createRenderNode(renderers, listIndexMap, listDepthMap)\n\n return blocks\n .map((node, index) => {\n const renderedNode = renderNode({\n node,\n index,\n isInline: false,\n renderNode,\n })\n\n if (index === blocks.length - 1) {\n return renderedNode\n }\n\n const nextNode = blocks.at(index + 1)\n\n if (!nextNode) {\n return renderedNode\n }\n\n const blockSpacing =\n renderBlockSpacing({\n current: node,\n next: nextNode,\n }) ?? '\\n\\n'\n\n return `${renderedNode}${blockSpacing}`\n })\n .join('')\n}\n","import {\n compileSchema,\n defineSchema,\n type AnnotationDefinition,\n type BlockObjectDefinition,\n type DecoratorDefinition,\n type ListDefinition,\n type StyleDefinition,\n} from '@portabletext/schema'\n\n/********************\n * Default style definitions\n ********************/\n\nexport const normalStyleDefinition = {\n name: 'normal',\n} as const satisfies StyleDefinition\n\nexport const h1StyleDefinition = {\n name: 'h1',\n} as const satisfies StyleDefinition\n\nexport const h2StyleDefinition = {\n name: 'h2',\n} as const satisfies StyleDefinition\n\nexport const h3StyleDefinition = {\n name: 'h3',\n} as const satisfies StyleDefinition\n\nexport const h4StyleDefinition = {\n name: 'h4',\n} as const satisfies StyleDefinition\n\nexport const h5StyleDefinition = {\n name: 'h5',\n} as const satisfies StyleDefinition\n\nexport const h6StyleDefinition = {\n name: 'h6',\n} as const satisfies StyleDefinition\n\nexport const blockquoteStyleDefinition = {\n name: 'blockquote',\n} as const satisfies StyleDefinition\n\n/********************\n * Default list definitions\n ********************/\n\nexport const defaultOrderedListItemDefinition = {\n name: 'number',\n} as const satisfies ListDefinition\n\nexport const defaultUnorderedListItemDefinition = {\n name: 'bullet',\n} as const satisfies ListDefinition\n\nexport const defaultTaskListItemDefinition = {\n name: 'task',\n} as const satisfies ListDefinition\n\n/********************\n * Default decorator definitions\n ********************/\n\nexport const defaultStrongDecoratorDefinition = {\n name: 'strong',\n} as const satisfies DecoratorDefinition\n\nexport const defaultEmDecoratorDefinition = {\n name: 'em',\n} as const satisfies DecoratorDefinition\n\nexport const defaultCodeDecoratorDefinition = {\n name: 'code',\n} as const satisfies DecoratorDefinition\n\nexport const defaultStrikeThroughDecoratorDefinition = {\n name: 'strike-through',\n} as const satisfies DecoratorDefinition\n\n/********************\n * Default annotation definitions\n ********************/\n\nexport const defaultLinkObjectDefinition = {\n name: 'link',\n fields: [\n {name: 'href', type: 'string'},\n {name: 'title', type: 'string'},\n ],\n} as const satisfies AnnotationDefinition\n\n/********************\n * Default object definitions\n ********************/\n\nexport const defaultCodeObjectDefinition = {\n name: 'code',\n fields: [\n {name: 'language', type: 'string'},\n {name: 'code', type: 'string'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultImageObjectDefinition = {\n name: 'image',\n fields: [\n {name: 'src', type: 'string'},\n {name: 'alt', type: 'string'},\n {name: 'title', type: 'string'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultHorizontalRuleObjectDefinition = {\n name: 'horizontal-rule',\n} as const satisfies BlockObjectDefinition\n\nexport const defaultHtmlObjectDefinition = {\n name: 'html',\n fields: [{name: 'html', type: 'string'}],\n} as const satisfies BlockObjectDefinition\n\n/**\n * Mirrors the canonical shape `@portabletext/plugin-table` expects: `table`\n * (`headerRows`, `rows`), `row` (`cells`), `cell` (`value`, text blocks or\n * standalone `image` objects). `alignment` is a `@portabletext/markdown`\n * extension field; `@portabletext/plugin-table` ignores it. Keep this in\n * sync with `packages/plugin-table/src/table-config.ts`'s\n * `defaultTableConfig`.\n */\nexport const defaultTableObjectDefinition = {\n name: 'table',\n fields: [\n {name: 'headerRows', type: 'number'},\n {name: 'alignment', type: 'array'},\n {\n name: 'rows',\n type: 'array',\n of: [\n {\n type: 'object',\n name: 'row',\n fields: [\n {\n name: 'cells',\n type: 'array',\n of: [\n {\n type: 'object',\n name: 'cell',\n fields: [\n {\n name: 'value',\n type: 'array',\n of: [{type: 'block'}, {type: 'image'}],\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultCalloutObjectDefinition = {\n name: 'callout',\n fields: [\n {name: 'tone', type: 'string'},\n {name: 'content', type: 'array'},\n ],\n} as const satisfies BlockObjectDefinition\n\n/**\n * The default schema for converting markdown to Portable Text.\n *\n * @public\n */\nexport const defaultSchema = compileSchema(\n defineSchema({\n block: {\n fields: [{name: 'checked', type: 'boolean'}],\n },\n styles: [\n normalStyleDefinition,\n h1StyleDefinition,\n h2StyleDefinition,\n h3StyleDefinition,\n h4StyleDefinition,\n h5StyleDefinition,\n h6StyleDefinition,\n blockquoteStyleDefinition,\n ],\n lists: [\n defaultOrderedListItemDefinition,\n defaultUnorderedListItemDefinition,\n defaultTaskListItemDefinition,\n ],\n decorators: [\n defaultStrongDecoratorDefinition,\n defaultEmDecoratorDefinition,\n defaultCodeDecoratorDefinition,\n defaultStrikeThroughDecoratorDefinition,\n ],\n annotations: [defaultLinkObjectDefinition],\n blockObjects: [\n defaultCalloutObjectDefinition,\n defaultCodeObjectDefinition,\n defaultHorizontalRuleObjectDefinition,\n defaultHtmlObjectDefinition,\n defaultImageObjectDefinition,\n defaultTableObjectDefinition,\n ],\n inlineObjects: [defaultImageObjectDefinition],\n }),\n)\n","import type {DegradationType} from './markdown-to-portable-text'\n\n/**\n * The full catalog of `Degradation['message']` prose, one entry per\n * `DegradationType`, grouped and ordered to match the union in\n * `markdown-to-portable-text.ts`. Kept apart from the conversion's\n * formatting mechanism (`buildDegradationMessage` and friends, in\n * `markdown-to-portable-text.ts`) so the catalog reads as one list instead\n * of being scattered across the walk that triggers it.\n *\n * `satisfies Record<DegradationType, ...>` makes the catalog exhaustive: a\n * new `DegradationType` member without a matching entry here is a type\n * error, caught at compile time instead of surfacing as an `undefined`\n * message at runtime.\n *\n * Style rule for every message here: a declarative statement of what\n * happened, never a verb that can parse as an imperative. A verb whose past\n * and imperative forms coincide (\"split\", \"set\", \"cut\", ...) never leads a\n * message, since the reader can't tell \"X was split\" from an instruction to\n * split X. State the effect first, the cause second, naming the schema\n * declaration that's missing.\n *\n * Not exported from the package entry: `message` is unstable by contract\n * (see `Degradation['message']`'s doc comment), so the catalog producing it\n * stays internal too.\n */\nexport const degradationMessage = {\n 'decorator-dropped': (\n decorator: 'code' | 'strong' | 'em' | 'strikeThrough',\n ): string => {\n switch (decorator) {\n case 'code':\n return 'Removed inline-code formatting, kept the text: the schema has no `code` decorator'\n case 'strong':\n return 'Removed bold formatting, kept the text: the schema has no `strong` decorator'\n case 'em':\n return 'Removed italic formatting, kept the text: the schema has no `em` decorator'\n case 'strikeThrough':\n return 'Removed strikethrough formatting, kept the text: the schema has no `strike-through` decorator'\n }\n },\n\n 'annotation-dropped': (cause: 'missing-url' | 'no-annotation'): string =>\n cause === 'missing-url'\n ? 'Removed a link that has no URL, kept its text'\n : 'Removed the link, kept its text: the schema has no `link` annotation',\n\n 'style-fallback': (name: string): string => {\n if (/^h[1-6]$/.test(name)) {\n const hashes = '#'.repeat(Number(name.slice(1)))\n return `\\`${hashes}\\` heading became a normal paragraph: the schema has no \\`${name}\\` style`\n }\n\n if (name === 'blockquote') {\n return 'Blockquote became normal paragraphs: the schema has no `blockquote` style'\n }\n\n return `Fell back to \\`normal\\` style: \\`${name}\\` not in schema`\n },\n\n 'list-flattened': (kind: 'bullet' | 'number'): string => {\n const label = kind === 'number' ? 'Numbered' : 'Bullet'\n return `${label} list became plain paragraphs: the schema has no \\`${kind}\\` list`\n },\n\n 'task-checkbox-stripped': (checked: boolean): string => {\n const checkbox = checked ? '[x]' : '[ ]'\n return `Removed the \\`${checkbox}\\` checkbox, kept a plain list item: the schema has no \\`task\\` list`\n },\n\n 'table-flattened':\n 'Table became plain text blocks, rows and columns lost: the schema has no `table` block object',\n\n 'code-block-to-text': (language: string | undefined): string =>\n language\n ? `\\`${language}\\` code block became plain text: the schema has no \\`code\\` block object`\n : `Code block became plain text: the schema has no \\`code\\` block object`,\n\n 'horizontal-rule-to-text':\n 'Horizontal rule became the text `---`: the schema has no `horizontal-rule` block object',\n\n 'html-block-to-text':\n 'HTML block became plain text: the schema has no `html` block object',\n\n 'inline-html-dropped':\n 'Removed inline HTML tags, kept nothing: `html.inline` is `skip` (the default)',\n\n 'image-block-to-inline': (cause: 'table-cell' | 'no-block-image'): string =>\n cause === 'table-cell'\n ? \"The image became inline: a table cell can't hold a block-level `image`\"\n : 'The image became inline: the schema has no block-level `image`',\n\n 'image-inline-to-block':\n 'The image became its own block, splitting the paragraph: the schema has no inline `image`',\n\n 'image-to-text':\n 'Image became its markdown source as plain text: the schema has no `image` object',\n\n 'callout-fallback': (calloutType: string, style: string): string =>\n `\\`[!${calloutType.toUpperCase()}]\\` callout became ${style}-styled text: the schema has no \\`callout\\` block object`,\n\n 'fields-dropped': (names: string, construct: string): string =>\n `Dropped ${names} from \\`${construct}\\`: not in the schema's \\`${construct}\\` fields`,\n\n 'object-carrier-invalid': (\n kind: 'fence' | 'code-span',\n payload: string,\n ): string =>\n kind === 'fence'\n ? `\\`json:object\\` fence fell back to a code block: ${describeObjectCarrierFailure(payload)}`\n : `\\`json:object\\`-tagged code span fell back to a plain code span: ${describeObjectCarrierFailure(payload)}`,\n} satisfies Record<DegradationType, string | ((...args: never[]) => string)>\n\n/**\n * Names why a `json:object` payload failed to parse as an object carrier:\n * a payload that isn't a JSON object at all reads differently from one\n * that is but has no usable `_type`.\n */\nfunction describeObjectCarrierFailure(payload: string): string {\n let parsed: unknown\n\n try {\n parsed = JSON.parse(payload)\n } catch {\n return 'the payload is not valid JSON'\n }\n\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return 'the payload is not a JSON object'\n }\n\n return 'the payload has no string `_type`'\n}\n","import type {\n PortableTextObject,\n Schema,\n SchemaDefinition,\n} from '@portabletext/schema'\n\n/**\n * Fields a default object/annotation matcher (`buildObjectMatcher`,\n * `buildAnnotationMatcher`) silently dropped while filtering a converted\n * value down to the schema's declared fields: the keys the conversion\n * supplied that the schema's field list doesn't declare, so they never made\n * it into the built object. Tagged onto the matcher's return value; read it\n * back with `readDroppedFields`. A consumer-supplied matcher's return value\n * never carries this: its own filtering, if any, is not this module's\n * business.\n */\nexport type DroppedFields = {\n construct: string\n keys: Array<string>\n}\n\nconst droppedFieldsTag = Symbol('droppedFields')\n\nexport function readDroppedFields(\n object: PortableTextObject | undefined,\n): DroppedFields | undefined {\n if (!object) {\n return undefined\n }\n return (object as unknown as Record<symbol, unknown>)[droppedFieldsTag] as\n | DroppedFields\n | undefined\n}\n\nfunction buildFilteredObject(\n schemaDefinition: {name: string; fields: ReadonlyArray<{name: string}>},\n value: Record<string, unknown>,\n keyGenerator: () => string,\n): PortableTextObject {\n const filteredValue = schemaDefinition.fields.reduce<Record<string, unknown>>(\n (filteredValue, field) => {\n const fieldValue = value[field.name]\n\n if (fieldValue !== undefined) {\n filteredValue[field.name] = fieldValue\n }\n\n return filteredValue\n },\n {},\n )\n\n const object = {\n _key: keyGenerator(),\n _type: schemaDefinition.name,\n ...filteredValue,\n }\n\n const suppliedKeys = Object.entries(value)\n .filter(([, fieldValue]) => fieldValue !== undefined)\n .map(([key]) => key)\n const droppedKeys = suppliedKeys.filter((key) => !(key in filteredValue))\n\n if (droppedKeys.length > 0) {\n Object.defineProperty(object, droppedFieldsTag, {\n value: {construct: schemaDefinition.name, keys: droppedKeys},\n enumerable: false,\n })\n }\n\n return object\n}\n\n/**\n * Matcher function for mapping markdown elements to Portable Text block styles.\n *\n * @public\n */\nexport type StyleMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildStyleMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): StyleMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.styles.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown list items to Portable Text list types.\n *\n * @public\n */\nexport type ListItemMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildListItemMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): ListItemMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.lists.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown inline formatting to Portable Text decorators.\n *\n * @public\n */\nexport type DecoratorMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildDecoratorMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): DecoratorMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.decorators.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown links to Portable Text annotations.\n *\n * @public\n */\nexport type AnnotationMatcher<\n TValue extends Record<string, unknown> = Record<string, never>,\n> = ({\n context,\n value,\n}: {\n context: {schema: Schema; keyGenerator: () => string}\n value: TValue\n}) => PortableTextObject | undefined\n\nexport function buildAnnotationMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): AnnotationMatcher<ExtractValue<TDefinition>> {\n return ({context, value}) => {\n const schemaDefinition = context.schema.annotations.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return buildFilteredObject(schemaDefinition, value, context.keyGenerator)\n }\n}\n\n/**\n * Matcher function for mapping markdown objects to Portable Text block or inline objects.\n *\n * @public\n */\nexport type ObjectMatcher<\n TValue extends Record<string, unknown> = Record<string, never>,\n> = ({\n context,\n value,\n isInline,\n}: {\n context: {schema: Schema; keyGenerator: () => string}\n value: TValue\n isInline: boolean\n}) => PortableTextObject | undefined\n\nexport function buildObjectMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): ObjectMatcher<ExtractValue<TDefinition>> {\n return ({context, value, isInline}) => {\n const schemaCollection = isInline\n ? context.schema.inlineObjects\n : context.schema.blockObjects\n\n const schemaDefinition = schemaCollection.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return buildFilteredObject(schemaDefinition, value, context.keyGenerator)\n }\n}\n\nexport type ExtractValue<\n TDefinition extends NonNullable<SchemaDefinition['blockObjects']>[0],\n> = TDefinition extends {fields: ReadonlyArray<{name: infer TNames}>}\n ? Record<TNames & string, unknown>\n : Record<string, never>\n","import {alert} from '@mdit/plugin-alert'\nimport {\n isSpan,\n isTextBlock,\n type PortableTextBlock,\n type PortableTextObject,\n type PortableTextTextBlock,\n type Schema,\n} from '@portabletext/schema'\nimport markdownit from 'markdown-it'\nimport {\n blockquoteStyleDefinition,\n defaultCalloutObjectDefinition,\n defaultCodeDecoratorDefinition,\n defaultCodeObjectDefinition,\n defaultEmDecoratorDefinition,\n defaultHorizontalRuleObjectDefinition,\n defaultHtmlObjectDefinition,\n defaultImageObjectDefinition,\n defaultLinkObjectDefinition,\n defaultOrderedListItemDefinition,\n defaultSchema,\n defaultStrikeThroughDecoratorDefinition,\n defaultStrongDecoratorDefinition,\n defaultTableObjectDefinition,\n defaultTaskListItemDefinition,\n defaultUnorderedListItemDefinition,\n h1StyleDefinition,\n h2StyleDefinition,\n h3StyleDefinition,\n h4StyleDefinition,\n h5StyleDefinition,\n h6StyleDefinition,\n normalStyleDefinition,\n} from '../default-schema'\nimport {unescapeImageAndLinkText} from '../escape'\nimport {defaultKeyGenerator} from '../key-generator'\nimport {degradationMessage} from './degradation-messages'\nimport {\n buildAnnotationMatcher,\n buildDecoratorMatcher,\n buildListItemMatcher,\n buildObjectMatcher,\n buildStyleMatcher,\n readDroppedFields,\n type AnnotationMatcher,\n type DecoratorMatcher,\n type ExtractValue,\n type ListItemMatcher,\n type ObjectMatcher,\n type StyleMatcher,\n} from './matchers'\n\n/**\n * The classification of a lossy conversion encountered while converting\n * markdown to Portable Text: a markdown construct the conversion couldn't\n * carry through losslessly, whether because the target schema (or the\n * active matchers) doesn't represent it, or because the surrounding\n * structure (a table cell, for instance) can't hold the shape markdown\n * expressed, so the conversion fell back to a lossier representation\n * instead of failing.\n *\n * @public\n */\nexport type DegradationType =\n | 'decorator-dropped'\n | 'annotation-dropped'\n | 'style-fallback'\n | 'list-flattened'\n | 'task-checkbox-stripped'\n | 'table-flattened'\n | 'code-block-to-text'\n | 'horizontal-rule-to-text'\n | 'html-block-to-text'\n | 'inline-html-dropped'\n | 'image-block-to-inline'\n | 'image-inline-to-block'\n | 'image-to-text'\n | 'callout-fallback'\n | 'fields-dropped'\n | 'object-carrier-invalid'\n\n/**\n * Reports a single lossy conversion, in encounter order: as the conversion\n * walks the markdown, that's the order nested constructs close in, not\n * necessarily top-to-bottom document order. `line` is the 1-based markdown\n * source line: usually the line of the token that degraded, but for a\n * token without its own line (an inline construct inside a table cell, for\n * instance) the enclosing construct's line instead; absent when no token\n * carries a usable line at all. `snippet` is the offending construct's\n * text, truncated to 40 characters with an ellipsis, present whenever the\n * degradation has a specific piece of source text to quote (a dropped\n * decorator's span, an unsupported image's alt text) and absent when the\n * construct has nothing to quote (a table with no `table` block object, a\n * callout whose type isn't in the schema). `message` is human-readable and\n * may change between releases; match on `type`, not `message`. The set of\n * `type` values grows in minor releases as new degradation sites report, so\n * compare against the values you handle rather than switching exhaustively.\n *\n * @public\n */\nexport type Degradation = {\n type: DegradationType\n message: string\n line?: number\n snippet?: string\n}\n\ntype Options = {\n schema?: Schema\n keyGenerator?: () => string\n /**\n * Called at most once, after the conversion has walked the whole\n * document, only when at least one construct degraded. Left unset, the\n * conversion stays silent and returns the lossiest representation it can\n * build. Passed a function, observe every degradation via\n * `report.degradations`, in encounter order. Enforce against lossy output by\n * throwing your own error from inside the callback, using\n * `report.message` (the canonical grouped text) as its message; the\n * throw propagates out of `markdownToPortableText`.\n *\n * ```ts\n * markdownToPortableText(markdown, {onDegradation: ({message}) => { throw new Error(message) }})\n * ```\n *\n * `report` is a single object, not positional parameters, so it can gain\n * fields later without a breaking change.\n */\n onDegradation?: (report: {\n degradations: Array<Degradation>\n message: string\n }) => void\n marks?: {\n strong?: DecoratorMatcher\n em?: DecoratorMatcher\n code?: DecoratorMatcher\n strikeThrough?: DecoratorMatcher\n link?: AnnotationMatcher<{href: string; title: string | undefined}>\n }\n block?: {\n normal?: StyleMatcher\n blockquote?: StyleMatcher\n h1?: StyleMatcher\n h2?: StyleMatcher\n h3?: StyleMatcher\n h4?: StyleMatcher\n h5?: StyleMatcher\n h6?: StyleMatcher\n }\n listItem?: {\n number?: ListItemMatcher\n bullet?: ListItemMatcher\n task?: ListItemMatcher\n }\n types?: {\n code?: ObjectMatcher<{language: string | undefined; code: string}>\n horizontalRule?: ObjectMatcher\n html?: ObjectMatcher<{html: string}>\n table?: ObjectMatcher<{\n headerRows: number | undefined\n alignment: Array<'left' | 'center' | 'right' | null> | undefined\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n }>\n image?: ObjectMatcher<{src: string; alt: string; title: string | undefined}>\n callout?: ObjectMatcher<{tone: string; content: Array<PortableTextBlock>}>\n blockquote?: ObjectMatcher<{content: Array<PortableTextBlock>}>\n list?: ObjectMatcher<{\n kind: 'bullet' | 'number' | 'task'\n items: Array<{\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | PortableTextObject>\n }>\n }>\n }\n html?: {\n /**\n * How to handle inline HTML.\n * - 'skip': Ignore inline HTML (default)\n * - 'text': Convert inline HTML to plain text\n *\n * @defaultValue 'skip'\n */\n inline?: 'skip' | 'text'\n }\n}\n\nconst codeBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultCodeObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultCodeObjectDefinition)\n const codeObject = defaultMatcher({context, value, isInline})\n\n if (!codeObject) {\n return undefined\n }\n\n if (!('code' in codeObject)) {\n return undefined\n }\n\n return codeObject\n}\n\nconst imageBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultImageObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultImageObjectDefinition)\n const imageObject = defaultMatcher({context, value, isInline})\n\n if (!imageObject) {\n return undefined\n }\n\n if (!('src' in imageObject)) {\n return undefined\n }\n\n return imageObject\n}\n\nconst tableBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultTableObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultTableObjectDefinition)\n const tableObject = defaultMatcher({context, value, isInline})\n\n if (!tableObject) {\n return undefined\n }\n\n if (!('rows' in tableObject)) {\n return undefined\n }\n\n return tableObject\n}\n\nconst defaultOptions = {\n schema: defaultSchema,\n keyGenerator: defaultKeyGenerator,\n html: {\n inline: 'skip',\n },\n block: {\n normal: buildStyleMatcher(normalStyleDefinition),\n blockquote: buildStyleMatcher(blockquoteStyleDefinition),\n h1: buildStyleMatcher(h1StyleDefinition),\n h2: buildStyleMatcher(h2StyleDefinition),\n h3: buildStyleMatcher(h3StyleDefinition),\n h4: buildStyleMatcher(h4StyleDefinition),\n h5: buildStyleMatcher(h5StyleDefinition),\n h6: buildStyleMatcher(h6StyleDefinition),\n },\n listItem: {\n number: buildListItemMatcher(defaultOrderedListItemDefinition),\n bullet: buildListItemMatcher(defaultUnorderedListItemDefinition),\n task: buildListItemMatcher(defaultTaskListItemDefinition),\n },\n marks: {\n strong: buildDecoratorMatcher(defaultStrongDecoratorDefinition),\n em: buildDecoratorMatcher(defaultEmDecoratorDefinition),\n code: buildDecoratorMatcher(defaultCodeDecoratorDefinition),\n strikeThrough: buildDecoratorMatcher(\n defaultStrikeThroughDecoratorDefinition,\n ),\n link: buildAnnotationMatcher(defaultLinkObjectDefinition),\n },\n types: {\n code: codeBlockMatcher,\n horizontalRule: buildObjectMatcher(defaultHorizontalRuleObjectDefinition),\n html: buildObjectMatcher(defaultHtmlObjectDefinition),\n image: imageBlockMatcher,\n callout: buildObjectMatcher(defaultCalloutObjectDefinition),\n table: tableBlockMatcher,\n },\n} as const satisfies Options\n\n/**\n * Reads GFM column alignment from a markdown-it cell token's `style`\n * attribute. Tolerates other CSS declarations sharing the value.\n */\nexport function extractAlignmentFromStyleAttr(\n styleAttr: string | null,\n): 'left' | 'center' | 'right' | null {\n if (!styleAttr) {\n return null\n }\n const match = styleAttr.match(/text-align\\s*:\\s*(left|center|right)/)\n if (!match) {\n return null\n }\n return match[1] as 'left' | 'center' | 'right'\n}\n\n/**\n * A table row is empty when every cell holds only blank spans, no non-empty\n * text, no inline objects, no non-text blocks. Used to detect a headerless\n * GFM table: `portableTextToMarkdown` emits an empty header row for\n * `headerRows: 0`, and an empty header must round-trip back to\n * `headerRows: 0` rather than a phantom header row.\n */\nfunction isEmptyTableRow(\n cells: Array<{value: Array<PortableTextBlock>}>,\n context: {schema: Schema},\n): boolean {\n return cells.every((cell) =>\n cell.value.every(\n (block) =>\n isTextBlock(context, block) &&\n block.children.every(\n (child) => isSpan(context, child) && (child.text ?? '').trim() === '',\n ),\n ),\n )\n}\n\n/**\n * Flattens a table structure by lifting all blocks from all cells.\n */\nfunction flattenTable(\n table: {\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n headerRows: number\n },\n portableText: Array<PortableTextBlock>,\n): void {\n // Flatten the table by lifting all blocks from all cells\n for (const row of table.rows) {\n for (const cell of row.cells) {\n for (const block of cell.value) {\n portableText.push(block)\n }\n }\n }\n}\n\n/**\n * Truncates a degradation message's snippet to keep the thrown/reported\n * message readable. Truncates on character count, not word boundaries: the\n * snippet is a diagnostic pointer back to the source, not prose. Undefined\n * for empty input, so a construct with nothing to quote (an empty link's\n * text, say) omits `snippet` entirely instead of reporting `\"\"`. Backs the\n * cut off by one unit when it would land on a lead surrogate, so a snippet\n * ending mid-emoji doesn't produce an unpaired surrogate. A literal newline\n * surviving into the snippet is escaped to `\\n`, since the reported message\n * is one line per finding.\n */\nfunction truncateSnippet(text: string, maxLength = 40): string | undefined {\n if (text.length === 0) {\n return undefined\n }\n\n if (text.length <= maxLength) {\n return text.replace(/\\n/g, '\\\\n')\n }\n\n let cut = maxLength\n const codeUnit = text.charCodeAt(cut - 1)\n if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) {\n cut -= 1\n }\n\n return `${text.slice(0, cut).replace(/\\n/g, '\\\\n')}...`\n}\n\n/**\n * Concatenates the plain text between an inline open token (`strong_open`,\n * `em_open`, `s_open`, `link_open`) and its matching close, for use as a\n * degradation message snippet. Tracks nesting depth so a same-type token\n * nested inside itself doesn't stop the scan at the wrong close.\n */\nfunction collectInlineText(\n children: ReadonlyArray<{type: string; content: string}>,\n openIndex: number,\n openType: string,\n closeType: string,\n): string {\n let depth = 1\n let text = ''\n for (let i = openIndex + 1; i < children.length; i++) {\n const child = children[i]\n if (!child) {\n continue\n }\n if (child.type === openType) {\n depth++\n } else if (child.type === closeType) {\n depth--\n if (depth === 0) {\n break\n }\n } else if (child.type === 'text') {\n text += child.content\n } else if (child.type === 'softbreak') {\n text += ' '\n } else if (child.type === 'hardbreak') {\n text += '\\n'\n }\n }\n return text\n}\n\n// A per-group snippet/line list longer than this is truncated with an\n// `and N more` tail: the grouped message is a one-line-per-finding summary,\n// not a full dump of every occurrence (that's what `degradations` is for).\nconst MAX_LISTED_PER_GROUP = 5\n\nfunction capList(values: ReadonlyArray<string>): string {\n if (values.length <= MAX_LISTED_PER_GROUP) {\n return values.join(', ')\n }\n const shown = values.slice(0, MAX_LISTED_PER_GROUP)\n const more = values.length - MAX_LISTED_PER_GROUP\n return `${shown.join(', ')}, and ${more} more`\n}\n\n/**\n * Builds the canonical grouped message reported alongside a non-empty\n * `degradations` array: identical (`type`, `message`) pairs collapse into one\n * line, so a document with the same missing decorator on three spans\n * doesn't repeat the same sentence three times. Groups sort by their\n * earliest-lined entry so the message reads top-to-bottom regardless of walk\n * order: nested constructs (a blockquote inside a blockquote, say) report\n * the innermost closing first even though it opened last, and that line may\n * arrive after another entry already in the group. Groups without any lined\n * entry sort last, in their relative encounter order.\n */\nfunction buildDegradationMessage(degradations: Array<Degradation>): string {\n const groups: Array<{\n base: string\n entries: Array<Degradation>\n }> = []\n const groupIndexByKey = new Map<string, number>()\n\n for (const degradation of degradations) {\n const key = `${degradation.type}\\u0000${degradation.message}`\n let groupIndex = groupIndexByKey.get(key)\n if (groupIndex === undefined) {\n groupIndex = groups.length\n groupIndexByKey.set(key, groupIndex)\n groups.push({base: degradation.message, entries: []})\n }\n groups[groupIndex]!.entries.push(degradation)\n }\n\n const minLine = (entries: Array<Degradation>): number | undefined => {\n const definedLines = entries\n .map((entry) => entry.line)\n .filter((line): line is number => line !== undefined)\n return definedLines.length > 0 ? Math.min(...definedLines) : undefined\n }\n\n const sortedGroups = [...groups].sort((a, b) => {\n const lineA = minLine(a.entries)\n const lineB = minLine(b.entries)\n if (lineA === undefined) {\n return lineB === undefined ? 0 : 1\n }\n if (lineB === undefined) {\n return -1\n }\n return lineA - lineB\n })\n\n const lines = sortedGroups.map((group) => {\n if (group.entries.length === 1) {\n const event = group.entries[0]!\n const snippetPart =\n event.snippet === undefined ? '' : ` (\"${event.snippet}\")`\n return event.line === undefined\n ? `- ${event.message}${snippetPart}`\n : `- line ${event.line}: ${event.message}${snippetPart}`\n }\n\n const snippets = group.entries\n .map((entry) => entry.snippet)\n .filter((snippet): snippet is string => snippet !== undefined)\n\n // Read top-to-bottom regardless of encounter order, same reasoning as\n // the group sort above. Entries without a line are counted but never\n // printed: joining a maybe-`undefined` would put the literal word\n // `undefined` in the message. Deduped: several entries in the group can\n // share one line (a table's cells, all pinned to the table's start\n // line), and the count already carries how many there were.\n const linesAscending = [\n ...new Set(\n group.entries\n .map((entry) => entry.line)\n .filter((line): line is number => line !== undefined)\n .sort((a, b) => a - b),\n ),\n ]\n\n const count = group.entries.length\n const suffix =\n snippets.length === count\n ? `(${count}\\u00d7: ${capList(snippets.map((snippet) => `\"${snippet}\"`))})`\n : linesAscending.length > 0\n ? `(${count}\\u00d7: lines ${capList(linesAscending.map(String))})`\n : `(${count}\\u00d7)`\n\n return `- ${group.base} ${suffix}`\n })\n\n return ['Markdown could not be converted without loss:', ...lines].join('\\n')\n}\n\n/**\n * Converts a markdown string to an array of Portable Text blocks.\n *\n * @public\n */\nexport function markdownToPortableText(\n markdown: string,\n options?: Options,\n): Array<PortableTextBlock> {\n const consolidatedOptions = {\n schema: options?.schema ?? defaultSchema,\n keyGenerator: options?.keyGenerator ?? defaultKeyGenerator,\n html: {\n inline: options?.html?.inline ?? 'skip',\n },\n marks: {\n ...defaultOptions.marks,\n ...options?.marks,\n },\n block: {\n ...defaultOptions.block,\n ...options?.block,\n },\n listItem: {\n ...defaultOptions.listItem,\n ...options?.listItem,\n },\n types: {\n ...defaultOptions.types,\n ...options?.types,\n },\n }\n\n const degradationEvents: Array<Degradation> = []\n\n const report = (event: Degradation): void => {\n degradationEvents.push(event)\n }\n\n // A markdown-it token's `map` is `[startLine, endLine)`, 0-based. Degradation\n // events report the 1-based start line for readability.\n const lineOf = (\n candidateToken: {map?: [number, number] | null} | null | undefined,\n ): number | undefined =>\n candidateToken?.map ? candidateToken.map[0] + 1 : undefined\n\n const reportStyleFallback = (\n name: string,\n line?: number,\n snippet?: string,\n ): void => {\n if (/^h[1-6]$/.test(name)) {\n const truncated =\n snippet === undefined ? undefined : truncateSnippet(snippet)\n report({\n type: 'style-fallback',\n message: degradationMessage['style-fallback'](name),\n line,\n snippet: truncated,\n })\n return\n }\n\n if (name === 'blockquote') {\n report({\n type: 'style-fallback',\n message: degradationMessage['style-fallback'](name),\n line,\n })\n return\n }\n\n report({\n type: 'style-fallback',\n message: degradationMessage['style-fallback'](name),\n line,\n })\n }\n\n // Only a default matcher (`buildObjectMatcher`, `buildAnnotationMatcher`)\n // tags its return value this way; a consumer-supplied matcher's output\n // passes through untouched, since its own filtering is its own business.\n const reportFieldsDropped = (\n object: PortableTextObject | undefined,\n line: number | undefined,\n ): void => {\n const dropped = readDroppedFields(object)\n if (!dropped) {\n return\n }\n const names = dropped.keys.map((key) => `\\`${key}\\``).join(', ')\n report({\n type: 'fields-dropped',\n message: degradationMessage['fields-dropped'](names, dropped.construct),\n line,\n })\n }\n\n const md = markdownit({\n html: true,\n linkify: true,\n typographer: false,\n })\n .enable(['strikethrough', 'table'])\n .use(alert)\n\n const tokens = md.parse(markdown, {})\n\n // Pre-pass: detect GFM task-list checkbox prefixes (`[ ]`, `[x]`, `[X]`)\n // on the first inline content of each list item. Strip the prefix from the\n // inline content and remember which list items are tasks (and their checked\n // state) so the main walk can apply `listItem: 'task'` and `checked` when\n // processing the corresponding `list_item_open` token.\n const taskCheckedByListItemIndex = new Map<number, boolean>()\n // The item's text (after the checkbox prefix is stripped below), for the\n // `task-checkbox-stripped` degradation message's snippet.\n const taskItemTextByListItemIndex = new Map<number, string>()\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]\n if (token?.type !== 'list_item_open') {\n continue\n }\n // Find the first inline token within this list item.\n let inlineIndex = -1\n for (let j = i + 1; j < tokens.length; j++) {\n const candidate = tokens[j]\n if (!candidate) {\n continue\n }\n if (candidate.type === 'list_item_close') {\n break\n }\n if (candidate.type === 'inline') {\n inlineIndex = j\n break\n }\n }\n if (inlineIndex === -1) {\n continue\n }\n const inlineToken = tokens[inlineIndex]\n if (!inlineToken) {\n continue\n }\n const match = inlineToken.content.match(/^\\[([ xX])\\] /)\n if (!match) {\n continue\n }\n const checked = match[1] !== ' '\n taskCheckedByListItemIndex.set(i, checked)\n // Strip the prefix from the content and the first child text token so the\n // resulting span doesn't include the checkbox marker.\n inlineToken.content = inlineToken.content.slice(match[0].length)\n taskItemTextByListItemIndex.set(i, inlineToken.content)\n const firstChild = inlineToken.children?.[0]\n if (firstChild && typeof firstChild.content === 'string') {\n firstChild.content = firstChild.content.slice(match[0].length)\n }\n }\n\n const portableText: Array<PortableTextBlock> = []\n\n // State\n let currentBlock: PortableTextTextBlock | null = null\n const currentListStack: Array<string | null> = []\n const markDefRefs: Array<string> = [] // mark keys: 'strong', 'em', 'code', or link keys\n let currentMarkDefs: Array<PortableTextObject> = []\n let currentBlockquoteStyle: string | null = null // Track blockquote style when inside blockquote\n let inListItem = false // Track if we're inside a list item\n // Provenance for `currentBlock`, set by `startBlock`'s caller: whether the\n // block's style was actually resolved through `currentBlockquoteStyle`\n // (a paragraph, say) rather than independently landing on the same value\n // by coincidence (a heading whose own style declined to the same\n // `normal` fallback). `flushBlock`'s callout gate reads this instead of\n // comparing styles, since two independent declines can resolve to the\n // same style name without either one being the other.\n let currentBlockTookBlockquoteStyle = false\n // Provenance for `currentBlock`: whether it was created to accumulate\n // paragraph text (a `paragraph_open`, or inline content starting a block\n // with no wrapper) as opposed to a dedicated single-purpose block (a\n // heading, a table cell, a code/HTML/hr fallback-to-text). A structural\n // list's decline fallback merges adjacent item content back into the flat\n // path's shape, and the flat path only ever merges accumulated paragraph\n // blocks: a fallback-to-text block always flushes and starts its own\n // block explicitly, never sharing `currentBlock` with surrounding text.\n let currentBlockIsPlainParagraph = false\n const plainParagraphBlocks = new WeakSet<PortableTextTextBlock>()\n\n // Callout state\n let calloutStartIndex: number | null = null\n let calloutStartTarget: Array<PortableTextBlock | PortableTextObject> | null =\n null\n let calloutType: string | null = null\n let calloutStartLine: number | undefined\n // Style names that declined while setting up the callout's content style,\n // reported once `alert_title` supplies the callout's own first line (the\n // marker, not the first content line `alert_open`'s map starts at).\n let calloutPendingStyleFallbacks: Array<string> = []\n\n // Blockquote container state. When `types.blockquote` is defined and the\n // parser enters a `blockquote_open`, a frame is pushed here. Block\n // emissions inside the surrounding open/close pair are captured and\n // spliced out at close to wrap them in a `blockquote` block-object.\n // Nested blockquotes push additional frames; `blockTarget()` already\n // routes correctly because the splice happens against the same target.\n const blockquoteStack: Array<{\n startTarget: Array<PortableTextBlock | PortableTextObject>\n startIndex: number\n line: number | undefined\n }> = []\n\n // Table state\n let currentTable: {\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n headerRows: number\n emptyHeaderDropped: boolean\n alignment: Array<'left' | 'center' | 'right' | null>\n line: number | undefined\n } | null = null\n let currentTableRow: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }> | null = null\n let inTableHead = false\n // Images demoted from block-level to inline while pushed into a table\n // cell (see the `inline` case). `td_close`/`th_close` may lift a sole\n // image child back to block-level losslessly; membership here lets that\n // lift decide whether to report the demotion, and the value carries which\n // cause to report it with (a schema-declared block image forced inline by\n // the cell vs. no block image in the schema at all).\n const demotedTableImages = new WeakMap<\n PortableTextObject,\n 'table-cell' | 'no-block-image'\n >()\n\n // List container state. When `types.list` is defined and the parser enters\n // a `bullet_list_open` / `ordered_list_open`, a structural-list frame is\n // pushed here. Block emissions inside the surrounding `list_item_open` /\n // `list_item_close` pair are diverted into the item's `content` array\n // instead of the top-level `portableText`. At list-close, the matcher is\n // called to materialize a `list` block-object, which is pushed into the\n // enclosing target (parent list item's content if nested, else top-level).\n type ListContainerItem = {\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | PortableTextObject>\n }\n type ListContainerFrame = {\n kind: 'bullet' | 'number' | 'task'\n items: Array<ListContainerItem>\n currentItem: ListContainerItem | null\n line: number | undefined\n }\n // A null entry marks a list that is being handled by the flat path (either\n // because `types.list` is undefined, or because a nested list inside a\n // flat-path list should also stay flat). Parallel to `currentListStack`.\n const listContainerStack: Array<ListContainerFrame | null> = []\n\n // Flat-path `list-flattened` verdicts, parallel to `currentListStack`: a\n // list whose own kind (`bullet`/`number`) isn't in the schema doesn't\n // necessarily degrade, since every item might still resolve through a\n // `task` checkbox override. The verdict is deferred to the first item\n // that actually needs the fallback (`list_item_open`'s `listType === null`\n // branch), so a schema with only a `task` list and an all-checkbox list\n // reports nothing. `null` marks a list whose own kind resolved fine, so no\n // verdict is pending.\n const pendingListFlattenedStack: Array<{\n line: number | undefined\n kindName: 'bullet' | 'number'\n reported: boolean\n } | null> = []\n\n // Per-item task-checkbox metadata for structural list items (line + text\n // snippet), keyed by item object identity. Not stored on the item itself:\n // `frame.items` is handed verbatim to a consumer's `types.list` matcher,\n // and this bookkeeping is only needed if that matcher declines and the\n // fallback needs to reproduce the flat path's `task-checkbox-stripped`\n // report for the item.\n const taskInfoByListItem = new WeakMap<\n ListContainerItem,\n {line: number | undefined; snippet: string | undefined}\n >()\n\n /**\n * Returns the array that block emissions should land in. If the innermost\n * structural list frame has an open `currentItem`, blocks land in that\n * item's `content`. Otherwise blocks land at the top level.\n */\n const blockTarget = (): Array<PortableTextBlock | PortableTextObject> => {\n for (let i = listContainerStack.length - 1; i >= 0; i--) {\n const frame = listContainerStack[i]\n if (frame && frame.currentItem) {\n return frame.currentItem.content\n }\n }\n return portableText\n }\n\n /**\n * Pushes a block into the current target (innermost open list item, or\n * top-level `portableText` if none). Use instead of direct\n * `portableText.push(...)` for any block emission that should be captured\n * by an enclosing list container.\n */\n const pushBlock = (block: PortableTextBlock | PortableTextObject): void => {\n blockTarget().push(block as PortableTextBlock)\n }\n\n const startBlock = (\n style: string,\n provenance?: {tookBlockquoteStyle?: boolean; isPlainParagraph?: boolean},\n ) => {\n flushBlock()\n currentBlock = {\n _type: 'block' as const,\n style,\n children: [],\n _key: consolidatedOptions.keyGenerator(),\n markDefs: [],\n }\n currentMarkDefs = []\n currentBlockTookBlockquoteStyle = provenance?.tookBlockquoteStyle ?? false\n currentBlockIsPlainParagraph = provenance?.isPlainParagraph ?? false\n }\n\n const flushBlock = () => {\n if (!currentBlock) {\n return\n }\n\n // A callout with pending style fallbacks (its own style resolution\n // declined) only actually degrades once a text block actually commits\n // needing that resolved style. A heading inside a callout commits with\n // its own heading style and never touches the callout's content style,\n // so it doesn't count; a plain paragraph does, since paragraphs adopt\n // `currentBlockquoteStyle` directly. A callout holding nothing but,\n // say, a standalone image discards its placeholder block without ever\n // reaching here (see the `inline` case's standalone-image branch), and\n // never degraded.\n if (\n calloutPendingStyleFallbacks.length > 0 &&\n currentBlockTookBlockquoteStyle\n ) {\n for (const name of calloutPendingStyleFallbacks) {\n reportStyleFallback(name, calloutStartLine)\n }\n calloutPendingStyleFallbacks = []\n }\n\n // Text blocks must have at least one child span\n if (currentBlock.children.length === 0) {\n currentBlock.children.push({\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: '',\n marks: [],\n })\n }\n\n // Assign accumulated markDefs to the block\n currentBlock.markDefs = currentMarkDefs\n\n if (currentBlockIsPlainParagraph) {\n plainParagraphBlocks.add(currentBlock)\n }\n\n pushBlock(currentBlock)\n\n currentBlock = null\n currentMarkDefs = []\n }\n\n const addSpan = (text: string) => {\n if (text.length === 0) {\n return\n }\n\n if (!currentBlock) {\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal')\n startBlock('normal', {isPlainParagraph: true})\n } else {\n startBlock(style, {\n tookBlockquoteStyle: currentBlockquoteStyle !== null,\n isPlainParagraph: true,\n })\n }\n }\n\n if (!currentBlock) {\n throw new Error('Expected current block')\n }\n\n const lastChild = currentBlock.children.at(-1)\n\n if (\n isSpan({schema: consolidatedOptions.schema}, lastChild) &&\n lastChild.marks?.every((mark) => markDefRefs.includes(mark)) &&\n markDefRefs.every((mark) => lastChild.marks?.includes(mark))\n ) {\n // Merge with previous span if marks match\n lastChild.text += text\n } else {\n currentBlock.children.push({\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: text,\n marks: [...markDefRefs],\n })\n }\n }\n\n // Helpers for lists\n const listLevel = () => currentListStack.length\n const ensureListBlock = (listItem: string, checked?: boolean) => {\n if (!currentBlock) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal')\n startBlock('normal')\n } else {\n startBlock(style, {\n tookBlockquoteStyle: currentBlockquoteStyle !== null,\n })\n }\n }\n\n if (!currentBlock) {\n throw new Error('Expected current block')\n }\n\n if (\n currentBlock.listItem !== listItem ||\n currentBlock.level !== listLevel()\n ) {\n currentBlock.listItem = listItem\n currentBlock.level = listLevel()\n }\n\n if (checked !== undefined) {\n ;(currentBlock as PortableTextTextBlock & {checked?: boolean}).checked =\n checked\n }\n }\n\n // Walk tokens\n for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {\n const token = tokens[tokenIndex]\n if (!token) {\n continue\n }\n\n switch (token.type) {\n // Paragraphs\n case 'paragraph_open': {\n // If we're in a list item but have no current block (e.g., after a code block),\n // we need to create a new list item block\n if (inListItem) {\n // Structural list path: start a plain text block; the paragraph\n // lands in the current list item's `content` via `pushBlock`.\n if (listContainerStack.at(-1)) {\n if (!currentBlock) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n }\n\n startBlock(style ?? 'normal', {\n tookBlockquoteStyle: currentBlockquoteStyle !== null,\n isPlainParagraph: true,\n })\n }\n break\n }\n\n // Flat list path: ensure the current text block carries\n // `listItem` + `level` fields.\n if (!currentBlock) {\n const listType = currentListStack.at(-1)\n\n if (listType) {\n ensureListBlock(listType)\n }\n }\n\n break\n }\n\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n startBlock('normal', {isPlainParagraph: true})\n break\n }\n\n startBlock(style, {\n tookBlockquoteStyle: currentBlockquoteStyle !== null,\n isPlainParagraph: true,\n })\n break\n }\n case 'paragraph_close':\n // In a flat list item: skip flushing, list_item_close will flush.\n // In a structural list item: flush so multiple paragraphs in one\n // item land as separate text blocks.\n if (inListItem) {\n if (listContainerStack.at(-1)) {\n flushBlock()\n }\n break\n }\n flushBlock()\n break\n\n // Headings\n case 'heading_open': {\n const level = Number(token?.tag?.slice(1))\n\n // Map level to the appropriate heading matcher\n const headingMatchers = {\n 1: consolidatedOptions.block.h1,\n 2: consolidatedOptions.block.h2,\n 3: consolidatedOptions.block.h3,\n 4: consolidatedOptions.block.h4,\n 5: consolidatedOptions.block.h5,\n 6: consolidatedOptions.block.h6,\n } as const\n\n const headingMatcher =\n headingMatchers[level as keyof typeof headingMatchers]\n\n const headingStyle = headingMatcher?.({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!headingStyle) {\n reportStyleFallback(\n `h${level}`,\n lineOf(token),\n tokens[tokenIndex + 1]?.content,\n )\n }\n\n const style =\n headingStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n startBlock('normal')\n break\n }\n\n startBlock(style)\n break\n }\n case 'heading_close':\n flushBlock()\n break\n\n // Blockquote\n case 'blockquote_open': {\n // Flush any current block before entering blockquote\n flushBlock()\n\n // Structural-blockquote path: when the consumer registers a\n // `types.blockquote` matcher, plain blockquotes (NOT GFM alerts -\n // those use separate `alert_open`/`alert_close` tokens) become\n // block-objects with an explicit `content` array. Block emissions\n // inside the open/close pair are spliced out at close time and\n // wrapped in a `blockquote` block-object.\n if (consolidatedOptions.types.blockquote) {\n const startTarget = blockTarget()\n blockquoteStack.push({\n startTarget,\n startIndex: startTarget.length,\n line: lineOf(token),\n })\n break\n }\n\n // Flat path: set the blockquote style for paragraphs inside the\n // blockquote so they emit text blocks with `style: 'blockquote'`.\n const blockquoteStyle = consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!blockquoteStyle) {\n reportStyleFallback('blockquote', lineOf(token))\n }\n\n const style =\n blockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n }\n\n currentBlockquoteStyle = style ?? 'normal'\n break\n }\n case 'blockquote_close': {\n // Flush any blockquote content before exiting\n flushBlock()\n\n // Structural path: pop the topmost frame and splice its captured\n // content into a `blockquote` block-object via the matcher. If the\n // matcher returns undefined, fall back to flat-style by re-emitting\n // the content blocks with `style: 'blockquote'`.\n if (\n consolidatedOptions.types.blockquote &&\n blockquoteStack.length > 0\n ) {\n const frame = blockquoteStack.pop()\n if (frame) {\n const contentBlocks = frame.startTarget.splice(\n frame.startIndex,\n ) as Array<PortableTextBlock>\n\n const blockquoteObject = consolidatedOptions.types.blockquote({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {content: contentBlocks},\n isInline: false,\n })\n\n if (blockquoteObject) {\n pushBlock(blockquoteObject)\n } else {\n // Matcher returned undefined: fall back to exactly what the\n // flat path would have produced (never registering\n // `types.blockquote` at all), including which events it would\n // have reported. Only plain paragraphs pick up the blockquote\n // style there; headings and fallback-to-text blocks (a\n // degraded code fence, say) keep whatever style they already\n // resolved to, so restyling is gated on `plainParagraphBlocks`\n // provenance, not the block's resolved style name.\n const blockquoteStyle = consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!blockquoteStyle) {\n reportStyleFallback('blockquote', frame.line)\n }\n\n const resolvedStyle =\n blockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!resolvedStyle) {\n reportStyleFallback('normal', frame.line)\n }\n\n const fallbackStyle = resolvedStyle ?? 'blockquote'\n for (const block of contentBlocks) {\n if (\n block._type === 'block' &&\n plainParagraphBlocks.has(block as PortableTextTextBlock)\n ) {\n const restyledBlock: PortableTextTextBlock = {\n ...(block as PortableTextTextBlock),\n style: fallbackStyle,\n }\n // The spread above makes a new object, so the enclosing\n // structural list's stampable gate (keyed on\n // `plainParagraphBlocks` object identity) would otherwise\n // lose this block's provenance across the restyle.\n plainParagraphBlocks.add(restyledBlock)\n pushBlock(restyledBlock)\n } else {\n pushBlock(block)\n }\n }\n }\n }\n break\n }\n\n currentBlockquoteStyle = null\n break\n }\n // Lists\n case 'bullet_list_open': {\n flushBlock()\n\n // Structural-container path: when the consumer registers a\n // `types.list` matcher, lists become block-objects with explicit\n // `items` arrays. Block emissions inside list items are diverted\n // into `currentItem.content` via `blockTarget()`. Mirrors the\n // `types.table` pattern.\n if (consolidatedOptions.types.list) {\n listContainerStack.push({\n kind: 'bullet',\n items: [],\n currentItem: null,\n line: lineOf(token),\n })\n currentListStack.push(null)\n pendingListFlattenedStack.push(null)\n break\n }\n\n // Flat path: lists are reconstructed from text blocks with\n // `listItem` + `level` fields at render time.\n const listItem = consolidatedOptions.listItem.bullet({\n context: {schema: consolidatedOptions.schema},\n })\n\n listContainerStack.push(null)\n if (!listItem) {\n pendingListFlattenedStack.push({\n line: lineOf(token),\n kindName: 'bullet',\n reported: false,\n })\n currentListStack.push(null)\n break\n }\n pendingListFlattenedStack.push(null)\n currentListStack.push(listItem)\n break\n }\n case 'ordered_list_open': {\n flushBlock()\n\n if (consolidatedOptions.types.list) {\n listContainerStack.push({\n kind: 'number',\n items: [],\n currentItem: null,\n line: lineOf(token),\n })\n currentListStack.push(null)\n pendingListFlattenedStack.push(null)\n break\n }\n\n const listItem = consolidatedOptions.listItem.number({\n context: {schema: consolidatedOptions.schema},\n })\n\n listContainerStack.push(null)\n if (!listItem) {\n pendingListFlattenedStack.push({\n line: lineOf(token),\n kindName: 'number',\n reported: false,\n })\n currentListStack.push(null)\n break\n }\n pendingListFlattenedStack.push(null)\n currentListStack.push(listItem)\n break\n }\n case 'bullet_list_close':\n case 'ordered_list_close': {\n const frame = listContainerStack.pop()\n currentListStack.pop()\n pendingListFlattenedStack.pop()\n\n // Structural close: materialize the list block-object and push it\n // into the enclosing target (parent list item's content if nested,\n // else top-level).\n if (frame && consolidatedOptions.types.list) {\n // Promote `kind` to 'task' if any item carries a checked state.\n const kind: 'bullet' | 'number' | 'task' = frame.items.some(\n (item) => 'checked' in item,\n )\n ? 'task'\n : frame.kind\n\n const listObject = consolidatedOptions.types.list({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {kind, items: frame.items},\n isInline: false,\n })\n\n if (listObject) {\n pushBlock(listObject)\n } else {\n // Matcher returned undefined: fall back to exactly what the\n // flat path would have produced for this same content (never\n // registering `types.list` at all), including which events it\n // would have reported. A decline whose mirrored flat form is\n // lossless (the schema has every list kind this list needs)\n // reports nothing: going structural and being declined isn't\n // itself a degradation, only losing information is.\n const kindListItem =\n (frame.kind === 'number'\n ? consolidatedOptions.listItem.number\n : consolidatedOptions.listItem.bullet)({\n context: {schema: consolidatedOptions.schema},\n }) ?? null\n const taskListItemType =\n consolidatedOptions.listItem.task?.({\n context: {schema: consolidatedOptions.schema},\n }) ?? null\n const kindName = frame.kind === 'number' ? 'number' : 'bullet'\n\n // The just-popped list was nested at depth = remaining stack\n // length + 1 (since we already popped).\n const level = listContainerStack.length + 1\n let flattenedReported = false\n\n for (const item of frame.items) {\n let itemListType: string | null = kindListItem\n let itemChecked: boolean | undefined\n\n if (item.checked !== undefined) {\n if (taskListItemType) {\n itemListType = taskListItemType\n itemChecked = item.checked\n } else if (kindListItem !== null) {\n const info = taskInfoByListItem.get(item)\n report({\n type: 'task-checkbox-stripped',\n message: degradationMessage['task-checkbox-stripped'](\n item.checked,\n ),\n line: info?.line,\n snippet: info?.snippet,\n })\n }\n }\n\n if (itemListType === null && !flattenedReported) {\n report({\n type: 'list-flattened',\n message: degradationMessage['list-flattened'](kindName),\n line: frame.line,\n })\n flattenedReported = true\n }\n\n // Adjacent plain-paragraph blocks within one item merge into\n // a single block, mirroring the flat path: consecutive\n // `paragraph_open`/`paragraph_close` pairs inside a flat list\n // item share one `currentBlock`, since only non-paragraph\n // content (headings, code blocks, ...) flushes it. Resets per\n // item: `list_item_close` always flushes in the flat path, so\n // a merge never crosses an item boundary. Gated on\n // `plainParagraphBlocks` (provenance, not shape): a\n // fallback-to-text block (a degraded code fence, say) never\n // shares `currentBlock` with surrounding text in the flat\n // path either, even when its style happens to match, and the\n // flat path never stamps it with `listItem` at all.\n let mergeTarget: PortableTextTextBlock | null = null\n\n for (const block of item.content) {\n const isStampable =\n itemListType !== null &&\n block._type === 'block' &&\n !('listItem' in block) &&\n !/^h[1-6]$/.test(\n (block as PortableTextTextBlock).style ?? '',\n ) &&\n plainParagraphBlocks.has(block as PortableTextTextBlock)\n\n if (!isStampable) {\n mergeTarget = null\n pushBlock(block)\n continue\n }\n\n const textBlock = block as PortableTextTextBlock\n if (mergeTarget && mergeTarget.style === textBlock.style) {\n mergeTarget.children.push(...textBlock.children)\n mergeTarget.markDefs = [\n ...(mergeTarget.markDefs ?? []),\n ...(textBlock.markDefs ?? []),\n ]\n continue\n }\n\n mergeTarget = {\n ...textBlock,\n listItem: itemListType as string,\n level,\n ...(itemChecked === undefined ? {} : {checked: itemChecked}),\n }\n pushBlock(mergeTarget)\n }\n }\n }\n }\n break\n }\n case 'list_item_open': {\n const frame = listContainerStack.at(-1)\n\n // Flush any previous list item block before starting a new one\n // This is needed for proper separation of list items\n if (currentBlock) {\n flushBlock()\n }\n\n // Structural path: start a new `list-item` whose `content` becomes\n // the divert target for subsequent block emissions until\n // `list_item_close`.\n if (frame) {\n const taskChecked = taskCheckedByListItemIndex.get(tokenIndex)\n frame.currentItem = {\n _type: 'list-item',\n _key: consolidatedOptions.keyGenerator(),\n ...(taskChecked === undefined ? {} : {checked: taskChecked}),\n content: [],\n }\n if (taskChecked !== undefined) {\n taskInfoByListItem.set(frame.currentItem, {\n line: lineOf(token),\n snippet: truncateSnippet(\n taskItemTextByListItemIndex.get(tokenIndex) ?? '',\n ),\n })\n }\n inListItem = true\n break\n }\n\n // Flat path\n const baseListType = currentListStack.at(-1)\n\n if (baseListType === undefined) {\n throw new Error('Expected an open list')\n }\n\n // Resolve task list type and checked state for this specific item.\n // If the schema declares a `task` list definition, GFM checkboxes\n // (`- [ ]` / `- [x]`) override the surrounding list's type for this\n // item. Otherwise the prefix has already been stripped by the\n // pre-pass and we render as the surrounding list type.\n const taskChecked = taskCheckedByListItemIndex.get(tokenIndex)\n let listType = baseListType\n let checked: boolean | undefined\n if (taskChecked !== undefined) {\n const taskListType = consolidatedOptions.listItem.task?.({\n context: {schema: consolidatedOptions.schema},\n })\n if (taskListType) {\n listType = taskListType\n checked = taskChecked\n }\n }\n\n // If listType is null, it means there's no list definition in the schema\n // Just create a normal block without list properties\n if (listType === null) {\n const pendingFlattened = pendingListFlattenedStack.at(-1)\n if (pendingFlattened && !pendingFlattened.reported) {\n report({\n type: 'list-flattened',\n message: degradationMessage['list-flattened'](\n pendingFlattened.kindName,\n ),\n line: pendingFlattened.line,\n })\n pendingFlattened.reported = true\n }\n\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n startBlock('normal')\n } else {\n startBlock(style, {\n tookBlockquoteStyle: currentBlockquoteStyle !== null,\n })\n }\n inListItem = true\n break\n }\n\n if (taskChecked !== undefined && checked === undefined) {\n const itemText = taskItemTextByListItemIndex.get(tokenIndex) ?? ''\n const snippet = truncateSnippet(itemText)\n report({\n type: 'task-checkbox-stripped',\n message: degradationMessage['task-checkbox-stripped'](taskChecked),\n line: lineOf(token),\n snippet,\n })\n }\n\n ensureListBlock(listType, checked)\n inListItem = true\n break\n }\n case 'list_item_close': {\n const frame = listContainerStack.at(-1)\n\n // Structural path: flush any current block into the item's content,\n // then push the completed item onto the frame.\n if (frame && frame.currentItem) {\n flushBlock()\n frame.items.push(frame.currentItem)\n frame.currentItem = null\n inListItem = false\n break\n }\n\n // Flat path\n inListItem = false\n flushBlock()\n break\n }\n\n // Code fences / blocks\n case 'fence': {\n flushBlock()\n\n const language = token.info.trim() || undefined\n // Remove trailing newline from code content\n const code = token.content.replace(/\\n$/, '')\n\n if (language === 'json:object') {\n const objectValue = parseJsonObjectFence(code)\n\n if (objectValue) {\n pushBlock(objectValue as PortableTextObject)\n break\n }\n\n report({\n type: 'object-carrier-invalid',\n message: degradationMessage['object-carrier-invalid'](\n 'fence',\n code,\n ),\n line: lineOf(token),\n snippet: truncateSnippet(code),\n })\n }\n\n const codeObject = consolidatedOptions.types.code({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {language, code},\n isInline: false,\n })\n\n if (!codeObject) {\n const snippet = truncateSnippet(code.split('\\n')[0] ?? '')\n report({\n type: 'code-block-to-text',\n message: degradationMessage['code-block-to-text'](language),\n line: lineOf(token),\n snippet,\n })\n\n // Code block not in schema, fall back to text block\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(code)\n flushBlock()\n break\n }\n\n reportFieldsDropped(codeObject, lineOf(token))\n pushBlock(codeObject)\n\n break\n }\n\n // Horizontal rule\n case 'hr': {\n flushBlock()\n\n const hrObject = consolidatedOptions.types.horizontalRule({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {},\n isInline: false,\n })\n\n if (!hrObject) {\n report({\n type: 'horizontal-rule-to-text',\n message: degradationMessage['horizontal-rule-to-text'],\n line: lineOf(token),\n })\n\n // If there's no break definition in the schema, parse as text\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan('---')\n flushBlock()\n break\n }\n\n pushBlock(hrObject)\n\n break\n }\n\n // HTML block\n case 'html_block': {\n flushBlock()\n\n const htmlContent = token.content.trim()\n\n if (!htmlContent) {\n break\n }\n\n const htmlObject = consolidatedOptions.types.html({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {html: htmlContent},\n isInline: false,\n })\n\n if (!htmlObject) {\n const snippet = truncateSnippet(htmlContent)\n report({\n type: 'html-block-to-text',\n message: degradationMessage['html-block-to-text'],\n line: lineOf(token),\n snippet,\n })\n\n // If there's no HTML block definition in the schema, parse as text\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(htmlContent)\n flushBlock()\n break\n }\n\n reportFieldsDropped(htmlObject, lineOf(token))\n pushBlock(htmlObject)\n\n break\n }\n\n case 'code_block': {\n flushBlock()\n\n // Remove trailing newline from code content\n const code = token.content.replace(/\\n$/, '')\n\n const codeObject = consolidatedOptions.types.code({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {language: undefined, code},\n isInline: false,\n })\n\n if (!codeObject) {\n const snippet = truncateSnippet(code.split('\\n')[0] ?? '')\n report({\n type: 'code-block-to-text',\n message: degradationMessage['code-block-to-text'](undefined),\n line: lineOf(token),\n snippet,\n })\n\n // Code block not in schema, fall back to text block\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', lineOf(token))\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(code)\n flushBlock()\n } else {\n reportFieldsDropped(codeObject, lineOf(token))\n pushBlock(codeObject)\n }\n\n break\n }\n\n // Tables\n case 'table_open':\n flushBlock()\n currentTable = {\n rows: [],\n headerRows: 0,\n emptyHeaderDropped: false,\n alignment: [],\n line: lineOf(token),\n }\n break\n\n case 'table_close': {\n if (!currentTable) {\n break\n }\n\n // Only create table object if table type is defined\n if (consolidatedOptions.types.table) {\n const hasAlignment = currentTable.alignment.some((a) => a !== null)\n const tableObject = consolidatedOptions.types.table({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {\n rows: currentTable.rows,\n headerRows:\n currentTable.headerRows > 0\n ? currentTable.headerRows\n : currentTable.emptyHeaderDropped\n ? 0\n : undefined,\n alignment: hasAlignment ? currentTable.alignment : undefined,\n },\n isInline: false,\n })\n\n if (tableObject) {\n reportFieldsDropped(tableObject, currentTable.line)\n pushBlock(tableObject)\n } else {\n report({\n type: 'table-flattened',\n message: degradationMessage['table-flattened'],\n line: currentTable.line,\n })\n // If table object couldn't be created, flatten the table\n flattenTable(\n currentTable,\n blockTarget() as Array<PortableTextBlock>,\n )\n }\n } else {\n report({\n type: 'table-flattened',\n message: degradationMessage['table-flattened'],\n line: currentTable.line,\n })\n // If there's no table definition in the schema, flatten the table\n flattenTable(currentTable, blockTarget() as Array<PortableTextBlock>)\n }\n\n currentTable = null\n break\n }\n\n case 'thead_open':\n inTableHead = true\n break\n\n case 'thead_close':\n inTableHead = false\n break\n\n case 'tbody_open':\n case 'tbody_close':\n // Just markers, no action needed\n break\n\n case 'tr_open':\n currentTableRow = []\n break\n\n case 'tr_close':\n if (currentTable && currentTableRow) {\n if (\n inTableHead &&\n isEmptyTableRow(currentTableRow, {\n schema: consolidatedOptions.schema,\n })\n ) {\n // An all-empty header row means \"no header\": drop it and leave\n // `headerRows` at 0 (recorded so `table_close` emits an explicit\n // 0, not `undefined`), so `portableTextToMarkdown`'s headerless\n // output round-trips back to `headerRows: 0`.\n currentTable.emptyHeaderDropped = true\n } else {\n currentTable.rows.push({\n _key: consolidatedOptions.keyGenerator(),\n _type: 'row',\n cells: currentTableRow,\n })\n if (inTableHead) {\n currentTable.headerRows++\n }\n }\n }\n currentTableRow = null\n break\n\n case 'th_open':\n case 'td_open': {\n // Alignment is per-column, set on every cell of that column. Read\n // from the header so each column contributes exactly one entry.\n if (currentTable && inTableHead && token.type === 'th_open') {\n currentTable.alignment.push(\n extractAlignmentFromStyleAttr(token.attrGet('style')),\n )\n }\n\n // Start a new block for the table cell\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', currentTable?.line)\n startBlock('normal')\n } else {\n startBlock(style)\n }\n break\n }\n\n case 'th_close':\n case 'td_close': {\n // Flush the current block into the cell\n flushBlock()\n\n // Get all blocks that were added since this cell started\n // We need to extract them from the current target array\n const cellBlocks: Array<PortableTextBlock> = []\n const target = blockTarget()\n\n // Check if we have blocks to extract (added after table_open)\n if (target.length > 0) {\n const lastBlock = target.at(-1)\n if (lastBlock && lastBlock._type === 'block') {\n cellBlocks.push(target.pop()! as PortableTextBlock)\n }\n }\n\n // If no blocks were created (empty cell), create an empty block\n if (cellBlocks.length === 0) {\n cellBlocks.push({\n _type: 'block' as const,\n style:\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) || 'normal',\n children: [\n {\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: '',\n marks: [],\n },\n ],\n _key: consolidatedOptions.keyGenerator(),\n markDefs: [],\n })\n }\n\n // Images pushed as inline children during this cell (see the\n // `inline` case below) were demoted from block-level at push time,\n // before it was known whether the sole-image lift below would\n // recover them losslessly. Collect them so the lift's verdict can\n // decide whether the demotion actually degraded anything.\n const demotedInlineImages: Array<PortableTextObject> = []\n for (const block of cellBlocks) {\n if (\n block._type === 'block' &&\n 'children' in block &&\n Array.isArray(block.children)\n ) {\n for (const child of block.children) {\n if (\n typeof child === 'object' &&\n child !== null &&\n demotedTableImages.has(child as PortableTextObject)\n ) {\n demotedInlineImages.push(child as PortableTextObject)\n }\n }\n }\n }\n\n // Check if the cell contains a single block with a single image child\n // If so, extract the image as a block-level image\n const firstBlock = cellBlocks[0]\n let liftedImage: PortableTextObject | undefined\n if (\n cellBlocks.length === 1 &&\n firstBlock &&\n firstBlock._type === 'block' &&\n 'children' in firstBlock &&\n Array.isArray(firstBlock.children) &&\n firstBlock.children.length === 1\n ) {\n const onlyChild = firstBlock.children[0]\n // Check if it's an image object (not a span)\n if (\n typeof onlyChild === 'object' &&\n onlyChild !== null &&\n '_type' in onlyChild &&\n onlyChild._type !== consolidatedOptions.schema.span.name &&\n onlyChild._type === 'image'\n ) {\n // Replace the block with just the image\n cellBlocks[0] = onlyChild as PortableTextBlock\n liftedImage = onlyChild as PortableTextObject\n }\n }\n\n // A demoted image the lift didn't recover is stuck as an inline\n // child of the cell's text block: report it now that the verdict is\n // known, instead of at demotion time.\n for (const demotedImage of demotedInlineImages) {\n if (demotedImage !== liftedImage) {\n const {alt, src} = demotedImage as {alt?: string; src?: string}\n report({\n type: 'image-block-to-inline',\n message: degradationMessage['image-block-to-inline'](\n demotedTableImages.get(demotedImage) ?? 'table-cell',\n ),\n line: currentTable?.line,\n snippet: truncateSnippet(alt || src || ''),\n })\n }\n }\n\n if (currentTableRow !== null) {\n currentTableRow.push({\n _type: 'cell',\n _key: consolidatedOptions.keyGenerator(),\n value: cellBlocks,\n })\n }\n break\n }\n\n // Inline container\n case 'inline': {\n // Check if we're in a table cell\n const inTableCell = currentTableRow !== null\n\n // `inline` tokens inside table cells carry no `map` of their own;\n // fall back to the enclosing table's line.\n const inlineLine = (): number | undefined =>\n lineOf(token) ?? currentTable?.line\n\n // Check if this is a standalone image (paragraph with only an image)\n if (\n token.children?.length === 1 &&\n token.children[0]?.type === 'image'\n ) {\n const imageToken = token.children[0]\n if (!imageToken) {\n break\n }\n\n const src =\n imageToken.attrs?.find(([name]) => name === 'src')?.at(1) || ''\n const alt = unescapeImageAndLinkText(imageToken.content || '')\n const title =\n imageToken.attrs?.find(([name]) => name === 'title')?.at(1) ||\n undefined\n\n const blockImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title},\n isInline: false,\n })\n\n if (blockImageObject) {\n reportFieldsDropped(blockImageObject, inlineLine())\n if (inTableCell) {\n demotedTableImages.set(\n blockImageObject as PortableTextObject,\n 'table-cell',\n )\n\n // In table cells, we can't push to portableText directly\n // The block image will be handled in th_close/td_close extraction logic\n // For now, add it as a child of the current block\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n blockImageObject as PortableTextObject,\n )\n }\n } else {\n // If the current block has content, flush it before adding the block image\n // Otherwise, discard the empty block that was created by paragraph_open\n const hasContent =\n currentBlock &&\n 'children' in currentBlock &&\n (currentBlock as PortableTextTextBlock).children.length > 0\n\n if (hasContent) {\n flushBlock()\n } else {\n currentBlock = null\n currentMarkDefs = []\n }\n pushBlock(blockImageObject)\n }\n break\n }\n\n // Block image not supported, try inline image as fallback\n const inlineImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title},\n isInline: true,\n })\n\n if (inlineImageObject) {\n reportFieldsDropped(inlineImageObject, inlineLine())\n if (inTableCell) {\n // Defer to the `td_close` sole-image lift: a standalone image\n // that's the cell's only content round-trips back to\n // block-level losslessly, and reporting here would be a false\n // positive for that case.\n demotedTableImages.set(\n inlineImageObject as PortableTextObject,\n 'no-block-image',\n )\n } else {\n report({\n type: 'image-block-to-inline',\n message:\n degradationMessage['image-block-to-inline']('no-block-image'),\n line: inlineLine(),\n snippet: truncateSnippet(alt || src),\n })\n }\n // Ensure we have a block to add the inline image to\n if (!currentBlock) {\n if (inListItem) {\n // Structural list: start a plain text block; the image\n // lands in the current item's content via flushBlock.\n if (listContainerStack.at(-1)) {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', inlineLine())\n }\n\n startBlock(style ?? 'normal')\n } else {\n const listType = currentListStack.at(-1)\n\n if (listType) {\n ensureListBlock(listType)\n }\n }\n } else {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (style) {\n startBlock(style)\n }\n }\n }\n\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n inlineImageObject as PortableTextObject,\n )\n }\n break\n }\n\n // Neither block nor inline image supported, fall back to text\n const standaloneImageSnippet = truncateSnippet(alt || src)\n report({\n type: 'image-to-text',\n message: degradationMessage['image-to-text'],\n line: inlineLine(),\n snippet: standaloneImageSnippet,\n })\n addSpan(``)\n break\n }\n\n // Walk its children for text/marks/links\n const inlineChildren = token.children ?? []\n for (\n let childIndex = 0;\n childIndex < inlineChildren.length;\n childIndex++\n ) {\n const childToken = inlineChildren[childIndex]\n if (!childToken) {\n continue\n }\n\n switch (childToken.type) {\n case 'text': {\n const nextToken = inlineChildren[childIndex + 1]\n\n if (\n childToken.content.endsWith('json:object') &&\n nextToken?.type === 'code_inline' &&\n currentBlock &&\n 'children' in currentBlock\n ) {\n const objectValue = parseJsonObjectFence(nextToken.content)\n\n if (objectValue) {\n const prefix = childToken.content.slice(\n 0,\n -'json:object'.length,\n )\n\n if (prefix.length > 0) {\n addSpan(prefix)\n }\n\n ;(currentBlock as PortableTextTextBlock).children.push(\n objectValue as PortableTextObject,\n )\n\n childIndex++\n break\n }\n\n report({\n type: 'object-carrier-invalid',\n message: degradationMessage['object-carrier-invalid'](\n 'code-span',\n nextToken.content,\n ),\n line: inlineLine(),\n snippet: truncateSnippet(nextToken.content),\n })\n }\n\n addSpan(childToken.content)\n break\n }\n case 'softbreak':\n addSpan(' ')\n break\n case 'hardbreak':\n addSpan('\\n')\n break\n case 'code_inline': {\n const decorator = consolidatedOptions.marks.code({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n const codeSnippet = truncateSnippet(childToken.content)\n report({\n type: 'decorator-dropped',\n message: degradationMessage['decorator-dropped']('code'),\n line: inlineLine(),\n snippet: codeSnippet,\n })\n // No code decorator defined, just add the content without marks\n addSpan(childToken.content)\n break\n }\n\n markDefRefs.push(decorator)\n addSpan(childToken.content)\n\n // code_inline is self-contained, so we need to pop the decorator\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'strong_open': {\n const decorator = consolidatedOptions.marks.strong({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n const strongSnippet = truncateSnippet(\n collectInlineText(\n inlineChildren,\n childIndex,\n 'strong_open',\n 'strong_close',\n ),\n )\n report({\n type: 'decorator-dropped',\n message: degradationMessage['decorator-dropped']('strong'),\n line: inlineLine(),\n snippet: strongSnippet,\n })\n break\n }\n\n markDefRefs.push(decorator)\n break\n }\n case 'strong_close': {\n const decorator = consolidatedOptions.marks.strong({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'em_open': {\n const decorator = consolidatedOptions.marks.em({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n const emSnippet = truncateSnippet(\n collectInlineText(\n inlineChildren,\n childIndex,\n 'em_open',\n 'em_close',\n ),\n )\n report({\n type: 'decorator-dropped',\n message: degradationMessage['decorator-dropped']('em'),\n line: inlineLine(),\n snippet: emSnippet,\n })\n break\n }\n\n markDefRefs.push(decorator)\n\n break\n }\n case 'em_close': {\n const decorator = consolidatedOptions.marks.em({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 's_open': {\n const decorator = consolidatedOptions.marks.strikeThrough({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n const strikeSnippet = truncateSnippet(\n collectInlineText(\n inlineChildren,\n childIndex,\n 's_open',\n 's_close',\n ),\n )\n report({\n type: 'decorator-dropped',\n message:\n degradationMessage['decorator-dropped']('strikeThrough'),\n line: inlineLine(),\n snippet: strikeSnippet,\n })\n break\n }\n\n markDefRefs.push(decorator)\n\n break\n }\n case 's_close': {\n const decorator = consolidatedOptions.marks.strikeThrough({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'link_open': {\n const href = childToken.attrs\n ?.find(([name]) => name === 'href')\n ?.at(1)\n\n if (!href) {\n const missingHrefSnippet = truncateSnippet(\n collectInlineText(\n inlineChildren,\n childIndex,\n 'link_open',\n 'link_close',\n ),\n )\n report({\n type: 'annotation-dropped',\n message:\n degradationMessage['annotation-dropped']('missing-url'),\n line: inlineLine(),\n snippet: missingHrefSnippet,\n })\n break\n }\n\n const title = childToken.attrs\n ?.find(([name]) => name === 'title')\n ?.at(1)\n\n const linkObject = consolidatedOptions.marks.link({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {href, title},\n })\n\n if (!linkObject) {\n const linkSnippet = truncateSnippet(\n collectInlineText(\n inlineChildren,\n childIndex,\n 'link_open',\n 'link_close',\n ),\n )\n report({\n type: 'annotation-dropped',\n message:\n degradationMessage['annotation-dropped']('no-annotation'),\n line: inlineLine(),\n snippet: linkSnippet,\n })\n break\n }\n\n reportFieldsDropped(linkObject, inlineLine())\n currentMarkDefs.push(linkObject)\n markDefRefs.push(linkObject._key)\n break\n }\n case 'link_close': {\n // remove the last link key\n const markDefKeys = new Set(currentMarkDefs.map((d) => d._key))\n let lastLinkIndex: number | undefined\n\n for (const markDefRef of markDefRefs.reverse()) {\n if (markDefKeys.has(markDefRef)) {\n lastLinkIndex = markDefRefs.indexOf(markDefRef)\n break\n }\n }\n\n if (lastLinkIndex !== undefined) {\n const realIndex = markDefRefs.length - 1 - lastLinkIndex\n markDefRefs.splice(realIndex, 1)\n }\n break\n }\n case 'image': {\n const src =\n childToken.attrs?.find(([name]) => name === 'src')?.at(1) || ''\n const alt = unescapeImageAndLinkText(childToken.content || '')\n\n // Try to create an inline image first\n const inlineImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title: undefined},\n isInline: true,\n })\n\n if (inlineImageObject) {\n reportFieldsDropped(inlineImageObject, inlineLine())\n // Inline image is supported - add it to current block\n if (!currentBlock) {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n reportStyleFallback('normal', inlineLine())\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n // At this point currentBlock should exist\n if (!currentBlock) {\n throw new Error('Expected current block after startBlock')\n }\n\n // Add the image as an inline object (TypeScript assertion needed for type narrowing)\n ;(currentBlock as PortableTextTextBlock).children.push(\n inlineImageObject as PortableTextObject,\n )\n break\n }\n\n // Inline image not supported - try block image as fallback\n const blockImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title: undefined},\n isInline: false,\n })\n\n if (!blockImageObject) {\n // Neither inline nor block image supported\n const inlineImageSnippet = truncateSnippet(alt || src)\n report({\n type: 'image-to-text',\n message: degradationMessage['image-to-text'],\n line: inlineLine(),\n snippet: inlineImageSnippet,\n })\n addSpan(``)\n break\n }\n\n // Block image supported - flush current block and add as block-level\n // Skip if we're in a table cell (images in cells are handled differently)\n if (inTableCell) {\n reportFieldsDropped(blockImageObject, inlineLine())\n demotedTableImages.set(\n blockImageObject as PortableTextObject,\n 'table-cell',\n )\n\n // In table cells, add the image to current block (will be extracted later)\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n blockImageObject as PortableTextObject,\n )\n }\n break\n }\n\n // Not in table - flush current block, add image as block, start new block\n reportFieldsDropped(blockImageObject, inlineLine())\n report({\n type: 'image-inline-to-block',\n message: degradationMessage['image-inline-to-block'],\n line: inlineLine(),\n snippet: truncateSnippet(alt || src),\n })\n flushBlock()\n pushBlock(blockImageObject)\n\n // Start a new block for any remaining content\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (style) {\n startBlock(style)\n }\n\n break\n }\n case 'html_inline': {\n // Handle inline HTML based on configuration\n if (consolidatedOptions.html.inline === 'text') {\n addSpan(childToken.content)\n } else if (childToken.content) {\n const htmlInlineSnippet = truncateSnippet(childToken.content)\n report({\n type: 'inline-html-dropped',\n message: degradationMessage['inline-html-dropped'],\n line: inlineLine(),\n snippet: htmlInlineSnippet,\n })\n }\n break\n }\n default:\n // Ignore other inline token types by default\n break\n }\n }\n break\n }\n\n // Callouts (GFM alerts)\n case 'alert_open': {\n flushBlock()\n calloutStartTarget = blockTarget()\n calloutStartIndex = calloutStartTarget.length\n calloutType = token.markup\n calloutStartLine = lineOf(token)\n\n // Set blockquote style so content blocks inside the callout\n // get blockquote styling (used in fallback when callout type\n // is not in the schema)\n const blockquoteStyle = consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n })\n\n calloutPendingStyleFallbacks = []\n if (!blockquoteStyle) {\n calloutPendingStyleFallbacks.push('blockquote')\n }\n\n const style =\n blockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n calloutPendingStyleFallbacks.push('normal')\n }\n\n currentBlockquoteStyle = style ?? 'normal'\n break\n }\n\n case 'alert_title': {\n // `alert_open`'s own map starts at the first content line; the\n // marker line (`> [!NOTE]`) is `alert_title`'s. Any pending style\n // fallbacks flush lazily, from `flushBlock`, once a text block\n // actually commits needing the style.\n calloutStartLine = lineOf(token)\n break\n }\n\n case 'alert_close': {\n flushBlock()\n\n // Nothing ever needed the pending style: no text block materialized\n // inside the callout, so nothing degraded.\n calloutPendingStyleFallbacks = []\n\n if (\n calloutStartIndex !== null &&\n calloutType !== null &&\n calloutStartTarget !== null\n ) {\n const contentBlocks = calloutStartTarget.splice(\n calloutStartIndex,\n ) as Array<PortableTextBlock>\n\n const calloutObject = consolidatedOptions.types.callout?.({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {tone: calloutType, content: contentBlocks},\n isInline: false,\n })\n\n if (calloutObject) {\n reportFieldsDropped(calloutObject, calloutStartLine)\n pushBlock(calloutObject)\n } else {\n report({\n type: 'callout-fallback',\n message: degradationMessage['callout-fallback'](\n calloutType,\n currentBlockquoteStyle ?? 'normal',\n ),\n line: calloutStartLine,\n })\n for (const block of contentBlocks) {\n pushBlock(block)\n }\n }\n }\n\n calloutStartIndex = null\n calloutStartTarget = null\n calloutType = null\n calloutStartLine = undefined\n currentBlockquoteStyle = null\n break\n }\n\n default:\n break\n }\n }\n\n flushBlock()\n\n if (degradationEvents.length > 0) {\n options?.onDegradation?.({\n degradations: degradationEvents,\n message: buildDegradationMessage(degradationEvents),\n })\n }\n\n return portableText\n}\n\n/**\n * A `json:object` fence always reconstructs its object, schema or no\n * schema: the fence carries its own `_type`, and degrading it to a code\n * block would reintroduce the loss the syntax exists to remove. Returns\n * `undefined` instead of throwing, so an unusable fence falls through to\n * the regular code path.\n */\nfunction parseJsonObjectFence(\n code: string,\n): (Record<string, unknown> & {_type: string}) | undefined {\n let parsed: unknown\n\n try {\n parsed = JSON.parse(code)\n } catch {\n return undefined\n }\n\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return undefined\n }\n\n const objectValue = parsed as Record<string, unknown>\n\n if (\n typeof objectValue['_type'] !== 'string' ||\n objectValue['_type'].length === 0\n ) {\n return undefined\n }\n\n return objectValue as Record<string, unknown> & {_type: string}\n}\n"],"mappings":"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"}
|