@dxos/ui-editor 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (551) hide show
  1. package/dist/lib/chunk-diff.mjs +935 -0
  2. package/dist/lib/chunk-diff.mjs.map +1 -0
  3. package/dist/lib/headless.mjs +2 -0
  4. package/dist/lib/index.mjs +9937 -0
  5. package/dist/lib/index.mjs.map +1 -0
  6. package/dist/lib/types.mjs +18 -0
  7. package/dist/lib/types.mjs.map +1 -0
  8. package/dist/types/src/extensions/{bookmarks.d.ts → behavior/bookmarks.d.ts} +3 -0
  9. package/dist/types/src/extensions/behavior/bookmarks.d.ts.map +1 -0
  10. package/dist/types/src/extensions/behavior/dnd.d.ts.map +1 -0
  11. package/dist/types/src/extensions/behavior/index.d.ts +6 -0
  12. package/dist/types/src/extensions/behavior/index.d.ts.map +1 -0
  13. package/dist/types/src/extensions/{listener.d.ts → behavior/listener.d.ts} +3 -0
  14. package/dist/types/src/extensions/behavior/listener.d.ts.map +1 -0
  15. package/dist/types/src/extensions/{spacing.d.ts → behavior/spacing.d.ts} +3 -0
  16. package/dist/types/src/extensions/behavior/spacing.d.ts.map +1 -0
  17. package/dist/types/src/extensions/behavior/submit.d.ts.map +1 -0
  18. package/dist/types/src/extensions/collab/automerge/automerge.d.ts.map +1 -0
  19. package/dist/types/src/extensions/collab/automerge/automerge.test.d.ts.map +1 -0
  20. package/dist/types/src/extensions/{automerge → collab/automerge}/cursor.d.ts +1 -1
  21. package/dist/types/src/extensions/collab/automerge/cursor.d.ts.map +1 -0
  22. package/dist/types/src/extensions/{automerge → collab/automerge}/defs.d.ts +3 -1
  23. package/dist/types/src/extensions/collab/automerge/defs.d.ts.map +1 -0
  24. package/dist/types/src/extensions/collab/automerge/index.d.ts +3 -0
  25. package/dist/types/src/extensions/collab/automerge/index.d.ts.map +1 -0
  26. package/dist/types/src/extensions/collab/automerge/sync.d.ts.map +1 -0
  27. package/dist/types/src/extensions/{automerge → collab/automerge}/update-automerge.d.ts +4 -0
  28. package/dist/types/src/extensions/collab/automerge/update-automerge.d.ts.map +1 -0
  29. package/dist/types/src/extensions/{automerge → collab/automerge}/update-codemirror.d.ts +4 -0
  30. package/dist/types/src/extensions/collab/automerge/update-codemirror.d.ts.map +1 -0
  31. package/dist/types/src/extensions/collab/awareness/awareness-provider.d.ts.map +1 -0
  32. package/dist/types/src/extensions/{awareness → collab/awareness}/awareness.d.ts +4 -1
  33. package/dist/types/src/extensions/collab/awareness/awareness.d.ts.map +1 -0
  34. package/dist/types/src/extensions/collab/awareness/index.d.ts.map +1 -0
  35. package/dist/types/src/extensions/collab/index.d.ts +3 -0
  36. package/dist/types/src/extensions/collab/index.d.ts.map +1 -0
  37. package/dist/types/src/extensions/completion/autocomplete.d.ts.map +1 -0
  38. package/dist/types/src/extensions/{autocomplete → completion}/index.d.ts +1 -0
  39. package/dist/types/src/extensions/completion/index.d.ts.map +1 -0
  40. package/dist/types/src/extensions/{autocomplete → completion}/match.d.ts +2 -2
  41. package/dist/types/src/extensions/completion/match.d.ts.map +1 -0
  42. package/dist/types/src/extensions/{mention.d.ts → completion/mention.d.ts} +3 -0
  43. package/dist/types/src/extensions/completion/mention.d.ts.map +1 -0
  44. package/dist/types/src/extensions/completion/placeholder.d.ts.map +1 -0
  45. package/dist/types/src/extensions/{autocomplete → completion}/typeahead.d.ts +2 -2
  46. package/dist/types/src/extensions/completion/typeahead.d.ts.map +1 -0
  47. package/dist/types/src/extensions/{factories.d.ts → core/factories.d.ts} +23 -2
  48. package/dist/types/src/extensions/core/factories.d.ts.map +1 -0
  49. package/dist/types/src/extensions/core/factories.test.d.ts.map +1 -0
  50. package/dist/types/src/extensions/core/index.d.ts +3 -0
  51. package/dist/types/src/extensions/core/index.d.ts.map +1 -0
  52. package/dist/types/src/extensions/{modes.d.ts → core/modes.d.ts} +3 -0
  53. package/dist/types/src/extensions/core/modes.d.ts.map +1 -0
  54. package/dist/types/src/extensions/{debug.d.ts → debug/debug.d.ts} +3 -0
  55. package/dist/types/src/extensions/debug/debug.d.ts.map +1 -0
  56. package/dist/types/src/extensions/debug/index.d.ts +2 -0
  57. package/dist/types/src/extensions/debug/index.d.ts.map +1 -0
  58. package/dist/types/src/extensions/{annotations.d.ts → decoration/annotations.d.ts} +1 -1
  59. package/dist/types/src/extensions/decoration/annotations.d.ts.map +1 -0
  60. package/dist/types/src/extensions/decoration/assistant.d.ts +27 -0
  61. package/dist/types/src/extensions/decoration/assistant.d.ts.map +1 -0
  62. package/dist/types/src/extensions/decoration/fader.d.ts.map +1 -0
  63. package/dist/types/src/extensions/decoration/hashtag.d.ts +6 -0
  64. package/dist/types/src/extensions/decoration/hashtag.d.ts.map +1 -0
  65. package/dist/types/src/extensions/decoration/index.d.ts +8 -0
  66. package/dist/types/src/extensions/decoration/index.d.ts.map +1 -0
  67. package/dist/types/src/extensions/decoration/marker.d.ts.map +1 -0
  68. package/dist/types/src/extensions/{pos.d.ts → decoration/pos.d.ts} +40 -14
  69. package/dist/types/src/extensions/decoration/pos.d.ts.map +1 -0
  70. package/dist/types/src/extensions/decoration/pos.test.d.ts.map +1 -0
  71. package/dist/types/src/extensions/{replacer.d.ts → decoration/replacer.d.ts} +8 -8
  72. package/dist/types/src/extensions/decoration/replacer.d.ts.map +1 -0
  73. package/dist/types/src/extensions/decoration/replacer.test.d.ts.map +1 -0
  74. package/dist/types/src/extensions/{blast.d.ts → demo/blast.d.ts} +3 -0
  75. package/dist/types/src/extensions/demo/blast.d.ts.map +1 -0
  76. package/dist/types/src/extensions/demo/index.d.ts +3 -0
  77. package/dist/types/src/extensions/demo/index.d.ts.map +1 -0
  78. package/dist/types/src/extensions/demo/snippets.d.ts.map +1 -0
  79. package/dist/types/src/extensions/index.d.ts +10 -33
  80. package/dist/types/src/extensions/index.d.ts.map +1 -1
  81. package/dist/types/src/extensions/language/index.d.ts +5 -0
  82. package/dist/types/src/extensions/language/index.d.ts.map +1 -0
  83. package/dist/types/src/extensions/language/json/index.d.ts +2 -0
  84. package/dist/types/src/extensions/language/json/index.d.ts.map +1 -0
  85. package/dist/types/src/extensions/language/json/json.d.ts +12 -0
  86. package/dist/types/src/extensions/language/json/json.d.ts.map +1 -0
  87. package/dist/types/src/extensions/language/markdown/action.d.ts.map +1 -0
  88. package/dist/types/src/extensions/language/markdown/bundle.d.ts.map +1 -0
  89. package/dist/types/src/extensions/{markdown → language/markdown}/changes.d.ts +1 -1
  90. package/dist/types/src/extensions/language/markdown/changes.d.ts.map +1 -0
  91. package/dist/types/src/extensions/language/markdown/changes.test.d.ts.map +1 -0
  92. package/dist/types/src/extensions/{markdown → language/markdown}/debug.d.ts +3 -0
  93. package/dist/types/src/extensions/language/markdown/debug.d.ts.map +1 -0
  94. package/dist/types/src/extensions/{markdown → language/markdown}/decorate.d.ts +5 -1
  95. package/dist/types/src/extensions/language/markdown/decorate.d.ts.map +1 -0
  96. package/dist/types/src/extensions/{markdown → language/markdown}/formatting.d.ts +11 -2
  97. package/dist/types/src/extensions/language/markdown/formatting.d.ts.map +1 -0
  98. package/dist/types/src/extensions/language/markdown/formatting.test.d.ts.map +1 -0
  99. package/dist/types/src/extensions/{markdown → language/markdown}/highlight.d.ts +16 -12
  100. package/dist/types/src/extensions/language/markdown/highlight.d.ts.map +1 -0
  101. package/dist/types/src/extensions/language/markdown/image.d.ts.map +1 -0
  102. package/dist/types/src/extensions/language/markdown/image.test.d.ts.map +1 -0
  103. package/dist/types/src/extensions/language/markdown/index.d.ts.map +1 -0
  104. package/dist/types/src/extensions/language/markdown/link.d.ts +25 -0
  105. package/dist/types/src/extensions/language/markdown/link.d.ts.map +1 -0
  106. package/dist/types/src/extensions/language/markdown/link.test.d.ts +2 -0
  107. package/dist/types/src/extensions/language/markdown/link.test.d.ts.map +1 -0
  108. package/dist/types/src/extensions/language/markdown/parser.test.d.ts.map +1 -0
  109. package/dist/types/src/extensions/{markdown → language/markdown}/styles.d.ts +3 -0
  110. package/dist/types/src/extensions/language/markdown/styles.d.ts.map +1 -0
  111. package/dist/types/src/extensions/language/markdown/table.d.ts.map +1 -0
  112. package/dist/types/src/extensions/language/mermaid/index.d.ts +2 -0
  113. package/dist/types/src/extensions/language/mermaid/index.d.ts.map +1 -0
  114. package/dist/types/src/extensions/language/mermaid/mermaid.d.ts +18 -0
  115. package/dist/types/src/extensions/language/mermaid/mermaid.d.ts.map +1 -0
  116. package/dist/types/src/extensions/language/xml/extended-markdown.d.ts.map +1 -0
  117. package/dist/types/src/extensions/language/xml/extended-markdown.test.d.ts.map +1 -0
  118. package/dist/types/src/extensions/language/xml/index.d.ts.map +1 -0
  119. package/dist/types/src/extensions/language/xml/stub.d.ts +76 -0
  120. package/dist/types/src/extensions/language/xml/stub.d.ts.map +1 -0
  121. package/dist/types/src/extensions/language/xml/widgets/anchor.d.ts.map +1 -0
  122. package/dist/types/src/extensions/language/xml/widgets/index.d.ts.map +1 -0
  123. package/dist/types/src/extensions/language/xml/xml-block-decoration.d.ts +48 -0
  124. package/dist/types/src/extensions/language/xml/xml-block-decoration.d.ts.map +1 -0
  125. package/dist/types/src/extensions/language/xml/xml-formatting.d.ts.map +1 -0
  126. package/dist/types/src/extensions/{tags → language/xml}/xml-tags.d.ts +12 -1
  127. package/dist/types/src/extensions/language/xml/xml-tags.d.ts.map +1 -0
  128. package/dist/types/src/extensions/language/xml/xml-tags.test.d.ts +2 -0
  129. package/dist/types/src/extensions/language/xml/xml-tags.test.d.ts.map +1 -0
  130. package/dist/types/src/extensions/language/xml/xml-util.d.ts.map +1 -0
  131. package/dist/types/src/extensions/language/xml/xml-util.test.d.ts.map +1 -0
  132. package/dist/types/src/extensions/review/change-bar.d.ts +29 -0
  133. package/dist/types/src/extensions/review/change-bar.d.ts.map +1 -0
  134. package/dist/types/src/extensions/{comments.d.ts → review/comments.d.ts} +56 -38
  135. package/dist/types/src/extensions/review/comments.d.ts.map +1 -0
  136. package/dist/types/src/extensions/review/comments.test.d.ts +2 -0
  137. package/dist/types/src/extensions/review/comments.test.d.ts.map +1 -0
  138. package/dist/types/src/extensions/review/diff.d.ts +131 -0
  139. package/dist/types/src/extensions/review/diff.d.ts.map +1 -0
  140. package/dist/types/src/extensions/review/diff.test.d.ts +2 -0
  141. package/dist/types/src/extensions/review/diff.test.d.ts.map +1 -0
  142. package/dist/types/src/extensions/review/index.d.ts +7 -0
  143. package/dist/types/src/extensions/review/index.d.ts.map +1 -0
  144. package/dist/types/src/extensions/review/suggest.d.ts +89 -0
  145. package/dist/types/src/extensions/review/suggest.d.ts.map +1 -0
  146. package/dist/types/src/extensions/review/suggest.test.d.ts +2 -0
  147. package/dist/types/src/extensions/review/suggest.test.d.ts.map +1 -0
  148. package/dist/types/src/extensions/review/suggestions-overlay.d.ts +25 -0
  149. package/dist/types/src/extensions/review/suggestions-overlay.d.ts.map +1 -0
  150. package/dist/types/src/extensions/review/suggestions-overlay.test.d.ts +2 -0
  151. package/dist/types/src/extensions/review/suggestions-overlay.test.d.ts.map +1 -0
  152. package/dist/types/src/extensions/review/track-changes.d.ts +27 -0
  153. package/dist/types/src/extensions/review/track-changes.d.ts.map +1 -0
  154. package/dist/types/src/extensions/review/track-changes.test.d.ts +2 -0
  155. package/dist/types/src/extensions/review/track-changes.test.d.ts.map +1 -0
  156. package/dist/types/src/extensions/{busy.d.ts → state/busy.d.ts} +1 -0
  157. package/dist/types/src/extensions/state/busy.d.ts.map +1 -0
  158. package/dist/types/src/extensions/{focus.d.ts → state/focus.d.ts} +4 -0
  159. package/dist/types/src/extensions/state/focus.d.ts.map +1 -0
  160. package/dist/types/src/extensions/state/index.d.ts +5 -0
  161. package/dist/types/src/extensions/state/index.d.ts.map +1 -0
  162. package/dist/types/src/extensions/state/modal.d.ts.map +1 -0
  163. package/dist/types/src/extensions/{selection.d.ts → state/selection.d.ts} +1 -1
  164. package/dist/types/src/extensions/state/selection.d.ts.map +1 -0
  165. package/dist/types/src/extensions/state/selection.test.d.ts.map +1 -0
  166. package/dist/types/src/extensions/streaming/index.d.ts +4 -0
  167. package/dist/types/src/extensions/streaming/index.d.ts.map +1 -0
  168. package/dist/types/src/extensions/streaming/pending/index.d.ts.map +1 -0
  169. package/dist/types/src/extensions/streaming/pending/pending-text-stream.d.ts.map +1 -0
  170. package/dist/types/src/extensions/streaming/pending/pending-text-stream.test.d.ts.map +1 -0
  171. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text.d.ts +1 -0
  172. package/dist/types/src/extensions/streaming/pending/pending-text.d.ts.map +1 -0
  173. package/dist/types/src/extensions/streaming/pending/pending-text.test.d.ts.map +1 -0
  174. package/dist/types/src/extensions/streaming/scrolling/auto-scroll.d.ts.map +1 -0
  175. package/dist/types/src/extensions/streaming/scrolling/crawler.d.ts.map +1 -0
  176. package/dist/types/src/extensions/streaming/scrolling/index.d.ts.map +1 -0
  177. package/dist/types/src/extensions/streaming/scrolling/scroll-past-end.d.ts +4 -0
  178. package/dist/types/src/extensions/streaming/scrolling/scroll-past-end.d.ts.map +1 -0
  179. package/dist/types/src/extensions/streaming/scrolling/scrollbar-autohide.d.ts.map +1 -0
  180. package/dist/types/src/extensions/streaming/scrolling/scroller.d.ts.map +1 -0
  181. package/dist/types/src/extensions/{typewriter.d.ts → streaming/typewriter.d.ts} +12 -12
  182. package/dist/types/src/extensions/streaming/typewriter.d.ts.map +1 -0
  183. package/dist/types/src/extensions/streaming/typewriter.test.d.ts.map +1 -0
  184. package/dist/types/src/extensions/structure/blocks/blocks.d.ts +52 -0
  185. package/dist/types/src/extensions/structure/blocks/blocks.d.ts.map +1 -0
  186. package/dist/types/src/extensions/structure/blocks/blocks.test.d.ts +2 -0
  187. package/dist/types/src/extensions/structure/blocks/blocks.test.d.ts.map +1 -0
  188. package/dist/types/src/extensions/structure/blocks/drag.d.ts +57 -0
  189. package/dist/types/src/extensions/structure/blocks/drag.d.ts.map +1 -0
  190. package/dist/types/src/extensions/structure/blocks/index.d.ts +5 -0
  191. package/dist/types/src/extensions/structure/blocks/index.d.ts.map +1 -0
  192. package/dist/types/src/extensions/structure/blocks/selection.d.ts +47 -0
  193. package/dist/types/src/extensions/structure/blocks/selection.d.ts.map +1 -0
  194. package/dist/types/src/extensions/structure/blocks/selection.test.d.ts +2 -0
  195. package/dist/types/src/extensions/structure/blocks/selection.test.d.ts.map +1 -0
  196. package/dist/types/src/extensions/structure/blocks/types.d.ts +17 -0
  197. package/dist/types/src/extensions/structure/blocks/types.d.ts.map +1 -0
  198. package/dist/types/src/extensions/structure/folding/folding.d.ts.map +1 -0
  199. package/dist/types/src/extensions/structure/folding/index.d.ts +3 -0
  200. package/dist/types/src/extensions/structure/folding/index.d.ts.map +1 -0
  201. package/dist/types/src/extensions/structure/folding/turns.d.ts +55 -0
  202. package/dist/types/src/extensions/structure/folding/turns.d.ts.map +1 -0
  203. package/dist/types/src/extensions/structure/folding/turns.test.d.ts +2 -0
  204. package/dist/types/src/extensions/structure/folding/turns.test.d.ts.map +1 -0
  205. package/dist/types/src/extensions/structure/index.d.ts +4 -0
  206. package/dist/types/src/extensions/structure/index.d.ts.map +1 -0
  207. package/dist/types/src/extensions/structure/outliner/commands.d.ts +31 -0
  208. package/dist/types/src/extensions/structure/outliner/commands.d.ts.map +1 -0
  209. package/dist/types/src/extensions/structure/outliner/dnd.d.ts +43 -0
  210. package/dist/types/src/extensions/structure/outliner/dnd.d.ts.map +1 -0
  211. package/dist/types/src/extensions/structure/outliner/dnd.test.d.ts +2 -0
  212. package/dist/types/src/extensions/structure/outliner/dnd.test.d.ts.map +1 -0
  213. package/dist/types/src/extensions/structure/outliner/editor.d.ts.map +1 -0
  214. package/dist/types/src/extensions/structure/outliner/editor.test.d.ts.map +1 -0
  215. package/dist/types/src/extensions/{outliner → structure/outliner}/index.d.ts +1 -0
  216. package/dist/types/src/extensions/structure/outliner/index.d.ts.map +1 -0
  217. package/dist/types/src/extensions/{outliner → structure/outliner}/menu.d.ts +1 -0
  218. package/dist/types/src/extensions/structure/outliner/menu.d.ts.map +1 -0
  219. package/dist/types/src/extensions/structure/outliner/outliner.d.ts.map +1 -0
  220. package/dist/types/src/extensions/structure/outliner/outliner.test.d.ts.map +1 -0
  221. package/dist/types/src/extensions/{outliner → structure/outliner}/tree.d.ts +1 -1
  222. package/dist/types/src/extensions/structure/outliner/tree.d.ts.map +1 -0
  223. package/dist/types/src/extensions/structure/outliner/tree.test.d.ts.map +1 -0
  224. package/dist/types/src/headless.d.ts +4 -0
  225. package/dist/types/src/headless.d.ts.map +1 -0
  226. package/dist/types/src/styles/theme.d.ts +1 -1
  227. package/dist/types/src/styles/theme.d.ts.map +1 -1
  228. package/dist/types/src/util/util.d.ts +2 -0
  229. package/dist/types/src/util/util.d.ts.map +1 -1
  230. package/dist/types/tsconfig.tsbuildinfo +1 -1
  231. package/package.json +48 -42
  232. package/src/defaults.ts +1 -1
  233. package/src/extensions/{bookmarks.ts → behavior/bookmarks.ts} +24 -14
  234. package/src/extensions/behavior/index.ts +9 -0
  235. package/src/extensions/{listener.ts → behavior/listener.ts} +4 -1
  236. package/src/extensions/{spacing.ts → behavior/spacing.ts} +8 -2
  237. package/src/extensions/{submit.ts → behavior/submit.ts} +2 -10
  238. package/src/extensions/{automerge → collab/automerge}/automerge.test.tsx +4 -4
  239. package/src/extensions/{automerge → collab/automerge}/automerge.ts +7 -4
  240. package/src/extensions/{automerge → collab/automerge}/cursor.ts +1 -1
  241. package/src/extensions/{automerge → collab/automerge}/defs.ts +4 -1
  242. package/src/extensions/{automerge → collab/automerge}/index.ts +1 -0
  243. package/src/extensions/{automerge → collab/automerge}/sync.ts +1 -2
  244. package/src/extensions/{automerge → collab/automerge}/update-automerge.ts +4 -0
  245. package/src/extensions/{automerge → collab/automerge}/update-codemirror.ts +5 -1
  246. package/src/extensions/{awareness → collab/awareness}/awareness-provider.ts +3 -4
  247. package/src/extensions/{awareness → collab/awareness}/awareness.ts +19 -16
  248. package/src/extensions/collab/index.ts +6 -0
  249. package/src/extensions/{autocomplete → completion}/autocomplete.ts +7 -5
  250. package/src/extensions/{autocomplete → completion}/index.ts +2 -1
  251. package/src/extensions/{autocomplete → completion}/match.ts +2 -2
  252. package/src/extensions/{mention.ts → completion/mention.ts} +3 -0
  253. package/src/extensions/{autocomplete → completion}/placeholder.ts +1 -1
  254. package/src/extensions/completion/typeahead.ts +97 -0
  255. package/src/extensions/{factories.ts → core/factories.ts} +35 -13
  256. package/src/extensions/core/index.ts +6 -0
  257. package/src/extensions/{modes.ts → core/modes.ts} +4 -1
  258. package/src/extensions/{debug.ts → debug/debug.ts} +3 -0
  259. package/src/extensions/debug/index.ts +5 -0
  260. package/src/extensions/{annotations.ts → decoration/annotations.ts} +12 -10
  261. package/src/extensions/decoration/assistant.ts +225 -0
  262. package/src/extensions/{fader.ts → decoration/fader.ts} +17 -19
  263. package/src/extensions/{hashtag.ts → decoration/hashtag.ts} +35 -28
  264. package/src/extensions/decoration/index.ts +11 -0
  265. package/src/extensions/{marker.ts → decoration/marker.ts} +18 -18
  266. package/src/extensions/{pos.test.ts → decoration/pos.test.ts} +57 -1
  267. package/src/extensions/{pos.ts → decoration/pos.ts} +165 -31
  268. package/src/extensions/{blast.ts → demo/blast.ts} +3 -0
  269. package/src/extensions/demo/index.ts +6 -0
  270. package/src/extensions/{snippets.ts → demo/snippets.ts} +5 -1
  271. package/src/extensions/index.ts +10 -33
  272. package/src/extensions/language/index.ts +8 -0
  273. package/src/extensions/language/json/index.ts +5 -0
  274. package/src/extensions/{json.ts → language/json/json.ts} +11 -6
  275. package/src/extensions/{markdown → language/markdown}/action.ts +1 -1
  276. package/src/extensions/{markdown → language/markdown}/bundle.ts +7 -1
  277. package/src/extensions/{markdown → language/markdown}/changes.test.ts +2 -2
  278. package/src/extensions/{markdown → language/markdown}/changes.ts +2 -2
  279. package/src/extensions/{markdown → language/markdown}/debug.ts +3 -0
  280. package/src/extensions/{markdown → language/markdown}/decorate.ts +96 -85
  281. package/src/extensions/{markdown → language/markdown}/formatting.test.ts +88 -1
  282. package/src/extensions/{markdown → language/markdown}/formatting.ts +193 -74
  283. package/src/extensions/{markdown → language/markdown}/highlight.ts +42 -41
  284. package/src/extensions/{markdown → language/markdown}/image.test.ts +1 -1
  285. package/src/extensions/{markdown → language/markdown}/image.ts +6 -6
  286. package/src/extensions/language/markdown/link.test.ts +58 -0
  287. package/src/extensions/language/markdown/link.ts +109 -0
  288. package/src/extensions/{markdown → language/markdown}/parser.test.ts +0 -28
  289. package/src/extensions/{markdown → language/markdown}/styles.ts +38 -7
  290. package/src/extensions/{markdown → language/markdown}/table.ts +5 -5
  291. package/src/extensions/language/mermaid/index.ts +5 -0
  292. package/src/extensions/language/mermaid/mermaid.ts +44 -0
  293. package/src/extensions/{tags → language/xml}/DESIGN.md +3 -3
  294. package/src/extensions/{tags → language/xml}/extended-markdown.test.ts +2 -1
  295. package/src/extensions/{tags → language/xml}/extended-markdown.ts +2 -4
  296. package/src/extensions/language/xml/stub.ts +233 -0
  297. package/src/extensions/language/xml/xml-block-decoration.ts +165 -0
  298. package/src/extensions/{tags → language/xml}/xml-formatting.ts +54 -38
  299. package/src/extensions/language/xml/xml-tags.test.ts +588 -0
  300. package/src/extensions/{tags → language/xml}/xml-tags.ts +165 -66
  301. package/src/extensions/{tags → language/xml}/xml-util.test.ts +2 -2
  302. package/src/extensions/review/change-bar.ts +94 -0
  303. package/src/extensions/review/comments.test.ts +72 -0
  304. package/src/extensions/{comments.ts → review/comments.ts} +395 -267
  305. package/src/extensions/review/diff.test.ts +405 -0
  306. package/src/extensions/review/diff.ts +502 -0
  307. package/src/extensions/review/index.ts +10 -0
  308. package/src/extensions/review/suggest.test.ts +170 -0
  309. package/src/extensions/review/suggest.ts +512 -0
  310. package/src/extensions/review/suggestions-overlay.test.ts +58 -0
  311. package/src/extensions/review/suggestions-overlay.ts +50 -0
  312. package/src/extensions/review/track-changes.test.ts +101 -0
  313. package/src/extensions/review/track-changes.ts +215 -0
  314. package/src/extensions/{busy.ts → state/busy.ts} +1 -0
  315. package/src/extensions/{focus.ts → state/focus.ts} +4 -0
  316. package/src/extensions/state/index.ts +8 -0
  317. package/src/extensions/{selection.ts → state/selection.ts} +3 -3
  318. package/src/extensions/streaming/index.ts +7 -0
  319. package/src/extensions/{pending → streaming/pending}/pending-text-stream.ts +10 -3
  320. package/src/extensions/{pending → streaming/pending}/pending-text.test.ts +1 -1
  321. package/src/extensions/{pending → streaming/pending}/pending-text.ts +20 -19
  322. package/src/extensions/{scrolling → streaming/scrolling}/auto-scroll.ts +9 -6
  323. package/src/extensions/{scrolling → streaming/scrolling}/scroll-past-end.ts +1 -0
  324. package/src/extensions/{scrolling → streaming/scrolling}/scrollbar-autohide.ts +13 -11
  325. package/src/extensions/{typewriter.ts → streaming/typewriter.ts} +46 -47
  326. package/src/extensions/structure/blocks/DESIGN.md +134 -0
  327. package/src/extensions/structure/blocks/blocks.test.ts +147 -0
  328. package/src/extensions/structure/blocks/blocks.ts +219 -0
  329. package/src/extensions/structure/blocks/drag.ts +996 -0
  330. package/src/extensions/structure/blocks/index.ts +8 -0
  331. package/src/extensions/structure/blocks/selection.test.ts +56 -0
  332. package/src/extensions/structure/blocks/selection.ts +279 -0
  333. package/src/extensions/structure/blocks/types.ts +22 -0
  334. package/src/extensions/{folding.ts → structure/folding/folding.ts} +12 -10
  335. package/src/extensions/structure/folding/index.ts +6 -0
  336. package/src/extensions/structure/folding/turns.test.ts +72 -0
  337. package/src/extensions/structure/folding/turns.ts +209 -0
  338. package/src/extensions/structure/index.ts +7 -0
  339. package/src/extensions/structure/outliner/DESIGN.md +183 -0
  340. package/src/extensions/structure/outliner/SPEC.mdl +305 -0
  341. package/src/extensions/{outliner → structure/outliner}/commands.ts +125 -42
  342. package/src/extensions/structure/outliner/dnd.test.ts +142 -0
  343. package/src/extensions/structure/outliner/dnd.ts +375 -0
  344. package/src/extensions/structure/outliner/editor.test.ts +85 -0
  345. package/src/extensions/{outliner → structure/outliner}/editor.ts +14 -9
  346. package/src/extensions/{outliner → structure/outliner}/index.ts +1 -0
  347. package/src/extensions/{outliner → structure/outliner}/menu.ts +48 -25
  348. package/src/extensions/structure/outliner/outliner.test.ts +193 -0
  349. package/src/extensions/structure/outliner/outliner.ts +183 -0
  350. package/src/extensions/{outliner → structure/outliner}/tree.test.ts +2 -2
  351. package/src/extensions/{outliner → structure/outliner}/tree.ts +1 -1
  352. package/src/headless.ts +13 -0
  353. package/src/styles/theme.ts +3 -1
  354. package/src/util/util.ts +3 -0
  355. package/dist/lib/browser/index.mjs +0 -9594
  356. package/dist/lib/browser/index.mjs.map +0 -7
  357. package/dist/lib/browser/meta.json +0 -1
  358. package/dist/lib/browser/types/index.mjs +0 -33
  359. package/dist/lib/browser/types/index.mjs.map +0 -7
  360. package/dist/lib/node-esm/index.mjs +0 -9596
  361. package/dist/lib/node-esm/index.mjs.map +0 -7
  362. package/dist/lib/node-esm/meta.json +0 -1
  363. package/dist/lib/node-esm/types/index.mjs +0 -35
  364. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  365. package/dist/types/src/extensions/annotations.d.ts.map +0 -1
  366. package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +0 -1
  367. package/dist/types/src/extensions/autocomplete/index.d.ts.map +0 -1
  368. package/dist/types/src/extensions/autocomplete/match.d.ts.map +0 -1
  369. package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +0 -1
  370. package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +0 -1
  371. package/dist/types/src/extensions/automerge/automerge.d.ts.map +0 -1
  372. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +0 -1
  373. package/dist/types/src/extensions/automerge/cursor.d.ts.map +0 -1
  374. package/dist/types/src/extensions/automerge/defs.d.ts.map +0 -1
  375. package/dist/types/src/extensions/automerge/index.d.ts +0 -2
  376. package/dist/types/src/extensions/automerge/index.d.ts.map +0 -1
  377. package/dist/types/src/extensions/automerge/sync.d.ts.map +0 -1
  378. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +0 -1
  379. package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +0 -1
  380. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +0 -1
  381. package/dist/types/src/extensions/awareness/awareness.d.ts.map +0 -1
  382. package/dist/types/src/extensions/awareness/index.d.ts.map +0 -1
  383. package/dist/types/src/extensions/blast.d.ts.map +0 -1
  384. package/dist/types/src/extensions/blocks.d.ts +0 -2
  385. package/dist/types/src/extensions/blocks.d.ts.map +0 -1
  386. package/dist/types/src/extensions/bookmarks.d.ts.map +0 -1
  387. package/dist/types/src/extensions/busy.d.ts.map +0 -1
  388. package/dist/types/src/extensions/comments.d.ts.map +0 -1
  389. package/dist/types/src/extensions/debug.d.ts.map +0 -1
  390. package/dist/types/src/extensions/dnd.d.ts.map +0 -1
  391. package/dist/types/src/extensions/factories.d.ts.map +0 -1
  392. package/dist/types/src/extensions/factories.test.d.ts.map +0 -1
  393. package/dist/types/src/extensions/fader.d.ts.map +0 -1
  394. package/dist/types/src/extensions/focus.d.ts.map +0 -1
  395. package/dist/types/src/extensions/folding.d.ts.map +0 -1
  396. package/dist/types/src/extensions/hashtag.d.ts +0 -3
  397. package/dist/types/src/extensions/hashtag.d.ts.map +0 -1
  398. package/dist/types/src/extensions/json.d.ts +0 -7
  399. package/dist/types/src/extensions/json.d.ts.map +0 -1
  400. package/dist/types/src/extensions/listener.d.ts.map +0 -1
  401. package/dist/types/src/extensions/markdown/action.d.ts.map +0 -1
  402. package/dist/types/src/extensions/markdown/bundle.d.ts.map +0 -1
  403. package/dist/types/src/extensions/markdown/changes.d.ts.map +0 -1
  404. package/dist/types/src/extensions/markdown/changes.test.d.ts.map +0 -1
  405. package/dist/types/src/extensions/markdown/debug.d.ts.map +0 -1
  406. package/dist/types/src/extensions/markdown/decorate.d.ts.map +0 -1
  407. package/dist/types/src/extensions/markdown/formatting.d.ts.map +0 -1
  408. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +0 -1
  409. package/dist/types/src/extensions/markdown/highlight.d.ts.map +0 -1
  410. package/dist/types/src/extensions/markdown/image.d.ts.map +0 -1
  411. package/dist/types/src/extensions/markdown/image.test.d.ts.map +0 -1
  412. package/dist/types/src/extensions/markdown/index.d.ts.map +0 -1
  413. package/dist/types/src/extensions/markdown/link.d.ts +0 -7
  414. package/dist/types/src/extensions/markdown/link.d.ts.map +0 -1
  415. package/dist/types/src/extensions/markdown/parser.test.d.ts.map +0 -1
  416. package/dist/types/src/extensions/markdown/styles.d.ts.map +0 -1
  417. package/dist/types/src/extensions/markdown/table.d.ts.map +0 -1
  418. package/dist/types/src/extensions/marker.d.ts.map +0 -1
  419. package/dist/types/src/extensions/mention.d.ts.map +0 -1
  420. package/dist/types/src/extensions/modal.d.ts.map +0 -1
  421. package/dist/types/src/extensions/modes.d.ts.map +0 -1
  422. package/dist/types/src/extensions/outliner/commands.d.ts +0 -10
  423. package/dist/types/src/extensions/outliner/commands.d.ts.map +0 -1
  424. package/dist/types/src/extensions/outliner/editor.d.ts.map +0 -1
  425. package/dist/types/src/extensions/outliner/editor.test.d.ts.map +0 -1
  426. package/dist/types/src/extensions/outliner/index.d.ts.map +0 -1
  427. package/dist/types/src/extensions/outliner/menu.d.ts.map +0 -1
  428. package/dist/types/src/extensions/outliner/outliner.d.ts.map +0 -1
  429. package/dist/types/src/extensions/outliner/outliner.test.d.ts.map +0 -1
  430. package/dist/types/src/extensions/outliner/selection.d.ts +0 -12
  431. package/dist/types/src/extensions/outliner/selection.d.ts.map +0 -1
  432. package/dist/types/src/extensions/outliner/tree.d.ts.map +0 -1
  433. package/dist/types/src/extensions/outliner/tree.test.d.ts.map +0 -1
  434. package/dist/types/src/extensions/pending/index.d.ts.map +0 -1
  435. package/dist/types/src/extensions/pending/pending-text-stream.d.ts.map +0 -1
  436. package/dist/types/src/extensions/pending/pending-text-stream.test.d.ts.map +0 -1
  437. package/dist/types/src/extensions/pending/pending-text.d.ts.map +0 -1
  438. package/dist/types/src/extensions/pending/pending-text.test.d.ts.map +0 -1
  439. package/dist/types/src/extensions/pos.d.ts.map +0 -1
  440. package/dist/types/src/extensions/pos.test.d.ts.map +0 -1
  441. package/dist/types/src/extensions/replacer.d.ts.map +0 -1
  442. package/dist/types/src/extensions/replacer.test.d.ts.map +0 -1
  443. package/dist/types/src/extensions/scrolling/auto-scroll.d.ts.map +0 -1
  444. package/dist/types/src/extensions/scrolling/crawler.d.ts.map +0 -1
  445. package/dist/types/src/extensions/scrolling/index.d.ts.map +0 -1
  446. package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts +0 -3
  447. package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts.map +0 -1
  448. package/dist/types/src/extensions/scrolling/scrollbar-autohide.d.ts.map +0 -1
  449. package/dist/types/src/extensions/scrolling/scroller.d.ts.map +0 -1
  450. package/dist/types/src/extensions/selection.d.ts.map +0 -1
  451. package/dist/types/src/extensions/selection.test.d.ts.map +0 -1
  452. package/dist/types/src/extensions/snippets.d.ts.map +0 -1
  453. package/dist/types/src/extensions/spacing.d.ts.map +0 -1
  454. package/dist/types/src/extensions/state.d.ts +0 -2
  455. package/dist/types/src/extensions/state.d.ts.map +0 -1
  456. package/dist/types/src/extensions/submit.d.ts.map +0 -1
  457. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +0 -1
  458. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts.map +0 -1
  459. package/dist/types/src/extensions/tags/index.d.ts.map +0 -1
  460. package/dist/types/src/extensions/tags/stub.d.ts +0 -35
  461. package/dist/types/src/extensions/tags/stub.d.ts.map +0 -1
  462. package/dist/types/src/extensions/tags/widgets/anchor.d.ts.map +0 -1
  463. package/dist/types/src/extensions/tags/widgets/index.d.ts.map +0 -1
  464. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts +0 -31
  465. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts.map +0 -1
  466. package/dist/types/src/extensions/tags/xml-formatting.d.ts.map +0 -1
  467. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +0 -1
  468. package/dist/types/src/extensions/tags/xml-util.d.ts.map +0 -1
  469. package/dist/types/src/extensions/tags/xml-util.test.d.ts.map +0 -1
  470. package/dist/types/src/extensions/typewriter.d.ts.map +0 -1
  471. package/dist/types/src/extensions/typewriter.test.d.ts.map +0 -1
  472. package/src/extensions/autocomplete/typeahead.ts +0 -87
  473. package/src/extensions/blocks.ts +0 -131
  474. package/src/extensions/markdown/link.ts +0 -49
  475. package/src/extensions/outliner/editor.test.ts +0 -33
  476. package/src/extensions/outliner/outliner.test.ts +0 -99
  477. package/src/extensions/outliner/outliner.ts +0 -166
  478. package/src/extensions/outliner/selection.ts +0 -50
  479. package/src/extensions/state.ts +0 -7
  480. package/src/extensions/tags/stub.ts +0 -80
  481. package/src/extensions/tags/xml-block-decoration.ts +0 -123
  482. package/dist/types/src/extensions/{dnd.d.ts → behavior/dnd.d.ts} +0 -0
  483. package/dist/types/src/extensions/{submit.d.ts → behavior/submit.d.ts} +0 -0
  484. package/dist/types/src/extensions/{automerge → collab/automerge}/automerge.d.ts +0 -0
  485. package/dist/types/src/extensions/{automerge → collab/automerge}/automerge.test.d.ts +0 -0
  486. package/dist/types/src/extensions/{automerge → collab/automerge}/sync.d.ts +0 -0
  487. package/dist/types/src/extensions/{awareness → collab/awareness}/awareness-provider.d.ts +0 -0
  488. package/dist/types/src/extensions/{awareness → collab/awareness}/index.d.ts +0 -0
  489. package/dist/types/src/extensions/{autocomplete → completion}/autocomplete.d.ts +0 -0
  490. package/dist/types/src/extensions/{autocomplete → completion}/placeholder.d.ts +0 -0
  491. package/dist/types/src/extensions/{factories.test.d.ts → core/factories.test.d.ts} +0 -0
  492. package/dist/types/src/extensions/{fader.d.ts → decoration/fader.d.ts} +0 -0
  493. package/dist/types/src/extensions/{marker.d.ts → decoration/marker.d.ts} +0 -0
  494. package/dist/types/src/extensions/{pos.test.d.ts → decoration/pos.test.d.ts} +0 -0
  495. package/dist/types/src/extensions/{replacer.test.d.ts → decoration/replacer.test.d.ts} +0 -0
  496. package/dist/types/src/extensions/{snippets.d.ts → demo/snippets.d.ts} +0 -0
  497. package/dist/types/src/extensions/{markdown → language/markdown}/action.d.ts +0 -0
  498. package/dist/types/src/extensions/{markdown → language/markdown}/bundle.d.ts +0 -0
  499. package/dist/types/src/extensions/{markdown → language/markdown}/changes.test.d.ts +0 -0
  500. package/dist/types/src/extensions/{markdown → language/markdown}/formatting.test.d.ts +0 -0
  501. package/dist/types/src/extensions/{markdown → language/markdown}/image.d.ts +0 -0
  502. package/dist/types/src/extensions/{markdown → language/markdown}/image.test.d.ts +0 -0
  503. package/dist/types/src/extensions/{markdown → language/markdown}/index.d.ts +0 -0
  504. package/dist/types/src/extensions/{markdown → language/markdown}/parser.test.d.ts +0 -0
  505. package/dist/types/src/extensions/{markdown → language/markdown}/table.d.ts +0 -0
  506. package/dist/types/src/extensions/{tags → language/xml}/extended-markdown.d.ts +0 -0
  507. package/dist/types/src/extensions/{tags → language/xml}/extended-markdown.test.d.ts +0 -0
  508. package/dist/types/src/extensions/{tags → language/xml}/index.d.ts +0 -0
  509. package/dist/types/src/extensions/{tags → language/xml}/widgets/anchor.d.ts +0 -0
  510. package/dist/types/src/extensions/{tags → language/xml}/widgets/index.d.ts +0 -0
  511. package/dist/types/src/extensions/{tags → language/xml}/xml-formatting.d.ts +0 -0
  512. package/dist/types/src/extensions/{tags → language/xml}/xml-util.d.ts +0 -0
  513. package/dist/types/src/extensions/{tags → language/xml}/xml-util.test.d.ts +0 -0
  514. package/dist/types/src/extensions/{modal.d.ts → state/modal.d.ts} +0 -0
  515. package/dist/types/src/extensions/{selection.test.d.ts → state/selection.test.d.ts} +0 -0
  516. package/dist/types/src/extensions/{pending → streaming/pending}/index.d.ts +0 -0
  517. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text-stream.d.ts +0 -0
  518. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text-stream.test.d.ts +0 -0
  519. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text.test.d.ts +0 -0
  520. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/auto-scroll.d.ts +0 -0
  521. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/crawler.d.ts +0 -0
  522. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/index.d.ts +0 -0
  523. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/scrollbar-autohide.d.ts +0 -0
  524. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/scroller.d.ts +0 -0
  525. package/dist/types/src/extensions/{typewriter.test.d.ts → streaming/typewriter.test.d.ts} +0 -0
  526. package/dist/types/src/extensions/{folding.d.ts → structure/folding/folding.d.ts} +0 -0
  527. package/dist/types/src/extensions/{outliner → structure/outliner}/editor.d.ts +0 -0
  528. package/dist/types/src/extensions/{outliner → structure/outliner}/editor.test.d.ts +0 -0
  529. package/dist/types/src/extensions/{outliner → structure/outliner}/outliner.d.ts +0 -0
  530. package/dist/types/src/extensions/{outliner → structure/outliner}/outliner.test.d.ts +0 -0
  531. package/dist/types/src/extensions/{outliner → structure/outliner}/tree.test.d.ts +0 -0
  532. package/src/extensions/{dnd.ts → behavior/dnd.ts} +29 -29
  533. package/src/extensions/{awareness → collab/awareness}/index.ts +0 -0
  534. package/src/extensions/{factories.test.ts → core/factories.test.ts} +0 -0
  535. package/src/extensions/{replacer.test.ts → decoration/replacer.test.ts} +0 -0
  536. package/src/extensions/{replacer.ts → decoration/replacer.ts} +25 -25
  537. /package/src/extensions/{markdown → language/markdown}/index.ts +0 -0
  538. /package/src/extensions/{tags → language/xml}/index.ts +0 -0
  539. /package/src/extensions/{tags → language/xml}/testing/text.md +0 -0
  540. /package/src/extensions/{tags → language/xml}/testing/text.txt +0 -0
  541. /package/src/extensions/{tags → language/xml}/widgets/anchor.ts +0 -0
  542. /package/src/extensions/{tags → language/xml}/widgets/index.ts +0 -0
  543. /package/src/extensions/{tags → language/xml}/xml-util.ts +0 -0
  544. /package/src/extensions/{modal.ts → state/modal.ts} +0 -0
  545. /package/src/extensions/{selection.test.ts → state/selection.test.ts} +0 -0
  546. /package/src/extensions/{pending → streaming/pending}/index.ts +0 -0
  547. /package/src/extensions/{pending → streaming/pending}/pending-text-stream.test.ts +0 -0
  548. /package/src/extensions/{scrolling → streaming/scrolling}/crawler.ts +0 -0
  549. /package/src/extensions/{scrolling → streaming/scrolling}/index.ts +0 -0
  550. /package/src/extensions/{scrolling → streaming/scrolling}/scroller.ts +0 -0
  551. /package/src/extensions/{typewriter.test.ts → streaming/typewriter.test.ts} +0 -0
@@ -0,0 +1,405 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import {
8
+ type DiffHunk,
9
+ cherryPickHunk,
10
+ computeCharHunks,
11
+ computeHunks,
12
+ diffHunks,
13
+ groupHunks,
14
+ pairMarkupHunks,
15
+ rebaseHunks,
16
+ rebaseHunksWith,
17
+ revertHunk,
18
+ } from './diff';
19
+
20
+ describe('diff hunks', () => {
21
+ const original = ['# Title', '', 'Line one.', 'Line two.', ''].join('\n');
22
+ const modified = ['# Title', '', 'Line one CHANGED.', 'Line two.', 'Line three ADDED.', ''].join('\n');
23
+
24
+ test('computeHunks finds changed regions', ({ expect }) => {
25
+ const hunks = computeHunks(original, modified);
26
+ expect(hunks.length).toBeGreaterThan(0);
27
+ // Every hunk has consistent A/B ranges.
28
+ for (const hunk of hunks) {
29
+ expect(hunk.toA).toBeGreaterThanOrEqual(hunk.fromA);
30
+ expect(hunk.toB).toBeGreaterThanOrEqual(hunk.fromB);
31
+ }
32
+ });
33
+
34
+ test('cherryPickHunk resolves only the anchored word hunk, not the whole line or other changes', ({ expect }) => {
35
+ // Range over the changed word "CHANGED" in the modified (current) text.
36
+ const start = modified.indexOf('CHANGED');
37
+ const splice = cherryPickHunk(modified, original, { start, end: start + 'CHANGED'.length });
38
+ expect(splice).toBeDefined();
39
+ if (!splice) {
40
+ return;
41
+ }
42
+ // Applying the splice to `modified` reverts that hunk to `original`.
43
+ const applied = modified.slice(0, splice.from) + splice.insert + modified.slice(splice.from + splice.del);
44
+ expect(applied).toContain('Line one.');
45
+ expect(applied).not.toContain('CHANGED');
46
+ // Word-level: the separate change on another line is untouched (would break with line granularity).
47
+ expect(applied).toContain('Line three ADDED.');
48
+ });
49
+
50
+ test('reflects the latest compare text, not a snapshot', ({ expect }) => {
51
+ const start = modified.indexOf('CHANGED');
52
+ const range = { start, end: start + 'CHANGED'.length };
53
+
54
+ // First compare version does not carry the later edit.
55
+ const v1 = cherryPickHunk(modified, original, range);
56
+ expect(v1?.insert).not.toContain('EDITED AGAIN');
57
+
58
+ // Compare text edited further; cherry-pick now yields the NEWER version.
59
+ const originalV2 = ['# Title', '', 'Line one EDITED AGAIN.', 'Line two.', ''].join('\n');
60
+ const v2 = cherryPickHunk(modified, originalV2, range);
61
+ expect(v2?.insert).toContain('EDITED AGAIN');
62
+ });
63
+
64
+ test('returns undefined when the range is not on a changed hunk', ({ expect }) => {
65
+ // "Line two." is identical in both → no hunk there.
66
+ const start = modified.indexOf('Line two');
67
+ expect(cherryPickHunk(modified, original, { start, end: start + 4 })).toBeUndefined();
68
+ });
69
+
70
+ test('revertHunk reverts the branch hunk at a base-side range back to base', ({ expect }) => {
71
+ const base = 'alpha\nbravo\ncharlie\n';
72
+ const branch = 'alpha\nBRAVO\ncharlie\n';
73
+ // Range over 'bravo' in the base.
74
+ const start = base.indexOf('bravo');
75
+ const splice = revertHunk(base, branch, { start, end: start + 5 });
76
+ expect(splice).toBeDefined();
77
+ if (!splice) {
78
+ return;
79
+ }
80
+ // Applying the splice to the branch restores the base text at that hunk.
81
+ const applied = branch.slice(0, splice.from) + splice.insert + branch.slice(splice.from + splice.del);
82
+ expect(applied).toBe(base);
83
+ });
84
+
85
+ test('revertHunk returns undefined when the base range is not on a changed hunk', ({ expect }) => {
86
+ const base = 'alpha\nbravo\ncharlie\n';
87
+ const branch = 'alpha\nBRAVO\ncharlie\n';
88
+ const start = base.indexOf('charlie');
89
+ expect(revertHunk(base, branch, { start, end: start + 4 })).toBeUndefined();
90
+ });
91
+
92
+ // A pure insertion is empty on the base side, and the review companion anchors it at that single
93
+ // offset — so both sides of the overlap test are zero-width. A strict half-open test never matches,
94
+ // which made Accept/Reject silently no-op for every suggestion that only adds text.
95
+ test('accepts and reverts a pure insertion anchored at an empty range', ({ expect }) => {
96
+ const base = 'alpha\nbravo\n';
97
+ const branch = 'alpha\nbravo\ncharlie\n';
98
+ const at = base.length;
99
+
100
+ // Accept: splice the branch's added line into the base.
101
+ const accept = cherryPickHunk(base, branch, { start: at, end: at });
102
+ expect(accept).toBeDefined();
103
+ if (!accept) {
104
+ return;
105
+ }
106
+ expect(base.slice(0, accept.from) + accept.insert + base.slice(accept.from + accept.del)).toBe(branch);
107
+
108
+ // Reject: strip the addition back off the branch.
109
+ const revert = revertHunk(base, branch, { start: at, end: at });
110
+ expect(revert).toBeDefined();
111
+ if (!revert) {
112
+ return;
113
+ }
114
+ expect(branch.slice(0, revert.from) + revert.insert + branch.slice(revert.from + revert.del)).toBe(base);
115
+ });
116
+ });
117
+
118
+ describe('pairMarkupHunks', () => {
119
+ test('a multi-word bold wrap coalesces into one atomic replace', ({ expect }) => {
120
+ const before = 'alpha bravo charlie delta.';
121
+ const hunks = diffHunks(before, 'alpha **bravo charlie** delta.');
122
+ expect(hunks).toHaveLength(2);
123
+ const paired = pairMarkupHunks(hunks, before);
124
+ expect(paired).toHaveLength(1);
125
+ expect(paired[0].removed).toBe('bravo charlie');
126
+ expect(paired[0].inserted).toBe('**bravo charlie**');
127
+ });
128
+
129
+ test('a single-word wrap is already one hunk and passes through', ({ expect }) => {
130
+ const before = 'alpha bravo charlie';
131
+ const hunks = pairMarkupHunks(diffHunks(before, 'alpha **bravo** charlie'), before);
132
+ expect(hunks).toHaveLength(1);
133
+ expect(hunks[0].inserted).toBe('**bravo**');
134
+ });
135
+
136
+ test('does not bridge across a line break or pair unrelated inserts', ({ expect }) => {
137
+ const before = 'alpha\nbravo';
138
+ const hunks = diffHunks(before, '**alpha\nbravo**');
139
+ expect(pairMarkupHunks(hunks, before)).toHaveLength(2);
140
+ const unrelated = diffHunks('one two three', 'one X two Y three');
141
+ expect(pairMarkupHunks(unrelated, 'one two three')).toHaveLength(2);
142
+ });
143
+
144
+ test('cherry-picking a pair-spanning range applies the whole pair', ({ expect }) => {
145
+ const current = 'alpha bravo charlie delta.';
146
+ const compare = 'alpha **bravo charlie** delta.';
147
+ // The paired hunk's range in `current` covers the wrapped words.
148
+ const splice = cherryPickHunk(current, compare, { start: 6, end: 19 });
149
+ expect(splice).toBeDefined();
150
+ const applied = current.slice(0, splice!.from) + splice!.insert + current.slice(splice!.from + splice!.del);
151
+ expect(applied).toBe(compare);
152
+ });
153
+ });
154
+
155
+ describe('diffHunks', () => {
156
+ /** Apply every hunk's replacement to `before` (right-to-left so earlier offsets stay valid). */
157
+ const applyAll = (before: string, hunks: DiffHunk[]): string =>
158
+ [...hunks]
159
+ .sort((a, b) => b.from - a.from)
160
+ .reduce((text, hunk) => text.slice(0, hunk.from) + hunk.inserted + text.slice(hunk.to), before);
161
+
162
+ test('anchors ranges in the before text', ({ expect }) => {
163
+ const before = 'the quick fox';
164
+ const hunks = diffHunks(before, 'the slow fox');
165
+ expect(hunks).toHaveLength(1);
166
+ expect(before.slice(hunks[0].from, hunks[0].to)).toBe(hunks[0].removed);
167
+ expect(hunks[0].removed).toBe('quick');
168
+ expect(hunks[0].inserted).toBe('slow');
169
+ });
170
+
171
+ test('a pure insertion is a zero-width hunk', ({ expect }) => {
172
+ const hunks = diffHunks('one three', 'one two three');
173
+ expect(hunks).toHaveLength(1);
174
+ expect(hunks[0].from).toBe(hunks[0].to);
175
+ expect(hunks[0].removed).toBe('');
176
+ expect(hunks[0].inserted).toBe('two ');
177
+ });
178
+
179
+ test('an insert adjacent to identical text stays a pure insertion (minimal hunk)', ({ expect }) => {
180
+ // Word-level diffing sees `WorldHello` -> `WorldHelloWorld` as one changed word; the hunk must
181
+ // still not claim the unchanged `WorldHello` — a replace here strikes real document text and
182
+ // re-inserts it, which renders as doubled content.
183
+ const before = '# Hello WorldHello\n\n';
184
+ const hunks = diffHunks(before, '# Hello WorldHelloWorld\n\n');
185
+ expect(hunks).toHaveLength(1);
186
+ expect(hunks[0].removed).toBe('');
187
+ expect(hunks[0].inserted).toBe('World');
188
+ expect(hunks[0].from).toBe(hunks[0].to);
189
+ expect(applyAll(before, hunks)).toBe('# Hello WorldHelloWorld\n\n');
190
+ });
191
+
192
+ test('a delete adjacent to identical text stays a pure deletion (minimal hunk)', ({ expect }) => {
193
+ const before = '# Hello WorldHelloWorld\n\n';
194
+ const hunks = diffHunks(before, '# Hello WorldHello\n\n');
195
+ expect(hunks).toHaveLength(1);
196
+ expect(hunks[0].inserted).toBe('');
197
+ expect(hunks[0].removed).toBe('World');
198
+ expect(applyAll(before, hunks)).toBe('# Hello WorldHello\n\n');
199
+ });
200
+
201
+ test('a genuine word replace keeps word granularity (no mid-word trim)', ({ expect }) => {
202
+ const before = 'the lazy dog';
203
+ const hunks = diffHunks(before, 'the lively dog');
204
+ expect(hunks).toHaveLength(1);
205
+ expect(hunks[0].removed).toBe('lazy');
206
+ expect(hunks[0].inserted).toBe('lively');
207
+ });
208
+
209
+ test('a pure deletion has no inserted text', ({ expect }) => {
210
+ const hunks = diffHunks('one two three', 'one three');
211
+ expect(hunks).toHaveLength(1);
212
+ expect(hunks[0].inserted).toBe('');
213
+ expect(hunks[0].removed).toBe('two ');
214
+ });
215
+
216
+ test('separates changes bounded by unchanged text into distinct hunks', ({ expect }) => {
217
+ const before = 'alpha bravo charlie';
218
+ const hunks = diffHunks(before, 'ALPHA bravo CHARLIE');
219
+ expect(hunks).toHaveLength(2);
220
+ expect(hunks.every((hunk) => before.slice(hunk.from, hunk.to) === hunk.removed)).toBe(true);
221
+ });
222
+
223
+ test('applying every hunk reconstructs the after text', ({ expect }) => {
224
+ const cases: Array<[string, string]> = [
225
+ ['the quick brown fox', 'the slow brown cat'],
226
+ ['one three', 'one two three'],
227
+ ['one two three', 'one three'],
228
+ ['', 'abc def'],
229
+ ['abc def', ''],
230
+ ['same text', 'same text'],
231
+ ['a b c d e', 'a X c Y e'],
232
+ ];
233
+ for (const [before, after] of cases) {
234
+ expect(applyAll(before, diffHunks(before, after))).toBe(after);
235
+ }
236
+ });
237
+
238
+ test('handles empty inputs', ({ expect }) => {
239
+ expect(diffHunks('', '')).toEqual([]);
240
+ expect(diffHunks('same', 'same')).toEqual([]);
241
+ });
242
+ });
243
+
244
+ describe('rebaseHunks', () => {
245
+ test('maps hunks 1:1 when the doc equals the base', ({ expect }) => {
246
+ const base = 'The quick brown fox.';
247
+ const hunks = diffHunks(base, 'The slow brown fox.');
248
+ expect(rebaseHunks(base, base, hunks)).toEqual(hunks);
249
+ });
250
+
251
+ test('shifts a hunk after a doc insertion by the inserted length', ({ expect }) => {
252
+ const base = 'The quick brown fox.';
253
+ // The doc (branch) inserted "very " before "quick"; base offsets after it shift right by 5.
254
+ const doc = 'The very quick brown fox.';
255
+ const hunks = diffHunks(base, 'The quick brown cat.'); // fox -> cat, anchored in base.
256
+ const [hunk] = hunks;
257
+ const [rebased] = rebaseHunks(base, doc, hunks);
258
+ // The rebased hunk lands on "fox" in the diverged doc, not on the user's inserted "very".
259
+ expect(rebased.from).toBe(hunk.from + 'very '.length);
260
+ expect(doc.slice(rebased.from, rebased.to)).toBe(hunk.removed);
261
+ });
262
+
263
+ test('leaves a base hunk before a later doc insertion unshifted', ({ expect }) => {
264
+ const base = 'The quick brown fox.';
265
+ const doc = 'The quick brown fox. More text.'; // appended after the change region.
266
+ const hunks = diffHunks(base, 'The slow brown fox.'); // quick -> slow near the start.
267
+ const [rebased] = rebaseHunks(base, doc, hunks);
268
+ expect(rebased.from).toBe(hunks[0].from);
269
+ expect(doc.slice(rebased.from, rebased.to)).toBe(hunks[0].removed);
270
+ });
271
+
272
+ test('a doc insertion at a trailing pure-insert anchor stays BEHIND the proposal', ({ expect }) => {
273
+ // The author proposed "World\n" at the end of base; the user then typed "After" at that same
274
+ // spot on main. The proposal must stay anchored BEFORE the user's new text — mapping it past the
275
+ // insertion renders the user's input "in front" of the suggestion they typed after.
276
+ const base = '# Hello World\nHello\n';
277
+ const doc = '# Hello World\nHello\nAfter';
278
+ const hunks = diffHunks(base, '# Hello World\nHello\nWorld\n');
279
+ expect(hunks).toEqual([{ from: 20, to: 20, removed: '', inserted: 'World\n' }]);
280
+ const [rebased] = rebaseHunks(base, doc, hunks);
281
+ expect(rebased.from).toBe(20);
282
+ expect(rebased.to).toBe(20);
283
+ });
284
+
285
+ test('a zero-width (pure-insertion) hunk at a doc-edit boundary never inverts (from <= to)', ({ expect }) => {
286
+ // Bob inserts "!" right after "one" (a zero-width hunk at base offset 3); the user also inserts "X"
287
+ // at that same offset. Both endpoints of the zero-width hunk must map to the same doc offset, so the
288
+ // rebased range stays collapsed (from === to) rather than inverting.
289
+ const base = 'one two';
290
+ const doc = 'oneX two';
291
+ const hunks = diffHunks(base, 'one! two'); // Bob inserts "!" at offset 3 (from === to).
292
+ const [rebased] = rebaseHunks(base, doc, hunks);
293
+ expect(rebased.from).toBe(rebased.to);
294
+ expect(rebased.to).toBeGreaterThanOrEqual(rebased.from);
295
+ });
296
+
297
+ test('a foreign hunk ending exactly where a doc edit begins does not absorb the user text', ({ expect }) => {
298
+ // Bob deletes "one " (base offsets [0,4)); the user inserts "X" at offset 4, immediately after.
299
+ // The rebased strike must cover only "one ", never "one X" (the user's own adjacent character).
300
+ const base = 'one two';
301
+ const doc = 'one Xtwo';
302
+ const hunks = diffHunks(base, 'two'); // Bob removes the leading "one ".
303
+ const [rebased] = rebaseHunks(base, doc, hunks);
304
+ expect(doc.slice(rebased.from, rebased.to)).toBe('one ');
305
+ });
306
+
307
+ test('rebaseHunksWith with a precomputed char diff equals rebaseHunks (hoist parity)', ({ expect }) => {
308
+ // The hoisted path (compute the base↔doc char diff once, reuse across sources) must produce
309
+ // identical results to the per-call rebaseHunks — several sources over the same diverged doc.
310
+ const base = 'The quick brown fox jumps over the lazy dog.';
311
+ const doc = 'The very quick brown fox leaps over the lazy dog.';
312
+ const sources = ['The quick brown cat jumps over the lazy dog.', 'The quick brown fox jumps over the tired dog.'];
313
+ const charHunks = computeCharHunks(base, doc);
314
+ for (const source of sources) {
315
+ const hunks = diffHunks(base, source);
316
+ expect(rebaseHunksWith(charHunks, hunks)).toEqual(rebaseHunks(base, doc, hunks));
317
+ }
318
+ });
319
+ });
320
+
321
+ describe('groupHunks', () => {
322
+ /** Apply every hunk's replacement to `before` (right-to-left so earlier offsets stay valid). */
323
+ const applyAll = (before: string, hunks: DiffHunk[]): string =>
324
+ [...hunks]
325
+ .sort((a, b) => b.from - a.from)
326
+ .reduce((text, hunk) => text.slice(0, hunk.from) + hunk.inserted + text.slice(hunk.to), before);
327
+
328
+ test('default policy leaves each hunk its own group', ({ expect }) => {
329
+ const before = 'alpha bravo charlie';
330
+ const hunks = diffHunks(before, 'ALPHA bravo CHARLIE');
331
+ expect(groupHunks(hunks, before)).toEqual(hunks);
332
+ });
333
+
334
+ test('coalesces adjacent hunks within maxGap and still reconstructs after', ({ expect }) => {
335
+ const before = 'alpha bravo charlie';
336
+ const after = 'ALPHA bravo CHARLIE';
337
+ const hunks = diffHunks(before, after);
338
+ expect(hunks).toHaveLength(2);
339
+ // The gap between the two changes is ' bravo ' (7 chars); a maxGap covering it merges them.
340
+ const grouped = groupHunks(hunks, before, { maxGap: 7 });
341
+ expect(grouped).toHaveLength(1);
342
+ expect(before.slice(grouped[0].from, grouped[0].to)).toBe(grouped[0].removed);
343
+ expect(applyAll(before, grouped)).toBe(after);
344
+ });
345
+
346
+ test('respects block boundaries — a paragraph break is never bridged', ({ expect }) => {
347
+ const before = 'alpha\n\nbravo';
348
+ const after = 'ALPHA\n\nBRAVO';
349
+ const hunks = diffHunks(before, after);
350
+ expect(hunks).toHaveLength(2);
351
+ // Even with a maxGap wide enough for the gap, the blank line keeps the groups separate.
352
+ expect(groupHunks(hunks, before, { maxGap: 10 })).toHaveLength(2);
353
+ // Opting out of boundary-respect bridges them.
354
+ expect(groupHunks(hunks, before, { maxGap: 10, respectBlockBoundaries: false })).toHaveLength(1);
355
+ });
356
+ });
357
+
358
+ describe('computeCharHunks', () => {
359
+ // Character diffing is what keeps a single keystroke from restyling a whole word, but it aligns on
360
+ // any matching character — so deleting whole words can anchor mid-token (the `t` of `it` matching the
361
+ // `t` of `two`), striking half of two words the reader never touched.
362
+ test('a whole-word deletion anchors on word boundaries, not mid-token', ({ expect }) => {
363
+ const original = 'the revision it was written on, so two people can suggest';
364
+ const modified = 'the revision two people can suggest';
365
+
366
+ const hunks = computeCharHunks(original, modified);
367
+ expect(hunks).toHaveLength(1);
368
+ expect(original.slice(hunks[0].fromA, hunks[0].toA)).toBe('it was written on, so ');
369
+ });
370
+ });
371
+
372
+ describe('overlay hunks after the reader edits', () => {
373
+ const MAIN =
374
+ 'The editor now tracks suggestions from every collaborator at once. Each proposal is diffed against the revision it was written on, so two people can suggest changes.';
375
+ // Alice proposes replacing a run of words further along the paragraph.
376
+ const ALICE = MAIN.replace('it was written on, so two people can', 'the revision it was written on, so anyone may');
377
+
378
+ /** What the overlay renders: the proposal diffed against its anchor, rebased into doc coordinates. */
379
+ const overlayHunks = (doc: string) => rebaseHunksWith(computeCharHunks(MAIN, doc), diffHunks(MAIN, ALICE));
380
+
381
+ /** A struck span must not cut a word in half — `written` may not render as `wri` + struck `tten`. */
382
+ const splitsWord = (text: string, offset: number) =>
383
+ offset > 0 && offset < text.length && /\w/.test(text[offset - 1]) && /\w/.test(text[offset]);
384
+
385
+ test('a foreign strike keeps whole words when the reader edits inside a nearby word', ({ expect }) => {
386
+ // The reader corrects a typo inside `written` — a character-level edit in the middle of a word.
387
+ const doc = MAIN.replace('written', 'writtten');
388
+ for (const hunk of overlayHunks(doc)) {
389
+ if (hunk.to > hunk.from) {
390
+ expect(splitsWord(doc, hunk.from)).toBe(false);
391
+ expect(splitsWord(doc, hunk.to)).toBe(false);
392
+ }
393
+ }
394
+ });
395
+
396
+ test('a foreign strike keeps whole words when the reader deletes words before it', ({ expect }) => {
397
+ const doc = MAIN.replace('from every collaborator ', '');
398
+ for (const hunk of overlayHunks(doc)) {
399
+ if (hunk.to > hunk.from) {
400
+ expect(splitsWord(doc, hunk.from)).toBe(false);
401
+ expect(splitsWord(doc, hunk.to)).toBe(false);
402
+ }
403
+ }
404
+ });
405
+ });