@stll/folio-core 0.32.1 → 0.33.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 (222) hide show
  1. package/dist/ai-edits/__fixtures__/paragraphs.d.ts +17 -0
  2. package/dist/ai-edits/__fixtures__/paragraphs.js +33 -0
  3. package/dist/ai-edits/apply.d.ts +49 -3
  4. package/dist/ai-edits/apply.js +692 -75
  5. package/dist/ai-edits/blockRange.d.ts +7 -3
  6. package/dist/ai-edits/blockRange.js +14 -6
  7. package/dist/ai-edits/headless.d.ts +39 -5
  8. package/dist/ai-edits/headless.js +76 -17
  9. package/dist/ai-edits/index.d.ts +6 -6
  10. package/dist/ai-edits/index.js +3 -3
  11. package/dist/ai-edits/read.d.ts +4 -0
  12. package/dist/ai-edits/read.js +30 -6
  13. package/dist/ai-edits/scoped-reading.js +4 -3
  14. package/dist/ai-edits/snapshot.d.ts +42 -2
  15. package/dist/ai-edits/snapshot.js +127 -62
  16. package/dist/ai-edits/table-row-column-mutations.d.ts +24 -1
  17. package/dist/ai-edits/table-row-column-mutations.js +98 -6
  18. package/dist/ai-edits/table-targets.d.ts +12 -3
  19. package/dist/ai-edits/table-targets.js +15 -5
  20. package/dist/ai-edits/types.d.ts +235 -7
  21. package/dist/ai-edits/word-diff.d.ts +54 -11
  22. package/dist/ai-edits/word-diff.js +221 -61
  23. package/dist/compare/__fixtures__/body-sequence.d.ts +33 -0
  24. package/dist/compare/__fixtures__/body-sequence.js +67 -0
  25. package/dist/compare/__fixtures__/nested-table.d.ts +16 -0
  26. package/dist/compare/__fixtures__/nested-table.js +50 -0
  27. package/dist/compare/__fixtures__/numbered-list.d.ts +34 -0
  28. package/dist/compare/__fixtures__/numbered-list.js +85 -0
  29. package/dist/compare/column-alignment.d.ts +27 -0
  30. package/dist/compare/column-alignment.js +162 -0
  31. package/dist/compare/compare.d.ts +107 -0
  32. package/dist/compare/compare.js +406 -0
  33. package/dist/compare/formatting.d.ts +29 -0
  34. package/dist/compare/formatting.js +84 -0
  35. package/dist/compare/plan.d.ts +22 -0
  36. package/dist/compare/plan.js +1059 -0
  37. package/dist/compare/reproducible-package.d.ts +17 -0
  38. package/dist/compare/reproducible-package.js +30 -0
  39. package/dist/compare/scenario.d.ts +77 -0
  40. package/dist/compare/scenario.js +263 -0
  41. package/dist/compare/types.d.ts +282 -0
  42. package/dist/compare/types.js +32 -0
  43. package/dist/compare/verification.d.ts +55 -0
  44. package/dist/compare/verification.js +146 -0
  45. package/dist/compat/eigenpal.d.ts +9 -6
  46. package/dist/compat/eigenpal.js +6 -3
  47. package/dist/controller/layoutPipeline.d.ts +13 -0
  48. package/dist/controller/layoutPipeline.js +15 -1
  49. package/dist/display-list/build/buildContext.d.ts +39 -0
  50. package/dist/display-list/build/buildContext.js +31 -0
  51. package/dist/display-list/build/buildDisplayList.d.ts +79 -0
  52. package/dist/display-list/build/buildDisplayList.js +283 -0
  53. package/dist/display-list/build/colors.d.ts +20 -0
  54. package/dist/display-list/build/colors.js +136 -0
  55. package/dist/display-list/build/floatingImages.d.ts +24 -0
  56. package/dist/display-list/build/floatingImages.js +41 -0
  57. package/dist/display-list/build/fontTable.d.ts +31 -0
  58. package/dist/display-list/build/fontTable.js +97 -0
  59. package/dist/display-list/build/furniture.d.ts +86 -0
  60. package/dist/display-list/build/furniture.js +98 -0
  61. package/dist/display-list/build/glyphs.d.ts +55 -0
  62. package/dist/display-list/build/glyphs.js +103 -0
  63. package/dist/display-list/build/headerFooterPrimitives.d.ts +17 -0
  64. package/dist/display-list/build/headerFooterPrimitives.js +40 -0
  65. package/dist/display-list/build/imagePrimitives.d.ts +35 -0
  66. package/dist/display-list/build/imagePrimitives.js +264 -0
  67. package/dist/display-list/build/pageBorderPrimitives.d.ts +23 -0
  68. package/dist/display-list/build/pageBorderPrimitives.js +111 -0
  69. package/dist/display-list/build/pageFurniture.d.ts +35 -0
  70. package/dist/display-list/build/pageFurniture.js +141 -0
  71. package/dist/display-list/build/paragraphPrimitives.d.ts +19 -0
  72. package/dist/display-list/build/paragraphPrimitives.js +819 -0
  73. package/dist/display-list/build/regions.d.ts +46 -0
  74. package/dist/display-list/build/regions.js +56 -0
  75. package/dist/display-list/build/storyPrimitives.d.ts +29 -0
  76. package/dist/display-list/build/storyPrimitives.js +279 -0
  77. package/dist/display-list/build/strokes.d.ts +19 -0
  78. package/dist/display-list/build/strokes.js +78 -0
  79. package/dist/display-list/build/tablePrimitives.d.ts +38 -0
  80. package/dist/display-list/build/tablePrimitives.js +409 -0
  81. package/dist/display-list/build/textBoxPrimitives.d.ts +14 -0
  82. package/dist/display-list/build/textBoxPrimitives.js +129 -0
  83. package/dist/display-list/build/textDecorations.d.ts +29 -0
  84. package/dist/display-list/build/textDecorations.js +29 -0
  85. package/dist/display-list/build/unsupported.d.ts +57 -0
  86. package/dist/display-list/build/unsupported.js +0 -0
  87. package/dist/display-list/build/watermarkPrimitives.d.ts +15 -0
  88. package/dist/display-list/build/watermarkPrimitives.js +128 -0
  89. package/dist/display-list/dom/renderDisplayListToDom.d.ts +26 -0
  90. package/dist/display-list/dom/renderDisplayListToDom.js +620 -0
  91. package/dist/display-list/editor/displayListPagePainter.d.ts +22 -0
  92. package/dist/display-list/editor/displayListPagePainter.js +63 -0
  93. package/dist/display-list/editor/pageRenderer.d.ts +24 -0
  94. package/dist/display-list/editor/pageRenderer.js +36 -0
  95. package/dist/display-list/primitives.d.ts +95 -0
  96. package/dist/display-list/primitives.js +127 -0
  97. package/dist/display-list/types.d.ts +472 -0
  98. package/dist/display-list/types.js +0 -0
  99. package/dist/document-operations.d.ts +42 -9
  100. package/dist/document-operations.js +171 -16
  101. package/dist/document-stories.d.ts +16 -0
  102. package/dist/document-stories.js +48 -4
  103. package/dist/docx/packageParts.d.ts +35 -0
  104. package/dist/docx/packageParts.js +120 -0
  105. package/dist/docx/paragraphParser.js +22 -22
  106. package/dist/docx/paragraphTraversal.js +1 -1
  107. package/dist/docx/renderedPageBreakNormalization.js +3 -1
  108. package/dist/docx/revisionIdNormalization.d.ts +13 -0
  109. package/dist/docx/revisionIdNormalization.js +103 -0
  110. package/dist/docx/rezip.js +26 -17
  111. package/dist/docx/selectiveSave.js +2 -2
  112. package/dist/docx/serializer/commentSerializer.js +6 -1
  113. package/dist/docx/serializer/paragraphSerializer.js +33 -4
  114. package/dist/docx/serializer/runSerializer.js +11 -10
  115. package/dist/docx/serializer/tableSerializer.js +2 -1
  116. package/dist/docx/server/applyDocxXmlPatchProposal.js +1 -1
  117. package/dist/docx/server/createBilingualDocx.js +3 -2
  118. package/dist/docx/streamingXmlParser.d.ts +13 -1
  119. package/dist/docx/streamingXmlParser.js +49 -11
  120. package/dist/docx/unzip.d.ts +1 -2
  121. package/dist/docx/unzip.js +25 -6
  122. package/dist/docx/xmlParser.d.ts +3 -1
  123. package/dist/docx/xmlParser.js +33 -27
  124. package/dist/export-pdf.d.ts +43 -0
  125. package/dist/export-pdf.js +98 -0
  126. package/dist/fonts/headlessMeasure.d.ts +76 -0
  127. package/dist/fonts/headlessMeasure.js +0 -0
  128. package/dist/fonts/sfnt/parse.d.ts +51 -0
  129. package/dist/fonts/sfnt/parse.js +525 -0
  130. package/dist/fonts/sfnt/subset.d.ts +20 -0
  131. package/dist/fonts/sfnt/subset.js +350 -0
  132. package/dist/fonts/sfnt/tables.d.ts +88 -0
  133. package/dist/fonts/sfnt/tables.js +131 -0
  134. package/dist/fonts/sfnt/woff.d.ts +14 -0
  135. package/dist/fonts/sfnt/woff.js +163 -0
  136. package/dist/generated/text_shaper.js +324 -0
  137. package/dist/generated/text_shaper_bg.wasm +0 -0
  138. package/dist/headless-layout.d.ts +75 -0
  139. package/dist/headless-layout.js +350 -0
  140. package/dist/index.d.ts +9 -6
  141. package/dist/index.js +6 -3
  142. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  143. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  144. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  145. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  146. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -1
  147. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -0
  148. package/dist/layout-engine/measure/advanceComposition.d.ts +62 -0
  149. package/dist/layout-engine/measure/advanceComposition.js +148 -0
  150. package/dist/layout-engine/measure/cache.d.ts +2 -0
  151. package/dist/layout-engine/measure/measureContainer.js +13 -0
  152. package/dist/layout-engine/measure/measureParagraph.js +1 -2
  153. package/dist/layout-engine/measure/measureTypes.d.ts +12 -0
  154. package/dist/layout-engine/measure/tableInlinePlacement.d.ts +3 -2
  155. package/dist/layout-engine/measure/tableInlinePlacement.js +14 -1
  156. package/dist/layout-engine/tableIndentCompatibility.d.ts +5 -0
  157. package/dist/layout-engine/tableIndentCompatibility.js +15 -0
  158. package/dist/layout-engine/types.d.ts +8 -0
  159. package/dist/layout-painter/renderPage.d.ts +29 -1
  160. package/dist/layout-painter/renderPage.js +47 -19
  161. package/dist/layout-painter/renderParagraph.d.ts +21 -2
  162. package/dist/layout-painter/renderParagraph.js +1 -1
  163. package/dist/layout-painter/renderTable.js +37 -4
  164. package/dist/managers/editorShortcuts.d.ts +33 -1
  165. package/dist/managers/editorShortcuts.js +20 -1
  166. package/dist/markdown/renderRuns.js +7 -2
  167. package/dist/markdown/renderTable.js +5 -1
  168. package/dist/model.d.ts +3 -3
  169. package/dist/model.js +2 -2
  170. package/dist/pdf/contentStream.d.ts +73 -0
  171. package/dist/pdf/contentStream.js +143 -0
  172. package/dist/pdf/fonts.d.ts +96 -0
  173. package/dist/pdf/fonts.js +593 -0
  174. package/dist/pdf/images.d.ts +28 -0
  175. package/dist/pdf/images.js +439 -0
  176. package/dist/pdf/objects.d.ts +93 -0
  177. package/dist/pdf/objects.js +237 -0
  178. package/dist/pdf/pageSpace.d.ts +43 -0
  179. package/dist/pdf/pageSpace.js +57 -0
  180. package/dist/pdf/paint.d.ts +32 -0
  181. package/dist/pdf/paint.js +442 -0
  182. package/dist/pdf/writePdf.d.ts +56 -0
  183. package/dist/pdf/writePdf.js +345 -0
  184. package/dist/prosemirror/commands/comments.js +91 -6
  185. package/dist/prosemirror/conversion/fromProseDoc.js +41 -7
  186. package/dist/prosemirror/conversion/toProseDoc.js +41 -4
  187. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +15 -2
  188. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +35 -6
  189. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +2 -2
  190. package/dist/prosemirror/extensions/features/pasteCleanup.js +4 -3
  191. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +3 -1
  192. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +5 -3
  193. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -1
  194. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +9 -3
  195. package/dist/prosemirror/extensions/nodes/TableExtension.js +56 -39
  196. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +3 -1
  197. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +5 -3
  198. package/dist/prosemirror/plugins/suggestionMode.js +1 -0
  199. package/dist/prosemirror/revisionCarriers.js +19 -2
  200. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +2 -2
  201. package/dist/prosemirror/utils/extractTrackedChanges.js +59 -23
  202. package/dist/prosemirror/validation.js +55 -27
  203. package/dist/prosemirror/zeroWidthAnchors.d.ts +10 -0
  204. package/dist/prosemirror/zeroWidthAnchors.js +23 -0
  205. package/dist/redline.js +12 -79
  206. package/dist/server.d.ts +4 -4
  207. package/dist/server.js +2 -2
  208. package/dist/shaping/placeRun.d.ts +51 -0
  209. package/dist/shaping/placeRun.js +84 -0
  210. package/dist/shaping/shaper.d.ts +92 -0
  211. package/dist/shaping/shaper.js +102 -0
  212. package/dist/types/block-id.d.ts +18 -2
  213. package/dist/types/block-id.js +49 -5
  214. package/dist/types/content.d.ts +2 -2
  215. package/dist/utils/clipboard.js +4 -3
  216. package/dist/utils/fontResolver.js +183 -0
  217. package/dist/utils/htmlComments.d.ts +17 -0
  218. package/dist/utils/htmlComments.js +22 -0
  219. package/dist/utils/scriptSegments.d.ts +12 -1
  220. package/dist/utils/scriptSegments.js +17 -1
  221. package/dist/version-comparison.d.ts +1 -1
  222. package/package.json +7 -3
@@ -10,6 +10,33 @@ type FolioAIBlockPreviewRun = {
10
10
  fontSizePt?: number;
11
11
  color?: string;
12
12
  };
13
+ /**
14
+ * Where a block sits inside its innermost enclosing table. Every index is
15
+ * zero-based: `tableIndex` counts tables in document order across the story,
16
+ * `rowIndex` is the row's index in that table, `cellIndex` is the cell's
17
+ * PHYSICAL index within the row (a merged cell occupies one slot, so this is
18
+ * not a grid column), and `paragraphIndex` orders the block among the cell's
19
+ * own blocks. Absent on a block that is not inside a table.
20
+ */
21
+ type FolioAIBlockTableLocation = {
22
+ /**
23
+ * Document-order index of the OUTERMOST table the block sits in — the same
24
+ * as `tableIndex` unless tables nest. A comparison aligns on this: a table
25
+ * inside a cell is part of its parent, not a structure of its own that can
26
+ * be paired against one somewhere else.
27
+ */
28
+ outerTableIndex: number;
29
+ tableIndex: number;
30
+ rowIndex: number;
31
+ cellIndex: number;
32
+ /** Grid column occupied by the cell's left edge, derived from `TableMap`. */
33
+ gridColumnIndex: number;
34
+ /** Number of grid columns occupied by this physical cell. */
35
+ columnSpan: number;
36
+ /** Number of grid rows occupied by this physical cell. */
37
+ rowSpan: number;
38
+ paragraphIndex: number;
39
+ };
13
40
  type FolioAIBlock = {
14
41
  id: string;
15
42
  kind: FolioAIBlockKind;
@@ -18,13 +45,42 @@ type FolioAIBlock = {
18
45
  headingLevel?: number;
19
46
  displayLabel?: string;
20
47
  styleId?: string;
48
+ /**
49
+ * `w:numPr/w:ilvl`: the block's list indent level. Present only on a block
50
+ * that carries numbering, and the only pPr property a redline can move
51
+ * without touching a word — a demoted list item reads as unchanged text and
52
+ * is not.
53
+ */
54
+ listLevel?: number;
21
55
  previewRuns?: FolioAIBlockPreviewRun[];
56
+ table?: FolioAIBlockTableLocation;
22
57
  };
58
+ /**
59
+ * The paragraph properties an operation may set. A subset of `w:pPrChange`'s
60
+ * scope: the two a comparison can see in a block projection, and the two an
61
+ * agent has a reason to change.
62
+ */
63
+ type FolioAIBlockParagraphProperties = {
64
+ /** `w:pStyle`. `null` clears the style back to the default. */
65
+ styleId?: string | null;
66
+ /**
67
+ * `w:numPr/w:ilvl`, zero-based. `null` removes `w:numPr` altogether: the
68
+ * paragraph stops being a list item rather than moving to another level.
69
+ */
70
+ listLevel?: number | null;
71
+ };
72
+ /**
73
+ * Every paragraph of one story, blank ones included.
74
+ *
75
+ * A blank paragraph is part of a document's shape: an empty cell is a column,
76
+ * an empty row is a row, and an operation or a comparison that cannot address
77
+ * them cannot describe what changed around them. A surface that reads the
78
+ * document for a person or a model wants only the paragraphs that carry text,
79
+ * and says so with `isFolioAIContentBlock`.
80
+ */
23
81
  type FolioAIEditSnapshot = {
24
82
  blocks: FolioAIBlock[];
25
83
  anchors: Record<string, FolioAIBlockAnchor>;
26
- /** Hidden empty paragraph used to anchor insertions when `blocks` is empty. */
27
- emptyDocumentAnchorId?: string;
28
84
  };
29
85
  type FolioAIBlockAnchor = {
30
86
  id: string;
@@ -113,6 +169,7 @@ type FolioAIInlineFormatting = {
113
169
  bold?: boolean;
114
170
  italic?: boolean;
115
171
  underline?: boolean;
172
+ strike?: boolean;
116
173
  };
117
174
  /**
118
175
  * A party in an `insertSignatureTable` op. Mirrors the
@@ -161,8 +218,27 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
161
218
  id: string;
162
219
  type: "insertAfterBlock" | "insertBeforeBlock";
163
220
  blockId: string;
221
+ /**
222
+ * The paragraph text to insert. A line break splits `text` into
223
+ * consecutive paragraphs at the same anchor instead of becoming
224
+ * literal newlines inside one paragraph: only the first paragraph
225
+ * gets `styleId` / `inheritFormatting`, later ones use body
226
+ * formatting. Blank lines are dropped. Reported as a
227
+ * `splitMultilineText` normalization when it happens.
228
+ *
229
+ * `""` inserts a BLANK paragraph, and is a real edit: adding an empty
230
+ * line is a change a reader sees, and a document that has one where
231
+ * another does not differs. It is applied like any other insertion,
232
+ * with a tracked paragraph mark, so rejecting closes it away.
233
+ */
164
234
  text: string;
165
235
  inheritFormatting?: boolean;
236
+ /**
237
+ * Links this insertion to the deletion that carries the same
238
+ * `moveId`: together they are one relocation, written as `w:moveTo`
239
+ * and `w:moveFrom`. See `deleteBlock`.
240
+ */
241
+ moveId?: string;
166
242
  /**
167
243
  * When true, mark the inserted paragraph with
168
244
  * `pageBreakBefore` so the layout engine starts it on a
@@ -173,9 +249,19 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
173
249
  * Override the paragraph `styleId` attr of the inserted
174
250
  * block (e.g. `ClauseHeading1`). When omitted the inserted
175
251
  * block inherits the source block's styleId via
176
- * `inheritFormatting`.
252
+ * `inheritFormatting`; `null` gives it no style at all, which
253
+ * inheritance alone cannot say.
177
254
  */
178
- styleId?: string;
255
+ styleId?: string | null;
256
+ /**
257
+ * Override `w:numPr/w:ilvl` on the inserted block, keeping the
258
+ * anchor's `w:numId`. Without it the inserted paragraph takes the
259
+ * anchor's level, which is the wrong one whenever the new item sits
260
+ * beside a list item at a different depth. `null` gives it no
261
+ * numbering at all — an ordinary paragraph next to a list item, which
262
+ * inheritance alone cannot say.
263
+ */
264
+ listLevel?: number | null;
179
265
  comment?: FolioAIComment;
180
266
  } | {
181
267
  id: string;
@@ -185,11 +271,110 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
185
271
  preserveFormatting?: boolean;
186
272
  styleId?: string;
187
273
  comment?: FolioAIComment;
188
- } | {
274
+ } |
275
+ /**
276
+ * Delete the whole block. A block with words loses them and its paragraph
277
+ * mark; a BLANK block has only a paragraph mark to lose, and loses it, so
278
+ * the empty line goes away rather than the operation doing nothing.
279
+ */
280
+ {
189
281
  id: string;
190
282
  type: "deleteBlock";
191
283
  blockId: string;
284
+ /**
285
+ * Links this deletion to the insertion that carries the same
286
+ * `moveId`: together they are one relocation, written as `w:moveFrom`
287
+ * and `w:moveTo` rather than as an unrelated deletion and insertion.
288
+ * A `moveId` that does not name exactly one of each is reported as an
289
+ * `unpairedMove` normalization and both halves apply plainly.
290
+ */
291
+ moveId?: string;
192
292
  comment?: FolioAIComment;
293
+ } |
294
+ /**
295
+ * Break the block in two at `offset`, moving a paragraph mark and no
296
+ * words. In tracked-changes mode the first half carries an INSERTED
297
+ * paragraph mark, so accepting keeps the break and rejecting closes it;
298
+ * the alternative — rewriting the first half and inserting the second —
299
+ * claims the tail was newly written when nobody touched it.
300
+ */
301
+ {
302
+ id: string;
303
+ type: "splitBlock";
304
+ /** Offset in the block's text. Must fall strictly inside it. */
305
+ offset: number;
306
+ /**
307
+ * Text at `offset` the break replaces — the space between the two
308
+ * halves, when the split consumed one. Deleted in `"direct"` mode and
309
+ * deletion-marked in tracked mode, so rejecting restores it.
310
+ */
311
+ separator?: string;
312
+ blockId: string;
313
+ } |
314
+ /**
315
+ * Add a whole table next to the anchor block, its rows marked inserted in
316
+ * tracked mode. `insertTableRow` can only grow a table that already
317
+ * exists; a comparison whose target gained one needs to say so.
318
+ */
319
+ {
320
+ id: string;
321
+ type: "insertTable";
322
+ blockId: string;
323
+ /** Place the table after the anchor (default) or before it. */
324
+ position?: "after" | "before";
325
+ /**
326
+ * Cell texts row by row. Every row must hold the same number of cells.
327
+ *
328
+ * A cell holds paragraphs, not lines: a line break in a cell's text
329
+ * starts a new paragraph in that cell, and a blank line is a blank
330
+ * paragraph. That is not the rule `insertAfterBlock` follows for
331
+ * prose, where a blank line between two model-written clauses is
332
+ * formatting noise and is dropped — a cell's text describes paragraphs
333
+ * that exist, so dropping one would lose a block.
334
+ */
335
+ rows: readonly (readonly string[])[];
336
+ } |
337
+ /**
338
+ * Remove the whole table the block sits in, its rows marked deleted in
339
+ * tracked mode. The mirror of `insertTable`.
340
+ */
341
+ {
342
+ id: string;
343
+ type: "deleteTable";
344
+ blockId: string;
345
+ } |
346
+ /**
347
+ * Replace the block's paragraph properties, recorded as a `w:pPrChange`
348
+ * in tracked mode so the previous set is restored on reject. The edit
349
+ * that moves no words: a list item demoted a level, a paragraph restyled
350
+ * as a heading.
351
+ */
352
+ {
353
+ id: string;
354
+ type: "setBlockParagraphProperties";
355
+ blockId: string;
356
+ properties: FolioAIBlockParagraphProperties;
357
+ } |
358
+ /**
359
+ * Join the block with the one after it, the mirror of `splitBlock`: in
360
+ * tracked-changes mode the block carries a DELETED paragraph mark, so
361
+ * accepting closes the break and rejecting keeps it.
362
+ *
363
+ * Refused when the block has no joinable sibling — the last paragraph of
364
+ * a table cell, or of the story — because a deleted mark there would
365
+ * accept into a join that cannot happen and leave a revision no reader
366
+ * can resolve.
367
+ */
368
+ {
369
+ id: string;
370
+ type: "mergeBlockWithNext";
371
+ /**
372
+ * Text the join inserts between the two halves — the space the
373
+ * paragraph break used to stand in for. Insertion-marked in tracked
374
+ * mode, so rejecting removes it along with the join.
375
+ */
376
+ separator?: string;
377
+ blockId: string;
193
378
  } | {
194
379
  id: string;
195
380
  type: "commentOnBlock";
@@ -214,7 +399,18 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
214
399
  /** Stable paragraph anchor inside the row that receives the new sibling. */
215
400
  blockId: string;
216
401
  position?: "after" | "before";
217
- /** Initial text for each physical cell in source order; omitted cells stay empty. */
402
+ /**
403
+ * Initial text for each cell of the new row, in order — the same order
404
+ * a block's `table.cellIndex` counts. Cells left unnamed stay empty.
405
+ *
406
+ * Sized against the table's COLUMN count, which is the most cells any
407
+ * row of it could have: more texts than that is refused rather than
408
+ * silently truncated, and fewer is not, so a row the table can hold is
409
+ * no longer refused because a span makes it narrower than the table.
410
+ *
411
+ * A line break in a cell's text starts a new paragraph in that cell,
412
+ * as in `insertTable`.
413
+ */
218
414
  cellTexts?: string[];
219
415
  } | {
220
416
  id: string;
@@ -318,9 +514,41 @@ type FolioAIEditSkippedOperation = {
318
514
  id: string;
319
515
  reason: FolioAIEditSkipReason;
320
516
  };
517
+ /**
518
+ * One automatic adjustment `apply.ts` made to an operation's input to keep the
519
+ * applied result well-formed. Reported rather than applied silently: the
520
+ * caller asked for something the document could not hold, and gets told what
521
+ * it got instead.
522
+ */
523
+ type FolioAIEditNormalization =
524
+ /**
525
+ * A line-break in `insertAfterBlock` / `insertBeforeBlock`'s `text` cannot
526
+ * become one paragraph with an embedded break (Word paragraphs are single
527
+ * lines); the applier split it into one paragraph per non-blank line.
528
+ */
529
+ {
530
+ id: string;
531
+ code: "splitMultilineText";
532
+ /** Number of paragraphs the operation's `text` was split into. */
533
+ paragraphCount: number;
534
+ } |
535
+ /**
536
+ * A `moveId` that did not name exactly one deletion and one insertion in
537
+ * the batch. The operation still applies, as an ordinary insertion or
538
+ * deletion: half a move pair is not a move, and `w:moveTo` without its
539
+ * `w:moveFrom` is a relocation from nowhere.
540
+ */
541
+ {
542
+ id: string;
543
+ code: "unpairedMove";
544
+ moveId: string;
545
+ };
546
+ type FolioAIEditNormalizationCode = FolioAIEditNormalization["code"];
321
547
  type FolioAIEditApplyResult = {
322
548
  applied: FolioAIEditAppliedOperation[];
323
549
  skipped: FolioAIEditSkippedOperation[];
550
+ /** Present only when at least one operation triggered a normalization. */
551
+ normalizations?: FolioAIEditNormalization[];
324
552
  };
325
553
  //#endregion
326
- export { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineFormatting, FolioAISignatureParty, FolioAITextRangeHandle, FolioDocumentNavigationTarget, FolioDocumentOutline, FolioDocumentOutlineEntry, FolioDocumentSection, FolioDocumentSectionHandle, FolioDocumentSectionReadResult };
554
+ export { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockParagraphProperties, FolioAIBlockPreviewRun, FolioAIBlockTableLocation, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineFormatting, FolioAISignatureParty, FolioAITextRangeHandle, FolioDocumentNavigationTarget, FolioDocumentOutline, FolioDocumentOutlineEntry, FolioDocumentSection, FolioDocumentSectionHandle, FolioDocumentSectionReadResult };
@@ -1,20 +1,63 @@
1
1
  //#region src/ai-edits/word-diff.d.ts
2
2
  /**
3
- * Word-level diff between two strings. Tokenises on whitespace
4
- * boundaries (preserving the whitespace as part of each token), runs
5
- * an LCS, and returns a left-to-right ordered list of segments where
6
- * shared runs render as `equal`, removed runs as `del`, and added
7
- * runs as `ins`. Used by both the panel (to render minimal-change
8
- * redlines) and the apply engine (so tracked changes only mark the
9
- * divergent tokens, not the whole replaced span).
3
+ * Diff between two strings, as the segments a redline is drawn from.
10
4
  *
11
- * O(n*m) on token counts; if a single replacement ever holds more
12
- * than a few hundred tokens, swap for a streaming diff.
5
+ * Tokenises (by default on whitespace boundaries, preserving the whitespace as
6
+ * part of each token), runs an LCS, and returns a left-to-right ordered list of
7
+ * segments where shared runs render as `equal`, removed runs as `del`, and
8
+ * added runs as `ins`. Used by the panel (to render minimal-change redlines),
9
+ * the version comparison, and the apply engine (so tracked changes mark only
10
+ * the divergent tokens, not the whole replaced span).
11
+ *
12
+ * ## The shortest diff is not the most readable one
13
+ *
14
+ * An LCS maximises matched characters, which on a rewritten sentence means
15
+ * matching every stray "the" and comma it can reach. The reader then gets a
16
+ * shredded paragraph — a dozen struck-through fragments interleaved with a
17
+ * dozen inserted ones — where one deletion followed by one insertion says the
18
+ * same thing and can actually be read. Three rules pull the output back:
19
+ *
20
+ * 1. A match made only of separators is not a match ({@link isSeparatorOnly}).
21
+ * 2. A match too short to carry meaning is dropped unless it opens the string,
22
+ * where it is the reader's anchor rather than an island.
23
+ * 3. When what survives is still too fragmented for its length, the whole
24
+ * paragraph is one replacement ({@link isTooFragmented}).
25
+ *
26
+ * O(n*m) on token counts; past {@link MAX_WORD_DIFF_CELLS} the DP is skipped
27
+ * for a single whole-string `del` + `ins` pair.
13
28
  */
14
29
  type WordDiffSegment = {
15
30
  type: "equal" | "del" | "ins";
16
31
  text: string;
17
32
  };
18
- declare const diffWordSegments: (before: string, after: string) => WordDiffSegment[];
33
+ /**
34
+ * What one token is. `"word"` tokenises on whitespace and is what a redline
35
+ * over prose should use; `"character"` marks the changed letters inside a
36
+ * word, which reads well for a reference number or a date and badly for a
37
+ * sentence.
38
+ */
39
+ declare const WORD_DIFF_GRANULARITIES: readonly ["word", "character"];
40
+ type WordDiffGranularity = (typeof WORD_DIFF_GRANULARITIES)[number];
41
+ /**
42
+ * Differences the caller does not want marked.
43
+ *
44
+ * A normalized run is reported as `equal` and carries the BEFORE string's
45
+ * text, so the before side still reconstructs exactly while the after side
46
+ * reconstructs only up to the normalization. A caller that must reproduce the
47
+ * after string — anything generating tracked changes — leaves both off.
48
+ */
49
+ type WordDiffNormalization = {
50
+ /** `"Shall"` and `"shall"` are the same token. */
51
+ case?: boolean;
52
+ /** Whitespace around and inside a token does not distinguish it. */
53
+ whitespace?: boolean;
54
+ };
55
+ type WordDiffOptions = {
56
+ /** Default `"word"`. */
57
+ granularity?: WordDiffGranularity;
58
+ /** Default: nothing normalized, so both strings reconstruct exactly. */
59
+ normalization?: WordDiffNormalization;
60
+ };
61
+ declare const diffWordSegments: (before: string, after: string, options?: WordDiffOptions) => WordDiffSegment[];
19
62
  //#endregion
20
- export { WordDiffSegment, diffWordSegments };
63
+ export { WORD_DIFF_GRANULARITIES, WordDiffGranularity, WordDiffNormalization, WordDiffOptions, WordDiffSegment, diffWordSegments };