@stll/folio-core 0.53.0 → 0.54.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/ai-edits/apply.js +415 -166
  2. package/dist/ai-edits/batch-claims.d.ts +21 -6
  3. package/dist/ai-edits/batch-claims.js +47 -16
  4. package/dist/ai-edits/headless.d.ts +20 -0
  5. package/dist/ai-edits/headless.js +140 -11
  6. package/dist/ai-edits/pending-suggestions.js +1 -1
  7. package/dist/ai-edits/read.d.ts +5 -3
  8. package/dist/ai-edits/read.js +97 -47
  9. package/dist/ai-edits/revisionStretches.d.ts +17 -0
  10. package/dist/ai-edits/revisionStretches.js +80 -0
  11. package/dist/ai-edits/snapshot.js +3 -2
  12. package/dist/ai-edits/table-cell-mutations.d.ts +3 -1
  13. package/dist/ai-edits/table-cell-mutations.js +2 -1
  14. package/dist/ai-edits/table-row-column-mutations.d.ts +6 -1
  15. package/dist/ai-edits/table-row-column-mutations.js +27 -10
  16. package/dist/compare/content-alignment.d.ts +5 -1
  17. package/dist/compare/content-alignment.js +39 -32
  18. package/dist/compare/inline-provenance.js +1 -1
  19. package/dist/controller/layoutPipeline.js +3 -2
  20. package/dist/docx/archiveInflation.d.ts +127 -0
  21. package/dist/docx/archiveInflation.js +181 -0
  22. package/dist/docx/metadataPrivacy.js +24 -1
  23. package/dist/docx/noteReferenceMark.d.ts +15 -0
  24. package/dist/docx/noteReferenceMark.js +48 -0
  25. package/dist/docx/paragraphParser.js +5 -3
  26. package/dist/docx/paragraphPropertySource.d.ts +1 -1
  27. package/dist/docx/paragraphPropertySource.js +4 -2
  28. package/dist/docx/parser.js +2 -2
  29. package/dist/docx/rezip.js +4 -2
  30. package/dist/docx/selectiveXmlPatch.d.ts +3 -1
  31. package/dist/docx/selectiveXmlPatch.js +81 -3
  32. package/dist/docx/server/boundedArchive.d.ts +8 -13
  33. package/dist/docx/server/boundedArchive.js +70 -59
  34. package/dist/docx/server/extractDocxText.d.ts +8 -2
  35. package/dist/docx/server/extractDocxText.js +2 -2
  36. package/dist/docx/server/validateDocxConformance.d.ts +1 -1
  37. package/dist/docx/server/validateDocxConformance.js +1 -0
  38. package/dist/docx/unzip.d.ts +19 -2
  39. package/dist/docx/unzip.js +135 -24
  40. package/dist/docx/verticalMergeProjection.d.ts +17 -0
  41. package/dist/docx/verticalMergeProjection.js +120 -0
  42. package/dist/fonts/embeddedFonts.js +1 -1
  43. package/dist/i18n/messages/catalogs.gen.d.ts +34 -34
  44. package/dist/i18n/messages/catalogs.gen.js +34 -34
  45. package/dist/i18n/messages/messages.gen.d.ts +2 -2
  46. package/dist/internal/wholeStoryRevisionResolution.js +95 -25
  47. package/dist/layout-engine/measure/measureParagraph.js +2 -2
  48. package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +12 -1
  49. package/dist/layout-engine/measure/paragraphMeasureShared.js +14 -1
  50. package/dist/markdown/escape.d.ts +2 -2
  51. package/dist/markdown/escape.js +4 -5
  52. package/dist/markdown/renderBlock.js +91 -25
  53. package/dist/markdown/renderRuns.d.ts +10 -1
  54. package/dist/markdown/renderRuns.js +320 -59
  55. package/dist/prosemirror/clearRunColor.d.ts +6 -0
  56. package/dist/prosemirror/clearRunColor.js +46 -0
  57. package/dist/prosemirror/commands/comments.js +62 -22
  58. package/dist/prosemirror/commands/formatPainter.js +1 -1
  59. package/dist/prosemirror/commands/hyperlink.js +2 -1
  60. package/dist/prosemirror/commands/propertyChangeScope.d.ts +3 -2
  61. package/dist/prosemirror/commands/propertyChangeScope.js +28 -4
  62. package/dist/prosemirror/commands/resolveAllTableChanges.js +40 -41
  63. package/dist/prosemirror/commands/resolveParagraphProperties.js +33 -8
  64. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +7 -1
  65. package/dist/prosemirror/commands/tableCellMergeResolution.js +39 -20
  66. package/dist/prosemirror/commands/tableMergeFoldDecisions.d.ts +61 -0
  67. package/dist/prosemirror/commands/tableMergeFoldDecisions.js +79 -0
  68. package/dist/prosemirror/containerFinalParagraph.d.ts +11 -5
  69. package/dist/prosemirror/containerFinalParagraph.js +7 -6
  70. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
  71. package/dist/prosemirror/conversion/fromProseDoc.js +12 -590
  72. package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -13
  73. package/dist/prosemirror/conversion/toProseDoc.js +28 -262
  74. package/dist/prosemirror/documentSchema.d.ts +8 -0
  75. package/dist/prosemirror/documentSchema.js +18 -0
  76. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  77. package/dist/prosemirror/extensions/core/ParagraphExtension.js +104 -63
  78. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -1
  79. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +24 -3
  80. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.d.ts +20 -0
  81. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +43 -0
  82. package/dist/prosemirror/extensions/features/ListExtension.js +10 -9
  83. package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +1 -1
  84. package/dist/prosemirror/extensions/features/pastedHtmlLists.js +2 -4
  85. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +14 -8
  86. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +8 -4
  87. package/dist/prosemirror/extensions/marks/StrikeExtension.js +2 -2
  88. package/dist/prosemirror/extensions/marks/SubscriptExtension.js +2 -2
  89. package/dist/prosemirror/extensions/marks/SuperscriptExtension.js +2 -2
  90. package/dist/prosemirror/extensions/marks/TextColorExtension.js +4 -3
  91. package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -6
  92. package/dist/prosemirror/extensions/marks/markUtils.js +17 -8
  93. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +3 -1
  94. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +12 -1
  95. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +2 -2
  96. package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +5 -3
  97. package/dist/prosemirror/extensions/nodes/TableExtension.js +104 -210
  98. package/dist/prosemirror/extensions/types.d.ts +7 -0
  99. package/dist/prosemirror/hyperlinkRemoval.d.ts +9 -0
  100. package/dist/prosemirror/hyperlinkRemoval.js +129 -0
  101. package/dist/prosemirror/index.d.ts +2 -1
  102. package/dist/prosemirror/index.js +2 -1
  103. package/dist/prosemirror/listNumbering.d.ts +3 -21
  104. package/dist/prosemirror/listNumbering.js +24 -39
  105. package/dist/prosemirror/listRendering.d.ts +29 -0
  106. package/dist/prosemirror/listRendering.js +26 -0
  107. package/dist/prosemirror/markupViewNotes.d.ts +8 -0
  108. package/dist/prosemirror/markupViewNotes.js +49 -0
  109. package/dist/prosemirror/markupViewProjection.d.ts +3 -1
  110. package/dist/prosemirror/markupViewProjection.js +7 -2
  111. package/dist/prosemirror/noteReferenceReview.d.ts +77 -0
  112. package/dist/prosemirror/noteReferenceReview.js +332 -0
  113. package/dist/prosemirror/paragraphIndentation.js +5 -2
  114. package/dist/prosemirror/paragraphMarkJoin.d.ts +6 -4
  115. package/dist/prosemirror/paragraphMarkJoin.js +21 -19
  116. package/dist/prosemirror/paragraphPropertyCarry.d.ts +64 -0
  117. package/dist/prosemirror/paragraphPropertyCarry.js +155 -0
  118. package/dist/prosemirror/plugins/documentStyleState.d.ts +26 -0
  119. package/dist/prosemirror/plugins/documentStyleState.js +32 -0
  120. package/dist/prosemirror/plugins/documentStyles.d.ts +2 -21
  121. package/dist/prosemirror/plugins/documentStyles.js +66 -29
  122. package/dist/prosemirror/plugins/index.d.ts +2 -1
  123. package/dist/prosemirror/plugins/index.js +2 -1
  124. package/dist/prosemirror/plugins/paragraphStyleResolution.d.ts +15 -0
  125. package/dist/prosemirror/plugins/paragraphStyleResolution.js +230 -0
  126. package/dist/prosemirror/plugins/suggestionMode.d.ts +12 -2
  127. package/dist/prosemirror/plugins/suggestionMode.js +387 -28
  128. package/dist/prosemirror/plugins/templateDirectives.d.ts +6 -0
  129. package/dist/prosemirror/plugins/templateDirectives.js +21 -7
  130. package/dist/prosemirror/plugins/templatePreviewValues.js +14 -21
  131. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +22 -2
  132. package/dist/prosemirror/rebaseParagraphRunFormatting.js +39 -13
  133. package/dist/prosemirror/rebaseParagraphRuns.d.ts +36 -0
  134. package/dist/prosemirror/rebaseParagraphRuns.js +99 -0
  135. package/dist/prosemirror/runFormattingFromMarks.d.ts +18 -0
  136. package/dist/prosemirror/runFormattingFromMarks.js +567 -0
  137. package/dist/prosemirror/runFormattingReconciliation.js +10 -9
  138. package/dist/prosemirror/schema/nodes.d.ts +2 -0
  139. package/dist/prosemirror/styles/paragraphStyleCascade.d.ts +59 -0
  140. package/dist/prosemirror/styles/paragraphStyleCascade.js +145 -0
  141. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +21 -2
  142. package/dist/prosemirror/styles/resolvedStyleAttrs.js +38 -1
  143. package/dist/prosemirror/styles/tableStyleRegions.d.ts +31 -0
  144. package/dist/prosemirror/styles/tableStyleRegions.js +55 -0
  145. package/dist/prosemirror/tableCellPaste.d.ts +74 -0
  146. package/dist/prosemirror/tableCellPaste.js +525 -0
  147. package/dist/prosemirror/tableGridMutation.d.ts +53 -14
  148. package/dist/prosemirror/tableGridMutation.js +166 -18
  149. package/dist/prosemirror/tableRunIn.d.ts +51 -0
  150. package/dist/prosemirror/tableRunIn.js +165 -0
  151. package/dist/prosemirror/textInput.js +11 -2
  152. package/dist/prosemirror/trackedRevisionPath.d.ts +17 -0
  153. package/dist/prosemirror/trackedRevisionPath.js +32 -0
  154. package/dist/server.d.ts +2 -2
  155. package/package.json +6 -6
@@ -2,6 +2,7 @@ import { expectRunPropertyChangeMarkAttrs, expectTrackedChangeMarkAttrs } from "
2
2
  import { getFolioNodeRevisionCarriers } from "../prosemirror/revisionCarriers.js";
3
3
  import { expandRunFormattingCarrier, runFormattingCarrierReviewText, runFormattingInlineAtomDisposition } from "../prosemirror/runFormattingInlineCarriers.js";
4
4
  import { getTableCellMergeChange } from "../prosemirror/tableCellMergeRevision.js";
5
+ import { enclosingInsertionAncestors, trackedRevisionLayerOf } from "../prosemirror/trackedRevisionPath.js";
5
6
  import { readerTextOf } from "./note-references.js";
6
7
  import { collectNoteReferenceLabels, createFolioAIEditSnapshot, sourceDocumentOf } from "./snapshot.js";
7
8
  //#region src/ai-edits/read.ts
@@ -53,16 +54,29 @@ const firstBlockIdWithin = ({ node, nodePos, blockStarts }) => {
53
54
  };
54
55
  const belongsToRowRevision = (scope, revision) => revision.id === scope.change.id || revision.author === scope.change.author && revision.date === scope.change.date;
55
56
  /** Shared revision interpreter; a null block map omits unrelated block-id projection. */
56
- const getTrackedChangesFromProjectedDoc = (doc, blockStarts) => {
57
+ const getTrackedChangeGroupsFromProjectedDoc = (doc, blockStarts) => {
57
58
  const insertionType = doc.type.schema.marks["insertion"];
58
59
  const deletionType = doc.type.schema.marks["deletion"];
59
60
  const grouped = /* @__PURE__ */ new Map();
61
+ const inlineRanges = /* @__PURE__ */ new Map();
62
+ const lastInlineGroupByPath = /* @__PURE__ */ new Map();
63
+ const transparentInlineEnds = /* @__PURE__ */ new Map();
64
+ const transparentGap = (start, end) => {
65
+ let pos = start;
66
+ while (pos < end) {
67
+ const next = transparentInlineEnds.get(pos);
68
+ if (next === void 0) return false;
69
+ pos = next;
70
+ }
71
+ return pos === end;
72
+ };
60
73
  const structuralChangeCellPositions = /* @__PURE__ */ new Map();
61
74
  const rowRevisionScopes = [];
62
75
  const derivedFormattingRepresentationPositions = /* @__PURE__ */ new Set();
63
76
  const noteReferences = collectNoteReferenceLabels(doc);
64
77
  let currentBlockId = null;
65
78
  doc.descendants((node, pos) => {
79
+ if (node.type.name === "commentReference") transparentInlineEnds.set(pos, pos + node.nodeSize);
66
80
  while (pos >= (rowRevisionScopes.at(-1)?.end ?? Number.POSITIVE_INFINITY)) rowRevisionScopes.pop();
67
81
  const nodeRevisionCarriers = getFolioNodeRevisionCarriers(node, pos);
68
82
  if (nodeRevisionCarriers.length > 0) {
@@ -204,70 +218,106 @@ const getTrackedChangesFromProjectedDoc = (doc, blockStarts) => {
204
218
  }
205
219
  }
206
220
  const text = readerTextOf(node, noteReferences);
207
- for (const mark of node.marks) {
208
- if (mark.type.name === "runPropertyChange") continue;
209
- if (typeof mark.attrs["revisionId"] !== "number") continue;
210
- let kind;
211
- if (mark.type === insertionType) kind = "insertion";
212
- else if (mark.type === deletionType) kind = "deletion";
213
- else continue;
214
- const author = mark.attrs["author"];
215
- const date = mark.attrs["date"];
216
- const layers = [...(expectTrackedChangeMarkAttrs(mark)._docxRevisionAncestors ?? []).map((ancestor) => ({
217
- kind: ancestor.type === "insertion" || ancestor.type === "moveTo" ? "insertion" : "deletion",
218
- revision: {
219
- id: ancestor.revisionId,
220
- author: ancestor.author,
221
- date: ancestor.date ?? null
222
- }
223
- })), {
224
- kind,
225
- revision: {
226
- id: mark.attrs["revisionId"],
227
- author: typeof author === "string" ? author : "",
228
- date: typeof date === "string" ? date : null
229
- }
230
- }];
231
- for (const { kind: layerKind, revision } of layers) {
232
- const rowScope = rowRevisionScopes.at(-1);
233
- if (rowScope?.kind === layerKind && belongsToRowRevision(rowScope, revision)) continue;
234
- const key = `${currentBlockId ?? ""}:${layerKind}:${revision.id}`;
235
- const existing = grouped.get(key);
236
- if (existing) {
237
- existing.text += text;
238
- continue;
239
- }
240
- grouped.set(key, {
241
- ...revision,
242
- type: layerKind,
243
- text,
244
- blockId: currentBlockId
245
- });
221
+ const insertionMark = node.marks.find((mark) => mark.type === insertionType);
222
+ const deletionMark = node.marks.find((mark) => mark.type === deletionType);
223
+ const mark = deletionMark ?? insertionMark;
224
+ if (!mark || typeof mark.attrs["revisionId"] !== "number") return;
225
+ const attrs = expectTrackedChangeMarkAttrs(mark);
226
+ const pathLayers = [...enclosingInsertionAncestors({
227
+ insertionMark: deletionMark ? insertionMark : void 0,
228
+ ancestors: attrs._docxRevisionAncestors ?? [],
229
+ node
230
+ }), trackedRevisionLayerOf(mark, node)];
231
+ const layers = pathLayers.map((layer) => ({
232
+ kind: layer.type === "insertion" || layer.type === "moveTo" ? "insertion" : "deletion",
233
+ revision: {
234
+ id: layer.revisionId,
235
+ author: layer.author,
236
+ date: layer.date ?? null
237
+ }
238
+ }));
239
+ for (const [layerIndex, { kind: layerKind, revision }] of layers.entries()) {
240
+ const rowScope = rowRevisionScopes.at(-1);
241
+ if (rowScope?.kind === layerKind && belongsToRowRevision(rowScope, revision)) continue;
242
+ const path = `${currentBlockId ?? ""}:${JSON.stringify(pathLayers.slice(0, layerIndex + 1))}`;
243
+ const previousKey = lastInlineGroupByPath.get(path);
244
+ const previousRange = previousKey === void 0 ? void 0 : inlineRanges.get(previousKey);
245
+ const key = previousKey !== void 0 && previousRange && transparentGap(previousRange.end, pos) ? previousKey : `${path}:${pos}`;
246
+ lastInlineGroupByPath.set(path, key);
247
+ const hyperlink = node.marks.find((candidate) => candidate.type.name === "hyperlink");
248
+ const commentId = node.marks.find((candidate) => candidate.type.name === "comment")?.attrs["commentId"];
249
+ const boundary = {
250
+ hyperlink: hyperlink ? String(hyperlink.attrs["href"] ?? "") : null,
251
+ comment: typeof commentId === "number" ? commentId : null,
252
+ revisionParents: JSON.stringify(pathLayers.slice(0, layerIndex))
253
+ };
254
+ const range = inlineRanges.get(key);
255
+ if (range) {
256
+ range.end = pos + node.nodeSize;
257
+ range.lastBoundary = boundary;
258
+ } else inlineRanges.set(key, {
259
+ start: pos,
260
+ end: pos + node.nodeSize,
261
+ firstBoundary: boundary,
262
+ lastBoundary: boundary
263
+ });
264
+ const existing = grouped.get(key);
265
+ if (existing) {
266
+ existing.text += text;
267
+ continue;
246
268
  }
269
+ grouped.set(key, {
270
+ ...revision,
271
+ type: layerKind,
272
+ text,
273
+ blockId: currentBlockId
274
+ });
247
275
  }
248
276
  });
249
- return [...grouped.values()];
277
+ const groups = [];
278
+ let previousKey = null;
279
+ for (const [key, change] of grouped) {
280
+ const range = inlineRanges.get(key);
281
+ const previous = groups.at(-1);
282
+ const previousRange = previousKey === null ? void 0 : inlineRanges.get(previousKey);
283
+ if (previous && range && previousRange && previousRange.end <= range.start && transparentGap(previousRange.end, range.start) && previousRange.lastBoundary.revisionParents === range.firstBoundary.revisionParents && (previousRange.lastBoundary.hyperlink !== range.firstBoundary.hyperlink || previousRange.lastBoundary.comment !== range.firstBoundary.comment || previousRange.end !== range.start) && (change.type === "insertion" || change.type === "deletion") && previous.change.type === change.type && previous.change.author === change.author && previous.change.date === change.date && previous.change.blockId === change.blockId) {
284
+ previous.change.text += change.text;
285
+ previous.ids.push(change.id);
286
+ previousRange.end = range.end;
287
+ previousRange.lastBoundary = range.lastBoundary;
288
+ continue;
289
+ }
290
+ groups.push({
291
+ change: { ...change },
292
+ ids: [change.id]
293
+ });
294
+ previousKey = key;
295
+ }
296
+ return groups;
250
297
  };
298
+ const getTrackedChangesFromProjectedDoc = (doc, blockStarts) => getTrackedChangeGroupsFromProjectedDoc(doc, blockStarts).map(({ change }) => change);
251
299
  /** Read revisions from the exact immutable document that produced a snapshot. */
252
300
  const getTrackedChangesFromSnapshot = (snapshot) => getTrackedChangesFromProjectedDoc(sourceDocumentOf(snapshot), blockStartIdsFromSnapshot(snapshot));
253
301
  /**
254
302
  * The tracked changes present in the body, read from inline marks and
255
- * structural node attributes. Runs of one inline revision within a block fold
256
- * into a single entry.
303
+ * structural node attributes. Adjacent runs sharing a revision wrapper path
304
+ * fold into one entry; interrupted or differently nested wrappers stay separate.
257
305
  *
258
306
  * A tracked row insertion or deletion marks the row AND every run in its
259
307
  * cells, the way Word writes it. Both halves are one change, so the run marks
260
308
  * fold into the row's entry rather than reporting a second time.
261
309
  */
262
310
  const getTrackedChangesFromDoc = (doc) => getTrackedChangesFromProjectedDoc(doc, blockStartIdsFromDoc(doc));
311
+ /** Physical revision ids behind an inline change split by markup. */
312
+ const getTrackedChangeGroupIdsFromDoc = (doc, id) => getTrackedChangeGroupsFromProjectedDoc(doc, blockStartIdsFromDoc(doc)).find(({ ids }) => ids.includes(id))?.ids ?? [id];
263
313
  /** @internal Read revision statistics without paying for an unrelated block projection. */
264
314
  const getTrackedChangeStatsFromDoc = (doc) => {
265
315
  let highestId = 0;
266
- const changes = getTrackedChangesFromProjectedDoc(doc, null);
267
- for (const change of changes) highestId = Math.max(highestId, change.id);
316
+ const groups = getTrackedChangeGroupsFromProjectedDoc(doc, null);
317
+ for (const { ids } of groups) for (const id of ids) highestId = Math.max(highestId, id);
268
318
  return {
269
319
  highestId,
270
- present: changes.length > 0
320
+ present: groups.length > 0
271
321
  };
272
322
  };
273
323
  /**
@@ -313,4 +363,4 @@ const getCommentAnchorsFromDoc = (doc) => {
313
363
  }));
314
364
  };
315
365
  //#endregion
316
- export { FOLIO_REVIEW_CHANGE_KINDS, getCommentAnchorsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot };
366
+ export { FOLIO_REVIEW_CHANGE_KINDS, getCommentAnchorsFromDoc, getTrackedChangeGroupIdsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot };
@@ -0,0 +1,17 @@
1
+ import { Transaction } from "prosemirror-state";
2
+ //#region src/ai-edits/revisionStretches.d.ts
3
+ type SeparateRevisionStretchesOptions = {
4
+ tr: Transaction;
5
+ revisionSeed: number;
6
+ };
7
+ type SeparatedRevisionStretches = {
8
+ nextRevisionId: number;
9
+ /** Each fresh id, with the revision whose stretch it now names. */
10
+ minted: {
11
+ revisionId: number;
12
+ from: number;
13
+ }[];
14
+ };
15
+ declare const separateRevisionStretches: ({ tr, revisionSeed }: SeparateRevisionStretchesOptions) => SeparatedRevisionStretches;
16
+ //#endregion
17
+ export { SeparatedRevisionStretches, separateRevisionStretches };
@@ -0,0 +1,80 @@
1
+ import { expectTrackedChangeMarkAttrs } from "../prosemirror/attrs/index.js";
2
+ //#region src/ai-edits/revisionStretches.ts
3
+ const INLINE_REVISION_MARKS = /* @__PURE__ */ new Set(["insertion", "deletion"]);
4
+ const separateRevisionStretches = ({ tr, revisionSeed }) => {
5
+ let nextRevisionId = revisionSeed;
6
+ const minted = [];
7
+ const retargets = [];
8
+ let stretches = /* @__PURE__ */ new Map();
9
+ tr.doc.descendants((node, pos) => {
10
+ if (node.isTextblock) {
11
+ stretches = /* @__PURE__ */ new Map();
12
+ return true;
13
+ }
14
+ if (!node.isInline || !(node.isLeaf || node.isText)) return true;
15
+ const layersOf = (mark) => {
16
+ const attrs = expectTrackedChangeMarkAttrs(mark);
17
+ return [...(attrs._docxRevisionAncestors ?? []).flatMap((ancestor) => ancestor.type === "insertion" || ancestor.type === "deletion" ? [{
18
+ kind: ancestor.type,
19
+ revisionId: ancestor.revisionId
20
+ }] : []), {
21
+ kind: mark.type.name,
22
+ revisionId: attrs.revisionId
23
+ }];
24
+ };
25
+ const revisionMarks = node.marks.filter((mark) => INLINE_REVISION_MARKS.has(mark.type.name) && expectTrackedChangeMarkAttrs(mark).moveKind === void 0);
26
+ const carried = new Set(revisionMarks.flatMap((mark) => layersOf(mark).map(({ kind, revisionId }) => `${kind}:${String(revisionId)}`)));
27
+ if (node.type.name !== "commentReference") {
28
+ for (const [key, stretch] of stretches) if (!carried.has(key)) stretch.interrupted = true;
29
+ }
30
+ for (const mark of revisionMarks) {
31
+ const ids = /* @__PURE__ */ new Map();
32
+ for (const { kind, revisionId } of layersOf(mark)) {
33
+ const key = `${kind}:${String(revisionId)}`;
34
+ let stretch = stretches.get(key);
35
+ if (!stretch) {
36
+ stretch = {
37
+ id: revisionId,
38
+ interrupted: false
39
+ };
40
+ stretches.set(key, stretch);
41
+ } else if (stretch.interrupted) {
42
+ const fresh = nextRevisionId++;
43
+ minted.push({
44
+ revisionId: fresh,
45
+ from: revisionId
46
+ });
47
+ stretch = {
48
+ id: fresh,
49
+ interrupted: false
50
+ };
51
+ stretches.set(key, stretch);
52
+ }
53
+ if (stretch.id !== revisionId) ids.set(revisionId, stretch.id);
54
+ }
55
+ if (ids.size > 0) retargets.push({
56
+ from: pos,
57
+ to: pos + node.nodeSize,
58
+ mark,
59
+ ids
60
+ });
61
+ }
62
+ return true;
63
+ });
64
+ for (const { from, to, mark, ids } of retargets) {
65
+ const attrs = expectTrackedChangeMarkAttrs(mark);
66
+ const ancestors = attrs._docxRevisionAncestors;
67
+ tr.removeMark(from, to, mark);
68
+ tr.addMark(from, to, mark.type.create({
69
+ ...mark.attrs,
70
+ revisionId: ids.get(attrs.revisionId) ?? attrs.revisionId,
71
+ ...ancestors && { _docxRevisionAncestors: ancestors.map((ancestor) => Object.assign(structuredClone(ancestor), { revisionId: ids.get(ancestor.revisionId) ?? ancestor.revisionId })) }
72
+ }));
73
+ }
74
+ return {
75
+ nextRevisionId,
76
+ minted
77
+ };
78
+ };
79
+ //#endregion
80
+ export { separateRevisionStretches };
@@ -4,13 +4,13 @@ import { resolveParagraphNumbering } from "../docx/numberingReference.js";
4
4
  import { OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC, isOpaqueNestedRowMarkup, opaqueRevisionCarrierName } from "../docx/opaqueCarrier.js";
5
5
  import { recreateProseNodeWithParagraphPropertySource } from "../docx/paragraphPropertySource.js";
6
6
  import { expectCharacterStyleMarkAttrs, expectHyperlinkMarkAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs } from "../prosemirror/attrs/index.js";
7
- import { marksToTextFormatting } from "../prosemirror/conversion/fromProseDoc.js";
8
7
  import { createListLabelCounter } from "../prosemirror/listLabels.js";
9
8
  import { paragraphNumberingAttr, readParagraphNumberingAttr } from "../prosemirror/numberingAttr.js";
10
9
  import { readOutlineLevelAttr } from "../prosemirror/outlineLevelAttr.js";
11
10
  import { directParagraphAlignment } from "../prosemirror/paragraphAlignment.js";
12
11
  import { directParagraphIndentation } from "../prosemirror/paragraphIndentation.js";
13
12
  import { directParagraphSpacing } from "../prosemirror/paragraphSpacing.js";
13
+ import { marksToTextFormatting } from "../prosemirror/runFormattingFromMarks.js";
14
14
  import { runFormattingInlineAtomCleanText } from "../prosemirror/runFormattingInlineCarriers.js";
15
15
  import { authoredRunFormattingFromAttrs } from "../prosemirror/runFormattingProvenance.js";
16
16
  import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "../prosemirror/runFormattingReconciliation.js";
@@ -748,7 +748,8 @@ const getDefaultPreviewRunStyle = (node, styleResolver) => {
748
748
  };
749
749
  };
750
750
  const getPreviewRunStyle = (marks, defaultStyle) => {
751
- const style = { ...defaultStyle };
751
+ const { bold: _bold, italic: _italic, underline: _underline, strike: _strike, ...inherited } = defaultStyle;
752
+ const style = { ...inherited };
752
753
  for (const mark of marks) switch (mark.type.name) {
753
754
  case "bold":
754
755
  style.bold = true;
@@ -17,5 +17,7 @@ declare const mergeTableRectangle: ({ tr, tablePosition, table, rectangle }: Tab
17
17
  declare const mergeTrackedVerticalTableCells: ({ tr, tablePosition, table, rectangle, revisionId, author, date }: TrackedTableCellRectangleMutationOptions) => Transaction | null;
18
18
  declare const splitTableRectangle: ({ tr, tablePosition, table, rectangle }: TableCellRectangleMutationOptions) => Transaction | null;
19
19
  declare const splitTrackedVerticalTableCell: ({ tr, tablePosition, table, rectangle, revisionId, author, date }: TrackedTableCellRectangleMutationOptions) => Transaction | null;
20
+ /** A cell holding one empty paragraph: all a tracked merge may fold away. */
21
+ declare const isEmptyTableCell: (cell: Node) => boolean;
20
22
  //#endregion
21
- export { mergeTableRectangle, mergeTrackedVerticalTableCells, splitTableRectangle, splitTrackedVerticalTableCell };
23
+ export { isEmptyTableCell, mergeTableRectangle, mergeTrackedVerticalTableCells, splitTableRectangle, splitTrackedVerticalTableCell };
@@ -259,6 +259,7 @@ const splitTrackedVerticalTableCell = ({ tr, tablePosition, table, rectangle, re
259
259
  markStructuralChange(tr);
260
260
  return tr;
261
261
  };
262
+ /** A cell holding one empty paragraph: all a tracked merge may fold away. */
262
263
  const isEmptyTableCell = (cell) => cell.childCount === 1 && cell.firstChild?.isTextblock === true && cell.firstChild.childCount === 0;
263
264
  const trackedSplitCellFromStoredSource = ({ origin, source, marker }) => {
264
265
  if (source.formatting?.gridSpan !== void 0 && source.formatting.gridSpan > 1) return null;
@@ -286,4 +287,4 @@ const formattingWithoutVerticalMerge = (formatting) => {
286
287
  return next;
287
288
  };
288
289
  //#endregion
289
- export { mergeTableRectangle, mergeTrackedVerticalTableCells, splitTableRectangle, splitTrackedVerticalTableCell };
290
+ export { isEmptyTableCell, mergeTableRectangle, mergeTrackedVerticalTableCells, splitTableRectangle, splitTrackedVerticalTableCell };
@@ -1,4 +1,5 @@
1
1
  import { TableStructureRevision } from "./table-template.js";
2
+ import { RowsEmptiedInBatch } from "../prosemirror/tableGridMutation.js";
2
3
  import { TableRowTarget } from "./table-targets.js";
3
4
  import { Node } from "prosemirror-model";
4
5
  import { Transaction } from "prosemirror-state";
@@ -30,6 +31,8 @@ type TableRowColumnMutationResult = {
30
31
  type: "applied";
31
32
  transaction: Transaction;
32
33
  revisionId: number | null;
34
+ /** Every revision written: a column change writes one per cell. */
35
+ revisionIds: readonly number[];
33
36
  } | {
34
37
  type: "unsupported";
35
38
  };
@@ -117,8 +120,10 @@ type ApplyTableColumnDeletionOptions = {
117
120
  deletion: TableColumnDeletion;
118
121
  insertedColumnCount: number;
119
122
  revision: TableStructureRevision | null;
123
+ /** Where to defer closing rows the deletion leaves without cells, when it runs in a batch. */
124
+ emptiedRows?: RowsEmptiedInBatch;
120
125
  };
121
- declare const applyTableColumnDeletion: ({ tr, deletion, insertedColumnCount, revision }: ApplyTableColumnDeletionOptions) => TableRowColumnMutationResult;
126
+ declare const applyTableColumnDeletion: ({ tr, deletion, insertedColumnCount, revision, emptiedRows }: ApplyTableColumnDeletionOptions) => TableRowColumnMutationResult;
122
127
  type ApplyTableRowDeletionOptions = {
123
128
  tr: Transaction;
124
129
  deletion: TableRowDeletion;
@@ -1,10 +1,19 @@
1
1
  import { markStructuralChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
2
- import { reconcileTableGridAfterColumnInsertion, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCells, removeTableRow } from "../prosemirror/tableGridMutation.js";
2
+ import { markRowsEmptiedInBatch, reconcileTableGridAfterColumnInsertion, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCells, removeTableRow } from "../prosemirror/tableGridMutation.js";
3
3
  import { stripBlockIdentityAttrs } from "./block-identity.js";
4
4
  import { findEnclosingTableCell, findEnclosingTableRow } from "./table-targets.js";
5
5
  import { tableRowFromTemplate } from "./table-template.js";
6
6
  import { TableMap, columnIsHeader, removeColumn, rowIsHeader, tableNodeTypes } from "prosemirror-tables";
7
7
  //#region src/ai-edits/table-row-column-mutations.ts
8
+ /**
9
+ * The revision of the `index`th cell a column change marks. The save writes
10
+ * each cell's marker as a revision of its own, and each is accepted or
11
+ * rejected on its own; the reviewer's revisions are those from the start.
12
+ */
13
+ const cellRevision = (revision, index) => ({
14
+ ...revision,
15
+ revisionId: revision.revisionId + index
16
+ });
8
17
  const UNPLACED_TEXT_PREVIEW_LENGTH = 40;
9
18
  const previewCellText = (text) => JSON.stringify(text.length > UNPLACED_TEXT_PREVIEW_LENGTH ? `${text.slice(0, UNPLACED_TEXT_PREVIEW_LENGTH)}…` : text);
10
19
  /**
@@ -165,6 +174,7 @@ const applyTableColumnInsertion = ({ tr, insertion, cellTexts, revision }) => {
165
174
  });
166
175
  if (!actions || revision && actions.some(({ type }) => type === "setColspan")) return { type: "unsupported" };
167
176
  const mapFrom = tr.mapping.maps.length;
177
+ let markedCells = 0;
168
178
  for (const action of actions) {
169
179
  const position = tr.mapping.slice(mapFrom).map(tablePosition + 1 + action.position);
170
180
  if (action.type === "setColspan") {
@@ -175,7 +185,7 @@ const applyTableColumnInsertion = ({ tr, insertion, cellTexts, revision }) => {
175
185
  ...action.cell.attrs,
176
186
  cellMarker: {
177
187
  kind: "ins",
178
- info: revision
188
+ info: cellRevision(revision, markedCells++)
179
189
  }
180
190
  }, action.cell.content) : action.cell;
181
191
  tr.insert(position, cell);
@@ -186,9 +196,9 @@ const applyTableColumnInsertion = ({ tr, insertion, cellTexts, revision }) => {
186
196
  previousTable: table,
187
197
  insertedColumn: insertion.columnIndex
188
198
  });
189
- return applied(tr, revision);
199
+ return applied(tr, revision, markedCells);
190
200
  };
191
- const applyTableColumnDeletion = ({ tr, deletion, insertedColumnCount, revision }) => {
201
+ const applyTableColumnDeletion = ({ tr, deletion, insertedColumnCount, revision, emptiedRows }) => {
192
202
  const tablePosition = tr.mapping.map(deletion.tablePosition, 1);
193
203
  const table = tr.doc.nodeAt(tablePosition);
194
204
  if (!table || table.type.spec["tableRole"] !== "table") return { type: "unsupported" };
@@ -202,12 +212,12 @@ const applyTableColumnDeletion = ({ tr, deletion, insertedColumnCount, revision
202
212
  columnIndex
203
213
  });
204
214
  if (!cellPositions) return { type: "unsupported" };
205
- for (const cellPosition of cellPositions) tr.setNodeAttribute(tablePosition + 1 + cellPosition, "cellMarker", {
215
+ for (const [index, cellPosition] of cellPositions.entries()) tr.setNodeAttribute(tablePosition + 1 + cellPosition, "cellMarker", {
206
216
  kind: "del",
207
- info: revision
217
+ info: cellRevision(revision, index)
208
218
  });
209
219
  markStructuralChange(tr);
210
- return applied(tr, revision);
220
+ return applied(tr, revision, cellPositions.length);
211
221
  }
212
222
  if (map.width === 1) {
213
223
  const transaction = deleteTableNode({
@@ -232,7 +242,13 @@ const applyTableColumnDeletion = ({ tr, deletion, insertedColumnCount, revision
232
242
  previousTable: table,
233
243
  removedColumn: columnIndex
234
244
  });
235
- removeRowsWithoutCells(tr, tablePosition);
245
+ if (emptiedRows) markRowsEmptiedInBatch({
246
+ tr,
247
+ tablePosition,
248
+ previousTable: table,
249
+ emptied: emptiedRows
250
+ });
251
+ else removeRowsWithoutCells(tr, tablePosition);
236
252
  return applied(tr, null);
237
253
  };
238
254
  const applyTableRowDeletion = ({ tr, deletion, revision }) => {
@@ -269,10 +285,11 @@ const applyTableRowDeletion = ({ tr, deletion, revision }) => {
269
285
  }, at.index());
270
286
  return applied(tr, null);
271
287
  };
272
- const applied = (transaction, revision) => ({
288
+ const applied = (transaction, revision, revisionCount = 1) => ({
273
289
  type: "applied",
274
290
  transaction,
275
- revisionId: revision?.revisionId ?? null
291
+ revisionId: revision?.revisionId ?? null,
292
+ revisionIds: revision ? Array.from({ length: revisionCount }, (_, index) => revision.revisionId + index) : []
276
293
  });
277
294
  const deleteTableNode = ({ tr, tablePosition, table }) => {
278
295
  const tableEnd = tablePosition + table.nodeSize;
@@ -17,6 +17,10 @@ type FolioContentBlockPair = {
17
17
  baseIndex: number;
18
18
  revisedIndex: number;
19
19
  };
20
+ type IncreasingPairOptions = {
21
+ priority?: (pair: FolioContentBlockPair) => number;
22
+ tieBreak?: "earliest" | "minimum-tail";
23
+ };
20
24
  /**
21
25
  * Longest strictly increasing subsequence by revised index.
22
26
  *
@@ -24,7 +28,7 @@ type FolioContentBlockPair = {
24
28
  * preserving the historical deterministic tie break while reducing the
25
29
  * stable-anchor pass from quadratic to O(n log n).
26
30
  */
27
- declare const longestIncreasingFolioContentPairs: (pairs: readonly FolioContentBlockPair[]) => FolioContentBlockPair[];
31
+ declare const longestIncreasingFolioContentPairs: (pairs: readonly FolioContentBlockPair[], options?: IncreasingPairOptions) => FolioContentBlockPair[];
28
32
  type FolioContentAlignedBlockEvent<Block extends FolioContentBlock = FolioContentBlock> = {
29
33
  type: "pair";
30
34
  baseBlock: Block;
@@ -45,15 +45,29 @@ const folioContentIdStability = (block) => block.idStability ?? "stable";
45
45
  * preserving the historical deterministic tie break while reducing the
46
46
  * stable-anchor pass from quadratic to O(n log n).
47
47
  */
48
- const longestIncreasingFolioContentPairs = (pairs) => {
48
+ const longestIncreasingFolioContentPairs = (pairs, options = {}) => {
49
49
  if (pairs.length === 0) return [];
50
50
  const coordinates = [...new Set(pairs.map(({ revisedIndex }) => revisedIndex))].toSorted((left, right) => left - right);
51
51
  const rankByCoordinate = new Map(coordinates.map((coordinate, index) => [coordinate, index + 1]));
52
- const treeLengths = new Int32Array(coordinates.length + 1);
53
52
  const treeIndexes = new Int32Array(coordinates.length + 1).fill(-1);
54
53
  const lengths = new Int32Array(pairs.length).fill(1);
55
54
  const predecessors = new Int32Array(pairs.length).fill(-1);
56
- const earlier = (leftLength, leftIndex, rightLength, rightIndex) => leftLength > rightLength || leftLength === rightLength && leftLength > 0 && leftIndex < rightIndex;
55
+ const priorities = new Int32Array(pairs.length);
56
+ const earlier = ({ leftIndex, rightIndex }) => {
57
+ const leftLength = lengths[leftIndex] ?? 0;
58
+ const rightLength = lengths[rightIndex] ?? 0;
59
+ if (leftLength !== rightLength) return leftLength > rightLength;
60
+ if (leftLength === 0) return false;
61
+ const leftPriority = priorities[leftIndex] ?? 0;
62
+ const rightPriority = priorities[rightIndex] ?? 0;
63
+ if (leftPriority !== rightPriority) return leftPriority > rightPriority;
64
+ if (options.tieBreak === "minimum-tail") {
65
+ const leftTail = pairs[leftIndex]?.revisedIndex ?? Number.POSITIVE_INFINITY;
66
+ const rightTail = pairs[rightIndex]?.revisedIndex ?? Number.POSITIVE_INFINITY;
67
+ if (leftTail !== rightTail) return leftTail < rightTail;
68
+ }
69
+ return leftIndex < rightIndex;
70
+ };
57
71
  let bestEnd = 0;
58
72
  let groupStart = 0;
59
73
  while (groupStart < pairs.length) {
@@ -63,32 +77,38 @@ const longestIncreasingFolioContentPairs = (pairs) => {
63
77
  for (let pairIndex = groupStart; pairIndex < groupEnd; pairIndex++) {
64
78
  const pair = pairs[pairIndex];
65
79
  const rank = pair === void 0 ? void 0 : rankByCoordinate.get(pair.revisedIndex);
66
- if (rank === void 0) continue;
80
+ if (rank === void 0 || pair === void 0) continue;
67
81
  let predecessorLength = 0;
68
82
  let predecessorIndex = -1;
69
83
  for (let cursor = rank - 1; cursor > 0; cursor -= cursor & -cursor) {
70
- const candidateLength = treeLengths[cursor] ?? 0;
71
84
  const candidateIndex = treeIndexes[cursor] ?? -1;
72
- if (earlier(candidateLength, candidateIndex, predecessorLength, predecessorIndex)) {
85
+ const candidateLength = lengths[candidateIndex] ?? 0;
86
+ if (earlier({
87
+ leftIndex: candidateIndex,
88
+ rightIndex: predecessorIndex
89
+ })) {
73
90
  predecessorLength = candidateLength;
74
91
  predecessorIndex = candidateIndex;
75
92
  }
76
93
  }
77
94
  lengths[pairIndex] = predecessorLength + 1;
78
95
  predecessors[pairIndex] = predecessorIndex;
79
- if ((lengths[pairIndex] ?? 0) > (lengths[bestEnd] ?? 0)) bestEnd = pairIndex;
96
+ priorities[pairIndex] = (priorities[predecessorIndex] ?? 0) + (options.priority?.(pair) ?? 0);
97
+ if (earlier({
98
+ leftIndex: pairIndex,
99
+ rightIndex: bestEnd
100
+ })) bestEnd = pairIndex;
80
101
  }
81
102
  for (let pairIndex = groupStart; pairIndex < groupEnd; pairIndex++) {
82
103
  const pair = pairs[pairIndex];
83
104
  const rank = pair === void 0 ? void 0 : rankByCoordinate.get(pair.revisedIndex);
84
105
  if (rank === void 0) continue;
85
- for (let cursor = rank; cursor < treeLengths.length; cursor += cursor & -cursor) {
86
- const currentLength = treeLengths[cursor] ?? 0;
106
+ for (let cursor = rank; cursor < treeIndexes.length; cursor += cursor & -cursor) {
87
107
  const currentIndex = treeIndexes[cursor] ?? -1;
88
- if (earlier(lengths[pairIndex] ?? 0, pairIndex, currentLength, currentIndex)) {
89
- treeLengths[cursor] = lengths[pairIndex] ?? 0;
90
- treeIndexes[cursor] = pairIndex;
91
- }
108
+ if (earlier({
109
+ leftIndex: pairIndex,
110
+ rightIndex: currentIndex
111
+ })) treeIndexes[cursor] = pairIndex;
92
112
  }
93
113
  }
94
114
  groupStart = groupEnd;
@@ -238,27 +258,14 @@ const pairByUniqueExactText = ({ base, revised, baseFrom, baseTo, revisedFrom, r
238
258
  }
239
259
  const orderedCandidates = candidates.toSorted((left, right) => left.baseIndex - right.baseIndex || left.revisedIndex - right.revisedIndex);
240
260
  if (orderedCandidates.length === 0) return [];
241
- const tailRevisedIndexes = [];
242
- const tailCandidateIndexes = [];
243
- const predecessors = new Int32Array(orderedCandidates.length).fill(-1);
244
- orderedCandidates.forEach((candidate, candidateIndex) => {
245
- let lower = 0;
246
- let upper = tailRevisedIndexes.length;
247
- while (lower < upper) {
248
- const middle = lower + Math.floor((upper - lower) / 2);
249
- if ((tailRevisedIndexes[middle] ?? Number.POSITIVE_INFINITY) < candidate.revisedIndex) lower = middle + 1;
250
- else upper = middle;
261
+ return longestIncreasingFolioContentPairs(orderedCandidates, {
262
+ tieBreak: "minimum-tail",
263
+ priority: ({ baseIndex, revisedIndex }) => {
264
+ const baseBlock = base[baseIndex];
265
+ const revisedBlock = revised[revisedIndex];
266
+ return baseBlock && revisedBlock && baseBlock.pairingFacts.id === revisedBlock.pairingFacts.id && baseBlock.pairingFacts.idStability !== revisedBlock.pairingFacts.idStability ? 1 : 0;
251
267
  }
252
- predecessors[candidateIndex] = lower === 0 ? -1 : tailCandidateIndexes[lower - 1] ?? -1;
253
- tailRevisedIndexes[lower] = candidate.revisedIndex;
254
- tailCandidateIndexes[lower] = candidateIndex;
255
268
  });
256
- const pairs = [];
257
- for (let candidateIndex = tailCandidateIndexes.at(-1) ?? -1; candidateIndex !== -1; candidateIndex = predecessors[candidateIndex] ?? -1) {
258
- const candidate = orderedCandidates[candidateIndex];
259
- if (candidate) pairs.push(candidate);
260
- }
261
- return pairs.toReversed();
262
269
  };
263
270
  /**
264
271
  * Unique exact text anchors, then again inside every sub-gap they leave:
@@ -1,6 +1,6 @@
1
1
  import { sourceDocumentOf, styleResolverOf } from "../ai-edits/snapshot.js";
2
2
  import { expectHyperlinkMarkAttrs, expectRunPropertyChangeMarkAttrs, expectTableCellAttrs } from "../prosemirror/attrs/index.js";
3
- import { getDocumentStyleResolver } from "../prosemirror/plugins/documentStyles.js";
3
+ import { getDocumentStyleResolver } from "../prosemirror/plugins/documentStyleState.js";
4
4
  import { applyMarksToRunFormattingRepresentation, expandRunFormattingCarrier, runFormattingCarrierReviewText } from "../prosemirror/runFormattingInlineCarriers.js";
5
5
  import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "../prosemirror/runFormattingReconciliation.js";
6
6
  import { nearestParagraphRunStyleContext } from "../prosemirror/runStyleFormatting.js";
@@ -30,6 +30,7 @@ import { renderPages } from "../layout-painter/renderPage.js";
30
30
  import { tryBuildIncrementalMeasures } from "../paged-layout/incrementalMeasure.js";
31
31
  import { computePerBlockMeasureInputs } from "../paged-layout/sectionBlockWidths.js";
32
32
  import { getMargins, getPageNumbering, getPageSize, twipsToPixels } from "../paged-layout/sectionGeometry.js";
33
+ import { markupViewNotes } from "../prosemirror/markupViewNotes.js";
33
34
  import { projectMarkupView } from "../prosemirror/markupViewProjection.js";
34
35
  import { templatePreviewValuesKey } from "../prosemirror/plugins/templatePreviewValues.js";
35
36
  import { getDocumentWatermark } from "../watermark/index.js";
@@ -215,10 +216,10 @@ function runLayoutPipelineMeasured(deps, state, options) {
215
216
  recordPhaseDuration("flow-blocks", phaseStartedAt);
216
217
  phaseStartedAt = performance.now();
217
218
  const footnoteRefs = collectFootnoteRefs(newBlocks);
218
- const documentFootnotes = document?.package.footnotes;
219
+ const documentFootnotes = markupViewNotes(document?.package.footnotes, markupView, state, document);
219
220
  const hasFootnotes = footnoteRefs.length > 0 && documentFootnotes !== void 0;
220
221
  const footnoteDisplayNumbers = documentFootnotes ? computeNoteDisplayNumbers(documentFootnotes, footnoteRefs.map((ref) => ref.footnoteId)) : void 0;
221
- const documentEndnotes = document?.package.endnotes;
222
+ const documentEndnotes = markupViewNotes(document?.package.endnotes, markupView, state, document);
222
223
  const endnoteDisplayNumbers = documentEndnotes ? computeNoteDisplayNumbers(documentEndnotes, collectEndnoteRefs(newBlocks).map((ref) => ref.endnoteId)) : void 0;
223
224
  const endnoteNumberFormat = document?.package.document.sections?.at(-1)?.properties.endnotePr?.numFmt ?? document?.package.settings?.endnotePr?.numFmt ?? "lowerRoman";
224
225
  const endnoteTexts = endnoteDisplayNumbers ? formatEndnoteTexts(endnoteDisplayNumbers, (displayNumber) => formatOoxmlCounter(displayNumber, endnoteNumberFormat)) : void 0;