@stll/folio-core 0.52.0 → 0.53.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 (307) hide show
  1. package/README.md +23 -0
  2. package/dist/ai-edits/apply.d.ts +26 -1
  3. package/dist/ai-edits/apply.js +1519 -105
  4. package/dist/ai-edits/batch-claims.d.ts +130 -0
  5. package/dist/ai-edits/batch-claims.js +244 -0
  6. package/dist/ai-edits/blockRange.js +9 -3
  7. package/dist/ai-edits/character-boundaries.d.ts +43 -0
  8. package/dist/ai-edits/character-boundaries.js +95 -0
  9. package/dist/ai-edits/clean-text.d.ts +33 -3
  10. package/dist/ai-edits/clean-text.js +52 -6
  11. package/dist/ai-edits/comment-lifecycle.d.ts +18 -0
  12. package/dist/ai-edits/comment-lifecycle.js +52 -0
  13. package/dist/ai-edits/headless.d.ts +71 -7
  14. package/dist/ai-edits/headless.js +381 -41
  15. package/dist/ai-edits/index.d.ts +2 -1
  16. package/dist/ai-edits/index.js +2 -1
  17. package/dist/ai-edits/minimal-replacement.d.ts +21 -6
  18. package/dist/ai-edits/minimal-replacement.js +134 -15
  19. package/dist/ai-edits/newListNumbering.d.ts +23 -0
  20. package/dist/ai-edits/newListNumbering.js +94 -0
  21. package/dist/ai-edits/note-references.d.ts +96 -0
  22. package/dist/ai-edits/note-references.js +139 -0
  23. package/dist/ai-edits/pending-suggestions.d.ts +79 -0
  24. package/dist/ai-edits/pending-suggestions.js +306 -0
  25. package/dist/ai-edits/read.d.ts +1 -1
  26. package/dist/ai-edits/read.js +56 -43
  27. package/dist/ai-edits/result-validation.d.ts +29 -0
  28. package/dist/ai-edits/result-validation.js +164 -0
  29. package/dist/ai-edits/snapshot.d.ts +36 -3
  30. package/dist/ai-edits/snapshot.js +177 -23
  31. package/dist/ai-edits/table-cell-mutations.d.ts +1 -1
  32. package/dist/ai-edits/table-cell-mutations.js +4 -1
  33. package/dist/ai-edits/table-geometry.d.ts +1 -1
  34. package/dist/ai-edits/table-row-column-mutations.d.ts +38 -16
  35. package/dist/ai-edits/table-row-column-mutations.js +61 -26
  36. package/dist/ai-edits/types.d.ts +155 -16
  37. package/dist/compare/compare.d.ts +1 -1
  38. package/dist/compare/compare.js +65 -16
  39. package/dist/compare/content-alignment.js +13 -2
  40. package/dist/compare/content-types.d.ts +7 -0
  41. package/dist/compare/content.d.ts +4 -1
  42. package/dist/compare/content.js +6 -1
  43. package/dist/compare/formatting.js +2 -1
  44. package/dist/compare/inline-atoms.d.ts +21 -4
  45. package/dist/compare/inline-atoms.js +138 -16
  46. package/dist/compare/plan.js +10 -5
  47. package/dist/compare/scenario.js +14 -3
  48. package/dist/compare/section-boundary-properties.js +1 -1
  49. package/dist/compare/types.d.ts +4 -2
  50. package/dist/compare/types.js +2 -1
  51. package/dist/compare/verification.d.ts +1 -1
  52. package/dist/compare/verification.js +15 -3
  53. package/dist/controller/committedLayoutDiff.d.ts +25 -0
  54. package/dist/controller/committedLayoutDiff.js +71 -0
  55. package/dist/controller/contentControlWidgetController.d.ts +1 -1
  56. package/dist/controller/folioEditor.d.ts +1 -1
  57. package/dist/controller/fontReadiness.d.ts +70 -3
  58. package/dist/controller/fontReadiness.js +100 -10
  59. package/dist/controller/headerFooterEditorManager.js +6 -1
  60. package/dist/controller/layoutPipeline.d.ts +12 -10
  61. package/dist/controller/layoutPipeline.js +62 -9
  62. package/dist/controller/layoutRunOptions.d.ts +24 -0
  63. package/dist/controller/layoutRunOptions.js +17 -0
  64. package/dist/controller/layoutScheduler.d.ts +19 -14
  65. package/dist/controller/layoutScheduler.js +15 -12
  66. package/dist/controller/layoutSession.d.ts +26 -2
  67. package/dist/controller/layoutSession.js +1 -1
  68. package/dist/controller/noteEditorManager.js +8 -3
  69. package/dist/document-operations.d.ts +11 -2
  70. package/dist/document-operations.js +230 -21
  71. package/dist/docx/altChunk.d.ts +8 -0
  72. package/dist/docx/altChunk.js +17 -0
  73. package/dist/docx/attributeRemainder.d.ts +1 -1
  74. package/dist/docx/blockContentParser.d.ts +64 -1
  75. package/dist/docx/blockContentParser.js +17 -4
  76. package/dist/docx/blockCustomXmlShell.d.ts +7 -0
  77. package/dist/docx/blockCustomXmlShell.js +14 -0
  78. package/dist/docx/blockPlainText.js +7 -0
  79. package/dist/docx/commentAnchorIndex.js +1 -1
  80. package/dist/docx/commentRangeIntegrity.js +8 -3
  81. package/dist/docx/commentReferenceNormalization.js +1 -1
  82. package/dist/docx/commentReplyMarkers.js +20 -1
  83. package/dist/docx/compatibility.d.ts +1 -1
  84. package/dist/docx/compatibility.js +34 -13
  85. package/dist/docx/containerChildren.gen.d.ts +1 -1
  86. package/dist/docx/containerChildren.gen.js +1 -0
  87. package/dist/docx/documentParser.js +12 -12
  88. package/dist/docx/drawingIdNormalization.d.ts +3 -1
  89. package/dist/docx/drawingIdNormalization.js +6 -1
  90. package/dist/docx/ensureParaIds.js +119 -97
  91. package/dist/docx/footnoteParser.js +8 -4
  92. package/dist/docx/headerFooterParser.js +3 -3
  93. package/dist/docx/headerFooterReferenceNormalization.d.ts +20 -1
  94. package/dist/docx/headerFooterReferenceNormalization.js +52 -27
  95. package/dist/docx/hyperlinkParser.d.ts +1 -1
  96. package/dist/docx/index.d.ts +1 -1
  97. package/dist/docx/listNumberingInstances.d.ts +59 -0
  98. package/dist/docx/listNumberingInstances.js +249 -0
  99. package/dist/docx/normalizeBaseDirection.js +2 -1
  100. package/dist/docx/opaqueCarrier.d.ts +7 -0
  101. package/dist/docx/opaqueCarrier.js +38 -0
  102. package/dist/docx/packageParts.js +4 -1
  103. package/dist/docx/paragraphParser.js +91 -24
  104. package/dist/docx/paragraphPropertySource.d.ts +4 -2
  105. package/dist/docx/paragraphPropertySource.js +7 -1
  106. package/dist/docx/paragraphTraversal.js +1 -0
  107. package/dist/docx/parseWarningMessage.js +4 -1
  108. package/dist/docx/parser.js +173 -20
  109. package/dist/docx/rezip.js +27 -5
  110. package/dist/docx/sdtProperties.js +1 -1
  111. package/dist/docx/sdtPropertiesPatch.js +3 -0
  112. package/dist/docx/selectiveSave.js +16 -9
  113. package/dist/docx/selectiveXmlPatch.js +106 -37
  114. package/dist/docx/serializer/blockCustomXmlSerializer.d.ts +5 -0
  115. package/dist/docx/serializer/blockCustomXmlSerializer.js +4 -0
  116. package/dist/docx/serializer/documentSerializer.js +2 -0
  117. package/dist/docx/serializer/headerFooterSerializer.js +2 -0
  118. package/dist/docx/serializer/noteSerializer.js +3 -1
  119. package/dist/docx/serializer/paragraphSerializer.js +33 -9
  120. package/dist/docx/serializer/tableSerializer.js +25 -38
  121. package/dist/docx/server/createBilingualDocument.js +3 -3
  122. package/dist/docx/tableParser.d.ts +157 -1
  123. package/dist/docx/tableParser.js +89 -10
  124. package/dist/docx/textBoxParser.js +1 -1
  125. package/dist/docx/unzip.d.ts +2 -1
  126. package/dist/docx/unzip.js +1 -1
  127. package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
  128. package/dist/docx/wordprocessingPrefixes.js +286 -0
  129. package/dist/i18n/messages/catalogs.gen.d.ts +136 -0
  130. package/dist/i18n/messages/catalogs.gen.js +153 -17
  131. package/dist/i18n/messages/messages.gen.d.ts +8 -0
  132. package/dist/internal/compare/inline-presentation.d.ts +2 -1
  133. package/dist/internal/compare/inline-presentation.js +11 -10
  134. package/dist/internal/headlessRevisionResolutionGuard.d.ts +2 -8
  135. package/dist/internal/headlessRevisionResolutionGuard.js +2 -11
  136. package/dist/internal/indexedPositionMap.d.ts +11 -0
  137. package/dist/internal/indexedPositionMap.js +42 -0
  138. package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
  139. package/dist/internal/revisionResolutionEdits.d.ts +13 -0
  140. package/dist/internal/revisionResolutionEdits.js +19 -0
  141. package/dist/internal/revisionResolutionInline.d.ts +24 -0
  142. package/dist/internal/{headlessRevisionResolution.js → revisionResolutionInline.js} +61 -43
  143. package/dist/internal/revisionResolutionStep.d.ts +34 -0
  144. package/dist/internal/revisionResolutionStep.js +282 -0
  145. package/dist/internal/revisionResolutionTracking.d.ts +11 -0
  146. package/dist/internal/revisionResolutionTracking.js +124 -0
  147. package/dist/internal/wholeStoryRevisionResolution.d.ts +56 -0
  148. package/dist/internal/wholeStoryRevisionResolution.js +530 -0
  149. package/dist/layout-bridge/convert/markupViewFlow.d.ts +20 -0
  150. package/dist/layout-bridge/convert/markupViewFlow.js +123 -0
  151. package/dist/layout-bridge/convert/tableConversion.js +1 -1
  152. package/dist/layout-bridge/convert/toFlowBlocks.js +10 -1
  153. package/dist/layout-engine/layoutInstrumentation.d.ts +9 -1
  154. package/dist/layout-engine/layoutInstrumentation.js +4 -1
  155. package/dist/layout-engine/measure/cache.d.ts +18 -1
  156. package/dist/layout-engine/measure/cache.js +31 -1
  157. package/dist/layout-engine/measure/font-metrics.worker.js +3 -7
  158. package/dist/layout-engine/measure/measureContainer.js +7 -47
  159. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -1
  160. package/dist/layout-engine/measure/measureHelpers.js +22 -2
  161. package/dist/layout-engine/measure/measureWorker.js +2 -3
  162. package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +6 -7
  163. package/dist/layout-engine/measure/measureWorkerProtocol.js +1 -2
  164. package/dist/layout-engine/types.d.ts +6 -0
  165. package/dist/layout-painter/renderPage.js +1 -0
  166. package/dist/layout-painter/renderParagraph.js +1 -1
  167. package/dist/managers/ContextMenuManager.js +5 -2
  168. package/dist/managers/types.d.ts +3 -0
  169. package/dist/markdown/fromMarkdown.js +2 -1
  170. package/dist/markdown/internals.d.ts +11 -1
  171. package/dist/markdown/internals.js +24 -3
  172. package/dist/markdown/renderBlock.js +39 -9
  173. package/dist/markdown/renderParagraph.d.ts +13 -1
  174. package/dist/markdown/renderParagraph.js +85 -38
  175. package/dist/markdown/renderRuns.js +3 -10
  176. package/dist/markdown/renderTable.js +24 -12
  177. package/dist/markdown/trailers.js +2 -2
  178. package/dist/markdown/types.d.ts +29 -7
  179. package/dist/paged-layout/incrementalMeasure.d.ts +1 -2
  180. package/dist/paged-layout/incrementalMeasure.js +1 -9
  181. package/dist/paged-layout/transactionDirtyRange.d.ts +1 -3
  182. package/dist/paged-layout/transactionDirtyRange.js +29 -41
  183. package/dist/panel-layout.d.ts +83 -0
  184. package/dist/panel-layout.js +96 -0
  185. package/dist/prosemirror/anchoredTextBoxes.d.ts +37 -0
  186. package/dist/prosemirror/anchoredTextBoxes.js +156 -0
  187. package/dist/prosemirror/attrs/index.d.ts +6 -2
  188. package/dist/prosemirror/attrs/index.js +172 -1
  189. package/dist/prosemirror/commands/comments.d.ts +7 -8
  190. package/dist/prosemirror/commands/comments.js +241 -207
  191. package/dist/prosemirror/commands/contentControls.d.ts +1 -1
  192. package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
  193. package/dist/prosemirror/commands/formatting.d.ts +1 -1
  194. package/dist/prosemirror/commands/index.d.ts +2 -2
  195. package/dist/prosemirror/commands/index.js +2 -2
  196. package/dist/prosemirror/commands/paragraph.d.ts +7 -1
  197. package/dist/prosemirror/commands/paragraph.js +9 -1
  198. package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +13 -0
  199. package/dist/prosemirror/commands/paragraphBookmarkJoin.js +22 -0
  200. package/dist/prosemirror/commands/pastePlainText.d.ts +1 -1
  201. package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
  202. package/dist/prosemirror/commands/resolveAllTableChanges.js +615 -0
  203. package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.d.ts +15 -0
  204. package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.js +46 -0
  205. package/dist/prosemirror/commands/resolveParagraphProperties.d.ts +16 -0
  206. package/dist/prosemirror/commands/resolveParagraphProperties.js +59 -0
  207. package/dist/prosemirror/commands/sectionBreak.js +2 -1
  208. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -2
  209. package/dist/prosemirror/commands/tableCellMergeResolution.js +1 -1
  210. package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
  211. package/dist/prosemirror/conversion/fromProseDoc.js +181 -31
  212. package/dist/prosemirror/conversion/toProseDoc.js +39 -4
  213. package/dist/prosemirror/emptyFieldResultRuns.d.ts +18 -0
  214. package/dist/prosemirror/emptyFieldResultRuns.js +33 -0
  215. package/dist/prosemirror/extensions/ExtensionManager.d.ts +1 -1
  216. package/dist/prosemirror/extensions/ExtensionManager.js +3 -1
  217. package/dist/prosemirror/extensions/StarterKit.js +3 -1
  218. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  219. package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -0
  220. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +3 -0
  221. package/dist/prosemirror/extensions/features/ListExtension.js +161 -123
  222. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +19 -2
  223. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +33 -20
  224. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +31 -2
  225. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +270 -99
  226. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +3 -2
  227. package/dist/prosemirror/extensions/features/pasteCleanup.js +2 -1
  228. package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
  229. package/dist/prosemirror/extensions/features/pastedHtmlLists.js +126 -0
  230. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +21 -5
  231. package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
  232. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
  233. package/dist/prosemirror/extensions/marks/markUtils.d.ts +7 -2
  234. package/dist/prosemirror/extensions/marks/markUtils.js +8 -2
  235. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +10 -0
  236. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +35 -0
  237. package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.d.ts +6 -0
  238. package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.js +52 -0
  239. package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
  240. package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
  241. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +4 -1
  242. package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
  243. package/dist/prosemirror/extensions/nodes/TableExtension.js +19 -18
  244. package/dist/prosemirror/extensions/types.d.ts +4 -1
  245. package/dist/prosemirror/findReplaceSelection.js +1 -1
  246. package/dist/prosemirror/index.d.ts +3 -2
  247. package/dist/prosemirror/index.js +3 -2
  248. package/dist/prosemirror/indexedNodeLookup.d.ts +17 -0
  249. package/dist/prosemirror/indexedNodeLookup.js +103 -0
  250. package/dist/prosemirror/listAutoformatMarkers.d.ts +19 -0
  251. package/dist/prosemirror/listAutoformatMarkers.js +98 -0
  252. package/dist/prosemirror/listInstanceReferences.d.ts +12 -0
  253. package/dist/prosemirror/listInstanceReferences.js +72 -0
  254. package/dist/prosemirror/listLabels.d.ts +24 -0
  255. package/dist/prosemirror/listLabels.js +111 -0
  256. package/dist/prosemirror/listNumbering.d.ts +110 -0
  257. package/dist/prosemirror/listNumbering.js +345 -0
  258. package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
  259. package/dist/prosemirror/listRenderingAttrs.js +8 -1
  260. package/dist/prosemirror/markupViewProjection.d.ts +95 -0
  261. package/dist/prosemirror/markupViewProjection.js +83 -0
  262. package/dist/prosemirror/numberingAttr.d.ts +9 -1
  263. package/dist/prosemirror/numberingAttr.js +9 -1
  264. package/dist/prosemirror/outlineLevelAttr.js +1 -1
  265. package/dist/prosemirror/paragraphIndentation.d.ts +10 -1
  266. package/dist/prosemirror/paragraphIndentation.js +29 -7
  267. package/dist/prosemirror/paragraphMarkJoin.d.ts +19 -0
  268. package/dist/prosemirror/paragraphMarkJoin.js +24 -0
  269. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +1 -1
  270. package/dist/prosemirror/plugins/documentNumbering.d.ts +27 -1
  271. package/dist/prosemirror/plugins/documentNumbering.js +97 -11
  272. package/dist/prosemirror/plugins/documentStyles.d.ts +10 -1
  273. package/dist/prosemirror/plugins/documentStyles.js +14 -1
  274. package/dist/prosemirror/plugins/suggestionMode.d.ts +16 -2
  275. package/dist/prosemirror/plugins/suggestionMode.js +116 -52
  276. package/dist/prosemirror/plugins/templateDirectives.d.ts +1 -1
  277. package/dist/prosemirror/plugins/transactionInvariants.d.ts +32 -0
  278. package/dist/prosemirror/plugins/transactionInvariants.js +86 -0
  279. package/dist/prosemirror/positionSweep.d.ts +24 -0
  280. package/dist/prosemirror/positionSweep.js +222 -0
  281. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +1 -1
  282. package/dist/prosemirror/rejoinRunCarriers.d.ts +1 -1
  283. package/dist/prosemirror/replacedAnnotations.d.ts +33 -1
  284. package/dist/prosemirror/replacedAnnotations.js +170 -1
  285. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
  286. package/dist/prosemirror/schema/index.d.ts +2 -2
  287. package/dist/prosemirror/schema/index.js +3 -0
  288. package/dist/prosemirror/schema/nodes.d.ts +42 -11
  289. package/dist/prosemirror/sectionMarkEdits.d.ts +20 -0
  290. package/dist/prosemirror/sectionMarkEdits.js +59 -0
  291. package/dist/prosemirror/storyListNumbering.d.ts +17 -0
  292. package/dist/prosemirror/storyListNumbering.js +102 -0
  293. package/dist/prosemirror/tableGridMutation.d.ts +48 -2
  294. package/dist/prosemirror/tableGridMutation.js +106 -1
  295. package/dist/prosemirror/validation.js +5 -1
  296. package/dist/redline.js +93 -9
  297. package/dist/render-dom/BodySelectionOverlay.d.ts +4 -1
  298. package/dist/render-dom/BodySelectionOverlay.js +3 -2
  299. package/dist/utils/findReplace.js +2 -2
  300. package/dist/utils/mergeDocumentContent.js +1 -1
  301. package/dist/utils/noteReferenceLabels.d.ts +36 -0
  302. package/dist/utils/noteReferenceLabels.js +32 -0
  303. package/dist/utils/replaceText.js +1 -1
  304. package/dist/version-comparison.d.ts +1 -0
  305. package/dist/version-comparison.js +1 -0
  306. package/package.json +3 -2
  307. package/dist/internal/headlessRevisionResolution.d.ts +0 -23
@@ -1,5 +1,10 @@
1
- import { applyFolioAIEditOperations, previewFolioAIEditOperations } from "./ai-edits/apply.js";
1
+ import { applyFolioAIEditOperations, previewFolioAIEditOperationsWithResult } from "./ai-edits/apply.js";
2
+ import { describeModelError, findIntroducedModelErrors } from "./ai-edits/result-validation.js";
3
+ import { LIST_KINDS } from "./docx/listNumberingInstances.js";
2
4
  import { isNumberingReference } from "./docx/numberingReference.js";
5
+ import { completeNumberingForDoc } from "./prosemirror/listInstanceReferences.js";
6
+ import { outlineLevelFromAttrValue } from "./prosemirror/outlineLevelAttr.js";
7
+ import { getStatedDocumentNumbering } from "./prosemirror/plugins/documentNumbering.js";
3
8
  import { LINE_SPACING_RULE_VALUES, PARAGRAPH_ALIGNMENT_VALUES } from "./types/documentEnumValues.js";
4
9
  import { TaggedError } from "better-result";
5
10
  import { sanitizeXmlCharacters } from "@stll/docx-core";
@@ -293,11 +298,40 @@ const readClearableParagraphIndentation = ({ value, key, path }) => {
293
298
  }
294
299
  return indentation;
295
300
  };
301
+ /** `w:ilvl` names one of an abstract numbering's nine levels. */
302
+ const MAX_NEW_LIST_LEVEL = 8;
303
+ const LIST_KIND_SET = new Set(LIST_KINDS);
304
+ const isListKind = (value) => LIST_KIND_SET.has(value);
305
+ /** `{ start: "new", kind, level? }`: a list the operation starts. */
306
+ const readNewListReference = (candidate, numberingPath) => {
307
+ assertAllowedKeys(candidate, numberingPath, [
308
+ "start",
309
+ "kind",
310
+ "level"
311
+ ]);
312
+ const kind = candidate["kind"];
313
+ if (typeof kind !== "string" || !isListKind(kind)) return invalidBatch(`${numberingPath}.kind`, `expected one of ${LIST_KINDS.join(", ")}`);
314
+ if (candidate["level"] === void 0) return {
315
+ start: "new",
316
+ kind
317
+ };
318
+ const level = readNonNegativeInteger(candidate, "level", numberingPath);
319
+ if (level > MAX_NEW_LIST_LEVEL) return invalidBatch(`${numberingPath}.level`, `expected at most ${MAX_NEW_LIST_LEVEL}`);
320
+ return {
321
+ start: "new",
322
+ kind,
323
+ level
324
+ };
325
+ };
296
326
  const readClearableNumbering = ({ value, key, path }) => {
297
327
  const candidate = value[key];
298
328
  if (candidate === void 0 || candidate === null) return candidate;
299
329
  const numberingPath = `${path}.${key}`;
300
330
  if (!isPlainObject(candidate)) return invalidBatch(numberingPath, "expected an object or null when provided");
331
+ if (candidate["start"] !== void 0) {
332
+ if (candidate["start"] !== "new") return invalidBatch(`${numberingPath}.start`, "expected \"new\"");
333
+ return readNewListReference(candidate, numberingPath);
334
+ }
301
335
  assertAllowedKeys(candidate, numberingPath, ["numId", "level"]);
302
336
  const numId = readNonNegativeInteger(candidate, "numId", numberingPath);
303
337
  if (!isNumberingReference(numId)) return invalidBatch(`${numberingPath}.numId`, "expected a positive integer");
@@ -326,12 +360,22 @@ const readTableRows = (value, path) => {
326
360
  if (parsed.some((row) => row.length !== width)) return invalidBatch(rowsPath, "expected every row to hold the same number of cells");
327
361
  return parsed;
328
362
  };
363
+ const readClearableOutlineLevel = (value, path) => {
364
+ const candidate = value["outlineLevel"];
365
+ if (candidate === void 0 || candidate === null) return candidate;
366
+ if (!isPlainObject(candidate)) return invalidBatch(`${path}.outlineLevel`, "expected an outline level");
367
+ assertAllowedKeys(candidate, `${path}.outlineLevel`, ["kind", "level"]);
368
+ const outlineLevel = outlineLevelFromAttrValue(candidate);
369
+ if (outlineLevel === null) return invalidBatch(`${path}.outlineLevel`, "expected a valid outline level");
370
+ return outlineLevel;
371
+ };
329
372
  const readParagraphProperties = ({ value, key, path }) => {
330
373
  const candidate = value[key];
331
374
  const propertiesPath = `${path}.${key}`;
332
375
  if (!isPlainObject(candidate)) return invalidBatch(propertiesPath, "expected an object");
333
376
  assertAllowedKeys(candidate, propertiesPath, [
334
377
  "styleId",
378
+ "outlineLevel",
335
379
  "listLevel",
336
380
  "numbering",
337
381
  "alignment",
@@ -339,6 +383,7 @@ const readParagraphProperties = ({ value, key, path }) => {
339
383
  "indentation"
340
384
  ]);
341
385
  const styleId = candidate["styleId"] === null ? null : readOptionalString(candidate, "styleId", propertiesPath);
386
+ const outlineLevel = readClearableOutlineLevel(candidate, propertiesPath);
342
387
  const listLevel = readClearableNonNegativeInteger(candidate, "listLevel", propertiesPath);
343
388
  const numbering = readClearableNumbering({
344
389
  value: candidate,
@@ -360,9 +405,10 @@ const readParagraphProperties = ({ value, key, path }) => {
360
405
  key: "indentation",
361
406
  path: propertiesPath
362
407
  });
363
- if (styleId === void 0 && listLevel === void 0 && numbering === void 0 && alignment === void 0 && spacing === void 0 && indentation === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
408
+ if (styleId === void 0 && outlineLevel === void 0 && listLevel === void 0 && numbering === void 0 && alignment === void 0 && spacing === void 0 && indentation === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
364
409
  return {
365
410
  ...styleId !== void 0 && { styleId },
411
+ ...outlineLevel !== void 0 && { outlineLevel },
366
412
  ...listLevel !== void 0 && { listLevel },
367
413
  ...numbering !== void 0 && { numbering },
368
414
  ...alignment !== void 0 && { alignment },
@@ -515,6 +561,7 @@ const OPERATION_KEY_DECISIONS = {
515
561
  pageBreakBefore: true,
516
562
  hardPageBreak: true,
517
563
  styleId: true,
564
+ outlineLevel: true,
518
565
  comment: true
519
566
  },
520
567
  insertBeforeBlock: {
@@ -532,6 +579,7 @@ const OPERATION_KEY_DECISIONS = {
532
579
  pageBreakBefore: true,
533
580
  hardPageBreak: true,
534
581
  styleId: true,
582
+ outlineLevel: true,
535
583
  comment: true
536
584
  },
537
585
  replaceBlock: {
@@ -783,6 +831,7 @@ const parseDocumentOperation = (value, index) => {
783
831
  const pageBreakBefore = readOptionalBoolean(value, "pageBreakBefore", path);
784
832
  const hardPageBreak = readOptionalHardPageBreak(value, path);
785
833
  const styleId = value["styleId"] === null ? null : readOptionalString(value, "styleId", path);
834
+ const outlineLevel = readClearableOutlineLevel(value, path);
786
835
  const moveId = readOptionalString(value, "moveId", path);
787
836
  const listLevel = readClearableNonNegativeInteger(value, "listLevel", path);
788
837
  const numbering = readClearableNumbering({
@@ -810,7 +859,7 @@ const parseDocumentOperation = (value, index) => {
810
859
  const formattingScope = value["formattingScope"];
811
860
  if (formattingScope !== void 0 && formattingScope !== "firstParagraph" && formattingScope !== "allParagraphs") return invalidBatch(`${path}.formattingScope`, "expected \"firstParagraph\" or \"allParagraphs\" when provided");
812
861
  const text = readString(value, "text", path);
813
- if (hardPageBreak !== void 0 && text.length > 0) return invalidBatch(`${path}.text`, "expected empty text with hardPageBreak");
862
+ if (hardPageBreak !== void 0 && text.length > 0) return invalidBatch(`${path}.text`, "omit hardPageBreak to insert text, or set text to \"\" to insert a hard page break");
814
863
  if (hardPageBreak !== void 0 && pageBreakBefore !== void 0) return invalidBatch(`${path}.pageBreakBefore`, "cannot combine hardPageBreak with pageBreakBefore");
815
864
  if (hardPageBreak !== void 0 && lineBreakMode !== void 0) return invalidBatch(`${path}.lineBreakMode`, "cannot combine hardPageBreak with lineBreakMode");
816
865
  return {
@@ -831,6 +880,7 @@ const parseDocumentOperation = (value, index) => {
831
880
  ...pageBreakBefore !== void 0 && { pageBreakBefore },
832
881
  ...hardPageBreak !== void 0 && { hardPageBreak },
833
882
  ...styleId !== void 0 && { styleId },
883
+ ...outlineLevel !== void 0 && { outlineLevel },
834
884
  ...comment !== void 0 && { comment }
835
885
  };
836
886
  }
@@ -1014,22 +1064,31 @@ const recoveryByReason = {
1014
1064
  pendingRunPropertyChange: "resolveTrackedChange",
1015
1065
  noopOperation: "removeOperation",
1016
1066
  documentVersionMismatch: "refreshDocument",
1017
- documentNotEditable: "retryLater"
1067
+ documentNotEditable: "retryLater",
1068
+ payloadDoesNotFit: "changeTarget",
1069
+ overlappingOperation: "refreshDocument",
1070
+ splitsCharacter: "changeTarget",
1071
+ protectedReference: "narrowMatch",
1072
+ missingStyle: "refreshDocument",
1073
+ missingNumbering: "refreshDocument",
1074
+ invalidResult: "refreshDocument",
1075
+ pendingDeletion: "resolveTrackedChange"
1018
1076
  };
1019
1077
  const getFolioDocumentOperationIssues = (operations, skipped) => {
1020
1078
  const indexById = /* @__PURE__ */ new Map();
1021
1079
  operations.forEach(({ id }, index) => {
1022
1080
  indexById.set(id, index);
1023
1081
  });
1024
- return skipped.map(({ id, reason }) => {
1082
+ return skipped.map(({ id, reason, message }) => {
1025
1083
  const operationIndex = indexById.get(id) ?? -1;
1026
1084
  return {
1027
1085
  operationId: id,
1028
1086
  operationIndex,
1029
1087
  path: `$.operations[${operationIndex}]`,
1030
1088
  code: reason,
1031
- retryable: reason !== "emptyOperation" && reason !== "noopOperation" && reason !== "pendingParagraphPropertyChange" && reason !== "pendingRunPropertyChange",
1032
- recovery: recoveryByReason[reason]
1089
+ retryable: reason !== "emptyOperation" && reason !== "noopOperation" && reason !== "pendingParagraphPropertyChange" && reason !== "pendingRunPropertyChange" && reason !== "pendingDeletion" && reason !== "payloadDoesNotFit" && reason !== "protectedReference" && reason !== "invalidResult",
1090
+ recovery: recoveryByReason[reason],
1091
+ ...message !== void 0 && { message }
1033
1092
  };
1034
1093
  });
1035
1094
  };
@@ -1183,26 +1242,173 @@ const getFolioDocumentOperationReceiptsForStory = ({ operations, applied, story
1183
1242
  });
1184
1243
  return receipts;
1185
1244
  };
1186
- const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground }) => {
1245
+ const NO_COMMIT = () => {};
1246
+ /** Skips reported in the order of the operations they belong to. */
1247
+ const inOperationOrder = (operations, skipped) => {
1248
+ const indexById = new Map(operations.map(({ id }, index) => [id, index]));
1249
+ return [...skipped].sort((left, right) => (indexById.get(left.id) ?? -1) - (indexById.get(right.id) ?? -1));
1250
+ };
1251
+ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles }) => {
1187
1252
  const parsedBatch = parseFolioDocumentOperationBatch(batch);
1188
- const apply = ({ targetView, targetCreateCommentId = createCommentId, preview = false }) => {
1189
- return (preview ? previewFolioAIEditOperations : applyFolioAIEditOperations)({
1190
- view: targetView,
1253
+ const isAtomic = parsedBatch.atomic === true;
1254
+ const beforeDoc = view.state.doc;
1255
+ const packageNumbering = getStatedDocumentNumbering(view.state);
1256
+ const attempt = (operations, preview) => {
1257
+ const common = {
1191
1258
  snapshot,
1192
- operations: parsedBatch.operations,
1259
+ operations,
1193
1260
  mode: parsedBatch.mode ?? "tracked-changes",
1194
1261
  ...author !== void 0 && { author },
1195
- ...targetCreateCommentId !== void 0 && { createCommentId: targetCreateCommentId },
1196
1262
  ...revisionStamp !== void 0 && { revisionStamp },
1197
1263
  ...wordDiff !== void 0 && { wordDiff },
1198
1264
  ...tableTemplates !== void 0 && { tableTemplates },
1199
- ...replacementBackground !== void 0 && { replacementBackground }
1265
+ ...replacementBackground !== void 0 && { replacementBackground },
1266
+ ...undefinedStyles !== void 0 && { undefinedStyles }
1267
+ };
1268
+ if (preview) return {
1269
+ ...previewFolioAIEditOperationsWithResult({
1270
+ ...common,
1271
+ view,
1272
+ ...createCommentId !== void 0 && { createCommentId }
1273
+ }),
1274
+ commit: NO_COMMIT
1275
+ };
1276
+ const held = {};
1277
+ const commentIds = [];
1278
+ return {
1279
+ outcome: applyFolioAIEditOperations({
1280
+ ...common,
1281
+ view: {
1282
+ state: view.state,
1283
+ dispatch: (transaction) => {
1284
+ held.transaction = transaction;
1285
+ }
1286
+ },
1287
+ ...createCommentId !== void 0 && { createCommentId: (text) => {
1288
+ const id = createCommentId(text);
1289
+ commentIds.push(id);
1290
+ return id;
1291
+ } }
1292
+ }),
1293
+ doc: held.transaction?.doc ?? null,
1294
+ commentIds,
1295
+ commit: () => {
1296
+ if (held.transaction !== void 0) view.dispatch(held.transaction);
1297
+ }
1298
+ };
1299
+ };
1300
+ const introducedErrors = (run) => {
1301
+ if (run.doc === null || run.outcome.applied.length === 0) return [];
1302
+ const numbering = packageNumbering === void 0 ? void 0 : completeNumberingForDoc(packageNumbering ?? void 0, run.doc) ?? null;
1303
+ return findIntroducedModelErrors(beforeDoc, run.doc, {
1304
+ numbering,
1305
+ createdCommentIds: run.commentIds,
1306
+ ...author !== void 0 && { commentAuthor: author }
1200
1307
  });
1201
1308
  };
1202
- const preview = () => apply({
1203
- targetView: view,
1204
- preview: true
1205
- });
1309
+ /**
1310
+ * An attempt on the refusal path, where the applier runs on subsets of the
1311
+ * batch it was not asked to apply: a throw there is one more reason to
1312
+ * refuse, never a reason to fail a batch the first run could apply.
1313
+ */
1314
+ const checkedAttempt = (operations, preview) => {
1315
+ try {
1316
+ const run = attempt(operations, preview);
1317
+ return {
1318
+ run,
1319
+ error: introducedErrors(run)[0]
1320
+ };
1321
+ } catch (error) {
1322
+ return {
1323
+ run: null,
1324
+ error: {
1325
+ path: "package.document",
1326
+ message: `the operation could not be applied (${error instanceof Error ? error.message : String(error)}).`,
1327
+ severity: "error"
1328
+ }
1329
+ };
1330
+ }
1331
+ };
1332
+ /**
1333
+ * Which applied operations produced the unsaveable result: each one is
1334
+ * previewed alone against the unchanged story. When none fails alone, the
1335
+ * failure is their combination, and every one of them is refused.
1336
+ */
1337
+ const refuseInvalidResult = (run, firstError) => {
1338
+ const operationsById = new Map(parsedBatch.operations.map((operation) => [operation.id, operation]));
1339
+ const refused = [];
1340
+ for (const { id } of run.outcome.applied) {
1341
+ const operation = operationsById.get(id);
1342
+ if (operation === void 0) continue;
1343
+ const alone = checkedAttempt([operation], true).error;
1344
+ if (alone !== void 0) refused.push({
1345
+ id,
1346
+ reason: "invalidResult",
1347
+ message: describeModelError(alone)
1348
+ });
1349
+ }
1350
+ if (refused.length > 0) return refused;
1351
+ return run.outcome.applied.map(({ id }) => ({
1352
+ id,
1353
+ reason: "invalidResult",
1354
+ message: describeModelError(firstError)
1355
+ }));
1356
+ };
1357
+ /**
1358
+ * Apply (or preview) the batch and check the result with the save-time
1359
+ * validator before anything reaches the caller. Operations whose result would
1360
+ * not save are skipped with `invalidResult`; in a best-effort batch the rest
1361
+ * is applied again without them, in an atomic one nothing is.
1362
+ */
1363
+ const guardedAttempt = (preview) => {
1364
+ const first = attempt(parsedBatch.operations, preview);
1365
+ const [firstError] = introducedErrors(first);
1366
+ if (firstError === void 0) return {
1367
+ outcome: {
1368
+ ...first.outcome,
1369
+ skipped: inOperationOrder(parsedBatch.operations, first.outcome.skipped)
1370
+ },
1371
+ commit: first.commit
1372
+ };
1373
+ const refused = refuseInvalidResult(first, firstError);
1374
+ const refusedIds = new Set(refused.map(({ id }) => id));
1375
+ if (isAtomic) return {
1376
+ outcome: {
1377
+ ...first.outcome,
1378
+ applied: [],
1379
+ skipped: inOperationOrder(parsedBatch.operations, [...first.outcome.skipped, ...refused])
1380
+ },
1381
+ commit: NO_COMMIT
1382
+ };
1383
+ const second = checkedAttempt(parsedBatch.operations.filter(({ id }) => !refusedIds.has(id)), preview);
1384
+ if (second.run === null || second.error !== void 0) {
1385
+ const reported = second.run?.outcome ?? first.outcome;
1386
+ return {
1387
+ outcome: {
1388
+ ...reported,
1389
+ applied: [],
1390
+ skipped: inOperationOrder(parsedBatch.operations, [
1391
+ ...reported.skipped.filter(({ id }) => !refusedIds.has(id)),
1392
+ ...refused,
1393
+ ...reported.applied.filter(({ id }) => !refusedIds.has(id)).map(({ id }) => ({
1394
+ id,
1395
+ reason: "invalidResult",
1396
+ message: describeModelError(second.error ?? firstError)
1397
+ }))
1398
+ ])
1399
+ },
1400
+ commit: NO_COMMIT
1401
+ };
1402
+ }
1403
+ return {
1404
+ outcome: {
1405
+ ...second.run.outcome,
1406
+ skipped: inOperationOrder(parsedBatch.operations, [...second.run.outcome.skipped, ...refused])
1407
+ },
1408
+ commit: second.run.commit
1409
+ };
1410
+ };
1411
+ const preview = () => guardedAttempt(true).outcome;
1206
1412
  const atomicResult = (previewResult, status) => {
1207
1413
  const skippedById = new Map(previewResult.skipped.map((operation) => [operation.id, operation]));
1208
1414
  const skipped = parsedBatch.operations.map(({ id }) => skippedById.get(id) ?? {
@@ -1223,7 +1429,7 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
1223
1429
  };
1224
1430
  if (parsedBatch.dryRun === true) {
1225
1431
  const previewResult = preview();
1226
- if (parsedBatch.atomic === true && previewResult.skipped.length > 0) return atomicResult(previewResult, "previewed");
1432
+ if (isAtomic && previewResult.skipped.length > 0) return atomicResult(previewResult, "previewed");
1227
1433
  return {
1228
1434
  version: 1,
1229
1435
  status: "previewed",
@@ -1240,11 +1446,14 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
1240
1446
  nextRevisionId: previewResult.nextRevisionId
1241
1447
  };
1242
1448
  }
1243
- if (parsedBatch.atomic === true) {
1449
+ if (isAtomic) {
1244
1450
  const previewResult = preview();
1245
1451
  if (previewResult.skipped.length > 0) return atomicResult(previewResult, "rejected");
1246
1452
  }
1247
- const result = apply({ targetView: view });
1453
+ const guarded = guardedAttempt(false);
1454
+ const result = guarded.outcome;
1455
+ if (isAtomic && result.skipped.some(({ reason }) => reason === "invalidResult")) return atomicResult(result, "rejected");
1456
+ guarded.commit();
1248
1457
  return {
1249
1458
  version: 1,
1250
1459
  status: "committed",
@@ -0,0 +1,8 @@
1
+ //#region src/docx/altChunk.d.ts
2
+ declare const ALT_CHUNK_READER_DIAGNOSTIC = "[Unsupported w:altChunk content]";
3
+ declare const ALT_CHUNK_PLAIN_TEXT_LIMIT_BYTES = 1000000;
4
+ /** The captured fragment's expanded name, not its source prefix, identifies w:altChunk. */
5
+ declare const isAltChunkMarkup: (xml: string) => boolean;
6
+ declare const getAltChunkRelationshipId: (xml: string) => string | undefined;
7
+ //#endregion
8
+ export { ALT_CHUNK_PLAIN_TEXT_LIMIT_BYTES, ALT_CHUNK_READER_DIAGNOSTIC, getAltChunkRelationshipId, isAltChunkMarkup };
@@ -0,0 +1,17 @@
1
+ import { OOXML_NAMESPACE_SCOPE, WORDPROCESSINGML_NAMESPACE_URIS, getAttribute, getChildElements, getLocalName, parseXml } from "./xmlParser.js";
2
+ //#region src/docx/altChunk.ts
3
+ const ALT_CHUNK_READER_DIAGNOSTIC = "[Unsupported w:altChunk content]";
4
+ const ALT_CHUNK_PLAIN_TEXT_LIMIT_BYTES = 1e6;
5
+ const OFFICE_RELATIONSHIPS_NAMESPACE_URI = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
6
+ /** The captured fragment's expanded name, not its source prefix, identifies w:altChunk. */
7
+ const isAltChunkMarkup = (xml) => {
8
+ const element = getChildElements(parseXml(xml, OOXML_NAMESPACE_SCOPE)).at(0);
9
+ return element?.type === "element" && getLocalName(element.name) === "altChunk" && WORDPROCESSINGML_NAMESPACE_URIS.has(element.namespaceUri ?? "");
10
+ };
11
+ const getAltChunkRelationshipId = (xml) => {
12
+ const element = getChildElements(parseXml(xml, OOXML_NAMESPACE_SCOPE)).at(0);
13
+ if (element?.type !== "element" || getLocalName(element.name) !== "altChunk" || !WORDPROCESSINGML_NAMESPACE_URIS.has(element.namespaceUri ?? "")) return;
14
+ return getAttribute(element, OFFICE_RELATIONSHIPS_NAMESPACE_URI, "id") ?? void 0;
15
+ };
16
+ //#endregion
17
+ export { ALT_CHUNK_PLAIN_TEXT_LIMIT_BYTES, ALT_CHUNK_READER_DIAGNOSTIC, getAltChunkRelationshipId, isAltChunkMarkup };
@@ -1,5 +1,5 @@
1
- import { ModelledAttributes } from "./propertyElementAttributes.js";
2
1
  import { XmlElement } from "./xmlParser.js";
2
+ import { ModelledAttributes } from "./propertyElementAttributes.js";
3
3
  import { PreservedAttribute } from "@stll/docx-core/model";
4
4
  //#region src/docx/attributeRemainder.d.ts
5
5
  declare const InvalidPreservedAttributeError_base: import("better-result").TaggedErrorClass<"InvalidPreservedAttributeError">;
@@ -2,6 +2,7 @@ import { document_d_exports } from "../types/document.js";
2
2
  import { NumberingMap } from "./numberingParser.js";
3
3
  import { ParseContext } from "./parseContext.js";
4
4
  import { XmlElement } from "./xmlParser.js";
5
+ import { OwnedElsewhere } from "./containerChildren.js";
5
6
  import { PreviewLedger } from "./previewBudget.js";
6
7
  import { StyleMap } from "./styleParser.js";
7
8
  //#region src/docx/blockContentParser.d.ts
@@ -11,6 +12,68 @@ type ParseBlockContentOptions = {
11
12
  context?: ParseContext | undefined;
12
13
  previews?: PreviewLedger;
13
14
  };
15
+ /** The options every block below the entry point reads, with its ledger settled. */
16
+ type BlockContentScope = ParseBlockContentOptions & {
17
+ previews: PreviewLedger;
18
+ };
19
+ type PreviousListState = {
20
+ abstractNumId: number | null;
21
+ fromStyle: boolean;
22
+ numId: number | null;
23
+ };
24
+ type ParseBlockContentState = {
25
+ listCounters: Map<number, number[]>;
26
+ abstractCounters: Map<number, number[]>;
27
+ restartedNumIds: Set<number>;
28
+ previousList: PreviousListState;
29
+ options: BlockContentScope;
30
+ };
14
31
  declare const parseBlockContent: (parent: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null, options?: ParseBlockContentOptions) => document_d_exports.BlockContent[];
32
+ /** The parts and maps a block sequence is read against. */
33
+ type BlockContentResources = {
34
+ styles: StyleMap | null;
35
+ theme: document_d_exports.Theme | null;
36
+ numbering: NumberingMap | null;
37
+ rels: document_d_exports.RelationshipMap | null;
38
+ media: Map<string, document_d_exports.MediaFile> | null;
39
+ };
40
+ /** One block container's children as they are read. */
41
+ type BlockContentWalk = {
42
+ resources: BlockContentResources;
43
+ state: ParseBlockContentState;
44
+ modelled: document_d_exports.BlockContent[];
45
+ };
46
+ declare const BLOCK_CONTENT_HANDLERS: {
47
+ readonly altChunk: "capture";
48
+ readonly commentRangeEnd: "capture";
49
+ readonly commentRangeStart: "capture";
50
+ readonly customXmlDelRangeEnd: "capture";
51
+ readonly customXmlDelRangeStart: "capture";
52
+ readonly customXmlInsRangeEnd: "capture";
53
+ readonly customXmlInsRangeStart: "capture";
54
+ readonly customXmlMoveFromRangeEnd: "capture";
55
+ readonly customXmlMoveFromRangeStart: "capture";
56
+ readonly customXmlMoveToRangeEnd: "capture";
57
+ readonly customXmlMoveToRangeStart: "capture";
58
+ readonly del: "capture";
59
+ readonly ins: "capture";
60
+ readonly moveFrom: "capture";
61
+ readonly moveFromRangeEnd: "capture";
62
+ readonly moveFromRangeStart: "capture";
63
+ readonly moveTo: "capture";
64
+ readonly moveToRangeEnd: "capture";
65
+ readonly moveToRangeStart: "capture";
66
+ readonly permEnd: "capture";
67
+ readonly permStart: "capture";
68
+ readonly proofErr: "capture";
69
+ readonly sectPr: OwnedElsewhere<"block-content", "sectPr">;
70
+ readonly tcPr: OwnedElsewhere<"block-content", "tcPr">;
71
+ readonly p: (child: XmlElement, { resources: { styles, theme, numbering, rels, media }, state, modelled }: BlockContentWalk) => void;
72
+ readonly tbl: (child: XmlElement, { resources: { styles, theme, numbering, rels, media }, state, modelled }: BlockContentWalk) => "capture" | undefined;
73
+ readonly sdt: (child: XmlElement, { resources: { styles, theme, numbering, rels, media }, state, modelled }: BlockContentWalk) => void;
74
+ readonly customXml: (child: XmlElement, { resources: { styles, theme, numbering, rels, media }, state, modelled }: BlockContentWalk) => void;
75
+ readonly bookmarkStart: (child: XmlElement, { modelled }: BlockContentWalk) => void;
76
+ readonly bookmarkEnd: (child: XmlElement, { modelled }: BlockContentWalk) => void;
77
+ };
15
78
  //#endregion
16
- export { parseBlockContent };
79
+ export { BLOCK_CONTENT_HANDLERS, parseBlockContent };
@@ -1,3 +1,4 @@
1
+ import { blockCustomXmlShell } from "./blockCustomXmlShell.js";
1
2
  import { parseBookmarkEnd, parseBookmarkStart } from "./bookmarkParser.js";
2
3
  import { bulletMarkerFontName, convertBulletToUnicode } from "./bulletMarkers.js";
3
4
  import { CAPTURE, dispatchChildrenWithContext, ownedElsewhere, withPreservedChildren } from "./containerChildren.js";
@@ -8,7 +9,7 @@ import { enrichParagraphTextBoxes } from "./paragraphTextBoxEnrichment.js";
8
9
  import { standalonePreviewLedger } from "./previewBudget.js";
9
10
  import { captureSdtSiblingMarkers, parseSdtProperties } from "./sdtProperties.js";
10
11
  import { parseTable } from "./tableParser.js";
11
- import { findWordprocessingChild, mergeXmlnsDeclarations, selectAlternateContentBranch } from "./xmlParser.js";
12
+ import { findWordprocessingChild, getLocalName, mergeXmlnsDeclarations, selectAlternateContentBranch } from "./xmlParser.js";
12
13
  //#region src/docx/blockContentParser.ts
13
14
  const computeListMarker = (paragraph, { numbering, listCounters, abstractCounters, restartedNumIds, previousList }) => {
14
15
  const listRendering = paragraph.listRendering;
@@ -131,6 +132,13 @@ const BLOCK_CONTENT_UNDECLARED = { AlternateContent: (child, { resources: { styl
131
132
  if (!selectedBranch) return;
132
133
  modelled.push(...parseBlockContentWithState(selectedBranch, styles, theme, numbering, rels, media, withContainerXmlns(withContainerXmlns(state, child), selectedBranch)));
133
134
  } };
135
+ const parseBlockCustomXml = (child, styles, theme, numbering, rels, media, state) => {
136
+ return {
137
+ type: "blockCustomXml",
138
+ ...blockCustomXmlShell(child),
139
+ content: parseBlockContentWithState(child, styles, theme, numbering, rels, media, withContainerXmlns(state, child))
140
+ };
141
+ };
134
142
  const BLOCK_CONTENT_HANDLERS = {
135
143
  p: (child, { resources: { styles, theme, numbering, rels, media }, state, modelled }) => {
136
144
  const paragraph = parseParagraph(child, styles, theme, numbering, rels, media, {
@@ -149,12 +157,18 @@ const BLOCK_CONTENT_HANDLERS = {
149
157
  },
150
158
  tbl: (child, { resources: { styles, theme, numbering, rels, media }, state, modelled }) => {
151
159
  const table = parseTable(child, styles, theme, numbering, rels, media, state.options);
152
- if (!table) return;
160
+ if (!table) return child.elements?.some((tableChild) => {
161
+ const localName = getLocalName(tableChild.name ?? "");
162
+ return localName !== "tblPr" && localName !== "tblGrid";
163
+ }) ?? false ? CAPTURE : void 0;
153
164
  modelled.push(table);
154
165
  },
155
166
  sdt: (child, { resources: { styles, theme, numbering, rels, media }, state, modelled }) => {
156
167
  modelled.push(parseBlockSdt(child, styles, theme, numbering, rels, media, state));
157
168
  },
169
+ customXml: (child, { resources: { styles, theme, numbering, rels, media }, state, modelled }) => {
170
+ modelled.push(parseBlockCustomXml(child, styles, theme, numbering, rels, media, state));
171
+ },
158
172
  bookmarkStart: (child, { modelled }) => {
159
173
  modelled.push(parseBookmarkStart(child));
160
174
  },
@@ -165,7 +179,6 @@ const BLOCK_CONTENT_HANDLERS = {
165
179
  altChunk: CAPTURE,
166
180
  commentRangeEnd: CAPTURE,
167
181
  commentRangeStart: CAPTURE,
168
- customXml: CAPTURE,
169
182
  customXmlDelRangeEnd: CAPTURE,
170
183
  customXmlDelRangeStart: CAPTURE,
171
184
  customXmlInsRangeEnd: CAPTURE,
@@ -223,4 +236,4 @@ const parseBlockSdt = (child, styles, theme, numbering, rels, media, state) => {
223
236
  };
224
237
  };
225
238
  //#endregion
226
- export { parseBlockContent };
239
+ export { BLOCK_CONTENT_HANDLERS, parseBlockContent };
@@ -0,0 +1,7 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { XmlElement } from "./xmlParser.js";
3
+ //#region src/docx/blockCustomXmlShell.d.ts
4
+ /** Capture the wrapper independently of its modeled and preserved children. */
5
+ declare const blockCustomXmlShell: (element: XmlElement) => Pick<document_d_exports.BlockCustomXml, "openingXml" | "closingXml">;
6
+ //#endregion
7
+ export { blockCustomXmlShell };
@@ -0,0 +1,14 @@
1
+ import { captureVerbatimXml } from "./verbatimCapture.js";
2
+ import { cloneElement } from "./xmlParser.js";
3
+ //#region src/docx/blockCustomXmlShell.ts
4
+ /** Capture the wrapper independently of its modeled and preserved children. */
5
+ const blockCustomXmlShell = (element) => {
6
+ const shell = captureVerbatimXml(cloneElement(element, { elements: [] }));
7
+ const name = element.name ?? "w:customXml";
8
+ return {
9
+ openingXml: shell.endsWith("/>") ? `${shell.slice(0, -2)}>` : shell,
10
+ closingXml: `</${name}>`
11
+ };
12
+ };
13
+ //#endregion
14
+ export { blockCustomXmlShell };
@@ -1,3 +1,5 @@
1
+ import { ALT_CHUNK_READER_DIAGNOSTIC, isAltChunkMarkup } from "./altChunk.js";
2
+ import { OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC, isOpaqueNestedRowMarkup, opaqueRevisionCarrierName } from "./opaqueCarrier.js";
1
3
  import { getParagraphText } from "./paragraphParser.js";
2
4
  import { panic } from "better-result";
3
5
  //#region src/docx/blockPlainText.ts
@@ -29,9 +31,14 @@ const collectBlockTexts = (blocks) => {
29
31
  }
30
32
  break;
31
33
  case "blockSdt":
34
+ case "blockCustomXml":
32
35
  texts.push(...collectBlockTexts(block.content));
33
36
  break;
34
37
  case "preservedBlock":
38
+ if (isAltChunkMarkup(block.xml)) texts.push(block.readerText === void 0 ? ALT_CHUNK_READER_DIAGNOSTIC : `${ALT_CHUNK_READER_DIAGNOSTIC}\n${block.readerText}`);
39
+ else if (opaqueRevisionCarrierName(block.xml) !== void 0) texts.push(OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC);
40
+ else if (isOpaqueNestedRowMarkup(block.xml)) texts.push("[Unsupported nested w:tr content]");
41
+ break;
35
42
  case "bookmarkStart":
36
43
  case "bookmarkEnd": break;
37
44
  default: panic(`Unsupported block in plain-text extraction: ${JSON.stringify(block)}`);
@@ -19,7 +19,7 @@ const visitCommentMarkers = (blocks, visit) => {
19
19
  for (const row of block.rows) for (const cell of row.cells) visitBlocks(cell.content);
20
20
  return;
21
21
  }
22
- if (block.type !== "blockSdt") return;
22
+ if (block.type !== "blockSdt" && block.type !== "blockCustomXml") return;
23
23
  visitBlocks(block.content);
24
24
  };
25
25
  const visitBlocks = (nested) => {
@@ -1,6 +1,11 @@
1
1
  import { cloneParagraphWithPropertySource } from "./paragraphPropertySource.js";
2
2
  //#region src/docx/commentRangeIntegrity.ts
3
- const COMMENT_RANGE_MARKER_PATTERN = /<w:commentRange(Start|End)\s[^>]*w:id="(\d+)"/gu;
3
+ /**
4
+ * A range marker under any prefix, or none: this is the guard a splice is
5
+ * refused by, and a guard that only knows `w:` passes every patch of a part
6
+ * that spells WordprocessingML another way.
7
+ */
8
+ const COMMENT_RANGE_MARKER_PATTERN = /<(?:[\w.-]+:)?commentRange(Start|End)(?:\s[^>]*?)?\s(?:[\w.-]+:)?id=["'](\d+)["']/gu;
4
9
  /**
5
10
  * Comment ids whose range is not a start followed by an end in this story's
6
11
  * XML. Either half alone is invalid OOXML and anchors nothing: Word shows no
@@ -147,7 +152,7 @@ const withoutOrphanBlockMarkers = (blocks, validCommentIds) => {
147
152
  const withoutOrphanBlockMarker = (block, validCommentIds) => {
148
153
  if (block.type === "paragraph") return withoutOrphanParagraphMarkers(block, validCommentIds);
149
154
  if (block.type === "table") return withoutOrphanTableMarkers(block, validCommentIds);
150
- if (block.type !== "blockSdt") return block;
155
+ if (block.type !== "blockSdt" && block.type !== "blockCustomXml") return block;
151
156
  const content = withoutOrphanBlockMarkers(block.content, validCommentIds);
152
157
  if (!content) return block;
153
158
  return {
@@ -204,7 +209,7 @@ const withoutOrphanTableCellBlockMarkers = (blocks, validCommentIds) => {
204
209
  const withoutOrphanTableCellBlockMarker = (block, validCommentIds) => {
205
210
  if (block.type === "paragraph") return withoutOrphanParagraphMarkers(block, validCommentIds);
206
211
  if (block.type === "table") return withoutOrphanTableMarkers(block, validCommentIds);
207
- if (block.type === "blockSdt") {
212
+ if (block.type === "blockSdt" || block.type === "blockCustomXml") {
208
213
  const content = withoutOrphanTableCellBlockMarkers(block.content, validCommentIds);
209
214
  return content ? {
210
215
  ...block,
@@ -40,7 +40,7 @@ const normalizeCommentReferences = ({ documentBody, comments, headers, footers,
40
40
  normalizeTable(block);
41
41
  return;
42
42
  }
43
- if (block.type !== "blockSdt") return;
43
+ if (block.type !== "blockSdt" && block.type !== "blockCustomXml") return;
44
44
  normalizeBlocks(block.content);
45
45
  };
46
46
  const normalizeBlocks = (blocks) => {