@ecsplico/editor 2.0.0 → 2.1.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.
Files changed (278) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +4 -3
  3. package/dist/adapters/anchors.d.ts +80 -0
  4. package/dist/adapters/anchors.js +270 -0
  5. package/dist/adapters/anchors.js.map +1 -0
  6. package/dist/adapters/comments/client.d.ts +64 -0
  7. package/dist/adapters/comments/client.js +536 -0
  8. package/dist/adapters/comments/client.js.map +1 -0
  9. package/dist/adapters/comments/drizzle.d.ts +430 -0
  10. package/dist/adapters/comments/drizzle.js +236 -0
  11. package/dist/adapters/comments/drizzle.js.map +1 -0
  12. package/dist/adapters/comments/errors.d.ts +9 -0
  13. package/dist/adapters/comments/errors.js +19 -0
  14. package/dist/adapters/comments/errors.js.map +1 -0
  15. package/dist/adapters/comments/json.d.ts +19 -0
  16. package/dist/adapters/comments/json.js +94 -0
  17. package/dist/adapters/comments/json.js.map +1 -0
  18. package/dist/adapters/comments/record.js +78 -0
  19. package/dist/adapters/comments/record.js.map +1 -0
  20. package/dist/adapters/comments/server.d.ts +23 -0
  21. package/dist/adapters/comments/server.js +102 -0
  22. package/dist/adapters/comments/server.js.map +1 -0
  23. package/dist/adapters/comments/types.d.ts +109 -0
  24. package/dist/adapters/documents.js +108 -0
  25. package/dist/adapters/documents.js.map +1 -0
  26. package/dist/adapters/drizzle.d.ts +293 -0
  27. package/dist/adapters/drizzle.js +157 -0
  28. package/dist/adapters/drizzle.js.map +1 -0
  29. package/dist/adapters/files.js +30 -0
  30. package/dist/adapters/files.js.map +1 -0
  31. package/dist/adapters/forge.d.ts +58 -0
  32. package/dist/adapters/forge.js +91 -0
  33. package/dist/adapters/forge.js.map +1 -0
  34. package/dist/adapters/index.d.ts +13 -0
  35. package/dist/adapters/index.js +0 -0
  36. package/dist/adapters/json.d.ts +24 -0
  37. package/dist/adapters/json.js +128 -0
  38. package/dist/adapters/json.js.map +1 -0
  39. package/dist/adapters/nitro.d.ts +61 -0
  40. package/dist/adapters/nitro.js +212 -0
  41. package/dist/adapters/nitro.js.map +1 -0
  42. package/dist/adapters/routes.js +16 -0
  43. package/dist/adapters/routes.js.map +1 -0
  44. package/dist/adapters/shared.d.ts +37 -0
  45. package/dist/adapters/shared.js +32 -0
  46. package/dist/adapters/shared.js.map +1 -0
  47. package/dist/adapters/vue.d.ts +67 -0
  48. package/dist/adapters/vue.js +187 -0
  49. package/dist/adapters/vue.js.map +1 -0
  50. package/dist/code/CodeSurface.vue.d.ts +3 -3
  51. package/dist/core/doc-anchors.d.ts +5 -0
  52. package/dist/core/doc-anchors.js +4 -3
  53. package/dist/core/doc-anchors.js.map +1 -1
  54. package/dist/core/editor-ui.js +57 -1
  55. package/dist/core/editor-ui.js.map +1 -1
  56. package/dist/core/surface-session.js +139 -0
  57. package/dist/core/surface-session.js.map +1 -0
  58. package/dist/document/DocumentSurface.d.ts +1 -1
  59. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  60. package/dist/features/ai/agent-op-review.d.ts +2 -2
  61. package/dist/features/ai/agent-op-review.js.map +1 -1
  62. package/dist/features/ai/agent-ops.d.ts +1 -1
  63. package/dist/features/ai/agent-ops.js +9 -6
  64. package/dist/features/ai/agent-ops.js.map +1 -1
  65. package/dist/features/ai/ai-apply.d.ts +1 -1
  66. package/dist/features/ai/ai-review.js +10 -1
  67. package/dist/features/ai/ai-review.js.map +1 -1
  68. package/dist/features/ai/components/AiSelectionMenu.js +78 -252
  69. package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
  70. package/dist/features/ai/components/AiSelectionMenu.vue.d.ts +2 -1
  71. package/dist/features/ai/components/AiSidebar.js +2 -2
  72. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  73. package/dist/features/ai/components/DocumentChatOps.js +1 -0
  74. package/dist/features/ai/components/DocumentChatOps.js.map +1 -1
  75. package/dist/features/ai/components/ModelQuickSwitch.js +1 -1
  76. package/dist/features/ai/components/SettingsAiTab.js +1 -1
  77. package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
  78. package/dist/features/ai/document-chat.d.ts +3 -2
  79. package/dist/features/ai/document-chat.js +16 -19
  80. package/dist/features/ai/document-chat.js.map +1 -1
  81. package/dist/features/ai/index.d.ts +5 -3
  82. package/dist/features/ai/index.js +4 -2
  83. package/dist/features/ai/protocol/agent-ops.d.ts +22 -17
  84. package/dist/features/ai/protocol/agent-ops.js +65 -39
  85. package/dist/features/ai/protocol/agent-ops.js.map +1 -1
  86. package/dist/features/ai/protocol/block-lines.d.ts +89 -0
  87. package/dist/features/ai/protocol/block-lines.js +177 -0
  88. package/dist/features/ai/protocol/block-lines.js.map +1 -0
  89. package/dist/features/ai/protocol/chat.js +10 -10
  90. package/dist/features/ai/protocol/chat.js.map +1 -1
  91. package/dist/features/ai/protocol/index.d.ts +3 -2
  92. package/dist/features/ai/protocol/index.js +3 -2
  93. package/dist/features/ai/react/AiSelectionMenu.d.ts +3 -2
  94. package/dist/features/ai/react/AiSelectionMenu.js +64 -255
  95. package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
  96. package/dist/features/ai/react/AiSidebar.js +2 -2
  97. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  98. package/dist/features/ai/react/DocumentChatOps.js +1 -0
  99. package/dist/features/ai/react/DocumentChatOps.js.map +1 -1
  100. package/dist/features/ai/react/ModelQuickSwitch.js +1 -1
  101. package/dist/features/ai/react/SettingsAiTab.js +1 -1
  102. package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
  103. package/dist/features/ai/react/use-ai-selection-flow.js +34 -0
  104. package/dist/features/ai/react/use-ai-selection-flow.js.map +1 -0
  105. package/dist/features/ai/selection-flow.d.ts +133 -0
  106. package/dist/features/ai/selection-flow.js +283 -0
  107. package/dist/features/ai/selection-flow.js.map +1 -0
  108. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  109. package/dist/features/ai/use-document-chat.d.ts +1 -1
  110. package/dist/features/authors/components/AuthorColorsPanel.js +1 -1
  111. package/dist/features/authors/feature.js +1 -1
  112. package/dist/features/authors/index.js +1 -1
  113. package/dist/features/authors/react/AuthorColorsPanel.js +1 -1
  114. package/dist/features/comments/components/CommentBubble.js +1 -1
  115. package/dist/features/comments/components/CommentComposer.js +1 -1
  116. package/dist/features/comments/components/CommentThreadView.js +5 -2
  117. package/dist/features/comments/components/CommentThreadView.js.map +1 -1
  118. package/dist/features/comments/components/CommentsMargin.js +108 -230
  119. package/dist/features/comments/components/CommentsMargin.js.map +1 -1
  120. package/dist/features/comments/components/CommentsOverlay.js +1 -1
  121. package/dist/features/comments/feature.js +1 -1
  122. package/dist/features/comments/index.d.ts +4 -2
  123. package/dist/features/comments/index.js +4 -2
  124. package/dist/features/comments/margin-controller.d.ts +44 -0
  125. package/dist/features/comments/margin-controller.js +132 -0
  126. package/dist/features/comments/margin-controller.js.map +1 -0
  127. package/dist/features/comments/margin-layout.d.ts +55 -0
  128. package/dist/features/comments/margin-layout.js +79 -0
  129. package/dist/features/comments/margin-layout.js.map +1 -0
  130. package/dist/features/comments/model.d.ts +8 -0
  131. package/dist/features/comments/model.js +60 -34
  132. package/dist/features/comments/model.js.map +1 -1
  133. package/dist/features/comments/react/CommentBubble.js +1 -1
  134. package/dist/features/comments/react/CommentComposer.js +1 -1
  135. package/dist/features/comments/react/CommentThreadView.js +2 -2
  136. package/dist/features/comments/react/CommentThreadView.js.map +1 -1
  137. package/dist/features/comments/react/CommentsMargin.d.ts +0 -5
  138. package/dist/features/comments/react/CommentsMargin.js +85 -251
  139. package/dist/features/comments/react/CommentsMargin.js.map +1 -1
  140. package/dist/features/comments/react/CommentsOverlay.js +1 -1
  141. package/dist/features/comments/react/use-comments.js +1 -1
  142. package/dist/features/comments/react/use-margin-layout.js +45 -0
  143. package/dist/features/comments/react/use-margin-layout.js.map +1 -0
  144. package/dist/features/comments/react.d.ts +1 -1
  145. package/dist/features/comments/schema.d.ts +23 -0
  146. package/dist/features/comments/schema.js.map +1 -1
  147. package/dist/features/comments/snapshot-equality.js +40 -0
  148. package/dist/features/comments/snapshot-equality.js.map +1 -0
  149. package/dist/features/comments/thread-anchor.js +33 -0
  150. package/dist/features/comments/thread-anchor.js.map +1 -0
  151. package/dist/features/comments/use-comments.d.ts +3 -1
  152. package/dist/features/comments/use-comments.js +1 -0
  153. package/dist/features/comments/use-comments.js.map +1 -1
  154. package/dist/features/comments/use-margin-layout.js +29 -0
  155. package/dist/features/comments/use-margin-layout.js.map +1 -0
  156. package/dist/features/comments/vue.d.ts +1 -1
  157. package/dist/features/composites/accepted-children.d.ts +21 -0
  158. package/dist/features/composites/accepted-children.js +126 -0
  159. package/dist/features/composites/accepted-children.js.map +1 -0
  160. package/dist/features/composites/components/CompositeDetails.js +1 -1
  161. package/dist/features/composites/components/CompositeInspector.js +38 -164
  162. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  163. package/dist/features/composites/feature.d.ts +2 -1
  164. package/dist/features/composites/feature.js +8 -2
  165. package/dist/features/composites/feature.js.map +1 -1
  166. package/dist/features/composites/index.d.ts +5 -3
  167. package/dist/features/composites/index.js +8 -6
  168. package/dist/features/composites/inspector-model.d.ts +97 -0
  169. package/dist/features/composites/inspector-model.js +255 -0
  170. package/dist/features/composites/inspector-model.js.map +1 -0
  171. package/dist/features/composites/kinds.d.ts +11 -0
  172. package/dist/features/composites/kinds.js +17 -2
  173. package/dist/features/composites/kinds.js.map +1 -1
  174. package/dist/features/composites/outline.d.ts +18 -5
  175. package/dist/features/composites/outline.js +44 -12
  176. package/dist/features/composites/outline.js.map +1 -1
  177. package/dist/features/composites/react/CompositeDetails.js +1 -1
  178. package/dist/features/composites/react/CompositeInspector.d.ts +1 -1
  179. package/dist/features/composites/react/CompositeInspector.js +21 -180
  180. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  181. package/dist/features/composites/react/CompositeStatusMenu.d.ts +1 -1
  182. package/dist/features/composites/react/CompositeView.js +1 -1
  183. package/dist/features/composites/react/use-composite-inspector.js +29 -0
  184. package/dist/features/composites/react/use-composite-inspector.js.map +1 -0
  185. package/dist/features/composites/schema.d.ts +2 -2
  186. package/dist/features/composites/schema.js +2 -2
  187. package/dist/features/composites/schema.js.map +1 -1
  188. package/dist/features/composites/use-composite-anchors.d.ts +1 -1
  189. package/dist/features/composites/use-composite-inspector.js +41 -0
  190. package/dist/features/composites/use-composite-inspector.js.map +1 -0
  191. package/dist/features/composites/use-composite-rows.d.ts +1 -1
  192. package/dist/features/media/index.d.ts +1 -1
  193. package/dist/features/media/vue.d.ts +1 -1
  194. package/dist/features/mentions/index.d.ts +3 -3
  195. package/dist/features/mentions/index.js +3 -3
  196. package/dist/features/mentions/schema.d.ts +1 -1
  197. package/dist/features/mentions/schema.js +1 -1
  198. package/dist/features/themes/index.d.ts +1 -1
  199. package/dist/features/themes/index.js +1 -1
  200. package/dist/features/transcript/feature.js +1 -1
  201. package/dist/features/transcript/index.js +2 -2
  202. package/dist/i18n/de/ai.js +2 -0
  203. package/dist/i18n/de/ai.js.map +1 -1
  204. package/dist/i18n/de/composites.js +8 -1
  205. package/dist/i18n/de/composites.js.map +1 -1
  206. package/dist/i18n/de/tree.js +14 -1
  207. package/dist/i18n/de/tree.js.map +1 -1
  208. package/dist/i18n/de.d.ts +22 -0
  209. package/dist/i18n/en/ai.js +2 -0
  210. package/dist/i18n/en/ai.js.map +1 -1
  211. package/dist/i18n/en/composites.js +8 -1
  212. package/dist/i18n/en/composites.js.map +1 -1
  213. package/dist/i18n/en/tree.js +14 -1
  214. package/dist/i18n/en/tree.js.map +1 -1
  215. package/dist/integrations/composite-ai/composite-fill.js +2 -2
  216. package/dist/integrations/composite-ai/composite-summary.js +2 -2
  217. package/dist/integrations/composite-ai/index.js +2 -2
  218. package/dist/integrations/transcript-ai/transcript-cleanup.js +1 -1
  219. package/dist/markdown/MarkdownSurface.d.ts +1 -1
  220. package/dist/markdown/MarkdownSurface.js +2 -2
  221. package/dist/markdown/MarkdownSurface.vue.d.ts +9 -9
  222. package/dist/markdown/index.d.ts +2 -2
  223. package/dist/nuxt/runtime/server/routes/collab/[id].js +1 -1
  224. package/dist/react/EditorSurface.d.ts +1 -1
  225. package/dist/react/EditorSurface.js +43 -149
  226. package/dist/react/EditorSurface.js.map +1 -1
  227. package/dist/react/EditorToolbar.js +3 -40
  228. package/dist/react/EditorToolbar.js.map +1 -1
  229. package/dist/schema/advanced.js +2 -2
  230. package/dist/server/adapter.d.ts +2 -2
  231. package/dist/server/collab.js +1 -1
  232. package/dist/server/handlers/ai.d.ts +4 -2
  233. package/dist/server/handlers/ai.js +11 -9
  234. package/dist/server/handlers/ai.js.map +1 -1
  235. package/dist/server/handlers/context.d.ts +1 -1
  236. package/dist/server/handlers/editor.d.ts +1 -1
  237. package/dist/server/handlers/editor.js +2 -2
  238. package/dist/server/host.d.ts +1 -1
  239. package/dist/server/index.d.ts +2 -2
  240. package/dist/settings/index.d.ts +1 -1
  241. package/dist/styles/tokens.css +1 -1
  242. package/dist/tree/DocumentTree.js +159 -387
  243. package/dist/tree/DocumentTree.js.map +1 -1
  244. package/dist/tree/drop-rules.js +37 -0
  245. package/dist/tree/drop-rules.js.map +1 -0
  246. package/dist/tree/react/DocumentTree.d.ts +2 -2
  247. package/dist/tree/react/DocumentTree.js +135 -397
  248. package/dist/tree/react/DocumentTree.js.map +1 -1
  249. package/dist/tree/react/use-tree-model.js +129 -0
  250. package/dist/tree/react/use-tree-model.js.map +1 -0
  251. package/dist/tree/react.js +1 -1
  252. package/dist/tree/tree-host.js +100 -0
  253. package/dist/tree/tree-host.js.map +1 -0
  254. package/dist/tree/tree-items.js +22 -43
  255. package/dist/tree/tree-items.js.map +1 -1
  256. package/dist/tree/tree-model.js +580 -0
  257. package/dist/tree/tree-model.js.map +1 -0
  258. package/dist/tree/tree-rows.js +77 -0
  259. package/dist/tree/tree-rows.js.map +1 -0
  260. package/dist/tree/use-tree-model.js +94 -0
  261. package/dist/tree/use-tree-model.js.map +1 -0
  262. package/dist/tree/vue.js +1 -1
  263. package/dist/vue/AdvancedEditor.vue.d.ts +6 -6
  264. package/dist/vue/SimpleEditor.vue.d.ts +2 -2
  265. package/dist/vue/components/EditorSurface.js +27 -87
  266. package/dist/vue/components/EditorSurface.js.map +1 -1
  267. package/dist/vue/components/EditorSurface.vue.d.ts +6 -6
  268. package/dist/vue/components/EditorToolbar.js +7 -44
  269. package/dist/vue/components/EditorToolbar.js.map +1 -1
  270. package/dist/vue/context.d.ts +1 -1
  271. package/dist/vue/context.js +1 -1
  272. package/dist/vue/context.js.map +1 -1
  273. package/dist/vue/use-editor-ui.d.ts +1 -1
  274. package/dist/vue/use-notifier.d.ts +1 -1
  275. package/docs/integration.md +97 -4
  276. package/docs/llms.md +9 -1
  277. package/docs/usage.md +10 -5
  278. package/package.json +67 -5
@@ -1 +1 @@
1
- {"version":3,"file":"ai-review.js","names":[],"sources":["../../../src/features/ai/ai-review.ts"],"sourcesContent":["import { type Editor, Extension } from '@tiptap/core'\nimport { closeHistory } from '@tiptap/pm/history'\nimport { DOMSerializer, Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport { type EditorState, Plugin, PluginKey, type Transaction } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet, type EditorView } from '@tiptap/pm/view'\nimport { anchorResolverOf, captureRange, type DocAnchor, docAnchorsKey, type DocAnchorsMeta, parseBlocks, resolveRange, structureBlocks } from '../../core'\nimport { BLOCK_ID_ATTR } from '../../core/schema'\nimport { inlineReplacement, replaceRangeWithBlocks } from './ai-apply'\n\n/**\n * A proposed change; `id` is the caller's. 'replace' (default): `markdown` (the model's result) replaces the captured\n * `range`. 'blocks': ready-made `blocks` (a block conversion) replace `range` as one block hunk. 'insert': `markdown`\n * as blocks at `at`, a collapsed range between blocks (e.g. after a block). 'delete': `range` covers exactly one\n * block, which is removed.\n */\nexport type AiReviewChange =\n | { id: string, kind?: 'replace', range: DocAnchor, markdown: string }\n | { id: string, kind: 'blocks', range: DocAnchor, blocks: Fragment }\n | { id: string, kind: 'insert', at: DocAnchor, markdown: string }\n | { id: string, kind: 'delete', range: DocAnchor }\n\n/** Why a change got no review: range gone, result identical, range overlaps a pending review, or empty result. */\nexport type AiReviewSkipReason = 'missing' | 'unchanged' | 'overlap' | 'empty'\n\nexport type AiReviewOutcome = 'accepted' | 'rejected' | 'invalid'\n\n/** One decided hunk; 'invalid': dropped because the original text changed underneath. */\nexport interface AiReviewDecision { reviewId: string, changeId: string, hunkId: string, outcome: AiReviewOutcome }\n\n/** Per change of a finished review: hunk counts, and 'partial' when its hunks were decided differently. */\nexport interface AiReviewChangeSummary { id: string, outcome: AiReviewOutcome | 'partial', accepted: number, rejected: number, invalid: number }\n\nexport interface AiReviewOptions {\n /** Decisions as they happen, batched per transaction. */\n onDecision?: (decisions: AiReviewDecision[]) => void\n /** Once every hunk of the review is decided. */\n onDone?: (summary: AiReviewChangeSummary[]) => void\n}\n\n/** `hunks === 0`: no review started (every change skipped). */\nexport interface AiReviewHandle {\n id: string\n hunks: number\n skipped: { id: string, reason: AiReviewSkipReason }[]\n /** Rejects the review's pending hunks. */\n cancel: () => void\n}\n\n/**\n * One reviewable difference: [from, to] of the document replaced by `insert` on accept.\n * 'inline': a word-level change inside one textblock (`original` = its inline content);\n * 'block': the whole range replaced by blocks, since the result's structure differs (`original` = its text);\n * 'insert': blocks inserted at the collapsed position `from === to` between blocks;\n * 'delete': the one block [from, to] removed (`original` = that block, `insert` empty).\n */\nexport type AiReviewHunk = {\n id: string\n reviewId: string\n changeId: string\n from: number\n to: number\n insert: Fragment\n /**\n * Edit-surviving [from, to] (DocAnchors), released when the hunk is decided. Bound to the range's own first and\n * last characters, so text inserted at a boundary (here or remotely) stays outside.\n */\n anchor: DocAnchor\n} & ({ kind: 'inline', original: Fragment } | { kind: 'block', original: string } | { kind: 'insert' } | { kind: 'delete', original: PMNode })\n\nexport interface AiReviewState {\n /** Pending hunks, in document order. */\n hunks: readonly AiReviewHunk[]\n /** The clicked hunk, whose accept/reject controls are shown. */\n active: string | null\n /** The latest decisions (oldest first); `logEnd` counts all decisions ever made. */\n log: readonly AiReviewDecision[]\n logEnd: number\n decorations: DecorationSet\n}\n\ntype ReviewMeta =\n | { type: 'add', hunks: AiReviewHunk[] }\n | { type: 'decide', ids: string[], outcome: 'accepted' | 'rejected' }\n | { type: 'activate', id: string | null }\n\ninterface ReviewEntry {\n options: AiReviewOptions\n total: number\n decided: number\n tallies: Map<string, Record<AiReviewOutcome, number>>\n}\n\nexport const aiReviewKey = new PluginKey<AiReviewState>('aiReview')\n\nconst LOG_LIMIT = 500\n/** LCS table cells per textblock diff; beyond, the differing middle becomes one hunk. */\nconst MAX_DIFF_CELLS = 4_000_000\n/** Words, whitespace runs, single other characters (punctuation). */\nconst TOKEN = /\\s+|[\\p{L}\\p{N}_]+|[^\\s\\p{L}\\p{N}_]/gu\n\n/** Callbacks of running reviews, per editor view. */\nconst reviews = new WeakMap<EditorView, Map<string, ReviewEntry>>()\nlet reviewCount = 0\n\n/**\n * In-document review of AI rewrites: the difference between a range and its proposed replacement shows as local\n * decorations only (red strike = deletion, green widget = insertion), so collaborators never see unaccepted text.\n * Accepting writes the accepted hunks in one transaction (one undo step); rejecting only drops decorations.\n * Client-only, not part of `schemaExtensions()`. Driven by `startAiReview`, `acceptAiReview`, `rejectAiReview`;\n * AiReviewBar shows the controls.\n */\nexport const AiReview = Extension.create({\n name: 'aiReview',\n\n addProseMirrorPlugins() {\n return [\n new Plugin<AiReviewState>({\n key: aiReviewKey,\n state: {\n init: () => ({ hunks: [], active: null, log: [], logEnd: 0, decorations: DecorationSet.empty }),\n apply: applyReview,\n },\n props: {\n decorations: state => aiReviewKey.getState(state)?.decorations,\n handleDOMEvents: {\n // A click on a change shows its controls; a click elsewhere hides them.\n mousedown(view, event) {\n const review = aiReviewKey.getState(view.state)\n if (!review?.hunks.length) return false\n const target = event.target instanceof Element ? event.target : (event.target as Node | null)?.parentElement\n const id = target?.closest('[data-ai-hunk]')?.getAttribute('data-ai-hunk') ?? null\n if (id !== review.active) setActiveAiReviewHunk(view, id)\n return false\n },\n },\n },\n view(view) {\n let seen = aiReviewKey.getState(view.state)!.logEnd\n return {\n update(_view, prevState) {\n const review = aiReviewKey.getState(view.state)!\n if (review.logEnd !== seen) {\n const count = review.logEnd - seen\n seen = review.logEnd\n // Hunks dropped as invalid keep their anchors (decided ones release them in their transaction).\n const anchors = docAnchorsKey.getState(view.state)\n const kept = new Set(review.hunks.map(h => h.anchor.id))\n const stale = aiReviewKey.getState(prevState)!.hunks\n .filter(h => !kept.has(h.anchor.id) && anchors?.has(h.anchor.id))\n .map(h => h.anchor.id)\n // Callbacks may dispatch: not during this update.\n queueMicrotask(() => {\n if (stale.length && !view.isDestroyed) {\n view.dispatch(view.state.tr.setMeta(docAnchorsKey, { remove: stale } satisfies DocAnchorsMeta).setMeta('addToHistory', false))\n }\n report(view, review.log.slice(-Math.min(count, review.log.length)))\n })\n }\n },\n destroy() {\n reviews.delete(view)\n },\n }\n },\n }),\n ]\n },\n})\n\n/**\n * Opens a review of `changes` (independent, non-overlapping ranges; several reviews may be pending at once). A\n * replacement becomes word-level hunks per textblock when the result has the range's block structure, otherwise one\n * block-level hunk; an insertion or deletion is one hunk. Changes that cannot be reviewed are returned as `skipped`.\n */\nexport function startAiReview(editor: Editor, changes: readonly AiReviewChange[], options: AiReviewOptions = {}): AiReviewHandle {\n const { state, view } = editor\n const pending = aiReviewKey.getState(state)\n if (!pending) throw new Error('startAiReview needs the AiReview extension')\n const reviewId = `ai-review-${++reviewCount}`\n const hunks: AiReviewHunk[] = []\n const skipped: AiReviewHandle['skipped'] = []\n // Insertion points only collide with a range strictly around them, so a block can be deleted or rewritten and\n // content inserted after it, and several insertions can stack at one position; ranges collide when they touch.\n const taken: { from: number, to: number, point: boolean }[] = pending.hunks.map(({ from, to, kind }) => ({ from, to, point: kind === 'insert' }))\n const collides = (range: { from: number, to: number, point: boolean }) => taken.some((t) => {\n if (t.point && range.point) return false\n if (t.point) return range.from < t.from && t.from < range.to\n if (range.point) return t.from < range.from && range.from < t.to\n return t.from <= range.to && range.from <= t.to\n })\n const tallies: ReviewEntry['tallies'] = new Map()\n\n for (const change of changes) {\n const point = change.kind === 'insert'\n const resolved = resolveRange(state, change.kind === 'insert' ? change.at : change.range)\n if (!resolved || (point ? resolved.from !== resolved.to : resolved.from >= resolved.to)) {\n skipped.push({ id: change.id, reason: 'missing' })\n continue\n }\n const range = { ...resolved, point }\n if (collides(range)) {\n skipped.push({ id: change.id, reason: 'overlap' })\n continue\n }\n const planned: PlannedHunk[] | AiReviewSkipReason = change.kind === 'insert'\n ? planInsert(editor, range.from, change.markdown)\n : change.kind === 'delete'\n ? planDelete(state.doc, range.from, range.to)\n : change.kind === 'blocks'\n ? [{ kind: 'block', from: range.from, to: range.to, insert: change.blocks }]\n : planChange(editor, range.from, range.to, change.markdown)\n if (typeof planned === 'string') {\n skipped.push({ id: change.id, reason: planned })\n continue\n }\n taken.push(range)\n tallies.set(change.id, { accepted: 0, rejected: 0, invalid: 0 })\n for (const { kind, from, to, insert } of planned) {\n const base = { id: `${reviewId}-${hunks.length}`, reviewId, changeId: change.id, from, to, insert, anchor: captureRange(editor, { from, to }, { startInside: from !== to }) }\n if (kind === 'block') {\n hunks.push({ ...base, kind, original: state.doc.textBetween(from, to, '\\n', '\\uFFFC') })\n continue\n }\n if (kind === 'insert') {\n hunks.push({ ...base, kind })\n continue\n }\n if (kind === 'delete') {\n hunks.push({ ...base, kind, original: state.doc.nodeAt(from)! })\n continue\n }\n const $from = state.doc.resolve(from)\n hunks.push({ ...base, kind, original: $from.parent.content.cut($from.parentOffset, $from.parentOffset + to - from) })\n }\n }\n\n const handle: AiReviewHandle = {\n id: reviewId,\n hunks: hunks.length,\n skipped,\n cancel: () => {\n const open = aiReviewKey.getState(editor.state)?.hunks.filter(h => h.reviewId === reviewId).map(h => h.id)\n if (open?.length) rejectAiReview(editor, open)\n },\n }\n if (!hunks.length) return handle\n let entries = reviews.get(view)\n if (!entries) reviews.set(view, entries = new Map())\n entries.set(reviewId, { options, total: hunks.length, decided: 0, tallies })\n dispatchMeta(view, { type: 'add', hunks })\n return handle\n}\n\n/**\n * Writes the pending hunks `ids` (all when omitted) in one transaction — one undo step of its own: y-undo (collaborative)\n * or prosemirror-history (standalone) would merge it with typing around it within their grouping delay, so the event is\n * closed before and after.\n */\nexport function acceptAiReview(editor: Editor, ids?: readonly string[]): void {\n const chosen = aiReviewKey.getState(editor.state)?.hunks.filter(h => !ids || ids.includes(h.id)) ?? []\n if (!chosen.length) return\n const tr = editor.state.tr\n // Back to front: earlier positions stay valid. At one position the range starting there goes first, then the\n // insertions in reverse (pending hunks are in document order, ties in the order they were proposed), so each lands\n // before the ones after it.\n for (const hunk of [...chosen].reverse().sort((a, b) => b.from - a.from || b.to - a.to)) {\n if (hunk.kind === 'block') replaceRangeWithBlocks(tr, hunk.from, hunk.to, hunk.insert)\n else tr.replaceWith(hunk.from, hunk.to, hunk.insert)\n }\n tr.setMeta(aiReviewKey, { type: 'decide', ids: chosen.map(h => h.id), outcome: 'accepted' } satisfies ReviewMeta)\n tr.setMeta(docAnchorsKey, { remove: chosen.map(h => h.anchor.id) } satisfies DocAnchorsMeta)\n // The collaboration feature's anchor resolver stops its Yjs undo capturing; without one (or without an undo manager)\n // prosemirror-history is the history and gets the closing transactions.\n const resolver = anchorResolverOf(editor)\n const collaborative = resolver?.stopUndoCapture(editor.state) ?? false\n editor.view.dispatch(closeHistory(tr))\n resolver?.stopUndoCapture(editor.state)\n // prosemirror-history: an empty transaction that closes the event, so typing right after starts a new one.\n if (!collaborative) editor.view.dispatch(closeHistory(editor.state.tr))\n}\n\n/** Drops the pending hunks `ids` (all when omitted); the document and undo history stay untouched. */\nexport function rejectAiReview(editor: Editor, ids?: readonly string[]): void {\n const chosen = aiReviewKey.getState(editor.state)?.hunks.filter(h => !ids || ids.includes(h.id)) ?? []\n if (!chosen.length) return\n const meta: ReviewMeta = { type: 'decide', ids: chosen.map(h => h.id), outcome: 'rejected' }\n editor.view.dispatch(editor.state.tr\n .setMeta(aiReviewKey, meta)\n .setMeta(docAnchorsKey, { remove: chosen.map(h => h.anchor.id) } satisfies DocAnchorsMeta)\n .setMeta('addToHistory', false))\n}\n\n/** Shows the controls of hunk `id` (null hides them). */\nexport function setActiveAiReviewHunk(view: EditorView, id: string | null): void {\n dispatchMeta(view, { type: 'activate', id })\n}\n\nfunction dispatchMeta(view: EditorView, meta: ReviewMeta): void {\n view.dispatch(view.state.tr.setMeta(aiReviewKey, meta).setMeta('addToHistory', false))\n}\n\nfunction applyReview(tr: Transaction, value: AiReviewState, _oldState: EditorState, newState: EditorState): AiReviewState {\n const meta = tr.getMeta(aiReviewKey) as ReviewMeta | undefined\n if (!meta && (!tr.docChanged || !value.hunks.length)) return value\n\n let hunks = value.hunks\n // DocAnchors (higher priority, so already applied in `newState`) maps local changes and re-resolves remote ones.\n if (tr.docChanged) hunks = hunks.map(hunk => ({ ...hunk, ...(resolveRange(newState, hunk.anchor) ?? { from: -1, to: -1 }) }))\n\n const decided: AiReviewDecision[] = []\n const decide = (hunk: AiReviewHunk, outcome: AiReviewOutcome) => {\n decided.push({ reviewId: hunk.reviewId, changeId: hunk.changeId, hunkId: hunk.id, outcome })\n }\n if (meta?.type === 'add') hunks = [...hunks, ...meta.hunks].sort((a, b) => a.from - b.from || a.to - b.to)\n if (meta?.type === 'decide') {\n const ids = new Set(meta.ids)\n hunks = hunks.filter((hunk) => {\n if (!ids.has(hunk.id)) return true\n decide(hunk, meta.outcome)\n return false\n })\n }\n if (tr.docChanged) {\n hunks = hunks.filter((hunk) => {\n if (isIntact(newState.doc, hunk)) return true\n decide(hunk, 'invalid')\n return false\n })\n }\n\n let active = meta?.type === 'activate' ? meta.id : value.active\n if (active && !hunks.some(h => h.id === active)) active = null\n return {\n hunks,\n active,\n log: decided.length ? [...value.log, ...decided].slice(-LOG_LIMIT) : value.log,\n logEnd: value.logEnd + decided.length,\n decorations: renderDecorations(newState, hunks, active),\n }\n}\n\n/** Whether the document still holds the hunk's original content at its positions. */\nfunction isIntact(doc: PMNode, hunk: AiReviewHunk): boolean {\n if (hunk.from < 0 || hunk.from > hunk.to || hunk.to > doc.content.size) return false\n if (hunk.kind === 'block') return hunk.from < hunk.to && doc.textBetween(hunk.from, hunk.to, '\\n', '\\uFFFC') === hunk.original\n if (hunk.kind === 'delete') return hunk.to - hunk.from === hunk.original.nodeSize && !!doc.nodeAt(hunk.from)?.eq(hunk.original)\n if (hunk.kind === 'insert') {\n const $at = doc.resolve(hunk.from)\n return hunk.from === hunk.to && !$at.parent.inlineContent && $at.parent.canReplace($at.index(), $at.index(), hunk.insert)\n }\n const $from = doc.resolve(hunk.from)\n const $to = doc.resolve(hunk.to)\n return $from.sameParent($to) && $from.parent.inlineContent\n && $from.parent.content.cut($from.parentOffset, $to.parentOffset).eq(hunk.original)\n}\n\nfunction renderDecorations(state: EditorState, hunks: readonly AiReviewHunk[], active: string | null): DecorationSet {\n if (!hunks.length) return DecorationSet.empty\n const serializer = DOMSerializer.fromSchema(state.schema)\n const decorations: Decoration[] = []\n for (const hunk of hunks) {\n const activeClass = hunk.id === active ? ' is-active' : ''\n if (hunk.kind === 'delete') {\n decorations.push(Decoration.node(hunk.from, hunk.to, { 'class': `ai-review-del-block${activeClass}`, 'data-ai-hunk': hunk.id }))\n continue\n }\n if (hunk.from < hunk.to) {\n decorations.push(Decoration.inline(hunk.from, hunk.to, { 'class': `ai-review-del${activeClass}`, 'data-ai-hunk': hunk.id }))\n }\n if (!hunk.insert.size) continue\n // Replacing blocks go below the top-level block the range ends in; inserted blocks at their position; inline\n // insertions right after the deleted text.\n const $to = state.doc.resolve(hunk.to)\n const block = hunk.kind === 'block' || hunk.kind === 'insert'\n const pos = hunk.kind === 'block' && $to.depth > 0 ? $to.after(1) : hunk.to\n decorations.push(Decoration.widget(pos, () => {\n const dom = document.createElement(block ? 'div' : 'span')\n dom.className = `${block ? 'ai-review-ins-block' : 'ai-review-ins'}${activeClass}`\n dom.setAttribute('data-ai-hunk', hunk.id)\n dom.contentEditable = 'false'\n dom.append(serializer.serializeFragment(hunk.insert))\n return dom\n }, { key: `${hunk.id}${activeClass}`, side: -1, ignoreSelection: true }))\n }\n return DecorationSet.create(state.doc, decorations)\n}\n\n/** Reports decisions to their reviews' callbacks; a review whose hunks are all decided ends. */\nfunction report(view: EditorView, decisions: readonly AiReviewDecision[]): void {\n const entries = reviews.get(view)\n if (!entries) return\n const byReview = new Map<string, AiReviewDecision[]>()\n for (const decision of decisions) byReview.set(decision.reviewId, [...byReview.get(decision.reviewId) ?? [], decision])\n for (const [reviewId, batch] of byReview) {\n const entry = entries.get(reviewId)\n if (!entry) continue\n for (const decision of batch) entry.tallies.get(decision.changeId)![decision.outcome]++\n entry.decided += batch.length\n entry.options.onDecision?.(batch)\n if (entry.decided < entry.total) continue\n entries.delete(reviewId)\n entry.options.onDone?.([...entry.tallies].map(([id, tally]) => {\n const kinds = (Object.keys(tally) as AiReviewOutcome[]).filter(outcome => tally[outcome] > 0)\n return { id, outcome: kinds.length === 1 ? kinds[0]! : 'partial', ...tally }\n }))\n }\n}\n\ntype PlannedHunk = Pick<AiReviewHunk, 'kind' | 'from' | 'to' | 'insert'>\n\n/** The hunks turning [from, to] into the parsed `markdown`. */\nfunction planChange(editor: Editor, from: number, to: number, markdown: string): PlannedHunk[] | AiReviewSkipReason {\n const { doc, schema } = editor.state\n const result = parseBlocks(editor, markdown)\n if (!result.blocks.length) return 'empty'\n const $from = doc.resolve(from)\n const $to = doc.resolve(to)\n const blocks = Fragment.fromArray(result.blocks.map(block => schema.nodeFromJSON(block)))\n\n const inline = inlineReplacement($from, $to, result)\n const inlineContent = inline && Fragment.fromArray(inline.map(node => schema.nodeFromJSON(node)))\n const planned = inlineContent && $from.parent.type.validContent(inlineContent)\n ? diffInline($from.parent.content.cut($from.parentOffset, $to.parentOffset), inlineContent, from)\n : inline ? null : diffTextblocks(doc, from, to, blocks)\n if (planned) return planned.length ? planned : 'unchanged'\n return [{ kind: 'block', from, to, insert: blocks }]\n}\n\n/** The hunk inserting `markdown` as blocks in the preferred structure (`structureBlocks` of the parsed result) at `pos` (between blocks). */\nfunction planInsert(editor: Editor, pos: number, markdown: string): PlannedHunk[] | AiReviewSkipReason {\n const { doc, schema } = editor.state\n const blocks = structureBlocks(editor, parseBlocks(editor, markdown).blocks)\n if (!blocks.length) return 'empty'\n const $pos = doc.resolve(pos)\n if ($pos.parent.inlineContent) return 'missing'\n let insert = Fragment.fromArray(blocks.map(block => schema.nodeFromJSON(block)))\n const fits = (content: Fragment) => $pos.parent.canReplace($pos.index(), $pos.index(), content)\n // A list (or quote) inserted into a list (quote) of the same type contributes its items.\n if (!fits(insert) && insert.childCount === 1 && insert.firstChild!.type === $pos.parent.type) insert = insert.firstChild!.content\n return fits(insert) ? [{ kind: 'insert', from: pos, to: pos, insert }] : 'missing'\n}\n\n/** The hunk deleting [from, to], which must be exactly one node. */\nfunction planDelete(doc: PMNode, from: number, to: number): PlannedHunk[] | AiReviewSkipReason {\n const node = doc.nodeAt(from)\n return node && from + node.nodeSize === to ? [{ kind: 'delete', from, to, insert: Fragment.empty }] : 'missing'\n}\n\n/** Word diffs per textblock when the result has the range's textblocks (types, attributes, nesting); else null. */\nfunction diffTextblocks(doc: PMNode, from: number, to: number, blocks: Fragment): PlannedHunk[] | null {\n const originals: { path: string, node: PMNode }[] = []\n const results: { path: string, node: PMNode }[] = []\n if (!flattenTextblocks(doc.cut(from, to), '', originals) || !flattenTextblocks(doc.type.create(null, blocks), '', results)) return null\n if (originals.length !== results.length || originals.some((original, i) => original.path !== results[i]!.path)) return null\n\n const ranges: { from: number, to: number }[] = []\n doc.nodesBetween(from, to, (node, pos) => {\n if (!node.isTextblock) return true\n ranges.push({ from: Math.max(from, pos + 1), to: Math.min(to, pos + node.nodeSize - 1) })\n return false\n })\n if (ranges.length !== results.length) return null\n return ranges.flatMap((range, i) => {\n const $from = doc.resolve(range.from)\n const original = $from.parent.content.cut($from.parentOffset, $from.parentOffset + range.to - range.from)\n return diffInline(original, results[i]!.node.content, range.from)\n })\n}\n\n/** Collects `node`'s textblocks with their ancestry (types and attributes but block IDs); false for other leaf blocks (images, rules). */\nfunction flattenTextblocks(node: PMNode, path: string, out: { path: string, node: PMNode }[]): boolean {\n let ok = true\n node.forEach((child) => {\n if (!ok) return\n const attrs = Object.entries(child.attrs).filter(([name]) => name !== BLOCK_ID_ATTR)\n const childPath = `${path}/${child.type.name}${JSON.stringify(attrs)}`\n if (child.isTextblock) out.push({ path: childPath, node: child })\n else if (child.isLeaf) ok = false\n else ok = flattenTextblocks(child, childPath, out)\n })\n return ok\n}\n\ninterface Token { key: string, node: PMNode, whitespace: boolean }\n\n/** Words, whitespace and punctuation with their marks; inline nodes (chips, breaks) are one token each. */\nfunction tokenize(content: Fragment): Token[] {\n const tokens: Token[] = []\n content.forEach((node) => {\n if (!node.isText) {\n tokens.push({ key: JSON.stringify(node.toJSON()), node, whitespace: false })\n return\n }\n const marks = JSON.stringify(node.marks.map(mark => mark.toJSON()))\n for (const match of node.text!.matchAll(TOKEN)) {\n tokens.push({ key: marks + match[0], node: node.cut(match.index, match.index + match[0].length), whitespace: !match[0].trim() })\n }\n })\n return tokens\n}\n\n/** Word-level hunks turning `original` (inline content starting at document position `base`) into `result`. */\nfunction diffInline(original: Fragment, result: Fragment, base: number): PlannedHunk[] {\n const a = tokenize(original)\n const b = tokenize(result)\n const offsets = [base]\n for (const token of a) offsets.push(offsets.at(-1)! + token.node.nodeSize)\n return diffTokens(a, b).map(span => ({\n kind: 'inline',\n from: offsets[span.aFrom]!,\n to: offsets[span.aTo]!,\n insert: Fragment.fromArray(b.slice(span.bFrom, span.bTo).map(token => token.node)),\n }))\n}\n\ninterface Span { aFrom: number, aTo: number, bFrom: number, bTo: number }\n\n/** Differing spans of two token lists (LCS); spans only whitespace apart merge, so a rewritten phrase is one hunk. */\nfunction diffTokens(a: Token[], b: Token[]): Span[] {\n let start = 0\n while (start < a.length && start < b.length && a[start]!.key === b[start]!.key) start++\n let endA = a.length\n let endB = b.length\n while (endA > start && endB > start && a[endA - 1]!.key === b[endB - 1]!.key) {\n endA--\n endB--\n }\n const n = endA - start\n const m = endB - start\n if (!n && !m) return []\n if (!n || !m || n * m > MAX_DIFF_CELLS) return [{ aFrom: start, aTo: endA, bFrom: start, bTo: endB }]\n\n // lcs[i * w + j]: LCS length of a[start + i..] and b[start + j..].\n const w = m + 1\n const lcs = new Uint32Array((n + 1) * w)\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n lcs[i * w + j] = a[start + i]!.key === b[start + j]!.key\n ? lcs[(i + 1) * w + j + 1]! + 1\n : Math.max(lcs[(i + 1) * w + j]!, lcs[i * w + j + 1]!)\n }\n }\n\n const spans: Span[] = []\n let open: Span | null = null\n let i = 0\n let j = 0\n while (i < n || j < m) {\n if (i < n && j < m && a[start + i]!.key === b[start + j]!.key) {\n if (open) spans.push(open)\n open = null\n i++\n j++\n continue\n }\n open ??= { aFrom: start + i, aTo: start + i, bFrom: start + j, bTo: start + j }\n if (j < m && (i === n || lcs[i * w + j + 1]! >= lcs[(i + 1) * w + j]!)) open.bTo = start + ++j\n else open.aTo = start + ++i\n }\n if (open) spans.push(open)\n\n const merged: Span[] = []\n for (const span of spans) {\n const previous = merged.at(-1)\n if (previous && a.slice(previous.aTo, span.aFrom).every(token => token.whitespace)) {\n previous.aTo = span.aTo\n previous.bTo = span.bTo\n }\n else merged.push({ ...span })\n }\n return merged\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ai-review.js","names":[],"sources":["../../../src/features/ai/ai-review.ts"],"sourcesContent":["import { type Editor, Extension } from '@tiptap/core'\nimport { closeHistory } from '@tiptap/pm/history'\nimport { DOMSerializer, Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport { type EditorState, Plugin, PluginKey, type Transaction } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet, type EditorView } from '@tiptap/pm/view'\nimport { anchorResolverOf, captureRange, type DocAnchor, docAnchorsKey, type DocAnchorsMeta, parseBlocks, resolveRange, structureBlocks } from '../../core'\nimport { BLOCK_ID_ATTR } from '../../core/schema'\nimport { inlineReplacement, replaceRangeWithBlocks } from './ai-apply'\n\n/**\n * A proposed change; `id` is the caller's. 'replace' (default): `markdown` (the model's result) replaces the captured\n * `range`. 'blocks': ready-made `blocks` (a block conversion) replace `range` as one block hunk. 'insert': `markdown`\n * as blocks at `at`, a collapsed range between blocks (e.g. after a block). 'delete': `range` covers exactly one\n * block, which is removed.\n */\nexport type AiReviewChange =\n | { id: string, kind?: 'replace', range: DocAnchor, markdown: string }\n | { id: string, kind: 'blocks', range: DocAnchor, blocks: Fragment }\n | { id: string, kind: 'insert', at: DocAnchor, markdown: string }\n | { id: string, kind: 'delete', range: DocAnchor }\n\n/** Why a change got no review: range gone, result identical, range overlaps a pending review, or empty result. */\nexport type AiReviewSkipReason = 'missing' | 'unchanged' | 'overlap' | 'empty'\n\nexport type AiReviewOutcome = 'accepted' | 'rejected' | 'invalid'\n\n/** One decided hunk; 'invalid': dropped because the original text changed underneath. */\nexport interface AiReviewDecision { reviewId: string, changeId: string, hunkId: string, outcome: AiReviewOutcome }\n\n/** Per change of a finished review: hunk counts, and 'partial' when its hunks were decided differently. */\nexport interface AiReviewChangeSummary { id: string, outcome: AiReviewOutcome | 'partial', accepted: number, rejected: number, invalid: number }\n\nexport interface AiReviewOptions {\n /** Decisions as they happen, batched per transaction. */\n onDecision?: (decisions: AiReviewDecision[]) => void\n /** Once every hunk of the review is decided. */\n onDone?: (summary: AiReviewChangeSummary[]) => void\n}\n\n/** `hunks === 0`: no review started (every change skipped). */\nexport interface AiReviewHandle {\n id: string\n hunks: number\n skipped: { id: string, reason: AiReviewSkipReason }[]\n /** Rejects the review's pending hunks. */\n cancel: () => void\n}\n\n/**\n * One reviewable difference: [from, to] of the document replaced by `insert` on accept.\n * 'inline': a word-level change inside one textblock (`original` = its inline content);\n * 'block': the whole range replaced by blocks, since the result's structure differs (`original` = its text);\n * 'insert': blocks inserted at the collapsed position `from === to` between blocks;\n * 'delete': the one block [from, to] removed (`original` = that block, `insert` empty).\n */\nexport type AiReviewHunk = {\n id: string\n reviewId: string\n changeId: string\n from: number\n to: number\n insert: Fragment\n /**\n * Edit-surviving [from, to] (DocAnchors), released when the hunk is decided. Bound to the range's own first and\n * last characters, so text inserted at a boundary (here or remotely) stays outside.\n */\n anchor: DocAnchor\n} & ({ kind: 'inline', original: Fragment } | { kind: 'block', original: string } | { kind: 'insert' } | { kind: 'delete', original: PMNode })\n\nexport interface AiReviewState {\n /** Pending hunks, in document order. */\n hunks: readonly AiReviewHunk[]\n /** The clicked hunk, whose accept/reject controls are shown. */\n active: string | null\n /** The latest decisions (oldest first); `logEnd` counts all decisions ever made. */\n log: readonly AiReviewDecision[]\n logEnd: number\n decorations: DecorationSet\n}\n\ntype ReviewMeta =\n | { type: 'add', hunks: AiReviewHunk[] }\n | { type: 'decide', ids: string[], outcome: 'accepted' | 'rejected' }\n | { type: 'activate', id: string | null }\n\ninterface ReviewEntry {\n options: AiReviewOptions\n total: number\n decided: number\n tallies: Map<string, Record<AiReviewOutcome, number>>\n}\n\nexport const aiReviewKey = new PluginKey<AiReviewState>('aiReview')\n\nconst LOG_LIMIT = 500\n/** LCS table cells per textblock diff; beyond, the differing middle becomes one hunk. */\nconst MAX_DIFF_CELLS = 4_000_000\n/** Words, whitespace runs, single other characters (punctuation). */\nconst TOKEN = /\\s+|[\\p{L}\\p{N}_]+|[^\\s\\p{L}\\p{N}_]/gu\n\n/** Callbacks of running reviews, per editor view. */\nconst reviews = new WeakMap<EditorView, Map<string, ReviewEntry>>()\nlet reviewCount = 0\n\n/**\n * In-document review of AI rewrites: the difference between a range and its proposed replacement shows as local\n * decorations only (red strike = deletion, green widget = insertion), so collaborators never see unaccepted text.\n * Accepting writes the accepted hunks in one transaction (one undo step); rejecting only drops decorations.\n * Client-only, not part of `schemaExtensions()`. Driven by `startAiReview`, `acceptAiReview`, `rejectAiReview`;\n * AiReviewBar shows the controls.\n */\nexport const AiReview = Extension.create({\n name: 'aiReview',\n\n addProseMirrorPlugins() {\n return [\n new Plugin<AiReviewState>({\n key: aiReviewKey,\n state: {\n init: () => ({ hunks: [], active: null, log: [], logEnd: 0, decorations: DecorationSet.empty }),\n apply: applyReview,\n },\n props: {\n decorations: state => aiReviewKey.getState(state)?.decorations,\n handleDOMEvents: {\n // A click on a change shows its controls; a click elsewhere hides them.\n mousedown(view, event) {\n const review = aiReviewKey.getState(view.state)\n if (!review?.hunks.length) return false\n const target = event.target instanceof Element ? event.target : (event.target as Node | null)?.parentElement\n const id = target?.closest('[data-ai-hunk]')?.getAttribute('data-ai-hunk') ?? null\n if (id !== review.active) setActiveAiReviewHunk(view, id)\n return false\n },\n },\n },\n view(view) {\n let seen = aiReviewKey.getState(view.state)!.logEnd\n return {\n update(_view, prevState) {\n const review = aiReviewKey.getState(view.state)!\n if (review.logEnd !== seen) {\n const count = review.logEnd - seen\n seen = review.logEnd\n // Hunks dropped as invalid keep their anchors (decided ones release them in their transaction).\n const anchors = docAnchorsKey.getState(view.state)\n const kept = new Set(review.hunks.map(h => h.anchor.id))\n const stale = aiReviewKey.getState(prevState)!.hunks\n .filter(h => !kept.has(h.anchor.id) && anchors?.has(h.anchor.id))\n .map(h => h.anchor.id)\n // Callbacks may dispatch: not during this update.\n queueMicrotask(() => {\n if (stale.length && !view.isDestroyed) {\n view.dispatch(view.state.tr.setMeta(docAnchorsKey, { remove: stale } satisfies DocAnchorsMeta).setMeta('addToHistory', false))\n }\n report(view, review.log.slice(-Math.min(count, review.log.length)))\n })\n }\n },\n destroy() {\n reviews.delete(view)\n },\n }\n },\n }),\n ]\n },\n})\n\n/**\n * Opens a review of `changes` (independent, non-overlapping ranges; several reviews may be pending at once). A\n * replacement becomes word-level hunks per textblock when the result has the range's block structure, otherwise one\n * block-level hunk; an insertion or deletion is one hunk. Changes that cannot be reviewed are returned as `skipped`.\n */\nexport function startAiReview(editor: Editor, changes: readonly AiReviewChange[], options: AiReviewOptions = {}): AiReviewHandle {\n const { state, view } = editor\n const pending = aiReviewKey.getState(state)\n if (!pending) throw new Error('startAiReview needs the AiReview extension')\n const reviewId = `ai-review-${++reviewCount}`\n const hunks: AiReviewHunk[] = []\n const skipped: AiReviewHandle['skipped'] = []\n // Insertion points only collide with a range strictly around them, so a block can be deleted or rewritten and\n // content inserted after it, and several insertions can stack at one position; ranges collide when they touch.\n const taken: { from: number, to: number, point: boolean }[] = pending.hunks.map(({ from, to, kind }) => ({ from, to, point: kind === 'insert' }))\n const collides = (range: { from: number, to: number, point: boolean }) => taken.some((t) => {\n if (t.point && range.point) return false\n if (t.point) return range.from < t.from && t.from < range.to\n if (range.point) return t.from < range.from && range.from < t.to\n return t.from <= range.to && range.from <= t.to\n })\n const tallies: ReviewEntry['tallies'] = new Map()\n\n for (const change of changes) {\n const point = change.kind === 'insert'\n const resolved = resolveRange(state, change.kind === 'insert' ? change.at : change.range)\n if (!resolved || (point ? resolved.from !== resolved.to : resolved.from >= resolved.to)) {\n skipped.push({ id: change.id, reason: 'missing' })\n continue\n }\n const range = { ...resolved, point }\n if (collides(range)) {\n skipped.push({ id: change.id, reason: 'overlap' })\n continue\n }\n const planned: PlannedHunk[] | AiReviewSkipReason = change.kind === 'insert'\n ? planInsert(editor, range.from, change.markdown)\n : change.kind === 'delete'\n ? planDelete(state.doc, range.from, range.to)\n : change.kind === 'blocks'\n ? [{ kind: 'block', from: range.from, to: range.to, insert: change.blocks }]\n : planChange(editor, range.from, range.to, change.markdown)\n if (typeof planned === 'string') {\n skipped.push({ id: change.id, reason: planned })\n continue\n }\n taken.push(range)\n tallies.set(change.id, { accepted: 0, rejected: 0, invalid: 0 })\n for (const { kind, from, to, insert } of planned) {\n const base = { id: `${reviewId}-${hunks.length}`, reviewId, changeId: change.id, from, to, insert, anchor: captureRange(editor, { from, to }, { startInside: from !== to }) }\n if (kind === 'block') {\n hunks.push({ ...base, kind, original: state.doc.textBetween(from, to, '\\n', '\\uFFFC') })\n continue\n }\n if (kind === 'insert') {\n hunks.push({ ...base, kind })\n continue\n }\n if (kind === 'delete') {\n hunks.push({ ...base, kind, original: state.doc.nodeAt(from)! })\n continue\n }\n const $from = state.doc.resolve(from)\n hunks.push({ ...base, kind, original: $from.parent.content.cut($from.parentOffset, $from.parentOffset + to - from) })\n }\n }\n\n const handle: AiReviewHandle = {\n id: reviewId,\n hunks: hunks.length,\n skipped,\n cancel: () => {\n const open = aiReviewKey.getState(editor.state)?.hunks.filter(h => h.reviewId === reviewId).map(h => h.id)\n if (open?.length) rejectAiReview(editor, open)\n },\n }\n if (!hunks.length) return handle\n let entries = reviews.get(view)\n if (!entries) reviews.set(view, entries = new Map())\n entries.set(reviewId, { options, total: hunks.length, decided: 0, tallies })\n dispatchMeta(view, { type: 'add', hunks })\n return handle\n}\n\n/**\n * Writes the pending hunks `ids` (all when omitted) in one transaction — one undo step of its own: y-undo (collaborative)\n * or prosemirror-history (standalone) would merge it with typing around it within their grouping delay, so the event is\n * closed before and after.\n */\nexport function acceptAiReview(editor: Editor, ids?: readonly string[]): void {\n const chosen = aiReviewKey.getState(editor.state)?.hunks.filter(h => !ids || ids.includes(h.id)) ?? []\n if (!chosen.length) return\n const tr = editor.state.tr\n // Insertions at one position that stay pending go behind the ones written now: their anchors move past that text,\n // so accepting the earlier of two insertions after the same block does not put the later one in front of it.\n const pending = aiReviewKey.getState(editor.state)?.hunks ?? []\n const after = pending.filter((hunk) => {\n if (hunk.kind !== 'insert' || chosen.includes(hunk)) return false\n const written = chosen.filter(h => h.kind === 'insert' && h.from === hunk.from).map(h => pending.indexOf(h))\n return written.length > 0 && written.every(index => index < pending.indexOf(hunk))\n }).map(hunk => hunk.anchor.id)\n // Back to front: earlier positions stay valid. At one position the range starting there goes first, then the\n // insertions in reverse (pending hunks are in document order, ties in the order they were proposed), so each lands\n // before the ones after it.\n for (const hunk of [...chosen].reverse().sort((a, b) => b.from - a.from || b.to - a.to)) {\n if (hunk.kind === 'block') replaceRangeWithBlocks(tr, hunk.from, hunk.to, hunk.insert)\n else tr.replaceWith(hunk.from, hunk.to, hunk.insert)\n }\n tr.setMeta(aiReviewKey, { type: 'decide', ids: chosen.map(h => h.id), outcome: 'accepted' } satisfies ReviewMeta)\n tr.setMeta(docAnchorsKey, { remove: chosen.map(h => h.anchor.id), after } satisfies DocAnchorsMeta)\n // The collaboration feature's anchor resolver stops its Yjs undo capturing; without one (or without an undo manager)\n // prosemirror-history is the history and gets the closing transactions.\n const resolver = anchorResolverOf(editor)\n const collaborative = resolver?.stopUndoCapture(editor.state) ?? false\n editor.view.dispatch(closeHistory(tr))\n resolver?.stopUndoCapture(editor.state)\n // prosemirror-history: an empty transaction that closes the event, so typing right after starts a new one.\n if (!collaborative) editor.view.dispatch(closeHistory(editor.state.tr))\n}\n\n/** Drops the pending hunks `ids` (all when omitted); the document and undo history stay untouched. */\nexport function rejectAiReview(editor: Editor, ids?: readonly string[]): void {\n const chosen = aiReviewKey.getState(editor.state)?.hunks.filter(h => !ids || ids.includes(h.id)) ?? []\n if (!chosen.length) return\n const meta: ReviewMeta = { type: 'decide', ids: chosen.map(h => h.id), outcome: 'rejected' }\n editor.view.dispatch(editor.state.tr\n .setMeta(aiReviewKey, meta)\n .setMeta(docAnchorsKey, { remove: chosen.map(h => h.anchor.id) } satisfies DocAnchorsMeta)\n .setMeta('addToHistory', false))\n}\n\n/** Shows the controls of hunk `id` (null hides them). */\nexport function setActiveAiReviewHunk(view: EditorView, id: string | null): void {\n dispatchMeta(view, { type: 'activate', id })\n}\n\nfunction dispatchMeta(view: EditorView, meta: ReviewMeta): void {\n view.dispatch(view.state.tr.setMeta(aiReviewKey, meta).setMeta('addToHistory', false))\n}\n\nfunction applyReview(tr: Transaction, value: AiReviewState, _oldState: EditorState, newState: EditorState): AiReviewState {\n const meta = tr.getMeta(aiReviewKey) as ReviewMeta | undefined\n if (!meta && (!tr.docChanged || !value.hunks.length)) return value\n\n let hunks = value.hunks\n // DocAnchors (higher priority, so already applied in `newState`) maps local changes and re-resolves remote ones.\n if (tr.docChanged) hunks = hunks.map(hunk => ({ ...hunk, ...(resolveRange(newState, hunk.anchor) ?? { from: -1, to: -1 }) }))\n\n const decided: AiReviewDecision[] = []\n const decide = (hunk: AiReviewHunk, outcome: AiReviewOutcome) => {\n decided.push({ reviewId: hunk.reviewId, changeId: hunk.changeId, hunkId: hunk.id, outcome })\n }\n if (meta?.type === 'add') hunks = [...hunks, ...meta.hunks].sort((a, b) => a.from - b.from || a.to - b.to)\n if (meta?.type === 'decide') {\n const ids = new Set(meta.ids)\n hunks = hunks.filter((hunk) => {\n if (!ids.has(hunk.id)) return true\n decide(hunk, meta.outcome)\n return false\n })\n }\n if (tr.docChanged) {\n hunks = hunks.filter((hunk) => {\n if (isIntact(newState.doc, hunk)) return true\n decide(hunk, 'invalid')\n return false\n })\n }\n\n let active = meta?.type === 'activate' ? meta.id : value.active\n if (active && !hunks.some(h => h.id === active)) active = null\n return {\n hunks,\n active,\n log: decided.length ? [...value.log, ...decided].slice(-LOG_LIMIT) : value.log,\n logEnd: value.logEnd + decided.length,\n decorations: renderDecorations(newState, hunks, active),\n }\n}\n\n/** Whether the document still holds the hunk's original content at its positions. */\nfunction isIntact(doc: PMNode, hunk: AiReviewHunk): boolean {\n if (hunk.from < 0 || hunk.from > hunk.to || hunk.to > doc.content.size) return false\n if (hunk.kind === 'block') return hunk.from < hunk.to && doc.textBetween(hunk.from, hunk.to, '\\n', '\\uFFFC') === hunk.original\n if (hunk.kind === 'delete') return hunk.to - hunk.from === hunk.original.nodeSize && !!doc.nodeAt(hunk.from)?.eq(hunk.original)\n if (hunk.kind === 'insert') {\n const $at = doc.resolve(hunk.from)\n return hunk.from === hunk.to && !$at.parent.inlineContent && $at.parent.canReplace($at.index(), $at.index(), hunk.insert)\n }\n const $from = doc.resolve(hunk.from)\n const $to = doc.resolve(hunk.to)\n return $from.sameParent($to) && $from.parent.inlineContent\n && $from.parent.content.cut($from.parentOffset, $to.parentOffset).eq(hunk.original)\n}\n\nfunction renderDecorations(state: EditorState, hunks: readonly AiReviewHunk[], active: string | null): DecorationSet {\n if (!hunks.length) return DecorationSet.empty\n const serializer = DOMSerializer.fromSchema(state.schema)\n const decorations: Decoration[] = []\n for (const hunk of hunks) {\n const activeClass = hunk.id === active ? ' is-active' : ''\n if (hunk.kind === 'delete') {\n decorations.push(Decoration.node(hunk.from, hunk.to, { 'class': `ai-review-del-block${activeClass}`, 'data-ai-hunk': hunk.id }))\n continue\n }\n if (hunk.from < hunk.to) {\n decorations.push(Decoration.inline(hunk.from, hunk.to, { 'class': `ai-review-del${activeClass}`, 'data-ai-hunk': hunk.id }))\n }\n if (!hunk.insert.size) continue\n // Replacing blocks go below the top-level block the range ends in; inserted blocks at their position; inline\n // insertions right after the deleted text.\n const $to = state.doc.resolve(hunk.to)\n const block = hunk.kind === 'block' || hunk.kind === 'insert'\n const pos = hunk.kind === 'block' && $to.depth > 0 ? $to.after(1) : hunk.to\n decorations.push(Decoration.widget(pos, () => {\n const dom = document.createElement(block ? 'div' : 'span')\n dom.className = `${block ? 'ai-review-ins-block' : 'ai-review-ins'}${activeClass}`\n dom.setAttribute('data-ai-hunk', hunk.id)\n dom.contentEditable = 'false'\n dom.append(serializer.serializeFragment(hunk.insert))\n return dom\n }, { key: `${hunk.id}${activeClass}`, side: -1, ignoreSelection: true }))\n }\n return DecorationSet.create(state.doc, decorations)\n}\n\n/** Reports decisions to their reviews' callbacks; a review whose hunks are all decided ends. */\nfunction report(view: EditorView, decisions: readonly AiReviewDecision[]): void {\n const entries = reviews.get(view)\n if (!entries) return\n const byReview = new Map<string, AiReviewDecision[]>()\n for (const decision of decisions) byReview.set(decision.reviewId, [...byReview.get(decision.reviewId) ?? [], decision])\n for (const [reviewId, batch] of byReview) {\n const entry = entries.get(reviewId)\n if (!entry) continue\n for (const decision of batch) entry.tallies.get(decision.changeId)![decision.outcome]++\n entry.decided += batch.length\n entry.options.onDecision?.(batch)\n if (entry.decided < entry.total) continue\n entries.delete(reviewId)\n entry.options.onDone?.([...entry.tallies].map(([id, tally]) => {\n const kinds = (Object.keys(tally) as AiReviewOutcome[]).filter(outcome => tally[outcome] > 0)\n return { id, outcome: kinds.length === 1 ? kinds[0]! : 'partial', ...tally }\n }))\n }\n}\n\ntype PlannedHunk = Pick<AiReviewHunk, 'kind' | 'from' | 'to' | 'insert'>\n\n/** The hunks turning [from, to] into the parsed `markdown`. */\nfunction planChange(editor: Editor, from: number, to: number, markdown: string): PlannedHunk[] | AiReviewSkipReason {\n const { doc, schema } = editor.state\n const result = parseBlocks(editor, markdown)\n if (!result.blocks.length) return 'empty'\n const $from = doc.resolve(from)\n const $to = doc.resolve(to)\n const blocks = Fragment.fromArray(result.blocks.map(block => schema.nodeFromJSON(block)))\n\n const inline = inlineReplacement($from, $to, result)\n const inlineContent = inline && Fragment.fromArray(inline.map(node => schema.nodeFromJSON(node)))\n const planned = inlineContent && $from.parent.type.validContent(inlineContent)\n ? diffInline($from.parent.content.cut($from.parentOffset, $to.parentOffset), inlineContent, from)\n : inline ? null : diffTextblocks(doc, from, to, blocks)\n if (planned) return planned.length ? planned : 'unchanged'\n return [{ kind: 'block', from, to, insert: blocks }]\n}\n\n/** The hunk inserting `markdown` as blocks in the preferred structure (`structureBlocks` of the parsed result) at `pos` (between blocks). */\nfunction planInsert(editor: Editor, pos: number, markdown: string): PlannedHunk[] | AiReviewSkipReason {\n const { doc, schema } = editor.state\n const blocks = structureBlocks(editor, parseBlocks(editor, markdown).blocks)\n if (!blocks.length) return 'empty'\n const $pos = doc.resolve(pos)\n if ($pos.parent.inlineContent) return 'missing'\n let insert = Fragment.fromArray(blocks.map(block => schema.nodeFromJSON(block)))\n const fits = (content: Fragment) => $pos.parent.canReplace($pos.index(), $pos.index(), content)\n // A list (or quote) inserted into a list (quote) of the same type contributes its items.\n if (!fits(insert) && insert.childCount === 1 && insert.firstChild!.type === $pos.parent.type) insert = insert.firstChild!.content\n return fits(insert) ? [{ kind: 'insert', from: pos, to: pos, insert }] : 'missing'\n}\n\n/** The hunk deleting [from, to], which must be exactly one node. */\nfunction planDelete(doc: PMNode, from: number, to: number): PlannedHunk[] | AiReviewSkipReason {\n const node = doc.nodeAt(from)\n return node && from + node.nodeSize === to ? [{ kind: 'delete', from, to, insert: Fragment.empty }] : 'missing'\n}\n\n/** Word diffs per textblock when the result has the range's textblocks (types, attributes, nesting); else null. */\nfunction diffTextblocks(doc: PMNode, from: number, to: number, blocks: Fragment): PlannedHunk[] | null {\n const originals: { path: string, node: PMNode }[] = []\n const results: { path: string, node: PMNode }[] = []\n if (!flattenTextblocks(doc.cut(from, to), '', originals) || !flattenTextblocks(doc.type.create(null, blocks), '', results)) return null\n if (originals.length !== results.length || originals.some((original, i) => original.path !== results[i]!.path)) return null\n\n const ranges: { from: number, to: number }[] = []\n doc.nodesBetween(from, to, (node, pos) => {\n if (!node.isTextblock) return true\n ranges.push({ from: Math.max(from, pos + 1), to: Math.min(to, pos + node.nodeSize - 1) })\n return false\n })\n if (ranges.length !== results.length) return null\n return ranges.flatMap((range, i) => {\n const $from = doc.resolve(range.from)\n const original = $from.parent.content.cut($from.parentOffset, $from.parentOffset + range.to - range.from)\n return diffInline(original, results[i]!.node.content, range.from)\n })\n}\n\n/** Collects `node`'s textblocks with their ancestry (types and attributes but block IDs); false for other leaf blocks (images, rules). */\nfunction flattenTextblocks(node: PMNode, path: string, out: { path: string, node: PMNode }[]): boolean {\n let ok = true\n node.forEach((child) => {\n if (!ok) return\n const attrs = Object.entries(child.attrs).filter(([name]) => name !== BLOCK_ID_ATTR)\n const childPath = `${path}/${child.type.name}${JSON.stringify(attrs)}`\n if (child.isTextblock) out.push({ path: childPath, node: child })\n else if (child.isLeaf) ok = false\n else ok = flattenTextblocks(child, childPath, out)\n })\n return ok\n}\n\ninterface Token { key: string, node: PMNode, whitespace: boolean }\n\n/** Words, whitespace and punctuation with their marks; inline nodes (chips, breaks) are one token each. */\nfunction tokenize(content: Fragment): Token[] {\n const tokens: Token[] = []\n content.forEach((node) => {\n if (!node.isText) {\n tokens.push({ key: JSON.stringify(node.toJSON()), node, whitespace: false })\n return\n }\n const marks = JSON.stringify(node.marks.map(mark => mark.toJSON()))\n for (const match of node.text!.matchAll(TOKEN)) {\n tokens.push({ key: marks + match[0], node: node.cut(match.index, match.index + match[0].length), whitespace: !match[0].trim() })\n }\n })\n return tokens\n}\n\n/** Word-level hunks turning `original` (inline content starting at document position `base`) into `result`. */\nfunction diffInline(original: Fragment, result: Fragment, base: number): PlannedHunk[] {\n const a = tokenize(original)\n const b = tokenize(result)\n const offsets = [base]\n for (const token of a) offsets.push(offsets.at(-1)! + token.node.nodeSize)\n return diffTokens(a, b).map(span => ({\n kind: 'inline',\n from: offsets[span.aFrom]!,\n to: offsets[span.aTo]!,\n insert: Fragment.fromArray(b.slice(span.bFrom, span.bTo).map(token => token.node)),\n }))\n}\n\ninterface Span { aFrom: number, aTo: number, bFrom: number, bTo: number }\n\n/** Differing spans of two token lists (LCS); spans only whitespace apart merge, so a rewritten phrase is one hunk. */\nfunction diffTokens(a: Token[], b: Token[]): Span[] {\n let start = 0\n while (start < a.length && start < b.length && a[start]!.key === b[start]!.key) start++\n let endA = a.length\n let endB = b.length\n while (endA > start && endB > start && a[endA - 1]!.key === b[endB - 1]!.key) {\n endA--\n endB--\n }\n const n = endA - start\n const m = endB - start\n if (!n && !m) return []\n if (!n || !m || n * m > MAX_DIFF_CELLS) return [{ aFrom: start, aTo: endA, bFrom: start, bTo: endB }]\n\n // lcs[i * w + j]: LCS length of a[start + i..] and b[start + j..].\n const w = m + 1\n const lcs = new Uint32Array((n + 1) * w)\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n lcs[i * w + j] = a[start + i]!.key === b[start + j]!.key\n ? lcs[(i + 1) * w + j + 1]! + 1\n : Math.max(lcs[(i + 1) * w + j]!, lcs[i * w + j + 1]!)\n }\n }\n\n const spans: Span[] = []\n let open: Span | null = null\n let i = 0\n let j = 0\n while (i < n || j < m) {\n if (i < n && j < m && a[start + i]!.key === b[start + j]!.key) {\n if (open) spans.push(open)\n open = null\n i++\n j++\n continue\n }\n open ??= { aFrom: start + i, aTo: start + i, bFrom: start + j, bTo: start + j }\n if (j < m && (i === n || lcs[i * w + j + 1]! >= lcs[(i + 1) * w + j]!)) open.bTo = start + ++j\n else open.aTo = start + ++i\n }\n if (open) spans.push(open)\n\n const merged: Span[] = []\n for (const span of spans) {\n const previous = merged.at(-1)\n if (previous && a.slice(previous.aTo, span.aFrom).every(token => token.whitespace)) {\n previous.aTo = span.aTo\n previous.bTo = span.bTo\n }\n else merged.push({ ...span })\n }\n return merged\n}\n"],"mappings":"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"}