@stll/folio-core 0.36.0 → 0.37.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 (200) hide show
  1. package/README.md +59 -1
  2. package/dist/ai-edits/apply.js +689 -367
  3. package/dist/ai-edits/block-identity.d.ts +4 -1
  4. package/dist/ai-edits/block-identity.js +4 -1
  5. package/dist/ai-edits/blockRange.js +14 -14
  6. package/dist/ai-edits/clean-text.d.ts +40 -1
  7. package/dist/ai-edits/clean-text.js +52 -2
  8. package/dist/ai-edits/headless.d.ts +3 -1
  9. package/dist/ai-edits/headless.js +133 -71
  10. package/dist/ai-edits/index.d.ts +3 -3
  11. package/dist/ai-edits/index.js +2 -2
  12. package/dist/ai-edits/read.js +38 -20
  13. package/dist/ai-edits/snapshot.d.ts +14 -6
  14. package/dist/ai-edits/snapshot.js +99 -19
  15. package/dist/ai-edits/table-cell-mutations.js +1 -1
  16. package/dist/ai-edits/table-row-column-mutations.js +7 -0
  17. package/dist/ai-edits/table-template.d.ts +11 -1
  18. package/dist/ai-edits/table-template.js +49 -17
  19. package/dist/ai-edits/types.d.ts +60 -57
  20. package/dist/ai-suggestions/conflict.js +1 -4
  21. package/dist/ai-suggestions/text-positions.d.ts +8 -0
  22. package/dist/ai-suggestions/text-positions.js +27 -5
  23. package/dist/compare/__fixtures__/body-sequence.js +3 -4
  24. package/dist/compare/column-alignment.d.ts +13 -13
  25. package/dist/compare/column-alignment.js +78 -39
  26. package/dist/compare/compare.d.ts +4 -3
  27. package/dist/compare/compare.js +41 -5
  28. package/dist/compare/content-alignment.d.ts +95 -0
  29. package/dist/compare/content-alignment.js +1450 -0
  30. package/dist/compare/content-types.d.ts +100 -0
  31. package/dist/compare/content-types.js +0 -0
  32. package/dist/compare/content.d.ts +209 -0
  33. package/dist/compare/content.js +885 -0
  34. package/dist/compare/formatting.d.ts +5 -5
  35. package/dist/compare/formatting.js +6 -4
  36. package/dist/compare/plan.d.ts +6 -1
  37. package/dist/compare/plan.js +201 -569
  38. package/dist/compare/scenario.d.ts +2 -2
  39. package/dist/compare/types.d.ts +3 -3
  40. package/dist/compare/verification.d.ts +2 -2
  41. package/dist/compare/verification.js +25 -8
  42. package/dist/compat/eigenpal.d.ts +5 -3
  43. package/dist/compat/eigenpal.js +3 -2
  44. package/dist/controller/headerFooterEditorManager.js +14 -6
  45. package/dist/controller/hiddenEditorManager.d.ts +7 -2
  46. package/dist/controller/hiddenEditorManager.js +15 -6
  47. package/dist/controller/layoutPipeline.js +5 -3
  48. package/dist/controller/noteEditorManager.js +12 -7
  49. package/dist/display-list/build/headerFooterPrimitives.js +1 -0
  50. package/dist/display-list/build/storyPrimitives.d.ts +5 -2
  51. package/dist/display-list/build/storyPrimitives.js +60 -3
  52. package/dist/display-list/build/tablePrimitives.js +30 -0
  53. package/dist/display-list/primitives.d.ts +1 -1
  54. package/dist/document-operations.d.ts +8 -6
  55. package/dist/document-operations.js +121 -26
  56. package/dist/docx/blockContentParser.js +6 -27
  57. package/dist/docx/ensureParaIds.js +9 -4
  58. package/dist/docx/numberingParser.d.ts +3 -1
  59. package/dist/docx/numberingParser.js +4 -1
  60. package/dist/docx/paragraphParser.js +7 -6
  61. package/dist/docx/paragraphTraversal.js +30 -34
  62. package/dist/docx/rezip.d.ts +0 -8
  63. package/dist/docx/rezip.js +41 -16
  64. package/dist/docx/runParser.js +4 -2
  65. package/dist/docx/serializer/paragraphSerializer.js +2 -0
  66. package/dist/docx/serializer/runSerializer.js +5 -3
  67. package/dist/docx/serializer/trackedChangeAttributes.d.ts +3 -1
  68. package/dist/docx/serializer/trackedChangeAttributes.js +11 -1
  69. package/dist/docx/server/build.d.ts +1 -1
  70. package/dist/headless-layout.js +5 -4
  71. package/dist/index.d.ts +5 -3
  72. package/dist/index.js +3 -2
  73. package/dist/internal/headlessRevisionResolution.d.ts +23 -0
  74. package/dist/internal/headlessRevisionResolution.js +176 -0
  75. package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
  76. package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
  77. package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
  78. package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
  79. package/dist/internal/pageBreakRunPartition.d.ts +26 -0
  80. package/dist/internal/pageBreakRunPartition.js +35 -0
  81. package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
  82. package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
  83. package/dist/internal/sectionEndpointResolution.d.ts +32 -0
  84. package/dist/internal/sectionEndpointResolution.js +38 -0
  85. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  86. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
  87. package/dist/layout-bridge/convert/headerFooterLayout.js +48 -5
  88. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
  89. package/dist/layout-bridge/convert/toFlowBlocks.js +379 -75
  90. package/dist/layout-bridge/dom/clickToPositionDom.d.ts +8 -1
  91. package/dist/layout-bridge/dom/clickToPositionDom.js +114 -40
  92. package/dist/layout-bridge/dom/textStreamDom.d.ts +24 -0
  93. package/dist/layout-bridge/dom/textStreamDom.js +75 -0
  94. package/dist/layout-bridge/headerFooterLayout.js +16 -30
  95. package/dist/layout-engine/index.js +12 -3
  96. package/dist/layout-engine/measure/tableFragmentBorderGeometry.d.ts +17 -0
  97. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +24 -0
  98. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  99. package/dist/layout-engine/types.d.ts +7 -0
  100. package/dist/layout-painter/imageLayout.d.ts +1 -1
  101. package/dist/layout-painter/renderTable.js +20 -0
  102. package/dist/model.d.ts +1 -1
  103. package/dist/paged-layout/rangeProjection.js +6 -9
  104. package/dist/paged-layout/transactionDirtyRange.d.ts +3 -1
  105. package/dist/paged-layout/transactionDirtyRange.js +23 -1
  106. package/dist/prosemirror/attrs/index.d.ts +7 -3
  107. package/dist/prosemirror/attrs/index.js +113 -7
  108. package/dist/prosemirror/bookmarkBoundaryIntegrity.d.ts +9 -0
  109. package/dist/prosemirror/bookmarkBoundaryIntegrity.js +22 -0
  110. package/dist/prosemirror/commands/comments.d.ts +10 -1
  111. package/dist/prosemirror/commands/comments.js +167 -59
  112. package/dist/prosemirror/commands/formatPainter.d.ts +45 -10
  113. package/dist/prosemirror/commands/formatPainter.js +319 -63
  114. package/dist/prosemirror/commands/index.d.ts +2 -2
  115. package/dist/prosemirror/commands/pageBreak.d.ts +5 -2
  116. package/dist/prosemirror/commands/pageBreak.js +18 -36
  117. package/dist/prosemirror/commands/propertyChangeScope.d.ts +7 -5
  118. package/dist/prosemirror/commands/propertyChangeScope.js +27 -18
  119. package/dist/prosemirror/conversion/fromProseDoc.d.ts +7 -2
  120. package/dist/prosemirror/conversion/fromProseDoc.js +809 -209
  121. package/dist/prosemirror/conversion/runShadingMark.js +2 -2
  122. package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
  123. package/dist/prosemirror/conversion/toProseDoc.js +416 -283
  124. package/dist/prosemirror/extensions/StarterKit.js +4 -0
  125. package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -8
  126. package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
  127. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -1
  128. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +27 -1
  129. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +134 -30
  130. package/dist/prosemirror/extensions/features/pasteCleanup.js +9 -15
  131. package/dist/prosemirror/extensions/marks/BoldExtension.js +4 -3
  132. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +4 -7
  133. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +5 -11
  134. package/dist/prosemirror/extensions/marks/FontSizeExtension.js +3 -3
  135. package/dist/prosemirror/extensions/marks/ItalicExtension.js +4 -3
  136. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +13 -0
  137. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +39 -0
  138. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +7 -1
  139. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +67 -21
  140. package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -1
  141. package/dist/prosemirror/extensions/marks/markUtils.js +88 -2
  142. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +44 -3
  143. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  144. package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +15 -4
  145. package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +6 -0
  146. package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +6 -0
  147. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.d.ts +6 -0
  148. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.js +36 -0
  149. package/dist/prosemirror/findReplaceSelection.js +8 -3
  150. package/dist/prosemirror/index.d.ts +3 -3
  151. package/dist/prosemirror/listMarker.d.ts +26 -1
  152. package/dist/prosemirror/listMarker.js +108 -14
  153. package/dist/prosemirror/pageBreakRunProjection.d.ts +28 -0
  154. package/dist/prosemirror/pageBreakRunProjection.js +47 -0
  155. package/dist/prosemirror/paraText.js +6 -0
  156. package/dist/prosemirror/paragraphSpacing.d.ts +29 -0
  157. package/dist/prosemirror/paragraphSpacing.js +125 -0
  158. package/dist/prosemirror/plugins/documentNumbering.d.ts +8 -0
  159. package/dist/prosemirror/plugins/documentNumbering.js +18 -0
  160. package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -2
  161. package/dist/prosemirror/plugins/pmTextScan.js +14 -4
  162. package/dist/prosemirror/plugins/suggestionMode.js +8 -10
  163. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +16 -0
  164. package/dist/prosemirror/rebaseParagraphRunFormatting.js +61 -0
  165. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +64 -0
  166. package/dist/prosemirror/runFormattingInlineCarriers.js +121 -0
  167. package/dist/prosemirror/runFormattingProvenance.d.ts +12 -0
  168. package/dist/prosemirror/runFormattingProvenance.js +48 -0
  169. package/dist/prosemirror/runFormattingReconciliation.d.ts +25 -0
  170. package/dist/prosemirror/runFormattingReconciliation.js +54 -0
  171. package/dist/prosemirror/runPropertyChangeResolution.d.ts +18 -0
  172. package/dist/prosemirror/runPropertyChangeResolution.js +18 -0
  173. package/dist/prosemirror/runStyleFormatting.d.ts +50 -0
  174. package/dist/prosemirror/runStyleFormatting.js +105 -0
  175. package/dist/prosemirror/schema/index.d.ts +3 -3
  176. package/dist/prosemirror/schema/marks.d.ts +82 -9
  177. package/dist/prosemirror/schema/marks.js +73 -1
  178. package/dist/prosemirror/schema/nodes.d.ts +18 -5
  179. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
  180. package/dist/prosemirror/styles/resolvedStyleAttrs.js +44 -23
  181. package/dist/prosemirror/styles/styleResolver.d.ts +10 -13
  182. package/dist/prosemirror/styles/styleResolver.js +3 -3
  183. package/dist/prosemirror/styles/styleToggleCascade.d.ts +8 -1
  184. package/dist/prosemirror/styles/styleToggleCascade.js +24 -1
  185. package/dist/prosemirror/tableGridMutation.d.ts +20 -0
  186. package/dist/prosemirror/tableGridMutation.js +30 -0
  187. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +31 -0
  188. package/dist/prosemirror/trackedRunInlineAtoms.js +39 -0
  189. package/dist/prosemirror/utils/visualLineNavigation.js +27 -31
  190. package/dist/prosemirror/validation.js +23 -4
  191. package/dist/render-dom/HeaderFooterSelectionOverlay.js +20 -20
  192. package/dist/render-dom/RenderedDomContext.js +17 -34
  193. package/dist/server.d.ts +4 -4
  194. package/dist/server.js +2 -2
  195. package/dist/style-engine/styleEngine.d.ts +1 -1
  196. package/dist/utils/clipboard.js +1 -1
  197. package/dist/utils/findReplace.js +38 -21
  198. package/dist/version-comparison.d.ts +38 -44
  199. package/dist/version-comparison.js +270 -401
  200. package/package.json +3 -2
@@ -1,5 +1,6 @@
1
1
  import { createTableCellFlowState, placeTableCellBlock } from "../../layout-engine/measure/tableCellFlow.js";
2
2
  import { buildTableCellGrid, buildTableCellPlacements, getSourceCellAt } from "../../layout-engine/measure/tableCellGrid.js";
3
+ import { tableFragmentBottomBorders } from "../../layout-engine/measure/tableFragmentBorderGeometry.js";
3
4
  import { resolveTableCellPadding } from "../../layout-engine/types.js";
4
5
  import { HIT_REGION_KINDS } from "../primitives.js";
5
6
  import { parseDisplayColor } from "./colors.js";
@@ -332,6 +333,28 @@ const paintTableBody = ({ composer, block, measure, xPx, yPx, fromRow, toRow, he
332
333
  cursorYPx += rowMeasure.height;
333
334
  }
334
335
  };
336
+ const paintFragmentBottomBorders = ({ composer, fragment, block, measure, context }) => {
337
+ if (fragment.continuesOnNext !== true || fragment.bottomClip === void 0) return;
338
+ const primitives = [];
339
+ for (const { left, width, border } of tableFragmentBottomBorders({
340
+ fragment,
341
+ block,
342
+ measure
343
+ })) {
344
+ const stroke = strokeFor(border, context, "table fragment bottom border");
345
+ if (!stroke) continue;
346
+ const yPx = fragment.y + fragment.height - stroke.thicknessPx / 2;
347
+ primitives.push({
348
+ kind: "line",
349
+ x1Px: fragment.x + left,
350
+ y1Px: yPx,
351
+ x2Px: fragment.x + left + width,
352
+ y2Px: yPx,
353
+ stroke
354
+ });
355
+ }
356
+ composer.push(primitives);
357
+ };
335
358
  /** A whole, unpaginated table: what a nested table inside a cell or box is. */
336
359
  const paintTableBlock = ({ composer, block, measure, xPx, yPx, context, paintTextBox }) => paintTableBody({
337
360
  composer,
@@ -404,6 +427,13 @@ const paintTableFragment = ({ composer, fragment, block, measure, context, paint
404
427
  children: [...clipped.primitives()],
405
428
  regions: [...clipped.regions()]
406
429
  }]);
430
+ paintFragmentBottomBorders({
431
+ composer,
432
+ fragment,
433
+ block,
434
+ measure,
435
+ context
436
+ });
407
437
  };
408
438
  //#endregion
409
439
  export { paintTableBlock, paintTableFragment };
@@ -15,7 +15,7 @@ import { hasComplexScript, isComplexScriptCodePoint } from "../utils/scriptSegme
15
15
  * advances rightward from its origin whatever the paragraph does.
16
16
  */
17
17
  declare const glyphCellOffsetsPx: (run: DisplayGlyphRun) => readonly number[];
18
- declare const DISPLAY_PRIMITIVE_KINDS: ("glyphRun" | "rect" | "line" | "image" | "clipGroup" | "rotateGroup" | "opacityGroup")[];
18
+ declare const DISPLAY_PRIMITIVE_KINDS: ("image" | "glyphRun" | "rect" | "line" | "clipGroup" | "rotateGroup" | "opacityGroup")[];
19
19
  /**
20
20
  * Dash geometry of each stroke pattern, as multiples of the stroke thickness.
21
21
  *
@@ -5,6 +5,8 @@ import { FolioAIEditView, FolioRevisionStamp, FolioWordDiffOptions } from "./ai-
5
5
  declare const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION: 1;
6
6
  /** Direct paragraph-alignment values accepted by the operation contract. */
7
7
  declare const FOLIO_PARAGRAPH_ALIGNMENT_VALUES: readonly ("left" | "center" | "right" | "both" | "distribute" | "mediumKashida" | "highKashida" | "lowKashida" | "thaiDistribute")[];
8
+ /** `w:spacing/@w:lineRule` values accepted by the operation contract. */
9
+ declare const FOLIO_LINE_SPACING_RULE_VALUES: readonly ("auto" | "exact" | "atLeast")[];
8
10
  declare const FOLIO_DOCUMENT_OPERATION_TYPES: readonly ["replaceInBlock", "replaceRange", "commentOnRange", "formatRange", "insertAfterBlock", "insertBeforeBlock", "replaceBlock", "deleteBlock", "splitBlock", "mergeBlockWithNext", "setBlockParagraphProperties", "insertTable", "deleteTable", "commentOnBlock", "insertSignatureTable", "insertTableRow", "deleteTableRow", "insertTableColumn", "deleteTableColumn", "mergeTableCells", "splitTableCell"];
9
11
  declare const FOLIO_DOCUMENT_OPERATION_MODES: readonly ["direct", "tracked-changes", "suggested"];
10
12
  declare const FOLIO_DOCUMENT_OPERATION_STORIES: readonly ["main", "header", "footer", "footnote", "endnote"];
@@ -95,12 +97,12 @@ declare const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE: Readonly<{
95
97
  readonly replaceRange: readonly ["id", "type", "range", "severity", "area", "precondition", "suggestionId", "replace", "comment"];
96
98
  readonly commentOnRange: readonly ["id", "type", "range", "severity", "area", "precondition", "comment"];
97
99
  readonly formatRange: readonly ["id", "type", "range", "severity", "area", "precondition", "suggestionId", "formatting"];
98
- readonly insertAfterBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
99
- readonly insertBeforeBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
100
+ readonly insertAfterBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "spacing", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
101
+ readonly insertBeforeBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "spacing", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
100
102
  readonly replaceBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "preserveFormatting", "styleId", "comment"];
101
103
  readonly deleteBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "moveId", "comment"];
102
- readonly splitBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "offset", "separator"];
103
- readonly mergeBlockWithNext: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "separator"];
104
+ readonly splitBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "offset", "separator", "firstParagraphProperties", "secondParagraphProperties"];
105
+ readonly mergeBlockWithNext: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "separator", "mergedParagraphProperties"];
104
106
  readonly setBlockParagraphProperties: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "properties"];
105
107
  readonly insertTable: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "position", "rows"];
106
108
  readonly deleteTable: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId"];
@@ -119,7 +121,7 @@ declare const parseFolioDocumentOperationBatch: (value: unknown) => FolioDocumen
119
121
  * review queue instead of applying it; the core apply path never produces it.
120
122
  */
121
123
  type FolioDocumentOperationStatus = "committed" | "previewed" | "rejected" | "queued";
122
- type FolioDocumentOperationRecovery = "refreshDocument" | "narrowMatch" | "changeMode" | "changeTarget" | "removeOperation" | "inspectBatch" | "retryLater";
124
+ type FolioDocumentOperationRecovery = "refreshDocument" | "narrowMatch" | "changeMode" | "changeTarget" | "removeOperation" | "inspectBatch" | "resolveTrackedChange" | "retryLater";
123
125
  type FolioDocumentOperationIssue = {
124
126
  operationId: string;
125
127
  operationIndex: number;
@@ -280,4 +282,4 @@ type ApplyFolioDocumentOperationsOptions = {
280
282
  };
281
283
  declare const applyFolioDocumentOperations: ({ view, snapshot, batch, story, author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates }: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
282
284
  //#endregion
283
- export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
285
+ export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
@@ -1,10 +1,12 @@
1
1
  import { applyFolioAIEditOperations, previewFolioAIEditOperations } from "./ai-edits/apply.js";
2
- import { PARAGRAPH_ALIGNMENT_VALUES } from "./types/documentEnumValues.js";
2
+ import { LINE_SPACING_RULE_VALUES, PARAGRAPH_ALIGNMENT_VALUES } from "./types/documentEnumValues.js";
3
3
  import { TaggedError } from "better-result";
4
4
  //#region src/document-operations.ts
5
5
  const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION = 1;
6
6
  /** Direct paragraph-alignment values accepted by the operation contract. */
7
7
  const FOLIO_PARAGRAPH_ALIGNMENT_VALUES = Object.freeze([...PARAGRAPH_ALIGNMENT_VALUES]);
8
+ /** `w:spacing/@w:lineRule` values accepted by the operation contract. */
9
+ const FOLIO_LINE_SPACING_RULE_VALUES = Object.freeze([...LINE_SPACING_RULE_VALUES]);
8
10
  const FOLIO_DOCUMENT_OPERATION_TYPES = Object.freeze([
9
11
  "replaceInBlock",
10
12
  "replaceRange",
@@ -146,6 +148,12 @@ const readOptionalBoolean = (value, key, path) => {
146
148
  if (typeof candidate === "boolean") return candidate;
147
149
  return invalidBatch(`${path}.${key}`, "expected a boolean when provided");
148
150
  };
151
+ const readClearableBoolean = (value, key, path) => {
152
+ const candidate = value[key];
153
+ if (candidate === void 0 || candidate === null) return candidate;
154
+ if (typeof candidate === "boolean") return candidate;
155
+ return invalidBatch(`${path}.${key}`, "expected a boolean or null when provided");
156
+ };
149
157
  const readClearableNonEmptyString = (value, key, path) => {
150
158
  const candidate = value[key];
151
159
  if (candidate === void 0 || candidate === null) return candidate;
@@ -175,8 +183,8 @@ const readOptionalStringArray = (value, key, path) => {
175
183
  };
176
184
  const readNonNegativeInteger = (value, key, path) => {
177
185
  const candidate = value[key];
178
- if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 0) return candidate;
179
- return invalidBatch(`${path}.${key}`, "expected a non-negative integer");
186
+ if (typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0) return candidate;
187
+ return invalidBatch(`${path}.${key}`, "expected a non-negative safe integer");
180
188
  };
181
189
  /**
182
190
  * A non-negative integer that may also be cleared. `undefined` is "say
@@ -194,6 +202,46 @@ const readClearableParagraphAlignment = ({ value, key, path }) => {
194
202
  for (const alignment of FOLIO_PARAGRAPH_ALIGNMENT_VALUES) if (candidate === alignment) return alignment;
195
203
  return invalidBatch(`${path}.${key}`, `expected one of ${FOLIO_PARAGRAPH_ALIGNMENT_VALUES.join(", ")} or null when provided`);
196
204
  };
205
+ const PARAGRAPH_SPACING_KEYS = [
206
+ "spaceBefore",
207
+ "spaceAfter",
208
+ "lineSpacing",
209
+ "lineSpacingRule",
210
+ "beforeAutospacing",
211
+ "afterAutospacing"
212
+ ];
213
+ const isLineSpacingRule = (value) => FOLIO_LINE_SPACING_RULE_VALUES.some((rule) => value === rule);
214
+ /**
215
+ * Read one complete direct `w:spacing` cluster. Individual fields are
216
+ * optional so explicit zero and false survive; null removes the child.
217
+ */
218
+ const readClearableParagraphSpacing = ({ value, key, path }) => {
219
+ const candidate = value[key];
220
+ if (candidate === void 0 || candidate === null) return candidate;
221
+ const spacingPath = `${path}.${key}`;
222
+ if (!isPlainObject(candidate)) return invalidBatch(spacingPath, "expected an object or null when provided");
223
+ assertAllowedKeys(candidate, spacingPath, PARAGRAPH_SPACING_KEYS);
224
+ if (Object.keys(candidate).length === 0) return invalidBatch(spacingPath, "expected at least one spacing property");
225
+ const spacing = {};
226
+ for (const unsignedKey of ["spaceBefore", "spaceAfter"]) if (candidate[unsignedKey] !== void 0) spacing[unsignedKey] = readNonNegativeInteger(candidate, unsignedKey, spacingPath);
227
+ const lineSpacing = candidate["lineSpacing"];
228
+ if (lineSpacing !== void 0) {
229
+ if (typeof lineSpacing !== "number" || !Number.isSafeInteger(lineSpacing)) return invalidBatch(`${spacingPath}.lineSpacing`, "expected a safe signed integer when provided");
230
+ spacing.lineSpacing = lineSpacing;
231
+ }
232
+ const lineSpacingRule = candidate["lineSpacingRule"];
233
+ if (lineSpacingRule !== void 0) {
234
+ if (!isLineSpacingRule(lineSpacingRule)) return invalidBatch(`${spacingPath}.lineSpacingRule`, `expected one of ${FOLIO_LINE_SPACING_RULE_VALUES.join(", ")} when provided`);
235
+ spacing.lineSpacingRule = lineSpacingRule;
236
+ }
237
+ for (const booleanKey of ["beforeAutospacing", "afterAutospacing"]) {
238
+ const booleanValue = candidate[booleanKey];
239
+ if (booleanValue === void 0) continue;
240
+ if (typeof booleanValue !== "boolean") return invalidBatch(`${spacingPath}.${booleanKey}`, "expected a boolean when provided");
241
+ spacing[booleanKey] = booleanValue;
242
+ }
243
+ return spacing;
244
+ };
197
245
  /**
198
246
  * A rectangular grid of cell texts. Rectangular because a table whose rows
199
247
  * hold different cell counts is not a table any consumer can lay out, and the
@@ -214,14 +262,15 @@ const readTableRows = (value, path) => {
214
262
  if (parsed.some((row) => row.length !== width)) return invalidBatch(rowsPath, "expected every row to hold the same number of cells");
215
263
  return parsed;
216
264
  };
217
- const readParagraphProperties = (value, path) => {
218
- const candidate = value["properties"];
219
- const propertiesPath = `${path}.properties`;
265
+ const readParagraphProperties = ({ value, key, path }) => {
266
+ const candidate = value[key];
267
+ const propertiesPath = `${path}.${key}`;
220
268
  if (!isPlainObject(candidate)) return invalidBatch(propertiesPath, "expected an object");
221
269
  assertAllowedKeys(candidate, propertiesPath, [
222
270
  "styleId",
223
271
  "listLevel",
224
- "alignment"
272
+ "alignment",
273
+ "spacing"
225
274
  ]);
226
275
  const styleId = candidate["styleId"] === null ? null : readOptionalString(candidate, "styleId", propertiesPath);
227
276
  const listLevel = readClearableNonNegativeInteger(candidate, "listLevel", propertiesPath);
@@ -230,11 +279,17 @@ const readParagraphProperties = (value, path) => {
230
279
  key: "alignment",
231
280
  path: propertiesPath
232
281
  });
233
- if (styleId === void 0 && listLevel === void 0 && alignment === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
282
+ const spacing = readClearableParagraphSpacing({
283
+ value: candidate,
284
+ key: "spacing",
285
+ path: propertiesPath
286
+ });
287
+ if (styleId === void 0 && listLevel === void 0 && alignment === void 0 && spacing === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
234
288
  return {
235
289
  ...styleId !== void 0 && { styleId },
236
290
  ...listLevel !== void 0 && { listLevel },
237
- ...alignment !== void 0 && { alignment }
291
+ ...alignment !== void 0 && { alignment },
292
+ ...spacing !== void 0 && { spacing }
238
293
  };
239
294
  };
240
295
  const readTextRange = (value, path) => {
@@ -280,10 +335,10 @@ const readInlineFormatting = (value, path) => {
280
335
  "fontSizePt",
281
336
  "color"
282
337
  ]);
283
- const bold = readOptionalBoolean(candidate, "bold", formattingPath);
284
- const italic = readOptionalBoolean(candidate, "italic", formattingPath);
285
- const underline = readOptionalBoolean(candidate, "underline", formattingPath);
286
- const strike = readOptionalBoolean(candidate, "strike", formattingPath);
338
+ const bold = readClearableBoolean(candidate, "bold", formattingPath);
339
+ const italic = readClearableBoolean(candidate, "italic", formattingPath);
340
+ const underline = readClearableBoolean(candidate, "underline", formattingPath);
341
+ const strike = readClearableBoolean(candidate, "strike", formattingPath);
287
342
  const fontFamily = readClearableNonEmptyString(candidate, "fontFamily", formattingPath);
288
343
  const fontSizePt = readClearableFontSize(candidate, "fontSizePt", formattingPath);
289
344
  const color = readClearableRgbColor(candidate, "color", formattingPath);
@@ -374,6 +429,7 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
374
429
  "text",
375
430
  "inheritFormatting",
376
431
  "alignment",
432
+ "spacing",
377
433
  "listLevel",
378
434
  "moveId",
379
435
  "pageBreakBefore",
@@ -385,6 +441,7 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
385
441
  "text",
386
442
  "inheritFormatting",
387
443
  "alignment",
444
+ "spacing",
388
445
  "listLevel",
389
446
  "moveId",
390
447
  "pageBreakBefore",
@@ -406,9 +463,15 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
406
463
  splitBlock: [
407
464
  ...COMMON_OPERATION_KEYS,
408
465
  "offset",
409
- "separator"
466
+ "separator",
467
+ "firstParagraphProperties",
468
+ "secondParagraphProperties"
469
+ ],
470
+ mergeBlockWithNext: [
471
+ ...COMMON_OPERATION_KEYS,
472
+ "separator",
473
+ "mergedParagraphProperties"
410
474
  ],
411
- mergeBlockWithNext: [...COMMON_OPERATION_KEYS, "separator"],
412
475
  setBlockParagraphProperties: [...COMMON_OPERATION_KEYS, "properties"],
413
476
  insertTable: [
414
477
  ...COMMON_OPERATION_KEYS,
@@ -531,24 +594,48 @@ const parseDocumentOperation = (value, index) => {
531
594
  id,
532
595
  type,
533
596
  blockId,
534
- properties: readParagraphProperties(value, path)
597
+ properties: readParagraphProperties({
598
+ value,
599
+ key: "properties",
600
+ path
601
+ })
535
602
  };
536
603
  if (type === "splitBlock" || type === "mergeBlockWithNext") {
537
604
  const separator = readOptionalString(value, "separator", path);
538
- if (type === "mergeBlockWithNext") return {
539
- ...operationMeta,
540
- id,
541
- type,
542
- blockId,
543
- ...separator !== void 0 && { separator }
544
- };
605
+ if (type === "mergeBlockWithNext") {
606
+ const mergedParagraphProperties = value["mergedParagraphProperties"] === void 0 ? void 0 : readParagraphProperties({
607
+ value,
608
+ key: "mergedParagraphProperties",
609
+ path
610
+ });
611
+ return {
612
+ ...operationMeta,
613
+ id,
614
+ type,
615
+ blockId,
616
+ ...separator !== void 0 && { separator },
617
+ ...mergedParagraphProperties !== void 0 && { mergedParagraphProperties }
618
+ };
619
+ }
620
+ const firstParagraphProperties = value["firstParagraphProperties"] === void 0 ? void 0 : readParagraphProperties({
621
+ value,
622
+ key: "firstParagraphProperties",
623
+ path
624
+ });
625
+ const secondParagraphProperties = value["secondParagraphProperties"] === void 0 ? void 0 : readParagraphProperties({
626
+ value,
627
+ key: "secondParagraphProperties",
628
+ path
629
+ });
545
630
  return {
546
631
  ...operationMeta,
547
632
  id,
548
633
  type,
549
634
  blockId,
550
635
  offset: readNonNegativeInteger(value, "offset", path),
551
- ...separator !== void 0 && { separator }
636
+ ...separator !== void 0 && { separator },
637
+ ...firstParagraphProperties !== void 0 && { firstParagraphProperties },
638
+ ...secondParagraphProperties !== void 0 && { secondParagraphProperties }
552
639
  };
553
640
  }
554
641
  if (type === "replaceInBlock") return {
@@ -571,6 +658,11 @@ const parseDocumentOperation = (value, index) => {
571
658
  key: "alignment",
572
659
  path
573
660
  });
661
+ const spacing = readClearableParagraphSpacing({
662
+ value,
663
+ key: "spacing",
664
+ path
665
+ });
574
666
  return {
575
667
  ...operationMeta,
576
668
  id,
@@ -579,6 +671,7 @@ const parseDocumentOperation = (value, index) => {
579
671
  text: readString(value, "text", path),
580
672
  ...inheritFormatting !== void 0 && { inheritFormatting },
581
673
  ...alignment !== void 0 && { alignment },
674
+ ...spacing !== void 0 && { spacing },
582
675
  ...listLevel !== void 0 && { listLevel },
583
676
  ...moveId !== void 0 && { moveId },
584
677
  ...pageBreakBefore !== void 0 && { pageBreakBefore },
@@ -762,6 +855,8 @@ const recoveryByReason = {
762
855
  preconditionFailed: "refreshDocument",
763
856
  staleRange: "refreshDocument",
764
857
  emptyOperation: "removeOperation",
858
+ pendingParagraphPropertyChange: "resolveTrackedChange",
859
+ pendingRunPropertyChange: "resolveTrackedChange",
765
860
  noopOperation: "removeOperation",
766
861
  documentVersionMismatch: "refreshDocument",
767
862
  documentNotEditable: "retryLater"
@@ -778,7 +873,7 @@ const getFolioDocumentOperationIssues = (operations, skipped) => {
778
873
  operationIndex,
779
874
  path: `$.operations[${operationIndex}]`,
780
875
  code: reason,
781
- retryable: reason !== "emptyOperation" && reason !== "noopOperation",
876
+ retryable: reason !== "emptyOperation" && reason !== "noopOperation" && reason !== "pendingParagraphPropertyChange" && reason !== "pendingRunPropertyChange",
782
877
  recovery: recoveryByReason[reason]
783
878
  };
784
879
  });
@@ -1008,4 +1103,4 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
1008
1103
  };
1009
1104
  };
1010
1105
  //#endregion
1011
- export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
1106
+ export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
@@ -9,7 +9,7 @@ import { parseTable } from "./tableParser.js";
9
9
  import { captureVerbatimXml } from "./verbatimCapture.js";
10
10
  import { findChild, getChildElements, getLocalName, mergeXmlnsDeclarations } from "./xmlParser.js";
11
11
  //#region src/docx/blockContentParser.ts
12
- const computeListMarker = (paragraph, { numbering, listCounters, abstractCounters, restartedNumIds, previousList, siblingNumIdsByAbstractNumId }) => {
12
+ const computeListMarker = (paragraph, { numbering, listCounters, abstractCounters, restartedNumIds, previousList }) => {
13
13
  const listRendering = paragraph.listRendering;
14
14
  if (!listRendering || !numbering) {
15
15
  previousList.abstractNumId = null;
@@ -26,26 +26,17 @@ const computeListMarker = (paragraph, { numbering, listCounters, abstractCounter
26
26
  }
27
27
  const firstEncounter = !listCounters.has(numId);
28
28
  if (firstEncounter) listCounters.set(numId, Array.from({ length: 9 }).fill(NaN));
29
- const counters = listCounters.get(numId);
29
+ let counters = listCounters.get(numId);
30
30
  if (!counters) return;
31
31
  const abstractNumId = numbering.getAbstractNumId(numId);
32
- if (firstEncounter && abstractNumId !== null) {
33
- let siblingNumIds = siblingNumIdsByAbstractNumId.get(abstractNumId);
34
- if (!siblingNumIds) {
35
- siblingNumIds = /* @__PURE__ */ new Set();
36
- siblingNumIdsByAbstractNumId.set(abstractNumId, siblingNumIds);
37
- }
38
- siblingNumIds.add(numId);
39
- }
40
32
  const styleNumbering = paragraph.formatting?.numPrFromStyle;
41
- let resumedAbstractCounters;
42
33
  const resumesRestartedInstance = firstEncounter && listRendering.startOverride === void 0 && abstractNumId !== null && previousList.abstractNumId === abstractNumId && previousList.numId !== null && previousList.numId !== numId && restartedNumIds.has(previousList.numId);
43
34
  const resumesStyleInstance = firstEncounter && !styleNumbering && listRendering.startOverride === void 0 && abstractNumId !== null && previousList.abstractNumId === abstractNumId && previousList.fromStyle === true;
44
35
  if (abstractNumId !== null && (styleNumbering || resumesRestartedInstance || resumesStyleInstance)) {
45
36
  const latestAbstractCounters = abstractCounters.get(abstractNumId);
46
37
  if (latestAbstractCounters) {
47
- for (let i = 0; i < counters.length; i += 1) counters[i] = latestAbstractCounters[i] ?? NaN;
48
- resumedAbstractCounters = latestAbstractCounters;
38
+ counters = latestAbstractCounters;
39
+ listCounters.set(numId, counters);
49
40
  }
50
41
  }
51
42
  if (listRendering.startOverride !== void 0 || resumesRestartedInstance || previousList.numId === numId && restartedNumIds.has(numId)) restartedNumIds.add(numId);
@@ -64,17 +55,7 @@ const computeListMarker = (paragraph, { numbering, listCounters, abstractCounter
64
55
  const childCounter = counters[level + 1];
65
56
  counters[level + 1] = (childCounter === void 0 || Number.isNaN(childCounter) ? 0 : childCounter) + childAdvances;
66
57
  }
67
- if (abstractNumId !== null) {
68
- if (resumedAbstractCounters) {
69
- const siblingNumIds = siblingNumIdsByAbstractNumId.get(abstractNumId);
70
- for (const otherNumId of siblingNumIds ?? []) {
71
- const otherCounters = listCounters.get(otherNumId);
72
- if (otherNumId === numId || !otherCounters || !otherCounters.every((value, index) => Object.is(value, resumedAbstractCounters[index]))) continue;
73
- for (let i = 0; i < otherCounters.length; i += 1) otherCounters[i] = counters[i] ?? NaN;
74
- }
75
- }
76
- abstractCounters.set(abstractNumId, [...counters]);
77
- }
58
+ if (abstractNumId !== null) abstractCounters.set(abstractNumId, counters);
78
59
  previousList.abstractNumId = abstractNumId;
79
60
  previousList.fromStyle = Boolean(styleNumbering);
80
61
  previousList.numId = numId;
@@ -108,7 +89,6 @@ const parseBlockContent = (parent, styles, theme, numbering, rels, media, option
108
89
  fromStyle: false,
109
90
  numId: null
110
91
  },
111
- siblingNumIdsByAbstractNumId: /* @__PURE__ */ new Map(),
112
92
  options: {
113
93
  ...options,
114
94
  rootXmlns: mergeXmlnsDeclarations(options?.rootXmlns ?? {}, parent)
@@ -129,8 +109,7 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
129
109
  listCounters: state.listCounters,
130
110
  abstractCounters: state.abstractCounters,
131
111
  restartedNumIds: state.restartedNumIds,
132
- previousList: state.previousList,
133
- siblingNumIdsByAbstractNumId: state.siblingNumIdsByAbstractNumId
112
+ previousList: state.previousList
134
113
  });
135
114
  content.push(paragraph);
136
115
  continue;
@@ -392,10 +392,15 @@ const ensureParaIdsInternal = async (docx, options) => {
392
392
  };
393
393
  const zip = await JSZip.loadAsync(docx);
394
394
  if (hasDigitalSignatureParts(zip) && options.allowSignedPackageMutation !== true) throw createEnsureParaIdsError("Refusing to normalize a digitally signed package because rewriting OOXML invalidates its signatures. Warn the user and pass allowSignedPackageMutation only if invalidation is acceptable.");
395
- for (const [partPath, content] of updates) zip.file(partPath, content, {
396
- compression: "DEFLATE",
397
- compressionOptions: { level: 6 }
398
- });
395
+ for (const [partPath, content] of updates) {
396
+ const sourceEntry = zip.file(partPath);
397
+ if (sourceEntry === null) throw createEnsureParaIdsError(`Package part disappeared during normalization: ${partPath}`);
398
+ zip.file(partPath, content, {
399
+ compression: "DEFLATE",
400
+ compressionOptions: { level: 6 },
401
+ date: sourceEntry.date
402
+ });
403
+ }
399
404
  return {
400
405
  docx: await zip.generateAsync({
401
406
  type: "uint8array",
@@ -80,5 +80,7 @@ declare function getBulletCharacter(level: document_d_exports.ListLevel): string
80
80
  * Check if a list level is a bullet (not numbered)
81
81
  */
82
82
  declare function isBulletLevel(level: document_d_exports.ListLevel): boolean;
83
+ /** Whether a numbering level reserves horizontal space for a visible marker. */
84
+ declare const numberingLevelHasMarkerSlot: (level: Pick<document_d_exports.ListLevel, "numFmt">) => boolean;
83
85
  //#endregion
84
- export { NumberingMap, computeListRendering, createNumberingMap, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerFormattingFromLevel, numPrEqual, padDecimal, parseNumbering, renderListMarker };
86
+ export { NumberingMap, computeListRendering, createNumberingMap, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerFormattingFromLevel, numPrEqual, numberingLevelHasMarkerSlot, padDecimal, parseNumbering, renderListMarker };
@@ -542,6 +542,7 @@ function computeListRendering(numPr, numbering) {
542
542
  level: ilvl,
543
543
  numId,
544
544
  marker: level.lvlText,
545
+ markerTemplate: level.lvlText,
545
546
  isBullet: level.numFmt === "bullet",
546
547
  numFmt: level.isLgl ? "decimal" : level.numFmt,
547
548
  levelNumFmts,
@@ -609,5 +610,7 @@ function getBulletCharacter(level) {
609
610
  function isBulletLevel(level) {
610
611
  return level.numFmt === "bullet" || level.numFmt === "none";
611
612
  }
613
+ /** Whether a numbering level reserves horizontal space for a visible marker. */
614
+ const numberingLevelHasMarkerSlot = (level) => level.numFmt !== "none";
612
615
  //#endregion
613
- export { computeListRendering, createNumberingMap, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerFormattingFromLevel, numPrEqual, padDecimal, parseNumbering, renderListMarker };
616
+ export { computeListRendering, createNumberingMap, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerFormattingFromLevel, numPrEqual, numberingLevelHasMarkerSlot, padDecimal, parseNumbering, renderListMarker };
@@ -4,7 +4,7 @@ import { isValidHexId } from "../utils/hexId.js";
4
4
  import { parseBookmarkEnd as parseBookmarkEnd$1, parseBookmarkStart as parseBookmarkStart$1 } from "./bookmarkParser.js";
5
5
  import { parseFieldType } from "./fieldParser.js";
6
6
  import { parseHyperlink as parseHyperlink$1, parseHyperlinkChild } from "./hyperlinkParser.js";
7
- import { markerFormattingFromLevel } from "./numberingParser.js";
7
+ import { markerFormattingFromLevel, numberingLevelHasMarkerSlot } from "./numberingParser.js";
8
8
  import { paraIdInRange } from "./paraIdRangeNormalization.js";
9
9
  import { assignParagraphPropertySource } from "./paragraphPropertySource.js";
10
10
  import { BorderStyleSchema, FrameWrapSchema, FrameXAlignSchema, FrameYAlignSchema, LineSpacingRuleSchema, ParagraphAlignmentSchema, ShadingPatternSchema, TabLeaderSchema, TabStopAlignmentSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
@@ -495,10 +495,10 @@ function normalizeDeletionContentElement(node) {
495
495
  let mappedName = node.name;
496
496
  if (localName === "delText") mappedName = replaceLocalName(node.name, "t");
497
497
  else if (localName === "delInstrText") mappedName = replaceLocalName(node.name, "instrText");
498
- const result = { ...node };
499
- if (mappedName !== void 0) result.name = mappedName;
500
- if (node.elements) result.elements = node.elements.map(normalizeDeletionContentElement);
501
- return result;
498
+ return cloneElement(node, {
499
+ ...mappedName !== void 0 ? { name: mappedName } : {},
500
+ ...node.elements ? { elements: node.elements.map(normalizeDeletionContentElement) } : {}
501
+ });
502
502
  }
503
503
  function parseParagraphPropertyChanges(pPr, theme, styles, currentFormatting) {
504
504
  if (!pPr) return;
@@ -1122,6 +1122,7 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
1122
1122
  level: ilvl,
1123
1123
  numId,
1124
1124
  marker: level.lvlText,
1125
+ markerTemplate: level.lvlText,
1125
1126
  isBullet: level.numFmt === "bullet",
1126
1127
  levelNumFmts,
1127
1128
  levelStarts
@@ -1186,7 +1187,7 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
1186
1187
  const directHanging = directInd ? parseNumericAttribute(directInd, "w", "hanging") : void 0;
1187
1188
  const hasDirectFirstLineOrHanging = directFirstLine !== void 0 && directFirstLine !== 0 || directHanging !== void 0 && directHanging !== 0;
1188
1189
  if (!hasDirectLeft && !chainInd.left && level.pPr.indentLeft !== void 0) paragraph.formatting.indentLeft = level.pPr.indentLeft;
1189
- if (!hasDirectFirstLineOrHanging && !chainInd.firstLine) {
1190
+ if (!hasDirectFirstLineOrHanging && !chainInd.firstLine && numberingLevelHasMarkerSlot(level)) {
1190
1191
  if (level.pPr.indentFirstLine !== void 0) paragraph.formatting.indentFirstLine = level.pPr.indentFirstLine;
1191
1192
  if (level.pPr.hangingIndent !== void 0) paragraph.formatting.hangingIndent = level.pPr.hangingIndent;
1192
1193
  }
@@ -1,41 +1,37 @@
1
1
  //#region src/docx/paragraphTraversal.ts
2
2
  /** Visit every run directly owned by a paragraph's inline-content tree. */
3
3
  const visitParagraphRuns = (paragraph, visit) => {
4
- const visitRun = (run) => {
5
- visit(run);
6
- };
7
- const visitHyperlink = (hyperlink) => {
8
- for (const child of hyperlink.children) if (child.type === "run") visitRun(child);
9
- };
10
- const visitInlineContent = (content) => {
11
- for (const child of content) {
12
- if (child.type === "run") {
13
- visitRun(child);
14
- continue;
15
- }
16
- if (child.type === "hyperlink") visitHyperlink(child);
17
- }
18
- };
19
4
  const visitParagraphContent = (content) => {
20
- if (content.type === "run") {
21
- visitRun(content);
22
- return;
23
- }
24
- if (content.type === "hyperlink") {
25
- visitHyperlink(content);
26
- return;
27
- }
28
- if (content.type === "simpleField" || content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo") {
29
- visitInlineContent(content.content);
30
- return;
31
- }
32
- if (content.type === "inlineSdt") {
33
- for (const child of content.content) visitParagraphContent(child);
34
- return;
35
- }
36
- if (content.type === "complexField") {
37
- for (const run of content.fieldCode) visitRun(run);
38
- for (const run of content.fieldResult) visitRun(run);
5
+ switch (content.type) {
6
+ case "run":
7
+ visit(content);
8
+ return;
9
+ case "hyperlink":
10
+ for (const child of content.children) visitParagraphContent(child);
11
+ return;
12
+ case "simpleField":
13
+ case "insertion":
14
+ case "deletion":
15
+ case "moveFrom":
16
+ case "moveTo":
17
+ case "inlineSdt":
18
+ for (const child of content.content) visitParagraphContent(child);
19
+ return;
20
+ case "complexField":
21
+ for (const run of content.fieldCode) visit(run);
22
+ for (const run of content.fieldResult) visit(run);
23
+ return;
24
+ case "bookmarkStart":
25
+ case "bookmarkEnd":
26
+ case "commentRangeStart":
27
+ case "commentRangeEnd":
28
+ case "commentReference":
29
+ case "moveFromRangeStart":
30
+ case "moveFromRangeEnd":
31
+ case "moveToRangeStart":
32
+ case "moveToRangeEnd":
33
+ case "mathEquation": return;
34
+ default: return content;
39
35
  }
40
36
  };
41
37
  for (const content of paragraph.content) visitParagraphContent(content);
@@ -28,14 +28,6 @@ type RepackOptions = {
28
28
  /** Changed note paragraphs that must be serialized even without source paraIds. */
29
29
  changedNoteParaIds?: ReadonlySet<string>;
30
30
  };
31
- /**
32
- * Repack a Document into a valid DOCX file
33
- *
34
- * @param doc - Document with modified content
35
- * @param options - Optional repack options
36
- * @returns Promise resolving to DOCX as ArrayBuffer
37
- * @throws {Error} if document has no original buffer for round-trip
38
- */
39
31
  declare function repackDocx(doc: document_d_exports.Document, options?: RepackOptions): Promise<ArrayBuffer>;
40
32
  /**
41
33
  * Repack a Document using raw content for more control