{"version":3,"sources":["../src/Extension.ts","../src/MarkdownManager.ts","../src/utils.ts"],"sourcesContent":["import {\n type InsertContentAtOptions as MarkdownInsertContentAtOptions,\n type InsertContentOptions as MarkdownInsertContentOptions,\n type SetContentOptions as MarkdownSetContentOptions,\n commands,\n Extension,\n} from '@tiptap/core'\nimport type { marked } from 'marked'\n\nimport MarkdownManager from './MarkdownManager.js'\nimport type { ContentType } from './types.js'\nimport { assumeContentType } from './utils.js'\n\ndeclare module '@tiptap/core' {\n interface Editor {\n /**\n * Get the content of the editor as markdown.\n */\n getMarkdown: () => string\n\n /**\n * The markdown manager instance.\n */\n markdown?: MarkdownManager\n }\n\n interface EditorOptions {\n /**\n * The content type the content is provided as.\n *\n * @default 'json'\n */\n contentType?: ContentType\n }\n\n interface Storage {\n markdown: MarkdownExtensionStorage\n }\n\n interface InsertContentOptions {\n /**\n * The content type the content is provided as.\n *\n * @default 'json'\n */\n contentType?: ContentType\n }\n\n interface InsertContentAtOptions {\n /**\n * The content type the content is provided as.\n *\n * @default 'json'\n */\n contentType?: ContentType\n }\n\n interface SetContentOptions {\n /**\n * The content type the content is provided as.\n *\n * @default 'json'\n */\n contentType?: ContentType\n }\n}\n\nexport type MarkdownExtensionOptions = {\n /**\n * Configure the indentation style and size for lists and code blocks.\n * - `style`: Choose between spaces or tabs. Default is 'space'.\n * - `size`: Number of spaces or tabs for indentation. Default is 2.\n */\n indentation?: { style?: 'space' | 'tab'; size?: number }\n\n /**\n * Use a custom version of `marked` for markdown parsing and serialization.\n * If not provided, the default `marked` instance will be used.\n */\n marked?: typeof marked\n\n /**\n * Options to pass to `marked.setOptions()`.\n * See the [marked documentation](https://marked.js.org/using_advanced#options) for available options.\n */\n markedOptions?: Parameters[0]\n}\n\nexport type MarkdownExtensionStorage = {\n manager: MarkdownManager\n}\n\nexport const Markdown = Extension.create({\n name: 'markdown',\n\n addOptions() {\n return {\n indentation: { style: 'space', size: 2 },\n marked: undefined,\n markedOptions: {},\n }\n },\n\n addCommands() {\n return {\n setContent: (content, options?: MarkdownSetContentOptions) => {\n // if no contentType is specified, we assume the content is in JSON format OR HTML format\n if (!options?.contentType) {\n return commands.setContent(content, options)\n }\n\n const actualContentType = assumeContentType(content, options?.contentType)\n\n if (actualContentType !== 'markdown' || !this.editor.markdown) {\n return commands.setContent(content, options)\n }\n\n const mdContent = this.editor.markdown.parse(content as string)\n return commands.setContent(mdContent, options)\n },\n\n insertContent: (value, options?: MarkdownInsertContentOptions) => {\n // if no contentType is specified, we assume the content is in JSON format OR HTML format\n if (!options?.contentType) {\n return commands.insertContent(value, options)\n }\n\n const actualContentType = assumeContentType(value, options?.contentType)\n\n if (actualContentType !== 'markdown' || !this.editor.markdown) {\n return commands.insertContent(value, options)\n }\n\n const mdContent = this.editor.markdown.parse(value as string)\n return commands.insertContent(mdContent, options)\n },\n\n insertContentAt: (position, value, options?: MarkdownInsertContentAtOptions) => {\n // if no contentType is specified, we assume the content is in JSON format OR HTML format\n if (!options?.contentType) {\n return commands.insertContentAt(position, value, options)\n }\n\n const actualContentType = assumeContentType(value, options?.contentType)\n\n if (actualContentType !== 'markdown' || !this.editor.markdown) {\n return commands.insertContentAt(position, value, options)\n }\n\n const mdContent = this.editor.markdown.parse(value as string)\n return commands.insertContentAt(position, mdContent, options)\n },\n }\n },\n\n addStorage() {\n return {\n manager: new MarkdownManager({\n indentation: this.options.indentation,\n marked: this.options.marked,\n markedOptions: this.options.markedOptions,\n extensions: [],\n }),\n }\n },\n\n onBeforeCreate() {\n if (this.editor.markdown) {\n console.error(\n '[tiptap][markdown]: There is already a `markdown` property on the editor instance. This might lead to unexpected behavior.',\n )\n return\n }\n\n this.storage.manager = new MarkdownManager({\n indentation: this.options.indentation,\n marked: this.options.marked,\n markedOptions: this.options.markedOptions,\n extensions: this.editor.extensionManager.baseExtensions,\n })\n\n this.editor.markdown = this.storage.manager\n\n // add a `getMarkdown()` method to the editor\n this.editor.getMarkdown = () => {\n return this.storage.manager.serialize(this.editor.getJSON())\n }\n\n if (!this.editor.options.contentType) {\n return\n }\n\n const assumedType = assumeContentType(\n this.editor.options.content,\n this.editor.options.contentType,\n )\n if (assumedType !== 'markdown') {\n return\n }\n\n if (!this.editor.markdown) {\n throw new Error(\n '[tiptap][markdown]: The `contentType` option is set to \"markdown\", but the Markdown extension is not added to the editor. Please add the Markdown extension to use this feature.',\n )\n }\n\n if (\n this.editor.options.content === undefined ||\n typeof this.editor.options.content !== 'string'\n ) {\n throw new Error(\n '[tiptap][markdown]: The `contentType` option is set to \"markdown\", but the initial content is not a string. Please provide the initial content as a markdown string.',\n )\n }\n\n const json = this.editor.markdown.parse(this.editor.options.content as string)\n\n // If the parsed markdown produced no content, leave options.content\n // as-is (empty string) so that createDoc / DOMParser.parse can fill in\n // the required block node via ProseMirror's ContentMatch.fillBefore.\n if (json.content?.length) {\n this.editor.options.content = json\n }\n },\n})\n","import {\n type AnyExtension,\n type ExtendableConfig,\n type JSONContent,\n type MarkdownExtensionSpec,\n type MarkdownLexerConfiguration,\n type MarkdownParseHelpers,\n type MarkdownParseResult,\n type MarkdownRendererHelpers,\n type MarkdownToken,\n type MarkdownTokenizer,\n type RenderContext,\n callOrReturn,\n decodeHtmlEntities,\n encodeHtmlEntities,\n flattenExtensions,\n generateJSON,\n getExtensionField,\n getSchema,\n sortExtensions,\n} from '@tiptap/core'\nimport { type Lexer, type Token, type TokenizerExtension, type TokenizerThis, marked } from 'marked'\n\nimport {\n attrsEqual,\n closeMarksBeforeNode,\n findMarksToClose,\n findMarksToCloseAtEnd,\n findMarksToOpen,\n isTaskItem,\n reopenMarksAfterNode,\n wrapInMarkdownBlock,\n} from './utils.js'\n\n/**\n * Returns true when the element's tag is not a recognized standard HTML\n * element. Note: the calling code further cross-references this result\n * against schema parseDOM tags, so non-standard tags that are declared\n * by registered extensions are still treated as valid.\n *\n * Browsers expose this classification natively: any non-hyphenated tag that\n * is not part of the HTML/SVG/MathML namespaces is constructed as an\n * `HTMLUnknownElement`. Standard tags (``, `
`, …) and custom\n * elements (``, must contain a hyphen) are `HTMLElement` instances.\n */\nconst isHtmlUnknownElement = (element: Element): boolean => {\n const ctor = (window as any).HTMLUnknownElement\n return typeof ctor === 'function' && element instanceof ctor\n}\n\nexport class MarkdownManager {\n private markedInstance: typeof marked\n private activeParseLexer: Lexer | null = null\n private registry: Map\n private nodeTypeRegistry: Map\n /**\n * Order in which extensions were registered. Used to resolve mark nesting\n * deterministically when several marks open on the same text node.\n *\n * The flattened extensions passed to the manager are pre-sorted by Tiptap's\n * extension priority (descending), which is also the order ProseMirror uses\n * to assign mark ranks. Recording that index here lets the serializer place\n * higher-priority / lower-rank marks (e.g. link with priority 1000) on the\n * outside without inspecting any rendered markdown output.\n */\n private extensionRanks: Map = new Map()\n private indentStyle: 'space' | 'tab'\n private indentSize: number\n private baseExtensions: AnyExtension[] = []\n private extensions: AnyExtension[] = []\n /** Set of extension names whose `code` spec property is truthy (nodes and marks). */\n private codeTypes: Set = new Set()\n /** Lazy cache of tag names declared by the registered schema's parseDOM rules. */\n private schemaParseDomTagsCache: Set | null = null\n\n /**\n * Create a MarkdownManager.\n * @param options.marked Optional marked instance to use (injected).\n * @param options.markedOptions Optional options to pass to marked.setOptions\n * @param options.indentation Indentation settings (style and size).\n * @param options.extensions An array of Tiptap extensions to register for markdown parsing and rendering.\n */\n constructor(options?: {\n marked?: typeof marked\n markedOptions?: Parameters[0]\n indentation?: { style?: 'space' | 'tab'; size?: number }\n extensions: AnyExtension[]\n }) {\n this.markedInstance = options?.marked ?? marked\n this.indentStyle = options?.indentation?.style ?? 'space'\n this.indentSize = options?.indentation?.size ?? 2\n this.baseExtensions = options?.extensions || []\n\n if (options?.markedOptions && typeof this.markedInstance.setOptions === 'function') {\n this.markedInstance.setOptions(options.markedOptions)\n }\n\n this.registry = new Map()\n this.nodeTypeRegistry = new Map()\n\n // If extensions were provided, register them now. Sort by Tiptap priority\n // first (matching how the editor builds its schema) so the registration\n // index lines up with ProseMirror's mark rank — this is what the\n // serializer relies on to nest higher-priority marks like link outermost.\n if (options?.extensions) {\n this.baseExtensions = options.extensions\n const flattened = sortExtensions(flattenExtensions(options.extensions))\n flattened.forEach(ext => this.registerExtension(ext))\n }\n }\n\n /** Returns the underlying marked instance. */\n get instance(): typeof marked {\n return this.markedInstance\n }\n\n /** Returns the correct indentCharacter (space or tab) */\n get indentCharacter(): string {\n return this.indentStyle === 'space' ? ' ' : '\\t'\n }\n\n /** Returns the correct indentString repeated X times */\n get indentString(): string {\n return this.indentCharacter.repeat(this.indentSize)\n }\n\n /** Helper to quickly check whether a marked instance is available. */\n hasMarked(): boolean {\n return !!this.markedInstance\n }\n\n /**\n * Register a Tiptap extension (Node/Mark/Extension). This will read\n * `markdownName`, `parseMarkdown`, `renderMarkdown` and `priority` from the\n * extension config (using the same resolution used across the codebase).\n */\n registerExtension(extension: AnyExtension): void {\n // Keep track of all extensions for HTML parsing\n this.extensions.push(extension)\n\n // Track extensions that declare `code: true` so we can skip HTML entity\n // encoding inside code contexts without hardcoding specific type names.\n const isCode = callOrReturn(getExtensionField(extension, 'code'))\n\n const name = extension.name\n\n if (isCode) {\n this.codeTypes.add(name)\n }\n\n if (!this.extensionRanks.has(name)) {\n this.extensionRanks.set(name, this.extensionRanks.size)\n }\n const tokenName =\n (getExtensionField(\n extension,\n 'markdownTokenName',\n ) as ExtendableConfig['markdownTokenName']) || name\n const parseMarkdown = getExtensionField(extension, 'parseMarkdown') as\n | ExtendableConfig['parseMarkdown']\n | undefined\n const renderMarkdown = getExtensionField(extension, 'renderMarkdown') as\n | ExtendableConfig['renderMarkdown']\n | undefined\n const tokenizer = getExtensionField(extension, 'markdownTokenizer') as\n | ExtendableConfig['markdownTokenizer']\n | undefined\n\n // Read the `markdown` object from the extension config. This allows\n // extensions to provide `markdown: { name?, parseName?, renderName?, parse?, render?, match? }`.\n const markdownCfg = (getExtensionField(extension, 'markdownOptions') ??\n null) as ExtendableConfig['markdownOptions']\n const isIndenting = markdownCfg?.indentsContent ?? false\n const htmlReopen = markdownCfg?.htmlReopen\n\n const spec: MarkdownExtensionSpec = {\n tokenName,\n nodeName: name,\n parseMarkdown,\n renderMarkdown,\n isIndenting,\n htmlReopen,\n tokenizer,\n }\n\n // Add to parse registry using parseName\n if (tokenName && parseMarkdown) {\n const parseExisting = this.registry.get(tokenName) || []\n parseExisting.push(spec)\n this.registry.set(tokenName, parseExisting)\n }\n\n // Add to render registry using renderName (node type)\n if (renderMarkdown) {\n const renderExisting = this.nodeTypeRegistry.get(name) || []\n renderExisting.push(spec)\n this.nodeTypeRegistry.set(name, renderExisting)\n }\n\n // Register custom tokenizer with marked.js\n if (tokenizer && this.hasMarked()) {\n this.registerTokenizer(tokenizer)\n }\n }\n\n private createLexer(): Lexer {\n return new this.markedInstance.Lexer()\n }\n\n private createTokenizerHelpers(lexer: Lexer): MarkdownLexerConfiguration {\n return {\n inlineTokens: (src: string) => lexer.inlineTokens(src),\n blockTokens: (src: string) => lexer.blockTokens(src),\n }\n }\n\n private tokenizeInline(src: string): MarkdownToken[] {\n return (this.activeParseLexer ?? this.createLexer()).inlineTokens(src) as MarkdownToken[]\n }\n\n /**\n * Register a custom tokenizer with marked.js for parsing non-standard markdown syntax.\n */\n private registerTokenizer(tokenizer: MarkdownTokenizer): void {\n if (!this.hasMarked()) {\n return\n }\n\n const { name, start, level = 'inline', tokenize } = tokenizer\n const createTokenizerHelpers = this.createTokenizerHelpers.bind(this)\n const createLexer = this.createLexer.bind(this)\n\n let startCb: (src: string) => number\n\n if (!start) {\n startCb = (src: string) => {\n // For other tokenizers, try to find a match and return its position\n const result = tokenize(src, [], this.createTokenizerHelpers(this.createLexer()))\n if (result && result.raw) {\n const index = src.indexOf(result.raw)\n return index\n }\n return -1\n }\n } else {\n startCb = typeof start === 'function' ? start : (src: string) => src.indexOf(start)\n }\n\n // Create marked.js extension with proper types\n const markedExtension: TokenizerExtension = {\n name,\n level,\n start: startCb,\n tokenizer(this: TokenizerThis, src, tokens) {\n const helper = this.lexer\n ? createTokenizerHelpers(this.lexer)\n : createTokenizerHelpers(createLexer())\n const result = tokenize(src, tokens, helper)\n\n if (result && result.type) {\n return {\n ...result,\n type: result.type || name,\n raw: result.raw || '',\n tokens: (result.tokens || []) as Token[],\n }\n }\n\n return undefined\n },\n childTokens: [],\n }\n\n // Register with marked.js - use extensions array to control priority\n this.markedInstance.use({\n extensions: [markedExtension],\n })\n }\n\n /** Get registered handlers for a token type and try each until one succeeds. */\n private getHandlersForToken(type: string): MarkdownExtensionSpec[] {\n try {\n return this.registry.get(type) || []\n } catch {\n return []\n }\n }\n\n /** Get the first handler for a token type (for backwards compatibility). */\n private getHandlerForToken(type: string): MarkdownExtensionSpec | undefined {\n // First try the markdown token registry (for parsing)\n const markdownHandlers = this.getHandlersForToken(type)\n if (markdownHandlers.length > 0) {\n return markdownHandlers[0]\n }\n\n // Then try the node type registry (for rendering)\n const nodeTypeHandlers = this.getHandlersForNodeType(type)\n return nodeTypeHandlers.length > 0 ? nodeTypeHandlers[0] : undefined\n }\n\n /** Get registered handlers for a node type (for rendering). */\n private getHandlersForNodeType(type: string): MarkdownExtensionSpec[] {\n try {\n return this.nodeTypeRegistry.get(type) || []\n } catch {\n return []\n }\n }\n\n /**\n * Serialize a ProseMirror-like JSON document (or node array) to a Markdown string\n * using registered renderers and fallback renderers.\n */\n serialize(docOrContent: JSONContent): string {\n if (!docOrContent) {\n return ''\n }\n\n const result = this.renderNodes(docOrContent, docOrContent)\n // Return empty string if result is only whitespace entities or non-breaking spaces\n return this.isEmptyOutput(result) ? '' : result\n }\n\n /**\n * Check if the markdown output represents an empty document.\n * Empty documents may contain only   entities or non-breaking space characters\n * which are used by the Paragraph extension to preserve blank lines.\n */\n private isEmptyOutput(markdown: string): boolean {\n if (!markdown || markdown.trim() === '') {\n return true\n }\n\n // Check if the output is only   entities or non-breaking space characters\n const cleanedOutput = markdown\n .replace(/ /g, '')\n .replace(/\\u00A0/g, '')\n .trim()\n return cleanedOutput === ''\n }\n\n /**\n * Parse markdown string into Tiptap JSON document using registered extension handlers.\n */\n parse(markdown: string): JSONContent {\n if (!this.hasMarked()) {\n throw new Error('No marked instance available for parsing')\n }\n\n const previousParseLexer = this.activeParseLexer\n const parseLexer = this.createLexer()\n\n this.activeParseLexer = parseLexer\n\n try {\n // Use a parse-scoped lexer so follow-up inline tokenization can reuse\n // the same configured lexer state without sharing it across parses.\n const tokens = parseLexer.lex(markdown) as MarkdownToken[]\n\n // Convert tokens to Tiptap JSON\n const content = this.parseTokens(tokens, true)\n\n // Return a document node containing the parsed content\n return {\n type: 'doc',\n content,\n }\n } finally {\n this.activeParseLexer = previousParseLexer\n }\n }\n\n /**\n * Convert an array of marked tokens into Tiptap JSON nodes using registered extension handlers.\n */\n private parseTokens(\n tokens: MarkdownToken[],\n parseImplicitEmptyParagraphs = false,\n ): JSONContent[] {\n const nonSpaceTokenIndexes = tokens.reduce((indexes, token, index) => {\n if (token.type !== 'space') {\n indexes.push(index)\n }\n\n return indexes\n }, [])\n\n let previousNonSpaceTokenIndex = -1\n let nextNonSpaceTokenPointer = 0\n\n return tokens.flatMap((token, index) => {\n while (\n nextNonSpaceTokenPointer < nonSpaceTokenIndexes.length &&\n nonSpaceTokenIndexes[nextNonSpaceTokenPointer] < index\n ) {\n previousNonSpaceTokenIndex = nonSpaceTokenIndexes[nextNonSpaceTokenPointer]\n nextNonSpaceTokenPointer += 1\n }\n\n if (parseImplicitEmptyParagraphs && token.type === 'space') {\n const nextNonSpaceTokenIndex = nonSpaceTokenIndexes[nextNonSpaceTokenPointer] ?? -1\n\n return this.createImplicitEmptyParagraphsFromSpace(\n token,\n previousNonSpaceTokenIndex,\n nextNonSpaceTokenIndex,\n )\n }\n\n const parsed = this.parseToken(token, parseImplicitEmptyParagraphs)\n\n if (parsed === null) {\n return []\n }\n\n return Array.isArray(parsed) ? parsed : [parsed]\n })\n }\n\n private createImplicitEmptyParagraphsFromSpace(\n token: MarkdownToken,\n previousNonSpaceTokenIndex: number,\n nextNonSpaceTokenIndex: number,\n ): JSONContent[] {\n const separatorCount = this.countParagraphSeparators(token.raw || '')\n\n if (separatorCount === 0) {\n return []\n }\n\n const isBoundarySpace = previousNonSpaceTokenIndex === -1 || nextNonSpaceTokenIndex === -1\n const emptyParagraphCount = Math.max(separatorCount - (isBoundarySpace ? 0 : 1), 0)\n\n return Array.from({ length: emptyParagraphCount }, () => ({ type: 'paragraph', content: [] }))\n }\n\n private countParagraphSeparators(raw: string): number {\n return (raw.replace(/\\r\\n/g, '\\n').match(/\\n\\n/g) || []).length\n }\n\n /**\n * Parse a single token into Tiptap JSON using the appropriate registered handler.\n */\n private parseToken(\n token: MarkdownToken,\n parseImplicitEmptyParagraphs = false,\n ): JSONContent | JSONContent[] | null {\n if (!token.type) {\n return null\n }\n\n // Special handling for 'list' tokens that may contain mixed bullet/task items\n if (token.type === 'list') {\n return this.parseListToken(token)\n }\n\n const handlers = this.getHandlersForToken(token.type)\n const helpers = this.createParseHelpers()\n\n // Try each handler until one returns a valid result\n const result = handlers.find(handler => {\n if (!handler.parseMarkdown) {\n return false\n }\n\n const parseResult = handler.parseMarkdown(token, helpers)\n const normalized = this.normalizeParseResult(parseResult)\n\n // Check if this handler returned a valid result (not null/empty array)\n if (normalized && (!Array.isArray(normalized) || normalized.length > 0)) {\n // Store result for return\n this.lastParseResult = normalized\n return true\n }\n\n return false\n })\n\n // If a handler worked, return its result\n if (result && this.lastParseResult) {\n const toReturn = this.lastParseResult\n this.lastParseResult = null // Clean up\n return toReturn\n }\n\n // If no handler worked, try fallback parsing\n return this.parseFallbackToken(token, parseImplicitEmptyParagraphs)\n }\n\n private lastParseResult: JSONContent | JSONContent[] | null = null\n\n /**\n * Parse a list token, handling mixed bullet and task list items by splitting them into separate lists.\n * This ensures that consecutive task items and bullet items are grouped and parsed as separate list nodes.\n *\n * @param token The list token to parse\n * @returns Array of parsed list nodes, or null if parsing fails\n */\n private parseListToken(token: MarkdownToken): JSONContent | JSONContent[] | null {\n if (!token.items || token.items.length === 0) {\n // No items, parse normally\n return this.parseTokenWithHandlers(token)\n }\n\n const hasTask = token.items.some(item => isTaskItem(item).isTask)\n const hasNonTask = token.items.some(item => !isTaskItem(item).isTask)\n\n if (!hasTask || !hasNonTask || this.getHandlersForToken('taskList').length === 0) {\n // Not mixed or no taskList extension, parse normally\n return this.parseTokenWithHandlers(token)\n }\n\n // Mixed list with taskList extension available: split into separate lists\n type TaskListItemToken = MarkdownToken & {\n type: 'taskItem'\n checked?: boolean\n indentLevel?: number\n }\n const groups: { type: 'list' | 'taskList'; items: (MarkdownToken | TaskListItemToken)[] }[] = []\n let currentGroup: (MarkdownToken | TaskListItemToken)[] = []\n let currentType: 'list' | 'taskList' | null = null\n\n for (let i = 0; i < token.items.length; i += 1) {\n const item = token.items[i]\n const { isTask, checked, indentLevel } = isTaskItem(item)\n let processedItem = item\n\n if (isTask) {\n // Transform list_item into taskItem token\n const raw = item.raw || item.text || ''\n\n // Split raw content by lines to separate main content from nested\n const lines = raw.split('\\n')\n\n // Extract main content from the first line\n const firstLineMatch = lines[0].match(/^\\s*[-+*]\\s+\\[([ xX])\\]\\s+(.*)$/)\n const mainContent = firstLineMatch ? firstLineMatch[2] : ''\n\n // Parse nested content from remaining lines\n let nestedTokens: MarkdownToken[] = []\n if (lines.length > 1) {\n // Join all lines after the first\n const nestedRaw = lines.slice(1).join('\\n')\n\n // Only parse if there's actual content\n if (nestedRaw.trim()) {\n // Find minimum indentation of non-empty lines\n const nestedLines = lines.slice(1)\n const nonEmptyLines = nestedLines.filter(line => line.trim())\n if (nonEmptyLines.length > 0) {\n const minIndent = Math.min(\n ...nonEmptyLines.map(line => line.length - line.trimStart().length),\n )\n // Remove common indentation while preserving structure\n const trimmedLines = nestedLines.map(line => {\n if (!line.trim()) {\n return '' // Keep empty lines\n }\n return line.slice(minIndent)\n })\n const nestedContent = trimmedLines.join('\\n').trim()\n // Use the lexer to parse nested content\n if (nestedContent) {\n // Use the full lexer pipeline to ensure inline tokens are populated\n nestedTokens = this.markedInstance.lexer(`${nestedContent}\\n`)\n }\n }\n }\n }\n\n processedItem = {\n type: 'taskItem',\n raw: '',\n mainContent,\n indentLevel,\n checked: checked ?? false,\n text: mainContent,\n tokens: this.tokenizeInline(mainContent),\n nestedTokens,\n }\n }\n\n const itemType: 'list' | 'taskList' = isTask ? 'taskList' : 'list'\n\n if (currentType !== itemType) {\n if (currentGroup.length > 0) {\n groups.push({ type: currentType!, items: currentGroup })\n }\n currentGroup = [processedItem]\n currentType = itemType\n } else {\n currentGroup.push(processedItem)\n }\n }\n\n if (currentGroup.length > 0) {\n groups.push({ type: currentType!, items: currentGroup })\n }\n\n // Parse each group as a separate token\n const results: JSONContent[] = []\n for (let i = 0; i < groups.length; i += 1) {\n const group = groups[i]\n const subToken = { ...token, type: group.type, items: group.items }\n const parsed = this.parseToken(subToken)\n if (parsed) {\n if (Array.isArray(parsed)) {\n results.push(...parsed)\n } else {\n results.push(parsed)\n }\n }\n }\n\n return results.length > 0 ? results : null\n }\n\n /**\n * Parse a token using registered handlers (extracted for reuse).\n */\n private parseTokenWithHandlers(token: MarkdownToken): JSONContent | JSONContent[] | null {\n if (!token.type) {\n return null\n }\n\n const handlers = this.getHandlersForToken(token.type)\n const helpers = this.createParseHelpers()\n\n // Try each handler until one returns a valid result\n const result = handlers.find(handler => {\n if (!handler.parseMarkdown) {\n return false\n }\n\n const parseResult = handler.parseMarkdown(token, helpers)\n const normalized = this.normalizeParseResult(parseResult)\n\n // Check if this handler returned a valid result (not null/empty array)\n if (normalized && (!Array.isArray(normalized) || normalized.length > 0)) {\n // Store result for return\n this.lastParseResult = normalized\n return true\n }\n\n return false\n })\n\n // If a handler worked, return its result\n if (result && this.lastParseResult) {\n const toReturn = this.lastParseResult\n this.lastParseResult = null // Clean up\n return toReturn\n }\n\n // If no handler worked, try fallback parsing\n return this.parseFallbackToken(token)\n }\n\n /**\n * Creates helper functions for parsing markdown tokens.\n * @returns An object containing helper functions for parsing.\n */\n private createParseHelpers(): MarkdownParseHelpers {\n return {\n parseInline: (tokens: MarkdownToken[]) => this.parseInlineTokens(tokens),\n tokenizeInline: (src: string) => this.tokenizeInline(src),\n parseChildren: (tokens: MarkdownToken[]) => this.parseTokens(tokens),\n parseBlockChildren: (tokens: MarkdownToken[]) => this.parseTokens(tokens, true),\n createTextNode: (text: string, marks?: Array<{ type: string; attrs?: any }>) => {\n const node = {\n type: 'text',\n text,\n marks: marks || undefined,\n }\n\n return node\n },\n createNode: (type: string, attrs?: any, content?: JSONContent[]) => {\n const node = {\n type,\n attrs: attrs || undefined,\n content: content || undefined,\n }\n\n if (!attrs || Object.keys(attrs).length === 0) {\n delete node.attrs\n }\n\n return node\n },\n applyMark: (markType: string, content: JSONContent[], attrs?: any) => ({\n mark: markType,\n content,\n attrs: attrs && Object.keys(attrs).length > 0 ? attrs : undefined,\n }),\n }\n }\n\n /**\n * Escape special regex characters in a string.\n */\n private escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n }\n\n /**\n * Parse inline tokens (bold, italic, links, etc.) into text nodes with marks.\n * This is the complex part that handles mark nesting and boundaries.\n */\n private parseInlineTokens(tokens: MarkdownToken[]): JSONContent[] {\n const result: JSONContent[] = []\n\n // Process tokens sequentially using an index so we can lookahead and\n // merge split inline HTML fragments like: text / / inner / / text\n for (let i = 0; i < tokens.length; i += 1) {\n const token = tokens[i]\n\n if (token.type === 'text') {\n // Create text node – decode HTML entities so that e.g. `<` displays as `<` in the editor\n result.push({\n type: 'text',\n text: decodeHtmlEntities(token.text || ''),\n })\n } else if (token.type === 'html') {\n // Handle possible split inline HTML by attempting to detect an\n // opening tag and searching forward for a matching closing tag.\n const raw = (token.raw ?? token.text ?? '').toString()\n\n // Quick checks for opening vs. closing tag\n const isClosing = /^<\\/[\\s]*[\\w-]+/i.test(raw)\n const openMatch = raw.match(/^<[\\s]*([\\w-]+)(\\s|>|\\/|$)/i)\n\n // oxlint-disable-next-line prefer-string-starts-ends-with\n if (!isClosing && openMatch && !/\\/>$/.test(raw)) {\n // Try to find the corresponding closing html token for this tag\n const tagName = openMatch[1]\n const escapedTagName = this.escapeRegex(tagName)\n const closingRegex = new RegExp(`^<\\\\/\\\\s*${escapedTagName}\\\\b`, 'i')\n let foundIndex = -1\n\n // Collect intermediate raw parts to reconstruct full HTML fragment\n const parts: string[] = [raw]\n for (let j = i + 1; j < tokens.length; j += 1) {\n const t = tokens[j]\n const tRaw = (t.raw ?? t.text ?? '').toString()\n parts.push(tRaw)\n if (t.type === 'html' && closingRegex.test(tRaw)) {\n foundIndex = j\n break\n }\n }\n\n if (foundIndex !== -1) {\n // Merge opening + inner + closing into one html fragment and parse\n const mergedRaw = parts.join('')\n const mergedToken = {\n type: 'html',\n raw: mergedRaw,\n text: mergedRaw,\n block: false,\n } as unknown as MarkdownToken\n\n const parsed = this.parseHTMLToken(mergedToken)\n if (parsed) {\n const normalized = this.normalizeParseResult(parsed as any)\n if (Array.isArray(normalized)) {\n result.push(...normalized)\n } else if (normalized) {\n result.push(normalized)\n }\n }\n\n // Advance i to the closing token\n i = foundIndex\n continue\n }\n }\n\n // Fallback: single html token parse\n const parsedSingle = this.parseHTMLToken(token)\n if (parsedSingle) {\n const normalized = this.normalizeParseResult(parsedSingle as any)\n if (Array.isArray(normalized)) {\n result.push(...normalized)\n } else if (normalized) {\n result.push(normalized)\n }\n }\n } else if (token.type) {\n // Handle inline marks (bold, italic, etc.)\n const markHandler = this.getHandlerForToken(token.type)\n if (markHandler && markHandler.parseMarkdown) {\n const helpers = this.createParseHelpers()\n const parsed = markHandler.parseMarkdown(token, helpers)\n\n if (this.isMarkResult(parsed)) {\n // This is a mark result - apply the mark to the content\n const markedContent = this.applyMarkToContent(parsed.mark, parsed.content, parsed.attrs)\n result.push(...markedContent)\n } else {\n // Regular inline node\n const normalized = this.normalizeParseResult(parsed)\n if (Array.isArray(normalized)) {\n result.push(...normalized)\n } else if (normalized) {\n result.push(normalized)\n }\n }\n } else if (token.tokens) {\n // Fallback: try to parse children if they exist\n result.push(...this.parseInlineTokens(token.tokens))\n }\n }\n }\n\n return result\n }\n\n /**\n * Apply a mark to content nodes.\n */\n private applyMarkToContent(markType: string, content: JSONContent[], attrs?: any): JSONContent[] {\n return content.map(node => {\n if (node.type === 'text') {\n // Add the mark to existing marks or create new marks array\n const existingMarks = node.marks || []\n const newMark = attrs ? { type: markType, attrs } : { type: markType }\n return {\n ...node,\n marks: [...existingMarks, newMark],\n }\n }\n\n // For non-text nodes, recursively apply to content\n return {\n ...node,\n content: node.content ? this.applyMarkToContent(markType, node.content, attrs) : undefined,\n }\n })\n } /**\n * Check if a parse result represents a mark to be applied.\n */\n private isMarkResult(\n result: any,\n ): result is { mark: string; content: JSONContent[]; attrs?: any } {\n return result && typeof result === 'object' && 'mark' in result\n }\n\n /**\n * Normalize parse results to ensure they're valid JSONContent.\n */\n private normalizeParseResult(result: MarkdownParseResult): JSONContent | JSONContent[] | null {\n if (!result) {\n return null\n }\n\n if (this.isMarkResult(result)) {\n // This shouldn't happen at the top level, but handle it gracefully\n return result.content\n }\n\n return result as JSONContent | JSONContent[]\n }\n\n /**\n * Fallback parsing for common tokens when no specific handler is registered.\n */\n private parseFallbackToken(\n token: MarkdownToken,\n parseImplicitEmptyParagraphs = false,\n ): JSONContent | JSONContent[] | null {\n switch (token.type) {\n case 'paragraph':\n return {\n type: 'paragraph',\n content: token.tokens ? this.parseInlineTokens(token.tokens) : [],\n }\n\n case 'heading':\n return {\n type: 'heading',\n attrs: { level: token.depth || 1 },\n content: token.tokens ? this.parseInlineTokens(token.tokens) : [],\n }\n\n case 'text':\n return {\n type: 'text',\n text: decodeHtmlEntities(token.text || ''),\n }\n\n case 'html':\n // Parse HTML using extensions' parseHTML methods\n return this.parseHTMLToken(token)\n\n case 'space':\n return null\n\n default:\n // Unknown token type - try to parse children if they exist\n if (token.tokens) {\n return this.parseTokens(token.tokens, parseImplicitEmptyParagraphs)\n }\n return null\n }\n }\n\n /**\n * Parse an HTML token from marked into JSONContent using the registered\n * extensions' `parseHTML` rules. Falls back to literal text when the HTML\n * has nothing for the schema to keep.\n *\n * @param token Marked HTML token (block or inline).\n * @example\n * parseHTMLToken({ type: 'html', raw: 'hi', block: false })\n * // → text node with an italic mark\n */\n private parseHTMLToken(token: MarkdownToken): JSONContent | JSONContent[] | null {\n const html = token.text || token.raw || ''\n\n if (!html.trim()) {\n return null\n }\n\n // Check if we're in a server-side environment (no window object)\n // If so, fall back to treating HTML as plain text to avoid runtime errors\n if (typeof window === 'undefined') {\n // For block-level HTML, wrap in a paragraph to maintain valid document structure\n if (token.block) {\n return {\n type: 'paragraph',\n content: [\n {\n type: 'text',\n text: html,\n },\n ],\n }\n }\n // For inline HTML, return plain text\n return {\n type: 'text',\n text: html,\n }\n }\n\n // If the HTML would parse to nothing meaningful, keep the original\n // characters as literal text instead of dropping them.\n if (this.isUnrecognizedHtml(html)) {\n return this.htmlAsLiteralText(html, !!token.block)\n }\n\n // Use generateJSON to parse the HTML using extensions' parseHTML rules\n try {\n const parsed = generateJSON(html, this.baseExtensions)\n\n // If the result is a doc node, extract its content\n if (parsed.type === 'doc' && parsed.content) {\n // For block-level HTML, return the content array\n if (token.block) {\n return parsed.content\n }\n\n // For inline HTML, we need to flatten the content appropriately\n // If there's only one paragraph with content, unwrap it\n if (\n parsed.content.length === 1 &&\n parsed.content[0].type === 'paragraph' &&\n parsed.content[0].content\n ) {\n return parsed.content[0].content\n }\n\n return parsed.content\n }\n\n return parsed as JSONContent\n } catch (error) {\n throw new Error(`Failed to parse HTML in markdown: ${error}`)\n }\n }\n\n /**\n * Returns true when the HTML contains an element the browser classifies as\n * `HTMLUnknownElement` – unless a registered extension declares the tag\n * name in its parseDOM rules, in which case it is treated as a known\n * custom element.\n *\n * Recognized but empty elements such as `` or ``,\n * and hyphenated custom elements like ``, are not considered\n * unrecognized.\n *\n * @param html Raw HTML string from a marked token.\n * @example\n * isUnrecognizedHtml('') // → true\n * isUnrecognizedHtml('') // → false (empty, but real tag)\n * isUnrecognizedHtml('hi') // → false\n * isUnrecognizedHtml('') // → false (valid custom element)\n * isUnrecognizedHtml('
') // → false\n */\n private isUnrecognizedHtml(html: string): boolean {\n if (typeof window === 'undefined' || typeof window.DOMParser === 'undefined') {\n // Can't reliably detect without DOMParser, so assume it's recognized to avoid false positives\n return false\n }\n\n const dom = new window.DOMParser().parseFromString(`${html}`, 'text/html').body\n const elements = dom.querySelectorAll('*')\n\n if (elements.length === 0) {\n return false\n }\n\n const schemaTags = this.getSchemaParseDomTags()\n\n return Array.from(elements).some(el => {\n if (!isHtmlUnknownElement(el)) {\n return false\n }\n\n // If the tag is declared by a registered extension's parseDOM rule,\n // treat it as recognized even though the browser doesn't know it.\n const tagName = el.tagName.toLowerCase()\n\n return !schemaTags.has(tagName)\n })\n }\n\n /**\n * Collect the lower-cased tag names declared by the registered extensions'\n * parseDOM rules, so custom node/mark elements that use non-hyphenated,\n * non-standard tag names are treated as recognized HTML. Result is cached for the\n * lifetime of the manager since extensions don't change after registration.\n *\n * @example\n * // After registering an extension with parseDOM [{ tag: 'something' }]\n * getSchemaParseDomTags().has('something') // → true\n */\n private getSchemaParseDomTags(): Set {\n if (this.schemaParseDomTagsCache) {\n return this.schemaParseDomTagsCache\n }\n\n const tags = new Set()\n\n try {\n const schema = getSchema(this.baseExtensions)\n\n const collect = (spec: any) => {\n const parseDOM = spec?.parseDOM\n if (!Array.isArray(parseDOM)) {\n return\n }\n parseDOM.forEach((rule: any) => {\n if (typeof rule?.tag === 'string') {\n // Extract the bare tag name from selectors like \"something.example\"\n const match = rule.tag.match(/^[a-zA-Z][\\w-]*/)\n if (match) {\n tags.add(match[0].toLowerCase())\n }\n }\n })\n }\n\n Object.values(schema.nodes).forEach(type => collect((type as any).spec))\n Object.values(schema.marks).forEach(type => collect((type as any).spec))\n } catch {\n // If schema construction fails, leave the set empty – detection then\n // falls back to the HTMLUnknownElement check alone.\n }\n\n this.schemaParseDomTagsCache = tags\n return tags\n }\n\n /**\n * Build a JSONContent that preserves the original HTML markup as literal\n * text. Used when the HTML would otherwise be silently dropped during\n * schema-aware parsing.\n *\n * @param html Raw HTML string to preserve verbatim.\n * @param isBlock Whether to wrap the text in a paragraph node (block tokens)\n * or return it as a bare text node (inline tokens).\n * @example\n * htmlAsLiteralText('', true)\n * // → { type: 'paragraph', content: [{ type: 'text', text: '' }] }\n */\n private htmlAsLiteralText(html: string, isBlock: boolean): JSONContent | JSONContent[] | null {\n // Strip trailing whitespace/newlines that marked appends to block HTML\n // tokens so the rendered text doesn't end with stray blank lines.\n const text = html.replace(/\\s+$/, '')\n\n if (!text) {\n return null\n }\n\n if (isBlock) {\n return {\n type: 'paragraph',\n content: [{ type: 'text', text }],\n }\n }\n\n return { type: 'text', text }\n }\n\n /**\n * Encode HTML entities in text unless the node is inside a code context\n * (code mark or code-block parent) where literal characters should be preserved.\n */\n private encodeTextForMarkdown(text: string, node: JSONContent, parentNode?: JSONContent): string {\n const isInsideCode =\n (parentNode?.type != null && this.codeTypes.has(parentNode.type)) ||\n (node.marks || []).some(m => this.codeTypes.has(typeof m === 'string' ? m : m.type))\n\n return isInsideCode ? text : encodeHtmlEntities(text)\n }\n\n renderNodeToMarkdown(\n node: JSONContent,\n parentNode?: JSONContent,\n index = 0,\n level = 0,\n meta: Record = {},\n ): string {\n // if node is a text node, we simply return it's text content\n // marks are handled at the array level in renderNodesWithMarkBoundaries\n if (node.type === 'text') {\n return this.encodeTextForMarkdown(node.text || '', node, parentNode)\n }\n\n if (!node.type) {\n return ''\n }\n\n const handler = this.getHandlerForToken(node.type)\n if (!handler) {\n return ''\n }\n\n const previousNode =\n Array.isArray(parentNode?.content) && index > 0 ? parentNode.content[index - 1] : undefined\n const helpers: MarkdownRendererHelpers = {\n renderChildren: (nodes, separator) => {\n const childLevel = handler.isIndenting ? level + 1 : level\n\n if (!Array.isArray(nodes) && (nodes as any).content) {\n return this.renderNodes(\n (nodes as any).content as JSONContent[],\n node,\n separator || '',\n index,\n childLevel,\n )\n }\n\n return this.renderNodes(nodes, node, separator || '', index, childLevel)\n },\n renderChild: (childNode, childIndex) => {\n const childLevel = handler.isIndenting ? level + 1 : level\n\n return this.renderNodeToMarkdown(childNode, node, childIndex, childLevel)\n },\n indent: content => {\n return this.indentString + content\n },\n wrapInBlock: wrapInMarkdownBlock,\n }\n\n const context: RenderContext = {\n index,\n level,\n parentType: parentNode?.type,\n previousNode,\n meta: {\n parentAttrs: parentNode?.attrs,\n ...meta,\n },\n }\n\n // First render the node itself (this will render children recursively)\n const rendered = handler.renderMarkdown?.(node, helpers, context) || ''\n\n return rendered\n }\n\n /**\n * Render a node or an array of nodes. Parent type controls how children\n * are joined (which determines newline insertion between children).\n */\n renderNodes(\n nodeOrNodes: JSONContent | JSONContent[],\n parentNode?: JSONContent,\n separator = '',\n index = 0,\n level = 0,\n ): string {\n // if we have just one node, call renderNodeToMarkdown directly\n if (!Array.isArray(nodeOrNodes)) {\n if (!nodeOrNodes.type) {\n return ''\n }\n\n return this.renderNodeToMarkdown(nodeOrNodes, parentNode, index, level)\n }\n\n return this.renderNodesWithMarkBoundaries(nodeOrNodes, parentNode, separator, level)\n }\n\n /**\n * Render an array of nodes while properly tracking mark boundaries.\n * This handles cases where marks span across multiple text nodes.\n */\n private renderNodesWithMarkBoundaries(\n nodes: JSONContent[],\n parentNode?: JSONContent,\n separator = '',\n level = 0,\n ): string {\n const result: string[] = []\n const activeMarks: Map = new Map()\n const reopenWithHtmlOnNextOpen = new Set()\n const markOpeningModes = new Map()\n nodes.forEach((node, i) => {\n // Lookahead to the next node to determine if marks need to be closed\n const nextNode = i < nodes.length - 1 ? nodes[i + 1] : null\n\n if (!node.type) {\n return\n }\n\n if (node.type === 'text') {\n let textContent = this.encodeTextForMarkdown(node.text || '', node, parentNode)\n const currentMarks = new Map((node.marks || []).map(mark => [mark.type, mark]))\n\n // Find marks that need to be closed and opened\n const marksToOpen = this.getMarksToOpenForSerialization(activeMarks, currentMarks, nextNode)\n const marksToClose = findMarksToClose(currentMarks, nextNode)\n\n // When marks simultaneously close (old) AND open (new) at this boundary, the naive\n // approach of appending old-close and prepending new-open produces interleaved\n // delimiters like `*456**` (italic open, text, bold close) instead of properly\n // nested `_456_**` (italic open, text, italic close, bold close).\n //\n // The fix: when both are present, defer old mark closings to the end of the node\n // (after the new marks also close), ensuring correct inner-before-outer order.\n //\n // If an already-active mark ends on this node while another mark opens on this same\n // node, we defer closing the active mark until the end of the node so nesting stays\n // valid (`**...++abc++**` instead of `**...++abc**++`).\n const activeMarksClosingHere = marksToClose.filter(markType => activeMarks.has(markType))\n const hasCrossedBoundary = activeMarksClosingHere.length > 0 && marksToOpen.length > 0\n\n let middleTrailingWhitespace = ''\n\n if (marksToClose.length > 0 && !hasCrossedBoundary) {\n // Extract trailing whitespace before closing marks to prevent invalid markdown like \"**text **\"\n const middleTrailingMatch = textContent.match(/(\\s+)$/)\n if (middleTrailingMatch) {\n middleTrailingWhitespace = middleTrailingMatch[1]\n textContent = textContent.slice(0, -middleTrailingWhitespace.length)\n }\n }\n\n if (!hasCrossedBoundary) {\n // Normal path: close marks that are ending here (no new marks opening simultaneously).\n // Reverse so the last-opened mark closes first (LIFO), preserving valid nesting.\n marksToClose\n .slice()\n .reverse()\n .forEach(markType => {\n if (!activeMarks.has(markType)) {\n return\n }\n\n const mark = currentMarks.get(markType)\n const closeMarkdown = this.getMarkClosing(\n markType,\n mark,\n markOpeningModes.get(markType),\n )\n if (closeMarkdown) {\n textContent += closeMarkdown\n }\n if (activeMarks.has(markType)) {\n activeMarks.delete(markType)\n markOpeningModes.delete(markType)\n }\n })\n }\n\n // Open new marks (should be at the beginning)\n // Extract leading whitespace before opening marks to prevent invalid markdown like \"** text**\"\n let leadingWhitespace = ''\n if (marksToOpen.length > 0) {\n const leadingMatch = textContent.match(/^(\\s+)/)\n if (leadingMatch) {\n leadingWhitespace = leadingMatch[1]\n textContent = textContent.slice(leadingWhitespace.length)\n }\n }\n\n // Snapshot active mark types before opening new marks, so each new mark's delimiter\n // is chosen based on what is already active (not including itself).\n // When crossing a boundary, old marks are still in activeMarks here (not yet removed),\n // so new marks correctly see them as active context.\n marksToOpen.forEach(({ type, mark }) => {\n const openingMode = reopenWithHtmlOnNextOpen.has(type) ? 'html' : 'markdown'\n const openMarkdown = this.getMarkOpening(type, mark, openingMode)\n if (openMarkdown) {\n textContent = openMarkdown + textContent\n }\n markOpeningModes.set(type, openingMode)\n reopenWithHtmlOnNextOpen.delete(type)\n })\n\n if (!hasCrossedBoundary) {\n marksToOpen\n .slice()\n .reverse()\n .forEach(({ type, mark }) => {\n activeMarks.set(type, mark)\n })\n }\n\n // Add leading whitespace before the mark opening\n textContent = leadingWhitespace + textContent\n\n // Determine marks to close at the end of this node.\n // On a crossed boundary, we close new marks (inner) first, then old marks (outer),\n // ensuring correct nesting order. Both sets are removed from activeMarks so the\n // next node's marksToOpen will reopen whichever ones continue.\n let marksToCloseAtEnd: string[]\n if (hasCrossedBoundary) {\n const nextMarkTypes = new Set((nextNode?.marks || []).map((mark: any) => mark.type))\n\n marksToOpen.forEach(({ type }) => {\n if (nextMarkTypes.has(type) && this.getHtmlReopenTags(type)) {\n reopenWithHtmlOnNextOpen.add(type)\n }\n })\n\n // Sort the previously-active closures in LIFO order: the mark that\n // was opened last (innermost) must close first. activeMarks preserves\n // insertion order, so a higher indexOf means opened later = inner.\n const activeMarkKeys = Array.from(activeMarks.keys())\n const activeMarksClosingHereLifo = activeMarksClosingHere\n .slice()\n .sort((a, b) => activeMarkKeys.indexOf(b) - activeMarkKeys.indexOf(a))\n\n marksToCloseAtEnd = [\n ...marksToOpen.map(m => m.type), // inner (opened here) — close first\n ...activeMarksClosingHereLifo, // outer (were active before) — close last, LIFO\n ]\n } else {\n marksToCloseAtEnd = findMarksToCloseAtEnd(\n activeMarks,\n currentMarks,\n nextNode,\n this.markSetsEqual.bind(this),\n )\n }\n\n // Extract trailing whitespace before closing marks to prevent invalid markdown like \"**text **\"\n let trailingWhitespace = ''\n if (marksToCloseAtEnd.length > 0) {\n const trailingMatch = textContent.match(/(\\s+)$/)\n if (trailingMatch) {\n trailingWhitespace = trailingMatch[1]\n textContent = textContent.slice(0, -trailingWhitespace.length)\n }\n }\n\n marksToCloseAtEnd.forEach(markType => {\n const mark = activeMarks.get(markType) ?? currentMarks.get(markType)\n const closeMarkdown = this.getMarkClosing(markType, mark, markOpeningModes.get(markType))\n if (closeMarkdown) {\n textContent += closeMarkdown\n }\n activeMarks.delete(markType)\n markOpeningModes.delete(markType)\n })\n\n // Add trailing whitespace after the mark closing\n textContent += trailingWhitespace\n textContent += middleTrailingWhitespace\n\n result.push(textContent)\n } else {\n // For non-text nodes, close all active marks before rendering, then reopen after\n // Only reopen marks that the node itself carries — marks don't skip over inline atoms.\n const nodeMarkTypes = new Set((node.marks || []).map((mark: { type: string }) => mark.type))\n const marksToReopen = new Map }>()\n const openingModesToReopen = new Map()\n activeMarks.forEach((mark, type) => {\n if (nodeMarkTypes.has(type)) {\n marksToReopen.set(type, mark)\n openingModesToReopen.set(type, markOpeningModes.get(type) ?? 'markdown')\n }\n })\n\n // Close all marks before the node\n const beforeMarkdown = closeMarksBeforeNode(activeMarks, (markType, mark) => {\n return this.getMarkClosing(markType, mark, markOpeningModes.get(markType))\n })\n markOpeningModes.clear()\n\n // Render the node\n const nodeContent = this.renderNodeToMarkdown(node, parentNode, i, level)\n\n // Reopen marks after the node, but NOT after a hard break\n // Hard breaks should terminate marks (they create a line break where marks don't continue)\n const afterMarkdown =\n node.type === 'hardBreak'\n ? ''\n : reopenMarksAfterNode(marksToReopen, activeMarks, (markType, mark) => {\n const openingMode = openingModesToReopen.get(markType) ?? 'markdown'\n markOpeningModes.set(markType, openingMode)\n return this.getMarkOpening(markType, mark, openingMode)\n })\n\n result.push(beforeMarkdown + nodeContent + afterMarkdown)\n }\n })\n\n return result.join(separator)\n }\n\n /**\n * Get the opening markdown syntax for a mark type.\n */\n private getMarkOpening(\n markType: string,\n mark: any,\n openingMode: 'markdown' | 'html' = 'markdown',\n ): string {\n if (openingMode === 'html') {\n return this.getHtmlReopenTags(markType)?.open || ''\n }\n\n const handlers = this.getHandlersForNodeType(markType)\n const handler = handlers.length > 0 ? handlers[0] : undefined\n if (!handler || !handler.renderMarkdown) {\n return ''\n }\n\n // Use a unique placeholder that's extremely unlikely to appear in real content\n const placeholder = '\\uE000__TIPTAP_MARKDOWN_PLACEHOLDER__\\uE001'\n\n // For most marks, we can extract the opening syntax by rendering a simple case\n const syntheticNode: JSONContent = {\n type: markType,\n attrs: mark.attrs || {},\n content: [{ type: 'text', text: placeholder }],\n }\n\n try {\n const rendered = handler.renderMarkdown(\n syntheticNode,\n {\n renderChildren: () => placeholder,\n renderChild: () => placeholder,\n indent: (content: string) => content,\n wrapInBlock: (prefix: string, content: string) => prefix + content,\n },\n { index: 0, level: 0, parentType: 'text', meta: {} },\n )\n\n // Extract the opening part (everything before placeholder)\n const placeholderIndex = rendered.indexOf(placeholder)\n return placeholderIndex >= 0 ? rendered.substring(0, placeholderIndex) : ''\n } catch (err) {\n throw new Error(`Failed to get mark opening for ${markType}: ${err}`)\n }\n }\n\n /**\n * Get the closing markdown syntax for a mark type.\n */\n private getMarkClosing(\n markType: string,\n mark: any,\n openingMode: 'markdown' | 'html' = 'markdown',\n ): string {\n if (openingMode === 'html') {\n return this.getHtmlReopenTags(markType)?.close || ''\n }\n\n const handlers = this.getHandlersForNodeType(markType)\n const handler = handlers.length > 0 ? handlers[0] : undefined\n if (!handler || !handler.renderMarkdown) {\n return ''\n }\n\n // Use a unique placeholder that's extremely unlikely to appear in real content\n const placeholder = '\\uE000__TIPTAP_MARKDOWN_PLACEHOLDER__\\uE001'\n\n const syntheticNode: JSONContent = {\n type: markType,\n attrs: mark.attrs || {},\n content: [{ type: 'text', text: placeholder }],\n }\n\n try {\n const rendered = handler.renderMarkdown(\n syntheticNode,\n {\n renderChildren: () => placeholder,\n renderChild: () => placeholder,\n indent: (content: string) => content,\n wrapInBlock: (prefix: string, content: string) => prefix + content,\n },\n { index: 0, level: 0, parentType: 'text', meta: {} },\n )\n\n // Extract the closing part (everything after placeholder)\n const placeholderIndex = rendered.indexOf(placeholder)\n const placeholderEnd = placeholderIndex + placeholder.length\n return placeholderIndex >= 0 ? rendered.substring(placeholderEnd) : ''\n } catch (err) {\n throw new Error(`Failed to get mark closing for ${markType}: ${err}`)\n }\n }\n\n /**\n * Returns the inline HTML tags an extension exposes for overlap-boundary\n * reopen handling, if that mark explicitly opted into HTML reopen mode.\n */\n private getHtmlReopenTags(markType: string): { open: string; close: string } | undefined {\n const handlers = this.getHandlersForNodeType(markType)\n const handler = handlers.length > 0 ? handlers[0] : undefined\n\n return handler?.htmlReopen\n }\n\n /**\n * Check if two mark sets are equal (same types and matching attributes).\n */\n private markSetsEqual(marks1: Map, marks2: Map): boolean {\n if (marks1.size !== marks2.size) {\n return false\n }\n\n return Array.from(marks1.entries()).every(([type, mark]) => {\n const otherMark = marks2.get(type)\n return otherMark && attrsEqual(mark.attrs, otherMark.attrs)\n })\n }\n\n /**\n * Decide the order in which marks open on the current text node.\n *\n * The returned array is iterated head-first when prepending opening\n * delimiters, so the first entry becomes the innermost mark in the emitted\n * markdown and the last becomes the outermost. Two stable signals drive\n * the order — neither one inspects any rendered markdown:\n *\n * 1. Marks that end on this node must be inner relative to marks that\n * continue into the next node, otherwise the delimiters interleave\n * instead of nesting.\n * 2. Within each lifetime group, marks are sorted so that lower\n * registration ranks (i.e. higher Tiptap extension priorities) end up\n * outermost. ProseMirror assigns mark ranks in the same priority-aware\n * order Tiptap uses when building the schema, so link (priority 1000)\n * naturally wraps bold/italic without the serializer needing to peek\n * at how any particular mark renders.\n */\n private getMarksToOpenForSerialization(\n activeMarks: Map,\n currentMarks: Map,\n nextNode: any,\n ) {\n const marksToOpen = findMarksToOpen(activeMarks, currentMarks)\n\n if (marksToOpen.length <= 1) {\n return marksToOpen\n }\n\n const nextMarks = nextNode?.marks || []\n\n // Helper: check if the next node has a mark with the same type AND\n // matching attributes. Two marks of the same type but with different\n // attributes are logically distinct and must not be treated as continuing.\n const continuesInNextNode = (markType: string, attrs: any) =>\n nextMarks.some((m: any) => m.type === markType && attrsEqual(m.attrs, attrs))\n\n // Higher rank → earlier in the array → innermost mark. Marks without a\n // recorded rank fall back to MAX_SAFE_INTEGER so they sort innermost,\n // matching the implicit \"registered last\" assumption for ad-hoc marks.\n const byRankInnerFirst = (a: { type: string }, b: { type: string }) => {\n const rankA = this.extensionRanks.get(a.type) ?? Number.MAX_SAFE_INTEGER\n const rankB = this.extensionRanks.get(b.type) ?? Number.MAX_SAFE_INTEGER\n\n if (rankA !== rankB) {\n return rankB - rankA\n }\n\n return a.type.localeCompare(b.type)\n }\n\n const endingHere = marksToOpen\n .filter(mark => !continuesInNextNode(mark.type, mark.mark.attrs))\n .sort(byRankInnerFirst)\n const continuing = marksToOpen\n .filter(mark => continuesInNextNode(mark.type, mark.mark.attrs))\n .sort(byRankInnerFirst)\n\n return [...endingHere, ...continuing]\n }\n}\n\nexport default MarkdownManager\n","import type { Content, MarkdownToken } from '@tiptap/core'\nimport type { Fragment, Node } from '@tiptap/pm/model'\n\nimport type { ContentType } from './types.js'\n\n/**\n * Wraps each line of the content with the given prefix.\n * @param prefix The prefix to wrap each line with.\n * @param content The content to wrap.\n * @returns The content with each line wrapped with the prefix.\n */\nexport function wrapInMarkdownBlock(prefix: string, content: string) {\n // split content lines\n const lines = content.split('\\n')\n\n // add empty strings between every line\n const output = lines\n // add empty lines between each block\n .flatMap(line => [line, ''])\n // add the prefix to each line\n .map(line => `${prefix}${line}`)\n .join('\\n')\n\n return output.slice(0, output.length - 1)\n}\n\n/**\n * Compare two attribute objects for equality.\n * Handles null/undefined and asserts key presence in both objects so that\n * `{ foo: undefined }` and `{ bar: undefined }` are not treated as equal.\n */\nexport function attrsEqual(\n a: Record | null | undefined,\n b: Record | null | undefined,\n): boolean {\n if (a === b) {\n return true\n }\n if (!a || !b) {\n return false\n }\n\n const keysA = Object.keys(a)\n const keysB = Object.keys(b)\n\n if (keysA.length !== keysB.length) {\n return false\n }\n\n return keysA.every(\n key => Object.prototype.hasOwnProperty.call(b, key) && Object.is(a[key], b[key]),\n )\n}\n\n/**\n * Identifies marks that need to be closed, based on the marks in the next node.\n * Compares both mark type and attributes — two marks of the same type with\n * different attributes are treated as distinct and need to be closed/reopened.\n */\nexport function findMarksToClose(currentMarks: Map, nextNode: any): string[] {\n const marksToClose: string[] = []\n\n Array.from(currentMarks.entries()).forEach(([markType, currentMark]) => {\n if (!nextNode) {\n marksToClose.push(markType)\n return\n }\n\n // Check if the next node has a mark of the same type with matching attributes\n const nextMark = (nextNode.marks || []).find(\n (mark: any) => mark.type === markType && attrsEqual(mark.attrs, currentMark.attrs),\n )\n\n if (!nextMark) {\n marksToClose.push(markType)\n }\n })\n return marksToClose\n}\n\n/**\n * Identifies marks that need to be opened (in current node but not active, or\n * active with different attributes). Two marks of the same type with different\n * attributes are treated as distinct — the old one must be closed and the new\n * one reopened.\n */\nexport function findMarksToOpen(\n activeMarks: Map,\n currentMarks: Map,\n): Array<{ type: string; mark: any }> {\n const marksToOpen: Array<{ type: string; mark: any }> = []\n Array.from(currentMarks.entries()).forEach(([markType, mark]) => {\n const activeMark = activeMarks.get(markType)\n\n // Open if the mark type is not active, or if the attributes differ\n if (!activeMark || !attrsEqual(activeMark.attrs, mark.attrs)) {\n marksToOpen.push({ type: markType, mark })\n }\n })\n return marksToOpen\n}\n\n/**\n * Determines which marks need to be closed at the end of the current text node.\n * This handles cases where marks end at node boundaries or when transitioning\n * to nodes with different mark sets.\n * Compares both mark type and attributes — two marks of the same type with\n * different attributes are treated as distinct and trigger a close/reopen.\n */\nexport function findMarksToCloseAtEnd(\n activeMarks: Map,\n currentMarks: Map,\n nextNode: any,\n markSetsEqual: (a: Map, b: Map) => boolean,\n): string[] {\n const isLastNode = !nextNode\n const nextNodeHasNoMarks = nextNode && (!nextNode.marks || nextNode.marks.length === 0)\n const nextNodeHasDifferentMarks =\n nextNode &&\n nextNode.marks &&\n !markSetsEqual(currentMarks, new Map(nextNode.marks.map((mark: any) => [mark.type, mark])))\n\n const marksToCloseAtEnd: string[] = []\n if (isLastNode || nextNodeHasNoMarks || nextNodeHasDifferentMarks) {\n if (nextNode && nextNode.marks) {\n Array.from(activeMarks.entries())\n .reverse()\n .forEach(([markType, activeMark]) => {\n // Check if nextNode has a mark of the same type with matching attrs\n const nextMark = nextNode.marks.find(\n (m: any) => m.type === markType && attrsEqual(m.attrs, activeMark.attrs),\n )\n if (!nextMark) {\n marksToCloseAtEnd.push(markType)\n }\n })\n } else if (isLastNode || nextNodeHasNoMarks) {\n // Close all active marks\n marksToCloseAtEnd.push(...Array.from(activeMarks.keys()).reverse())\n }\n }\n\n return marksToCloseAtEnd\n}\n\n/**\n * Closes active marks before rendering a non-text node.\n * Returns the closing markdown syntax and clears the active marks.\n */\nexport function closeMarksBeforeNode(\n activeMarks: Map,\n getMarkClosing: (markType: string, mark: any) => string,\n): string {\n let beforeMarkdown = ''\n Array.from(activeMarks.keys())\n .reverse()\n .forEach(markType => {\n const mark = activeMarks.get(markType)\n const closeMarkdown = getMarkClosing(markType, mark)\n if (closeMarkdown) {\n beforeMarkdown = closeMarkdown + beforeMarkdown\n }\n })\n activeMarks.clear()\n return beforeMarkdown\n}\n\n/**\n * Reopens marks after rendering a non-text node.\n * Returns the opening markdown syntax and updates the active marks.\n */\nexport function reopenMarksAfterNode(\n marksToReopen: Map,\n activeMarks: Map,\n getMarkOpening: (markType: string, mark: any) => string,\n): string {\n let afterMarkdown = ''\n Array.from(marksToReopen.entries()).forEach(([markType, mark]) => {\n const openMarkdown = getMarkOpening(markType, mark)\n if (openMarkdown) {\n afterMarkdown += openMarkdown\n }\n activeMarks.set(markType, mark)\n })\n return afterMarkdown\n}\n\n/**\n * Check if a markdown list item token is a task item and extract its state.\n *\n * @param item The list item token to check\n * @returns Object containing isTask flag, checked state, and indentation level\n *\n * @example\n * ```ts\n * isTaskItem({ raw: '- [ ] Task' }) // { isTask: true, checked: false, indentLevel: 0 }\n * isTaskItem({ raw: ' - [x] Done' }) // { isTask: true, checked: true, indentLevel: 2 }\n * isTaskItem({ raw: '- Regular' }) // { isTask: false, indentLevel: 0 }\n * ```\n */\nexport function isTaskItem(item: MarkdownToken): {\n isTask: boolean\n checked?: boolean\n indentLevel: number\n} {\n const raw = item.raw || item.text || ''\n\n // Match patterns like \"- [ ] \" or \" - [x] \"\n const match = raw.match(/^(\\s*)[-+*]\\s+\\[([ xX])\\]\\s+/)\n\n if (match) {\n return { isTask: true, checked: match[2].toLowerCase() === 'x', indentLevel: match[1].length }\n }\n return { isTask: false, indentLevel: 0 }\n}\n\n/**\n * Assumes the content type based off the content.\n * @param content The content to assume the type for.\n * @param contentType The content type that should be prioritized.\n */\nexport function assumeContentType(\n content: (Content | Fragment | Node) | string,\n contentType: ContentType,\n): ContentType {\n // if not a string, we assume it will be a json content object\n if (typeof content !== 'string') {\n return 'json'\n }\n\n // otherwise we let the content type be what it is\n return contentType\n}\n"],"mappings":"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","names":[]}