@stll/folio-core 0.51.0 → 0.53.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 (316) hide show
  1. package/README.md +23 -0
  2. package/dist/ai-edits/apply.d.ts +26 -1
  3. package/dist/ai-edits/apply.js +1519 -105
  4. package/dist/ai-edits/batch-claims.d.ts +130 -0
  5. package/dist/ai-edits/batch-claims.js +244 -0
  6. package/dist/ai-edits/blockRange.js +9 -3
  7. package/dist/ai-edits/character-boundaries.d.ts +43 -0
  8. package/dist/ai-edits/character-boundaries.js +95 -0
  9. package/dist/ai-edits/clean-text.d.ts +33 -3
  10. package/dist/ai-edits/clean-text.js +52 -6
  11. package/dist/ai-edits/comment-lifecycle.d.ts +18 -0
  12. package/dist/ai-edits/comment-lifecycle.js +52 -0
  13. package/dist/ai-edits/headless.d.ts +71 -7
  14. package/dist/ai-edits/headless.js +381 -41
  15. package/dist/ai-edits/index.d.ts +2 -1
  16. package/dist/ai-edits/index.js +2 -1
  17. package/dist/ai-edits/minimal-replacement.d.ts +21 -6
  18. package/dist/ai-edits/minimal-replacement.js +134 -15
  19. package/dist/ai-edits/newListNumbering.d.ts +23 -0
  20. package/dist/ai-edits/newListNumbering.js +94 -0
  21. package/dist/ai-edits/note-references.d.ts +96 -0
  22. package/dist/ai-edits/note-references.js +139 -0
  23. package/dist/ai-edits/pending-suggestions.d.ts +79 -0
  24. package/dist/ai-edits/pending-suggestions.js +306 -0
  25. package/dist/ai-edits/read.d.ts +1 -1
  26. package/dist/ai-edits/read.js +56 -43
  27. package/dist/ai-edits/result-validation.d.ts +29 -0
  28. package/dist/ai-edits/result-validation.js +164 -0
  29. package/dist/ai-edits/snapshot.d.ts +36 -3
  30. package/dist/ai-edits/snapshot.js +177 -23
  31. package/dist/ai-edits/table-cell-mutations.d.ts +1 -1
  32. package/dist/ai-edits/table-cell-mutations.js +4 -1
  33. package/dist/ai-edits/table-geometry.d.ts +1 -1
  34. package/dist/ai-edits/table-row-column-mutations.d.ts +38 -16
  35. package/dist/ai-edits/table-row-column-mutations.js +61 -26
  36. package/dist/ai-edits/types.d.ts +155 -16
  37. package/dist/compare/compare.d.ts +1 -1
  38. package/dist/compare/compare.js +65 -16
  39. package/dist/compare/content-alignment.js +13 -2
  40. package/dist/compare/content-types.d.ts +7 -0
  41. package/dist/compare/content.d.ts +4 -1
  42. package/dist/compare/content.js +6 -1
  43. package/dist/compare/formatting.js +2 -1
  44. package/dist/compare/inline-atoms.d.ts +21 -4
  45. package/dist/compare/inline-atoms.js +138 -16
  46. package/dist/compare/inline-provenance.js +18 -22
  47. package/dist/compare/plan.js +10 -5
  48. package/dist/compare/scenario.js +14 -3
  49. package/dist/compare/section-boundary-properties.js +14 -1
  50. package/dist/compare/types.d.ts +4 -2
  51. package/dist/compare/types.js +2 -1
  52. package/dist/compare/verification.d.ts +1 -1
  53. package/dist/compare/verification.js +15 -3
  54. package/dist/controller/committedLayoutDiff.d.ts +25 -0
  55. package/dist/controller/committedLayoutDiff.js +71 -0
  56. package/dist/controller/contentControlWidgetController.d.ts +1 -1
  57. package/dist/controller/folioEditor.d.ts +1 -1
  58. package/dist/controller/fontReadiness.d.ts +70 -3
  59. package/dist/controller/fontReadiness.js +100 -10
  60. package/dist/controller/headerFooterEditorManager.js +6 -1
  61. package/dist/controller/layoutPipeline.d.ts +12 -10
  62. package/dist/controller/layoutPipeline.js +62 -9
  63. package/dist/controller/layoutRunOptions.d.ts +24 -0
  64. package/dist/controller/layoutRunOptions.js +17 -0
  65. package/dist/controller/layoutScheduler.d.ts +19 -14
  66. package/dist/controller/layoutScheduler.js +15 -12
  67. package/dist/controller/layoutSession.d.ts +26 -2
  68. package/dist/controller/layoutSession.js +1 -1
  69. package/dist/controller/noteEditorManager.js +8 -3
  70. package/dist/document-operations.d.ts +11 -2
  71. package/dist/document-operations.js +230 -21
  72. package/dist/docx/altChunk.d.ts +8 -0
  73. package/dist/docx/altChunk.js +17 -0
  74. package/dist/docx/attributeRemainder.d.ts +1 -1
  75. package/dist/docx/blockContentParser.d.ts +64 -1
  76. package/dist/docx/blockContentParser.js +17 -4
  77. package/dist/docx/blockCustomXmlShell.d.ts +7 -0
  78. package/dist/docx/blockCustomXmlShell.js +14 -0
  79. package/dist/docx/blockPlainText.js +7 -0
  80. package/dist/docx/commentAnchorIndex.js +1 -1
  81. package/dist/docx/commentRangeIntegrity.js +8 -3
  82. package/dist/docx/commentReferenceNormalization.js +1 -1
  83. package/dist/docx/commentReplyMarkers.js +20 -1
  84. package/dist/docx/compatibility.d.ts +1 -1
  85. package/dist/docx/compatibility.js +34 -13
  86. package/dist/docx/containerChildren.gen.d.ts +1 -1
  87. package/dist/docx/containerChildren.gen.js +1 -0
  88. package/dist/docx/documentParser.js +12 -12
  89. package/dist/docx/drawingIdNormalization.d.ts +3 -1
  90. package/dist/docx/drawingIdNormalization.js +6 -1
  91. package/dist/docx/ensureParaIds.js +119 -97
  92. package/dist/docx/footnoteParser.js +8 -4
  93. package/dist/docx/headerFooterParser.js +3 -3
  94. package/dist/docx/headerFooterReferenceNormalization.d.ts +20 -1
  95. package/dist/docx/headerFooterReferenceNormalization.js +52 -27
  96. package/dist/docx/hyperlinkParser.d.ts +1 -1
  97. package/dist/docx/index.d.ts +1 -1
  98. package/dist/docx/listNumberingInstances.d.ts +59 -0
  99. package/dist/docx/listNumberingInstances.js +249 -0
  100. package/dist/docx/normalizeBaseDirection.js +2 -1
  101. package/dist/docx/opaqueCarrier.d.ts +7 -0
  102. package/dist/docx/opaqueCarrier.js +38 -0
  103. package/dist/docx/packageParts.js +4 -1
  104. package/dist/docx/paragraphParser.js +91 -24
  105. package/dist/docx/paragraphPropertySource.d.ts +4 -2
  106. package/dist/docx/paragraphPropertySource.js +7 -1
  107. package/dist/docx/paragraphTraversal.js +1 -0
  108. package/dist/docx/parseWarningMessage.js +4 -1
  109. package/dist/docx/parser.js +173 -20
  110. package/dist/docx/rezip.js +27 -5
  111. package/dist/docx/sdtProperties.js +1 -1
  112. package/dist/docx/sdtPropertiesPatch.js +3 -0
  113. package/dist/docx/selectiveSave.js +16 -9
  114. package/dist/docx/selectiveXmlPatch.js +106 -37
  115. package/dist/docx/serializer/blockCustomXmlSerializer.d.ts +5 -0
  116. package/dist/docx/serializer/blockCustomXmlSerializer.js +4 -0
  117. package/dist/docx/serializer/documentSerializer.js +2 -0
  118. package/dist/docx/serializer/headerFooterSerializer.js +2 -0
  119. package/dist/docx/serializer/noteSerializer.js +3 -1
  120. package/dist/docx/serializer/paragraphSerializer.js +33 -9
  121. package/dist/docx/serializer/tableSerializer.js +25 -38
  122. package/dist/docx/server/createBilingualDocument.js +3 -3
  123. package/dist/docx/tableParser.d.ts +157 -1
  124. package/dist/docx/tableParser.js +89 -10
  125. package/dist/docx/textBoxParser.js +1 -1
  126. package/dist/docx/unzip.d.ts +2 -1
  127. package/dist/docx/unzip.js +1 -1
  128. package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
  129. package/dist/docx/wordprocessingPrefixes.js +286 -0
  130. package/dist/generated/text_shaper.js +26 -0
  131. package/dist/generated/text_shaper_bg.wasm +0 -0
  132. package/dist/i18n/messages/catalogs.gen.d.ts +136 -0
  133. package/dist/i18n/messages/catalogs.gen.js +153 -17
  134. package/dist/i18n/messages/messages.gen.d.ts +8 -0
  135. package/dist/internal/compare/inline-presentation.d.ts +2 -1
  136. package/dist/internal/compare/inline-presentation.js +11 -10
  137. package/dist/internal/headlessRevisionResolutionGuard.d.ts +2 -8
  138. package/dist/internal/headlessRevisionResolutionGuard.js +2 -11
  139. package/dist/internal/indexedPositionMap.d.ts +11 -0
  140. package/dist/internal/indexedPositionMap.js +42 -0
  141. package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
  142. package/dist/internal/revisionResolutionEdits.d.ts +13 -0
  143. package/dist/internal/revisionResolutionEdits.js +19 -0
  144. package/dist/internal/revisionResolutionInline.d.ts +24 -0
  145. package/dist/internal/{headlessRevisionResolution.js → revisionResolutionInline.js} +61 -43
  146. package/dist/internal/revisionResolutionStep.d.ts +34 -0
  147. package/dist/internal/revisionResolutionStep.js +282 -0
  148. package/dist/internal/revisionResolutionTracking.d.ts +11 -0
  149. package/dist/internal/revisionResolutionTracking.js +124 -0
  150. package/dist/internal/wholeStoryRevisionResolution.d.ts +56 -0
  151. package/dist/internal/wholeStoryRevisionResolution.js +530 -0
  152. package/dist/layout-bridge/convert/markupViewFlow.d.ts +20 -0
  153. package/dist/layout-bridge/convert/markupViewFlow.js +123 -0
  154. package/dist/layout-bridge/convert/tableConversion.js +1 -1
  155. package/dist/layout-bridge/convert/toFlowBlocks.js +10 -1
  156. package/dist/layout-engine/layoutInstrumentation.d.ts +9 -1
  157. package/dist/layout-engine/layoutInstrumentation.js +4 -1
  158. package/dist/layout-engine/measure/cache.d.ts +18 -1
  159. package/dist/layout-engine/measure/cache.js +31 -1
  160. package/dist/layout-engine/measure/font-metrics.worker.js +3 -7
  161. package/dist/layout-engine/measure/measureContainer.js +7 -47
  162. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -1
  163. package/dist/layout-engine/measure/measureHelpers.js +22 -2
  164. package/dist/layout-engine/measure/measureWorker.js +2 -3
  165. package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +6 -7
  166. package/dist/layout-engine/measure/measureWorkerProtocol.js +1 -2
  167. package/dist/layout-engine/types.d.ts +6 -0
  168. package/dist/layout-painter/renderPage.js +1 -0
  169. package/dist/layout-painter/renderParagraph.js +1 -1
  170. package/dist/managers/ContextMenuManager.js +5 -2
  171. package/dist/managers/types.d.ts +3 -0
  172. package/dist/markdown/fromMarkdown.js +2 -1
  173. package/dist/markdown/internals.d.ts +11 -1
  174. package/dist/markdown/internals.js +24 -3
  175. package/dist/markdown/renderBlock.js +39 -9
  176. package/dist/markdown/renderParagraph.d.ts +13 -1
  177. package/dist/markdown/renderParagraph.js +85 -38
  178. package/dist/markdown/renderRuns.js +3 -10
  179. package/dist/markdown/renderTable.js +24 -12
  180. package/dist/markdown/trailers.js +2 -2
  181. package/dist/markdown/types.d.ts +29 -7
  182. package/dist/paged-layout/incrementalMeasure.d.ts +1 -2
  183. package/dist/paged-layout/incrementalMeasure.js +1 -9
  184. package/dist/paged-layout/transactionDirtyRange.d.ts +1 -3
  185. package/dist/paged-layout/transactionDirtyRange.js +29 -41
  186. package/dist/panel-layout.d.ts +83 -0
  187. package/dist/panel-layout.js +96 -0
  188. package/dist/prosemirror/anchoredTextBoxes.d.ts +37 -0
  189. package/dist/prosemirror/anchoredTextBoxes.js +156 -0
  190. package/dist/prosemirror/attrs/index.d.ts +6 -2
  191. package/dist/prosemirror/attrs/index.js +172 -1
  192. package/dist/prosemirror/commands/comments.d.ts +7 -8
  193. package/dist/prosemirror/commands/comments.js +241 -207
  194. package/dist/prosemirror/commands/contentControls.d.ts +1 -1
  195. package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
  196. package/dist/prosemirror/commands/formatting.d.ts +1 -1
  197. package/dist/prosemirror/commands/index.d.ts +2 -2
  198. package/dist/prosemirror/commands/index.js +2 -2
  199. package/dist/prosemirror/commands/paragraph.d.ts +7 -1
  200. package/dist/prosemirror/commands/paragraph.js +9 -1
  201. package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +13 -0
  202. package/dist/prosemirror/commands/paragraphBookmarkJoin.js +22 -0
  203. package/dist/prosemirror/commands/pastePlainText.d.ts +1 -1
  204. package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
  205. package/dist/prosemirror/commands/resolveAllTableChanges.js +615 -0
  206. package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.d.ts +15 -0
  207. package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.js +46 -0
  208. package/dist/prosemirror/commands/resolveParagraphProperties.d.ts +16 -0
  209. package/dist/prosemirror/commands/resolveParagraphProperties.js +59 -0
  210. package/dist/prosemirror/commands/sectionBreak.js +2 -1
  211. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -2
  212. package/dist/prosemirror/commands/tableCellMergeResolution.js +1 -1
  213. package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
  214. package/dist/prosemirror/conversion/fromProseDoc.js +181 -31
  215. package/dist/prosemirror/conversion/toProseDoc.js +39 -4
  216. package/dist/prosemirror/emptyFieldResultRuns.d.ts +18 -0
  217. package/dist/prosemirror/emptyFieldResultRuns.js +33 -0
  218. package/dist/prosemirror/extensions/ExtensionManager.d.ts +1 -1
  219. package/dist/prosemirror/extensions/ExtensionManager.js +3 -1
  220. package/dist/prosemirror/extensions/StarterKit.js +3 -1
  221. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  222. package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -0
  223. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +3 -0
  224. package/dist/prosemirror/extensions/features/ListExtension.js +161 -123
  225. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +19 -2
  226. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +33 -20
  227. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +31 -2
  228. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +270 -99
  229. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +3 -2
  230. package/dist/prosemirror/extensions/features/pasteCleanup.js +2 -1
  231. package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
  232. package/dist/prosemirror/extensions/features/pastedHtmlLists.js +126 -0
  233. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +21 -5
  234. package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
  235. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
  236. package/dist/prosemirror/extensions/marks/markUtils.d.ts +7 -2
  237. package/dist/prosemirror/extensions/marks/markUtils.js +8 -2
  238. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +10 -0
  239. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +35 -0
  240. package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.d.ts +6 -0
  241. package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.js +52 -0
  242. package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
  243. package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
  244. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +4 -1
  245. package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
  246. package/dist/prosemirror/extensions/nodes/TableExtension.js +19 -18
  247. package/dist/prosemirror/extensions/types.d.ts +4 -1
  248. package/dist/prosemirror/findReplaceSelection.js +1 -1
  249. package/dist/prosemirror/index.d.ts +3 -2
  250. package/dist/prosemirror/index.js +3 -2
  251. package/dist/prosemirror/indexedNodeLookup.d.ts +17 -0
  252. package/dist/prosemirror/indexedNodeLookup.js +103 -0
  253. package/dist/prosemirror/listAutoformatMarkers.d.ts +19 -0
  254. package/dist/prosemirror/listAutoformatMarkers.js +98 -0
  255. package/dist/prosemirror/listInstanceReferences.d.ts +12 -0
  256. package/dist/prosemirror/listInstanceReferences.js +72 -0
  257. package/dist/prosemirror/listLabels.d.ts +24 -0
  258. package/dist/prosemirror/listLabels.js +111 -0
  259. package/dist/prosemirror/listNumbering.d.ts +110 -0
  260. package/dist/prosemirror/listNumbering.js +345 -0
  261. package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
  262. package/dist/prosemirror/listRenderingAttrs.js +8 -1
  263. package/dist/prosemirror/markupViewProjection.d.ts +95 -0
  264. package/dist/prosemirror/markupViewProjection.js +83 -0
  265. package/dist/prosemirror/numberingAttr.d.ts +9 -1
  266. package/dist/prosemirror/numberingAttr.js +9 -1
  267. package/dist/prosemirror/outlineLevelAttr.js +1 -1
  268. package/dist/prosemirror/paragraphIndentation.d.ts +10 -1
  269. package/dist/prosemirror/paragraphIndentation.js +29 -7
  270. package/dist/prosemirror/paragraphMarkJoin.d.ts +19 -0
  271. package/dist/prosemirror/paragraphMarkJoin.js +24 -0
  272. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +1 -1
  273. package/dist/prosemirror/plugins/documentNumbering.d.ts +27 -1
  274. package/dist/prosemirror/plugins/documentNumbering.js +97 -11
  275. package/dist/prosemirror/plugins/documentStyles.d.ts +10 -1
  276. package/dist/prosemirror/plugins/documentStyles.js +14 -1
  277. package/dist/prosemirror/plugins/suggestionMode.d.ts +16 -2
  278. package/dist/prosemirror/plugins/suggestionMode.js +116 -52
  279. package/dist/prosemirror/plugins/templateDirectives.d.ts +1 -1
  280. package/dist/prosemirror/plugins/transactionInvariants.d.ts +32 -0
  281. package/dist/prosemirror/plugins/transactionInvariants.js +86 -0
  282. package/dist/prosemirror/positionSweep.d.ts +24 -0
  283. package/dist/prosemirror/positionSweep.js +222 -0
  284. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +1 -1
  285. package/dist/prosemirror/rejoinRunCarriers.d.ts +1 -1
  286. package/dist/prosemirror/replacedAnnotations.d.ts +33 -1
  287. package/dist/prosemirror/replacedAnnotations.js +170 -1
  288. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
  289. package/dist/prosemirror/runStyleFormatting.d.ts +7 -1
  290. package/dist/prosemirror/runStyleFormatting.js +13 -7
  291. package/dist/prosemirror/schema/index.d.ts +2 -2
  292. package/dist/prosemirror/schema/index.js +3 -0
  293. package/dist/prosemirror/schema/nodes.d.ts +42 -11
  294. package/dist/prosemirror/sectionMarkEdits.d.ts +20 -0
  295. package/dist/prosemirror/sectionMarkEdits.js +59 -0
  296. package/dist/prosemirror/storyListNumbering.d.ts +17 -0
  297. package/dist/prosemirror/storyListNumbering.js +102 -0
  298. package/dist/prosemirror/tableGridMutation.d.ts +48 -2
  299. package/dist/prosemirror/tableGridMutation.js +106 -1
  300. package/dist/prosemirror/validation.js +5 -1
  301. package/dist/redline.js +93 -9
  302. package/dist/render-dom/BodySelectionOverlay.d.ts +4 -1
  303. package/dist/render-dom/BodySelectionOverlay.js +3 -2
  304. package/dist/shaping/shaper.d.ts +47 -4
  305. package/dist/shaping/shaper.js +46 -15
  306. package/dist/text-shaping.d.ts +4 -0
  307. package/dist/text-shaping.js +4 -0
  308. package/dist/utils/findReplace.js +2 -2
  309. package/dist/utils/mergeDocumentContent.js +1 -1
  310. package/dist/utils/noteReferenceLabels.d.ts +36 -0
  311. package/dist/utils/noteReferenceLabels.js +32 -0
  312. package/dist/utils/replaceText.js +1 -1
  313. package/dist/version-comparison.d.ts +1 -0
  314. package/dist/version-comparison.js +1 -0
  315. package/package.json +8 -2
  316. package/dist/internal/headlessRevisionResolution.d.ts +0 -23
@@ -1,8 +1,13 @@
1
+ import { withTrackedSectionEndpointRemoval } from "../../../internal/sectionEndpointResolution.js";
1
2
  import { canonicalJson } from "../../../utils/canonicalJson.js";
3
+ import { enclosingParagraphIndexed, nodeAtIndexed, nodesBetweenIndexed } from "../../indexedNodeLookup.js";
4
+ import { sweepPositions } from "../../positionSweep.js";
2
5
  import { sectionPropertiesOf } from "../../sectionCarrier.js";
6
+ import { sectionMarkEditsOf } from "../../sectionMarkEdits.js";
3
7
  import { createExtension } from "../create.js";
4
8
  import { AddMarkStep, AddNodeMarkStep, AttrStep, RemoveMarkStep, RemoveNodeMarkStep } from "prosemirror-transform";
5
9
  import { Plugin, PluginKey } from "prosemirror-state";
10
+ import { isHistoryTransaction } from "prosemirror-history";
6
11
  //#region src/prosemirror/extensions/features/ParagraphChangeTrackerExtension.ts
7
12
  const paragraphChangeTrackerKey = new PluginKey("paragraphChangeTracker");
8
13
  const CLEAR_META = "clear";
@@ -10,14 +15,16 @@ const IGNORE_META = "ignore";
10
15
  const STRUCTURAL_META = "structural";
11
16
  const CHANGED_PARAGRAPH_RANGES_META = "folioChangedParagraphRanges";
12
17
  const SECTION_ENDPOINT_REMOVAL_META = "folioSectionEndpointRemoval";
18
+ const SECTION_EDIT_META = "folioSectionEdit";
13
19
  const isChangedParagraphRangesMeta = (value) => typeof value === "object" && value !== null && "type" in value && value.type === "changed-paragraph-ranges";
14
20
  const isRemovedSectionReference = (value) => typeof value === "object" && value !== null && "part" in value && (value.part === "header" || value.part === "footer") && "type" in value && (value.type === "default" || value.type === "first" || value.type === "even") && "relationshipId" in value && typeof value.relationshipId === "string";
15
21
  const isTrackedSectionEndpointRemoval = (value) => typeof value === "object" && value !== null && "type" in value && value.type === "tracked-section-endpoint-removal" && "sourceParagraphEndpointCount" in value && typeof value.sourceParagraphEndpointCount === "number" && Number.isSafeInteger(value.sourceParagraphEndpointCount) && "expectedParagraphEndpointCount" in value && typeof value.expectedParagraphEndpointCount === "number" && Number.isSafeInteger(value.expectedParagraphEndpointCount) && value.sourceParagraphEndpointCount > value.expectedParagraphEndpointCount && value.expectedParagraphEndpointCount >= 0 && "sourceEndpointFingerprint" in value && typeof value.sourceEndpointFingerprint === "string" && "expectedEndpointFingerprint" in value && typeof value.expectedEndpointFingerprint === "string" && "removedReferences" in value && Array.isArray(value.removedReferences) && value.removedReferences.every(isRemovedSectionReference);
16
22
  const isTrackedSectionEndpointRemovalMeta = (value) => typeof value === "object" && value !== null && "type" in value && value.type === "tracked-section-endpoint-removal-meta" && "authorization" in value && isTrackedSectionEndpointRemoval(value.authorization);
23
+ const isSectionEditMeta = (value) => typeof value === "object" && value !== null && "type" in value && value.type === "section-edit-meta" && "authorization" in value && (value.authorization === null || isTrackedSectionEndpointRemoval(value.authorization)) && "expectedEndpointFingerprint" in value && typeof value.expectedEndpointFingerprint === "string";
17
24
  /** Count the structural values the tracker compares for every transaction. */
18
25
  function countDocumentStructure(doc) {
19
26
  let paragraphs = 0;
20
- let sectionEndpoints = 0;
27
+ const sectionRecords = /* @__PURE__ */ new Set();
21
28
  const blockRecords = [];
22
29
  const endpointRecords = [];
23
30
  const visit = (parent, parentPath) => {
@@ -36,7 +43,7 @@ function countDocumentStructure(doc) {
36
43
  paragraphs++;
37
44
  const sectionProperties = sectionPropertiesOf(node);
38
45
  if (sectionProperties !== null) {
39
- sectionEndpoints++;
46
+ sectionRecords.add(sectionProperties);
40
47
  endpointRecords.push({
41
48
  path: parentPath.length === 0 ? `${index}` : `${parentPath}.${index}`,
42
49
  paraId: node.attrs["paraId"] ?? null,
@@ -51,11 +58,21 @@ function countDocumentStructure(doc) {
51
58
  visit(doc, "");
52
59
  return {
53
60
  blockStructureFingerprint: JSON.stringify(blockRecords),
61
+ sectionRecords,
54
62
  paragraphs,
55
- sectionEndpoints,
63
+ sectionEndpoints: sectionRecords.size,
56
64
  sectionEndpointFingerprint: canonicalJson(endpointRecords)
57
65
  };
58
66
  }
67
+ /**
68
+ * Whether a transaction left every section record in place, by identity: the
69
+ * same sections, however their paragraphs moved around them. An edit before a
70
+ * section break (a paragraph inserted, a split, a paraId allocated) moves the
71
+ * endpoint without changing which sections the package states, so a removal
72
+ * authorized earlier still describes the saved section count exactly. A record
73
+ * edited, added or dropped is a new transition the authorization never saw.
74
+ */
75
+ const holdsTheSameSections = (previous, next) => previous.sectionRecords.size === next.sectionRecords.size && [...next.sectionRecords].every((record) => previous.sectionRecords.has(record));
59
76
  const isUsableParaId = (value) => typeof value === "string" && value.length > 0 && value !== "00000000";
60
77
  /**
61
78
  * Collect paraIds of all paragraphs that overlap with the given range
@@ -64,7 +81,8 @@ function collectAffectedParaIds(doc, from, to) {
64
81
  const ids = /* @__PURE__ */ new Set();
65
82
  const positions = /* @__PURE__ */ new Set();
66
83
  let hasUntracked = false;
67
- doc.nodesBetween(from, to, (node, pos) => {
84
+ const start = Math.max(0, Math.min(from, doc.content.size));
85
+ nodesBetweenIndexed(doc, start, Math.max(start, Math.min(to, doc.content.size)), (node, pos) => {
68
86
  if (node.type.name === "paragraph") {
69
87
  positions.add(pos);
70
88
  const paraId = node.attrs["paraId"];
@@ -88,17 +106,14 @@ function collectAffectedParaIdsFromMarkLikeStep(doc, from, to) {
88
106
  const hi = Math.max(from, to);
89
107
  const primary = collectAffectedParaIds(doc, lo, hi > lo ? hi : lo + 1);
90
108
  if (primary.ids.size > 0 || primary.hasUntracked) return primary;
91
- const $p = doc.resolve(lo);
92
- for (let depth = $p.depth; depth > 0; depth--) {
93
- const node = $p.node(depth);
94
- if (node.type.name === "paragraph") {
95
- const paraId = node.attrs["paraId"];
96
- return {
97
- ids: new Set(isUsableParaId(paraId) ? [paraId] : []),
98
- positions: /* @__PURE__ */ new Set([$p.before(depth)]),
99
- hasUntracked: !isUsableParaId(paraId)
100
- };
101
- }
109
+ const paragraph = enclosingParagraphIndexed(doc, lo);
110
+ if (paragraph) {
111
+ const paraId = paragraph.node.attrs["paraId"];
112
+ return {
113
+ ids: new Set(isUsableParaId(paraId) ? [paraId] : []),
114
+ positions: /* @__PURE__ */ new Set([paragraph.pos]),
115
+ hasUntracked: !isUsableParaId(paraId)
116
+ };
102
117
  }
103
118
  return {
104
119
  ids: /* @__PURE__ */ new Set(),
@@ -106,25 +121,78 @@ function collectAffectedParaIdsFromMarkLikeStep(doc, from, to) {
106
121
  hasUntracked: false
107
122
  };
108
123
  }
109
- /** Map an edited paragraph's interior so markup replacement retains its ownership. */
110
- const mapParagraphPosition = (tr, position) => {
111
- const mapped = tr.mapping.mapResult(position + 1, 1);
112
- if (mapped.deletedAcross) return null;
113
- const $position = tr.doc.resolve(mapped.pos);
114
- for (let depth = $position.depth; depth > 0; depth--) if ($position.node(depth).type.name === "paragraph") return $position.before(depth);
115
- return null;
116
- };
124
+ /**
125
+ * Map edited paragraphs' interiors so markup replacement retains their
126
+ * ownership: each position's paragraph in `tr.doc`, or null once deleted. The
127
+ * positions go through the transaction together (see `sweepPositions`).
128
+ */
129
+ const mapParagraphPositions = (tr, positions) => sweepPositions([tr.mapping], positions.map((position) => ({
130
+ pos: position + 1,
131
+ assoc: 1,
132
+ from: 0
133
+ }))).map((mapped) => mapped.deletedAcross ? null : enclosingParagraphIndexed(tr.doc, mapped.pos)?.pos ?? null);
117
134
  const mapAffectedParagraphPositions = (tr, positions) => {
118
135
  const mappedPositions = /* @__PURE__ */ new Set();
119
- for (const position of positions) {
120
- const mapped = mapParagraphPosition(tr, position);
121
- if (mapped !== null) mappedPositions.add(mapped);
122
- }
136
+ for (const mapped of mapParagraphPositions(tr, [...positions])) if (mapped !== null) mappedPositions.add(mapped);
123
137
  return mappedPositions;
124
138
  };
125
- function mapStepPosition(remap, pos, assoc) {
126
- return remap.map(pos, assoc);
127
- }
139
+ /**
140
+ * Every position the step loop reads, each entering the sweep at the step
141
+ * after the one that produced it: the transaction is mapped once rather than
142
+ * sliced and walked again for every step.
143
+ */
144
+ const mapStepTouches = (tr, batches) => {
145
+ const queries = [];
146
+ const touches = [];
147
+ const addRange = (kind, from, to, at) => {
148
+ touches.push({
149
+ kind,
150
+ query: queries.length
151
+ });
152
+ queries.push({
153
+ pos: from,
154
+ assoc: 1,
155
+ from: at
156
+ }, {
157
+ pos: to,
158
+ assoc: -1,
159
+ from: at
160
+ });
161
+ };
162
+ const replacedStepMaps = /* @__PURE__ */ new Set();
163
+ for (const batch of batches) {
164
+ if (batch.replacesStepMapAt !== void 0) replacedStepMaps.add(batch.replacesStepMapAt);
165
+ for (const range of batch.ranges) addRange("mark-range", range.from, range.to, batch.mappingFrom);
166
+ }
167
+ for (let stepIndex = 0; stepIndex < tr.steps.length; stepIndex++) {
168
+ if (replacedStepMaps.has(stepIndex)) continue;
169
+ const step = tr.steps[stepIndex];
170
+ const at = stepIndex + 1;
171
+ if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) {
172
+ addRange("mark-range", step.from, step.to, at);
173
+ continue;
174
+ }
175
+ if (step instanceof AddNodeMarkStep || step instanceof RemoveNodeMarkStep || step instanceof AttrStep) {
176
+ touches.push({
177
+ kind: "node",
178
+ query: queries.length
179
+ });
180
+ queries.push({
181
+ pos: step.pos,
182
+ assoc: 1,
183
+ from: at
184
+ });
185
+ continue;
186
+ }
187
+ step.getMap().forEach((_oldStart, _oldEnd, newStart, newEnd) => {
188
+ addRange("replaced-range", newStart, newEnd, at);
189
+ });
190
+ }
191
+ return {
192
+ touches,
193
+ mapped: sweepPositions([tr.mapping], queries)
194
+ };
195
+ };
128
196
  function createParagraphChangeTrackerPlugin() {
129
197
  return new Plugin({
130
198
  key: paragraphChangeTrackerKey,
@@ -141,6 +209,7 @@ function createParagraphChangeTrackerPlugin() {
141
209
  paragraphCount: counts.paragraphs,
142
210
  sectionEndpointCount: counts.sectionEndpoints,
143
211
  sectionEndpointFingerprint: counts.sectionEndpointFingerprint,
212
+ sectionRecords: counts.sectionRecords,
144
213
  sectionEndpointRemoval: null
145
214
  };
146
215
  },
@@ -148,6 +217,7 @@ function createParagraphChangeTrackerPlugin() {
148
217
  const meta = tr.getMeta(paragraphChangeTrackerKey);
149
218
  const changedParagraphRangesMeta = tr.getMeta(CHANGED_PARAGRAPH_RANGES_META);
150
219
  const sectionEndpointRemovalMeta = tr.getMeta(SECTION_ENDPOINT_REMOVAL_META);
220
+ const sectionEditMeta = tr.getMeta(SECTION_EDIT_META);
151
221
  if (meta === CLEAR_META) {
152
222
  const counts = countDocumentStructure(tr.doc);
153
223
  return {
@@ -160,6 +230,7 @@ function createParagraphChangeTrackerPlugin() {
160
230
  paragraphCount: counts.paragraphs,
161
231
  sectionEndpointCount: counts.sectionEndpoints,
162
232
  sectionEndpointFingerprint: counts.sectionEndpointFingerprint,
233
+ sectionRecords: counts.sectionRecords,
163
234
  sectionEndpointRemoval: null
164
235
  };
165
236
  }
@@ -170,7 +241,7 @@ function createParagraphChangeTrackerPlugin() {
170
241
  const changedParaIds = /* @__PURE__ */ new Set();
171
242
  let unresolvedChanges = prevState.hasUntrackedSourceChanges;
172
243
  for (const position of affectedParagraphPositions) {
173
- const paraId = tr.doc.nodeAt(position)?.attrs["paraId"];
244
+ const paraId = nodeAtIndexed(tr.doc, position)?.attrs["paraId"];
174
245
  if (isUsableParaId(paraId)) changedParaIds.add(paraId);
175
246
  else unresolvedChanges = true;
176
247
  }
@@ -182,25 +253,32 @@ function createParagraphChangeTrackerPlugin() {
182
253
  blockStructureFingerprint: counts.blockStructureFingerprint,
183
254
  paragraphCount: counts.paragraphs,
184
255
  sectionEndpointCount: counts.sectionEndpoints,
185
- sectionEndpointRemoval: counts.sectionEndpointFingerprint === prevState.sectionEndpointFingerprint ? prevState.sectionEndpointRemoval : null,
186
- sectionEndpointFingerprint: counts.sectionEndpointFingerprint
256
+ sectionEndpointRemoval: holdsTheSameSections(prevState, counts) ? prevState.sectionEndpointRemoval : null,
257
+ sectionEndpointFingerprint: counts.sectionEndpointFingerprint,
258
+ sectionRecords: counts.sectionRecords
187
259
  };
188
260
  }
189
- if (!tr.docChanged) return prevState;
261
+ if (!tr.docChanged) return isSectionEditMeta(sectionEditMeta) && sectionEditMeta.expectedEndpointFingerprint === prevState.sectionEndpointFingerprint ? {
262
+ ...prevState,
263
+ sectionEndpointRemoval: sectionEditMeta.authorization
264
+ } : prevState;
190
265
  const counts = countDocumentStructure(tr.doc);
191
266
  const newCount = counts.paragraphs;
192
267
  let sectionEndpointRemoval = prevState.sectionEndpointRemoval;
193
- if (counts.sectionEndpointFingerprint !== prevState.sectionEndpointFingerprint) if (isTrackedSectionEndpointRemovalMeta(sectionEndpointRemovalMeta) && sectionEndpointRemovalMeta.authorization.sourceEndpointFingerprint === prevState.sectionEndpointFingerprint && sectionEndpointRemovalMeta.authorization.expectedEndpointFingerprint === counts.sectionEndpointFingerprint && sectionEndpointRemovalMeta.authorization.sourceParagraphEndpointCount === prevState.sectionEndpointCount && sectionEndpointRemovalMeta.authorization.expectedParagraphEndpointCount === counts.sectionEndpoints && counts.sectionEndpoints < prevState.sectionEndpointCount) {
194
- const authorization = sectionEndpointRemovalMeta.authorization;
195
- sectionEndpointRemoval = {
196
- type: "tracked-section-endpoint-removal",
197
- sourceParagraphEndpointCount: prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.sourceParagraphEndpointCount : authorization.sourceParagraphEndpointCount,
198
- expectedParagraphEndpointCount: authorization.expectedParagraphEndpointCount,
199
- sourceEndpointFingerprint: prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.sourceEndpointFingerprint : authorization.sourceEndpointFingerprint,
200
- expectedEndpointFingerprint: authorization.expectedEndpointFingerprint,
201
- removedReferences: [...prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.removedReferences : [], ...authorization.removedReferences]
202
- };
203
- } else sectionEndpointRemoval = null;
268
+ if (counts.sectionEndpointFingerprint !== prevState.sectionEndpointFingerprint) {
269
+ if (isTrackedSectionEndpointRemovalMeta(sectionEndpointRemovalMeta) && sectionEndpointRemovalMeta.authorization.sourceEndpointFingerprint === prevState.sectionEndpointFingerprint && sectionEndpointRemovalMeta.authorization.expectedEndpointFingerprint === counts.sectionEndpointFingerprint && sectionEndpointRemovalMeta.authorization.sourceParagraphEndpointCount === prevState.sectionEndpointCount && sectionEndpointRemovalMeta.authorization.expectedParagraphEndpointCount === counts.sectionEndpoints && counts.sectionEndpoints < prevState.sectionEndpointCount) {
270
+ const authorization = sectionEndpointRemovalMeta.authorization;
271
+ sectionEndpointRemoval = {
272
+ type: "tracked-section-endpoint-removal",
273
+ sourceParagraphEndpointCount: prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.sourceParagraphEndpointCount : authorization.sourceParagraphEndpointCount,
274
+ expectedParagraphEndpointCount: authorization.expectedParagraphEndpointCount,
275
+ sourceEndpointFingerprint: prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.sourceEndpointFingerprint : authorization.sourceEndpointFingerprint,
276
+ expectedEndpointFingerprint: authorization.expectedEndpointFingerprint,
277
+ removedReferences: [...prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.removedReferences : [], ...authorization.removedReferences]
278
+ };
279
+ } else if (!holdsTheSameSections(prevState, counts)) sectionEndpointRemoval = null;
280
+ }
281
+ if (isSectionEditMeta(sectionEditMeta) && sectionEditMeta.expectedEndpointFingerprint === counts.sectionEndpointFingerprint) sectionEndpointRemoval = sectionEditMeta.authorization;
204
282
  const newState = {
205
283
  affectedParagraphPositions: mapAffectedParagraphPositions(tr, prevState.affectedParagraphPositions),
206
284
  hasUntrackedSourceChanges: prevState.hasUntrackedSourceChanges,
@@ -211,71 +289,129 @@ function createParagraphChangeTrackerPlugin() {
211
289
  paragraphCount: newCount,
212
290
  sectionEndpointCount: counts.sectionEndpoints,
213
291
  sectionEndpointFingerprint: counts.sectionEndpointFingerprint,
292
+ sectionRecords: counts.sectionRecords,
214
293
  sectionEndpointRemoval
215
294
  };
216
- if (isChangedParagraphRangesMeta(changedParagraphRangesMeta)) for (const batch of changedParagraphRangesMeta.batches) {
217
- const remap = tr.mapping.slice(batch.mappingFrom);
218
- for (const range of batch.ranges) {
219
- const from = mapStepPosition(remap, range.from, 1);
220
- const to = mapStepPosition(remap, range.to, -1);
221
- if (to <= from) continue;
222
- const { ids, positions, hasUntracked } = collectAffectedParaIdsFromMarkLikeStep(tr.doc, from, to);
223
- for (const position of positions) newState.affectedParagraphPositions.add(position);
224
- for (const id of ids) newState.changedParaIds.add(id);
225
- if (hasUntracked) newState.hasUntrackedChanges = true;
226
- }
227
- }
228
- if (prevState.blockStructureFingerprint !== counts.blockStructureFingerprint) newState.structuralChange = true;
229
- for (let stepIndex = 0; stepIndex < tr.steps.length; stepIndex++) {
230
- const step = tr.steps[stepIndex];
231
- const remap = tr.mapping.slice(stepIndex + 1);
232
- if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) {
233
- const from = mapStepPosition(remap, step.from, 1);
234
- const to = mapStepPosition(remap, step.to, -1);
235
- if (to <= from) continue;
236
- const { ids, positions, hasUntracked } = collectAffectedParaIdsFromMarkLikeStep(tr.doc, from, to);
237
- for (const position of positions) newState.affectedParagraphPositions.add(position);
238
- for (const id of ids) newState.changedParaIds.add(id);
239
- if (hasUntracked) newState.hasUntrackedChanges = true;
295
+ const recordAffected = ({ ids, positions, hasUntracked }) => {
296
+ for (const position of positions) newState.affectedParagraphPositions.add(position);
297
+ for (const id of ids) newState.changedParaIds.add(id);
298
+ if (hasUntracked) newState.hasUntrackedChanges = true;
299
+ };
300
+ const { touches, mapped } = mapStepTouches(tr, isChangedParagraphRangesMeta(changedParagraphRangesMeta) ? changedParagraphRangesMeta.batches : []);
301
+ for (const touch of touches) {
302
+ const from = mapped[touch.query].pos;
303
+ if (touch.kind === "node") {
304
+ if (mapped[touch.query].deletedAcross) continue;
305
+ const node = nodeAtIndexed(tr.doc, from);
306
+ if (node) recordAffected(collectAffectedParaIds(tr.doc, from, from + node.nodeSize));
240
307
  continue;
241
308
  }
242
- if (step instanceof AddNodeMarkStep || step instanceof RemoveNodeMarkStep || step instanceof AttrStep) {
243
- const pos = mapStepPosition(remap, step.pos, 1);
244
- const node = tr.doc.nodeAt(pos);
245
- if (!node) continue;
246
- const end = pos + node.nodeSize;
247
- const { ids, positions, hasUntracked } = collectAffectedParaIds(tr.doc, pos, end);
248
- for (const position of positions) newState.affectedParagraphPositions.add(position);
249
- for (const id of ids) newState.changedParaIds.add(id);
250
- if (hasUntracked) newState.hasUntrackedChanges = true;
309
+ const to = mapped[touch.query + 1].pos;
310
+ if (touch.kind === "mark-range") {
311
+ if (to > from) recordAffected(collectAffectedParaIdsFromMarkLikeStep(tr.doc, from, to));
251
312
  continue;
252
313
  }
253
- step.getMap().forEach((_oldStart, _oldEnd, newStart, newEnd) => {
254
- const from = mapStepPosition(remap, newStart, 1);
255
- const to = mapStepPosition(remap, newEnd, -1);
256
- if (to < from) return;
257
- const { ids, positions, hasUntracked } = collectAffectedParaIds(tr.doc, from, to);
258
- for (const position of positions) newState.affectedParagraphPositions.add(position);
259
- for (const id of ids) newState.changedParaIds.add(id);
260
- if (hasUntracked) newState.hasUntrackedChanges = true;
261
- });
314
+ if (to >= from) recordAffected(collectAffectedParaIds(tr.doc, from, to));
262
315
  }
263
- if (newState.hasUntrackedChanges || prevState.blockStructureFingerprint !== counts.blockStructureFingerprint) tr.before.descendants((node, position) => {
264
- if (node.type.name !== "paragraph") return true;
265
- if (!isUsableParaId(node.attrs["paraId"])) {
266
- const mapped = mapParagraphPosition(tr, position);
267
- if (mapped === null || newState.affectedParagraphPositions.has(mapped)) {
268
- newState.hasUntrackedSourceChanges = true;
269
- newState.hasUntrackedChanges = true;
270
- }
316
+ if (prevState.blockStructureFingerprint !== counts.blockStructureFingerprint) newState.structuralChange = true;
317
+ if (newState.hasUntrackedChanges || prevState.blockStructureFingerprint !== counts.blockStructureFingerprint) {
318
+ const unidentified = [];
319
+ tr.before.descendants((node, position) => {
320
+ if (node.type.name !== "paragraph") return true;
321
+ if (!isUsableParaId(node.attrs["paraId"])) unidentified.push(position);
322
+ return false;
323
+ });
324
+ for (const survivor of mapParagraphPositions(tr, unidentified)) if (survivor === null || newState.affectedParagraphPositions.has(survivor)) {
325
+ newState.hasUntrackedSourceChanges = true;
326
+ newState.hasUntrackedChanges = true;
271
327
  }
272
- return false;
273
- });
328
+ }
274
329
  return newState;
275
330
  }
276
- }
331
+ },
332
+ appendTransaction: (transactions, oldState, newState) => sectionEditTransaction(transactions, oldState, newState)
277
333
  });
278
334
  }
335
+ const referencesOf = (records) => {
336
+ const references = [];
337
+ for (const record of records) {
338
+ for (const { type, rId } of record.headerReferences ?? []) references.push({
339
+ part: "header",
340
+ type,
341
+ relationshipId: rId
342
+ });
343
+ for (const { type, rId } of record.footerReferences ?? []) references.push({
344
+ part: "footer",
345
+ type,
346
+ relationshipId: rId
347
+ });
348
+ }
349
+ return references;
350
+ };
351
+ /** `references` without one occurrence of each of `restored`. */
352
+ const withoutReferences = (references, restored) => {
353
+ const remaining = [...references];
354
+ for (const reference of restored) {
355
+ const index = remaining.findIndex((candidate) => candidate.part === reference.part && candidate.type === reference.type && candidate.relationshipId === reference.relationshipId);
356
+ if (index !== -1) remaining.splice(index, 1);
357
+ }
358
+ return remaining;
359
+ };
360
+ /**
361
+ * Carry section breaks through an ordinary edit, and record the ones it
362
+ * deleted.
363
+ *
364
+ * Deleting the mark of a section-ending paragraph (Backspace or Delete across
365
+ * it, a selection, a cut or a paste over it, a join) deletes the break, and
366
+ * the section's content joins the following section: the same outcome as
367
+ * deleting the paragraph as a block, or accepting its tracked deletion. The
368
+ * appended transaction moves each joined paragraph's record to the one its
369
+ * surviving mark carries (see `sectionMarkEditsOf`) and states the removal
370
+ * the save is to accept.
371
+ *
372
+ * Only a record whose mark a replacement deleted counts as removed on
373
+ * purpose. A record that goes any other way (an attribute cleared, a record
374
+ * swapped for another) leaves the edit unauthorized, and the save refuses the
375
+ * smaller package as it always did. Records coming back (an undo) take their
376
+ * removal back out of the authorization.
377
+ */
378
+ const sectionEditTransaction = (transactions, oldState, newState) => {
379
+ if (!transactions.some((transaction) => transaction.docChanged && transaction.getMeta(paragraphChangeTrackerKey) !== IGNORE_META) || transactions.some((transaction) => transaction.getMeta(SECTION_EDIT_META) !== void 0 || transaction.getMeta(SECTION_ENDPOINT_REMOVAL_META) !== void 0 || transaction.getMeta(paragraphChangeTrackerKey) === CLEAR_META)) return null;
380
+ const base = paragraphChangeTrackerKey.getState(oldState);
381
+ if (!base) return null;
382
+ if (base.sectionRecords.size === 0) return null;
383
+ const edits = sectionMarkEditsOf(transactions, newState.doc);
384
+ const tr = newState.tr;
385
+ const restoring = transactions.some((transaction) => isHistoryTransaction(transaction));
386
+ for (const { position, record } of restoring ? [] : edits.carriers) {
387
+ const paragraph = tr.doc.nodeAt(position);
388
+ if (paragraph?.type.name === "paragraph" && sectionPropertiesOf(paragraph) !== record) tr.setNodeAttribute(position, "_sectionProperties", record);
389
+ }
390
+ const after = countDocumentStructure(tr.doc);
391
+ if (holdsTheSameSections(base, after)) return tr.docChanged ? tr.setMeta(SECTION_EDIT_META, {
392
+ type: "section-edit-meta",
393
+ authorization: base.sectionEndpointRemoval,
394
+ expectedEndpointFingerprint: after.sectionEndpointFingerprint
395
+ }) : null;
396
+ const removed = [...base.sectionRecords].filter((record) => !after.sectionRecords.has(record));
397
+ const added = [...after.sectionRecords].filter((record) => !base.sectionRecords.has(record));
398
+ if (removed.some((record) => !edits.deletedMarks.has(record))) return tr.docChanged ? tr : null;
399
+ const prior = base.sectionEndpointRemoval;
400
+ const sourceParagraphEndpointCount = prior?.sourceParagraphEndpointCount ?? base.sectionEndpointCount;
401
+ const authorization = after.sectionEndpoints < sourceParagraphEndpointCount ? {
402
+ type: "tracked-section-endpoint-removal",
403
+ sourceParagraphEndpointCount,
404
+ expectedParagraphEndpointCount: after.sectionEndpoints,
405
+ sourceEndpointFingerprint: prior?.sourceEndpointFingerprint ?? base.sectionEndpointFingerprint,
406
+ expectedEndpointFingerprint: after.sectionEndpointFingerprint,
407
+ removedReferences: withoutReferences([...prior?.removedReferences ?? [], ...referencesOf(removed)], referencesOf(added))
408
+ } : null;
409
+ return tr.setMeta(SECTION_EDIT_META, {
410
+ type: "section-edit-meta",
411
+ authorization,
412
+ expectedEndpointFingerprint: after.sectionEndpointFingerprint
413
+ });
414
+ };
279
415
  /**
280
416
  * Get the change tracker state from an EditorState
281
417
  */
@@ -304,6 +440,24 @@ function hasUntrackedChanges(state) {
304
440
  function getTrackedSectionEndpointRemoval(state) {
305
441
  return getChangeTrackerState(state)?.sectionEndpointRemoval ?? null;
306
442
  }
443
+ /**
444
+ * Run an editor save's full repack with the section removals the editor's own
445
+ * edits made.
446
+ *
447
+ * A save refuses a package with fewer sections than its source unless it is
448
+ * told which removals were meant: deleting the paragraph that ends a section,
449
+ * or accepting its tracked deletion, removes that section on purpose. The
450
+ * tracker records exactly those removals; without them the repack throws and
451
+ * the edit cannot be saved.
452
+ */
453
+ const repackWithEditorSectionRemovals = ({ state, document, repack }) => {
454
+ const resolution = getTrackedSectionEndpointRemoval(state);
455
+ return resolution === null ? repack() : withTrackedSectionEndpointRemoval({
456
+ document,
457
+ resolution,
458
+ repack
459
+ });
460
+ };
307
461
  /** Record only a complete, internally consistent endpoint-removal transition. */
308
462
  function markTrackedSectionEndpointRemoval(tr, { sourceDoc, removedEndpointCount, removedReferences }) {
309
463
  const sourceStructure = countDocumentStructure(sourceDoc);
@@ -324,6 +478,23 @@ function markTrackedSectionEndpointRemoval(tr, { sourceDoc, removedEndpointCount
324
478
  });
325
479
  }
326
480
  /**
481
+ * Record that `tr` removed section breaks on purpose: a command whose job is
482
+ * to remove the break (not to delete its paragraph mark, which the tracker
483
+ * reads for itself). Only a plain removal is recorded; a transaction that also
484
+ * adds or replaces a record is left as it is.
485
+ */
486
+ function markSectionBreakRemoval(tr, sourceDoc) {
487
+ const before = countDocumentStructure(sourceDoc).sectionRecords;
488
+ const after = countDocumentStructure(tr.doc).sectionRecords;
489
+ const removed = [...before].filter((record) => !after.has(record));
490
+ if (removed.length === 0 || [...after].some((record) => !before.has(record))) return tr;
491
+ return markTrackedSectionEndpointRemoval(tr, {
492
+ sourceDoc,
493
+ removedEndpointCount: removed.length,
494
+ removedReferences: referencesOf(removed)
495
+ });
496
+ }
497
+ /**
327
498
  * Create a transaction that clears the change tracker
328
499
  */
329
500
  function clearTrackedChanges(state) {
@@ -352,4 +523,4 @@ const ParagraphChangeTrackerExtension = createExtension({
352
523
  }
353
524
  });
354
525
  //#endregion
355
- export { ParagraphChangeTrackerExtension, clearTrackedChanges, getChangeTrackerState, getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges, ignoreTrackedChanges, markChangedParagraphRanges, markStructuralChange, markTrackedSectionEndpointRemoval, paragraphChangeTrackerKey };
526
+ export { ParagraphChangeTrackerExtension, clearTrackedChanges, getChangeTrackerState, getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges, ignoreTrackedChanges, markChangedParagraphRanges, markSectionBreakRemoval, markStructuralChange, markTrackedSectionEndpointRemoval, paragraphChangeTrackerKey, repackWithEditorSectionRemovals };
@@ -3,6 +3,7 @@ import { createExtension } from "../create.js";
3
3
  import { Priority } from "../types.js";
4
4
  import { cleanPastedHtml, removeUnpairedBookmarkBoundaries, removeUnpairedMoveRangeBoundaries } from "./pasteCleanup.js";
5
5
  import { retargetPastedHeadingStyles } from "./pastedHeadingStyles.js";
6
+ import { flattenPastedHtmlLists, numberPastedHtmlLists } from "./pastedHtmlLists.js";
6
7
  import { Plugin } from "prosemirror-state";
7
8
  //#region src/prosemirror/extensions/features/PasteCleanupExtension.ts
8
9
  /**
@@ -30,9 +31,9 @@ const PasteCleanupExtension = createExtension({
30
31
  plugins: [new Plugin({ props: {
31
32
  transformPastedHTML(html) {
32
33
  const internalClipboardToken = options.getInternalClipboardToken?.();
33
- return cleanPastedHtml(html, { ...internalClipboardToken ? { internalClipboardToken } : {} });
34
+ return flattenPastedHtmlLists(cleanPastedHtml(html, { ...internalClipboardToken ? { internalClipboardToken } : {} }));
34
35
  },
35
- transformPasted: (slice, view) => retargetPastedHeadingStyles(removeUnpairedMoveRangeBoundaries(removeUnpairedBookmarkBoundaries(slice)), view)
36
+ transformPasted: (slice, view) => numberPastedHtmlLists(retargetPastedHeadingStyles(removeUnpairedMoveRangeBoundaries(removeUnpairedBookmarkBoundaries(slice)), view), view)
36
37
  } })],
37
38
  keyboardShortcuts: { "Mod-Alt-v": pasteWithoutFormatting }
38
39
  };
@@ -128,6 +128,7 @@ const BOOKMARK_BOUNDARY_ATTR = /\s+data-docx-bookmark-(?:boundary|id|name|col-fi
128
128
  const RANGE_ANCHOR_ATTR = /\s+data-docx-range-anchor(?:="[^"]*"|='[^']*'|=[^\s>]+)?/gi;
129
129
  const MOVE_RANGE_BOUNDARY_ATTR = /\s+data-docx-move-range-boundary(?:="[^"]*"|='[^']*'|=[^\s>]+)?/gi;
130
130
  const STRUCTURED_FIELD_ATTR = /\s+data-field-structured(?:="[^"]*"|='[^']*'|=[^\s>]+)?/gi;
131
+ const FIELD_CODE_ATTR = /\s+data-field-code(?:="[^"]*"|'[^']*'|=[^\s>]+)?/gi;
131
132
  /**
132
133
  * Treat reconstruction attributes as internal only when the HTML carries the
133
134
  * unguessable capability created with this editor schema. `data-pm-slice`
@@ -153,7 +154,7 @@ function stripForeignRangeCarriers(html, internal) {
153
154
  }
154
155
  function stripForeignStructuredFields(html, internal) {
155
156
  if (internal) return html;
156
- return html.replace(STRUCTURED_FIELD_ATTR, "");
157
+ return html.replace(STRUCTURED_FIELD_ATTR, "").replace(FIELD_CODE_ATTR, "");
157
158
  }
158
159
  /**
159
160
  * Remove empty spans left behind after stripping `mso-*` styles. Only truly
@@ -0,0 +1,12 @@
1
+ import { Slice } from "prosemirror-model";
2
+ import { EditorView } from "prosemirror-view";
3
+ //#region src/prosemirror/extensions/features/pastedHtmlLists.d.ts
4
+ /**
5
+ * Flatten only list containers. Other HTML remains in place for the normal
6
+ * clipboard parser, including tables and inline formatting inside list items.
7
+ */
8
+ declare const flattenPastedHtmlLists: (html: string) => string;
9
+ /** Resolve clipboard-only list hints against fresh document numbering ids. */
10
+ declare const numberPastedHtmlLists: (slice: Slice, view: EditorView) => Slice;
11
+ //#endregion
12
+ export { flattenPastedHtmlLists, numberPastedHtmlLists };