@pixerate/editor 0.16.0 → 0.16.1

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.
@@ -1,4 +1,7 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/serializers/mentions.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/serializers/plain-text.ts
2
+ var _model = require('@tiptap/pm/model');
3
+
4
+ // src/serializers/mentions.ts
2
5
  var MENTION_REGEX = /(?:^|[\s>(*_"';\\/[\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:"([^"]+)"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*))/g;
3
6
  var MARKDOWN_MENTION_SPLIT_REGEX = /(```[\s\S]*?```|~~~[\s\S]*?~~~|<pre[\s\S]*?<\/pre>|<code[\s\S]*?<\/code>|`[^`\n]+`|<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["']|data-mention=["'][^"']*["'])[^>]*>[\s\S]*?<\/span>|<[^>]+>|\]\([^)]+\)|(?:https?|file|vscode|cursor|mailto):\/\/[^\s<)]+)/gi;
4
7
  function stripMarkdownCode(content) {
@@ -155,6 +158,20 @@ function plainTextToTipTapHtml(text) {
155
158
  }
156
159
  return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => `<p>${escapeHtml(line)}</p>`).join("");
157
160
  }
161
+ function plainTextToSlice(text, schema) {
162
+ const nodes = [];
163
+ text.replace(/\r\n?/g, "\n").split("\n").forEach((line) => {
164
+ const nodeJson = { type: "paragraph" };
165
+ if (line.length > 0) {
166
+ nodeJson.content = [{ type: "text", text: line }];
167
+ }
168
+ try {
169
+ nodes.push(_model.Node.fromJSON(schema, nodeJson));
170
+ } catch (e2) {
171
+ }
172
+ });
173
+ return _model.Slice.maxOpen(_model.Fragment.fromArray(nodes));
174
+ }
158
175
  var BLOCK_TAGS = /* @__PURE__ */ new Set([
159
176
  "P",
160
177
  "DIV",
@@ -249,7 +266,7 @@ function getEditorText(editor) {
249
266
  if (typeof editor.getText === "function") {
250
267
  try {
251
268
  return editor.getText({ blockSeparator: "\n" });
252
- } catch (e2) {
269
+ } catch (e3) {
253
270
  return editor.getText();
254
271
  }
255
272
  }
@@ -510,5 +527,6 @@ function getEditorMarkdown(editor) {
510
527
 
511
528
 
512
529
 
513
- exports.MENTION_REGEX = MENTION_REGEX; exports.MARKDOWN_MENTION_SPLIT_REGEX = MARKDOWN_MENTION_SPLIT_REGEX; exports.stripMarkdownCode = stripMarkdownCode; exports.extractMentions = extractMentions; exports.parseMentionSegments = parseMentionSegments; exports.preprocessMarkdownMentions = preprocessMarkdownMentions; exports.escapeHtml = escapeHtml; exports.plainTextToTipTapHtml = plainTextToTipTapHtml; exports.htmlToPlainText = htmlToPlainText; exports.getEditorText = getEditorText; exports.extractMentionsFromDoc = extractMentionsFromDoc; exports.preprocessMarkdownFileLinks = preprocessMarkdownFileLinks; exports.markdownToTipTapHtml = markdownToTipTapHtml; exports.getEditorMarkdown = getEditorMarkdown;
514
- //# sourceMappingURL=chunk-SHWP2A43.cjs.map
530
+
531
+ exports.MENTION_REGEX = MENTION_REGEX; exports.MARKDOWN_MENTION_SPLIT_REGEX = MARKDOWN_MENTION_SPLIT_REGEX; exports.stripMarkdownCode = stripMarkdownCode; exports.extractMentions = extractMentions; exports.parseMentionSegments = parseMentionSegments; exports.preprocessMarkdownMentions = preprocessMarkdownMentions; exports.escapeHtml = escapeHtml; exports.plainTextToTipTapHtml = plainTextToTipTapHtml; exports.plainTextToSlice = plainTextToSlice; exports.htmlToPlainText = htmlToPlainText; exports.getEditorText = getEditorText; exports.extractMentionsFromDoc = extractMentionsFromDoc; exports.preprocessMarkdownFileLinks = preprocessMarkdownFileLinks; exports.markdownToTipTapHtml = markdownToTipTapHtml; exports.getEditorMarkdown = getEditorMarkdown;
532
+ //# sourceMappingURL=chunk-LLUAKTLW.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-LLUAKTLW.cjs","../src/serializers/plain-text.ts","../src/serializers/mentions.ts","../src/serializers/markdown.ts"],"names":["match"],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-LLUAKTLW.cjs","sourcesContent":[null,"import { Slice, Fragment, Node as ProsemirrorNode, type Schema } from \"@tiptap/pm/model\";\n\n/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Matches strings that are already TipTap paragraph HTML (start with `<p>` and\n * end with `</p>`), as opposed to plain text that merely mentions a `<p>` tag.\n */\nconst PARAGRAPH_HTML_REGEX = /^\\s*<p[\\s>][\\s\\S]*<\\/p>\\s*$/i;\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n * Input that is already paragraph HTML (`<p>…</p>`) is passed through as-is.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (PARAGRAPH_HTML_REGEX.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Builds an open ProseMirror slice with one paragraph per line, so inserting it\n * splits the surrounding paragraph like typing Enter would. Use it for\n * plain-text paste handling (`clipboardTextParser`) and literal text insertion.\n */\nexport function plainTextToSlice(text: string, schema: Schema): Slice {\n const nodes: ProsemirrorNode[] = [];\n text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .forEach((line) => {\n const nodeJson: any = { type: \"paragraph\" };\n if (line.length > 0) {\n nodeJson.content = [{ type: \"text\", text: line }];\n }\n try {\n nodes.push(ProsemirrorNode.fromJSON(schema, nodeJson));\n } catch {\n // Ignore invalid node\n }\n });\n return Slice.maxOpen(Fragment.fromArray(nodes));\n}\n\n/**\n * Block-level elements that start a new line in plain-text output.\n */\nconst BLOCK_TAGS = new Set([\n \"P\", \"DIV\", \"LI\", \"UL\", \"OL\", \"PRE\", \"BLOCKQUOTE\", \"TABLE\", \"TR\",\n \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"HR\",\n]);\n\n/**\n * Matches a TipTap mention span (including its content). The lookahead keeps\n * a single `[^>]*` scan per tag, avoiding catastrophic backtracking on\n * malformed input.\n */\nconst MENTION_SPAN_REGEX =\n /<span\\b(?=[^>]*\\bdata-type=[\"']mention[\"'])([^>]*)>[\\s\\S]*?<\\/span>/gi;\n\nfunction getHtmlAttribute(attrs: string, name: string): string | undefined {\n const match = new RegExp(`\\\\b${name}=(?:\"([^\"]*)\"|'([^']*)')`, \"i\").exec(\n attrs,\n );\n return match ? (match[1] ?? match[2]) : undefined;\n}\n\n/**\n * Parses HTML into an inert fragment. Content of a `<template>` element is not\n * rendered, so `<img onerror>` and similar handlers never run.\n */\nfunction parseHtmlFragment(html: string): DocumentFragment {\n const template = document.createElement(\"template\");\n template.innerHTML = html;\n return template.content;\n}\n\nfunction decodeHtmlEntities(text: string): string {\n return text\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#0*39;/g, \"'\")\n .replace(/&nbsp;/g, \"\\u00a0\")\n .replace(/&amp;/g, \"&\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html.replace(MENTION_SPAN_REGEX, (match, attrs) => {\n const label =\n getHtmlAttribute(attrs, \"data-label\") || getHtmlAttribute(attrs, \"data-id\");\n return label ? `@${label}` : match;\n });\n\n if (typeof document !== \"undefined\") {\n const fragment = parseHtmlFragment(mentionNormalized);\n fragment\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n\n // Walk the tree, emitting one line per innermost block so nested blocks\n // (e.g. TipTap's <li><p>…</p></li>) are not repeated.\n const lines: string[] = [];\n let current: string | null = null;\n const flush = () => {\n if (current !== null) {\n lines.push(current);\n current = null;\n }\n };\n const visit = (node: Node) => {\n if (node.nodeType === 3) {\n const value = node.nodeValue ?? \"\";\n // Skip formatting whitespace between blocks.\n if (current === null && value.trim() === \"\") return;\n current = (current ?? \"\") + value;\n return;\n }\n if (node.nodeType !== 1) return;\n const tag = (node as Element).tagName.toUpperCase();\n if (tag === \"BR\") {\n current = (current ?? \"\") + \"\\n\";\n return;\n }\n if (!BLOCK_TAGS.has(tag)) {\n node.childNodes.forEach(visit);\n return;\n }\n flush();\n const linesBefore = lines.length;\n node.childNodes.forEach(visit);\n flush();\n // An empty block (e.g. <p></p>) is an empty line.\n if (lines.length === linesBefore && tag !== \"HR\") {\n lines.push(\"\");\n }\n };\n fragment.childNodes.forEach(visit);\n flush();\n return lines.join(\"\\n\");\n }\n\n // Node.js fallback regex\n const text = mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n // A closing block, plus any closing wrappers right after it, ends one line.\n .replace(\n /<\\/(?:p|div|li|pre|blockquote|h[1-6])>(?:\\s*<\\/(?:li|ul|ol|blockquote|div)>)*/gi,\n \"\\n\",\n )\n .replace(/<[^>]+>/g, \"\");\n return decodeHtmlEntities(text).replace(/\\n$/, \"\");\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\nimport { extractMentions } from \"./mentions\";\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n parseHtmlFragment(docOrEditor).querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n\n // Fallback: If no HTML mention tags were found, extract raw @mentions from text or markdown\n if (mentions.length === 0) {\n const rawHandles = extractMentions(docOrEditor);\n for (const handle of rawHandles) {\n mentions.push({\n id: handle,\n label: handle,\n type: \"user\",\n });\n }\n }\n }\n\n return mentions;\n}\n","import { escapeHtml } from \"./plain-text\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Canonical regex pattern for matching @mentions in plain text or markdown.\n * Supports:\n * - Standard unquoted handles: @username, @user.name, @team_alpha, @sa-1\n * - Quoted handles: @\"John Doe\", &quot;Jane Doe&quot;\n * Unquoted handles exclude trailing punctuation (e.g. @violet. matches \"violet\" without the dot).\n */\nexport const MENTION_REGEX =\n /(?:^|[\\s>(*_\"';\\\\/[\\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:\"([^\"]+)\"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\\.[a-zA-Z0-9_-]+)*))/g;\n\n/**\n * Split regex identifying markdown code blocks, inline code, URLs, and existing HTML tags.\n * Used by preprocessMarkdownMentions to ensure non-mention regions remain completely untouched.\n */\nexport const MARKDOWN_MENTION_SPLIT_REGEX =\n /(```[\\s\\S]*?```|~~~[\\s\\S]*?~~~|<pre[\\s\\S]*?<\\/pre>|<code[\\s\\S]*?<\\/code>|`[^`\\n]+`|<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])[^>]*>[\\s\\S]*?<\\/span>|<[^>]+>|\\]\\([^)]+\\)|(?:https?|file|vscode|cursor|mailto):\\/\\/[^\\s<)]+)/gi;\n\nexport interface MentionSegment {\n type: \"text\" | \"mention\";\n value: string;\n handle?: string;\n}\n\nexport interface PreprocessMarkdownMentionsOptions {\n /**\n * Known pool of mentionable entities (users, agents, teams, etc.).\n */\n mentionables?: MentionEntity[];\n /**\n * Default entity type assigned when a handle does not match any entry in mentionables.\n * Defaults to 'user'.\n */\n defaultType?: string;\n /**\n * Custom resolver callback to derive entity metadata for unmatched handles.\n */\n resolveMention?: (handle: string) => Partial<MentionEntity> | null | undefined;\n}\n\n/**\n * Strips code blocks and inline code from markdown or HTML content:\n * - Fenced code blocks: ```...``` and ~~~...~~~\n * - Inline backtick code: `...`\n * - HTML code/pre tags: <pre>...</pre>, <code>...</code>\n * Used to avoid false-positive mention parsing and keyword analysis within code snippets, terminal logs, or stack traces.\n */\nexport function stripMarkdownCode(content: string): string {\n if (!content || typeof content !== \"string\") return \"\";\n return content\n .replace(/```[\\s\\S]*?```/g, \"\")\n .replace(/~~~[\\s\\S]*?~~~/g, \"\")\n .replace(/<pre[\\s\\S]*?<\\/pre>/gi, \"\")\n .replace(/<code[\\s\\S]*?<\\/code>/gi, \"\")\n .replace(/`[^`\\n]*`/g, \"\");\n}\n\n/**\n * Extracts unique mention handles from a text, markdown, or HTML string,\n * ignoring trailing punctuation, code blocks, URLs, and pre-existing HTML mention attributes.\n */\nexport function extractMentions(content: string): string[] {\n if (!content || typeof content !== \"string\") return [];\n\n // Normalize existing HTML mention nodes (e.g. from TipTap or rich text serializers)\n // so data-mention-suggestion-char=\"@\" does not trigger spurious quoted matches against attributes,\n // and ensure the actual mentioned label or ID is preserved cleanly.\n const normalizedMentionNodes = content.replace(\n /<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"'])[^>]*>([\\s\\S]*?)<\\/span>/gi,\n (match, inner) => {\n const labelMatch = match.match(/\\bdata-label=[\"']([^\"']+)[\"']/i);\n if (labelMatch) return ` @${labelMatch[1]} `;\n const idMatch = match.match(/\\bdata-id=[\"']([^\"']+)[\"']/i);\n if (idMatch) return ` @${idMatch[1]} `;\n return ` ${inner} `;\n }\n );\n\n const cleanContent = stripMarkdownCode(normalizedMentionNodes);\n // Strip URLs and markdown link destinations so @package or @handles in URLs are not extracted as mentions\n const withoutUrls = cleanContent\n .replace(/(?:https?|ftp|file|vscode|cursor|mailto):\\/\\/[^\\s<>()]+/gi, \"\")\n .replace(/\\]\\([^)]*\\)/g, \"]\");\n // Strip remaining HTML tags so attributes containing '@' or '>' aren't treated as mention triggers\n const textOnly = withoutUrls.replace(/<[^>]+>/g, \" \");\n\n const mentions: string[] = [];\n const seen = new Set<string>();\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(textOnly)) !== null) {\n const handle = (match[1] ?? match[2] ?? match[3] ?? \"\").trim();\n if (handle && !seen.has(handle)) {\n seen.add(handle);\n mentions.push(handle);\n }\n }\n\n return mentions;\n}\n\n/**\n * Segments a text string into plain text parts and mention tokens.\n * Correctly leaves trailing punctuation (like \".\") as part of the following text segment.\n */\nexport function parseMentionSegments(content: string): MentionSegment[] {\n if (!content) return [];\n\n const segments: MentionSegment[] = [];\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const fullMatch = match[0];\n const atIndex = fullMatch.indexOf(\"@\");\n const prefix = atIndex > 0 ? fullMatch.slice(0, atIndex) : \"\";\n const mentionToken = fullMatch.slice(atIndex);\n const handle = match[1] ?? match[2] ?? match[3];\n const matchStart = match.index + prefix.length;\n\n if (matchStart > lastIndex) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex, matchStart),\n });\n }\n\n segments.push({\n type: \"mention\",\n value: mentionToken,\n handle,\n });\n\n lastIndex = matchStart + mentionToken.length;\n }\n\n if (lastIndex < content.length) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex),\n });\n }\n\n return segments;\n}\n\n/**\n * Preprocesses markdown text by turning raw @mention handles into TipTap-compatible\n * mention HTML spans (<span class=\"pixerate-mention-node\" data-type=\"mention\" ...>),\n * ensuring code blocks, inline code, existing mention nodes, and URLs remain immune.\n */\nexport function preprocessMarkdownMentions(\n content: string,\n optionsOrMentionables: MentionEntity[] | PreprocessMarkdownMentionsOptions = []\n): string {\n if (!content || typeof content !== \"string\") return \"\";\n\n const options: PreprocessMarkdownMentionsOptions = Array.isArray(optionsOrMentionables)\n ? { mentionables: optionsOrMentionables }\n : optionsOrMentionables;\n\n const allMentionables = options.mentionables || [];\n const defaultType = options.defaultType || \"user\";\n const resolveMention = options.resolveMention;\n\n const parts = content.split(MARKDOWN_MENTION_SPLIT_REGEX);\n\n return parts\n .map((part) => {\n if (!part) return \"\";\n\n // Preserve code fences, code tags, inline backticks, existing mention spans,\n // HTML tags, markdown link targets, and raw URLs untouched.\n if (\n part.startsWith(\"```\") ||\n part.startsWith(\"~~~\") ||\n part.startsWith(\"`\") ||\n part.startsWith(\"](\") ||\n /^(?:https?|file|vscode|cursor|mailto):\\/\\//i.test(part) ||\n /^<pre[\\s>]/i.test(part) ||\n /^<code[\\s>]/i.test(part) ||\n /^<[^>]+>$/i.test(part) ||\n /^<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])/i.test(\n part\n )\n ) {\n return part;\n }\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n return part.replace(regex, (match, quotedHandle, escapedQuotedHandle, standardHandle) => {\n const atIndex = match.indexOf(\"@\");\n const prefix = atIndex > 0 ? match.slice(0, atIndex) : \"\";\n const rawHandle = (quotedHandle || escapedQuotedHandle || standardHandle || \"\").trim();\n if (!rawHandle) return match;\n\n const lowerHandle = rawHandle.toLowerCase();\n const entity = allMentionables.find((e) => {\n if (e.label?.toLowerCase() === lowerHandle) return true;\n if (e.handle?.toLowerCase() === lowerHandle) return true;\n if (e.name?.toLowerCase() === lowerHandle) return true;\n if (e.id?.toLowerCase() === lowerHandle) return true;\n if (e.type === \"agent\" && `agent${(e.handle || e.label || \"\").toLowerCase()}` === lowerHandle) return true;\n if (\n e.aliases?.some(\n (a: string) =>\n a.toLowerCase() === lowerHandle ||\n (e.type === \"agent\" && `agent${a.toLowerCase()}` === lowerHandle)\n )\n ) {\n return true;\n }\n return false;\n });\n\n let id = entity?.id;\n let label = entity?.label || entity?.handle || rawHandle;\n let type = entity?.type;\n let avatarUrl = entity?.avatarUrl;\n let color = entity?.color || entity?.hexColor;\n\n if (!entity) {\n const customResolved = resolveMention?.(rawHandle);\n if (customResolved) {\n id = customResolved.id ?? id;\n label = customResolved.label ?? customResolved.handle ?? label;\n type = customResolved.type ?? type;\n avatarUrl = customResolved.avatarUrl ?? avatarUrl;\n color = customResolved.color ?? customResolved.hexColor ?? color;\n } else {\n const stripped = lowerHandle.replace(/^agent[\\s\\-_]*/i, \"\");\n if (\n [\"supervisor\", \"coordinator\", \"planner\", \"validator\", \"executor\"].includes(stripped)\n ) {\n type = \"agent\";\n id = stripped;\n label = stripped;\n } else if (lowerHandle === \"agents\") {\n type = \"team\";\n id = \"agents\";\n label = \"agents\";\n } else {\n type = defaultType;\n id = rawHandle;\n label = rawHandle;\n }\n }\n }\n\n const avatarAttr = avatarUrl ? ` data-avatar-url=\"${escapeHtml(avatarUrl)}\"` : \"\";\n const colorAttr = color ? ` data-color=\"${escapeHtml(color)}\"` : \"\";\n\n return `${prefix}<span class=\"pixerate-mention-node\" data-type=\"mention\" data-id=\"${escapeHtml(\n id || label\n )}\" data-label=\"${escapeHtml(label)}\" data-mention-suggestion-char=\"@\" data-type-name=\"${escapeHtml(\n type || defaultType\n )}\"${avatarAttr}${colorAttr}>@${escapeHtml(label)}</span>`;\n });\n })\n .join(\"\");\n}\n","import MarkdownIt from \"markdown-it\";\nimport taskLists from \"markdown-it-task-lists\";\nimport { escapeHtml, getEditorText } from \"./plain-text\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n}).use(taskLists);\n\nconst defaultValidateLink = md.validateLink;\nmd.validateLink = (url: string) => {\n if (\n url.startsWith(\"file://\") ||\n url.startsWith(\"vscode://\") ||\n url.startsWith(\"cursor://\")\n ) {\n return true;\n }\n return defaultValidateLink.call(md, url);\n};\n\n/**\n * Tags allowed through from raw HTML embedded in markdown (e.g. mention spans\n * and file links that tiptap-markdown serializes as HTML). Anything else is\n * rendered as escaped text. `input` is limited to checkboxes, which\n * markdown-it-task-lists emits as raw HTML.\n */\nconst ALLOWED_HTML_TAGS = new Set([\n \"a\", \"abbr\", \"b\", \"blockquote\", \"br\", \"code\", \"del\", \"details\", \"div\", \"em\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"hr\", \"i\", \"img\", \"input\", \"kbd\", \"li\", \"mark\",\n \"ol\", \"p\", \"pre\", \"s\", \"span\", \"strong\", \"sub\", \"summary\", \"sup\", \"table\",\n \"tbody\", \"td\", \"tfoot\", \"th\", \"thead\", \"tr\", \"u\", \"ul\",\n]);\n\nconst ALLOWED_HTML_ATTRS = new Set([\n \"alt\", \"align\", \"checked\", \"class\", \"colspan\", \"disabled\", \"height\", \"href\",\n \"rel\", \"rowspan\", \"src\", \"start\", \"target\", \"title\", \"type\", \"width\",\n]);\n\nconst HTML_TAG_REGEX =\n /<(\\/?)([a-zA-Z][a-zA-Z0-9-]*)((?:\\s+[^\\s\"'>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s\"'=<>`]+))?)*)\\s*\\/?>/g;\nconst HTML_ATTR_REGEX =\n /([^\\s\"'>\\/=]+)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'=<>`]+)))?/g;\n\nfunction sanitizeTag(\n tagText: string,\n isClosing: string,\n rawTagName: string,\n rawAttrs: string,\n): string {\n const tagName = rawTagName.toLowerCase();\n if (!ALLOWED_HTML_TAGS.has(tagName)) return escapeHtml(tagText);\n if (isClosing) return `</${tagName}>`;\n if (tagName === \"input\" && !/\\stype\\s*=\\s*[\"']?checkbox[\"']?[\\s>/]/i.test(tagText)) {\n return escapeHtml(tagText);\n }\n\n let attrs = \"\";\n let attrMatch: RegExpExecArray | null;\n HTML_ATTR_REGEX.lastIndex = 0;\n while ((attrMatch = HTML_ATTR_REGEX.exec(rawAttrs)) !== null) {\n const name = attrMatch[1].toLowerCase();\n if (!ALLOWED_HTML_ATTRS.has(name) && !/^data-[a-z0-9_.-]+$/.test(name)) {\n continue;\n }\n const rawValue = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4];\n if (rawValue === undefined) {\n attrs += ` ${name}`;\n continue;\n }\n const value = md.utils.unescapeAll(rawValue);\n if (\n (name === \"href\" || name === \"src\") &&\n // Browsers ignore control characters and whitespace inside schemes.\n !md.validateLink(value.replace(/[\\u0000-\\u0020\\u007f]/g, \"\"))\n ) {\n continue;\n }\n attrs += ` ${name}=\"${escapeHtml(value)}\"`;\n }\n return `<${tagName}${attrs}>`;\n}\n\n/**\n * Sanitizes raw HTML with an allowlist of tags and attributes: event handlers,\n * `style`, and unsafe URL schemes are dropped; disallowed tags are escaped.\n */\nfunction sanitizeEmbeddedHtml(html: string): string {\n let result = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n HTML_TAG_REGEX.lastIndex = 0;\n while ((match = HTML_TAG_REGEX.exec(html)) !== null) {\n result += html.slice(lastIndex, match.index).replace(/</g, \"&lt;\");\n result += sanitizeTag(match[0], match[1], match[2], match[3]);\n lastIndex = match.index + match[0].length;\n }\n return result + html.slice(lastIndex).replace(/</g, \"&lt;\");\n}\n\nconst defaultHtmlInline = md.renderer.rules.html_inline;\nconst defaultHtmlBlock = md.renderer.rules.html_block;\nmd.renderer.rules.html_inline = (tokens, idx, options, env, self) =>\n env?.allowUnsafeHtml\n ? defaultHtmlInline!(tokens, idx, options, env, self)\n : sanitizeEmbeddedHtml(tokens[idx].content);\nmd.renderer.rules.html_block = (tokens, idx, options, env, self) =>\n env?.allowUnsafeHtml\n ? defaultHtmlBlock!(tokens, idx, options, env, self)\n : sanitizeEmbeddedHtml(tokens[idx].content);\n\nimport {\n preprocessMarkdownMentions,\n type PreprocessMarkdownMentionsOptions,\n} from \"./mentions\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Preprocesses file-protocol and editor-protocol links in markdown content:\n * converts [label](file://...), vscode://, and cursor:// links into anchor tags\n * annotated with data-file-link=\"true\", preserving code backticks in labels.\n */\nexport function preprocessMarkdownFileLinks(content: string): string {\n if (!content) return \"\";\n return content.replace(\n /\\[([^\\]]+)\\]\\(((?:file|vscode|cursor):\\/\\/[^)]+)\\)/g,\n (_match, rawLabel, href) => {\n const trimmed = rawLabel.trim();\n const codeMatch = trimmed.match(/^`([^`]+)`$/);\n const labelContent = codeMatch\n ? `<code>${escapeHtml(codeMatch[1])}</code>`\n : escapeHtml(trimmed);\n return `<a href=\"${escapeHtml(href)}\" data-file-link=\"true\" title=\"Click to copy file path\">${labelContent}</a>`;\n }\n );\n}\n\nexport interface MarkdownToHtmlOptions {\n /**\n * Preprocess file, vscode, and cursor links into clickable data-file-link tags.\n */\n preprocessFileLinks?: boolean;\n /**\n * Whether to preprocess @mentions into TipTap mention node HTML spans.\n */\n preprocessMentions?: boolean;\n /**\n * Pool of mentionables to pass to preprocessMarkdownMentions.\n */\n mentionables?: MentionEntity[];\n /**\n * Full options for preprocessMarkdownMentions.\n */\n preprocessOptions?: PreprocessMarkdownMentionsOptions;\n /**\n * Render raw HTML embedded in the markdown without sanitizing it. By default,\n * embedded HTML is restricted to an allowlist of tags and attributes (event\n * handlers, `style` and unsafe URL schemes are removed). Only enable this for\n * fully trusted input.\n */\n allowUnsafeHtml?: boolean;\n}\n\n/**\n * Converts a markdown string into HTML suitable for TipTap initial content or setContent.\n * Raw HTML embedded in the markdown is sanitized unless `allowUnsafeHtml` is set.\n */\nexport function markdownToTipTapHtml(\n markdown: string,\n options?: MarkdownToHtmlOptions\n): string {\n if (!markdown) return \"<p></p>\";\n let content = markdown;\n if (options?.preprocessFileLinks) {\n content = preprocessMarkdownFileLinks(content);\n }\n if (\n options?.preprocessMentions ||\n options?.mentionables ||\n options?.preprocessOptions\n ) {\n const mentionOpts = options.preprocessOptions || {\n mentionables: options.mentionables,\n };\n content = preprocessMarkdownMentions(content, mentionOpts);\n }\n return md.render(content, { allowUnsafeHtml: options?.allowUnsafeHtml });\n}\n\n/**\n * Extracts clean markdown from a TipTap editor instance.\n * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().\n * Otherwise, it falls back to getEditorText(editor).\n */\nexport function getEditorMarkdown(editor: any): string {\n if (!editor) return \"\";\n if (typeof editor.storage?.markdown?.getMarkdown === \"function\") {\n return editor.storage.markdown.getMarkdown();\n }\n return getEditorText(editor);\n}\n"]}
@@ -1,3 +1,6 @@
1
+ // src/serializers/plain-text.ts
2
+ import { Slice, Fragment, Node as ProsemirrorNode } from "@tiptap/pm/model";
3
+
1
4
  // src/serializers/mentions.ts
2
5
  var MENTION_REGEX = /(?:^|[\s>(*_"';\\/[\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:"([^"]+)"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*))/g;
3
6
  var MARKDOWN_MENTION_SPLIT_REGEX = /(```[\s\S]*?```|~~~[\s\S]*?~~~|<pre[\s\S]*?<\/pre>|<code[\s\S]*?<\/code>|`[^`\n]+`|<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["']|data-mention=["'][^"']*["'])[^>]*>[\s\S]*?<\/span>|<[^>]+>|\]\([^)]+\)|(?:https?|file|vscode|cursor|mailto):\/\/[^\s<)]+)/gi;
@@ -155,6 +158,20 @@ function plainTextToTipTapHtml(text) {
155
158
  }
156
159
  return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => `<p>${escapeHtml(line)}</p>`).join("");
157
160
  }
161
+ function plainTextToSlice(text, schema) {
162
+ const nodes = [];
163
+ text.replace(/\r\n?/g, "\n").split("\n").forEach((line) => {
164
+ const nodeJson = { type: "paragraph" };
165
+ if (line.length > 0) {
166
+ nodeJson.content = [{ type: "text", text: line }];
167
+ }
168
+ try {
169
+ nodes.push(ProsemirrorNode.fromJSON(schema, nodeJson));
170
+ } catch {
171
+ }
172
+ });
173
+ return Slice.maxOpen(Fragment.fromArray(nodes));
174
+ }
158
175
  var BLOCK_TAGS = /* @__PURE__ */ new Set([
159
176
  "P",
160
177
  "DIV",
@@ -504,6 +521,7 @@ export {
504
521
  preprocessMarkdownMentions,
505
522
  escapeHtml,
506
523
  plainTextToTipTapHtml,
524
+ plainTextToSlice,
507
525
  htmlToPlainText,
508
526
  getEditorText,
509
527
  extractMentionsFromDoc,
@@ -511,4 +529,4 @@ export {
511
529
  markdownToTipTapHtml,
512
530
  getEditorMarkdown
513
531
  };
514
- //# sourceMappingURL=chunk-BYCOFZAA.js.map
532
+ //# sourceMappingURL=chunk-QGVMBCT5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/serializers/plain-text.ts","../src/serializers/mentions.ts","../src/serializers/markdown.ts"],"sourcesContent":["import { Slice, Fragment, Node as ProsemirrorNode, type Schema } from \"@tiptap/pm/model\";\n\n/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Matches strings that are already TipTap paragraph HTML (start with `<p>` and\n * end with `</p>`), as opposed to plain text that merely mentions a `<p>` tag.\n */\nconst PARAGRAPH_HTML_REGEX = /^\\s*<p[\\s>][\\s\\S]*<\\/p>\\s*$/i;\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n * Input that is already paragraph HTML (`<p>…</p>`) is passed through as-is.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (PARAGRAPH_HTML_REGEX.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Builds an open ProseMirror slice with one paragraph per line, so inserting it\n * splits the surrounding paragraph like typing Enter would. Use it for\n * plain-text paste handling (`clipboardTextParser`) and literal text insertion.\n */\nexport function plainTextToSlice(text: string, schema: Schema): Slice {\n const nodes: ProsemirrorNode[] = [];\n text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .forEach((line) => {\n const nodeJson: any = { type: \"paragraph\" };\n if (line.length > 0) {\n nodeJson.content = [{ type: \"text\", text: line }];\n }\n try {\n nodes.push(ProsemirrorNode.fromJSON(schema, nodeJson));\n } catch {\n // Ignore invalid node\n }\n });\n return Slice.maxOpen(Fragment.fromArray(nodes));\n}\n\n/**\n * Block-level elements that start a new line in plain-text output.\n */\nconst BLOCK_TAGS = new Set([\n \"P\", \"DIV\", \"LI\", \"UL\", \"OL\", \"PRE\", \"BLOCKQUOTE\", \"TABLE\", \"TR\",\n \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"HR\",\n]);\n\n/**\n * Matches a TipTap mention span (including its content). The lookahead keeps\n * a single `[^>]*` scan per tag, avoiding catastrophic backtracking on\n * malformed input.\n */\nconst MENTION_SPAN_REGEX =\n /<span\\b(?=[^>]*\\bdata-type=[\"']mention[\"'])([^>]*)>[\\s\\S]*?<\\/span>/gi;\n\nfunction getHtmlAttribute(attrs: string, name: string): string | undefined {\n const match = new RegExp(`\\\\b${name}=(?:\"([^\"]*)\"|'([^']*)')`, \"i\").exec(\n attrs,\n );\n return match ? (match[1] ?? match[2]) : undefined;\n}\n\n/**\n * Parses HTML into an inert fragment. Content of a `<template>` element is not\n * rendered, so `<img onerror>` and similar handlers never run.\n */\nfunction parseHtmlFragment(html: string): DocumentFragment {\n const template = document.createElement(\"template\");\n template.innerHTML = html;\n return template.content;\n}\n\nfunction decodeHtmlEntities(text: string): string {\n return text\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#0*39;/g, \"'\")\n .replace(/&nbsp;/g, \"\\u00a0\")\n .replace(/&amp;/g, \"&\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html.replace(MENTION_SPAN_REGEX, (match, attrs) => {\n const label =\n getHtmlAttribute(attrs, \"data-label\") || getHtmlAttribute(attrs, \"data-id\");\n return label ? `@${label}` : match;\n });\n\n if (typeof document !== \"undefined\") {\n const fragment = parseHtmlFragment(mentionNormalized);\n fragment\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n\n // Walk the tree, emitting one line per innermost block so nested blocks\n // (e.g. TipTap's <li><p>…</p></li>) are not repeated.\n const lines: string[] = [];\n let current: string | null = null;\n const flush = () => {\n if (current !== null) {\n lines.push(current);\n current = null;\n }\n };\n const visit = (node: Node) => {\n if (node.nodeType === 3) {\n const value = node.nodeValue ?? \"\";\n // Skip formatting whitespace between blocks.\n if (current === null && value.trim() === \"\") return;\n current = (current ?? \"\") + value;\n return;\n }\n if (node.nodeType !== 1) return;\n const tag = (node as Element).tagName.toUpperCase();\n if (tag === \"BR\") {\n current = (current ?? \"\") + \"\\n\";\n return;\n }\n if (!BLOCK_TAGS.has(tag)) {\n node.childNodes.forEach(visit);\n return;\n }\n flush();\n const linesBefore = lines.length;\n node.childNodes.forEach(visit);\n flush();\n // An empty block (e.g. <p></p>) is an empty line.\n if (lines.length === linesBefore && tag !== \"HR\") {\n lines.push(\"\");\n }\n };\n fragment.childNodes.forEach(visit);\n flush();\n return lines.join(\"\\n\");\n }\n\n // Node.js fallback regex\n const text = mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n // A closing block, plus any closing wrappers right after it, ends one line.\n .replace(\n /<\\/(?:p|div|li|pre|blockquote|h[1-6])>(?:\\s*<\\/(?:li|ul|ol|blockquote|div)>)*/gi,\n \"\\n\",\n )\n .replace(/<[^>]+>/g, \"\");\n return decodeHtmlEntities(text).replace(/\\n$/, \"\");\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\nimport { extractMentions } from \"./mentions\";\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n parseHtmlFragment(docOrEditor).querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n\n // Fallback: If no HTML mention tags were found, extract raw @mentions from text or markdown\n if (mentions.length === 0) {\n const rawHandles = extractMentions(docOrEditor);\n for (const handle of rawHandles) {\n mentions.push({\n id: handle,\n label: handle,\n type: \"user\",\n });\n }\n }\n }\n\n return mentions;\n}\n","import { escapeHtml } from \"./plain-text\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Canonical regex pattern for matching @mentions in plain text or markdown.\n * Supports:\n * - Standard unquoted handles: @username, @user.name, @team_alpha, @sa-1\n * - Quoted handles: @\"John Doe\", &quot;Jane Doe&quot;\n * Unquoted handles exclude trailing punctuation (e.g. @violet. matches \"violet\" without the dot).\n */\nexport const MENTION_REGEX =\n /(?:^|[\\s>(*_\"';\\\\/[\\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:\"([^\"]+)\"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\\.[a-zA-Z0-9_-]+)*))/g;\n\n/**\n * Split regex identifying markdown code blocks, inline code, URLs, and existing HTML tags.\n * Used by preprocessMarkdownMentions to ensure non-mention regions remain completely untouched.\n */\nexport const MARKDOWN_MENTION_SPLIT_REGEX =\n /(```[\\s\\S]*?```|~~~[\\s\\S]*?~~~|<pre[\\s\\S]*?<\\/pre>|<code[\\s\\S]*?<\\/code>|`[^`\\n]+`|<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])[^>]*>[\\s\\S]*?<\\/span>|<[^>]+>|\\]\\([^)]+\\)|(?:https?|file|vscode|cursor|mailto):\\/\\/[^\\s<)]+)/gi;\n\nexport interface MentionSegment {\n type: \"text\" | \"mention\";\n value: string;\n handle?: string;\n}\n\nexport interface PreprocessMarkdownMentionsOptions {\n /**\n * Known pool of mentionable entities (users, agents, teams, etc.).\n */\n mentionables?: MentionEntity[];\n /**\n * Default entity type assigned when a handle does not match any entry in mentionables.\n * Defaults to 'user'.\n */\n defaultType?: string;\n /**\n * Custom resolver callback to derive entity metadata for unmatched handles.\n */\n resolveMention?: (handle: string) => Partial<MentionEntity> | null | undefined;\n}\n\n/**\n * Strips code blocks and inline code from markdown or HTML content:\n * - Fenced code blocks: ```...``` and ~~~...~~~\n * - Inline backtick code: `...`\n * - HTML code/pre tags: <pre>...</pre>, <code>...</code>\n * Used to avoid false-positive mention parsing and keyword analysis within code snippets, terminal logs, or stack traces.\n */\nexport function stripMarkdownCode(content: string): string {\n if (!content || typeof content !== \"string\") return \"\";\n return content\n .replace(/```[\\s\\S]*?```/g, \"\")\n .replace(/~~~[\\s\\S]*?~~~/g, \"\")\n .replace(/<pre[\\s\\S]*?<\\/pre>/gi, \"\")\n .replace(/<code[\\s\\S]*?<\\/code>/gi, \"\")\n .replace(/`[^`\\n]*`/g, \"\");\n}\n\n/**\n * Extracts unique mention handles from a text, markdown, or HTML string,\n * ignoring trailing punctuation, code blocks, URLs, and pre-existing HTML mention attributes.\n */\nexport function extractMentions(content: string): string[] {\n if (!content || typeof content !== \"string\") return [];\n\n // Normalize existing HTML mention nodes (e.g. from TipTap or rich text serializers)\n // so data-mention-suggestion-char=\"@\" does not trigger spurious quoted matches against attributes,\n // and ensure the actual mentioned label or ID is preserved cleanly.\n const normalizedMentionNodes = content.replace(\n /<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"'])[^>]*>([\\s\\S]*?)<\\/span>/gi,\n (match, inner) => {\n const labelMatch = match.match(/\\bdata-label=[\"']([^\"']+)[\"']/i);\n if (labelMatch) return ` @${labelMatch[1]} `;\n const idMatch = match.match(/\\bdata-id=[\"']([^\"']+)[\"']/i);\n if (idMatch) return ` @${idMatch[1]} `;\n return ` ${inner} `;\n }\n );\n\n const cleanContent = stripMarkdownCode(normalizedMentionNodes);\n // Strip URLs and markdown link destinations so @package or @handles in URLs are not extracted as mentions\n const withoutUrls = cleanContent\n .replace(/(?:https?|ftp|file|vscode|cursor|mailto):\\/\\/[^\\s<>()]+/gi, \"\")\n .replace(/\\]\\([^)]*\\)/g, \"]\");\n // Strip remaining HTML tags so attributes containing '@' or '>' aren't treated as mention triggers\n const textOnly = withoutUrls.replace(/<[^>]+>/g, \" \");\n\n const mentions: string[] = [];\n const seen = new Set<string>();\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(textOnly)) !== null) {\n const handle = (match[1] ?? match[2] ?? match[3] ?? \"\").trim();\n if (handle && !seen.has(handle)) {\n seen.add(handle);\n mentions.push(handle);\n }\n }\n\n return mentions;\n}\n\n/**\n * Segments a text string into plain text parts and mention tokens.\n * Correctly leaves trailing punctuation (like \".\") as part of the following text segment.\n */\nexport function parseMentionSegments(content: string): MentionSegment[] {\n if (!content) return [];\n\n const segments: MentionSegment[] = [];\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const fullMatch = match[0];\n const atIndex = fullMatch.indexOf(\"@\");\n const prefix = atIndex > 0 ? fullMatch.slice(0, atIndex) : \"\";\n const mentionToken = fullMatch.slice(atIndex);\n const handle = match[1] ?? match[2] ?? match[3];\n const matchStart = match.index + prefix.length;\n\n if (matchStart > lastIndex) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex, matchStart),\n });\n }\n\n segments.push({\n type: \"mention\",\n value: mentionToken,\n handle,\n });\n\n lastIndex = matchStart + mentionToken.length;\n }\n\n if (lastIndex < content.length) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex),\n });\n }\n\n return segments;\n}\n\n/**\n * Preprocesses markdown text by turning raw @mention handles into TipTap-compatible\n * mention HTML spans (<span class=\"pixerate-mention-node\" data-type=\"mention\" ...>),\n * ensuring code blocks, inline code, existing mention nodes, and URLs remain immune.\n */\nexport function preprocessMarkdownMentions(\n content: string,\n optionsOrMentionables: MentionEntity[] | PreprocessMarkdownMentionsOptions = []\n): string {\n if (!content || typeof content !== \"string\") return \"\";\n\n const options: PreprocessMarkdownMentionsOptions = Array.isArray(optionsOrMentionables)\n ? { mentionables: optionsOrMentionables }\n : optionsOrMentionables;\n\n const allMentionables = options.mentionables || [];\n const defaultType = options.defaultType || \"user\";\n const resolveMention = options.resolveMention;\n\n const parts = content.split(MARKDOWN_MENTION_SPLIT_REGEX);\n\n return parts\n .map((part) => {\n if (!part) return \"\";\n\n // Preserve code fences, code tags, inline backticks, existing mention spans,\n // HTML tags, markdown link targets, and raw URLs untouched.\n if (\n part.startsWith(\"```\") ||\n part.startsWith(\"~~~\") ||\n part.startsWith(\"`\") ||\n part.startsWith(\"](\") ||\n /^(?:https?|file|vscode|cursor|mailto):\\/\\//i.test(part) ||\n /^<pre[\\s>]/i.test(part) ||\n /^<code[\\s>]/i.test(part) ||\n /^<[^>]+>$/i.test(part) ||\n /^<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])/i.test(\n part\n )\n ) {\n return part;\n }\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n return part.replace(regex, (match, quotedHandle, escapedQuotedHandle, standardHandle) => {\n const atIndex = match.indexOf(\"@\");\n const prefix = atIndex > 0 ? match.slice(0, atIndex) : \"\";\n const rawHandle = (quotedHandle || escapedQuotedHandle || standardHandle || \"\").trim();\n if (!rawHandle) return match;\n\n const lowerHandle = rawHandle.toLowerCase();\n const entity = allMentionables.find((e) => {\n if (e.label?.toLowerCase() === lowerHandle) return true;\n if (e.handle?.toLowerCase() === lowerHandle) return true;\n if (e.name?.toLowerCase() === lowerHandle) return true;\n if (e.id?.toLowerCase() === lowerHandle) return true;\n if (e.type === \"agent\" && `agent${(e.handle || e.label || \"\").toLowerCase()}` === lowerHandle) return true;\n if (\n e.aliases?.some(\n (a: string) =>\n a.toLowerCase() === lowerHandle ||\n (e.type === \"agent\" && `agent${a.toLowerCase()}` === lowerHandle)\n )\n ) {\n return true;\n }\n return false;\n });\n\n let id = entity?.id;\n let label = entity?.label || entity?.handle || rawHandle;\n let type = entity?.type;\n let avatarUrl = entity?.avatarUrl;\n let color = entity?.color || entity?.hexColor;\n\n if (!entity) {\n const customResolved = resolveMention?.(rawHandle);\n if (customResolved) {\n id = customResolved.id ?? id;\n label = customResolved.label ?? customResolved.handle ?? label;\n type = customResolved.type ?? type;\n avatarUrl = customResolved.avatarUrl ?? avatarUrl;\n color = customResolved.color ?? customResolved.hexColor ?? color;\n } else {\n const stripped = lowerHandle.replace(/^agent[\\s\\-_]*/i, \"\");\n if (\n [\"supervisor\", \"coordinator\", \"planner\", \"validator\", \"executor\"].includes(stripped)\n ) {\n type = \"agent\";\n id = stripped;\n label = stripped;\n } else if (lowerHandle === \"agents\") {\n type = \"team\";\n id = \"agents\";\n label = \"agents\";\n } else {\n type = defaultType;\n id = rawHandle;\n label = rawHandle;\n }\n }\n }\n\n const avatarAttr = avatarUrl ? ` data-avatar-url=\"${escapeHtml(avatarUrl)}\"` : \"\";\n const colorAttr = color ? ` data-color=\"${escapeHtml(color)}\"` : \"\";\n\n return `${prefix}<span class=\"pixerate-mention-node\" data-type=\"mention\" data-id=\"${escapeHtml(\n id || label\n )}\" data-label=\"${escapeHtml(label)}\" data-mention-suggestion-char=\"@\" data-type-name=\"${escapeHtml(\n type || defaultType\n )}\"${avatarAttr}${colorAttr}>@${escapeHtml(label)}</span>`;\n });\n })\n .join(\"\");\n}\n","import MarkdownIt from \"markdown-it\";\nimport taskLists from \"markdown-it-task-lists\";\nimport { escapeHtml, getEditorText } from \"./plain-text\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n}).use(taskLists);\n\nconst defaultValidateLink = md.validateLink;\nmd.validateLink = (url: string) => {\n if (\n url.startsWith(\"file://\") ||\n url.startsWith(\"vscode://\") ||\n url.startsWith(\"cursor://\")\n ) {\n return true;\n }\n return defaultValidateLink.call(md, url);\n};\n\n/**\n * Tags allowed through from raw HTML embedded in markdown (e.g. mention spans\n * and file links that tiptap-markdown serializes as HTML). Anything else is\n * rendered as escaped text. `input` is limited to checkboxes, which\n * markdown-it-task-lists emits as raw HTML.\n */\nconst ALLOWED_HTML_TAGS = new Set([\n \"a\", \"abbr\", \"b\", \"blockquote\", \"br\", \"code\", \"del\", \"details\", \"div\", \"em\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"hr\", \"i\", \"img\", \"input\", \"kbd\", \"li\", \"mark\",\n \"ol\", \"p\", \"pre\", \"s\", \"span\", \"strong\", \"sub\", \"summary\", \"sup\", \"table\",\n \"tbody\", \"td\", \"tfoot\", \"th\", \"thead\", \"tr\", \"u\", \"ul\",\n]);\n\nconst ALLOWED_HTML_ATTRS = new Set([\n \"alt\", \"align\", \"checked\", \"class\", \"colspan\", \"disabled\", \"height\", \"href\",\n \"rel\", \"rowspan\", \"src\", \"start\", \"target\", \"title\", \"type\", \"width\",\n]);\n\nconst HTML_TAG_REGEX =\n /<(\\/?)([a-zA-Z][a-zA-Z0-9-]*)((?:\\s+[^\\s\"'>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s\"'=<>`]+))?)*)\\s*\\/?>/g;\nconst HTML_ATTR_REGEX =\n /([^\\s\"'>\\/=]+)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'=<>`]+)))?/g;\n\nfunction sanitizeTag(\n tagText: string,\n isClosing: string,\n rawTagName: string,\n rawAttrs: string,\n): string {\n const tagName = rawTagName.toLowerCase();\n if (!ALLOWED_HTML_TAGS.has(tagName)) return escapeHtml(tagText);\n if (isClosing) return `</${tagName}>`;\n if (tagName === \"input\" && !/\\stype\\s*=\\s*[\"']?checkbox[\"']?[\\s>/]/i.test(tagText)) {\n return escapeHtml(tagText);\n }\n\n let attrs = \"\";\n let attrMatch: RegExpExecArray | null;\n HTML_ATTR_REGEX.lastIndex = 0;\n while ((attrMatch = HTML_ATTR_REGEX.exec(rawAttrs)) !== null) {\n const name = attrMatch[1].toLowerCase();\n if (!ALLOWED_HTML_ATTRS.has(name) && !/^data-[a-z0-9_.-]+$/.test(name)) {\n continue;\n }\n const rawValue = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4];\n if (rawValue === undefined) {\n attrs += ` ${name}`;\n continue;\n }\n const value = md.utils.unescapeAll(rawValue);\n if (\n (name === \"href\" || name === \"src\") &&\n // Browsers ignore control characters and whitespace inside schemes.\n !md.validateLink(value.replace(/[\\u0000-\\u0020\\u007f]/g, \"\"))\n ) {\n continue;\n }\n attrs += ` ${name}=\"${escapeHtml(value)}\"`;\n }\n return `<${tagName}${attrs}>`;\n}\n\n/**\n * Sanitizes raw HTML with an allowlist of tags and attributes: event handlers,\n * `style`, and unsafe URL schemes are dropped; disallowed tags are escaped.\n */\nfunction sanitizeEmbeddedHtml(html: string): string {\n let result = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n HTML_TAG_REGEX.lastIndex = 0;\n while ((match = HTML_TAG_REGEX.exec(html)) !== null) {\n result += html.slice(lastIndex, match.index).replace(/</g, \"&lt;\");\n result += sanitizeTag(match[0], match[1], match[2], match[3]);\n lastIndex = match.index + match[0].length;\n }\n return result + html.slice(lastIndex).replace(/</g, \"&lt;\");\n}\n\nconst defaultHtmlInline = md.renderer.rules.html_inline;\nconst defaultHtmlBlock = md.renderer.rules.html_block;\nmd.renderer.rules.html_inline = (tokens, idx, options, env, self) =>\n env?.allowUnsafeHtml\n ? defaultHtmlInline!(tokens, idx, options, env, self)\n : sanitizeEmbeddedHtml(tokens[idx].content);\nmd.renderer.rules.html_block = (tokens, idx, options, env, self) =>\n env?.allowUnsafeHtml\n ? defaultHtmlBlock!(tokens, idx, options, env, self)\n : sanitizeEmbeddedHtml(tokens[idx].content);\n\nimport {\n preprocessMarkdownMentions,\n type PreprocessMarkdownMentionsOptions,\n} from \"./mentions\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Preprocesses file-protocol and editor-protocol links in markdown content:\n * converts [label](file://...), vscode://, and cursor:// links into anchor tags\n * annotated with data-file-link=\"true\", preserving code backticks in labels.\n */\nexport function preprocessMarkdownFileLinks(content: string): string {\n if (!content) return \"\";\n return content.replace(\n /\\[([^\\]]+)\\]\\(((?:file|vscode|cursor):\\/\\/[^)]+)\\)/g,\n (_match, rawLabel, href) => {\n const trimmed = rawLabel.trim();\n const codeMatch = trimmed.match(/^`([^`]+)`$/);\n const labelContent = codeMatch\n ? `<code>${escapeHtml(codeMatch[1])}</code>`\n : escapeHtml(trimmed);\n return `<a href=\"${escapeHtml(href)}\" data-file-link=\"true\" title=\"Click to copy file path\">${labelContent}</a>`;\n }\n );\n}\n\nexport interface MarkdownToHtmlOptions {\n /**\n * Preprocess file, vscode, and cursor links into clickable data-file-link tags.\n */\n preprocessFileLinks?: boolean;\n /**\n * Whether to preprocess @mentions into TipTap mention node HTML spans.\n */\n preprocessMentions?: boolean;\n /**\n * Pool of mentionables to pass to preprocessMarkdownMentions.\n */\n mentionables?: MentionEntity[];\n /**\n * Full options for preprocessMarkdownMentions.\n */\n preprocessOptions?: PreprocessMarkdownMentionsOptions;\n /**\n * Render raw HTML embedded in the markdown without sanitizing it. By default,\n * embedded HTML is restricted to an allowlist of tags and attributes (event\n * handlers, `style` and unsafe URL schemes are removed). Only enable this for\n * fully trusted input.\n */\n allowUnsafeHtml?: boolean;\n}\n\n/**\n * Converts a markdown string into HTML suitable for TipTap initial content or setContent.\n * Raw HTML embedded in the markdown is sanitized unless `allowUnsafeHtml` is set.\n */\nexport function markdownToTipTapHtml(\n markdown: string,\n options?: MarkdownToHtmlOptions\n): string {\n if (!markdown) return \"<p></p>\";\n let content = markdown;\n if (options?.preprocessFileLinks) {\n content = preprocessMarkdownFileLinks(content);\n }\n if (\n options?.preprocessMentions ||\n options?.mentionables ||\n options?.preprocessOptions\n ) {\n const mentionOpts = options.preprocessOptions || {\n mentionables: options.mentionables,\n };\n content = preprocessMarkdownMentions(content, mentionOpts);\n }\n return md.render(content, { allowUnsafeHtml: options?.allowUnsafeHtml });\n}\n\n/**\n * Extracts clean markdown from a TipTap editor instance.\n * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().\n * Otherwise, it falls back to getEditorText(editor).\n */\nexport function getEditorMarkdown(editor: any): string {\n if (!editor) return \"\";\n if (typeof editor.storage?.markdown?.getMarkdown === \"function\") {\n return editor.storage.markdown.getMarkdown();\n }\n return getEditorText(editor);\n}\n"],"mappings":"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","names":["match"]}
package/dist/index.cjs CHANGED
@@ -56,7 +56,8 @@ var _chunkSEDR75VHcjs = require('./chunk-SEDR75VH.cjs');
56
56
 
57
57
 
58
58
 
59
- var _chunkSHWP2A43cjs = require('./chunk-SHWP2A43.cjs');
59
+
60
+ var _chunkLLUAKTLWcjs = require('./chunk-LLUAKTLW.cjs');
60
61
 
61
62
 
62
63
 
@@ -78,25 +79,7 @@ var _chunk33UVEDOScjs = require('./chunk-33UVEDOS.cjs');
78
79
 
79
80
  // src/controller.ts
80
81
  var _core = require('@tiptap/core');
81
-
82
-
83
-
84
-
85
82
  var _model = require('@tiptap/pm/model');
86
- function plainTextToSlice(text, schema) {
87
- const nodes = [];
88
- text.replace(/\r\n?/g, "\n").split("\n").forEach((line) => {
89
- const nodeJson = { type: "paragraph" };
90
- if (line.length > 0) {
91
- nodeJson.content = [{ type: "text", text: line }];
92
- }
93
- try {
94
- nodes.push(_model.Node.fromJSON(schema, nodeJson));
95
- } catch (e) {
96
- }
97
- });
98
- return _model.Slice.maxOpen(_model.Fragment.fromArray(nodes));
99
- }
100
83
  var EditorController = class {
101
84
 
102
85
 
@@ -125,7 +108,7 @@ var EditorController = class {
125
108
  this.onMarkdownChange = onMarkdownChange;
126
109
  this.onTokensChange = onTokensChange;
127
110
  this.onSelectionChange = onSelectionChange;
128
- const initialContent = plainTextMode && typeof content === "string" ? _chunkSHWP2A43cjs.plainTextToTipTapHtml.call(void 0, content) : markdownMode && typeof content === "string" ? _chunkSHWP2A43cjs.markdownToTipTapHtml.call(void 0, content) : content;
111
+ const initialContent = plainTextMode && typeof content === "string" ? _chunkLLUAKTLWcjs.plainTextToTipTapHtml.call(void 0, content) : markdownMode && typeof content === "string" ? _chunkLLUAKTLWcjs.markdownToTipTapHtml.call(void 0, content) : content;
129
112
  this.editor = new (0, _core.Editor)({
130
113
  element: element || void 0,
131
114
  content: initialContent,
@@ -152,7 +135,7 @@ var EditorController = class {
152
135
  clipboardTextParser: (text, context, _plain, view) => {
153
136
  const schema = _optionalChain([context, 'optionalAccess', _5 => _5.doc, 'optionalAccess', _6 => _6.type, 'optionalAccess', _7 => _7.schema]) || _optionalChain([context, 'optionalAccess', _8 => _8.schema]) || _optionalChain([view, 'optionalAccess', _9 => _9.state, 'optionalAccess', _10 => _10.schema]) || this.editor.schema;
154
137
  if (!schema) return _model.Slice.empty;
155
- return plainTextToSlice(text, schema);
138
+ return _chunkLLUAKTLWcjs.plainTextToSlice.call(void 0, text, schema);
156
139
  }
157
140
  }
158
141
  });
@@ -178,20 +161,20 @@ var EditorController = class {
178
161
  }
179
162
  }
180
163
  getPlainText() {
181
- return _chunkSHWP2A43cjs.getEditorText.call(void 0, this.editor);
164
+ return _chunkLLUAKTLWcjs.getEditorText.call(void 0, this.editor);
182
165
  }
183
166
  setPlainText(text, emitUpdate = true) {
184
- const html = _chunkSHWP2A43cjs.plainTextToTipTapHtml.call(void 0, text);
167
+ const html = _chunkLLUAKTLWcjs.plainTextToTipTapHtml.call(void 0, text);
185
168
  this.editor.commands.setContent(html, emitUpdate);
186
169
  }
187
170
  getMarkdown() {
188
- return _chunkSHWP2A43cjs.getEditorMarkdown.call(void 0, this.editor);
171
+ return _chunkLLUAKTLWcjs.getEditorMarkdown.call(void 0, this.editor);
189
172
  }
190
173
  setMarkdown(markdown, emitUpdate = true) {
191
174
  if (_optionalChain([this, 'access', _15 => _15.editor, 'access', _16 => _16.storage, 'optionalAccess', _17 => _17.markdown, 'optionalAccess', _18 => _18.parser])) {
192
175
  this.editor.commands.setContent(markdown, emitUpdate);
193
176
  } else {
194
- const html = _chunkSHWP2A43cjs.markdownToTipTapHtml.call(void 0, markdown);
177
+ const html = _chunkLLUAKTLWcjs.markdownToTipTapHtml.call(void 0, markdown);
195
178
  this.editor.commands.setContent(html, emitUpdate);
196
179
  }
197
180
  }
@@ -201,7 +184,7 @@ var EditorController = class {
201
184
  */
202
185
  insertPlainText(from, to, text) {
203
186
  const { state, view } = this.editor;
204
- const tr = text.includes("\n") || text.includes("\r") ? state.tr.replace(from, to, plainTextToSlice(text, state.schema)) : text ? state.tr.insertText(text, from, to) : state.tr.delete(from, to);
187
+ const tr = text.includes("\n") || text.includes("\r") ? state.tr.replace(from, to, _chunkLLUAKTLWcjs.plainTextToSlice.call(void 0, text, state.schema)) : text ? state.tr.insertText(text, from, to) : state.tr.delete(from, to);
205
188
  view.dispatch(tr.scrollIntoView());
206
189
  }
207
190
  /** Inserts text literally at the selection; HTML in `text` is not parsed. */
@@ -379,5 +362,6 @@ function createDirtyTracker(initialBaseline, options) {
379
362
 
380
363
 
381
364
 
382
- exports.ColorHighlighter = _chunkLDES3EOScjs.ColorHighlighter; exports.DataSourceBinder = _chunkCYKQLDYHcjs.DataSourceBinder; exports.DependencyGraph = _chunkCYKQLDYHcjs.DependencyGraph; exports.DirtyTracker = DirtyTracker; exports.EditorController = EditorController; exports.FontSize = _chunkLDES3EOScjs.FontSize; exports.FormulaEvaluator = _chunkCYKQLDYHcjs.FormulaEvaluator; exports.FormulaParser = _chunkCYKQLDYHcjs.FormulaParser; exports.GradientText = _chunkLDES3EOScjs.GradientText; exports.HistoryManager = _chunk33UVEDOScjs.HistoryManager; exports.INSTRUCTION_REGEX = _chunkSEDR75VHcjs.INSTRUCTION_REGEX; exports.Image = _chunkLDES3EOScjs.Image; exports.LoadingNode = _chunkLDES3EOScjs.LoadingNode; exports.MARKDOWN_MENTION_SPLIT_REGEX = _chunkSHWP2A43cjs.MARKDOWN_MENTION_SPLIT_REGEX; exports.MENTION_REGEX = _chunkSHWP2A43cjs.MENTION_REGEX; exports.Markdown = _chunkLDES3EOScjs.Markdown; exports.Mention = _chunkLDES3EOScjs.Mention; exports.SlashCommands = _chunkLDES3EOScjs.SlashCommands; exports.SmilieReplacer = _chunkLDES3EOScjs.SmilieReplacer; exports.SpreadsheetController = _chunkCYKQLDYHcjs.SpreadsheetController; exports.TEMPLATE_DEPTH_ERROR = _chunkMPPXH7U5cjs.TEMPLATE_DEPTH_ERROR; exports.TEMPLATE_LOOP_ERROR = _chunkMPPXH7U5cjs.TEMPLATE_LOOP_ERROR; exports.TEMPLATE_REGEX = _chunkSEDR75VHcjs.TEMPLATE_REGEX; exports.TemplateSuggestions = _chunkLDES3EOScjs.TemplateSuggestions; exports.VARIABLE_REGEX = _chunkSEDR75VHcjs.VARIABLE_REGEX; exports.colNameToIndex = _chunkCYKQLDYHcjs.colNameToIndex; exports.createDirtyTracker = createDirtyTracker; exports.createEditor = createEditor; exports.createHistoryManager = _chunk33UVEDOScjs.createHistoryManager; exports.createMentionExtension = _chunkLDES3EOScjs.createMentionExtension; exports.createRichTextPreset = _chunkLDES3EOScjs.createRichTextPreset; exports.defaultIsEqual = defaultIsEqual; exports.escapeHtml = _chunkSHWP2A43cjs.escapeHtml; exports.extractCellDependencies = _chunkCYKQLDYHcjs.extractCellDependencies; exports.extractInstructionNames = _chunkMPPXH7U5cjs.extractInstructionNames; exports.extractMentions = _chunkSHWP2A43cjs.extractMentions; exports.extractMentionsFromDoc = _chunkSHWP2A43cjs.extractMentionsFromDoc; exports.extractTemplateNames = _chunkMPPXH7U5cjs.extractTemplateNames; exports.extractVariableNames = _chunkMPPXH7U5cjs.extractVariableNames; exports.findHexColors = _chunkLDES3EOScjs.findHexColors; exports.getEditorMarkdown = _chunkSHWP2A43cjs.getEditorMarkdown; exports.getEditorText = _chunkSHWP2A43cjs.getEditorText; exports.getLatestVersion = _chunkMPPXH7U5cjs.getLatestVersion; exports.getTemplateBody = _chunkMPPXH7U5cjs.getTemplateBody; exports.handleImageInsertion = _chunkLDES3EOScjs.handleImageInsertion; exports.htmlToPlainText = _chunkSHWP2A43cjs.htmlToPlainText; exports.imagePastePluginKey = _chunkLDES3EOScjs.imagePastePluginKey; exports.indexToColName = _chunkCYKQLDYHcjs.indexToColName; exports.insertImageNode = _chunkLDES3EOScjs.insertImageNode; exports.instructionRegex = _chunkSEDR75VHcjs.instructionRegex; exports.mapRawOffsetToResolved = _chunkMPPXH7U5cjs.mapRawOffsetToResolved; exports.mapResolvedOffsetToRaw = _chunkMPPXH7U5cjs.mapResolvedOffsetToRaw; exports.markdownToTipTapHtml = _chunkSHWP2A43cjs.markdownToTipTapHtml; exports.parseCellReference = _chunkCYKQLDYHcjs.parseCellReference; exports.parseFormula = _chunkCYKQLDYHcjs.parseFormula; exports.parseMentionSegments = _chunkSHWP2A43cjs.parseMentionSegments; exports.parseRange = _chunkCYKQLDYHcjs.parseRange; exports.plainTextToTipTapHtml = _chunkSHWP2A43cjs.plainTextToTipTapHtml; exports.preprocessMarkdownFileLinks = _chunkSHWP2A43cjs.preprocessMarkdownFileLinks; exports.preprocessMarkdownMentions = _chunkSHWP2A43cjs.preprocessMarkdownMentions; exports.removeImageNode = _chunkLDES3EOScjs.removeImageNode; exports.resolveTemplates = _chunkMPPXH7U5cjs.resolveTemplates; exports.resolveTemplatesWithMapping = _chunkMPPXH7U5cjs.resolveTemplatesWithMapping; exports.resolveVariables = _chunkMPPXH7U5cjs.resolveVariables; exports.stripMarkdownCode = _chunkSHWP2A43cjs.stripMarkdownCode; exports.templateRegex = _chunkSEDR75VHcjs.templateRegex; exports.tokenizeFormula = _chunkCYKQLDYHcjs.tokenizeFormula; exports.tokenizePrompt = _chunkMPPXH7U5cjs.tokenizePrompt; exports.updateImageSrc = _chunkLDES3EOScjs.updateImageSrc; exports.variableRegex = _chunkSEDR75VHcjs.variableRegex;
365
+
366
+ exports.ColorHighlighter = _chunkLDES3EOScjs.ColorHighlighter; exports.DataSourceBinder = _chunkCYKQLDYHcjs.DataSourceBinder; exports.DependencyGraph = _chunkCYKQLDYHcjs.DependencyGraph; exports.DirtyTracker = DirtyTracker; exports.EditorController = EditorController; exports.FontSize = _chunkLDES3EOScjs.FontSize; exports.FormulaEvaluator = _chunkCYKQLDYHcjs.FormulaEvaluator; exports.FormulaParser = _chunkCYKQLDYHcjs.FormulaParser; exports.GradientText = _chunkLDES3EOScjs.GradientText; exports.HistoryManager = _chunk33UVEDOScjs.HistoryManager; exports.INSTRUCTION_REGEX = _chunkSEDR75VHcjs.INSTRUCTION_REGEX; exports.Image = _chunkLDES3EOScjs.Image; exports.LoadingNode = _chunkLDES3EOScjs.LoadingNode; exports.MARKDOWN_MENTION_SPLIT_REGEX = _chunkLLUAKTLWcjs.MARKDOWN_MENTION_SPLIT_REGEX; exports.MENTION_REGEX = _chunkLLUAKTLWcjs.MENTION_REGEX; exports.Markdown = _chunkLDES3EOScjs.Markdown; exports.Mention = _chunkLDES3EOScjs.Mention; exports.SlashCommands = _chunkLDES3EOScjs.SlashCommands; exports.SmilieReplacer = _chunkLDES3EOScjs.SmilieReplacer; exports.SpreadsheetController = _chunkCYKQLDYHcjs.SpreadsheetController; exports.TEMPLATE_DEPTH_ERROR = _chunkMPPXH7U5cjs.TEMPLATE_DEPTH_ERROR; exports.TEMPLATE_LOOP_ERROR = _chunkMPPXH7U5cjs.TEMPLATE_LOOP_ERROR; exports.TEMPLATE_REGEX = _chunkSEDR75VHcjs.TEMPLATE_REGEX; exports.TemplateSuggestions = _chunkLDES3EOScjs.TemplateSuggestions; exports.VARIABLE_REGEX = _chunkSEDR75VHcjs.VARIABLE_REGEX; exports.colNameToIndex = _chunkCYKQLDYHcjs.colNameToIndex; exports.createDirtyTracker = createDirtyTracker; exports.createEditor = createEditor; exports.createHistoryManager = _chunk33UVEDOScjs.createHistoryManager; exports.createMentionExtension = _chunkLDES3EOScjs.createMentionExtension; exports.createRichTextPreset = _chunkLDES3EOScjs.createRichTextPreset; exports.defaultIsEqual = defaultIsEqual; exports.escapeHtml = _chunkLLUAKTLWcjs.escapeHtml; exports.extractCellDependencies = _chunkCYKQLDYHcjs.extractCellDependencies; exports.extractInstructionNames = _chunkMPPXH7U5cjs.extractInstructionNames; exports.extractMentions = _chunkLLUAKTLWcjs.extractMentions; exports.extractMentionsFromDoc = _chunkLLUAKTLWcjs.extractMentionsFromDoc; exports.extractTemplateNames = _chunkMPPXH7U5cjs.extractTemplateNames; exports.extractVariableNames = _chunkMPPXH7U5cjs.extractVariableNames; exports.findHexColors = _chunkLDES3EOScjs.findHexColors; exports.getEditorMarkdown = _chunkLLUAKTLWcjs.getEditorMarkdown; exports.getEditorText = _chunkLLUAKTLWcjs.getEditorText; exports.getLatestVersion = _chunkMPPXH7U5cjs.getLatestVersion; exports.getTemplateBody = _chunkMPPXH7U5cjs.getTemplateBody; exports.handleImageInsertion = _chunkLDES3EOScjs.handleImageInsertion; exports.htmlToPlainText = _chunkLLUAKTLWcjs.htmlToPlainText; exports.imagePastePluginKey = _chunkLDES3EOScjs.imagePastePluginKey; exports.indexToColName = _chunkCYKQLDYHcjs.indexToColName; exports.insertImageNode = _chunkLDES3EOScjs.insertImageNode; exports.instructionRegex = _chunkSEDR75VHcjs.instructionRegex; exports.mapRawOffsetToResolved = _chunkMPPXH7U5cjs.mapRawOffsetToResolved; exports.mapResolvedOffsetToRaw = _chunkMPPXH7U5cjs.mapResolvedOffsetToRaw; exports.markdownToTipTapHtml = _chunkLLUAKTLWcjs.markdownToTipTapHtml; exports.parseCellReference = _chunkCYKQLDYHcjs.parseCellReference; exports.parseFormula = _chunkCYKQLDYHcjs.parseFormula; exports.parseMentionSegments = _chunkLLUAKTLWcjs.parseMentionSegments; exports.parseRange = _chunkCYKQLDYHcjs.parseRange; exports.plainTextToSlice = _chunkLLUAKTLWcjs.plainTextToSlice; exports.plainTextToTipTapHtml = _chunkLLUAKTLWcjs.plainTextToTipTapHtml; exports.preprocessMarkdownFileLinks = _chunkLLUAKTLWcjs.preprocessMarkdownFileLinks; exports.preprocessMarkdownMentions = _chunkLLUAKTLWcjs.preprocessMarkdownMentions; exports.removeImageNode = _chunkLDES3EOScjs.removeImageNode; exports.resolveTemplates = _chunkMPPXH7U5cjs.resolveTemplates; exports.resolveTemplatesWithMapping = _chunkMPPXH7U5cjs.resolveTemplatesWithMapping; exports.resolveVariables = _chunkMPPXH7U5cjs.resolveVariables; exports.stripMarkdownCode = _chunkLLUAKTLWcjs.stripMarkdownCode; exports.templateRegex = _chunkSEDR75VHcjs.templateRegex; exports.tokenizeFormula = _chunkCYKQLDYHcjs.tokenizeFormula; exports.tokenizePrompt = _chunkMPPXH7U5cjs.tokenizePrompt; exports.updateImageSrc = _chunkLDES3EOScjs.updateImageSrc; exports.variableRegex = _chunkSEDR75VHcjs.variableRegex;
383
367
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/index.cjs","../src/controller.ts","../src/dirty.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/index.cjs","sourcesContent":[null,"import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport {\n Slice,\n Fragment,\n Node as ProsemirrorNode,\n type Schema,\n} from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * Builds an open slice with one paragraph per line, so inserting it splits the\n * surrounding paragraph like typing Enter would.\n */\nfunction plainTextToSlice(text: string, schema: Schema): Slice {\n const nodes: ProsemirrorNode[] = [];\n text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .forEach((line) => {\n const nodeJson: any = { type: \"paragraph\" };\n if (line.length > 0) {\n nodeJson.content = [{ type: \"text\", text: line }];\n }\n try {\n nodes.push(ProsemirrorNode.fromJSON(schema, nodeJson));\n } catch {\n // Ignore invalid node\n }\n });\n return Slice.maxOpen(Fragment.fromArray(nodes));\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/index.cjs","../src/controller.ts","../src/dirty.ts"],"names":[],"mappings":"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SAAA,UAAW,gBAAA;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,WAAA,CAAA,EAAiB;AACtB,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,WAAA,CAAY,KAAA,EAAgB;AACjC,IAAA,IAAA,CAAK,SAAA,EAAW,KAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKO,OAAA,CAAQ,OAAA,EAAqB;AAClC,IAAA,OAAO,CAAC,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,QAAA,EAAU,OAAO,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKO,KAAA,CAAM,OAAA,EAAkB;AAC7B,IAAA,IAAA,CAAK,SAAA,EAAW,OAAA;AAAA,EAClB;AACF,CAAA;AAKO,SAAS,kBAAA,CACd,eAAA,EACA,OAAA,EACiB;AACjB,EAAA,OAAO,IAAI,YAAA,CAAa,eAAA,EAAiB,OAAO,CAAA;AAClD;AFiMA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,g1IAAC","file":"/home/runner/work/editor/editor/packages/core/dist/index.cjs","sourcesContent":[null,"import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n plainTextToSlice,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -3,7 +3,7 @@ export { C as ColorGradient, I as INSTRUCTION_REGEX, a as TEMPLATE_REGEX, b as T
3
3
  export { ResolveTemplatesOptions, SourceMapSegment, TEMPLATE_DEPTH_ERROR, TEMPLATE_LOOP_ERROR, extractInstructionNames, extractTemplateNames, extractVariableNames, getLatestVersion, getTemplateBody, mapRawOffsetToResolved, mapResolvedOffsetToRaw, resolveTemplates, resolveTemplatesWithMapping, resolveVariables, tokenizePrompt } from './grammar/index.cjs';
4
4
  export { ColorHighlighter, FontSize, GradientText, GradientTextOptions, Image, ImageOptions, LoadingNode, Markdown, RichTextPresetOptions, SlashCommandMatchData, SlashCommands, SlashCommandsOptions, SmilieReplacer, TemplateSuggestions, TemplateSuggestionsOptions, createRichTextPreset, findHexColors, handleImageInsertion, imagePastePluginKey, insertImageNode, removeImageNode, updateImageSrc } from './extensions/index.cjs';
5
5
  export { M as Mention, a as MentionEntity, b as MentionOptions, c as createMentionExtension } from './mention-Dcevh3ff.cjs';
6
- export { ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, MarkdownToHtmlOptions, MentionSegment, PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode } from './serializers/index.cjs';
6
+ export { ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, MarkdownToHtmlOptions, MentionSegment, PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToSlice, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode } from './serializers/index.cjs';
7
7
  import { Editor, EditorOptions, Content, Extensions } from '@tiptap/core';
8
8
  export { Content, Editor, EditorOptions, Extensions } from '@tiptap/core';
9
9
  export { ASTNode, BinaryOpNode, CellCoordinate, CellData, CellDep, CellFormat, CellRange, CellRefNode, ColumnBinding, ColumnType, DataSourceBinder, DependencyGraph, EvaluationContext, FormulaEvaluator, FormulaParser, FormulaToken, FormulaTokenType, FunctionCallNode, LiteralNode, PropertyRefNode, RangeNode, RowType, SpreadsheetColumn, SpreadsheetController, SpreadsheetControllerOptions, SpreadsheetDataSource, SpreadsheetDataSourceField, SpreadsheetDocument, SpreadsheetRow, UnaryOpNode, colNameToIndex, extractCellDependencies, indexToColName, parseCellReference, parseFormula, parseRange, tokenizeFormula } from './spreadsheet/index.cjs';
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { C as ColorGradient, I as INSTRUCTION_REGEX, a as TEMPLATE_REGEX, b as T
3
3
  export { ResolveTemplatesOptions, SourceMapSegment, TEMPLATE_DEPTH_ERROR, TEMPLATE_LOOP_ERROR, extractInstructionNames, extractTemplateNames, extractVariableNames, getLatestVersion, getTemplateBody, mapRawOffsetToResolved, mapResolvedOffsetToRaw, resolveTemplates, resolveTemplatesWithMapping, resolveVariables, tokenizePrompt } from './grammar/index.js';
4
4
  export { ColorHighlighter, FontSize, GradientText, GradientTextOptions, Image, ImageOptions, LoadingNode, Markdown, RichTextPresetOptions, SlashCommandMatchData, SlashCommands, SlashCommandsOptions, SmilieReplacer, TemplateSuggestions, TemplateSuggestionsOptions, createRichTextPreset, findHexColors, handleImageInsertion, imagePastePluginKey, insertImageNode, removeImageNode, updateImageSrc } from './extensions/index.js';
5
5
  export { M as Mention, a as MentionEntity, b as MentionOptions, c as createMentionExtension } from './mention-Dcevh3ff.js';
6
- export { ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, MarkdownToHtmlOptions, MentionSegment, PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode } from './serializers/index.js';
6
+ export { ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, MarkdownToHtmlOptions, MentionSegment, PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToSlice, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode } from './serializers/index.js';
7
7
  import { Editor, EditorOptions, Content, Extensions } from '@tiptap/core';
8
8
  export { Content, Editor, EditorOptions, Extensions } from '@tiptap/core';
9
9
  export { ASTNode, BinaryOpNode, CellCoordinate, CellData, CellDep, CellFormat, CellRange, CellRefNode, ColumnBinding, ColumnType, DataSourceBinder, DependencyGraph, EvaluationContext, FormulaEvaluator, FormulaParser, FormulaToken, FormulaTokenType, FunctionCallNode, LiteralNode, PropertyRefNode, RangeNode, RowType, SpreadsheetColumn, SpreadsheetController, SpreadsheetControllerOptions, SpreadsheetDataSource, SpreadsheetDataSourceField, SpreadsheetDocument, SpreadsheetRow, UnaryOpNode, colNameToIndex, extractCellDependencies, indexToColName, parseCellReference, parseFormula, parseRange, tokenizeFormula } from './spreadsheet/index.js';
package/dist/index.js CHANGED
@@ -52,11 +52,12 @@ import {
52
52
  htmlToPlainText,
53
53
  markdownToTipTapHtml,
54
54
  parseMentionSegments,
55
+ plainTextToSlice,
55
56
  plainTextToTipTapHtml,
56
57
  preprocessMarkdownFileLinks,
57
58
  preprocessMarkdownMentions,
58
59
  stripMarkdownCode
59
- } from "./chunk-BYCOFZAA.js";
60
+ } from "./chunk-QGVMBCT5.js";
60
61
  import {
61
62
  DataSourceBinder,
62
63
  DependencyGraph,
@@ -78,25 +79,7 @@ import {
78
79
 
79
80
  // src/controller.ts
80
81
  import { Editor } from "@tiptap/core";
81
- import {
82
- Slice,
83
- Fragment,
84
- Node as ProsemirrorNode
85
- } from "@tiptap/pm/model";
86
- function plainTextToSlice(text, schema) {
87
- const nodes = [];
88
- text.replace(/\r\n?/g, "\n").split("\n").forEach((line) => {
89
- const nodeJson = { type: "paragraph" };
90
- if (line.length > 0) {
91
- nodeJson.content = [{ type: "text", text: line }];
92
- }
93
- try {
94
- nodes.push(ProsemirrorNode.fromJSON(schema, nodeJson));
95
- } catch {
96
- }
97
- });
98
- return Slice.maxOpen(Fragment.fromArray(nodes));
99
- }
82
+ import { Slice } from "@tiptap/pm/model";
100
83
  var EditorController = class {
101
84
  editor;
102
85
  plainTextMode;
@@ -366,6 +349,7 @@ export {
366
349
  parseFormula,
367
350
  parseMentionSegments,
368
351
  parseRange,
352
+ plainTextToSlice,
369
353
  plainTextToTipTapHtml,
370
354
  preprocessMarkdownFileLinks,
371
355
  preprocessMarkdownMentions,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/controller.ts","../src/dirty.ts"],"sourcesContent":["import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport {\n Slice,\n Fragment,\n Node as ProsemirrorNode,\n type Schema,\n} from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * Builds an open slice with one paragraph per line, so inserting it splits the\n * surrounding paragraph like typing Enter would.\n */\nfunction plainTextToSlice(text: string, schema: Schema): Slice {\n const nodes: ProsemirrorNode[] = [];\n text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .forEach((line) => {\n const nodeJson: any = { type: \"paragraph\" };\n if (line.length > 0) {\n nodeJson.content = [{ type: \"text\", text: line }];\n }\n try {\n nodes.push(ProsemirrorNode.fromJSON(schema, nodeJson));\n } catch {\n // Ignore invalid node\n }\n });\n return Slice.maxOpen(Fragment.fromArray(nodes));\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,cAAkD;AAC3D;AAAA,EACE;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,OAEH;AA2BP,SAAS,iBAAiB,MAAc,QAAuB;AAC7D,QAAM,QAA2B,CAAC;AAClC,OACG,QAAQ,UAAU,IAAI,EACtB,MAAM,IAAI,EACV,QAAQ,CAAC,SAAS;AACjB,UAAM,WAAgB,EAAE,MAAM,YAAY;AAC1C,QAAI,KAAK,SAAS,GAAG;AACnB,eAAS,UAAU,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,CAAC;AAAA,IAClD;AACA,QAAI;AACF,YAAM,KAAK,gBAAgB,SAAS,QAAQ,QAAQ,CAAC;AAAA,IACvD,QAAQ;AAAA,IAER;AAAA,EACF,CAAC;AACH,SAAO,MAAM,QAAQ,SAAS,UAAU,KAAK,CAAC;AAChD;AAMO,IAAM,mBAAN,MAAuB;AAAA,EACZ;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGT;AAAA,EAER,YAAY,UAAmC,CAAC,GAAG;AACjD,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,eAAe;AAAA,MACf,aAAa,CAAC;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,IAAI;AAEJ,SAAK,gBAAgB;AACrB,SAAK,eAAe;AACpB,SAAK,oBAAoB;AACzB,SAAK,mBAAmB;AACxB,SAAK,iBAAiB;AACtB,SAAK,oBAAoB;AAEzB,UAAM,iBACJ,iBAAiB,OAAO,YAAY,WAChC,sBAAsB,OAAO,IAC7B,gBAAgB,OAAO,YAAY,WACjC,qBAAqB,OAAO,IAC5B;AAER,SAAK,SAAS,IAAI,OAAO;AAAA,MACvB,SAAS,WAAW;AAAA,MACpB,SAAS;AAAA,MACT;AAAA,MACA,GAAG;AAAA,MACH,UAAU,CAAC,UAAU;AACnB,sBAAc,WAAW,KAAK;AAC9B,aAAK,aAAa;AAAA,MACpB;AAAA,MACA,mBAAmB,CAAC,UAAU;AAC5B,sBAAc,oBAAoB,KAAK;AACvC,aAAK,sBAAsB;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,QAAI,eAAe;AACjB,WAAK,0BAA0B;AAAA,IACjC;AAEA,SAAK,kBAAkB,KAAK,wBAAwB;AAAA,EACtD;AAAA,EAEQ,4BAA4B;AAClC,SAAK,OAAO,WAAW;AAAA,MACrB,aAAa;AAAA,QACX,GAAG,KAAK,OAAO,QAAQ;AAAA,QACvB,qBAAqB,CACnB,MACA,SACA,QACA,SACG;AACH,gBAAM,SACJ,SAAS,KAAK,MAAM,UACpB,SAAS,UACT,MAAM,OAAO,UACb,KAAK,OAAO;AAEd,cAAI,CAAC,OAAQ,QAAO,MAAM;AAE1B,iBAAO,iBAAiB,MAAM,MAAM;AAAA,QACtC;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,eAAe;AACrB,QAAI,KAAK,iBAAiB,KAAK,qBAAqB,KAAK,gBAAgB;AACvE,YAAM,OAAO,KAAK,aAAa;AAC/B,WAAK,oBAAoB,IAAI;AAE7B,UAAI,KAAK,gBAAgB;AACvB,cAAM,SAAS,eAAe,IAAI;AAClC,aAAK,eAAe,MAAM;AAAA,MAC5B;AAAA,IACF;AAEA,QAAI,KAAK,gBAAgB,KAAK,kBAAkB;AAC9C,YAAM,WAAW,KAAK,YAAY;AAClC,WAAK,mBAAmB,QAAQ;AAAA,IAClC;AAAA,EACF;AAAA,EAEQ,wBAAwB;AAC9B,QAAI,KAAK,mBAAmB;AAC1B,YAAM,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,MAAM;AACvC,WAAK,kBAAkB,EAAE,MAAM,GAAG,CAAC;AAAA,IACrC;AAAA,EACF;AAAA,EAEO,eAAuB;AAC5B,WAAO,cAAc,KAAK,MAAM;AAAA,EAClC;AAAA,EAEO,aAAa,MAAc,aAAa,MAAM;AACnD,UAAM,OAAO,sBAAsB,IAAI;AACvC,SAAK,OAAO,SAAS,WAAW,MAAM,UAAU;AAAA,EAClD;AAAA,EAEO,cAAsB;AAC3B,WAAO,kBAAkB,KAAK,MAAM;AAAA,EACtC;AAAA,EAEO,YAAY,UAAkB,aAAa,MAAM;AACtD,QAAI,KAAK,OAAO,SAAS,UAAU,QAAQ;AACzC,WAAK,OAAO,SAAS,WAAW,UAAU,UAAU;AAAA,IACtD,OAAO;AACL,YAAM,OAAO,qBAAqB,QAAQ;AAC1C,WAAK,OAAO,SAAS,WAAW,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,MAAc,IAAY,MAAc;AAC9D,UAAM,EAAE,OAAO,KAAK,IAAI,KAAK;AAC7B,UAAM,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,IAChD,MAAM,GAAG,QAAQ,MAAM,IAAI,iBAAiB,MAAM,MAAM,MAAM,CAAC,IAC/D,OACE,MAAM,GAAG,WAAW,MAAM,MAAM,EAAE,IAClC,MAAM,GAAG,OAAO,MAAM,EAAE;AAC9B,SAAK,SAAS,GAAG,eAAe,CAAC;AAAA,EACnC;AAAA;AAAA,EAGO,WAAW,MAAc;AAC9B,UAAM,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,MAAM;AACvC,SAAK,gBAAgB,MAAM,IAAI,IAAI;AAAA,EACrC;AAAA;AAAA,EAGO,aAAa,KAAa,MAAc;AAC7C,SAAK,gBAAgB,KAAK,KAAK,IAAI;AACnC,SAAK,OAAO,SAAS,MAAM;AAAA,EAC7B;AAAA;AAAA,EAGO,aAAa,MAAc,IAAY,MAAc;AAC1D,SAAK,gBAAgB,MAAM,IAAI,IAAI;AACnC,SAAK,OAAO,SAAS,MAAM;AAAA,EAC7B;AAAA,EAEO,0BAAkC;AACvC,QAAI,KAAK,cAAe,QAAO,KAAK,aAAa;AACjD,QAAI,KAAK,aAAc,QAAO,KAAK,YAAY;AAC/C,WAAO,KAAK,OAAO,QAAQ;AAAA,EAC7B;AAAA,EAEO,UAAmB;AACxB,WAAO,KAAK,wBAAwB,MAAM,KAAK;AAAA,EACjD;AAAA,EAEO,cAAc,SAAwB;AAC3C,SAAK,kBACH,YAAY,SAAY,UAAU,KAAK,wBAAwB;AAAA,EACnE;AAAA,EAEO,aAAmB;AACxB,SAAK,cAAc;AAAA,EACrB;AAAA,EAEO,qBAA6B;AAClC,WAAO,KAAK;AAAA,EACd;AAAA,EAEO,UAAU;AACf,SAAK,OAAO,QAAQ;AAAA,EACtB;AACF;AAKO,SAAS,aACd,UAAmC,CAAC,GAClB;AAClB,SAAO,IAAI,iBAAiB,OAAO;AACrC;;;AC3PO,SAAS,eAAkB,GAAM,GAAe;AACrD,MAAI,OAAO,GAAG,GAAG,CAAC,EAAG,QAAO;AAC5B,MACE,OAAO,MAAM,YACb,MAAM,QACN,OAAO,MAAM,YACb,MAAM,MACN;AACA,WAAO;AAAA,EACT;AAGA,MAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,GAAG;AACxC,QAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,aAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAI,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAG,QAAO;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,GAAG;AACzC,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,OAAO,KAAK,CAAC;AAC3B,QAAM,QAAQ,OAAO,KAAK,CAAC;AAE3B,MAAI,MAAM,WAAW,MAAM,OAAQ,QAAO;AAE1C,aAAW,OAAO,OAAO;AACvB,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,GAAG,EAAG,QAAO;AAC1D,QAAI,CAAC,eAAe,EAAE,GAAG,GAAG,EAAE,GAAG,CAAC,EAAG,QAAO;AAAA,EAC9C;AAEA,SAAO;AACT;AASO,IAAM,eAAN,MAAgC;AAAA,EAC7B;AAAA,EACS;AAAA,EAEjB,YACE,iBACA,SACA;AACA,SAAK,WAAW;AAChB,QAAI,OAAO,YAAY,YAAY;AACjC,WAAK,UAAU;AAAA,IACjB,OAAO;AACL,WAAK,UAAU,SAAS,WAAW;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,cAAiB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,YAAY,OAAgB;AACjC,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKO,QAAQ,SAAqB;AAClC,WAAO,CAAC,KAAK,QAAQ,KAAK,UAAU,OAAO;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKO,MAAM,SAAkB;AAC7B,SAAK,WAAW;AAAA,EAClB;AACF;AAKO,SAAS,mBACd,iBACA,SACiB;AACjB,SAAO,IAAI,aAAa,iBAAiB,OAAO;AAClD;","names":[]}
1
+ {"version":3,"sources":["../src/controller.ts","../src/dirty.ts"],"sourcesContent":["import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n plainTextToSlice,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"],"mappings":"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","names":[]}
@@ -13,8 +13,8 @@
13
13
 
14
14
 
15
15
 
16
- var _chunkSHWP2A43cjs = require('../chunk-SHWP2A43.cjs');
17
16
 
17
+ var _chunkLLUAKTLWcjs = require('../chunk-LLUAKTLW.cjs');
18
18
 
19
19
 
20
20
 
@@ -29,5 +29,7 @@ var _chunkSHWP2A43cjs = require('../chunk-SHWP2A43.cjs');
29
29
 
30
30
 
31
31
 
32
- exports.MARKDOWN_MENTION_SPLIT_REGEX = _chunkSHWP2A43cjs.MARKDOWN_MENTION_SPLIT_REGEX; exports.MENTION_REGEX = _chunkSHWP2A43cjs.MENTION_REGEX; exports.escapeHtml = _chunkSHWP2A43cjs.escapeHtml; exports.extractMentions = _chunkSHWP2A43cjs.extractMentions; exports.extractMentionsFromDoc = _chunkSHWP2A43cjs.extractMentionsFromDoc; exports.getEditorMarkdown = _chunkSHWP2A43cjs.getEditorMarkdown; exports.getEditorText = _chunkSHWP2A43cjs.getEditorText; exports.htmlToPlainText = _chunkSHWP2A43cjs.htmlToPlainText; exports.markdownToTipTapHtml = _chunkSHWP2A43cjs.markdownToTipTapHtml; exports.parseMentionSegments = _chunkSHWP2A43cjs.parseMentionSegments; exports.plainTextToTipTapHtml = _chunkSHWP2A43cjs.plainTextToTipTapHtml; exports.preprocessMarkdownFileLinks = _chunkSHWP2A43cjs.preprocessMarkdownFileLinks; exports.preprocessMarkdownMentions = _chunkSHWP2A43cjs.preprocessMarkdownMentions; exports.stripMarkdownCode = _chunkSHWP2A43cjs.stripMarkdownCode;
32
+
33
+
34
+ exports.MARKDOWN_MENTION_SPLIT_REGEX = _chunkLLUAKTLWcjs.MARKDOWN_MENTION_SPLIT_REGEX; exports.MENTION_REGEX = _chunkLLUAKTLWcjs.MENTION_REGEX; exports.escapeHtml = _chunkLLUAKTLWcjs.escapeHtml; exports.extractMentions = _chunkLLUAKTLWcjs.extractMentions; exports.extractMentionsFromDoc = _chunkLLUAKTLWcjs.extractMentionsFromDoc; exports.getEditorMarkdown = _chunkLLUAKTLWcjs.getEditorMarkdown; exports.getEditorText = _chunkLLUAKTLWcjs.getEditorText; exports.htmlToPlainText = _chunkLLUAKTLWcjs.htmlToPlainText; exports.markdownToTipTapHtml = _chunkLLUAKTLWcjs.markdownToTipTapHtml; exports.parseMentionSegments = _chunkLLUAKTLWcjs.parseMentionSegments; exports.plainTextToSlice = _chunkLLUAKTLWcjs.plainTextToSlice; exports.plainTextToTipTapHtml = _chunkLLUAKTLWcjs.plainTextToTipTapHtml; exports.preprocessMarkdownFileLinks = _chunkLLUAKTLWcjs.preprocessMarkdownFileLinks; exports.preprocessMarkdownMentions = _chunkLLUAKTLWcjs.preprocessMarkdownMentions; exports.stripMarkdownCode = _chunkLLUAKTLWcjs.stripMarkdownCode;
33
35
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/serializers/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,i8BAAC","file":"/home/runner/work/editor/editor/packages/core/dist/serializers/index.cjs"}
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/serializers/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,ggCAAC","file":"/home/runner/work/editor/editor/packages/core/dist/serializers/index.cjs"}
@@ -1,3 +1,4 @@
1
+ import { Schema, Slice } from '@tiptap/pm/model';
1
2
  import { a as MentionEntity } from '../mention-Dcevh3ff.cjs';
2
3
  import '@tiptap/core';
3
4
  import '@tiptap/extension-mention';
@@ -13,6 +14,12 @@ declare function escapeHtml(text: string): string;
13
14
  * Input that is already paragraph HTML (`<p>…</p>`) is passed through as-is.
14
15
  */
15
16
  declare function plainTextToTipTapHtml(text: string): string;
17
+ /**
18
+ * Builds an open ProseMirror slice with one paragraph per line, so inserting it
19
+ * splits the surrounding paragraph like typing Enter would. Use it for
20
+ * plain-text paste handling (`clipboardTextParser`) and literal text insertion.
21
+ */
22
+ declare function plainTextToSlice(text: string, schema: Schema): Slice;
16
23
  /**
17
24
  * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.
18
25
  */
@@ -137,4 +144,4 @@ declare function markdownToTipTapHtml(markdown: string, options?: MarkdownToHtml
137
144
  */
138
145
  declare function getEditorMarkdown(editor: any): string;
139
146
 
140
- export { type ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, type MarkdownToHtmlOptions, type MentionSegment, type PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode };
147
+ export { type ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, type MarkdownToHtmlOptions, type MentionSegment, type PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToSlice, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode };
@@ -1,3 +1,4 @@
1
+ import { Schema, Slice } from '@tiptap/pm/model';
1
2
  import { a as MentionEntity } from '../mention-Dcevh3ff.js';
2
3
  import '@tiptap/core';
3
4
  import '@tiptap/extension-mention';
@@ -13,6 +14,12 @@ declare function escapeHtml(text: string): string;
13
14
  * Input that is already paragraph HTML (`<p>…</p>`) is passed through as-is.
14
15
  */
15
16
  declare function plainTextToTipTapHtml(text: string): string;
17
+ /**
18
+ * Builds an open ProseMirror slice with one paragraph per line, so inserting it
19
+ * splits the surrounding paragraph like typing Enter would. Use it for
20
+ * plain-text paste handling (`clipboardTextParser`) and literal text insertion.
21
+ */
22
+ declare function plainTextToSlice(text: string, schema: Schema): Slice;
16
23
  /**
17
24
  * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.
18
25
  */
@@ -137,4 +144,4 @@ declare function markdownToTipTapHtml(markdown: string, options?: MarkdownToHtml
137
144
  */
138
145
  declare function getEditorMarkdown(editor: any): string;
139
146
 
140
- export { type ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, type MarkdownToHtmlOptions, type MentionSegment, type PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode };
147
+ export { type ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, type MarkdownToHtmlOptions, type MentionSegment, type PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToSlice, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode };
@@ -9,11 +9,12 @@ import {
9
9
  htmlToPlainText,
10
10
  markdownToTipTapHtml,
11
11
  parseMentionSegments,
12
+ plainTextToSlice,
12
13
  plainTextToTipTapHtml,
13
14
  preprocessMarkdownFileLinks,
14
15
  preprocessMarkdownMentions,
15
16
  stripMarkdownCode
16
- } from "../chunk-BYCOFZAA.js";
17
+ } from "../chunk-QGVMBCT5.js";
17
18
  export {
18
19
  MARKDOWN_MENTION_SPLIT_REGEX,
19
20
  MENTION_REGEX,
@@ -25,6 +26,7 @@ export {
25
26
  htmlToPlainText,
26
27
  markdownToTipTapHtml,
27
28
  parseMentionSegments,
29
+ plainTextToSlice,
28
30
  plainTextToTipTapHtml,
29
31
  preprocessMarkdownFileLinks,
30
32
  preprocessMarkdownMentions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/serializers/mentions.ts","../src/serializers/plain-text.ts","../src/serializers/markdown.ts"],"sourcesContent":["import { escapeHtml } from \"./plain-text\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Canonical regex pattern for matching @mentions in plain text or markdown.\n * Supports:\n * - Standard unquoted handles: @username, @user.name, @team_alpha, @sa-1\n * - Quoted handles: @\"John Doe\", &quot;Jane Doe&quot;\n * Unquoted handles exclude trailing punctuation (e.g. @violet. matches \"violet\" without the dot).\n */\nexport const MENTION_REGEX =\n /(?:^|[\\s>(*_\"';\\\\/[\\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:\"([^\"]+)\"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\\.[a-zA-Z0-9_-]+)*))/g;\n\n/**\n * Split regex identifying markdown code blocks, inline code, URLs, and existing HTML tags.\n * Used by preprocessMarkdownMentions to ensure non-mention regions remain completely untouched.\n */\nexport const MARKDOWN_MENTION_SPLIT_REGEX =\n /(```[\\s\\S]*?```|~~~[\\s\\S]*?~~~|<pre[\\s\\S]*?<\\/pre>|<code[\\s\\S]*?<\\/code>|`[^`\\n]+`|<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])[^>]*>[\\s\\S]*?<\\/span>|<[^>]+>|\\]\\([^)]+\\)|(?:https?|file|vscode|cursor|mailto):\\/\\/[^\\s<)]+)/gi;\n\nexport interface MentionSegment {\n type: \"text\" | \"mention\";\n value: string;\n handle?: string;\n}\n\nexport interface PreprocessMarkdownMentionsOptions {\n /**\n * Known pool of mentionable entities (users, agents, teams, etc.).\n */\n mentionables?: MentionEntity[];\n /**\n * Default entity type assigned when a handle does not match any entry in mentionables.\n * Defaults to 'user'.\n */\n defaultType?: string;\n /**\n * Custom resolver callback to derive entity metadata for unmatched handles.\n */\n resolveMention?: (handle: string) => Partial<MentionEntity> | null | undefined;\n}\n\n/**\n * Strips code blocks and inline code from markdown or HTML content:\n * - Fenced code blocks: ```...``` and ~~~...~~~\n * - Inline backtick code: `...`\n * - HTML code/pre tags: <pre>...</pre>, <code>...</code>\n * Used to avoid false-positive mention parsing and keyword analysis within code snippets, terminal logs, or stack traces.\n */\nexport function stripMarkdownCode(content: string): string {\n if (!content || typeof content !== \"string\") return \"\";\n return content\n .replace(/```[\\s\\S]*?```/g, \"\")\n .replace(/~~~[\\s\\S]*?~~~/g, \"\")\n .replace(/<pre[\\s\\S]*?<\\/pre>/gi, \"\")\n .replace(/<code[\\s\\S]*?<\\/code>/gi, \"\")\n .replace(/`[^`\\n]*`/g, \"\");\n}\n\n/**\n * Extracts unique mention handles from a text, markdown, or HTML string,\n * ignoring trailing punctuation, code blocks, URLs, and pre-existing HTML mention attributes.\n */\nexport function extractMentions(content: string): string[] {\n if (!content || typeof content !== \"string\") return [];\n\n // Normalize existing HTML mention nodes (e.g. from TipTap or rich text serializers)\n // so data-mention-suggestion-char=\"@\" does not trigger spurious quoted matches against attributes,\n // and ensure the actual mentioned label or ID is preserved cleanly.\n const normalizedMentionNodes = content.replace(\n /<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"'])[^>]*>([\\s\\S]*?)<\\/span>/gi,\n (match, inner) => {\n const labelMatch = match.match(/\\bdata-label=[\"']([^\"']+)[\"']/i);\n if (labelMatch) return ` @${labelMatch[1]} `;\n const idMatch = match.match(/\\bdata-id=[\"']([^\"']+)[\"']/i);\n if (idMatch) return ` @${idMatch[1]} `;\n return ` ${inner} `;\n }\n );\n\n const cleanContent = stripMarkdownCode(normalizedMentionNodes);\n // Strip URLs and markdown link destinations so @package or @handles in URLs are not extracted as mentions\n const withoutUrls = cleanContent\n .replace(/(?:https?|ftp|file|vscode|cursor|mailto):\\/\\/[^\\s<>()]+/gi, \"\")\n .replace(/\\]\\([^)]*\\)/g, \"]\");\n // Strip remaining HTML tags so attributes containing '@' or '>' aren't treated as mention triggers\n const textOnly = withoutUrls.replace(/<[^>]+>/g, \" \");\n\n const mentions: string[] = [];\n const seen = new Set<string>();\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(textOnly)) !== null) {\n const handle = (match[1] ?? match[2] ?? match[3] ?? \"\").trim();\n if (handle && !seen.has(handle)) {\n seen.add(handle);\n mentions.push(handle);\n }\n }\n\n return mentions;\n}\n\n/**\n * Segments a text string into plain text parts and mention tokens.\n * Correctly leaves trailing punctuation (like \".\") as part of the following text segment.\n */\nexport function parseMentionSegments(content: string): MentionSegment[] {\n if (!content) return [];\n\n const segments: MentionSegment[] = [];\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const fullMatch = match[0];\n const atIndex = fullMatch.indexOf(\"@\");\n const prefix = atIndex > 0 ? fullMatch.slice(0, atIndex) : \"\";\n const mentionToken = fullMatch.slice(atIndex);\n const handle = match[1] ?? match[2] ?? match[3];\n const matchStart = match.index + prefix.length;\n\n if (matchStart > lastIndex) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex, matchStart),\n });\n }\n\n segments.push({\n type: \"mention\",\n value: mentionToken,\n handle,\n });\n\n lastIndex = matchStart + mentionToken.length;\n }\n\n if (lastIndex < content.length) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex),\n });\n }\n\n return segments;\n}\n\n/**\n * Preprocesses markdown text by turning raw @mention handles into TipTap-compatible\n * mention HTML spans (<span class=\"pixerate-mention-node\" data-type=\"mention\" ...>),\n * ensuring code blocks, inline code, existing mention nodes, and URLs remain immune.\n */\nexport function preprocessMarkdownMentions(\n content: string,\n optionsOrMentionables: MentionEntity[] | PreprocessMarkdownMentionsOptions = []\n): string {\n if (!content || typeof content !== \"string\") return \"\";\n\n const options: PreprocessMarkdownMentionsOptions = Array.isArray(optionsOrMentionables)\n ? { mentionables: optionsOrMentionables }\n : optionsOrMentionables;\n\n const allMentionables = options.mentionables || [];\n const defaultType = options.defaultType || \"user\";\n const resolveMention = options.resolveMention;\n\n const parts = content.split(MARKDOWN_MENTION_SPLIT_REGEX);\n\n return parts\n .map((part) => {\n if (!part) return \"\";\n\n // Preserve code fences, code tags, inline backticks, existing mention spans,\n // HTML tags, markdown link targets, and raw URLs untouched.\n if (\n part.startsWith(\"```\") ||\n part.startsWith(\"~~~\") ||\n part.startsWith(\"`\") ||\n part.startsWith(\"](\") ||\n /^(?:https?|file|vscode|cursor|mailto):\\/\\//i.test(part) ||\n /^<pre[\\s>]/i.test(part) ||\n /^<code[\\s>]/i.test(part) ||\n /^<[^>]+>$/i.test(part) ||\n /^<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])/i.test(\n part\n )\n ) {\n return part;\n }\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n return part.replace(regex, (match, quotedHandle, escapedQuotedHandle, standardHandle) => {\n const atIndex = match.indexOf(\"@\");\n const prefix = atIndex > 0 ? match.slice(0, atIndex) : \"\";\n const rawHandle = (quotedHandle || escapedQuotedHandle || standardHandle || \"\").trim();\n if (!rawHandle) return match;\n\n const lowerHandle = rawHandle.toLowerCase();\n const entity = allMentionables.find((e) => {\n if (e.label?.toLowerCase() === lowerHandle) return true;\n if (e.handle?.toLowerCase() === lowerHandle) return true;\n if (e.name?.toLowerCase() === lowerHandle) return true;\n if (e.id?.toLowerCase() === lowerHandle) return true;\n if (e.type === \"agent\" && `agent${(e.handle || e.label || \"\").toLowerCase()}` === lowerHandle) return true;\n if (\n e.aliases?.some(\n (a: string) =>\n a.toLowerCase() === lowerHandle ||\n (e.type === \"agent\" && `agent${a.toLowerCase()}` === lowerHandle)\n )\n ) {\n return true;\n }\n return false;\n });\n\n let id = entity?.id;\n let label = entity?.label || entity?.handle || rawHandle;\n let type = entity?.type;\n let avatarUrl = entity?.avatarUrl;\n let color = entity?.color || entity?.hexColor;\n\n if (!entity) {\n const customResolved = resolveMention?.(rawHandle);\n if (customResolved) {\n id = customResolved.id ?? id;\n label = customResolved.label ?? customResolved.handle ?? label;\n type = customResolved.type ?? type;\n avatarUrl = customResolved.avatarUrl ?? avatarUrl;\n color = customResolved.color ?? customResolved.hexColor ?? color;\n } else {\n const stripped = lowerHandle.replace(/^agent[\\s\\-_]*/i, \"\");\n if (\n [\"supervisor\", \"coordinator\", \"planner\", \"validator\", \"executor\"].includes(stripped)\n ) {\n type = \"agent\";\n id = stripped;\n label = stripped;\n } else if (lowerHandle === \"agents\") {\n type = \"team\";\n id = \"agents\";\n label = \"agents\";\n } else {\n type = defaultType;\n id = rawHandle;\n label = rawHandle;\n }\n }\n }\n\n const avatarAttr = avatarUrl ? ` data-avatar-url=\"${escapeHtml(avatarUrl)}\"` : \"\";\n const colorAttr = color ? ` data-color=\"${escapeHtml(color)}\"` : \"\";\n\n return `${prefix}<span class=\"pixerate-mention-node\" data-type=\"mention\" data-id=\"${escapeHtml(\n id || label\n )}\" data-label=\"${escapeHtml(label)}\" data-mention-suggestion-char=\"@\" data-type-name=\"${escapeHtml(\n type || defaultType\n )}\"${avatarAttr}${colorAttr}>@${escapeHtml(label)}</span>`;\n });\n })\n .join(\"\");\n}\n","/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Matches strings that are already TipTap paragraph HTML (start with `<p>` and\n * end with `</p>`), as opposed to plain text that merely mentions a `<p>` tag.\n */\nconst PARAGRAPH_HTML_REGEX = /^\\s*<p[\\s>][\\s\\S]*<\\/p>\\s*$/i;\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n * Input that is already paragraph HTML (`<p>…</p>`) is passed through as-is.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (PARAGRAPH_HTML_REGEX.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Block-level elements that start a new line in plain-text output.\n */\nconst BLOCK_TAGS = new Set([\n \"P\", \"DIV\", \"LI\", \"UL\", \"OL\", \"PRE\", \"BLOCKQUOTE\", \"TABLE\", \"TR\",\n \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"HR\",\n]);\n\n/**\n * Matches a TipTap mention span (including its content). The lookahead keeps\n * a single `[^>]*` scan per tag, avoiding catastrophic backtracking on\n * malformed input.\n */\nconst MENTION_SPAN_REGEX =\n /<span\\b(?=[^>]*\\bdata-type=[\"']mention[\"'])([^>]*)>[\\s\\S]*?<\\/span>/gi;\n\nfunction getHtmlAttribute(attrs: string, name: string): string | undefined {\n const match = new RegExp(`\\\\b${name}=(?:\"([^\"]*)\"|'([^']*)')`, \"i\").exec(\n attrs,\n );\n return match ? (match[1] ?? match[2]) : undefined;\n}\n\n/**\n * Parses HTML into an inert fragment. Content of a `<template>` element is not\n * rendered, so `<img onerror>` and similar handlers never run.\n */\nfunction parseHtmlFragment(html: string): DocumentFragment {\n const template = document.createElement(\"template\");\n template.innerHTML = html;\n return template.content;\n}\n\nfunction decodeHtmlEntities(text: string): string {\n return text\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#0*39;/g, \"'\")\n .replace(/&nbsp;/g, \"\\u00a0\")\n .replace(/&amp;/g, \"&\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html.replace(MENTION_SPAN_REGEX, (match, attrs) => {\n const label =\n getHtmlAttribute(attrs, \"data-label\") || getHtmlAttribute(attrs, \"data-id\");\n return label ? `@${label}` : match;\n });\n\n if (typeof document !== \"undefined\") {\n const fragment = parseHtmlFragment(mentionNormalized);\n fragment\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n\n // Walk the tree, emitting one line per innermost block so nested blocks\n // (e.g. TipTap's <li><p>…</p></li>) are not repeated.\n const lines: string[] = [];\n let current: string | null = null;\n const flush = () => {\n if (current !== null) {\n lines.push(current);\n current = null;\n }\n };\n const visit = (node: Node) => {\n if (node.nodeType === 3) {\n const value = node.nodeValue ?? \"\";\n // Skip formatting whitespace between blocks.\n if (current === null && value.trim() === \"\") return;\n current = (current ?? \"\") + value;\n return;\n }\n if (node.nodeType !== 1) return;\n const tag = (node as Element).tagName.toUpperCase();\n if (tag === \"BR\") {\n current = (current ?? \"\") + \"\\n\";\n return;\n }\n if (!BLOCK_TAGS.has(tag)) {\n node.childNodes.forEach(visit);\n return;\n }\n flush();\n const linesBefore = lines.length;\n node.childNodes.forEach(visit);\n flush();\n // An empty block (e.g. <p></p>) is an empty line.\n if (lines.length === linesBefore && tag !== \"HR\") {\n lines.push(\"\");\n }\n };\n fragment.childNodes.forEach(visit);\n flush();\n return lines.join(\"\\n\");\n }\n\n // Node.js fallback regex\n const text = mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n // A closing block, plus any closing wrappers right after it, ends one line.\n .replace(\n /<\\/(?:p|div|li|pre|blockquote|h[1-6])>(?:\\s*<\\/(?:li|ul|ol|blockquote|div)>)*/gi,\n \"\\n\",\n )\n .replace(/<[^>]+>/g, \"\");\n return decodeHtmlEntities(text).replace(/\\n$/, \"\");\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\nimport { extractMentions } from \"./mentions\";\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n parseHtmlFragment(docOrEditor).querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n\n // Fallback: If no HTML mention tags were found, extract raw @mentions from text or markdown\n if (mentions.length === 0) {\n const rawHandles = extractMentions(docOrEditor);\n for (const handle of rawHandles) {\n mentions.push({\n id: handle,\n label: handle,\n type: \"user\",\n });\n }\n }\n }\n\n return mentions;\n}\n","import MarkdownIt from \"markdown-it\";\nimport taskLists from \"markdown-it-task-lists\";\nimport { escapeHtml, getEditorText } from \"./plain-text\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n}).use(taskLists);\n\nconst defaultValidateLink = md.validateLink;\nmd.validateLink = (url: string) => {\n if (\n url.startsWith(\"file://\") ||\n url.startsWith(\"vscode://\") ||\n url.startsWith(\"cursor://\")\n ) {\n return true;\n }\n return defaultValidateLink.call(md, url);\n};\n\n/**\n * Tags allowed through from raw HTML embedded in markdown (e.g. mention spans\n * and file links that tiptap-markdown serializes as HTML). Anything else is\n * rendered as escaped text. `input` is limited to checkboxes, which\n * markdown-it-task-lists emits as raw HTML.\n */\nconst ALLOWED_HTML_TAGS = new Set([\n \"a\", \"abbr\", \"b\", \"blockquote\", \"br\", \"code\", \"del\", \"details\", \"div\", \"em\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"hr\", \"i\", \"img\", \"input\", \"kbd\", \"li\", \"mark\",\n \"ol\", \"p\", \"pre\", \"s\", \"span\", \"strong\", \"sub\", \"summary\", \"sup\", \"table\",\n \"tbody\", \"td\", \"tfoot\", \"th\", \"thead\", \"tr\", \"u\", \"ul\",\n]);\n\nconst ALLOWED_HTML_ATTRS = new Set([\n \"alt\", \"align\", \"checked\", \"class\", \"colspan\", \"disabled\", \"height\", \"href\",\n \"rel\", \"rowspan\", \"src\", \"start\", \"target\", \"title\", \"type\", \"width\",\n]);\n\nconst HTML_TAG_REGEX =\n /<(\\/?)([a-zA-Z][a-zA-Z0-9-]*)((?:\\s+[^\\s\"'>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s\"'=<>`]+))?)*)\\s*\\/?>/g;\nconst HTML_ATTR_REGEX =\n /([^\\s\"'>\\/=]+)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'=<>`]+)))?/g;\n\nfunction sanitizeTag(\n tagText: string,\n isClosing: string,\n rawTagName: string,\n rawAttrs: string,\n): string {\n const tagName = rawTagName.toLowerCase();\n if (!ALLOWED_HTML_TAGS.has(tagName)) return escapeHtml(tagText);\n if (isClosing) return `</${tagName}>`;\n if (tagName === \"input\" && !/\\stype\\s*=\\s*[\"']?checkbox[\"']?[\\s>/]/i.test(tagText)) {\n return escapeHtml(tagText);\n }\n\n let attrs = \"\";\n let attrMatch: RegExpExecArray | null;\n HTML_ATTR_REGEX.lastIndex = 0;\n while ((attrMatch = HTML_ATTR_REGEX.exec(rawAttrs)) !== null) {\n const name = attrMatch[1].toLowerCase();\n if (!ALLOWED_HTML_ATTRS.has(name) && !/^data-[a-z0-9_.-]+$/.test(name)) {\n continue;\n }\n const rawValue = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4];\n if (rawValue === undefined) {\n attrs += ` ${name}`;\n continue;\n }\n const value = md.utils.unescapeAll(rawValue);\n if (\n (name === \"href\" || name === \"src\") &&\n // Browsers ignore control characters and whitespace inside schemes.\n !md.validateLink(value.replace(/[\\u0000-\\u0020\\u007f]/g, \"\"))\n ) {\n continue;\n }\n attrs += ` ${name}=\"${escapeHtml(value)}\"`;\n }\n return `<${tagName}${attrs}>`;\n}\n\n/**\n * Sanitizes raw HTML with an allowlist of tags and attributes: event handlers,\n * `style`, and unsafe URL schemes are dropped; disallowed tags are escaped.\n */\nfunction sanitizeEmbeddedHtml(html: string): string {\n let result = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n HTML_TAG_REGEX.lastIndex = 0;\n while ((match = HTML_TAG_REGEX.exec(html)) !== null) {\n result += html.slice(lastIndex, match.index).replace(/</g, \"&lt;\");\n result += sanitizeTag(match[0], match[1], match[2], match[3]);\n lastIndex = match.index + match[0].length;\n }\n return result + html.slice(lastIndex).replace(/</g, \"&lt;\");\n}\n\nconst defaultHtmlInline = md.renderer.rules.html_inline;\nconst defaultHtmlBlock = md.renderer.rules.html_block;\nmd.renderer.rules.html_inline = (tokens, idx, options, env, self) =>\n env?.allowUnsafeHtml\n ? defaultHtmlInline!(tokens, idx, options, env, self)\n : sanitizeEmbeddedHtml(tokens[idx].content);\nmd.renderer.rules.html_block = (tokens, idx, options, env, self) =>\n env?.allowUnsafeHtml\n ? defaultHtmlBlock!(tokens, idx, options, env, self)\n : sanitizeEmbeddedHtml(tokens[idx].content);\n\nimport {\n preprocessMarkdownMentions,\n type PreprocessMarkdownMentionsOptions,\n} from \"./mentions\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Preprocesses file-protocol and editor-protocol links in markdown content:\n * converts [label](file://...), vscode://, and cursor:// links into anchor tags\n * annotated with data-file-link=\"true\", preserving code backticks in labels.\n */\nexport function preprocessMarkdownFileLinks(content: string): string {\n if (!content) return \"\";\n return content.replace(\n /\\[([^\\]]+)\\]\\(((?:file|vscode|cursor):\\/\\/[^)]+)\\)/g,\n (_match, rawLabel, href) => {\n const trimmed = rawLabel.trim();\n const codeMatch = trimmed.match(/^`([^`]+)`$/);\n const labelContent = codeMatch\n ? `<code>${escapeHtml(codeMatch[1])}</code>`\n : escapeHtml(trimmed);\n return `<a href=\"${escapeHtml(href)}\" data-file-link=\"true\" title=\"Click to copy file path\">${labelContent}</a>`;\n }\n );\n}\n\nexport interface MarkdownToHtmlOptions {\n /**\n * Preprocess file, vscode, and cursor links into clickable data-file-link tags.\n */\n preprocessFileLinks?: boolean;\n /**\n * Whether to preprocess @mentions into TipTap mention node HTML spans.\n */\n preprocessMentions?: boolean;\n /**\n * Pool of mentionables to pass to preprocessMarkdownMentions.\n */\n mentionables?: MentionEntity[];\n /**\n * Full options for preprocessMarkdownMentions.\n */\n preprocessOptions?: PreprocessMarkdownMentionsOptions;\n /**\n * Render raw HTML embedded in the markdown without sanitizing it. By default,\n * embedded HTML is restricted to an allowlist of tags and attributes (event\n * handlers, `style` and unsafe URL schemes are removed). Only enable this for\n * fully trusted input.\n */\n allowUnsafeHtml?: boolean;\n}\n\n/**\n * Converts a markdown string into HTML suitable for TipTap initial content or setContent.\n * Raw HTML embedded in the markdown is sanitized unless `allowUnsafeHtml` is set.\n */\nexport function markdownToTipTapHtml(\n markdown: string,\n options?: MarkdownToHtmlOptions\n): string {\n if (!markdown) return \"<p></p>\";\n let content = markdown;\n if (options?.preprocessFileLinks) {\n content = preprocessMarkdownFileLinks(content);\n }\n if (\n options?.preprocessMentions ||\n options?.mentionables ||\n options?.preprocessOptions\n ) {\n const mentionOpts = options.preprocessOptions || {\n mentionables: options.mentionables,\n };\n content = preprocessMarkdownMentions(content, mentionOpts);\n }\n return md.render(content, { allowUnsafeHtml: options?.allowUnsafeHtml });\n}\n\n/**\n * Extracts clean markdown from a TipTap editor instance.\n * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().\n * Otherwise, it falls back to getEditorText(editor).\n */\nexport function getEditorMarkdown(editor: any): string {\n if (!editor) return \"\";\n if (typeof editor.storage?.markdown?.getMarkdown === \"function\") {\n return editor.storage.markdown.getMarkdown();\n }\n return getEditorText(editor);\n}\n"],"mappings":"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","names":["match"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-SHWP2A43.cjs","../src/serializers/mentions.ts","../src/serializers/plain-text.ts","../src/serializers/markdown.ts"],"names":["match"],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-SHWP2A43.cjs","sourcesContent":[null,"import { escapeHtml } from \"./plain-text\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Canonical regex pattern for matching @mentions in plain text or markdown.\n * Supports:\n * - Standard unquoted handles: @username, @user.name, @team_alpha, @sa-1\n * - Quoted handles: @\"John Doe\", &quot;Jane Doe&quot;\n * Unquoted handles exclude trailing punctuation (e.g. @violet. matches \"violet\" without the dot).\n */\nexport const MENTION_REGEX =\n /(?:^|[\\s>(*_\"';\\\\/[\\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:\"([^\"]+)\"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\\.[a-zA-Z0-9_-]+)*))/g;\n\n/**\n * Split regex identifying markdown code blocks, inline code, URLs, and existing HTML tags.\n * Used by preprocessMarkdownMentions to ensure non-mention regions remain completely untouched.\n */\nexport const MARKDOWN_MENTION_SPLIT_REGEX =\n /(```[\\s\\S]*?```|~~~[\\s\\S]*?~~~|<pre[\\s\\S]*?<\\/pre>|<code[\\s\\S]*?<\\/code>|`[^`\\n]+`|<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])[^>]*>[\\s\\S]*?<\\/span>|<[^>]+>|\\]\\([^)]+\\)|(?:https?|file|vscode|cursor|mailto):\\/\\/[^\\s<)]+)/gi;\n\nexport interface MentionSegment {\n type: \"text\" | \"mention\";\n value: string;\n handle?: string;\n}\n\nexport interface PreprocessMarkdownMentionsOptions {\n /**\n * Known pool of mentionable entities (users, agents, teams, etc.).\n */\n mentionables?: MentionEntity[];\n /**\n * Default entity type assigned when a handle does not match any entry in mentionables.\n * Defaults to 'user'.\n */\n defaultType?: string;\n /**\n * Custom resolver callback to derive entity metadata for unmatched handles.\n */\n resolveMention?: (handle: string) => Partial<MentionEntity> | null | undefined;\n}\n\n/**\n * Strips code blocks and inline code from markdown or HTML content:\n * - Fenced code blocks: ```...``` and ~~~...~~~\n * - Inline backtick code: `...`\n * - HTML code/pre tags: <pre>...</pre>, <code>...</code>\n * Used to avoid false-positive mention parsing and keyword analysis within code snippets, terminal logs, or stack traces.\n */\nexport function stripMarkdownCode(content: string): string {\n if (!content || typeof content !== \"string\") return \"\";\n return content\n .replace(/```[\\s\\S]*?```/g, \"\")\n .replace(/~~~[\\s\\S]*?~~~/g, \"\")\n .replace(/<pre[\\s\\S]*?<\\/pre>/gi, \"\")\n .replace(/<code[\\s\\S]*?<\\/code>/gi, \"\")\n .replace(/`[^`\\n]*`/g, \"\");\n}\n\n/**\n * Extracts unique mention handles from a text, markdown, or HTML string,\n * ignoring trailing punctuation, code blocks, URLs, and pre-existing HTML mention attributes.\n */\nexport function extractMentions(content: string): string[] {\n if (!content || typeof content !== \"string\") return [];\n\n // Normalize existing HTML mention nodes (e.g. from TipTap or rich text serializers)\n // so data-mention-suggestion-char=\"@\" does not trigger spurious quoted matches against attributes,\n // and ensure the actual mentioned label or ID is preserved cleanly.\n const normalizedMentionNodes = content.replace(\n /<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"'])[^>]*>([\\s\\S]*?)<\\/span>/gi,\n (match, inner) => {\n const labelMatch = match.match(/\\bdata-label=[\"']([^\"']+)[\"']/i);\n if (labelMatch) return ` @${labelMatch[1]} `;\n const idMatch = match.match(/\\bdata-id=[\"']([^\"']+)[\"']/i);\n if (idMatch) return ` @${idMatch[1]} `;\n return ` ${inner} `;\n }\n );\n\n const cleanContent = stripMarkdownCode(normalizedMentionNodes);\n // Strip URLs and markdown link destinations so @package or @handles in URLs are not extracted as mentions\n const withoutUrls = cleanContent\n .replace(/(?:https?|ftp|file|vscode|cursor|mailto):\\/\\/[^\\s<>()]+/gi, \"\")\n .replace(/\\]\\([^)]*\\)/g, \"]\");\n // Strip remaining HTML tags so attributes containing '@' or '>' aren't treated as mention triggers\n const textOnly = withoutUrls.replace(/<[^>]+>/g, \" \");\n\n const mentions: string[] = [];\n const seen = new Set<string>();\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(textOnly)) !== null) {\n const handle = (match[1] ?? match[2] ?? match[3] ?? \"\").trim();\n if (handle && !seen.has(handle)) {\n seen.add(handle);\n mentions.push(handle);\n }\n }\n\n return mentions;\n}\n\n/**\n * Segments a text string into plain text parts and mention tokens.\n * Correctly leaves trailing punctuation (like \".\") as part of the following text segment.\n */\nexport function parseMentionSegments(content: string): MentionSegment[] {\n if (!content) return [];\n\n const segments: MentionSegment[] = [];\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const fullMatch = match[0];\n const atIndex = fullMatch.indexOf(\"@\");\n const prefix = atIndex > 0 ? fullMatch.slice(0, atIndex) : \"\";\n const mentionToken = fullMatch.slice(atIndex);\n const handle = match[1] ?? match[2] ?? match[3];\n const matchStart = match.index + prefix.length;\n\n if (matchStart > lastIndex) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex, matchStart),\n });\n }\n\n segments.push({\n type: \"mention\",\n value: mentionToken,\n handle,\n });\n\n lastIndex = matchStart + mentionToken.length;\n }\n\n if (lastIndex < content.length) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex),\n });\n }\n\n return segments;\n}\n\n/**\n * Preprocesses markdown text by turning raw @mention handles into TipTap-compatible\n * mention HTML spans (<span class=\"pixerate-mention-node\" data-type=\"mention\" ...>),\n * ensuring code blocks, inline code, existing mention nodes, and URLs remain immune.\n */\nexport function preprocessMarkdownMentions(\n content: string,\n optionsOrMentionables: MentionEntity[] | PreprocessMarkdownMentionsOptions = []\n): string {\n if (!content || typeof content !== \"string\") return \"\";\n\n const options: PreprocessMarkdownMentionsOptions = Array.isArray(optionsOrMentionables)\n ? { mentionables: optionsOrMentionables }\n : optionsOrMentionables;\n\n const allMentionables = options.mentionables || [];\n const defaultType = options.defaultType || \"user\";\n const resolveMention = options.resolveMention;\n\n const parts = content.split(MARKDOWN_MENTION_SPLIT_REGEX);\n\n return parts\n .map((part) => {\n if (!part) return \"\";\n\n // Preserve code fences, code tags, inline backticks, existing mention spans,\n // HTML tags, markdown link targets, and raw URLs untouched.\n if (\n part.startsWith(\"```\") ||\n part.startsWith(\"~~~\") ||\n part.startsWith(\"`\") ||\n part.startsWith(\"](\") ||\n /^(?:https?|file|vscode|cursor|mailto):\\/\\//i.test(part) ||\n /^<pre[\\s>]/i.test(part) ||\n /^<code[\\s>]/i.test(part) ||\n /^<[^>]+>$/i.test(part) ||\n /^<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])/i.test(\n part\n )\n ) {\n return part;\n }\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n return part.replace(regex, (match, quotedHandle, escapedQuotedHandle, standardHandle) => {\n const atIndex = match.indexOf(\"@\");\n const prefix = atIndex > 0 ? match.slice(0, atIndex) : \"\";\n const rawHandle = (quotedHandle || escapedQuotedHandle || standardHandle || \"\").trim();\n if (!rawHandle) return match;\n\n const lowerHandle = rawHandle.toLowerCase();\n const entity = allMentionables.find((e) => {\n if (e.label?.toLowerCase() === lowerHandle) return true;\n if (e.handle?.toLowerCase() === lowerHandle) return true;\n if (e.name?.toLowerCase() === lowerHandle) return true;\n if (e.id?.toLowerCase() === lowerHandle) return true;\n if (e.type === \"agent\" && `agent${(e.handle || e.label || \"\").toLowerCase()}` === lowerHandle) return true;\n if (\n e.aliases?.some(\n (a: string) =>\n a.toLowerCase() === lowerHandle ||\n (e.type === \"agent\" && `agent${a.toLowerCase()}` === lowerHandle)\n )\n ) {\n return true;\n }\n return false;\n });\n\n let id = entity?.id;\n let label = entity?.label || entity?.handle || rawHandle;\n let type = entity?.type;\n let avatarUrl = entity?.avatarUrl;\n let color = entity?.color || entity?.hexColor;\n\n if (!entity) {\n const customResolved = resolveMention?.(rawHandle);\n if (customResolved) {\n id = customResolved.id ?? id;\n label = customResolved.label ?? customResolved.handle ?? label;\n type = customResolved.type ?? type;\n avatarUrl = customResolved.avatarUrl ?? avatarUrl;\n color = customResolved.color ?? customResolved.hexColor ?? color;\n } else {\n const stripped = lowerHandle.replace(/^agent[\\s\\-_]*/i, \"\");\n if (\n [\"supervisor\", \"coordinator\", \"planner\", \"validator\", \"executor\"].includes(stripped)\n ) {\n type = \"agent\";\n id = stripped;\n label = stripped;\n } else if (lowerHandle === \"agents\") {\n type = \"team\";\n id = \"agents\";\n label = \"agents\";\n } else {\n type = defaultType;\n id = rawHandle;\n label = rawHandle;\n }\n }\n }\n\n const avatarAttr = avatarUrl ? ` data-avatar-url=\"${escapeHtml(avatarUrl)}\"` : \"\";\n const colorAttr = color ? ` data-color=\"${escapeHtml(color)}\"` : \"\";\n\n return `${prefix}<span class=\"pixerate-mention-node\" data-type=\"mention\" data-id=\"${escapeHtml(\n id || label\n )}\" data-label=\"${escapeHtml(label)}\" data-mention-suggestion-char=\"@\" data-type-name=\"${escapeHtml(\n type || defaultType\n )}\"${avatarAttr}${colorAttr}>@${escapeHtml(label)}</span>`;\n });\n })\n .join(\"\");\n}\n","/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Matches strings that are already TipTap paragraph HTML (start with `<p>` and\n * end with `</p>`), as opposed to plain text that merely mentions a `<p>` tag.\n */\nconst PARAGRAPH_HTML_REGEX = /^\\s*<p[\\s>][\\s\\S]*<\\/p>\\s*$/i;\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n * Input that is already paragraph HTML (`<p>…</p>`) is passed through as-is.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (PARAGRAPH_HTML_REGEX.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Block-level elements that start a new line in plain-text output.\n */\nconst BLOCK_TAGS = new Set([\n \"P\", \"DIV\", \"LI\", \"UL\", \"OL\", \"PRE\", \"BLOCKQUOTE\", \"TABLE\", \"TR\",\n \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"HR\",\n]);\n\n/**\n * Matches a TipTap mention span (including its content). The lookahead keeps\n * a single `[^>]*` scan per tag, avoiding catastrophic backtracking on\n * malformed input.\n */\nconst MENTION_SPAN_REGEX =\n /<span\\b(?=[^>]*\\bdata-type=[\"']mention[\"'])([^>]*)>[\\s\\S]*?<\\/span>/gi;\n\nfunction getHtmlAttribute(attrs: string, name: string): string | undefined {\n const match = new RegExp(`\\\\b${name}=(?:\"([^\"]*)\"|'([^']*)')`, \"i\").exec(\n attrs,\n );\n return match ? (match[1] ?? match[2]) : undefined;\n}\n\n/**\n * Parses HTML into an inert fragment. Content of a `<template>` element is not\n * rendered, so `<img onerror>` and similar handlers never run.\n */\nfunction parseHtmlFragment(html: string): DocumentFragment {\n const template = document.createElement(\"template\");\n template.innerHTML = html;\n return template.content;\n}\n\nfunction decodeHtmlEntities(text: string): string {\n return text\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#0*39;/g, \"'\")\n .replace(/&nbsp;/g, \"\\u00a0\")\n .replace(/&amp;/g, \"&\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html.replace(MENTION_SPAN_REGEX, (match, attrs) => {\n const label =\n getHtmlAttribute(attrs, \"data-label\") || getHtmlAttribute(attrs, \"data-id\");\n return label ? `@${label}` : match;\n });\n\n if (typeof document !== \"undefined\") {\n const fragment = parseHtmlFragment(mentionNormalized);\n fragment\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n\n // Walk the tree, emitting one line per innermost block so nested blocks\n // (e.g. TipTap's <li><p>…</p></li>) are not repeated.\n const lines: string[] = [];\n let current: string | null = null;\n const flush = () => {\n if (current !== null) {\n lines.push(current);\n current = null;\n }\n };\n const visit = (node: Node) => {\n if (node.nodeType === 3) {\n const value = node.nodeValue ?? \"\";\n // Skip formatting whitespace between blocks.\n if (current === null && value.trim() === \"\") return;\n current = (current ?? \"\") + value;\n return;\n }\n if (node.nodeType !== 1) return;\n const tag = (node as Element).tagName.toUpperCase();\n if (tag === \"BR\") {\n current = (current ?? \"\") + \"\\n\";\n return;\n }\n if (!BLOCK_TAGS.has(tag)) {\n node.childNodes.forEach(visit);\n return;\n }\n flush();\n const linesBefore = lines.length;\n node.childNodes.forEach(visit);\n flush();\n // An empty block (e.g. <p></p>) is an empty line.\n if (lines.length === linesBefore && tag !== \"HR\") {\n lines.push(\"\");\n }\n };\n fragment.childNodes.forEach(visit);\n flush();\n return lines.join(\"\\n\");\n }\n\n // Node.js fallback regex\n const text = mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n // A closing block, plus any closing wrappers right after it, ends one line.\n .replace(\n /<\\/(?:p|div|li|pre|blockquote|h[1-6])>(?:\\s*<\\/(?:li|ul|ol|blockquote|div)>)*/gi,\n \"\\n\",\n )\n .replace(/<[^>]+>/g, \"\");\n return decodeHtmlEntities(text).replace(/\\n$/, \"\");\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\nimport { extractMentions } from \"./mentions\";\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n parseHtmlFragment(docOrEditor).querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n\n // Fallback: If no HTML mention tags were found, extract raw @mentions from text or markdown\n if (mentions.length === 0) {\n const rawHandles = extractMentions(docOrEditor);\n for (const handle of rawHandles) {\n mentions.push({\n id: handle,\n label: handle,\n type: \"user\",\n });\n }\n }\n }\n\n return mentions;\n}\n","import MarkdownIt from \"markdown-it\";\nimport taskLists from \"markdown-it-task-lists\";\nimport { escapeHtml, getEditorText } from \"./plain-text\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n}).use(taskLists);\n\nconst defaultValidateLink = md.validateLink;\nmd.validateLink = (url: string) => {\n if (\n url.startsWith(\"file://\") ||\n url.startsWith(\"vscode://\") ||\n url.startsWith(\"cursor://\")\n ) {\n return true;\n }\n return defaultValidateLink.call(md, url);\n};\n\n/**\n * Tags allowed through from raw HTML embedded in markdown (e.g. mention spans\n * and file links that tiptap-markdown serializes as HTML). Anything else is\n * rendered as escaped text. `input` is limited to checkboxes, which\n * markdown-it-task-lists emits as raw HTML.\n */\nconst ALLOWED_HTML_TAGS = new Set([\n \"a\", \"abbr\", \"b\", \"blockquote\", \"br\", \"code\", \"del\", \"details\", \"div\", \"em\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"hr\", \"i\", \"img\", \"input\", \"kbd\", \"li\", \"mark\",\n \"ol\", \"p\", \"pre\", \"s\", \"span\", \"strong\", \"sub\", \"summary\", \"sup\", \"table\",\n \"tbody\", \"td\", \"tfoot\", \"th\", \"thead\", \"tr\", \"u\", \"ul\",\n]);\n\nconst ALLOWED_HTML_ATTRS = new Set([\n \"alt\", \"align\", \"checked\", \"class\", \"colspan\", \"disabled\", \"height\", \"href\",\n \"rel\", \"rowspan\", \"src\", \"start\", \"target\", \"title\", \"type\", \"width\",\n]);\n\nconst HTML_TAG_REGEX =\n /<(\\/?)([a-zA-Z][a-zA-Z0-9-]*)((?:\\s+[^\\s\"'>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s\"'=<>`]+))?)*)\\s*\\/?>/g;\nconst HTML_ATTR_REGEX =\n /([^\\s\"'>\\/=]+)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'=<>`]+)))?/g;\n\nfunction sanitizeTag(\n tagText: string,\n isClosing: string,\n rawTagName: string,\n rawAttrs: string,\n): string {\n const tagName = rawTagName.toLowerCase();\n if (!ALLOWED_HTML_TAGS.has(tagName)) return escapeHtml(tagText);\n if (isClosing) return `</${tagName}>`;\n if (tagName === \"input\" && !/\\stype\\s*=\\s*[\"']?checkbox[\"']?[\\s>/]/i.test(tagText)) {\n return escapeHtml(tagText);\n }\n\n let attrs = \"\";\n let attrMatch: RegExpExecArray | null;\n HTML_ATTR_REGEX.lastIndex = 0;\n while ((attrMatch = HTML_ATTR_REGEX.exec(rawAttrs)) !== null) {\n const name = attrMatch[1].toLowerCase();\n if (!ALLOWED_HTML_ATTRS.has(name) && !/^data-[a-z0-9_.-]+$/.test(name)) {\n continue;\n }\n const rawValue = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4];\n if (rawValue === undefined) {\n attrs += ` ${name}`;\n continue;\n }\n const value = md.utils.unescapeAll(rawValue);\n if (\n (name === \"href\" || name === \"src\") &&\n // Browsers ignore control characters and whitespace inside schemes.\n !md.validateLink(value.replace(/[\\u0000-\\u0020\\u007f]/g, \"\"))\n ) {\n continue;\n }\n attrs += ` ${name}=\"${escapeHtml(value)}\"`;\n }\n return `<${tagName}${attrs}>`;\n}\n\n/**\n * Sanitizes raw HTML with an allowlist of tags and attributes: event handlers,\n * `style`, and unsafe URL schemes are dropped; disallowed tags are escaped.\n */\nfunction sanitizeEmbeddedHtml(html: string): string {\n let result = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n HTML_TAG_REGEX.lastIndex = 0;\n while ((match = HTML_TAG_REGEX.exec(html)) !== null) {\n result += html.slice(lastIndex, match.index).replace(/</g, \"&lt;\");\n result += sanitizeTag(match[0], match[1], match[2], match[3]);\n lastIndex = match.index + match[0].length;\n }\n return result + html.slice(lastIndex).replace(/</g, \"&lt;\");\n}\n\nconst defaultHtmlInline = md.renderer.rules.html_inline;\nconst defaultHtmlBlock = md.renderer.rules.html_block;\nmd.renderer.rules.html_inline = (tokens, idx, options, env, self) =>\n env?.allowUnsafeHtml\n ? defaultHtmlInline!(tokens, idx, options, env, self)\n : sanitizeEmbeddedHtml(tokens[idx].content);\nmd.renderer.rules.html_block = (tokens, idx, options, env, self) =>\n env?.allowUnsafeHtml\n ? defaultHtmlBlock!(tokens, idx, options, env, self)\n : sanitizeEmbeddedHtml(tokens[idx].content);\n\nimport {\n preprocessMarkdownMentions,\n type PreprocessMarkdownMentionsOptions,\n} from \"./mentions\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Preprocesses file-protocol and editor-protocol links in markdown content:\n * converts [label](file://...), vscode://, and cursor:// links into anchor tags\n * annotated with data-file-link=\"true\", preserving code backticks in labels.\n */\nexport function preprocessMarkdownFileLinks(content: string): string {\n if (!content) return \"\";\n return content.replace(\n /\\[([^\\]]+)\\]\\(((?:file|vscode|cursor):\\/\\/[^)]+)\\)/g,\n (_match, rawLabel, href) => {\n const trimmed = rawLabel.trim();\n const codeMatch = trimmed.match(/^`([^`]+)`$/);\n const labelContent = codeMatch\n ? `<code>${escapeHtml(codeMatch[1])}</code>`\n : escapeHtml(trimmed);\n return `<a href=\"${escapeHtml(href)}\" data-file-link=\"true\" title=\"Click to copy file path\">${labelContent}</a>`;\n }\n );\n}\n\nexport interface MarkdownToHtmlOptions {\n /**\n * Preprocess file, vscode, and cursor links into clickable data-file-link tags.\n */\n preprocessFileLinks?: boolean;\n /**\n * Whether to preprocess @mentions into TipTap mention node HTML spans.\n */\n preprocessMentions?: boolean;\n /**\n * Pool of mentionables to pass to preprocessMarkdownMentions.\n */\n mentionables?: MentionEntity[];\n /**\n * Full options for preprocessMarkdownMentions.\n */\n preprocessOptions?: PreprocessMarkdownMentionsOptions;\n /**\n * Render raw HTML embedded in the markdown without sanitizing it. By default,\n * embedded HTML is restricted to an allowlist of tags and attributes (event\n * handlers, `style` and unsafe URL schemes are removed). Only enable this for\n * fully trusted input.\n */\n allowUnsafeHtml?: boolean;\n}\n\n/**\n * Converts a markdown string into HTML suitable for TipTap initial content or setContent.\n * Raw HTML embedded in the markdown is sanitized unless `allowUnsafeHtml` is set.\n */\nexport function markdownToTipTapHtml(\n markdown: string,\n options?: MarkdownToHtmlOptions\n): string {\n if (!markdown) return \"<p></p>\";\n let content = markdown;\n if (options?.preprocessFileLinks) {\n content = preprocessMarkdownFileLinks(content);\n }\n if (\n options?.preprocessMentions ||\n options?.mentionables ||\n options?.preprocessOptions\n ) {\n const mentionOpts = options.preprocessOptions || {\n mentionables: options.mentionables,\n };\n content = preprocessMarkdownMentions(content, mentionOpts);\n }\n return md.render(content, { allowUnsafeHtml: options?.allowUnsafeHtml });\n}\n\n/**\n * Extracts clean markdown from a TipTap editor instance.\n * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().\n * Otherwise, it falls back to getEditorText(editor).\n */\nexport function getEditorMarkdown(editor: any): string {\n if (!editor) return \"\";\n if (typeof editor.storage?.markdown?.getMarkdown === \"function\") {\n return editor.storage.markdown.getMarkdown();\n }\n return getEditorText(editor);\n}\n"]}