@stll/folio-core 0.46.0 → 0.47.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 (366) hide show
  1. package/dist/ai-edits/apply.js +26 -24
  2. package/dist/ai-edits/headless.js +1 -1
  3. package/dist/ai-edits/read.d.ts +1 -0
  4. package/dist/ai-edits/read.js +1 -0
  5. package/dist/ai-edits/snapshot.js +32 -27
  6. package/dist/ai-edits/table-cell-mutations.js +15 -7
  7. package/dist/ai-edits/table-geometry.js +21 -18
  8. package/dist/ai-edits/table-template.js +2 -2
  9. package/dist/compare/content-alignment.js +108 -12
  10. package/dist/compare/content-types.d.ts +8 -2
  11. package/dist/compare/content.js +2 -11
  12. package/dist/compare/plan.js +7 -4
  13. package/dist/compare/section-boundary-properties.js +1 -2
  14. package/dist/content-controls/checkboxDisplay.d.ts +8 -2
  15. package/dist/content-controls/checkboxDisplay.js +11 -5
  16. package/dist/content-controls/mutateContentControls.js +41 -42
  17. package/dist/controller/layoutPipeline.js +8 -3
  18. package/dist/display-list/build/buildDisplayList.js +7 -7
  19. package/dist/display-list/build/imagePrimitives.d.ts +4 -4
  20. package/dist/display-list/build/imagePrimitives.js +38 -20
  21. package/dist/display-list/build/pageBorderPrimitives.js +2 -1
  22. package/dist/display-list/build/paragraphPrimitives.js +93 -13
  23. package/dist/display-list/build/previewPrimitives.d.ts +10 -0
  24. package/dist/display-list/build/previewPrimitives.js +89 -0
  25. package/dist/display-list/build/strokes.d.ts +177 -8
  26. package/dist/display-list/build/strokes.js +167 -47
  27. package/dist/display-list/build/tablePrimitives.js +4 -2
  28. package/dist/display-list/build/textBoxPrimitives.js +6 -4
  29. package/dist/display-list/build/textDecorations.d.ts +15 -1
  30. package/dist/display-list/build/textDecorations.js +15 -1
  31. package/dist/display-list/dom/renderDisplayListToDom.js +1 -19
  32. package/dist/display-list/primitives.d.ts +13 -2
  33. package/dist/display-list/primitives.js +36 -1
  34. package/dist/document-operations.js +2 -1
  35. package/dist/docx/attributeRemainder.d.ts +34 -1
  36. package/dist/docx/attributeRemainder.js +49 -3
  37. package/dist/docx/blockContentParser.d.ts +2 -0
  38. package/dist/docx/blockContentParser.js +39 -67
  39. package/dist/docx/blockPlainText.js +3 -1
  40. package/dist/docx/borderParser.js +26 -11
  41. package/dist/docx/builtInStyles.d.ts +8 -16
  42. package/dist/docx/builtInStyles.js +54 -17
  43. package/dist/docx/commentAnchorIndex.js +1 -1
  44. package/dist/docx/commentParser.js +3 -3
  45. package/dist/docx/commentRangeIntegrity.js +1 -1
  46. package/dist/docx/commentRangeJoin.js +1 -1
  47. package/dist/docx/commentReferenceNormalization.js +3 -2
  48. package/dist/docx/commentReplyMarkers.js +1 -1
  49. package/dist/docx/compatibility.js +56 -42
  50. package/dist/docx/containerChildren.d.ts +110 -13
  51. package/dist/docx/containerChildren.gen.d.ts +16 -1
  52. package/dist/docx/containerChildren.gen.js +18 -1
  53. package/dist/docx/containerChildren.js +63 -13
  54. package/dist/docx/diagramPreview.d.ts +14 -2
  55. package/dist/docx/diagramPreview.js +81 -169
  56. package/dist/docx/documentParser.js +4 -1
  57. package/dist/docx/drawingAnchor.d.ts +87 -0
  58. package/dist/docx/drawingAnchor.js +201 -0
  59. package/dist/docx/drawingUtils.d.ts +43 -38
  60. package/dist/docx/drawingUtils.js +205 -118
  61. package/dist/docx/fontTableParser.js +102 -41
  62. package/dist/docx/footnoteParser.js +10 -6
  63. package/dist/docx/groupDrawingParser.js +4 -3
  64. package/dist/docx/headerFooterReferenceNormalization.js +1 -1
  65. package/dist/docx/hyperlinkParser.d.ts +45 -7
  66. package/dist/docx/hyperlinkParser.js +126 -57
  67. package/dist/docx/imageParser.js +127 -107
  68. package/dist/docx/index.d.ts +2 -1
  69. package/dist/docx/index.js +2 -1
  70. package/dist/docx/inlineContentRemovals.d.ts +28 -0
  71. package/dist/docx/inlineContentRemovals.js +46 -0
  72. package/dist/docx/inlineWrapperContent.d.ts +84 -3
  73. package/dist/docx/inlineWrapperContent.js +85 -4
  74. package/dist/docx/inlineWrapperParser.d.ts +11 -0
  75. package/dist/docx/inlineWrapperParser.js +60 -0
  76. package/dist/docx/nonVisualDrawingProps.d.ts +5 -13
  77. package/dist/docx/normalizeBaseDirection.js +4 -2
  78. package/dist/docx/numberingParser.d.ts +25 -2
  79. package/dist/docx/numberingParser.js +264 -361
  80. package/dist/docx/numberingReference.d.ts +9 -16
  81. package/dist/docx/numberingReference.js +17 -16
  82. package/dist/docx/numberingReferenceNormalization.js +7 -7
  83. package/dist/docx/ooxmlCounterFormatter.d.ts +1 -1
  84. package/dist/docx/ooxmlCounterFormatter.js +4 -1
  85. package/dist/docx/paraIdAttribute.d.ts +91 -1
  86. package/dist/docx/paraIdAttribute.js +79 -1
  87. package/dist/docx/paragraphParser.d.ts +9 -24
  88. package/dist/docx/paragraphParser.js +212 -396
  89. package/dist/docx/paragraphProperties.d.ts +23 -0
  90. package/dist/docx/paragraphProperties.js +279 -0
  91. package/dist/docx/paragraphPropertySource.js +2 -0
  92. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  93. package/dist/docx/paragraphTextBoxEnrichment.js +14 -7
  94. package/dist/docx/paragraphTraversal.d.ts +14 -10
  95. package/dist/docx/paragraphTraversal.js +47 -49
  96. package/dist/docx/parseWarningMessage.js +3 -0
  97. package/dist/docx/parserEnums.d.ts +6 -8
  98. package/dist/docx/parserEnums.js +4 -6
  99. package/dist/docx/preservedRunContent.js +16 -6
  100. package/dist/docx/previewBudget.d.ts +44 -23
  101. package/dist/docx/previewBudget.js +61 -30
  102. package/dist/docx/propertyElementAttributes.d.ts +178 -0
  103. package/dist/docx/propertyElementAttributes.js +114 -0
  104. package/dist/docx/renderedPageBreakNormalization.js +2 -2
  105. package/dist/docx/rezip.d.ts +28 -2
  106. package/dist/docx/rezip.js +78 -9
  107. package/dist/docx/runConsolidator.d.ts +42 -2
  108. package/dist/docx/runConsolidator.js +60 -6
  109. package/dist/docx/runParser.d.ts +54 -18
  110. package/dist/docx/runParser.js +379 -295
  111. package/dist/docx/runPayload.d.ts +5 -0
  112. package/dist/docx/runPayload.js +4 -0
  113. package/dist/docx/sdtProperties.d.ts +39 -5
  114. package/dist/docx/sdtProperties.js +205 -84
  115. package/dist/docx/sdtPropertiesPatch.d.ts +5 -9
  116. package/dist/docx/sdtPropertiesPatch.js +68 -112
  117. package/dist/docx/sectionParser.d.ts +1 -2
  118. package/dist/docx/sectionParser.js +236 -240
  119. package/dist/docx/selectiveSave.js +3 -2
  120. package/dist/docx/selectiveXmlPatch.d.ts +21 -2
  121. package/dist/docx/selectiveXmlPatch.js +195 -99
  122. package/dist/docx/serializer/blockSdtSerializer.js +2 -96
  123. package/dist/docx/serializer/borderSerializer.d.ts +5 -5
  124. package/dist/docx/serializer/borderSerializer.js +10 -8
  125. package/dist/docx/serializer/documentSerializer.js +3 -0
  126. package/dist/docx/serializer/fontTableSerializer.js +31 -3
  127. package/dist/docx/serializer/headerFooterSerializer.js +3 -0
  128. package/dist/docx/serializer/markupRangeAttributes.d.ts +9 -1
  129. package/dist/docx/serializer/markupRangeAttributes.js +9 -1
  130. package/dist/docx/serializer/noteSerializer.js +3 -0
  131. package/dist/docx/serializer/numberingSerializer.d.ts +1 -6
  132. package/dist/docx/serializer/numberingSerializer.js +81 -79
  133. package/dist/docx/serializer/paragraphSerializer.d.ts +1 -9
  134. package/dist/docx/serializer/paragraphSerializer.js +88 -188
  135. package/dist/docx/serializer/runSerializer.d.ts +1 -5
  136. package/dist/docx/serializer/runSerializer.js +109 -59
  137. package/dist/docx/serializer/sdtPropertiesSerializer.d.ts +26 -0
  138. package/dist/docx/serializer/sdtPropertiesSerializer.js +111 -0
  139. package/dist/docx/serializer/sectionPropertiesSerializer.js +34 -45
  140. package/dist/docx/serializer/settingsSerializer.js +6 -4
  141. package/dist/docx/serializer/stylesSerializer.js +8 -11
  142. package/dist/docx/serializer/tableSerializer.js +268 -100
  143. package/dist/docx/serializer/textFormattingSerializer.d.ts +28 -4
  144. package/dist/docx/serializer/textFormattingSerializer.js +111 -101
  145. package/dist/docx/serializer/xmlUtils.d.ts +1 -1
  146. package/dist/docx/serializer/xmlUtils.js +1 -1
  147. package/dist/docx/server/createBilingualDocument.js +18 -16
  148. package/dist/docx/server/migrateYjsAttrSchema.js +3 -3
  149. package/dist/docx/settingsParser.js +7 -4
  150. package/dist/docx/shadingParser.d.ts +2 -1
  151. package/dist/docx/shadingParser.js +43 -7
  152. package/dist/docx/shapeParser.js +8 -3
  153. package/dist/docx/strictNames.d.ts +11 -0
  154. package/dist/docx/strictNames.gen.d.ts +45 -0
  155. package/dist/docx/strictNames.gen.js +50 -0
  156. package/dist/docx/strictNames.js +43 -0
  157. package/dist/docx/strictValueEncodings.gen.js +133 -131
  158. package/dist/docx/styleParser.js +17 -349
  159. package/dist/docx/tableParser.d.ts +10 -1
  160. package/dist/docx/tableParser.js +505 -181
  161. package/dist/docx/textBoxParser.d.ts +3 -1
  162. package/dist/docx/textBoxParser.js +18 -8
  163. package/dist/docx/themeColorAttribute.d.ts +13 -0
  164. package/dist/docx/themeColorAttribute.js +24 -0
  165. package/dist/docx/trackedMoveRangeNormalization.js +2 -1
  166. package/dist/docx/vmlImageParser.d.ts +13 -4
  167. package/dist/docx/vmlImageParser.js +74 -31
  168. package/dist/docx/vmlPreview.js +2 -2
  169. package/dist/docx/wrapPolygon.d.ts +30 -0
  170. package/dist/docx/wrapPolygon.js +70 -0
  171. package/dist/docx/xmlParser.d.ts +14 -1
  172. package/dist/docx/xmlParser.js +18 -2
  173. package/dist/fonts/embeddedFonts.js +3 -3
  174. package/dist/headless-layout.js +2 -0
  175. package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
  176. package/dist/i18n/messages/catalogs.gen.js +102 -34
  177. package/dist/i18n/messages/messages.gen.d.ts +4 -0
  178. package/dist/internal/headlessRevisionResolution.js +9 -0
  179. package/dist/internal/pageBreakRunSourceDescendantIndex.js +3 -1
  180. package/dist/internal/paragraphFormattingSerialization.d.ts +20 -9
  181. package/dist/internal/paragraphFormattingSerialization.js +118 -83
  182. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  183. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  184. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  185. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  186. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +17 -12
  187. package/dist/layout-bridge/convert/toFlowBlocks.js +177 -101
  188. package/dist/layout-engine/index.d.ts +2 -2
  189. package/dist/layout-engine/index.js +53 -17
  190. package/dist/layout-engine/measure/measureBlocks.d.ts +3 -0
  191. package/dist/layout-engine/measure/measureBlocks.js +6 -10
  192. package/dist/layout-engine/measure/tableCellGrid.js +2 -1
  193. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
  194. package/dist/layout-engine/measure/tableInlinePlacement.js +2 -5
  195. package/dist/layout-engine/paragraphSequence.js +3 -2
  196. package/dist/layout-engine/renderedBreakReconciliation.js +2 -1
  197. package/dist/layout-engine/section-breaks.d.ts +49 -2
  198. package/dist/layout-engine/section-breaks.js +55 -4
  199. package/dist/layout-engine/types.d.ts +47 -17
  200. package/dist/layout-engine/types.js +16 -1
  201. package/dist/layout-painter/borderStroke.d.ts +18 -4
  202. package/dist/layout-painter/renderPage.js +6 -4
  203. package/dist/layout-painter/renderParagraph.d.ts +2 -1
  204. package/dist/layout-painter/renderParagraph.js +13 -26
  205. package/dist/layout-painter/renderTable.d.ts +4 -1
  206. package/dist/layout-painter/renderTable.js +22 -22
  207. package/dist/layout-painter/renderTextBox.js +5 -3
  208. package/dist/markdown/renderBlock.js +3 -1
  209. package/dist/markdown/renderRuns.js +7 -2
  210. package/dist/markdown/renderTable.js +2 -1
  211. package/dist/model.d.ts +3 -3
  212. package/dist/model.js +2 -2
  213. package/dist/paged-layout/sectionBlockWidths.d.ts +3 -0
  214. package/dist/paged-layout/sectionBlockWidths.js +26 -4
  215. package/dist/prosemirror/attrs/index.d.ts +22 -4
  216. package/dist/prosemirror/attrs/index.js +498 -60
  217. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +9 -1
  218. package/dist/prosemirror/bookmarkBoundaryAttrs.js +22 -3
  219. package/dist/prosemirror/commands/comments.js +68 -53
  220. package/dist/prosemirror/commands/contentControls.js +24 -19
  221. package/dist/prosemirror/commands/image.d.ts +1 -1
  222. package/dist/prosemirror/commands/image.js +4 -1
  223. package/dist/prosemirror/commands/paragraph.d.ts +2 -1
  224. package/dist/prosemirror/commands/propertyChangeScope.d.ts +12 -4
  225. package/dist/prosemirror/commands/propertyChangeScope.js +22 -4
  226. package/dist/prosemirror/commands/sectionBreak.d.ts +33 -1
  227. package/dist/prosemirror/commands/sectionBreak.js +187 -11
  228. package/dist/prosemirror/conversion/fromProseDoc.d.ts +18 -2
  229. package/dist/prosemirror/conversion/fromProseDoc.js +330 -183
  230. package/dist/prosemirror/conversion/index.d.ts +2 -2
  231. package/dist/prosemirror/conversion/preservedSinkCarriers.d.ts +39 -0
  232. package/dist/prosemirror/conversion/preservedSinkCarriers.js +19 -0
  233. package/dist/prosemirror/conversion/runShadingMark.js +14 -1
  234. package/dist/prosemirror/conversion/sdtAttrs.d.ts +10 -1
  235. package/dist/prosemirror/conversion/sdtAttrs.js +19 -5
  236. package/dist/prosemirror/conversion/toProseDoc.js +371 -141
  237. package/dist/prosemirror/emptyRangeAnchor.d.ts +53 -0
  238. package/dist/prosemirror/emptyRangeAnchor.js +158 -0
  239. package/dist/prosemirror/extensions/StarterKit.js +8 -2
  240. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  241. package/dist/prosemirror/extensions/core/ParagraphExtension.js +19 -15
  242. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +3 -2
  243. package/dist/prosemirror/extensions/features/ListExtension.js +43 -24
  244. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +4 -3
  245. package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +3 -3
  246. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +5 -5
  247. package/dist/prosemirror/extensions/features/pasteCleanup.d.ts +3 -1
  248. package/dist/prosemirror/extensions/features/pasteCleanup.js +56 -2
  249. package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +5 -4
  250. package/dist/prosemirror/extensions/markRegistry.d.ts +26 -2
  251. package/dist/prosemirror/extensions/markRegistry.js +73 -10
  252. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +17 -3
  253. package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +26 -0
  254. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +134 -0
  255. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -1
  256. package/dist/prosemirror/extensions/marks/UnderlineExtension.js +12 -18
  257. package/dist/prosemirror/extensions/marks/markUtils.js +2 -1
  258. package/dist/prosemirror/extensions/nodes/BlockBookmarkBoundaryExtension.d.ts +29 -0
  259. package/dist/prosemirror/extensions/nodes/BlockBookmarkBoundaryExtension.js +46 -0
  260. package/dist/prosemirror/extensions/nodes/BlockSdtExtension.d.ts +4 -3
  261. package/dist/prosemirror/extensions/nodes/BlockSdtExtension.js +18 -13
  262. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +28 -53
  263. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +10 -0
  264. package/dist/prosemirror/extensions/nodes/ImageExtension.js +8 -1
  265. package/dist/prosemirror/extensions/nodes/MoveRangeBoundaryExtension.d.ts +11 -0
  266. package/dist/prosemirror/extensions/nodes/MoveRangeBoundaryExtension.js +43 -0
  267. package/dist/prosemirror/extensions/nodes/RangeAnchorExtension.d.ts +13 -0
  268. package/dist/prosemirror/extensions/nodes/RangeAnchorExtension.js +65 -0
  269. package/dist/prosemirror/extensions/nodes/SdtExtension.d.ts +3 -1
  270. package/dist/prosemirror/extensions/nodes/SdtExtension.js +22 -16
  271. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +4 -0
  272. package/dist/prosemirror/extensions/nodes/TableExtension.js +141 -123
  273. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -0
  274. package/dist/prosemirror/extensions/nodes/bookmarkBoundaryDom.d.ts +23 -0
  275. package/dist/prosemirror/extensions/nodes/bookmarkBoundaryDom.js +57 -0
  276. package/dist/prosemirror/extensions/types.d.ts +12 -3
  277. package/dist/prosemirror/index.d.ts +4 -2
  278. package/dist/prosemirror/index.js +2 -1
  279. package/dist/prosemirror/inlineWrapperStack.js +20 -3
  280. package/dist/prosemirror/listMarker.d.ts +2 -2
  281. package/dist/prosemirror/listMarker.js +7 -8
  282. package/dist/prosemirror/listRenderingAttrs.js +11 -1
  283. package/dist/prosemirror/listState.d.ts +62 -0
  284. package/dist/prosemirror/listState.js +49 -0
  285. package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +13 -0
  286. package/dist/prosemirror/moveRangeBoundaryAttrs.js +114 -0
  287. package/dist/prosemirror/numberedRefFields.js +4 -4
  288. package/dist/prosemirror/numberingAttr.d.ts +55 -0
  289. package/dist/prosemirror/numberingAttr.js +74 -0
  290. package/dist/prosemirror/outlineLevelAttr.d.ts +29 -0
  291. package/dist/prosemirror/outlineLevelAttr.js +42 -0
  292. package/dist/prosemirror/paragraphFormattingProvenance.d.ts +9 -0
  293. package/dist/prosemirror/paragraphFormattingProvenance.js +4 -1
  294. package/dist/prosemirror/plugins/selectionTracker.d.ts +3 -6
  295. package/dist/prosemirror/plugins/selectionTracker.js +3 -10
  296. package/dist/prosemirror/rangeAnchorAttrs.d.ts +14 -0
  297. package/dist/prosemirror/rangeAnchorAttrs.js +101 -0
  298. package/dist/prosemirror/replacedAnnotations.d.ts +1 -1
  299. package/dist/prosemirror/replacedAnnotations.js +24 -6
  300. package/dist/prosemirror/revisionCarriers.d.ts +86 -2
  301. package/dist/prosemirror/revisionCarriers.js +86 -60
  302. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -0
  303. package/dist/prosemirror/runFormattingInlineCarriers.js +2 -0
  304. package/dist/prosemirror/runIdentity.d.ts +28 -0
  305. package/dist/prosemirror/runIdentity.js +36 -0
  306. package/dist/prosemirror/runStyleFormatting.js +1 -1
  307. package/dist/prosemirror/schema/index.d.ts +2 -2
  308. package/dist/prosemirror/schema/marks.d.ts +23 -4
  309. package/dist/prosemirror/schema/nodes.d.ts +220 -24
  310. package/dist/prosemirror/sectionCarrier.d.ts +37 -0
  311. package/dist/prosemirror/sectionCarrier.js +40 -0
  312. package/dist/prosemirror/selectionState.d.ts +3 -0
  313. package/dist/prosemirror/selectionState.js +4 -1
  314. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +5 -4
  315. package/dist/prosemirror/styles/resolvedStyleAttrs.js +15 -13
  316. package/dist/prosemirror/tableResize.js +5 -6
  317. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
  318. package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
  319. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +10 -11
  320. package/dist/prosemirror/utils/extractTrackedChanges.js +109 -92
  321. package/dist/prosemirror/validation.js +17 -6
  322. package/dist/prosemirror/yjsDocumentMetadata.d.ts +2 -2
  323. package/dist/prosemirror/yjsDocumentMetadata.js +428 -7
  324. package/dist/prosemirror/zeroWidthAnchors.js +4 -0
  325. package/dist/style-sets/extract.js +4 -4
  326. package/dist/style-sets/stellaStyle.js +36 -23
  327. package/dist/types/colors.d.ts +2 -2
  328. package/dist/types/content.d.ts +2 -2
  329. package/dist/types/documentEnumValues.d.ts +53 -26
  330. package/dist/types/documentEnumValues.js +72 -174
  331. package/dist/types/formatting.d.ts +2 -2
  332. package/dist/types/index.d.ts +9 -2
  333. package/dist/utils/borderCss.d.ts +246 -0
  334. package/dist/utils/borderCss.js +325 -0
  335. package/dist/utils/colorResolver.d.ts +4 -3
  336. package/dist/utils/colorResolver.js +45 -76
  337. package/dist/utils/createDocument.js +24 -6
  338. package/dist/utils/findReplace.js +52 -10
  339. package/dist/utils/formatToStyle.d.ts +84 -2
  340. package/dist/utils/formatToStyle.js +133 -52
  341. package/dist/utils/headingCollector.js +3 -2
  342. package/dist/utils/mergeDocumentContent.js +5 -3
  343. package/dist/utils/paragraphFormattingMerge.js +27 -6
  344. package/dist/utils/replaceText.js +1 -1
  345. package/dist/utils/tableOperations.d.ts +5 -3
  346. package/dist/utils/tableOperations.js +14 -1
  347. package/dist/utils/tablePlacement.d.ts +7 -0
  348. package/dist/utils/tablePlacement.js +14 -0
  349. package/dist/utils/textDirectionFlow.d.ts +15 -0
  350. package/dist/utils/textDirectionFlow.js +38 -0
  351. package/dist/utils/textFormattingMerge.js +16 -4
  352. package/package.json +10 -10
  353. package/dist/ai-edits/__fixtures__/paragraphs.d.ts +0 -17
  354. package/dist/ai-edits/__fixtures__/paragraphs.js +0 -33
  355. package/dist/compare/__fixtures__/body-sequence.d.ts +0 -119
  356. package/dist/compare/__fixtures__/body-sequence.js +0 -225
  357. package/dist/compare/__fixtures__/nested-table.d.ts +0 -16
  358. package/dist/compare/__fixtures__/nested-table.js +0 -50
  359. package/dist/compare/__fixtures__/numbered-list.d.ts +0 -34
  360. package/dist/compare/__fixtures__/numbered-list.js +0 -85
  361. package/dist/docx/bookmarkPlacement.d.ts +0 -9
  362. package/dist/docx/bookmarkPlacement.js +0 -52
  363. package/dist/fonts/embeddedFontTable.d.ts +0 -45
  364. package/dist/fonts/embeddedFontTable.js +0 -80
  365. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +0 -13
  366. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +0 -39
@@ -1,4 +1,5 @@
1
1
  import { patchBreaksCommentRangeBalance } from "./commentRangeIntegrity.js";
2
+ import { resolveParagraphIdentities } from "./paraIdAttribute.js";
2
3
  import { captureVerbatimXml } from "./verbatimCapture.js";
3
4
  import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findAttributeByNamespaceUri, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, parseXmlDocument } from "./xmlParser.js";
4
5
  //#region src/docx/selectiveXmlPatch.ts
@@ -95,24 +96,43 @@ function extractParagraphXml(serializedXml, paraId) {
95
96
  function buildParagraphOffsetIndex(xml) {
96
97
  const seenCount = /* @__PURE__ */ new Map();
97
98
  const ranges = /* @__PURE__ */ new Map();
98
- const stack = [];
99
- let pos = 0;
100
- const noteOpen = (paraId) => {
101
- if (paraId) seenCount.set(paraId, (seenCount.get(paraId) ?? 0) + 1);
102
- };
103
- const noteRange = (paraId, start, end) => {
104
- if (paraId) ranges.set(paraId, {
99
+ for (const { start, end, paraId } of scanParagraphs(xml)) {
100
+ if (paraId === void 0) continue;
101
+ seenCount.set(paraId, (seenCount.get(paraId) ?? 0) + 1);
102
+ if (end > start) ranges.set(paraId, {
105
103
  start,
106
104
  end
107
105
  });
108
- };
106
+ }
107
+ const index = /* @__PURE__ */ new Map();
108
+ for (const [id, range] of ranges) if (seenCount.get(id) === 1) index.set(id, range);
109
+ return index;
110
+ }
111
+ /**
112
+ * Every `<w:p>` element of `xml`, in the document order of its opening tags,
113
+ * with the `w14:paraId` that tag carries.
114
+ *
115
+ * Document order is what makes the array an ordinal space: the *n*th entry of
116
+ * the source part and the *n*th entry of the model's serialization name the
117
+ * same paragraph, which is the only way to address a paragraph the producer
118
+ * gave no id. A `<w:p>` nested inside another (inside `mc:AlternateContent`,
119
+ * a text box) is one entry of its own, exactly as
120
+ * {@link countParagraphElements} counts it, so the two never disagree about
121
+ * what an ordinal is. An unterminated paragraph keeps `end === start`: it
122
+ * occupies its ordinal but no splice can be built from it.
123
+ */
124
+ function scanParagraphs(xml) {
125
+ const paragraphs = [];
126
+ const open = [];
127
+ let pos = 0;
109
128
  while (pos < xml.length) {
110
129
  const tagStart = xml.indexOf("<", pos);
111
130
  if (tagStart === -1) break;
112
131
  if (xml.startsWith("</w:p>", tagStart)) {
113
- const frame = stack.pop();
132
+ const slot = open.pop();
114
133
  const end = tagStart + 6;
115
- if (frame) noteRange(frame.paraId, frame.start, end);
134
+ const paragraph = slot === void 0 ? void 0 : paragraphs[slot];
135
+ if (paragraph) paragraph.end = end;
116
136
  pos = end;
117
137
  continue;
118
138
  }
@@ -123,18 +143,23 @@ function buildParagraphOffsetIndex(xml) {
123
143
  const tagEnd = xml.indexOf(">", tagStart);
124
144
  if (tagEnd === -1) break;
125
145
  const openTag = xml.slice(tagStart, tagEnd + 1);
126
- const paraId = /\bw14:paraId="(?<id>[^"]*)"/u.exec(openTag)?.groups?.["id"];
127
- noteOpen(paraId);
128
- if (xml[tagEnd - 1] === "/") noteRange(paraId, tagStart, tagEnd + 1);
129
- else stack.push({
146
+ const paraId = /\bw14:paraId="(?<id>[^"]+)"/u.exec(openTag)?.groups?.["id"];
147
+ if (xml[tagEnd - 1] === "/") paragraphs.push({
130
148
  start: tagStart,
149
+ end: tagEnd + 1,
131
150
  paraId
132
151
  });
152
+ else {
153
+ open.push(paragraphs.length);
154
+ paragraphs.push({
155
+ start: tagStart,
156
+ end: tagStart,
157
+ paraId
158
+ });
159
+ }
133
160
  pos = tagEnd + 1;
134
161
  }
135
- const index = /* @__PURE__ */ new Map();
136
- for (const [id, range] of ranges) if (seenCount.get(id) === 1) index.set(id, range);
137
- return index;
162
+ return paragraphs;
138
163
  }
139
164
  /**
140
165
  * Count <w:p> elements in an XML string (top-level paragraph count).
@@ -163,40 +188,140 @@ function collectParaIds(xml) {
163
188
  }
164
189
  return ids;
165
190
  }
191
+ /** Paragraph ids folio writes and this module may have to remove again. */
192
+ const MINTED_PARA_ID_ATTRIBUTE = /\sw14:(?:para|text)Id="[^"]*"/gu;
166
193
  /**
167
- * Validate that a selective patch can be safely applied.
194
+ * The replacement for a paragraph whose source open tag carries no paraId.
168
195
  *
169
- * Checks:
170
- * - All changed paraIds exist in original XML (exactly once)
171
- * - All changed paraIds exist in serialized XML (exactly once)
172
- * - Paragraph count matches between original and serialized (unless disabled)
196
+ * The model always has a key, because folio mints one for every paragraph that
197
+ * arrives without one, and the serializer writes whatever key the model holds.
198
+ * Writing a minted key into the package would upgrade a producer's id-less
199
+ * document to a partly-id'd one on any edit, declare a `w14` namespace the
200
+ * part never had, and turn an id the minter itself calls positional into an
201
+ * authored one the next reader trusts. So the save keeps the author's
202
+ * convention: `ensureParaIds` is the one pass that gives a package ids, and it
203
+ * runs when a host asks for it. An id the source *does* carry (a `w14:textId`
204
+ * beside no paraId) is the author's and stays.
173
205
  */
174
- function validatePatchSafety(originalXml, serializedXml, changedIds, options = {}) {
175
- if (changedIds.size === 0) return { safe: true };
206
+ const withoutMintedIds = (paragraphXml, sourceOpenTag) => {
207
+ const tagEnd = paragraphXml.indexOf(">");
208
+ if (tagEnd === -1) return paragraphXml;
209
+ return paragraphXml.slice(0, tagEnd + 1).replace(MINTED_PARA_ID_ATTRIBUTE, (attribute) => sourceOpenTag.includes(attribute.trim()) ? attribute : "") + paragraphXml.slice(tagEnd + 1);
210
+ };
211
+ /**
212
+ * Route every changed paragraph from the model's serialization to its region
213
+ * of the source part.
214
+ *
215
+ * One owner for the question the patch turns on: *which paragraph of the file
216
+ * is this model paragraph?* {@link resolveParagraphIdentities} answers it per
217
+ * paragraph, and the union is consumed exhaustively here, so a paragraph the
218
+ * source names by id keeps the id lookup — robust to any reordering — and one
219
+ * the source never named falls back to its ordinal, which is sound exactly
220
+ * when the identity plan says the two sequences line up. A package with ids on
221
+ * some paragraphs and not others therefore needs no special case: its authored
222
+ * ids are the witnesses that prove the ordinals for the rest.
223
+ */
224
+ const routeChangedParagraphs = (originalXml, serializedXml, changedIds) => {
225
+ const original = scanParagraphs(originalXml);
226
+ const serialized = scanParagraphs(serializedXml);
227
+ const { identities, ordinalsAligned } = resolveParagraphIdentities({
228
+ sourceParaIds: original.map(({ paraId }) => paraId),
229
+ serializedParaIds: serialized.map(({ paraId }) => paraId)
230
+ });
176
231
  const originalParaIds = collectParaIds(originalXml);
177
232
  const serializedParaIds = collectParaIds(serializedXml);
233
+ const identityByParaId = /* @__PURE__ */ new Map();
234
+ for (const identity of identities) if (identity.type !== "anonymous" && serializedParaIds.get(identity.paraId) === 1) identityByParaId.set(identity.paraId, identity);
235
+ const splices = [];
178
236
  for (const id of changedIds) {
179
- const origCount = originalParaIds.get(id) || 0;
180
- if (origCount === 0) return {
181
- safe: false,
182
- reason: `paraId-not-found-in-original: ${id}`
183
- };
184
- if (origCount > 1) return {
185
- safe: false,
237
+ const originalCount = originalParaIds.get(id) ?? 0;
238
+ if (originalCount > 1) return {
239
+ type: "refused",
186
240
  reason: `duplicate-paraId-in-original: ${id}`
187
241
  };
188
- }
189
- for (const id of changedIds) {
190
- const serCount = serializedParaIds.get(id) || 0;
191
- if (serCount === 0) return {
192
- safe: false,
242
+ const serializedCount = serializedParaIds.get(id) ?? 0;
243
+ if (originalCount === 1 && serializedCount === 0) return {
244
+ type: "refused",
193
245
  reason: `paraId-not-found-in-serialized: ${id}`
194
246
  };
195
- if (serCount > 1) return {
196
- safe: false,
247
+ if (serializedCount === 0) return {
248
+ type: "refused",
249
+ reason: `paraId-not-found-in-original: ${id}`
250
+ };
251
+ if (serializedCount > 1) return {
252
+ type: "refused",
197
253
  reason: `duplicate-paraId-in-serialized: ${id}`
198
254
  };
255
+ const identity = identityByParaId.get(id);
256
+ if (!identity) return {
257
+ type: "refused",
258
+ reason: `paraId-not-found-in-serialized: ${id}`
259
+ };
260
+ const replacement = serialized[identity.ordinal];
261
+ if (!replacement || replacement.end <= replacement.start) return {
262
+ type: "refused",
263
+ reason: `unterminated-paragraph: ${id}`
264
+ };
265
+ const newXml = serializedXml.slice(replacement.start, replacement.end);
266
+ switch (identity.type) {
267
+ case "authored": {
268
+ const offsets = findParagraphOffsets(originalXml, identity.paraId);
269
+ if (!offsets) return {
270
+ type: "refused",
271
+ reason: `paraId-not-found-in-original: ${id}`
272
+ };
273
+ splices.push({
274
+ start: offsets.start,
275
+ end: offsets.end,
276
+ newXml
277
+ });
278
+ break;
279
+ }
280
+ case "minted": {
281
+ if (!ordinalsAligned) return {
282
+ type: "refused",
283
+ reason: `unaligned-paragraph-ordinals: ${id}`
284
+ };
285
+ const source = original[identity.ordinal];
286
+ if (!source || source.end <= source.start) return {
287
+ type: "refused",
288
+ reason: `paraId-not-found-in-original: ${id}`
289
+ };
290
+ splices.push({
291
+ start: source.start,
292
+ end: source.end,
293
+ newXml: withoutMintedIds(newXml, originalXml.slice(source.start, source.end))
294
+ });
295
+ break;
296
+ }
297
+ case "anonymous": return {
298
+ type: "refused",
299
+ reason: `paraId-not-found-in-serialized: ${id}`
300
+ };
301
+ default: return identity;
302
+ }
199
303
  }
304
+ return {
305
+ type: "routed",
306
+ splices
307
+ };
308
+ };
309
+ /**
310
+ * Validate that a selective patch can be safely applied.
311
+ *
312
+ * Checks:
313
+ * - Every changed paraId routes to one region of the original XML, by its
314
+ * authored id or, when the producer wrote none, by its paragraph ordinal
315
+ * - All changed paraIds exist in serialized XML (exactly once)
316
+ * - Paragraph count matches between original and serialized (unless disabled)
317
+ */
318
+ function validatePatchSafety(originalXml, serializedXml, changedIds, options = {}) {
319
+ if (changedIds.size === 0) return { safe: true };
320
+ const routing = routeChangedParagraphs(originalXml, serializedXml, changedIds);
321
+ if (routing.type === "refused") return {
322
+ safe: false,
323
+ reason: routing.reason
324
+ };
200
325
  if (options.checkParagraphCount === false) return { safe: true };
201
326
  const originalCount = countParagraphElements(originalXml);
202
327
  const serializedCount = countParagraphElements(serializedXml);
@@ -261,19 +386,8 @@ const spliceXml = (xml, splices) => {
261
386
  * repack, whose parts are all re-serialized from one model.
262
387
  */
263
388
  function spliceChangedParagraphs(originalXml, serializedXml, changedIds) {
264
- const replacements = [];
265
- for (const paraId of changedIds) {
266
- const origOffsets = findParagraphOffsets(originalXml, paraId);
267
- if (!origOffsets) return null;
268
- const newXml = extractParagraphXml(serializedXml, paraId);
269
- if (!newXml) return null;
270
- replacements.push({
271
- start: origOffsets.start,
272
- end: origOffsets.end,
273
- newXml
274
- });
275
- }
276
- return spliceXml(originalXml, replacements);
389
+ const routing = routeChangedParagraphs(originalXml, serializedXml, changedIds);
390
+ return routing.type === "refused" ? null : spliceXml(originalXml, routing.splices);
277
391
  }
278
392
  /**
279
393
  * Depth-count the end of the element that opens at `start` (an `<openLiteral…>`
@@ -616,7 +730,7 @@ function buildNumberingElementOffsetIndex(xml, kind) {
616
730
  }
617
731
  return index;
618
732
  }
619
- const SYNTHETIC_NUM_FMT_PATTERN = /<w:numFmt w:val="decimalZero(?<width>[345])"\/>/u;
733
+ const CUSTOM_NUM_FMT_PATTERN = /<w:numFmt w:val="custom"(?: w:format="(?<format>[^"]*)")?\/>/u;
620
734
  /**
621
735
  * The numbering definitions whose current serialization differs from the
622
736
  * baseline (re-parsed original) serialization — the ones actually edited. An id
@@ -653,30 +767,15 @@ function extractLevelNumFmtElement(levelXml) {
653
767
  return match ? match[0] : null;
654
768
  }
655
769
  /**
656
- * A valid OOXML custom number format equivalent to a `decimalZero{width}`
657
- * synthetic value: a zero-padded first token folio's parser reads back to the
658
- * same width. Used only when the original element cannot be resolved, so a
659
- * changed definition never emits a non-OOXML synthetic value.
770
+ * The `@w:format` an original level's number-format element declares, or null
771
+ * when it declares no custom format at all. Telling a preserved format from an
772
+ * edited one is what keeps a genuine change from being reverted.
660
773
  */
661
- function reconstructCustomNumFmt(width) {
662
- return `<w:numFmt w:val="custom" w:format="${`${"0".repeat(Number.parseInt(width, 10) - 1)}1`}"/>`;
663
- }
664
- /**
665
- * The synthetic `decimalZero{width}` width the parser would derive from an
666
- * original level's number-format element (its custom `w:format` first token),
667
- * as the same digit-count string the SYNTHETIC_NUM_FMT_PATTERN captures. Mirrors
668
- * `parseCustomNumberFormat` (first comma-separated token, `^0+1$`, clamped to 5).
669
- * Returns null when the element carries no zero-padded custom format, so a
670
- * genuine format change is never mistaken for the original.
671
- */
672
- function originalNumFmtWidth(numFmtElement) {
774
+ function originalCustomNumFmtFormat(numFmtElement) {
673
775
  for (const match of numFmtElement.matchAll(/<w:numFmt\b[^>]*\/>/gu)) {
674
776
  const tag = match[0];
675
777
  if (!/\bw:val="custom"/u.test(tag)) continue;
676
- const format = /\bw:format="(?<format>[^"]*)"/u.exec(tag)?.groups?.["format"];
677
- if (format === void 0) continue;
678
- const firstToken = format.split(",")[0]?.trim() ?? "";
679
- return /^0+1$/u.test(firstToken) ? String(Math.min(firstToken.length, 5)) : null;
778
+ return /\bw:format="(?<format>[^"]*)"/u.exec(tag)?.groups?.["format"] ?? null;
680
779
  }
681
780
  return null;
682
781
  }
@@ -709,21 +808,19 @@ function withXmlnsDeclarations(fragmentXml, xmlnsDecls) {
709
808
  return fragmentXml.slice(0, nameEnd) + additions.join("") + fragmentXml.slice(nameEnd);
710
809
  }
711
810
  /**
712
- * Swap each synthetic `decimalZero{3,4,5}` numFmt in a re-serialized definition
713
- * back to the original level's number-format element.
811
+ * Swap each re-serialized custom numFmt back to the original level's
812
+ * number-format element.
714
813
  *
715
- * folio's parser collapses a Word custom / mc:AlternateContent number format
716
- * into a synthetic `decimalZero{3,4,5}` value the model cannot re-emit as valid
717
- * OOXML. When an unrelated field of the definition is edited, the whole
718
- * definition is re-serialized, so without this pass the level's custom format
719
- * would be replaced by an invalid value and lost on reparse. For each level
720
- * whose re-emitted numFmt is synthetic, restore the original level's numFmt
721
- * element by ilvl ONLY when the model's synthetic value still matches the
722
- * original's (the format was not edited, just preserved past an unrelated
723
- * change). When the model deliberately changed the width (e.g. decimalZero4 ->
724
- * decimalZero5), or the original cannot be resolved, emit a valid OOXML custom
725
- * format for the CURRENT width instead — honoring the edit and never leaving a
726
- * synthetic value.
814
+ * The model holds a custom format as `custom` plus its `@w:format`, which the
815
+ * serializer re-emits as a bare `<w:numFmt w:val="custom" w:format="…"/>`. That
816
+ * is valid OOXML and reparses to the same model, but it is not what the source
817
+ * wrote: Word wraps a custom format in an `mc:AlternateContent` whose Fallback
818
+ * carries a plain format for pre-w14 readers, and the model has no field for
819
+ * the Fallback. When an unrelated field of the definition is edited the whole
820
+ * definition is re-serialized, so without this pass that wrapper would be
821
+ * flattened away. Restore it by ilvl only when the model's format still matches
822
+ * the original's; a level whose format was actually edited keeps the model's
823
+ * own element, which is the edit.
727
824
  */
728
825
  function restoreLevelNumFmts(originalDefXml, currentDefXml) {
729
826
  const replacements = [];
@@ -732,21 +829,20 @@ function restoreLevelNumFmts(originalDefXml, currentDefXml) {
732
829
  const curOffsets = findElementByIdAttr(currentDefXml, LEVEL_OPEN_LITERAL, LEVEL_CLOSE_TAG, LEVEL_ID_ATTR, ilvl);
733
830
  if (!curOffsets) continue;
734
831
  const curLevel = currentDefXml.slice(curOffsets.start, curOffsets.end);
735
- const synthetic = SYNTHETIC_NUM_FMT_PATTERN.exec(curLevel);
736
- if (!synthetic) continue;
832
+ const custom = CUSTOM_NUM_FMT_PATTERN.exec(curLevel);
833
+ if (!custom) continue;
737
834
  const origLevel = extractElementByIdAttr(originalDefXml, LEVEL_OPEN_LITERAL, LEVEL_CLOSE_TAG, LEVEL_ID_ATTR, ilvl);
738
- const currentWidth = synthetic.groups["width"];
835
+ const currentFormat = custom.groups?.["format"] ?? null;
739
836
  const original = origLevel ? extractLevelNumFmtElement(origLevel) : null;
740
- let replacement;
741
- if (original && origLevel && originalNumFmtWidth(original) === currentWidth) replacement = withXmlnsDeclarations(original, {
837
+ if (!original || !origLevel || originalCustomNumFmtFormat(original) !== currentFormat) continue;
838
+ const ancestorXmlns = {
742
839
  ...collectXmlnsFromOpeningTag(originalDefXml),
743
840
  ...collectXmlnsFromOpeningTag(origLevel)
744
- });
745
- else replacement = reconstructCustomNumFmt(currentWidth);
841
+ };
746
842
  const restoredLevel = spliceXml(curLevel, [{
747
- start: synthetic.index,
748
- end: synthetic.index + synthetic[0].length,
749
- newXml: replacement
843
+ start: custom.index,
844
+ end: custom.index + custom[0].length,
845
+ newXml: withXmlnsDeclarations(original, ancestorXmlns)
750
846
  }]);
751
847
  if (restoredLevel === null) continue;
752
848
  replacements.push({
@@ -898,12 +994,12 @@ function appendNumberingDefs(xml, currentXml, added) {
898
994
  return head + abstractXmls.join("") + middle + numXmls.join("") + tail;
899
995
  }
900
996
  /**
901
- * For an added abstract definition that still carries a synthetic numFmt, find
997
+ * For an added abstract definition that carries a flattened custom numFmt, find
902
998
  * the original abstract it was cloned from (same serialized body apart from the
903
999
  * id) and restore the level formats from it.
904
1000
  */
905
1001
  function restoreClonedLevelNumFmts(originalXml, currentXml, addedDefXml, addedId) {
906
- if (!SYNTHETIC_NUM_FMT_PATTERN.test(addedDefXml)) return addedDefXml;
1002
+ if (!CUSTOM_NUM_FMT_PATTERN.test(addedDefXml)) return addedDefXml;
907
1003
  const addedBody = stripAbstractNumId(addedDefXml, addedId);
908
1004
  const originalIds = collectElementIds(originalXml, NUMBERING_OPEN_LITERAL.abstractNum, NUMBERING_ID_ATTR.abstractNum);
909
1005
  for (const [id] of originalIds) {
@@ -919,4 +1015,4 @@ function escapeRegExp(str) {
919
1015
  return str.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
920
1016
  }
921
1017
  //#endregion
922
- export { appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNotePartXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, patchNumberingDefinitions, spliceXml, validatePatchSafety };
1018
+ export { appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNotePartXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, patchNumberingDefinitions, scanParagraphs, spliceXml, validatePatchSafety };
@@ -1,102 +1,8 @@
1
- import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
2
- import { isSingleWellFormedElement } from "./xmlUtils.js";
3
- import { escapeXmlAttribute } from "@stll/docx-core";
1
+ import { serializeSdtWrapper } from "./sdtPropertiesSerializer.js";
4
2
  //#region src/docx/serializer/blockSdtSerializer.ts
5
- /**
6
- * Block-level SDT serializer.
7
- *
8
- * Replays `<w:sdtPr>` (and `<w:sdtEndPr>` when present) verbatim from the
9
- * `rawPropertiesXml` / `rawEndPropertiesXml` strings captured by the parser.
10
- * That keeps OOXML element order intact (`CT_SdtPr` is an `xsd:sequence`,
11
- * ECMA-376 §17.5.2) and round-trips unmodeled features — `w:dataBinding`,
12
- * `w15:repeatingSection`, `@lastValue`, custom XML mappings — without us
13
- * having to enumerate them.
14
- *
15
- * If a `BlockSdt` was constructed programmatically (no parsed snapshot to
16
- * replay), fall back to a minimal projection from the modeled fields so the
17
- * result is still a valid `<w:sdt>`.
18
- *
19
- * Sharing the helper between the document body and the header/footer
20
- * serializers keeps body↔HF parity in one place.
21
- */
22
- function serializeFallbackSdtPr(props) {
23
- const parts = [];
24
- if (props.id !== void 0) parts.push(`<w:id w:val="${props.id}"/>`);
25
- if (props.alias) parts.push(`<w:alias w:val="${escapeXmlAttribute(props.alias)}"/>`);
26
- if (props.tag) parts.push(`<w:tag w:val="${escapeXmlAttribute(props.tag)}"/>`);
27
- if (props.lock) parts.push(`<w:lock w:val="${props.lock}"/>`);
28
- if (props.placeholder) parts.push(`<w:placeholder><w:docPart w:val="${escapeXmlAttribute(props.placeholder)}"/></w:placeholder>`);
29
- if (props.showingPlaceholder) parts.push("<w:showingPlcHdr/>");
30
- switch (props.sdtType) {
31
- case "plainText":
32
- parts.push("<w:text/>");
33
- break;
34
- case "date": {
35
- const fullDateAttr = props.dateValueISO ? ` w:fullDate="${escapeXmlAttribute(props.dateValueISO)}"` : "";
36
- const formatChild = props.dateFormat ? `<w:dateFormat w:val="${escapeXmlAttribute(props.dateFormat)}"/>` : "";
37
- if (fullDateAttr || formatChild) parts.push(`<w:date${fullDateAttr}>${formatChild}</w:date>`);
38
- else parts.push("<w:date/>");
39
- break;
40
- }
41
- case "dropdown":
42
- case "comboBox": {
43
- const tag = props.sdtType === "dropdown" ? "w:dropDownList" : "w:comboBox";
44
- const items = (props.listItems ?? []).map((item) => `<w:listItem w:displayText="${escapeXmlAttribute(item.displayText)}" w:value="${escapeXmlAttribute(item.value)}"/>`).join("");
45
- parts.push(`<${tag}>${items}</${tag}>`);
46
- break;
47
- }
48
- case "checkbox": {
49
- const val = props.checked ? "1" : "0";
50
- parts.push(`<w14:checkbox><w14:checked w14:val="${val}"/></w14:checkbox>`);
51
- break;
52
- }
53
- case "picture":
54
- parts.push("<w:picture/>");
55
- break;
56
- case "buildingBlockGallery":
57
- parts.push("<w:docPartObj/>");
58
- break;
59
- case "group":
60
- parts.push("<w:group/>");
61
- break;
62
- default: break;
63
- }
64
- return `<w:sdtPr>${parts.join("")}</w:sdtPr>`;
65
- }
66
- /**
67
- * `properties.dropdownLastValue` is the only record of what was selected.
68
- *
69
- * The XSD default of `@w:lastValue` is the empty string, so "never selected",
70
- * "cleared" and "selected" are three distinguishable states, and the body's
71
- * display text is evidence for none of them: it is equally the placeholder of
72
- * a dropdown nobody has touched, and a displayText shared by two list items
73
- * picks the wrong sibling. The parser records the authored `@w:lastValue` and
74
- * `setContentControlValue` records a pick; what neither wrote is no selection.
75
- *
76
- * `""` is a value a producer can author (`<w:listItem w:value=""/>`), so
77
- * presence is the test, not truthiness.
78
- */
79
- function extractDropdownLastValue(blockSdt) {
80
- if (blockSdt.properties.sdtType !== "dropdown" && blockSdt.properties.sdtType !== "comboBox") return;
81
- return blockSdt.properties.dropdownLastValue;
82
- }
83
- function extractDateFullDate(blockSdt) {
84
- if (blockSdt.properties.sdtType !== "date") return;
85
- const iso = blockSdt.properties.dateValueISO;
86
- return iso !== void 0 && iso.length > 0 ? iso : void 0;
87
- }
88
3
  function serializeBlockSdt(blockSdt, serializeChild) {
89
4
  const props = blockSdt.properties;
90
- const baseSdtPr = props.rawPropertiesXml && isSingleWellFormedElement(props.rawPropertiesXml, "sdtPr") ? props.rawPropertiesXml : serializeFallbackSdtPr(props);
91
- const dateFullDate = extractDateFullDate(blockSdt);
92
- const dropdownLastValue = extractDropdownLastValue(blockSdt);
93
- const sdtPrXml = reconcileRawSdtPr(baseSdtPr, props, {
94
- ...dateFullDate !== void 0 ? { dateFullDate } : {},
95
- ...dropdownLastValue !== void 0 ? { dropdownLastValue } : {}
96
- });
97
- const sdtEndPrXml = props.rawEndPropertiesXml && isSingleWellFormedElement(props.rawEndPropertiesXml, "sdtEndPr") ? props.rawEndPropertiesXml : "";
98
- const contentXml = blockSdt.content.map(serializeChild).join("");
99
- return `<w:sdt>${sdtPrXml}${sdtEndPrXml}${props.rawSdtChildrenBeforeContent ?? ""}<w:sdtContent>${contentXml}</w:sdtContent>${props.rawSdtChildrenAfterContent ?? ""}</w:sdt>`;
5
+ return serializeSdtWrapper(props, blockSdt.content.map(serializeChild).join(""));
100
6
  }
101
7
  //#endregion
102
8
  export { serializeBlockSdt };
@@ -1,6 +1,6 @@
1
1
  import { document_d_exports } from "../../types/document.js";
2
2
  //#region src/docx/serializer/borderSerializer.d.ts
3
- type ClassifiedBorderField = "style" | "color" | "size" | "space" | "shadow" | "frame" | "artRelationshipId" | "topLeftArtRelationshipId" | "topRightArtRelationshipId" | "bottomLeftArtRelationshipId" | "bottomRightArtRelationshipId";
3
+ type ClassifiedBorderField = "style" | "color" | "size" | "space" | "shadow" | "frame" | "artRelationshipId" | "topLeftArtRelationshipId" | "topRightArtRelationshipId" | "bottomLeftArtRelationshipId" | "bottomRightArtRelationshipId" | "preservedAttributes";
4
4
  type ExhaustiveBorder = document_d_exports.ExhaustiveFields<document_d_exports.BorderSpec, ClassifiedBorderField>;
5
5
  /**
6
6
  * Serialize a single border element (`<w:top .../>`, `<w:left .../>`, ...).
@@ -16,10 +16,10 @@ type ExhaustiveBorder = document_d_exports.ExhaustiveFields<document_d_exports.B
16
16
  * turned-off side; those are emitted when present so the value survives a
17
17
  * save→parse round-trip and is not otherwise added.
18
18
  *
19
- * `style` and the color values come straight from the parsed DOCX (the parser
20
- * casts `w:val`/`w:color` without validating the enum), so they are
21
- * untrusted and are `escapeXmlAttribute`'d before re-entering XML attributes; for valid
22
- * documents these are enum/hex values, so escaping is a no-op.
19
+ * An unrecognised `w:val` and the color values come straight from the parsed
20
+ * DOCX, so they are untrusted and are `escapeXmlAttribute`'d before re-entering
21
+ * XML attributes; for valid documents these are enum/hex values, so escaping is
22
+ * a no-op.
23
23
  */
24
24
  declare function serializeBorder(input: ExhaustiveBorder | undefined, elementName: string): string;
25
25
  //#endregion
@@ -1,5 +1,7 @@
1
+ import { serializePreservedAttributes } from "../attributeRemainder.js";
1
2
  import { intAttr } from "./xmlUtils.js";
2
3
  import { escapeXmlAttribute } from "@stll/docx-core";
4
+ import { borderStyleToken, themeColorToken } from "@stll/docx-core/model";
3
5
  //#region src/docx/serializer/borderSerializer.ts
4
6
  /**
5
7
  * Serialize a single border element (`<w:top .../>`, `<w:left .../>`, ...).
@@ -15,22 +17,22 @@ import { escapeXmlAttribute } from "@stll/docx-core";
15
17
  * turned-off side; those are emitted when present so the value survives a
16
18
  * save→parse round-trip and is not otherwise added.
17
19
  *
18
- * `style` and the color values come straight from the parsed DOCX (the parser
19
- * casts `w:val`/`w:color` without validating the enum), so they are
20
- * untrusted and are `escapeXmlAttribute`'d before re-entering XML attributes; for valid
21
- * documents these are enum/hex values, so escaping is a no-op.
20
+ * An unrecognised `w:val` and the color values come straight from the parsed
21
+ * DOCX, so they are untrusted and are `escapeXmlAttribute`'d before re-entering
22
+ * XML attributes; for valid documents these are enum/hex values, so escaping is
23
+ * a no-op.
22
24
  */
23
25
  function serializeBorder(input, elementName) {
24
26
  if (!input) return "";
25
- const { style, color, size, space, shadow, frame, artRelationshipId, topLeftArtRelationshipId, topRightArtRelationshipId, bottomLeftArtRelationshipId, bottomRightArtRelationshipId } = input;
26
- const attrs = [`w:val="${escapeXmlAttribute(style)}"`];
27
+ const { style, color, size, space, shadow, frame, artRelationshipId, topLeftArtRelationshipId, topRightArtRelationshipId, bottomLeftArtRelationshipId, bottomRightArtRelationshipId, preservedAttributes } = input;
28
+ const attrs = [`w:val="${escapeXmlAttribute(borderStyleToken(style))}"`];
27
29
  if (size !== void 0) attrs.push(`w:sz="${intAttr(size)}"`);
28
30
  if (space !== void 0) attrs.push(`w:space="${intAttr(space)}"`);
29
31
  if (color) {
30
32
  const { auto, rgb, themeColor, themeTint, themeShade } = color;
31
33
  if (auto) attrs.push("w:color=\"auto\"");
32
34
  else if (rgb) attrs.push(`w:color="${escapeXmlAttribute(rgb)}"`);
33
- if (themeColor) attrs.push(`w:themeColor="${escapeXmlAttribute(themeColor)}"`);
35
+ if (themeColor) attrs.push(`w:themeColor="${escapeXmlAttribute(themeColorToken(themeColor))}"`);
34
36
  if (themeTint) attrs.push(`w:themeTint="${escapeXmlAttribute(themeTint)}"`);
35
37
  if (themeShade) attrs.push(`w:themeShade="${escapeXmlAttribute(themeShade)}"`);
36
38
  }
@@ -41,7 +43,7 @@ function serializeBorder(input, elementName) {
41
43
  if (topRightArtRelationshipId) attrs.push(`r:topRight="${escapeXmlAttribute(topRightArtRelationshipId)}"`);
42
44
  if (bottomLeftArtRelationshipId) attrs.push(`r:bottomLeft="${escapeXmlAttribute(bottomLeftArtRelationshipId)}"`);
43
45
  if (bottomRightArtRelationshipId) attrs.push(`r:bottomRight="${escapeXmlAttribute(bottomRightArtRelationshipId)}"`);
44
- return `<w:${elementName} ${attrs.join(" ")}/>`;
46
+ return `<w:${elementName} ${serializePreservedAttributes(attrs, preservedAttributes).join(" ")}/>`;
45
47
  }
46
48
  //#endregion
47
49
  export { serializeBorder };
@@ -1,4 +1,5 @@
1
1
  import { serializeBlockSdt } from "./blockSdtSerializer.js";
2
+ import { serializeBookmarkMarker } from "./markupRangeAttributes.js";
2
3
  import { serializeParagraph } from "./paragraphSerializer.js";
3
4
  import { serializePartElement } from "./partNamespaces.js";
4
5
  import { resetAutoIdCounter } from "./runSerializer.js";
@@ -43,6 +44,8 @@ function serializeBlockContent(block) {
43
44
  case "table": return serializeTable(block, serializeParagraph);
44
45
  case "blockSdt": return serializeBlockSdt(block, serializeBlockContent);
45
46
  case "preservedBlock": return block.xml;
47
+ case "bookmarkStart":
48
+ case "bookmarkEnd": return serializeBookmarkMarker(block);
46
49
  default: return block;
47
50
  }
48
51
  }