@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
@@ -11,6 +11,11 @@ const FOLIO_DOCUMENT_OPERATION_TYPES = Object.freeze([
11
11
  "insertBeforeBlock",
12
12
  "replaceBlock",
13
13
  "deleteBlock",
14
+ "splitBlock",
15
+ "mergeBlockWithNext",
16
+ "setBlockParagraphProperties",
17
+ "insertTable",
18
+ "deleteTable",
14
19
  "commentOnBlock",
15
20
  "insertSignatureTable",
16
21
  "insertTableRow",
@@ -56,6 +61,11 @@ const FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE = Object.freeze({
56
61
  insertBeforeBlock: DIRECT_TRACKED_AND_SUGGESTED_MODES,
57
62
  replaceBlock: DIRECT_TRACKED_AND_SUGGESTED_MODES,
58
63
  deleteBlock: DIRECT_TRACKED_AND_SUGGESTED_MODES,
64
+ splitBlock: DIRECT_AND_TRACKED_MODES,
65
+ mergeBlockWithNext: DIRECT_AND_TRACKED_MODES,
66
+ setBlockParagraphProperties: DIRECT_AND_TRACKED_MODES,
67
+ insertTable: DIRECT_AND_TRACKED_MODES,
68
+ deleteTable: DIRECT_AND_TRACKED_MODES,
59
69
  commentOnBlock: DIRECT_AND_TRACKED_MODES,
60
70
  insertSignatureTable: DIRECT_AND_SUGGESTED_MODES,
61
71
  insertTableRow: DIRECT_TRACKED_AND_SUGGESTED_MODES,
@@ -147,6 +157,49 @@ const readNonNegativeInteger = (value, key, path) => {
147
157
  if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 0) return candidate;
148
158
  return invalidBatch(`${path}.${key}`, "expected a non-negative integer");
149
159
  };
160
+ /**
161
+ * A non-negative integer that may also be cleared. `undefined` is "say
162
+ * nothing"; `null` is "there is none", which is a different instruction and
163
+ * the one absence alone cannot give.
164
+ */
165
+ const readClearableNonNegativeInteger = (value, key, path) => {
166
+ const candidate = value[key];
167
+ if (candidate === void 0) return;
168
+ return candidate === null ? null : readNonNegativeInteger(value, key, path);
169
+ };
170
+ /**
171
+ * A rectangular grid of cell texts. Rectangular because a table whose rows
172
+ * hold different cell counts is not a table any consumer can lay out, and the
173
+ * batch is the last place to catch that.
174
+ */
175
+ const readTableRows = (value, path) => {
176
+ const rows = value["rows"];
177
+ const rowsPath = `${path}.rows`;
178
+ if (!Array.isArray(rows) || rows.length === 0) return invalidBatch(rowsPath, "expected a non-empty array");
179
+ const parsed = rows.map((row, index) => {
180
+ if (!Array.isArray(row) || row.length === 0) return invalidBatch(`${rowsPath}[${String(index)}]`, "expected a non-empty array");
181
+ return row.map((cell, cellIndex) => {
182
+ if (typeof cell !== "string") return invalidBatch(`${rowsPath}[${String(index)}][${String(cellIndex)}]`, "expected a string");
183
+ return cell;
184
+ });
185
+ });
186
+ const width = parsed[0]?.length ?? 0;
187
+ if (parsed.some((row) => row.length !== width)) return invalidBatch(rowsPath, "expected every row to hold the same number of cells");
188
+ return parsed;
189
+ };
190
+ const readParagraphProperties = (value, path) => {
191
+ const candidate = value["properties"];
192
+ const propertiesPath = `${path}.properties`;
193
+ if (!isPlainObject(candidate)) return invalidBatch(propertiesPath, "expected an object");
194
+ assertAllowedKeys(candidate, propertiesPath, ["styleId", "listLevel"]);
195
+ const styleId = candidate["styleId"] === null ? null : readOptionalString(candidate, "styleId", propertiesPath);
196
+ const listLevel = readClearableNonNegativeInteger(candidate, "listLevel", propertiesPath);
197
+ if (styleId === void 0 && listLevel === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
198
+ return {
199
+ ...styleId !== void 0 && { styleId },
200
+ ...listLevel !== void 0 && { listLevel }
201
+ };
202
+ };
150
203
  const readTextRange = (value, path) => {
151
204
  const candidate = value["range"];
152
205
  const rangePath = `${path}.range`;
@@ -184,16 +237,19 @@ const readInlineFormatting = (value, path) => {
184
237
  assertAllowedKeys(candidate, formattingPath, [
185
238
  "bold",
186
239
  "italic",
187
- "underline"
240
+ "underline",
241
+ "strike"
188
242
  ]);
189
243
  const bold = readOptionalBoolean(candidate, "bold", formattingPath);
190
244
  const italic = readOptionalBoolean(candidate, "italic", formattingPath);
191
245
  const underline = readOptionalBoolean(candidate, "underline", formattingPath);
192
- if (bold === void 0 && italic === void 0 && underline === void 0) return invalidBatch(formattingPath, "expected at least one formatting property");
246
+ const strike = readOptionalBoolean(candidate, "strike", formattingPath);
247
+ if (bold === void 0 && italic === void 0 && underline === void 0 && strike === void 0) return invalidBatch(formattingPath, "expected at least one formatting property");
193
248
  return {
194
249
  ...bold !== void 0 && { bold },
195
250
  ...italic !== void 0 && { italic },
196
- ...underline !== void 0 && { underline }
251
+ ...underline !== void 0 && { underline },
252
+ ...strike !== void 0 && { strike }
197
253
  };
198
254
  };
199
255
  const readOptionalComment = (value, path) => {
@@ -271,6 +327,8 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
271
327
  ...COMMON_OPERATION_KEYS,
272
328
  "text",
273
329
  "inheritFormatting",
330
+ "listLevel",
331
+ "moveId",
274
332
  "pageBreakBefore",
275
333
  "styleId",
276
334
  "comment"
@@ -279,6 +337,8 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
279
337
  ...COMMON_OPERATION_KEYS,
280
338
  "text",
281
339
  "inheritFormatting",
340
+ "listLevel",
341
+ "moveId",
282
342
  "pageBreakBefore",
283
343
  "styleId",
284
344
  "comment"
@@ -290,7 +350,24 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
290
350
  "styleId",
291
351
  "comment"
292
352
  ],
293
- deleteBlock: [...COMMON_OPERATION_KEYS, "comment"],
353
+ deleteBlock: [
354
+ ...COMMON_OPERATION_KEYS,
355
+ "moveId",
356
+ "comment"
357
+ ],
358
+ splitBlock: [
359
+ ...COMMON_OPERATION_KEYS,
360
+ "offset",
361
+ "separator"
362
+ ],
363
+ mergeBlockWithNext: [...COMMON_OPERATION_KEYS, "separator"],
364
+ setBlockParagraphProperties: [...COMMON_OPERATION_KEYS, "properties"],
365
+ insertTable: [
366
+ ...COMMON_OPERATION_KEYS,
367
+ "position",
368
+ "rows"
369
+ ],
370
+ deleteTable: COMMON_OPERATION_KEYS,
294
371
  commentOnBlock: [
295
372
  ...COMMON_OPERATION_KEYS,
296
373
  "quote",
@@ -383,6 +460,49 @@ const parseDocumentOperation = (value, index) => {
383
460
  formatting: readInlineFormatting(value, path)
384
461
  };
385
462
  const blockId = readString(value, "blockId", path);
463
+ if (type === "insertTable") {
464
+ const position = value["position"];
465
+ if (position !== void 0 && position !== "after" && position !== "before") return invalidBatch(`${path}.position`, "expected \"after\" or \"before\" when provided");
466
+ return {
467
+ ...operationMeta,
468
+ id,
469
+ type,
470
+ blockId,
471
+ ...position !== void 0 && { position },
472
+ rows: readTableRows(value, path)
473
+ };
474
+ }
475
+ if (type === "deleteTable") return {
476
+ ...operationMeta,
477
+ id,
478
+ type,
479
+ blockId
480
+ };
481
+ if (type === "setBlockParagraphProperties") return {
482
+ ...operationMeta,
483
+ id,
484
+ type,
485
+ blockId,
486
+ properties: readParagraphProperties(value, path)
487
+ };
488
+ if (type === "splitBlock" || type === "mergeBlockWithNext") {
489
+ const separator = readOptionalString(value, "separator", path);
490
+ if (type === "mergeBlockWithNext") return {
491
+ ...operationMeta,
492
+ id,
493
+ type,
494
+ blockId,
495
+ ...separator !== void 0 && { separator }
496
+ };
497
+ return {
498
+ ...operationMeta,
499
+ id,
500
+ type,
501
+ blockId,
502
+ offset: readNonNegativeInteger(value, "offset", path),
503
+ ...separator !== void 0 && { separator }
504
+ };
505
+ }
386
506
  if (type === "replaceInBlock") return {
387
507
  ...operationMeta,
388
508
  id,
@@ -395,7 +515,9 @@ const parseDocumentOperation = (value, index) => {
395
515
  if (type === "insertAfterBlock" || type === "insertBeforeBlock") {
396
516
  const inheritFormatting = readOptionalBoolean(value, "inheritFormatting", path);
397
517
  const pageBreakBefore = readOptionalBoolean(value, "pageBreakBefore", path);
398
- const styleId = readOptionalString(value, "styleId", path);
518
+ const styleId = value["styleId"] === null ? null : readOptionalString(value, "styleId", path);
519
+ const moveId = readOptionalString(value, "moveId", path);
520
+ const listLevel = readClearableNonNegativeInteger(value, "listLevel", path);
399
521
  return {
400
522
  ...operationMeta,
401
523
  id,
@@ -403,6 +525,8 @@ const parseDocumentOperation = (value, index) => {
403
525
  blockId,
404
526
  text: readString(value, "text", path),
405
527
  ...inheritFormatting !== void 0 && { inheritFormatting },
528
+ ...listLevel !== void 0 && { listLevel },
529
+ ...moveId !== void 0 && { moveId },
406
530
  ...pageBreakBefore !== void 0 && { pageBreakBefore },
407
531
  ...styleId !== void 0 && { styleId },
408
532
  ...comment !== void 0 && { comment }
@@ -422,13 +546,17 @@ const parseDocumentOperation = (value, index) => {
422
546
  ...comment !== void 0 && { comment }
423
547
  };
424
548
  }
425
- if (type === "deleteBlock") return {
426
- ...operationMeta,
427
- id,
428
- type,
429
- blockId,
430
- ...comment !== void 0 && { comment }
431
- };
549
+ if (type === "deleteBlock") {
550
+ const moveId = readOptionalString(value, "moveId", path);
551
+ return {
552
+ ...operationMeta,
553
+ id,
554
+ type,
555
+ blockId,
556
+ ...moveId !== void 0 && { moveId },
557
+ ...comment !== void 0 && { comment }
558
+ };
559
+ }
432
560
  if (type === "commentOnBlock") {
433
561
  if (comment === void 0) return invalidBatch(`${path}.comment`, "expected an object");
434
562
  const quote = readOptionalString(value, "quote", path);
@@ -642,6 +770,14 @@ const getPrimaryAffectedTarget = (operation, story) => {
642
770
  blockId: operation.blockId,
643
771
  effect: "deleted"
644
772
  };
773
+ case "setBlockParagraphProperties":
774
+ case "splitBlock":
775
+ case "mergeBlockWithNext": return {
776
+ type: "block",
777
+ story,
778
+ blockId: operation.blockId,
779
+ effect: "updated"
780
+ };
645
781
  case "commentOnBlock": return {
646
782
  type: "block",
647
783
  story,
@@ -655,6 +791,19 @@ const getPrimaryAffectedTarget = (operation, story) => {
655
791
  position: operation.position ?? "after",
656
792
  content: "signatureTable"
657
793
  };
794
+ case "insertTable": return {
795
+ type: "insertion",
796
+ story,
797
+ anchorBlockId: operation.blockId,
798
+ position: operation.position ?? "after",
799
+ content: "table"
800
+ };
801
+ case "deleteTable": return {
802
+ type: "block",
803
+ story,
804
+ blockId: operation.blockId,
805
+ effect: "deleted"
806
+ };
658
807
  case "insertTableRow": return {
659
808
  type: "insertion",
660
809
  story,
@@ -730,7 +879,7 @@ const getFolioDocumentOperationReceiptsForStory = ({ operations, applied, story
730
879
  });
731
880
  return receipts;
732
881
  };
733
- const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle }) => {
882
+ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff }) => {
734
883
  const parsedBatch = parseFolioDocumentOperationBatch(batch);
735
884
  const apply = ({ targetView, targetCreateCommentId = createCommentId, preview = false }) => {
736
885
  return (preview ? previewFolioAIEditOperations : applyFolioAIEditOperations)({
@@ -739,7 +888,9 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
739
888
  operations: parsedBatch.operations,
740
889
  mode: parsedBatch.mode ?? "tracked-changes",
741
890
  ...author !== void 0 && { author },
742
- ...targetCreateCommentId !== void 0 && { createCommentId: targetCreateCommentId }
891
+ ...targetCreateCommentId !== void 0 && { createCommentId: targetCreateCommentId },
892
+ ...revisionStamp !== void 0 && { revisionStamp },
893
+ ...wordDiff !== void 0 && { wordDiff }
743
894
  });
744
895
  };
745
896
  const preview = () => apply({
@@ -759,7 +910,9 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
759
910
  skipped,
760
911
  issues: getFolioDocumentOperationIssues(parsedBatch.operations, skipped),
761
912
  receipts: [],
762
- undoHandle: null
913
+ ...previewResult.normalizations !== void 0 && { normalizations: previewResult.normalizations },
914
+ undoHandle: null,
915
+ nextRevisionId: previewResult.nextRevisionId
763
916
  };
764
917
  };
765
918
  if (parsedBatch.dryRun === true) {
@@ -776,7 +929,9 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
776
929
  applied: previewResult.applied,
777
930
  story
778
931
  }),
779
- undoHandle: null
932
+ ...previewResult.normalizations !== void 0 && { normalizations: previewResult.normalizations },
933
+ undoHandle: null,
934
+ nextRevisionId: previewResult.nextRevisionId
780
935
  };
781
936
  }
782
937
  if (parsedBatch.atomic === true) {
@@ -4,6 +4,22 @@ type FolioDocumentStoryPair = {
4
4
  baseStory: FolioDocumentStoryHandle | null;
5
5
  revisedStory: FolioDocumentStoryHandle | null;
6
6
  };
7
+ /**
8
+ * Pair two packages' stories: by identity first, then, for headers and
9
+ * footers, by kind and document order.
10
+ *
11
+ * A relationship id names a part inside ONE package. Two revisions of one file
12
+ * carry it forward, so matching on it pairs the right header exactly and is
13
+ * tried first. Two independently authored files do not: `rId6` in one has
14
+ * nothing to do with `rId6` in the other, and matching on it alone left every
15
+ * header and footer of such a pair reported as present on one side only —
16
+ * a comparison of two contracts covered their bodies and nothing else.
17
+ *
18
+ * Order is what is left to pair on. It is the order the package lists its
19
+ * parts in, so the nth header of one document answers to the nth header of the
20
+ * other, and a document with more of them than the other leaves its surplus
21
+ * unpaired rather than pairing a first-page header against a default one.
22
+ */
7
23
  declare const pairFolioDocumentStories: (baseStories: readonly FolioDocumentStoryHandle[], revisedStories: readonly FolioDocumentStoryHandle[]) => FolioDocumentStoryPair[];
8
24
  //#endregion
9
25
  export { FolioDocumentStoryPair, pairFolioDocumentStories };
@@ -4,18 +4,62 @@ const documentStoryKey = (story) => {
4
4
  if (story.type === "header" || story.type === "footer") return `${story.type}:${story.relationshipId}`;
5
5
  return `${story.type}:${String(story.noteId)}`;
6
6
  };
7
+ /**
8
+ * Pair two packages' stories: by identity first, then, for headers and
9
+ * footers, by kind and document order.
10
+ *
11
+ * A relationship id names a part inside ONE package. Two revisions of one file
12
+ * carry it forward, so matching on it pairs the right header exactly and is
13
+ * tried first. Two independently authored files do not: `rId6` in one has
14
+ * nothing to do with `rId6` in the other, and matching on it alone left every
15
+ * header and footer of such a pair reported as present on one side only —
16
+ * a comparison of two contracts covered their bodies and nothing else.
17
+ *
18
+ * Order is what is left to pair on. It is the order the package lists its
19
+ * parts in, so the nth header of one document answers to the nth header of the
20
+ * other, and a document with more of them than the other leaves its surplus
21
+ * unpaired rather than pairing a first-page header against a default one.
22
+ */
7
23
  const pairFolioDocumentStories = (baseStories, revisedStories) => {
8
24
  const revisedByKey = new Map(revisedStories.map((story) => [documentStoryKey(story), story]));
9
25
  const pairedKeys = /* @__PURE__ */ new Set();
10
- const pairs = [];
26
+ const pairedByIdentity = /* @__PURE__ */ new Map();
11
27
  for (const baseStory of baseStories) {
12
28
  const key = documentStoryKey(baseStory);
13
- const revisedStory = revisedByKey.get(key) ?? null;
29
+ const revisedStory = revisedByKey.get(key);
30
+ if (revisedStory) {
31
+ pairedKeys.add(key);
32
+ pairedByIdentity.set(baseStory, revisedStory);
33
+ }
34
+ }
35
+ const unpairedRevisedOfKind = (kind) => revisedStories.filter((story) => story.type === kind && !pairedKeys.has(documentStoryKey(story)));
36
+ const remaining = {
37
+ header: unpairedRevisedOfKind("header"),
38
+ footer: unpairedRevisedOfKind("footer")
39
+ };
40
+ const pairs = [];
41
+ for (const baseStory of baseStories) {
42
+ const identityMatch = pairedByIdentity.get(baseStory);
43
+ if (identityMatch) {
44
+ pairs.push({
45
+ baseStory,
46
+ revisedStory: identityMatch
47
+ });
48
+ continue;
49
+ }
50
+ if (baseStory.type !== "header" && baseStory.type !== "footer") {
51
+ pairs.push({
52
+ baseStory,
53
+ revisedStory: null
54
+ });
55
+ continue;
56
+ }
57
+ const byOrder = remaining[baseStory.type].shift() ?? null;
58
+ if (byOrder) pairedKeys.add(documentStoryKey(byOrder));
14
59
  pairs.push({
15
60
  baseStory,
16
- revisedStory
61
+ revisedStory: byOrder
17
62
  });
18
- if (revisedStory) pairedKeys.add(key);
19
63
  }
20
64
  for (const revisedStory of revisedStories) if (!pairedKeys.has(documentStoryKey(revisedStory))) pairs.push({
21
65
  baseStory: null,
@@ -0,0 +1,35 @@
1
+ import JSZip from "jszip";
2
+ //#region src/docx/packageParts.d.ts
3
+ /**
4
+ * Whether an entry path would escape the package when a host writes the archive
5
+ * to disk: absolute, backslash-separated, or climbing out through `..`. This is
6
+ * the only thing a save refuses, and it is about the archive, not the document.
7
+ *
8
+ * The full repack removes such an entry along with its references; the
9
+ * selective path bails to the full repack rather than overlay one part on top
10
+ * of a package carrying one. Both read this predicate, so neither can drift
11
+ * into passing what the other blocks.
12
+ */
13
+ declare const isUnsafePackagePath: (path: string) => boolean;
14
+ /** Drop the entries whose path a save refuses. Every other part survives. */
15
+ declare const removeUnsafeEntries: (zip: JSZip) => void;
16
+ /** What reconciliation removed to make the package internally consistent. */
17
+ type PackageReferenceRepair = {
18
+ /** Parts a relationship named that the package does not hold. */
19
+ danglingRelationships: string[];
20
+ /** Parts a content-type override named that the package does not hold. */
21
+ danglingOverrides: string[];
22
+ };
23
+ /**
24
+ * Make the package internally consistent before it is written: every internal
25
+ * relationship target and every content-type override must name a part the
26
+ * output actually holds.
27
+ *
28
+ * A part is rewritten only when something was dropped from it, so a package
29
+ * that needs no repair leaves byte for byte as it arrived. Running this on an
30
+ * already-reconciled package therefore reports nothing and changes nothing,
31
+ * which is what the repack tests assert about their own output.
32
+ */
33
+ declare const reconcilePackageReferences: (zip: JSZip, compressionLevel: number) => Promise<PackageReferenceRepair>;
34
+ //#endregion
35
+ export { PackageReferenceRepair, isUnsafePackagePath, reconcilePackageReferences, removeUnsafeEntries };
@@ -0,0 +1,120 @@
1
+ import { resolveRelativePath } from "./relsParser.js";
2
+ //#region src/docx/packageParts.ts
3
+ const CONTENT_TYPE_ELEMENT = /<(?:Default|Override)\b[^>]*?\/?>/giu;
4
+ const PART_NAME_ATTRIBUTE = /\bPartName\s*=\s*(?<quote>["'])(?<value>[^"']*)\k<quote>/u;
5
+ const RELATIONSHIP_ELEMENT = /<Relationship\b[^>]*?(?:\/>|>\s*<\/Relationship>)/giu;
6
+ const TARGET_ATTRIBUTE = /\bTarget\s*=\s*(?<quote>["'])(?<value>[^"']*)\k<quote>/u;
7
+ const TARGET_MODE_ATTRIBUTE = /\bTargetMode\s*=\s*(?<quote>["'])(?<value>[^"']*)\k<quote>/u;
8
+ const CONTENT_TYPES_PATTERN = /^\[Content_Types\]\.xml$/iu;
9
+ /** Normalize a package path for comparison: lower case, no leading slash. */
10
+ const normalizePartPath = (path) => (path.startsWith("/") ? path.slice(1) : path).toLowerCase();
11
+ /**
12
+ * Decode `%XX` escapes in a part name. `decodeURI` throws on a malformed
13
+ * escape, and a malformed target is exactly the input this has to survive, so
14
+ * the replacement is done by hand.
15
+ */
16
+ const decodePartName = (name) => name.replaceAll(/%[0-9A-Fa-f]{2}/gu, (escape) => String.fromCharCode(Number.parseInt(escape.slice(1), 16)));
17
+ /**
18
+ * Whether an entry path would escape the package when a host writes the archive
19
+ * to disk: absolute, backslash-separated, or climbing out through `..`. This is
20
+ * the only thing a save refuses, and it is about the archive, not the document.
21
+ *
22
+ * The full repack removes such an entry along with its references; the
23
+ * selective path bails to the full repack rather than overlay one part on top
24
+ * of a package carrying one. Both read this predicate, so neither can drift
25
+ * into passing what the other blocks.
26
+ */
27
+ const isUnsafePackagePath = (path) => {
28
+ if (!path || path.startsWith("/") || path.includes("\\")) return true;
29
+ return path.split("/").some((segment) => segment === "..");
30
+ };
31
+ /** Drop the entries whose path a save refuses. Every other part survives. */
32
+ const removeUnsafeEntries = (zip) => {
33
+ for (const [path, file] of Object.entries(zip.files)) if (!file.dir && isUnsafePackagePath(path)) zip.remove(path);
34
+ };
35
+ const presentPartPaths = (zip) => {
36
+ const present = /* @__PURE__ */ new Set();
37
+ for (const [path, file] of Object.entries(zip.files)) if (!file.dir) present.add(normalizePartPath(path));
38
+ return present;
39
+ };
40
+ const isPresent = (present, partPath) => present.has(normalizePartPath(partPath)) || present.has(normalizePartPath(decodePartName(partPath)));
41
+ /** The part a relationship names, or null when it points outside the package. */
42
+ const relationshipTarget = (element, relsPath) => {
43
+ if (TARGET_MODE_ATTRIBUTE.exec(element)?.groups?.["value"] === "External") return null;
44
+ const target = TARGET_ATTRIBUTE.exec(element)?.groups?.["value"];
45
+ return target === void 0 ? null : resolveRelativePath(relsPath, target);
46
+ };
47
+ /**
48
+ * Every `.rels` part with its text. Read one at a time rather than through
49
+ * `Promise.all`: a package holds a handful of tiny relationship parts, and the
50
+ * sequential read keeps the output order stable.
51
+ */
52
+ const readRelationshipParts = async (zip) => {
53
+ const parts = [];
54
+ for (const [path, file] of Object.entries(zip.files)) {
55
+ if (file.dir || !normalizePartPath(path).endsWith(".rels")) continue;
56
+ parts.push({
57
+ path,
58
+ xml: await file.async("text")
59
+ });
60
+ }
61
+ return parts;
62
+ };
63
+ const writePart = ({ zip, path, xml, compressionLevel }) => {
64
+ zip.file(path, xml, {
65
+ compression: "DEFLATE",
66
+ compressionOptions: { level: compressionLevel }
67
+ });
68
+ };
69
+ /**
70
+ * Make the package internally consistent before it is written: every internal
71
+ * relationship target and every content-type override must name a part the
72
+ * output actually holds.
73
+ *
74
+ * A part is rewritten only when something was dropped from it, so a package
75
+ * that needs no repair leaves byte for byte as it arrived. Running this on an
76
+ * already-reconciled package therefore reports nothing and changes nothing,
77
+ * which is what the repack tests assert about their own output.
78
+ */
79
+ const reconcilePackageReferences = async (zip, compressionLevel) => {
80
+ const present = presentPartPaths(zip);
81
+ const repair = {
82
+ danglingRelationships: [],
83
+ danglingOverrides: []
84
+ };
85
+ for (const { path, xml } of await readRelationshipParts(zip)) {
86
+ let dropped = false;
87
+ const pruned = xml.replaceAll(RELATIONSHIP_ELEMENT, (element) => {
88
+ const target = relationshipTarget(element, path);
89
+ if (target === null || isPresent(present, target)) return element;
90
+ repair.danglingRelationships.push(target);
91
+ dropped = true;
92
+ return "";
93
+ });
94
+ if (dropped) writePart({
95
+ zip,
96
+ path,
97
+ xml: pruned,
98
+ compressionLevel
99
+ });
100
+ }
101
+ const contentTypes = zip.file(CONTENT_TYPES_PATTERN)[0];
102
+ if (!contentTypes) return repair;
103
+ let droppedOverride = false;
104
+ const prunedContentTypes = (await contentTypes.async("text")).replaceAll(CONTENT_TYPE_ELEMENT, (element) => {
105
+ const partName = PART_NAME_ATTRIBUTE.exec(element)?.groups?.["value"];
106
+ if (partName === void 0 || isPresent(present, partName)) return element;
107
+ repair.danglingOverrides.push(normalizePartPath(decodePartName(partName)));
108
+ droppedOverride = true;
109
+ return "";
110
+ });
111
+ if (droppedOverride) writePart({
112
+ zip,
113
+ path: contentTypes.name,
114
+ xml: prunedContentTypes,
115
+ compressionLevel
116
+ });
117
+ return repair;
118
+ };
119
+ //#endregion
120
+ export { isUnsafePackagePath, reconcilePackageReferences, removeUnsafeEntries };
@@ -9,9 +9,9 @@ import { consolidateParagraphContent } from "./runConsolidator.js";
9
9
  import { parseRun, parseRunProperties } from "./runParser.js";
10
10
  import { parseSdtProperties } from "./sdtProperties.js";
11
11
  import { parseSectionProperties } from "./sectionParser.js";
12
- import { elementToXml, findChild, findChildren, getAttribute, getChildElements, getLocalName, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseNumberingLevelAttribute, parseNumericAttribute } from "./xmlParser.js";
12
+ import { WORDPROCESSINGML_NAMESPACE_URIS, elementToXml, findChild, findChildByNamespaceUri, findChildren, getAttribute, getChildElements, getLocalName, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseNumberingLevelAttribute, parseNumericAttribute } from "./xmlParser.js";
13
13
  import { panic } from "better-result";
14
- import { normalizeRevisionId } from "@stll/docx-core/model";
14
+ import { PARAGRAPH_MARK_CHANGE_KINDS, normalizeRevisionId } from "@stll/docx-core/model";
15
15
  //#region src/docx/paragraphParser.ts
16
16
  /**
17
17
  * Extract plain text from a math element (recursive text content extraction)
@@ -528,19 +528,16 @@ function parseParagraphMarkChange(pPr) {
528
528
  if (!pPr) return;
529
529
  const rPr = findChild(pPr, "w", "rPr");
530
530
  if (!rPr) return;
531
- const ins = findChild(rPr, "w", "ins");
532
- if (ins) return {
533
- kind: "ins",
534
- info: parseTrackedChangeInfo(ins)
535
- };
536
- const del = findChild(rPr, "w", "del");
537
- if (del) return {
538
- kind: "del",
539
- info: parseTrackedChangeInfo(del)
540
- };
531
+ for (const kind of PARAGRAPH_MARK_CHANGE_KINDS) {
532
+ const element = findChildByNamespaceUri(rPr, WORDPROCESSINGML_NAMESPACE_URIS, kind);
533
+ if (element) return {
534
+ kind,
535
+ info: parseTrackedChangeInfo(element)
536
+ };
537
+ }
541
538
  }
542
539
  function isTrackedChangeWrapperChild(content) {
543
- return content.type === "run" || content.type === "hyperlink";
540
+ return content.type === "run" || content.type === "hyperlink" || content.type === "bookmarkStart" || content.type === "bookmarkEnd" || content.type === "simpleField" || content.type === "complexField" || content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo";
544
541
  }
545
542
  function isInlineSdtContent(content) {
546
543
  return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo" || content.type === "mathEquation";
@@ -980,16 +977,19 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
980
977
  if (sectPr) paragraph.sectionProperties = parseSectionProperties(sectPr);
981
978
  }
982
979
  paragraph.content = consolidateParagraphContent(parseParagraphContents(node, styles, theme, numbering, rels, media, "default", options?.rootXmlns ?? {}));
983
- let effectiveNumPr = paragraph.formatting?.numPr;
980
+ const paragraphFormatting = paragraph.formatting;
981
+ const directNumPr = paragraphFormatting?.numPr;
982
+ const styleNumPr = paragraphFormatting?.styleId && styles ? styles.get(paragraphFormatting.styleId)?.pPr?.numPr : void 0;
983
+ let effectiveNumPr = directNumPr;
984
984
  let numPrFromStyle = false;
985
- if (!effectiveNumPr && paragraph.formatting?.styleId && styles) {
986
- const style = styles.get(paragraph.formatting.styleId);
987
- if (style?.pPr?.numPr) {
988
- effectiveNumPr = style.pPr.numPr;
989
- numPrFromStyle = true;
990
- paragraph.formatting.numPr = effectiveNumPr;
991
- paragraph.formatting.numPrFromStyle = effectiveNumPr;
992
- }
985
+ if (paragraphFormatting && styleNumPr && directNumPr?.numId === void 0) {
986
+ effectiveNumPr = {
987
+ ...styleNumPr,
988
+ ...directNumPr
989
+ };
990
+ numPrFromStyle = true;
991
+ paragraphFormatting.numPr = effectiveNumPr;
992
+ paragraphFormatting.numPrFromStyle = styleNumPr;
993
993
  }
994
994
  if (effectiveNumPr && numbering) {
995
995
  const { numId, ilvl = 0 } = effectiveNumPr;
@@ -13,7 +13,7 @@ const visitParagraphRuns = (paragraph, visit) => {
13
13
  visitRun(child);
14
14
  continue;
15
15
  }
16
- visitHyperlink(child);
16
+ if (child.type === "hyperlink") visitHyperlink(child);
17
17
  }
18
18
  };
19
19
  const visitParagraphContent = (content) => {
@@ -37,7 +37,9 @@ const scanHyperlink = (hyperlink, scan) => {
37
37
  };
38
38
  const scanInlineContent = (content, scan) => {
39
39
  for (const child of content) {
40
- const result = child.type === "run" ? scanRun(child, scan) : scanHyperlink(child, scan);
40
+ let result;
41
+ if (child.type === "run") result = scanRun(child, scan);
42
+ else if (child.type === "hyperlink") result = scanHyperlink(child, scan);
41
43
  if (result !== void 0) return result;
42
44
  }
43
45
  };
@@ -0,0 +1,13 @@
1
+ //#region src/docx/revisionIdNormalization.d.ts
2
+ declare const REVISION_ELEMENT_NAMES: Set<string>;
3
+ /**
4
+ * Keep physical tracked-change element ids unique across a package.
5
+ *
6
+ * Live editor marks and operation receipts keep their logical revision IDs.
7
+ * Saving assigns fresh IDs only where one logical change was split into
8
+ * multiple physical OOXML wrappers; reopening therefore exposes the physical
9
+ * wrapper IDs that the file format requires.
10
+ */
11
+ declare const normalizeRevisionIdsInXmlParts: (parts: ReadonlyMap<string, string>) => Map<string, string>;
12
+ //#endregion
13
+ export { REVISION_ELEMENT_NAMES, normalizeRevisionIdsInXmlParts };