@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,4 +1,5 @@
1
1
  import { NO_MODELLED_ATTRIBUTES, attributeRemainder } from "./attributeRemainder.js";
2
+ import { blockCustomXmlShell } from "./blockCustomXmlShell.js";
2
3
  import { parseBookmarkEnd, parseBookmarkStart } from "./bookmarkParser.js";
3
4
  import { parseBorderSpec } from "./borderParser.js";
4
5
  import { CAPTURE, dispatchChildrenWithContext, keptUnless, ownedElsewhere, sequencePositions, withPreservedChildren } from "./containerChildren.js";
@@ -14,6 +15,7 @@ import { parsePropertyChangeInfo, parseTrackedChangeInfo } from "./trackedChange
14
15
  import { percentageSpelling, transitionalSlotEncoding } from "./transitionalSpelling.js";
15
16
  import { captureVerbatimXml } from "./verbatimCapture.js";
16
17
  import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findChild, findChildren, findWordprocessingChild, getAttribute, getAttributeByNamespaceUri, getLocalName, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute, parseOnOffAttribute, parseTableMeasurementValue, selectAlternateContentBranch } from "./xmlParser.js";
18
+ import { PARSE_WARNING_CODES } from "@stll/docx-core/model";
17
19
  //#region src/docx/tableParser.ts
18
20
  /**
19
21
  * Sanity cap on `w:gridSpan` (and the derived table column count). Word's
@@ -556,6 +558,12 @@ function parseTableCellVerticalMergeRevisionValue(value) {
556
558
  if (value === "cont") return "continue";
557
559
  if (value === "rest") return "rest";
558
560
  }
561
+ function isTableCellMergeRevisionValue(value) {
562
+ return value === "continue" || value === "rest";
563
+ }
564
+ function isTableCellMergeRevisionContinuation(value) {
565
+ return value === "continue";
566
+ }
559
567
  const ROW_PROPERTY_HANDLERS = {
560
568
  cnfStyle: (child, formatting) => {
561
569
  const conditionalFormat = parseConditionalFormatStyle(child);
@@ -755,13 +763,35 @@ function parseTableCellProperties(tcPrElement) {
755
763
  if (preserved) formatting.preserved = preserved;
756
764
  return withSourceXml(formatting, tcPrElement);
757
765
  }
766
+ const createCustomXmlWrapper = (element, identity) => ({
767
+ id: identity.next++,
768
+ ...blockCustomXmlShell(element)
769
+ });
770
+ const recordCustomXmlWrapper = (wrapped, wrapper) => {
771
+ for (const item of wrapped) item.carrierStack = [{
772
+ type: "customXml",
773
+ wrapper
774
+ }, ...item.carrierStack ?? []];
775
+ };
758
776
  const recordContentControl = (wrapped, carriers, sdtElement) => {
759
777
  const properties = parseSdtProperties(findWordprocessingChild(sdtElement, "sdtPr"), findWordprocessingChild(sdtElement, "sdtEndPr"));
760
778
  const siblings = captureSdtSiblingMarkers(sdtElement);
761
779
  if (siblings.before.length > 0) properties.rawSdtChildrenBeforeContent = siblings.before;
762
780
  if (siblings.after.length > 0) properties.rawSdtChildrenAfterContent = siblings.after;
763
- for (const item of wrapped) item.contentControls = [properties, ...item.contentControls ?? []];
764
- for (const item of carriers) item.contentControls = [properties, ...item.contentControls ?? []];
781
+ for (const item of wrapped) {
782
+ item.contentControls = [properties, ...item.contentControls ?? []];
783
+ item.carrierStack = [{
784
+ type: "sdt",
785
+ properties
786
+ }, ...item.carrierStack ?? []];
787
+ }
788
+ for (const item of carriers) {
789
+ item.contentControls = [properties, ...item.contentControls ?? []];
790
+ item.carrierStack = [{
791
+ type: "sdt",
792
+ properties
793
+ }, ...item.carrierStack ?? []];
794
+ }
765
795
  };
766
796
  /**
767
797
  * Accumulate a table container's own `xmlns:*` onto the inherited in-scope set,
@@ -779,7 +809,7 @@ const findLastFlowBlock = (blocks) => {
779
809
  for (let index = blocks.length - 1; index >= 0; index -= 1) {
780
810
  const block = blocks[index];
781
811
  if (block?.type === "paragraph" || block?.type === "table") return block;
782
- if (block?.type === "blockSdt") {
812
+ if (block?.type === "blockSdt" || block?.type === "blockCustomXml") {
783
813
  const nested = findLastFlowBlock(block.content);
784
814
  if (nested) return nested;
785
815
  }
@@ -825,6 +855,19 @@ const CELL_CONTENT_HANDLERS = {
825
855
  })
826
856
  });
827
857
  },
858
+ customXml: (child, { resources, options, modelled }) => {
859
+ const customXml = {
860
+ type: "blockCustomXml",
861
+ ...blockCustomXmlShell(child),
862
+ content: parseCellChildren({
863
+ element: child,
864
+ resources,
865
+ options: withContainerXmlns(options, child),
866
+ requireTrailingParagraph: false
867
+ })
868
+ };
869
+ modelled.push(customXml);
870
+ },
828
871
  bookmarkStart: (child, { modelled }) => {
829
872
  modelled.push(parseBookmarkStart(child));
830
873
  },
@@ -836,7 +879,6 @@ const CELL_CONTENT_HANDLERS = {
836
879
  altChunk: CAPTURE,
837
880
  commentRangeEnd: CAPTURE,
838
881
  commentRangeStart: CAPTURE,
839
- customXml: CAPTURE,
840
882
  customXmlDelRangeEnd: CAPTURE,
841
883
  customXmlDelRangeStart: CAPTURE,
842
884
  customXmlInsRangeEnd: CAPTURE,
@@ -959,6 +1001,21 @@ const ROW_CONTENT_HANDLERS = {
959
1001
  }
960
1002
  recordContentControl(wrapped, [...preservedChildren.slice(firstCaptured), ...bookmarks.slice(firstBookmark)], child);
961
1003
  },
1004
+ customXml: (child, walk) => {
1005
+ const firstWrapped = walk.row.cells.length;
1006
+ const firstCaptured = walk.preservedChildren.length;
1007
+ const firstBookmark = walk.bookmarks.length;
1008
+ dispatchRowChildren(child, walk);
1009
+ if (walk.row.cells.length === firstWrapped) {
1010
+ walk.preservedChildren.splice(firstCaptured);
1011
+ walk.bookmarks.splice(firstBookmark);
1012
+ return CAPTURE;
1013
+ }
1014
+ const wrapper = createCustomXmlWrapper(child, walk.customXmlIdentity);
1015
+ recordCustomXmlWrapper(walk.row.cells.slice(firstWrapped), wrapper);
1016
+ recordCustomXmlWrapper(walk.preservedChildren.slice(firstCaptured), wrapper);
1017
+ recordCustomXmlWrapper(walk.bookmarks.slice(firstBookmark), wrapper);
1018
+ },
962
1019
  bookmarkStart: (child, { row, bookmarks }) => {
963
1020
  bookmarks.push({
964
1021
  index: row.cells.length,
@@ -974,7 +1031,7 @@ const ROW_CONTENT_HANDLERS = {
974
1031
  ...ROW_CHILD_OWNERS,
975
1032
  commentRangeEnd: CAPTURE,
976
1033
  commentRangeStart: CAPTURE,
977
- customXml: CAPTURE,
1034
+ customXmlPr: CAPTURE,
978
1035
  customXmlDelRangeEnd: CAPTURE,
979
1036
  customXmlDelRangeStart: CAPTURE,
980
1037
  customXmlInsRangeEnd: CAPTURE,
@@ -994,7 +1051,13 @@ const ROW_CONTENT_HANDLERS = {
994
1051
  permEnd: CAPTURE,
995
1052
  permStart: CAPTURE,
996
1053
  proofErr: CAPTURE,
997
- tr: CAPTURE
1054
+ tr: (child, { options }) => {
1055
+ options.context?.warn({
1056
+ code: PARSE_WARNING_CODES.nestedRowOpaque,
1057
+ element: child.name ?? "w:tr"
1058
+ });
1059
+ return CAPTURE;
1060
+ }
998
1061
  };
999
1062
  /**
1000
1063
  * One row's children, or a cell-level content control's.
@@ -1055,7 +1118,8 @@ function parseTableRow(trElement, styles, theme, numbering, rels, media, options
1055
1118
  options: withContainerXmlns(options, trElement),
1056
1119
  row,
1057
1120
  bookmarks,
1058
- preservedChildren
1121
+ preservedChildren,
1122
+ customXmlIdentity: { next: 0 }
1059
1123
  });
1060
1124
  if (preservedChildren.length > 0) row.preserved = { children: preservedChildren };
1061
1125
  if (bookmarks.length > 0) row.bookmarks = bookmarks;
@@ -1167,6 +1231,21 @@ const TABLE_CONTENT_HANDLERS = {
1167
1231
  }
1168
1232
  recordContentControl(wrapped, [...preservedChildren.slice(firstCaptured), ...bookmarks.slice(firstBookmark)], child);
1169
1233
  },
1234
+ customXml: (child, walk) => {
1235
+ const firstWrapped = walk.table.rows.length;
1236
+ const firstCaptured = walk.preservedChildren.length;
1237
+ const firstBookmark = walk.bookmarks.length;
1238
+ dispatchTableChildren(child, walk);
1239
+ if (walk.table.rows.length === firstWrapped) {
1240
+ walk.preservedChildren.splice(firstCaptured);
1241
+ walk.bookmarks.splice(firstBookmark);
1242
+ return CAPTURE;
1243
+ }
1244
+ const wrapper = createCustomXmlWrapper(child, walk.customXmlIdentity);
1245
+ recordCustomXmlWrapper(walk.table.rows.slice(firstWrapped), wrapper);
1246
+ recordCustomXmlWrapper(walk.preservedChildren.slice(firstCaptured), wrapper);
1247
+ recordCustomXmlWrapper(walk.bookmarks.slice(firstBookmark), wrapper);
1248
+ },
1170
1249
  ...TABLE_CHILD_OWNERS,
1171
1250
  bookmarkStart: (child, { table, bookmarks }) => {
1172
1251
  bookmarks.push({
@@ -1182,7 +1261,6 @@ const TABLE_CONTENT_HANDLERS = {
1182
1261
  },
1183
1262
  commentRangeEnd: CAPTURE,
1184
1263
  commentRangeStart: CAPTURE,
1185
- customXml: CAPTURE,
1186
1264
  customXmlPr: CAPTURE,
1187
1265
  customXmlDelRangeEnd: CAPTURE,
1188
1266
  customXmlDelRangeStart: CAPTURE,
@@ -1269,7 +1347,8 @@ function parseTable(tblElement, styles, theme, numbering, rels, media, options)
1269
1347
  table,
1270
1348
  rowsWithGridOffsets,
1271
1349
  bookmarks,
1272
- preservedChildren
1350
+ preservedChildren,
1351
+ customXmlIdentity: { next: 0 }
1273
1352
  });
1274
1353
  if (table.rows.length === 0) return;
1275
1354
  if (preservedChildren.length > 0) table.preserved = { children: preservedChildren };
@@ -1382,4 +1461,4 @@ function isFloatingTable(table) {
1382
1461
  return table.formatting?.floating !== void 0;
1383
1462
  }
1384
1463
  //#endregion
1385
- export { MAX_TABLE_COLUMNS, getHeaderRows, getTableColumnCount, getTableRowCount, getTableText, hasHeaderRow, isCellHorizontallyMerged, isCellMergeContinuation, isCellMergeStart, isFloatingTable, parseCellMargins, parseConditionalFormatStyle, parseFloatingTableProperties, parseTable, parseTableBorders, parseTableCell, parseTableCellProperties, parseTableGrid, parseTableLook, parseTableMeasurement, parseTableProperties, parseTablePropertyExceptions, parseTableRow, parseTableRowProperties };
1464
+ export { CELL_CONTENT_HANDLERS, MAX_TABLE_COLUMNS, ROW_CONTENT_HANDLERS, TABLE_CONTENT_HANDLERS, getHeaderRows, getTableColumnCount, getTableRowCount, getTableText, hasHeaderRow, isCellHorizontallyMerged, isCellMergeContinuation, isCellMergeStart, isFloatingTable, isTableCellMergeRevisionContinuation, isTableCellMergeRevisionValue, parseCellMargins, parseConditionalFormatStyle, parseFloatingTableProperties, parseTable, parseTableBorders, parseTableCell, parseTableCellProperties, parseTableGrid, parseTableLook, parseTableMeasurement, parseTableProperties, parseTablePropertyExceptions, parseTableRow, parseTableRowProperties };
@@ -300,7 +300,7 @@ const getTextBoxBlockText = (block) => {
300
300
  return runTexts.join("");
301
301
  }
302
302
  if (block.type === "table") return block.rows.map((row) => row.cells.map((cell) => cell.content.map(getTextBoxBlockText).join("\n")).join(" ")).join("\n");
303
- if (block.type !== "blockSdt") return "";
303
+ if (block.type !== "blockSdt" && block.type !== "blockCustomXml") return "";
304
304
  return block.content.map(getTextBoxBlockText).join("\n");
305
305
  };
306
306
  /**
@@ -82,6 +82,7 @@ type RawDocxContent = {
82
82
  * @returns Promise resolving to extracted content
83
83
  */
84
84
  declare function unzipDocx(buffer: ArrayBuffer, options?: DocxUnzipOptions): Promise<RawDocxContent>;
85
+ declare function getEntryUncompressedSize(file: JSZip.JSZipObject): number | null;
85
86
  /**
86
87
  * Get a list of all files in the DOCX
87
88
  *
@@ -142,4 +143,4 @@ declare function getContentSummary(content: RawDocxContent): {
142
143
  totalFiles: number;
143
144
  };
144
145
  //#endregion
145
- export { DocxSecurityError, DocxUnzipLimits, DocxUnzipOptions, RawDocxContent, extractFile, getContentSummary, getFileList, getMediaMimeType, hasFile, mediaToDataUrl, unzipDocx };
146
+ export { DocxSecurityError, DocxUnzipLimits, DocxUnzipOptions, RawDocxContent, extractFile, getContentSummary, getEntryUncompressedSize, getFileList, getMediaMimeType, hasFile, mediaToDataUrl, unzipDocx };
@@ -494,4 +494,4 @@ function getContentSummary(content) {
494
494
  };
495
495
  }
496
496
  //#endregion
497
- export { DocxSecurityError, extractFile, getContentSummary, getFileList, getMediaMimeType, hasFile, mediaToDataUrl, unzipDocx };
497
+ export { DocxSecurityError, extractFile, getContentSummary, getEntryUncompressedSize, getFileList, getMediaMimeType, hasFile, mediaToDataUrl, unzipDocx };
@@ -0,0 +1,78 @@
1
+ //#region src/docx/wordprocessingPrefixes.d.ts
2
+ /**
3
+ * Which prefixes a WordprocessingML part spells its namespaces with.
4
+ *
5
+ * A prefix is an alias: `<w:p>`, `<x:p>` and an unprefixed `<p>` under a
6
+ * default namespace are the same paragraph when the prefix (or the default)
7
+ * is bound to the WordprocessingML URI. The parser resolves names by URI, so
8
+ * every such package opens. The patchers that work on part XML as a string
9
+ * (`ensureParaIds`, the selective-save splices) find elements by their
10
+ * literal tags instead, and a literal `<w:p` finds nothing in a part that
11
+ * spells it `<x:p`: the patch reports success having touched nothing.
12
+ *
13
+ * {@link resolveWordprocessingPrefixes} is the one place those patchers ask
14
+ * how a part spells WordprocessingML, the `w14` extensions and
15
+ * markup compatibility (`mc`). A patcher either scans with every prefix the
16
+ * part binds, or checks the names its literal scan needs in their namespace
17
+ * scope. A prefix conflict on one of those names is refused.
18
+ */
19
+ /** How one part spells the namespaces a string-level patcher scans for. */
20
+ type WordprocessingPrefixes = {
21
+ /**
22
+ * Prefixes bound to WordprocessingML (Transitional or Strict), `""` for the
23
+ * default namespace. Never empty: an undeclared part reads as `w`.
24
+ */
25
+ main: readonly string[];
26
+ /** Prefixes bound to the `w14` extensions namespace. */
27
+ w14: readonly string[];
28
+ /** Whether a `w14` prefix is declared on the root (else `w14` is assumed). */
29
+ w14Declared: boolean;
30
+ /** Prefixes bound to markup compatibility (`mc`). */
31
+ mc: readonly string[];
32
+ /** Whether an `mc` prefix is declared on the root (else `mc` is assumed). */
33
+ mcDeclared: boolean;
34
+ /**
35
+ * The spelling folio's serializer writes: WordprocessingML only as `w`,
36
+ * `w14` and `mc` under their conventional prefixes. Splicing serializer
37
+ * output into a part is only sound when this holds.
38
+ */
39
+ canonical: boolean;
40
+ };
41
+ type WordprocessingPrefixResolution = {
42
+ type: "resolved";
43
+ prefixes: WordprocessingPrefixes;
44
+ } | {
45
+ type: "unsupported";
46
+ reason: string;
47
+ };
48
+ declare const resolveWordprocessingPrefixes: (xml: string) => WordprocessingPrefixResolution;
49
+ /** Root spelling for a selective scan whose relevant nested names are checked separately. */
50
+ declare const resolveSelectiveScanPrefixes: (xml: string) => WordprocessingPrefixResolution;
51
+ /**
52
+ * Whether a patcher that reads `<w:…>` literally sees every element it looks
53
+ * for in `xml`, and may splice the serializer's `w:` markup into it.
54
+ *
55
+ * True for the canonical spelling. Also true when the part binds
56
+ * WordprocessingML under an extra prefix besides `w` but never spells the
57
+ * names the patcher scans under that alias, or binds markup compatibility
58
+ * under another prefix. Relevant nested names are checked in their own scope.
59
+ */
60
+ declare const splicesAsCanonical: (xml: string, localNames: readonly string[]) => boolean;
61
+ /** The names the paragraph splices scan for: paragraphs, their containers and ids. */
62
+ declare const PARAGRAPH_SCAN_NAMES: readonly ["p", "tc", "txbxContent", "paraId", "textId"];
63
+ /** Whether `xml` spells WordprocessingML the way folio's serializer does. */
64
+ declare const hasCanonicalWordprocessingPrefixes: (xml: string) => boolean;
65
+ /** `<p`, `<w:p`, … — the open-tag literal of `localName` under `prefix`. */
66
+ declare const openTagLiteral: (prefix: string, localName: string) => string;
67
+ /** `</p>`, `</w:p>`, … — the close-tag literal of `localName` under `prefix`. */
68
+ declare const closeTagLiteral: (prefix: string, localName: string) => string;
69
+ /**
70
+ * Whether `xml` opens `localName` under one of `prefixes` at `start`, and the
71
+ * length of the literal that matched (`-1` when none did). The character after
72
+ * the name must end it, so `<w:pPr` is not `<w:p`.
73
+ */
74
+ declare const matchOpenTag: (xml: string, start: number, prefixes: readonly string[], localName: string) => number;
75
+ /** The length of the close tag of `localName` under one of `prefixes` at `start`, or -1. */
76
+ declare const matchCloseTag: (xml: string, start: number, prefixes: readonly string[], localName: string) => number;
77
+ //#endregion
78
+ export { PARAGRAPH_SCAN_NAMES, WordprocessingPrefixResolution, WordprocessingPrefixes, closeTagLiteral, hasCanonicalWordprocessingPrefixes, matchCloseTag, matchOpenTag, openTagLiteral, resolveSelectiveScanPrefixes, resolveWordprocessingPrefixes, splicesAsCanonical };
@@ -0,0 +1,286 @@
1
+ import { NAMESPACES, WORDPROCESSINGML_NAMESPACE_URIS, getLocalName, getNamespacePrefix, getNamespaceUri, parseXmlDocument, resolveAttributeNamespaceUri } from "./xmlParser.js";
2
+ //#region src/docx/wordprocessingPrefixes.ts
3
+ /**
4
+ * Which prefixes a WordprocessingML part spells its namespaces with.
5
+ *
6
+ * A prefix is an alias: `<w:p>`, `<x:p>` and an unprefixed `<p>` under a
7
+ * default namespace are the same paragraph when the prefix (or the default)
8
+ * is bound to the WordprocessingML URI. The parser resolves names by URI, so
9
+ * every such package opens. The patchers that work on part XML as a string
10
+ * (`ensureParaIds`, the selective-save splices) find elements by their
11
+ * literal tags instead, and a literal `<w:p` finds nothing in a part that
12
+ * spells it `<x:p`: the patch reports success having touched nothing.
13
+ *
14
+ * {@link resolveWordprocessingPrefixes} is the one place those patchers ask
15
+ * how a part spells WordprocessingML, the `w14` extensions and
16
+ * markup compatibility (`mc`). A patcher either scans with every prefix the
17
+ * part binds, or checks the names its literal scan needs in their namespace
18
+ * scope. A prefix conflict on one of those names is refused.
19
+ */
20
+ const XMLNS = "xmlns";
21
+ const isWhitespace = (character) => character === " " || character === " " || character === "\n" || character === "\r";
22
+ /** End offset (exclusive) of the tag opening at `start`, skipping quoted values. */
23
+ const tagEnd = (xml, start) => {
24
+ let quote = null;
25
+ for (let index = start + 1; index < xml.length; index += 1) {
26
+ const character = xml[index];
27
+ if (quote !== null) {
28
+ if (character === quote) quote = null;
29
+ continue;
30
+ }
31
+ if (character === "\"" || character === "'") quote = character;
32
+ else if (character === ">") return index + 1;
33
+ }
34
+ return -1;
35
+ };
36
+ /** The `xmlns` / `xmlns:*` declarations written in one start tag. */
37
+ const declarationsIn = (tag) => {
38
+ const declarations = [];
39
+ for (const match of tag.matchAll(/\sxmlns(?::(?<prefix>[^\s=/>]+))?\s*=\s*(?<quote>["'])(?<uri>[\s\S]*?)\k<quote>/gu)) declarations.push({
40
+ prefix: match.groups?.["prefix"] ?? "",
41
+ uri: match.groups?.["uri"] ?? ""
42
+ });
43
+ return declarations;
44
+ };
45
+ const OPAQUE_REGIONS = [
46
+ {
47
+ open: "<!--",
48
+ close: "-->"
49
+ },
50
+ {
51
+ open: "<![CDATA[",
52
+ close: "]]>"
53
+ },
54
+ {
55
+ open: "<?",
56
+ close: "?>"
57
+ }
58
+ ];
59
+ /** Visit every start tag of `xml` that declares a namespace, root first. */
60
+ const visitDeclaringStartTags = (xml, visit) => {
61
+ let seenRoot = false;
62
+ let pos = 0;
63
+ scan: while (pos < xml.length) {
64
+ const start = xml.indexOf("<", pos);
65
+ if (start === -1) break;
66
+ for (const { open, close } of OPAQUE_REGIONS) if (xml.startsWith(open, start)) {
67
+ const closeStart = xml.indexOf(close, start + open.length);
68
+ if (closeStart === -1) return false;
69
+ pos = closeStart + close.length;
70
+ continue scan;
71
+ }
72
+ const next = xml[start + 1];
73
+ if (next === "!" || next === "/") {
74
+ const end = xml.indexOf(">", start);
75
+ if (end === -1) return false;
76
+ pos = end + 1;
77
+ continue;
78
+ }
79
+ const end = tagEnd(xml, start);
80
+ if (end === -1) return false;
81
+ const isRoot = !seenRoot;
82
+ seenRoot = true;
83
+ const tag = xml.slice(start, end);
84
+ if (isRoot || tag.includes(XMLNS)) visit(tag, isRoot);
85
+ pos = end;
86
+ }
87
+ return seenRoot;
88
+ };
89
+ const MAIN_URIS = WORDPROCESSINGML_NAMESPACE_URIS;
90
+ const W14_URI = NAMESPACES.w14;
91
+ const MC_URI = NAMESPACES.mc;
92
+ const NESTED_BINDINGS = {
93
+ strict: "strict",
94
+ scoped: "scoped"
95
+ };
96
+ const slotOf = (uri) => {
97
+ if (MAIN_URIS.has(uri)) return "main";
98
+ if (uri === W14_URI) return "w14";
99
+ if (uri === MC_URI) return "mc";
100
+ return null;
101
+ };
102
+ const CONVENTIONAL_PREFIX = {
103
+ main: "w",
104
+ w14: "w14",
105
+ mc: "mc"
106
+ };
107
+ /**
108
+ * Resolve the prefixes `xml` binds to WordprocessingML, `w14` and `mc`.
109
+ *
110
+ * Root declarations decide. A namespace the root never declares is read under
111
+ * its conventional prefix, the tolerant reading of a malformed part. A declaration on
112
+ * a nested element is accepted only when it repeats a binding the scan already
113
+ * uses; anything else changes what a literal tag means partway through the
114
+ * part and is reported as unsupported.
115
+ */
116
+ const resolvePrefixes = (xml, nestedBindings) => {
117
+ const bound = {
118
+ main: [],
119
+ w14: [],
120
+ mc: []
121
+ };
122
+ const rootPrefixes = /* @__PURE__ */ new Map();
123
+ const nested = [];
124
+ if (!visitDeclaringStartTags(xml, (tag, isRoot) => {
125
+ for (const declaration of declarationsIn(tag)) {
126
+ if (!isRoot) {
127
+ nested.push(declaration);
128
+ continue;
129
+ }
130
+ rootPrefixes.set(declaration.prefix, declaration.uri);
131
+ const slot = slotOf(declaration.uri);
132
+ if (slot !== null) bound[slot].push(declaration.prefix);
133
+ }
134
+ })) return {
135
+ type: "unsupported",
136
+ reason: "no root element or unterminated markup"
137
+ };
138
+ const declared = {
139
+ main: bound.main.length > 0,
140
+ w14: bound.w14.length > 0,
141
+ mc: bound.mc.length > 0
142
+ };
143
+ for (const slot of [
144
+ "main",
145
+ "w14",
146
+ "mc"
147
+ ]) {
148
+ if (declared[slot]) {
149
+ if (slot !== "main" && bound[slot].includes("")) return {
150
+ type: "unsupported",
151
+ reason: `${slot} is bound only as the default namespace`
152
+ };
153
+ continue;
154
+ }
155
+ const conventional = CONVENTIONAL_PREFIX[slot];
156
+ if (rootPrefixes.has(conventional)) {
157
+ if (slot === "main") return {
158
+ type: "unsupported",
159
+ reason: `no WordprocessingML binding; ${conventional} is bound to another namespace`
160
+ };
161
+ continue;
162
+ }
163
+ bound[slot].push(conventional);
164
+ }
165
+ const inUse = /* @__PURE__ */ new Map();
166
+ for (const slot of [
167
+ "main",
168
+ "w14",
169
+ "mc"
170
+ ]) for (const prefix of bound[slot]) inUse.set(prefix, slot);
171
+ for (const { prefix, uri } of nestedBindings === NESTED_BINDINGS.strict ? nested : []) {
172
+ const slot = slotOf(uri);
173
+ const spelling = prefix === "" ? "the default namespace" : `prefix ${prefix}`;
174
+ if (slot !== null) {
175
+ if (!bound[slot].includes(prefix)) return {
176
+ type: "unsupported",
177
+ reason: `a nested element binds ${slot} under ${spelling}`
178
+ };
179
+ continue;
180
+ }
181
+ if (inUse.has(prefix)) return {
182
+ type: "unsupported",
183
+ reason: `a nested element rebinds ${spelling} to ${uri === "" ? "no namespace" : uri}`
184
+ };
185
+ }
186
+ const only = (prefixes, prefix) => prefixes.length === 1 && prefixes[0] === prefix;
187
+ const canonical = only(bound.main, "w") && only(bound.w14, "w14") && only(bound.mc, "mc");
188
+ return {
189
+ type: "resolved",
190
+ prefixes: {
191
+ main: bound.main,
192
+ w14: bound.w14,
193
+ w14Declared: declared.w14,
194
+ mc: bound.mc,
195
+ mcDeclared: declared.mc,
196
+ canonical
197
+ }
198
+ };
199
+ };
200
+ const resolveWordprocessingPrefixes = (xml) => resolvePrefixes(xml, NESTED_BINDINGS.strict);
201
+ /** Root spelling for a selective scan whose relevant nested names are checked separately. */
202
+ const resolveSelectiveScanPrefixes = (xml) => resolvePrefixes(xml, NESTED_BINDINGS.scoped);
203
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
204
+ /**
205
+ * Whether a patcher that reads `<w:…>` literally sees every element it looks
206
+ * for in `xml`, and may splice the serializer's `w:` markup into it.
207
+ *
208
+ * True for the canonical spelling. Also true when the part binds
209
+ * WordprocessingML under an extra prefix besides `w` but never spells the
210
+ * names the patcher scans under that alias, or binds markup compatibility
211
+ * under another prefix. Relevant nested names are checked in their own scope.
212
+ */
213
+ const splicesAsCanonical = (xml, localNames) => {
214
+ const resolution = resolveWordprocessingPrefixes(xml);
215
+ if (resolution.type === "resolved" && resolution.prefixes.canonical) return true;
216
+ const relaxed = resolveSelectiveScanPrefixes(xml);
217
+ if (relaxed.type !== "resolved") return false;
218
+ const { prefixes } = relaxed;
219
+ const only = (list, prefix) => list.length === 1 && list[0] === prefix;
220
+ const aliases = prefixes.main.filter((prefix) => prefix !== "w");
221
+ if (!prefixes.main.includes("w") || aliases.includes("") || !only(prefixes.w14, "w14") || prefixes.mc.length === 0) return false;
222
+ const names = localNames.map(escapeRegExp).join("|");
223
+ if (!aliases.every((alias) => !new RegExp(`[<\\s/]${escapeRegExp(alias)}:(?:${names})[\\s/>=]`, "u").test(xml))) return false;
224
+ const root = parseXmlDocument(xml);
225
+ if (!root) return false;
226
+ const mainNames = new Set(localNames.filter((name) => name !== "paraId" && name !== "textId"));
227
+ const idNames = /* @__PURE__ */ new Set(["paraId", "textId"]);
228
+ const mcNames = /* @__PURE__ */ new Set(["Fallback", "AlternateContent"]);
229
+ const visit = (element) => {
230
+ if (element.type !== "element") return true;
231
+ const name = element.name ?? "";
232
+ const local = getLocalName(name);
233
+ const prefix = getNamespacePrefix(name) ?? "";
234
+ const uri = getNamespaceUri(element) ?? "";
235
+ if (prefix === "mc" && uri !== MC_URI || mainNames.has(local) && WORDPROCESSINGML_NAMESPACE_URIS.has(uri) !== (prefix === "w") || mcNames.has(local) && uri === MC_URI !== prefixes.mc.includes(prefix)) return false;
236
+ for (const attribute of Object.keys(element.attributes ?? {})) {
237
+ const attributePrefix = getNamespacePrefix(attribute);
238
+ if (attributePrefix === "mc" && resolveAttributeNamespaceUri(element, attribute) !== MC_URI) return false;
239
+ if (!idNames.has(getLocalName(attribute))) continue;
240
+ if (resolveAttributeNamespaceUri(element, attribute) === W14_URI !== (attributePrefix === "w14")) return false;
241
+ }
242
+ return (element.elements ?? []).every(visit);
243
+ };
244
+ return visit(root);
245
+ };
246
+ /** The names the paragraph splices scan for: paragraphs, their containers and ids. */
247
+ const PARAGRAPH_SCAN_NAMES = [
248
+ "p",
249
+ "tc",
250
+ "txbxContent",
251
+ "paraId",
252
+ "textId"
253
+ ];
254
+ /** Whether `xml` spells WordprocessingML the way folio's serializer does. */
255
+ const hasCanonicalWordprocessingPrefixes = (xml) => {
256
+ const resolution = resolveWordprocessingPrefixes(xml);
257
+ return resolution.type === "resolved" && resolution.prefixes.canonical;
258
+ };
259
+ /** `<p`, `<w:p`, … — the open-tag literal of `localName` under `prefix`. */
260
+ const openTagLiteral = (prefix, localName) => prefix === "" ? `<${localName}` : `<${prefix}:${localName}`;
261
+ /** `</p>`, `</w:p>`, … — the close-tag literal of `localName` under `prefix`. */
262
+ const closeTagLiteral = (prefix, localName) => prefix === "" ? `</${localName}>` : `</${prefix}:${localName}>`;
263
+ /**
264
+ * Whether `xml` opens `localName` under one of `prefixes` at `start`, and the
265
+ * length of the literal that matched (`-1` when none did). The character after
266
+ * the name must end it, so `<w:pPr` is not `<w:p`.
267
+ */
268
+ const matchOpenTag = (xml, start, prefixes, localName) => {
269
+ for (const prefix of prefixes) {
270
+ const literal = openTagLiteral(prefix, localName);
271
+ if (!xml.startsWith(literal, start)) continue;
272
+ const after = xml[start + literal.length];
273
+ if (after === ">" || after === "/" || isWhitespace(after)) return literal.length;
274
+ }
275
+ return -1;
276
+ };
277
+ /** The length of the close tag of `localName` under one of `prefixes` at `start`, or -1. */
278
+ const matchCloseTag = (xml, start, prefixes, localName) => {
279
+ for (const prefix of prefixes) {
280
+ const literal = closeTagLiteral(prefix, localName);
281
+ if (xml.startsWith(literal, start)) return literal.length;
282
+ }
283
+ return -1;
284
+ };
285
+ //#endregion
286
+ export { PARAGRAPH_SCAN_NAMES, closeTagLiteral, hasCanonicalWordprocessingPrefixes, matchCloseTag, matchOpenTag, openTagLiteral, resolveSelectiveScanPrefixes, resolveWordprocessingPrefixes, splicesAsCanonical };