@stll/folio-core 0.43.0 → 0.44.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 (183) hide show
  1. package/dist/ai-edits/headless.js +6 -5
  2. package/dist/ai-edits/index.d.ts +2 -2
  3. package/dist/ai-edits/index.js +2 -2
  4. package/dist/ai-edits/snapshot.js +13 -9
  5. package/dist/compare/content-alignment.js +16 -1
  6. package/dist/compare/inline-atoms.js +1 -1
  7. package/dist/compare/style-resources.js +6 -0
  8. package/dist/docx/appVersionNormalization.d.ts +0 -18
  9. package/dist/docx/blockContentParser.js +8 -0
  10. package/dist/docx/blockRangeMarkers.d.ts +36 -0
  11. package/dist/docx/blockRangeMarkers.js +59 -0
  12. package/dist/docx/bookmarkParser.d.ts +2 -20
  13. package/dist/docx/bookmarkParser.js +6 -30
  14. package/dist/docx/borderParser.d.ts +13 -0
  15. package/dist/docx/borderParser.js +71 -0
  16. package/dist/docx/builtInStyles.d.ts +165 -0
  17. package/dist/docx/builtInStyles.js +239 -0
  18. package/dist/docx/commentIdNormalization.d.ts +3 -1
  19. package/dist/docx/commentIdNormalization.js +18 -1
  20. package/dist/docx/commentParser.d.ts +2 -1
  21. package/dist/docx/commentParser.js +34 -7
  22. package/dist/docx/commentReferenceNormalization.d.ts +4 -1
  23. package/dist/docx/commentReferenceNormalization.js +23 -14
  24. package/dist/docx/danglingRelationshipReferences.d.ts +15 -0
  25. package/dist/docx/danglingRelationshipReferences.js +30 -0
  26. package/dist/docx/defaultParagraphStyle.d.ts +18 -1
  27. package/dist/docx/defaultParagraphStyle.js +23 -1
  28. package/dist/docx/documentParser.d.ts +2 -1
  29. package/dist/docx/documentParser.js +2 -2
  30. package/dist/docx/drawingUtils.d.ts +8 -1
  31. package/dist/docx/drawingUtils.js +12 -3
  32. package/dist/docx/fieldParser.js +3 -5
  33. package/dist/docx/footnoteParser.d.ts +3 -2
  34. package/dist/docx/footnoteParser.js +19 -4
  35. package/dist/docx/groupDrawingParser.js +1 -1
  36. package/dist/docx/headerFooterRefParser.d.ts +4 -3
  37. package/dist/docx/headerFooterRefParser.js +42 -12
  38. package/dist/docx/headerFooterReferenceNormalization.d.ts +4 -1
  39. package/dist/docx/headerFooterReferenceNormalization.js +5 -1
  40. package/dist/docx/hyperlinkParser.js +11 -15
  41. package/dist/docx/imageParser.d.ts +1 -1
  42. package/dist/docx/imageParser.js +22 -18
  43. package/dist/docx/imageRawXml.js +5 -5
  44. package/dist/docx/markupRangeMarker.d.ts +15 -0
  45. package/dist/docx/markupRangeMarker.js +44 -0
  46. package/dist/docx/noteReferenceStyles.d.ts +29 -0
  47. package/dist/docx/noteReferenceStyles.js +70 -0
  48. package/dist/docx/numberingReferenceNormalization.d.ts +4 -1
  49. package/dist/docx/numberingReferenceNormalization.js +20 -1
  50. package/dist/docx/paraIdRangeNormalization.d.ts +0 -19
  51. package/dist/docx/paragraphParser.js +66 -99
  52. package/dist/docx/paragraphPropertySource.js +1 -0
  53. package/dist/docx/paragraphTraversal.d.ts +37 -1
  54. package/dist/docx/paragraphTraversal.js +84 -1
  55. package/dist/docx/parseContext.d.ts +37 -0
  56. package/dist/docx/parseContext.js +67 -0
  57. package/dist/docx/parseWarningMessage.d.ts +6 -0
  58. package/dist/docx/parseWarningMessage.js +44 -0
  59. package/dist/docx/parser.js +81 -27
  60. package/dist/docx/relsParser.d.ts +28 -11
  61. package/dist/docx/relsParser.js +26 -13
  62. package/dist/docx/revisionIdNormalization.js +81 -7
  63. package/dist/docx/rezip.js +63 -22
  64. package/dist/docx/runConsolidator.js +1 -2
  65. package/dist/docx/runParser.d.ts +8 -1
  66. package/dist/docx/runParser.js +30 -48
  67. package/dist/docx/sectionParser.d.ts +2 -1
  68. package/dist/docx/sectionParser.js +21 -65
  69. package/dist/docx/serializer/borderSerializer.d.ts +1 -2
  70. package/dist/docx/serializer/commentSerializer.js +22 -9
  71. package/dist/docx/serializer/documentSerializer.d.ts +1 -5
  72. package/dist/docx/serializer/documentSerializer.js +6 -16
  73. package/dist/docx/serializer/headerFooterSerializer.js +5 -0
  74. package/dist/docx/serializer/markupRangeAttributes.d.ts +8 -0
  75. package/dist/docx/serializer/markupRangeAttributes.js +24 -0
  76. package/dist/docx/serializer/noteSerializer.js +5 -0
  77. package/dist/docx/serializer/paragraphSerializer.d.ts +1 -5
  78. package/dist/docx/serializer/paragraphSerializer.js +29 -35
  79. package/dist/docx/serializer/runSerializer.js +13 -7
  80. package/dist/docx/serializer/tableSerializer.js +28 -13
  81. package/dist/docx/serializer/textFormattingSerializer.d.ts +2 -3
  82. package/dist/docx/server/build.js +8 -1
  83. package/dist/docx/server/createBilingualDocument.js +10 -18
  84. package/dist/docx/server/extractDocxText.js +3 -4
  85. package/dist/docx/shadingParser.d.ts +6 -0
  86. package/dist/docx/shadingParser.js +32 -0
  87. package/dist/docx/shapeParser.js +3 -3
  88. package/dist/docx/styleParser.js +13 -87
  89. package/dist/docx/styleReferenceResolution.d.ts +36 -0
  90. package/dist/docx/styleReferenceResolution.js +51 -0
  91. package/dist/docx/tableLook.d.ts +57 -0
  92. package/dist/docx/tableLook.js +63 -0
  93. package/dist/docx/tableParser.d.ts +7 -9
  94. package/dist/docx/tableParser.js +64 -110
  95. package/dist/docx/textBoxParser.js +4 -4
  96. package/dist/docx/trackedMoveRangeNormalization.d.ts +3 -1
  97. package/dist/docx/trackedMoveRangeNormalization.js +11 -21
  98. package/dist/docx/transitionalSpelling.d.ts +13 -2
  99. package/dist/docx/transitionalSpelling.js +23 -1
  100. package/dist/docx/verbatimCapture.js +4 -11
  101. package/dist/docx/vmlImageParser.js +2 -2
  102. package/dist/docx/watermarkParser.js +2 -2
  103. package/dist/docx/xmlParser.d.ts +22 -32
  104. package/dist/docx/xmlParser.js +36 -21
  105. package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
  106. package/dist/internal/paragraphFormattingSerialization.d.ts +2 -3
  107. package/dist/internal/paragraphFormattingSerialization.js +26 -6
  108. package/dist/layout-bridge/convert/footnoteLayout.js +2 -7
  109. package/dist/layout-engine/index.d.ts +2 -2
  110. package/dist/layout-engine/index.js +2 -2
  111. package/dist/layout-engine/measure/measureBlocks.js +1 -6
  112. package/dist/layout-engine/types.d.ts +8 -2
  113. package/dist/layout-engine/types.js +35 -2
  114. package/dist/markdown/index.js +1 -1
  115. package/dist/markdown/internals.d.ts +6 -1
  116. package/dist/markdown/internals.js +14 -1
  117. package/dist/markdown/renderBlock.js +35 -21
  118. package/dist/markdown/renderParagraph.js +14 -5
  119. package/dist/markdown/renderRuns.js +4 -3
  120. package/dist/markdown/renderTable.js +4 -3
  121. package/dist/markdown/trailers.js +41 -7
  122. package/dist/markdown/types.d.ts +3 -7
  123. package/dist/prosemirror/attrs/index.js +2 -5
  124. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +11 -1
  125. package/dist/prosemirror/bookmarkBoundaryAttrs.js +18 -3
  126. package/dist/prosemirror/commands/index.d.ts +3 -3
  127. package/dist/prosemirror/commands/index.js +2 -2
  128. package/dist/prosemirror/commands/paragraph.d.ts +3 -3
  129. package/dist/prosemirror/commands/paragraph.js +2 -2
  130. package/dist/prosemirror/commentIdAllocator.js +2 -7
  131. package/dist/prosemirror/conversion/fromProseDoc.js +129 -40
  132. package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -14
  133. package/dist/prosemirror/conversion/toProseDoc.js +375 -316
  134. package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +14 -1
  135. package/dist/prosemirror/extensions/core/ParagraphExtension.js +11 -6
  136. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -3
  137. package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
  138. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +6 -2
  139. package/dist/prosemirror/extensions/features/pastedHeadingStyles.d.ts +7 -0
  140. package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +74 -0
  141. package/dist/prosemirror/extensions/marks/markUtils.d.ts +11 -3
  142. package/dist/prosemirror/extensions/marks/markUtils.js +98 -19
  143. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +7 -3
  144. package/dist/prosemirror/extensions/nodes/ImageExtension.js +2 -1
  145. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
  146. package/dist/prosemirror/extensions/nodes/TableExtension.js +15 -1
  147. package/dist/prosemirror/extensions/types.d.ts +2 -2
  148. package/dist/prosemirror/index.d.ts +3 -3
  149. package/dist/prosemirror/index.js +3 -3
  150. package/dist/prosemirror/insertOperations.d.ts +9 -2
  151. package/dist/prosemirror/insertOperations.js +9 -4
  152. package/dist/prosemirror/paragraphFormattingProvenance.d.ts +159 -0
  153. package/dist/prosemirror/paragraphFormattingProvenance.js +106 -0
  154. package/dist/prosemirror/plugins/documentStyles.d.ts +9 -1
  155. package/dist/prosemirror/plugins/documentStyles.js +11 -1
  156. package/dist/prosemirror/plugins/index.d.ts +2 -2
  157. package/dist/prosemirror/plugins/index.js +2 -2
  158. package/dist/prosemirror/plugins/revisionIds.d.ts +11 -2
  159. package/dist/prosemirror/plugins/revisionIds.js +21 -6
  160. package/dist/prosemirror/runFormattingReconciliation.js +3 -2
  161. package/dist/prosemirror/runStyleFormatting.d.ts +1 -1
  162. package/dist/prosemirror/schema/nodes.d.ts +31 -0
  163. package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -0
  164. package/dist/prosemirror/styles/styleResolver.d.ts +9 -0
  165. package/dist/prosemirror/styles/styleResolver.js +12 -0
  166. package/dist/style-engine/styleEngine.d.ts +3 -0
  167. package/dist/style-engine/styleEngine.js +3 -0
  168. package/dist/style-sets/extract.js +1 -23
  169. package/dist/style-sets/stellaStyle.js +46 -39
  170. package/dist/style-sets/styleSetNormalization.d.ts +19 -0
  171. package/dist/style-sets/styleSetNormalization.js +99 -0
  172. package/dist/types/content.d.ts +2 -2
  173. package/dist/utils/createDocument.js +145 -20
  174. package/dist/utils/headingCollector.d.ts +8 -5
  175. package/dist/utils/headingCollector.js +23 -25
  176. package/dist/utils/tableOfContentsStyle.js +9 -2
  177. package/package.json +2 -2
  178. package/dist/docx/textWhitespace.d.ts +0 -4
  179. package/dist/docx/textWhitespace.js +0 -4
  180. package/dist/layout-bridge/engine/tableWidthUtils.d.ts +0 -6
  181. package/dist/layout-bridge/engine/tableWidthUtils.js +0 -25
  182. package/dist/markdown/headings.d.ts +0 -13
  183. package/dist/markdown/headings.js +0 -20
@@ -264,11 +264,12 @@ const formatBlockLine = (block, text) => {
264
264
  return `${label} ${text}`;
265
265
  };
266
266
  const formatBlockForLLM = (block) => formatBlockLine(block, block.text);
267
- const headingLevel = (block) => {
268
- const digits = /(\d+)/u.exec(block.styleId ?? block.displayLabel ?? "")?.[1];
269
- const level = digits ? Number.parseInt(digits, 10) : 1;
270
- return level >= 1 && level <= 9 ? level : 1;
271
- };
267
+ /**
268
+ * The level the snapshot already classified. Scraping a digit out of the style
269
+ * id instead read `ClauseParagraph2` as an h2 and every localized heading id
270
+ * without a digit as an h1.
271
+ */
272
+ const headingLevel = (block) => block.headingLevel ?? 1;
272
273
  const revisionIdOf = (target) => typeof target === "number" ? target : target.id;
273
274
  const commentPlainText = (comment) => (comment.content ?? []).map(paragraphPlainText).join("\n");
274
275
  const paragraphPlainText = (paragraph) => {
@@ -6,8 +6,8 @@ import { DocPositionRange, clampRangeToDocSize, resolveFolioAIBlockRange, resolv
6
6
  import { buildAnnotatedBlockText } from "./clean-text.js";
7
7
  import { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
8
8
  import { FolioCommentAnchor, FolioReviewChange, FolioReviewChangeKind, getCommentAnchorsFromDoc, getTrackedChangesFromDoc } from "./read.js";
9
- import { createFolioAIEditSnapshot, createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./snapshot.js";
9
+ import { createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./snapshot.js";
10
10
  import { FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioApplyDocumentOperationsToStoryOptions, FolioDocumentStory, FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, FolioEditableDocumentStoryHandle, FolioReadReviewedStoryOptions, FolioResolveReviewedStoryOptions, FolioResolvedReviewedView, FolioReviewedStory, FolioReviewedView, UnsupportedFolioReviewedViewError, isFolioResolvedReviewedView, isFolioReviewedView } from "./headless.js";
11
11
  import { getFolioDocumentOutline, readFolioDocumentSection } from "./scoped-reading.js";
12
12
  import { getFolioParaIdFromBlockId } from "../types/block-id.js";
13
- export { type ApplyFolioDocumentOperationsOptions, type DocPositionRange, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIEditView, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIInsertFormattingScope, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsToStoryOptions, type FolioCommentAnchor, type FolioContentParagraphKind, type FolioDocumentNavigationTarget, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocumentOutline, type FolioDocumentOutlineEntry, type FolioDocumentSection, type FolioDocumentSectionHandle, type FolioDocumentSectionReadResult, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, type FolioEditableDocumentStoryHandle, type FolioReadReviewedStoryOptions, type FolioResolveReviewedStoryOptions, type FolioResolvedReviewedView, type FolioReviewChange, type FolioReviewChangeKind, type FolioReviewedStory, type FolioReviewedView, type FolioRevisionStamp, type FolioWordDiffOptions, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAITextRangeHandle, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
13
+ export { type ApplyFolioDocumentOperationsOptions, type DocPositionRange, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIEditView, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIInsertFormattingScope, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsToStoryOptions, type FolioCommentAnchor, type FolioContentParagraphKind, type FolioDocumentNavigationTarget, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocumentOutline, type FolioDocumentOutlineEntry, type FolioDocumentSection, type FolioDocumentSectionHandle, type FolioDocumentSectionReadResult, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, type FolioEditableDocumentStoryHandle, type FolioReadReviewedStoryOptions, type FolioResolveReviewedStoryOptions, type FolioResolvedReviewedView, type FolioReviewChange, type FolioReviewChangeKind, type FolioReviewedStory, type FolioReviewedView, type FolioRevisionStamp, type FolioWordDiffOptions, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
@@ -6,6 +6,6 @@ import { buildAnnotatedBlockText } from "./clean-text.js";
6
6
  import { FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioDocumentStoryNotFoundError, UnsupportedFolioReviewedViewError, isFolioResolvedReviewedView, isFolioReviewedView } from "./headless.js";
7
7
  import { getCommentAnchorsFromDoc, getTrackedChangesFromDoc } from "./read.js";
8
8
  import { getFolioDocumentOutline, readFolioDocumentSection } from "./scoped-reading.js";
9
- import { createFolioAIEditSnapshot, createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./snapshot.js";
9
+ import { createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./snapshot.js";
10
10
  import { WORD_DIFF_GRANULARITIES, diffWordSegments } from "./word-diff.js";
11
- export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioDocumentStoryNotFoundError, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAITextRangeHandle, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
11
+ export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, 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, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioDocumentStoryNotFoundError, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
@@ -1,3 +1,4 @@
1
+ import { EMPTY_BUILT_IN_STYLE_INDEX, resolveHeadingLevel } from "../docx/builtInStyles.js";
1
2
  import { recreateProseNodeWithParagraphPropertySource } from "../docx/paragraphPropertySource.js";
2
3
  import { expectCharacterStyleMarkAttrs, expectHyperlinkMarkAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs } from "../prosemirror/attrs/index.js";
3
4
  import { marksToTextFormatting } from "../prosemirror/conversion/fromProseDoc.js";
@@ -335,6 +336,7 @@ const getTableLocation = ({ path, blockIndex, tableIndexByStart }) => {
335
336
  }
336
337
  };
337
338
  const createFolioAIEditSnapshotInternal = (doc, styleResolver) => {
339
+ const builtInStyles = styleResolver?.builtInStyles ?? EMPTY_BUILT_IN_STYLE_INDEX;
338
340
  const draftBlocks = [];
339
341
  const hashCounts = /* @__PURE__ */ new Map();
340
342
  const usedBlockIds = /* @__PURE__ */ new Set();
@@ -394,9 +396,9 @@ const createFolioAIEditSnapshotInternal = (doc, styleResolver) => {
394
396
  });
395
397
  }
396
398
  usedBlockIds.add(id);
397
- const headingLevel = getHeadingLevel(node);
399
+ const headingLevel = getHeadingLevel(node, builtInStyles);
398
400
  const kind = getBlockKind(node, headingLevel);
399
- const displayLabel = getDisplayLabel(node);
401
+ const displayLabel = getDisplayLabel(node, kind === "heading");
400
402
  const styleId = getStyleId(node);
401
403
  const listLevel = getListLevel(node);
402
404
  const listReference = getListReference(node);
@@ -477,19 +479,21 @@ const getBlockKind = (node, headingLevel) => {
477
479
  if (headingLevel !== void 0) return "heading";
478
480
  return "paragraph";
479
481
  };
480
- const getHeadingLevel = (node) => {
482
+ /** The block's 1-based heading level, as {@link resolveHeadingLevel} classifies it. */
483
+ const getHeadingLevel = (node, styles) => {
481
484
  const outlineLevel = node.attrs["outlineLevel"];
482
- if (typeof outlineLevel === "number" && Number.isInteger(outlineLevel) && outlineLevel >= 0 && outlineLevel <= 8) return outlineLevel + 1;
483
485
  const styleId = node.attrs["styleId"];
484
- if (typeof styleId !== "string") return;
485
- const level = /^heading(?<level>[1-9])$/iu.exec(styleId)?.groups?.["level"];
486
- return level === void 0 ? void 0 : Number.parseInt(level, 10);
486
+ const level = resolveHeadingLevel({
487
+ outlineLevel: typeof outlineLevel === "number" ? outlineLevel : null,
488
+ styleId: typeof styleId === "string" ? styleId : null
489
+ }, styles);
490
+ return level === void 0 ? void 0 : level + 1;
487
491
  };
488
- const getDisplayLabel = (node) => {
492
+ const getDisplayLabel = (node, isHeading) => {
489
493
  const listMarker = node.attrs["listMarker"];
490
494
  if (typeof listMarker === "string" && listMarker.trim().length > 0) return listMarker.trim();
491
495
  const styleId = node.attrs["styleId"];
492
- if (typeof styleId === "string" && /^heading/iu.test(styleId)) return styleId;
496
+ if (isHeading && typeof styleId === "string") return styleId;
493
497
  };
494
498
  const getListLevel = (node) => {
495
499
  const numPr = node.attrs["numPr"];
@@ -1171,7 +1171,22 @@ const contentStructureEvidenceIndexes = (base, revised) => {
1171
1171
  revised: index(revised)
1172
1172
  };
1173
1173
  };
1174
- const sortedIndexesLeaveRange = (indexes, start, end) => indexes !== void 0 && ((indexes.at(0) ?? start) < start || (indexes.at(-1) ?? end - 1) >= end);
1174
+ /**
1175
+ * Whether the evidence lies outside the range, and only outside it.
1176
+ *
1177
+ * Evidence inside the range is at least as good a counterpart as evidence
1178
+ * beyond it, so a match that is also present locally does not make the local
1179
+ * pair suspect. Without the second test, two structurally identical tables in
1180
+ * one document cancel each other: each shares every exact signature and anchor
1181
+ * text with the other by construction, so each looks like it belongs
1182
+ * elsewhere, and comparing the document with itself reports both deleted and
1183
+ * both re-inserted.
1184
+ */
1185
+ const sortedIndexesLeaveRange = (indexes, start, end) => {
1186
+ if (indexes === void 0) return false;
1187
+ if ((indexes.at(0) ?? start) >= start && (indexes.at(-1) ?? end - 1) < end) return false;
1188
+ return !indexes.some((index) => index >= start && index < end);
1189
+ };
1175
1190
  const profileHasEvidenceOutsideRange = (profile, opposite, start, end) => {
1176
1191
  const exactKey = opposite.exactKeyByProfile.get(profile);
1177
1192
  if (exactKey !== void 0 && sortedIndexesLeaveRange(opposite.exactIndexes.get(exactKey), start, end)) return true;
@@ -69,7 +69,7 @@ const atomBlockOf = ({ node, from }) => {
69
69
  }
70
70
  const prepared = prepareTargetInlineAtom(child);
71
71
  if (!prepared) {
72
- unalignable = true;
72
+ unsupportedTopology.push(`${offset}:${child.type.name}:${canonicalJson(child.attrs)}`);
73
73
  return false;
74
74
  }
75
75
  supported.push({
@@ -213,6 +213,12 @@ const importReferencedStyleDefinitions = ({ sourceStyles, destinationStyles, sou
213
213
  styleIdMap: /* @__PURE__ */ new Map(),
214
214
  importedStyleIds: []
215
215
  };
216
+ if (requested.length === 0 && !sourceStyles && !destinationStyles) return {
217
+ status: "unchanged",
218
+ styles: destinationStyles,
219
+ styleIdMap: /* @__PURE__ */ new Map(),
220
+ importedStyleIds: []
221
+ };
216
222
  if (!sourceStyles) return {
217
223
  status: "unalignable",
218
224
  detail: "the target has no style definitions"
@@ -1,22 +1,4 @@
1
1
  //#region src/docx/appVersionNormalization.d.ts
2
- /**
3
- * Keep the application version a package states about itself in the form the
4
- * schema gives it.
5
- *
6
- * `AppVersion` in the extended-properties part is `XX.YYYY`: a one- or
7
- * two-digit integer, a dot, and four digits. Producers exist that write a
8
- * three-part version there instead, and folio copies `docProps/app.xml`
9
- * through verbatim when it saves a document it did not create — so a package
10
- * can carry a value with two dots in, and a save that copies it out hands a
11
- * consumer a package it refuses to open at all.
12
- *
13
- * {@link appVersionInSchemaForm} is the one mapping, and it is a pure function
14
- * of the value alone: it keeps the leading integer where the value opens with
15
- * one the form allows, and writes the build digits the form requires. Nothing
16
- * else in the part is touched, and a package that carries no extended
17
- * properties keeps carrying none — synthesizing metadata a document never
18
- * stated is a different decision.
19
- */
20
2
  declare const AppVersionSchemaError_base: import("better-result").TaggedErrorClass<"AppVersionSchemaError">;
21
3
  /**
22
4
  * A value reached the package that the schema form does not accept.
@@ -1,3 +1,4 @@
1
+ import { attachPendingRangeMarkers, attachTrailingRangeMarkers, isBlockRangeMarker } from "./blockRangeMarkers.js";
1
2
  import { parseBookmarkEnd, parseBookmarkStart } from "./bookmarkParser.js";
2
3
  import { appendBookmarkMarkerToLastParagraphInBlocks, prependBookmarkMarkersToFirstParagraphInBlocks } from "./bookmarkPlacement.js";
3
4
  import { convertBulletToUnicode } from "./bulletMarkers.js";
@@ -106,6 +107,7 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
106
107
  const content = [];
107
108
  const children = getChildElements(parent);
108
109
  const pendingBookmarkMarkers = [];
110
+ const pendingRangeMarkers = [];
109
111
  for (const child of children) {
110
112
  const localName = getLocalName(child.name ?? "");
111
113
  if (localName === "p") {
@@ -119,6 +121,7 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
119
121
  restartedNumIds: state.restartedNumIds,
120
122
  previousList: state.previousList
121
123
  });
124
+ attachPendingRangeMarkers(paragraph, pendingRangeMarkers);
122
125
  content.push(paragraph);
123
126
  continue;
124
127
  }
@@ -126,6 +129,7 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
126
129
  const table = parseTable(child, styles, theme, numbering, rels, media, state.options);
127
130
  if (!table) continue;
128
131
  if (prependBookmarkMarkersToFirstParagraphInBlocks([table], pendingBookmarkMarkers)) pendingBookmarkMarkers.length = 0;
132
+ attachPendingRangeMarkers(table, pendingRangeMarkers);
129
133
  content.push(table);
130
134
  continue;
131
135
  }
@@ -143,6 +147,7 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
143
147
  content: sdtContent ? parseBlockContentWithState(sdtContent, styles, theme, numbering, rels, media, withContainerXmlns(withContainerXmlns(state, child), sdtContent)) : []
144
148
  };
145
149
  if (prependBookmarkMarkersToFirstParagraphInBlocks(blockSdt.content, pendingBookmarkMarkers)) pendingBookmarkMarkers.length = 0;
150
+ attachPendingRangeMarkers(blockSdt, pendingRangeMarkers);
146
151
  content.push(blockSdt);
147
152
  continue;
148
153
  }
@@ -154,12 +159,15 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
154
159
  if (localName === "bookmarkStart" || localName === "bookmarkEnd") {
155
160
  const marker = parseBookmarkMarker(child, localName);
156
161
  if (!appendBookmarkMarkerToLastParagraphInBlocks(content, marker)) pendingBookmarkMarkers.push(marker);
162
+ continue;
157
163
  }
164
+ if (isBlockRangeMarker(localName)) pendingRangeMarkers.push(captureVerbatimXml(child));
158
165
  }
159
166
  if (pendingBookmarkMarkers.length > 0) content.push({
160
167
  type: "paragraph",
161
168
  content: [...pendingBookmarkMarkers]
162
169
  });
170
+ attachTrailingRangeMarkers(content, pendingRangeMarkers);
163
171
  return content;
164
172
  };
165
173
  /**
@@ -0,0 +1,36 @@
1
+ //#region src/docx/blockRangeMarkers.d.ts
2
+ /**
3
+ * Range markers that stand between two blocks.
4
+ *
5
+ * `w:body`, `w:tc`, a header and an SDT's content all admit
6
+ * `EG_RunLevelElts` and `EG_RangeMarkupElements` beside their paragraphs, and
7
+ * every block container dropped them: a `w:permStart` between two paragraphs
8
+ * is the whole of a document-protection range, so losing it removes the
9
+ * protection from the saved file without a word. folio models none of these,
10
+ * and their position is their meaning, so they are captured verbatim and
11
+ * replayed where they stood — the same treatment `w:sdt`'s sibling markers
12
+ * already get (MS-OE376 §2.5.2.30).
13
+ *
14
+ * Bookmarks are absent from the set on purpose: they are modelled, and the
15
+ * block containers already relocate them into the neighbouring paragraph.
16
+ */
17
+ declare const isBlockRangeMarker: (localName: string) => boolean;
18
+ /** Hand the markers collected so far to the block they stood before. */
19
+ declare const attachPendingRangeMarkers: (block: {
20
+ rawMarkersBefore?: string;
21
+ }, pending: string[]) => void;
22
+ /**
23
+ * Markers after the last block ride on it, since there is no block after them.
24
+ * With no block at all they are dropped: a container holding markers and no
25
+ * content has nothing for them to delimit.
26
+ */
27
+ declare const attachTrailingRangeMarkers: (blocks: readonly {
28
+ rawMarkersAfter?: string;
29
+ }[], pending: string[]) => void;
30
+ /** Wrap a serialized block in the markup that stood around it. */
31
+ declare const withBlockRangeMarkers: (block: {
32
+ rawMarkersBefore?: string;
33
+ rawMarkersAfter?: string;
34
+ }, xml: string) => string;
35
+ //#endregion
36
+ export { attachPendingRangeMarkers, attachTrailingRangeMarkers, isBlockRangeMarker, withBlockRangeMarkers };
@@ -0,0 +1,59 @@
1
+ //#region src/docx/blockRangeMarkers.ts
2
+ /**
3
+ * Range markers that stand between two blocks.
4
+ *
5
+ * `w:body`, `w:tc`, a header and an SDT's content all admit
6
+ * `EG_RunLevelElts` and `EG_RangeMarkupElements` beside their paragraphs, and
7
+ * every block container dropped them: a `w:permStart` between two paragraphs
8
+ * is the whole of a document-protection range, so losing it removes the
9
+ * protection from the saved file without a word. folio models none of these,
10
+ * and their position is their meaning, so they are captured verbatim and
11
+ * replayed where they stood — the same treatment `w:sdt`'s sibling markers
12
+ * already get (MS-OE376 §2.5.2.30).
13
+ *
14
+ * Bookmarks are absent from the set on purpose: they are modelled, and the
15
+ * block containers already relocate them into the neighbouring paragraph.
16
+ */
17
+ const BLOCK_RANGE_MARKER_NAMES = /* @__PURE__ */ new Set([
18
+ "commentRangeEnd",
19
+ "commentRangeStart",
20
+ "customXmlDelRangeEnd",
21
+ "customXmlDelRangeStart",
22
+ "customXmlInsRangeEnd",
23
+ "customXmlInsRangeStart",
24
+ "customXmlMoveFromRangeEnd",
25
+ "customXmlMoveFromRangeStart",
26
+ "customXmlMoveToRangeEnd",
27
+ "customXmlMoveToRangeStart",
28
+ "moveFromRangeEnd",
29
+ "moveFromRangeStart",
30
+ "moveToRangeEnd",
31
+ "moveToRangeStart",
32
+ "permEnd",
33
+ "permStart"
34
+ ]);
35
+ const isBlockRangeMarker = (localName) => BLOCK_RANGE_MARKER_NAMES.has(localName);
36
+ /** Hand the markers collected so far to the block they stood before. */
37
+ const attachPendingRangeMarkers = (block, pending) => {
38
+ if (pending.length === 0) return;
39
+ block.rawMarkersBefore = pending.join("");
40
+ pending.length = 0;
41
+ };
42
+ /**
43
+ * Markers after the last block ride on it, since there is no block after them.
44
+ * With no block at all they are dropped: a container holding markers and no
45
+ * content has nothing for them to delimit.
46
+ */
47
+ const attachTrailingRangeMarkers = (blocks, pending) => {
48
+ const last = blocks.at(-1);
49
+ if (pending.length === 0 || last === void 0) {
50
+ pending.length = 0;
51
+ return;
52
+ }
53
+ last.rawMarkersAfter = pending.join("");
54
+ pending.length = 0;
55
+ };
56
+ /** Wrap a serialized block in the markup that stood around it. */
57
+ const withBlockRangeMarkers = (block, xml) => `${block.rawMarkersBefore ?? ""}${xml}${block.rawMarkersAfter ?? ""}`;
58
+ //#endregion
59
+ export { attachPendingRangeMarkers, attachTrailingRangeMarkers, isBlockRangeMarker, withBlockRangeMarkers };
@@ -1,27 +1,9 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { XmlElement } from "./xmlParser.js";
3
3
  //#region src/docx/bookmarkParser.d.ts
4
- /**
5
- * Parse a bookmark start element (w:bookmarkStart)
6
- *
7
- * Extracts:
8
- * - id: Numeric identifier (required, matches with bookmarkEnd)
9
- * - name: Bookmark name (required, used by hyperlinks)
10
- * - colFirst: First column for table bookmarks (optional)
11
- * - colLast: Last column for table bookmarks (optional)
12
- *
13
- * @param node - The w:bookmarkStart XML element
14
- * @returns Parsed BookmarkStart object
15
- */
4
+ /** Parse a bookmark start element (w:bookmarkStart, CT_Bookmark). */
16
5
  declare function parseBookmarkStart(node: XmlElement): document_d_exports.BookmarkStart;
17
- /**
18
- * Parse a bookmark end element (w:bookmarkEnd)
19
- *
20
- * Bookmark ends only contain an ID that matches the corresponding start marker.
21
- *
22
- * @param node - The w:bookmarkEnd XML element
23
- * @returns Parsed BookmarkEnd object
24
- */
6
+ /** Parse a bookmark end element (w:bookmarkEnd, CT_MarkupRange). */
25
7
  declare function parseBookmarkEnd(node: XmlElement): document_d_exports.BookmarkEnd;
26
8
  /**
27
9
  * Bookmark map for quick lookup by ID or name
@@ -1,41 +1,17 @@
1
- import { getAttribute, parseNumericAttribute } from "./xmlParser.js";
1
+ import { parseBookmarkRangeMarker, parseMarkupRangeMarker } from "./markupRangeMarker.js";
2
2
  //#region src/docx/bookmarkParser.ts
3
- /**
4
- * Parse a bookmark start element (w:bookmarkStart)
5
- *
6
- * Extracts:
7
- * - id: Numeric identifier (required, matches with bookmarkEnd)
8
- * - name: Bookmark name (required, used by hyperlinks)
9
- * - colFirst: First column for table bookmarks (optional)
10
- * - colLast: Last column for table bookmarks (optional)
11
- *
12
- * @param node - The w:bookmarkStart XML element
13
- * @returns Parsed BookmarkStart object
14
- */
3
+ /** Parse a bookmark start element (w:bookmarkStart, CT_Bookmark). */
15
4
  function parseBookmarkStart(node) {
16
- const bookmark = {
5
+ return {
17
6
  type: "bookmarkStart",
18
- id: parseNumericAttribute(node, "w", "id") ?? 0,
19
- name: getAttribute(node, "w", "name") ?? ""
7
+ ...parseBookmarkRangeMarker(node)
20
8
  };
21
- const colFirst = parseNumericAttribute(node, "w", "colFirst");
22
- if (colFirst !== void 0) bookmark.colFirst = colFirst;
23
- const colLast = parseNumericAttribute(node, "w", "colLast");
24
- if (colLast !== void 0) bookmark.colLast = colLast;
25
- return bookmark;
26
9
  }
27
- /**
28
- * Parse a bookmark end element (w:bookmarkEnd)
29
- *
30
- * Bookmark ends only contain an ID that matches the corresponding start marker.
31
- *
32
- * @param node - The w:bookmarkEnd XML element
33
- * @returns Parsed BookmarkEnd object
34
- */
10
+ /** Parse a bookmark end element (w:bookmarkEnd, CT_MarkupRange). */
35
11
  function parseBookmarkEnd(node) {
36
12
  return {
37
13
  type: "bookmarkEnd",
38
- id: parseNumericAttribute(node, "w", "id") ?? 0
14
+ ...parseMarkupRangeMarker(node)
39
15
  };
40
16
  }
41
17
  /**
@@ -0,0 +1,13 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { ParseContext } from "./parseContext.js";
3
+ import { XmlElement } from "./xmlParser.js";
4
+ //#region src/docx/borderParser.d.ts
5
+ /**
6
+ * `w:val` is `use="required"` on `CT_Border`. An element without it states no
7
+ * style at all, so the border is dropped rather than invented as `none`:
8
+ * `none` is an authored token that cancels an inherited border, and a
9
+ * malformed element is not evidence the author wanted that.
10
+ */
11
+ declare function parseBorderSpec(border: XmlElement | null, context?: ParseContext): document_d_exports.BorderSpec | undefined;
12
+ //#endregion
13
+ export { parseBorderSpec };
@@ -0,0 +1,71 @@
1
+ import { BorderStyleSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
2
+ import { getAttribute, parseNumericAttribute, parseOnOffAttribute } from "./xmlParser.js";
3
+ import { PARSE_WARNING_CODES } from "@stll/docx-core/model";
4
+ //#region src/docx/borderParser.ts
5
+ /**
6
+ * The one reader for `CT_Border`, shared by the paragraph (`w:pBdr`), style,
7
+ * table (`w:tblBorders`/`w:tcBorders`) and page (`w:pgBorders`) tiers.
8
+ *
9
+ * `w:val` is `ST_Border`, whose 193 members include two distinct "no border"
10
+ * tokens: `nil` and `none`. They are not interchangeable downstream, and an
11
+ * explicit one overrides a border inherited from the container, so the member
12
+ * the author wrote is preserved exactly. Members outside the model's known
13
+ * union survive verbatim rather than collapsing to a default, which is how the
14
+ * repo already treats `w:numFmt`, `w:suff` and `w:tab`.
15
+ */
16
+ const parseBorderColor = (border) => {
17
+ const rgb = getAttribute(border, "w", "color");
18
+ const themeColor = getAttribute(border, "w", "themeColor");
19
+ const themeTint = getAttribute(border, "w", "themeTint");
20
+ const themeShade = getAttribute(border, "w", "themeShade");
21
+ if (rgb === null && themeColor === null && themeTint === null && themeShade === null) return;
22
+ const color = {};
23
+ if (rgb === "auto") color.auto = true;
24
+ else if (rgb) color.rgb = rgb;
25
+ const validatedThemeColor = narrowEnum(themeColor, ThemeColorSlotSchema);
26
+ if (validatedThemeColor) color.themeColor = validatedThemeColor;
27
+ if (themeTint) color.themeTint = themeTint;
28
+ if (themeShade) color.themeShade = themeShade;
29
+ return color;
30
+ };
31
+ /**
32
+ * `w:val` is `use="required"` on `CT_Border`. An element without it states no
33
+ * style at all, so the border is dropped rather than invented as `none`:
34
+ * `none` is an authored token that cancels an inherited border, and a
35
+ * malformed element is not evidence the author wanted that.
36
+ */
37
+ function parseBorderSpec(border, context) {
38
+ if (!border) return;
39
+ const rawStyle = getAttribute(border, "w", "val");
40
+ if (!rawStyle) {
41
+ context?.warn({
42
+ code: PARSE_WARNING_CODES.borderWithoutValue,
43
+ element: border.name ?? "border"
44
+ });
45
+ return;
46
+ }
47
+ const spec = { style: narrowEnum(rawStyle, BorderStyleSchema) ?? rawStyle };
48
+ const color = parseBorderColor(border);
49
+ if (color) spec.color = color;
50
+ const size = parseNumericAttribute(border, "w", "sz");
51
+ if (size !== void 0) spec.size = size;
52
+ const space = parseNumericAttribute(border, "w", "space");
53
+ if (space !== void 0) spec.space = space;
54
+ const shadow = parseOnOffAttribute(border, "w", "shadow");
55
+ if (shadow !== void 0) spec.shadow = shadow;
56
+ const frame = parseOnOffAttribute(border, "w", "frame");
57
+ if (frame !== void 0) spec.frame = frame;
58
+ const artRelationshipId = getAttribute(border, "w", "id")?.trim();
59
+ if (artRelationshipId) spec.artRelationshipId = artRelationshipId;
60
+ const topLeftArtRelationshipId = getAttribute(border, "w", "topLeft")?.trim();
61
+ if (topLeftArtRelationshipId) spec.topLeftArtRelationshipId = topLeftArtRelationshipId;
62
+ const topRightArtRelationshipId = getAttribute(border, "w", "topRight")?.trim();
63
+ if (topRightArtRelationshipId) spec.topRightArtRelationshipId = topRightArtRelationshipId;
64
+ const bottomLeftArtRelationshipId = getAttribute(border, "w", "bottomLeft")?.trim();
65
+ if (bottomLeftArtRelationshipId) spec.bottomLeftArtRelationshipId = bottomLeftArtRelationshipId;
66
+ const bottomRightArtRelationshipId = getAttribute(border, "w", "bottomRight")?.trim();
67
+ if (bottomRightArtRelationshipId) spec.bottomRightArtRelationshipId = bottomRightArtRelationshipId;
68
+ return spec;
69
+ }
70
+ //#endregion
71
+ export { parseBorderSpec };