@a3s-lab/office 0.2.2 → 0.4.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 (277) hide show
  1. package/COLLABORATION_ROADMAP.md +426 -0
  2. package/README.md +649 -10
  3. package/dist/0~1403.js +1 -1
  4. package/dist/0~2805.js +1279 -0
  5. package/dist/{0~use-office-draft.js → 0~345.js} +30 -1
  6. package/dist/0~3539.js +1 -1
  7. package/dist/0~3557.js +1 -1
  8. package/dist/0~3635.js +1 -1
  9. package/dist/0~4595.js +123 -12
  10. package/dist/0~4980.js +154 -0
  11. package/dist/0~5050.js +124 -113
  12. package/dist/{0~9512.js → 0~6090.js} +540 -3
  13. package/dist/0~7048.js +92 -66
  14. package/dist/0~7614.js +2 -1
  15. package/dist/0~7754.js +5653 -0
  16. package/dist/0~9445.js +1 -1
  17. package/dist/0~document-editor.js +4992 -3323
  18. package/dist/0~markdown-editor.js +250 -44
  19. package/dist/0~pdf-viewer.js +1016 -24
  20. package/dist/0~presentation-editor.js +179 -8
  21. package/dist/0~spreadsheet-editor.js +3371 -578
  22. package/dist/0~work-docx-export.js +6801 -658
  23. package/dist/0~work-docx-import.js +1388 -795
  24. package/dist/0~work-office-diagnostics.js +524 -30
  25. package/dist/0~work-pptx-export.js +2 -1
  26. package/dist/0~work-pptx-import.js +1 -2
  27. package/dist/0~work-presentation-charts.js +1 -1
  28. package/dist/2591.js +197 -0
  29. package/dist/3818.js +1090 -0
  30. package/dist/4104.js +970 -60
  31. package/dist/432.js +171 -14
  32. package/dist/4476.js +2008 -0
  33. package/dist/4560.js +674 -0
  34. package/dist/4650.js +70 -0
  35. package/dist/{1134.js → 5184.js} +183 -1
  36. package/dist/6489.js +18 -18
  37. package/dist/7060.js +132 -0
  38. package/dist/8715.js +2 -136
  39. package/dist/8928.js +16778 -0
  40. package/dist/9787.js +209 -0
  41. package/dist/core.d.ts +29 -9
  42. package/dist/core.js +10 -2
  43. package/dist/index.js +13 -3
  44. package/dist/internal/collaboration/office-collaboration-flat-json.d.ts +13 -0
  45. package/dist/internal/collaboration/office-collaboration-json.d.ts +4 -0
  46. package/dist/internal/collaboration/office-collaboration-presence.d.ts +86 -0
  47. package/dist/internal/collaboration/office-collaboration-transport.d.ts +42 -0
  48. package/dist/internal/collaboration/office-collaboration.d.ts +85 -0
  49. package/dist/internal/collaboration/office-document-collaboration-bibliography.d.ts +7 -0
  50. package/dist/internal/collaboration/office-document-collaboration-claims.d.ts +9 -0
  51. package/dist/internal/collaboration/office-document-collaboration-comments.d.ts +7 -0
  52. package/dist/internal/collaboration/office-document-collaboration-sidecar-utils.d.ts +27 -0
  53. package/dist/internal/collaboration/office-document-collaboration-sidecars.d.ts +16 -0
  54. package/dist/internal/collaboration/office-document-collaboration.d.ts +45 -0
  55. package/dist/internal/collaboration/office-markdown-collaboration.d.ts +31 -0
  56. package/dist/internal/collaboration/office-pdf-collaboration-claims.d.ts +4 -0
  57. package/dist/internal/collaboration/office-pdf-collaboration-conflicts.d.ts +2 -0
  58. package/dist/internal/collaboration/office-pdf-collaboration-model.d.ts +26 -0
  59. package/dist/internal/collaboration/office-pdf-collaboration-records.d.ts +21 -0
  60. package/dist/internal/collaboration/office-pdf-collaboration-types.d.ts +91 -0
  61. package/dist/internal/collaboration/office-pdf-collaboration-validation.d.ts +4 -0
  62. package/dist/internal/collaboration/office-pdf-collaboration.d.ts +35 -0
  63. package/dist/internal/collaboration/office-presentation-collaboration-model.d.ts +25 -0
  64. package/dist/internal/collaboration/office-presentation-collaboration-records.d.ts +22 -0
  65. package/dist/internal/collaboration/office-presentation-collaboration-validation.d.ts +4 -0
  66. package/dist/internal/collaboration/office-presentation-collaboration.d.ts +32 -0
  67. package/dist/internal/collaboration/office-spreadsheet-collaboration-cells.d.ts +13 -0
  68. package/dist/internal/collaboration/office-spreadsheet-collaboration-claims.d.ts +4 -0
  69. package/dist/internal/collaboration/office-spreadsheet-collaboration-conflicts.d.ts +2 -0
  70. package/dist/internal/collaboration/office-spreadsheet-collaboration-flat-json.d.ts +10 -0
  71. package/dist/internal/collaboration/office-spreadsheet-collaboration-model.d.ts +31 -0
  72. package/dist/internal/collaboration/office-spreadsheet-collaboration-records.d.ts +17 -0
  73. package/dist/internal/collaboration/office-spreadsheet-collaboration-validation.d.ts +4 -0
  74. package/dist/internal/collaboration/office-spreadsheet-collaboration.d.ts +32 -0
  75. package/dist/internal/design-system/primitives/navigation/tabs.d.ts +3 -1
  76. package/dist/internal/features/work/components/work-document-page-border.d.ts +6 -0
  77. package/dist/internal/features/work/editors/document-command-catalog.d.ts +536 -0
  78. package/dist/internal/features/work/editors/document-editor-focus.d.ts +1 -1
  79. package/dist/internal/features/work/editors/document-editor-support.d.ts +7 -3
  80. package/dist/internal/features/work/editors/document-editor.d.ts +8 -2
  81. package/dist/internal/features/work/editors/document-external-content.d.ts +14 -0
  82. package/dist/internal/features/work/editors/document-format-clipboard.d.ts +6 -0
  83. package/dist/internal/features/work/editors/document-format-tools.d.ts +4 -0
  84. package/dist/internal/features/work/editors/document-layout-panel.d.ts +4 -1
  85. package/dist/internal/features/work/editors/document-page-chrome-wps-shortcuts.d.ts +2 -0
  86. package/dist/internal/features/work/editors/document-page-layout-ribbon.d.ts +14 -0
  87. package/dist/internal/features/work/editors/document-page-stack.d.ts +10 -1
  88. package/dist/internal/features/work/editors/document-page-thumbnail.d.ts +2 -0
  89. package/dist/internal/features/work/editors/document-pagination-run-coordinator.d.ts +26 -0
  90. package/dist/internal/features/work/editors/document-picture-properties-dialog-model.d.ts +20 -1
  91. package/dist/internal/features/work/editors/document-review-navigation.d.ts +9 -0
  92. package/dist/internal/features/work/editors/document-statistics-dialog.d.ts +7 -0
  93. package/dist/internal/features/work/editors/document-status-bar.d.ts +2 -1
  94. package/dist/internal/features/work/editors/document-table-properties-dialog-model.d.ts +4 -1
  95. package/dist/internal/features/work/editors/document-toolbar.d.ts +19 -42
  96. package/dist/internal/features/work/editors/document-wps-shortcuts.d.ts +12 -0
  97. package/dist/internal/features/work/editors/document-zoom.d.ts +17 -0
  98. package/dist/internal/features/work/editors/markdown-editor-focus.d.ts +1 -1
  99. package/dist/internal/features/work/editors/markdown-editor.d.ts +5 -1
  100. package/dist/internal/features/work/editors/markdown-toolbar.d.ts +2 -1
  101. package/dist/internal/features/work/editors/office-collaboration-participants.d.ts +3 -0
  102. package/dist/internal/features/work/editors/office-collaboration-presence-context.d.ts +17 -0
  103. package/dist/internal/features/work/editors/office-collaboration-presence-ui.d.ts +25 -0
  104. package/dist/internal/features/work/editors/office-editor-focus-handoff.d.ts +27 -0
  105. package/dist/internal/features/work/editors/pdf-annotation-controller.d.ts +5 -0
  106. package/dist/internal/features/work/editors/pdf-collaboration-presence.d.ts +3 -0
  107. package/dist/internal/features/work/editors/pdf-collaboration-projection.d.ts +10 -0
  108. package/dist/internal/features/work/editors/pdf-evidence-contract.d.ts +36 -0
  109. package/dist/internal/features/work/editors/pdf-evidence-overlay.d.ts +37 -0
  110. package/dist/internal/features/work/editors/pdf-toolbar.d.ts +2 -1
  111. package/dist/internal/features/work/editors/pdf-viewer-controller.d.ts +7 -1
  112. package/dist/internal/features/work/editors/pdf-viewer.d.ts +11 -1
  113. package/dist/internal/features/work/editors/presentation-collaboration-presence.d.ts +5 -0
  114. package/dist/internal/features/work/editors/presentation-editor-focus.d.ts +3 -2
  115. package/dist/internal/features/work/editors/presentation-editor-types.d.ts +3 -0
  116. package/dist/internal/features/work/editors/presentation-editor.d.ts +1 -1
  117. package/dist/internal/features/work/editors/spreadsheet-auto-filter.d.ts +9 -0
  118. package/dist/internal/features/work/editors/spreadsheet-cell-clear.d.ts +3 -0
  119. package/dist/internal/features/work/editors/spreadsheet-cell-merge.d.ts +12 -0
  120. package/dist/internal/features/work/editors/spreadsheet-clipboard-shortcuts.d.ts +3 -7
  121. package/dist/internal/features/work/editors/spreadsheet-collaboration-presence.d.ts +9 -0
  122. package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +464 -0
  123. package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +45 -9
  124. package/dist/internal/features/work/editors/spreadsheet-context-menu.d.ts +2 -0
  125. package/dist/internal/features/work/editors/spreadsheet-editor-ribbon.d.ts +9 -28
  126. package/dist/internal/features/work/editors/spreadsheet-editor.d.ts +8 -2
  127. package/dist/internal/features/work/editors/spreadsheet-format-painter.d.ts +27 -0
  128. package/dist/internal/features/work/editors/spreadsheet-freeze-panes.d.ts +14 -0
  129. package/dist/internal/features/work/editors/use-document-insert-commands.d.ts +3 -2
  130. package/dist/internal/features/work/editors/use-document-pagination.d.ts +6 -1
  131. package/dist/internal/features/work/editors/use-document-review-conflicts.d.ts +28 -0
  132. package/dist/internal/features/work/editors/use-spreadsheet-auto-filter.d.ts +21 -0
  133. package/dist/internal/features/work/editors/use-spreadsheet-collaboration.d.ts +27 -0
  134. package/dist/internal/features/work/editors/use-spreadsheet-format-painter.d.ts +18 -0
  135. package/dist/internal/features/work/editors/work-office-chrome.d.ts +22 -3
  136. package/dist/internal/features/work/editors/work-office-ribbon-overflow.d.ts +2 -0
  137. package/dist/internal/features/work/work-document-bookmark-references.d.ts +37 -0
  138. package/dist/internal/features/work/work-document-bookmarks.d.ts +29 -0
  139. package/dist/internal/features/work/work-document-caption-nodes.d.ts +4 -1
  140. package/dist/internal/features/work/work-document-comments.d.ts +1 -1
  141. package/dist/internal/features/work/work-document-equations.d.ts +513 -0
  142. package/dist/internal/features/work/work-document-extensions.d.ts +1 -0
  143. package/dist/internal/features/work/work-document-field-identity.d.ts +2 -0
  144. package/dist/internal/features/work/work-document-field-node.d.ts +2 -2
  145. package/dist/internal/features/work/work-document-fields.d.ts +7 -0
  146. package/dist/internal/features/work/work-document-image-identity.d.ts +30 -0
  147. package/dist/internal/features/work/work-document-image-layout.d.ts +46 -1
  148. package/dist/internal/features/work/work-document-image-wrap-contour.d.ts +16 -0
  149. package/dist/internal/features/work/work-document-incremental-layout.d.ts +2 -2
  150. package/dist/internal/features/work/work-document-model-codec.d.ts +4 -1
  151. package/dist/internal/features/work/work-document-note-integrity.d.ts +2 -0
  152. package/dist/internal/features/work/work-document-page-borders.d.ts +25 -0
  153. package/dist/internal/features/work/work-document-page-capture.d.ts +8 -0
  154. package/dist/internal/features/work/work-document-page-frames.d.ts +15 -0
  155. package/dist/internal/features/work/work-document-page-margins.d.ts +56 -0
  156. package/dist/internal/features/work/work-document-page-size.d.ts +47 -0
  157. package/dist/internal/features/work/work-document-pagination-measurement.d.ts +1 -2
  158. package/dist/internal/features/work/work-document-pagination-types.d.ts +7 -2
  159. package/dist/internal/features/work/work-document-pagination.d.ts +2 -2
  160. package/dist/internal/features/work/work-document-paragraph-borders.d.ts +32 -0
  161. package/dist/internal/features/work/work-document-paragraph-identity.d.ts +26 -0
  162. package/dist/internal/features/work/work-document-paragraph-shading.d.ts +18 -0
  163. package/dist/internal/features/work/work-document-review-conflicts.d.ts +35 -0
  164. package/dist/internal/features/work/work-document-section.d.ts +4 -0
  165. package/dist/internal/features/work/work-document-snapshot.d.ts +19 -0
  166. package/dist/internal/features/work/work-document-source.d.ts +23 -0
  167. package/dist/internal/features/work/work-document-table-column-widths.d.ts +7 -0
  168. package/dist/internal/features/work/work-document-table-property-changes.d.ts +3 -0
  169. package/dist/internal/features/work/work-document-table-row-identity.d.ts +15 -0
  170. package/dist/internal/features/work/work-document-table-sizing.d.ts +3 -0
  171. package/dist/internal/features/work/work-document-text-layout.d.ts +3 -1
  172. package/dist/internal/features/work/work-document-word-line-metrics.d.ts +2 -0
  173. package/dist/internal/features/work/work-docx-bookmark-diagnostics.d.ts +3 -0
  174. package/dist/internal/features/work/work-docx-bookmark-import.d.ts +24 -0
  175. package/dist/internal/features/work/work-docx-bookmarks.d.ts +17 -0
  176. package/dist/internal/features/work/work-docx-comment-durable-id-preservation.d.ts +2 -0
  177. package/dist/internal/features/work/work-docx-comment-export.d.ts +3 -0
  178. package/dist/internal/features/work/work-docx-comment-metadata.d.ts +2 -0
  179. package/dist/internal/features/work/work-docx-drawing-extension-preservation.d.ts +4 -0
  180. package/dist/internal/features/work/work-docx-equation-diagnostics.d.ts +3 -0
  181. package/dist/internal/features/work/work-docx-equation-export.d.ts +14 -0
  182. package/dist/internal/features/work/work-docx-equation-import.d.ts +30 -0
  183. package/dist/internal/features/work/work-docx-equation-story.d.ts +9 -0
  184. package/dist/internal/features/work/work-docx-export-formatting.d.ts +3 -1
  185. package/dist/internal/features/work/work-docx-export-image.d.ts +5 -1
  186. package/dist/internal/features/work/work-docx-export.d.ts +1 -1
  187. package/dist/internal/features/work/work-docx-field-instructions.d.ts +8 -0
  188. package/dist/internal/features/work/work-docx-font-table-preservation.d.ts +3 -0
  189. package/dist/internal/features/work/work-docx-ignorable-extension-preservation.d.ts +15 -0
  190. package/dist/internal/features/work/work-docx-image-crop.d.ts +12 -0
  191. package/dist/internal/features/work/work-docx-image-identity.d.ts +17 -0
  192. package/dist/internal/features/work/work-docx-image-layer.d.ts +12 -0
  193. package/dist/internal/features/work/work-docx-image-layout-import.d.ts +14 -2
  194. package/dist/internal/features/work/work-docx-image-wrap.d.ts +15 -0
  195. package/dist/internal/features/work/work-docx-import.d.ts +13 -3
  196. package/dist/internal/features/work/work-docx-list-export.d.ts +18 -0
  197. package/dist/internal/features/work/work-docx-list-import.d.ts +14 -0
  198. package/dist/internal/features/work/work-docx-note-comment-content-control-block-preservation.d.ts +18 -0
  199. package/dist/internal/features/work/work-docx-note-comment-content-control-model.d.ts +47 -0
  200. package/dist/internal/features/work/work-docx-note-comment-content-control-preservation.d.ts +4 -0
  201. package/dist/internal/features/work/work-docx-note-comment-content-control-properties.d.ts +17 -0
  202. package/dist/internal/features/work/work-docx-note-comment-content-control-table-model.d.ts +17 -0
  203. package/dist/internal/features/work/work-docx-note-comment-content-control-xml.d.ts +14 -0
  204. package/dist/internal/features/work/work-docx-note-comment-extension-preservation.d.ts +2 -0
  205. package/dist/internal/features/work/work-docx-note-comment-hyperlink-content.d.ts +40 -0
  206. package/dist/internal/features/work/work-docx-note-comment-hyperlink-preservation.d.ts +5 -0
  207. package/dist/internal/features/work/work-docx-note-comment-hyperlink-relationships.d.ts +35 -0
  208. package/dist/internal/features/work/work-docx-note-comment-identity.d.ts +15 -0
  209. package/dist/internal/features/work/work-docx-note-comment-run-preservation.d.ts +4 -0
  210. package/dist/internal/features/work/work-docx-note-comment-run-properties.d.ts +2 -0
  211. package/dist/internal/features/work/work-docx-note-image-import.d.ts +12 -0
  212. package/dist/internal/features/work/work-docx-note-image-relationships.d.ts +1 -0
  213. package/dist/internal/features/work/work-docx-numbering-extension-preservation.d.ts +6 -0
  214. package/dist/internal/features/work/work-docx-numbering.d.ts +1 -0
  215. package/dist/internal/features/work/work-docx-page-borders-diagnostics.d.ts +3 -0
  216. package/dist/internal/features/work/work-docx-page-borders-import.d.ts +10 -0
  217. package/dist/internal/features/work/work-docx-page-margins-diagnostics.d.ts +3 -0
  218. package/dist/internal/features/work/work-docx-page-margins-import.d.ts +18 -0
  219. package/dist/internal/features/work/work-docx-page-size-diagnostics.d.ts +2 -0
  220. package/dist/internal/features/work/work-docx-page-size-import.d.ts +17 -0
  221. package/dist/internal/features/work/work-docx-paragraph-borders-diagnostics.d.ts +3 -0
  222. package/dist/internal/features/work/work-docx-paragraph-borders-export.d.ts +18 -0
  223. package/dist/internal/features/work/work-docx-paragraph-borders-import.d.ts +24 -0
  224. package/dist/internal/features/work/work-docx-paragraph-default-collapsed.d.ts +19 -0
  225. package/dist/internal/features/work/work-docx-paragraph-extension-preservation.d.ts +2 -0
  226. package/dist/internal/features/work/work-docx-paragraph-identity-import.d.ts +10 -0
  227. package/dist/internal/features/work/work-docx-paragraph-identity.d.ts +18 -0
  228. package/dist/internal/features/work/work-docx-paragraph-pagination-import.d.ts +6 -1
  229. package/dist/internal/features/work/work-docx-paragraph-shading-diagnostics.d.ts +3 -0
  230. package/dist/internal/features/work/work-docx-paragraph-shading-export.d.ts +5 -0
  231. package/dist/internal/features/work/work-docx-paragraph-shading-import.d.ts +18 -0
  232. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +3 -0
  233. package/dist/internal/features/work/work-docx-settings-preservation.d.ts +10 -0
  234. package/dist/internal/features/work/work-docx-settings-xml.d.ts +16 -0
  235. package/dist/internal/features/work/work-docx-style-extension-preservation.d.ts +2 -0
  236. package/dist/internal/features/work/work-docx-table-cell-export.d.ts +2 -1
  237. package/dist/internal/features/work/work-docx-table-cell-import.d.ts +3 -0
  238. package/dist/internal/features/work/work-docx-table-extension-preservation.d.ts +2 -0
  239. package/dist/internal/features/work/work-docx-table-row-import.d.ts +2 -0
  240. package/dist/internal/features/work/work-docx-table-sizing-import.d.ts +1 -0
  241. package/dist/internal/features/work/work-docx-theme-reference.d.ts +23 -0
  242. package/dist/internal/features/work/work-docx-theme.d.ts +4 -1
  243. package/dist/internal/features/work/work-docx-twips.d.ts +12 -0
  244. package/dist/internal/features/work/work-file-contract.d.ts +1 -0
  245. package/dist/internal/features/work/work-file-io.d.ts +1 -1
  246. package/dist/internal/features/work/work-markdown-extensions.d.ts +4 -1
  247. package/dist/internal/features/work/work-ooxml-package-preservation.d.ts +12 -0
  248. package/dist/internal/features/work/work-ooxml-package-security.d.ts +6 -0
  249. package/dist/internal/features/work/work-ooxml-relationship-preservation.d.ts +10 -0
  250. package/dist/internal/features/work/work-ooxml-xml.d.ts +2 -0
  251. package/dist/internal/features/work/work-pdf-export.d.ts +10 -0
  252. package/dist/internal/features/work/work-repository.d.ts +2 -0
  253. package/dist/internal/features/work/work-types.d.ts +15 -2
  254. package/dist/internal/kernel/office-kernel-client-types.d.ts +1 -0
  255. package/dist/internal/kernel/office-kernel-protocol.d.ts +7 -0
  256. package/dist/internal/kernel/office-kernel-version.d.ts +1 -1
  257. package/dist/office-kernel.wasm +0 -0
  258. package/dist/office-kernel.worker.js +93 -41
  259. package/dist/react.d.ts +18 -12
  260. package/dist/react.js +1 -1
  261. package/dist/styles.css +1367 -16
  262. package/dist/vue.d.ts +48 -5
  263. package/dist/vue.js +42 -3
  264. package/dist/web-component.d.ts +24 -2
  265. package/dist/web-component.js +101 -2
  266. package/docs/latest/en/browser-editor-architecture.md +262 -47
  267. package/package.json +29 -4
  268. package/dist/0~152.js +0 -94
  269. package/dist/0~2582.js +0 -485
  270. package/dist/0~4750.js +0 -939
  271. package/dist/0~5861.js +0 -596
  272. package/dist/0~work-document-extensions.js +0 -3045
  273. package/dist/0~work-document-model-codec.js +0 -42
  274. package/dist/0~work-docx-bibliography.js +0 -347
  275. package/dist/0~work-docx-page-color.js +0 -42
  276. package/dist/2881.js +0 -1455
  277. package/dist/8728.js +0 -723
@@ -1,15 +1,98 @@
1
- import { docxCaptionSequenceKind, docxFieldOccurrences, docxCaptionBookmark, docxCaptionReferenceTarget, docxFieldInstructions } from "./0~152.js";
2
- import { documentCitationTagsFromInstruction, docxDocumentFieldKind } from "./2881.js";
3
- import { contentTypeForPart, directChildren, formulaHasStructuredReference, OoxmlPackage, formulaHasExternalReference, firstDescendant, parseSpreadsheetPrintTitles, stripSpreadsheetSheetQualifier, descendants, directChild, attribute, volatileSpreadsheetFormulaFunctions } from "./8715.js";
4
- import { readDocxBibliography } from "./0~work-docx-bibliography.js";
1
+ import { descendants, directChildren, directChild, OoxmlPackage, attribute, firstDescendant, contentTypeForPart } from "./5184.js";
2
+ import { normalizeDocumentBookmarkName, docxBookmarkReferenceTarget, normalizeDocumentBookmarkNativeId, isDocumentParagraphArtBorderStyle, supportedDocxBookmarkReferenceInstruction, documentCitationTagsFromInstruction, docxDocumentFieldKind } from "./8928.js";
3
+ import { markDocxParagraphShading, inspectDocxPageSize, docxCaptionBookmark, hasInvalidDocxFieldStructure, inspectDocxPageMargins, inspectDocxPaperSource, createDocxParagraphStyleResolver, createDocxTableStyleResolver, docxFieldOccurrences, inspectDocxEquation, inspectDocxPageMarginSettings, markDocxParagraphBorders, docxFieldOccurrenceIsInlineEditable, docxCaptionSequenceKind, inspectDocxPageBorders, docxFieldInstructions, isSupportedDocxEquationPlacement } from "./0~7754.js";
4
+ import { normalizeDocumentHref } from "./0~work-document-links.js";
5
+ import { xmlAttributeLocalName, parseDocxParagraphDefaultCollapsed, readDocxBibliography, DOCX_WORDPROCESSING_NAMESPACES, xmlAttributeNamespace, createDocxThemeResolver } from "./0~2805.js";
5
6
  import { isSupportedXlsxCombinationChartNodes, MAX_XLSX_WORKSHEET_IMAGE_BYTES, inspectXlsxPivotTables, isSupportedXlsxWorksheetImageContentType, isSupportedXlsxChartLegend, isSupportedXlsxChartPlotLayout, xlsxChartNodeUsesStackedGrouping, isSupportedXlsxChartSeriesFormatting, readXlsxFormulaFeaturesFromPackage, inspectXlsxHeaderFooterText, isEditableXlsxPaperSizeCode, diagnoseXlsxProtection, xlsxChartSeriesFormattingShapeProperties } from "./4104.js";
6
- import { spreadsheetConditionalComparisonNeedsUpperValue, isSpreadsheetConditionalIconSetName, isSpreadsheetConditionalComparisonOperator, spreadsheetConditionalIconSetCount } from "./8728.js";
7
+ import { spreadsheetConditionalComparisonNeedsUpperValue, isSpreadsheetConditionalIconSetName, isSpreadsheetConditionalComparisonOperator, spreadsheetConditionalIconSetCount } from "./4476.js";
8
+ import { formulaHasStructuredReference, formulaHasExternalReference, parseSpreadsheetPrintTitles, volatileSpreadsheetFormulaFunctions, stripSpreadsheetSheetQualifier } from "./8715.js";
7
9
  import { unsupportedSpreadsheetFormulaFunctions } from "./0~work-spreadsheet-formula-support.js";
10
+ async function diagnoseDocxBookmarksAndLinks(archive, document) {
11
+ const starts = descendants(document, 'bookmarkStart');
12
+ const ends = descendants(document, 'bookmarkEnd');
13
+ const hyperlinks = descendants(document, 'hyperlink');
14
+ if (!starts.length && !ends.length && !hyperlinks.length) return [];
15
+ const issues = [
16
+ bookmarkIssue('docx.bookmarks-links', 'Paired body bookmarks remain editable native bookmark ranges. Bookmark REF fields stay live and editable, internal hyperlinks retain Word anchor semantics without external relationships, and supported web and email links retain external hyperlink relationships.', 'info')
17
+ ];
18
+ const startsById = groupedByAttribute(starts, 'id');
19
+ const endsById = groupedByAttribute(ends, 'id');
20
+ const boundaryIds = new Set([
21
+ ...startsById.keys(),
22
+ ...endsById.keys()
23
+ ]);
24
+ if (starts.some((start)=>!attribute(start, 'id')?.trim()) || ends.some((end)=>!attribute(end, 'id')?.trim()) || Array.from(boundaryIds).some((id)=>(startsById.get(id)?.length ?? 0) !== (endsById.get(id)?.length ?? 0))) issues.push(bookmarkIssue('docx.bookmarks.structure', 'Unpaired bookmark boundaries cannot form a complete editable range and are omitted during editing import.'));
25
+ const names = new Set();
26
+ const nativeIds = new Set();
27
+ let normalizedIdentity = false;
28
+ for (const start of starts){
29
+ const sourceName = attribute(start, 'name')?.trim() ?? '';
30
+ const name = normalizeDocumentBookmarkName(sourceName);
31
+ const sourceNativeId = attribute(start, 'id');
32
+ const nativeId = normalizeDocumentBookmarkNativeId(sourceNativeId);
33
+ const foldedName = name?.toLowerCase();
34
+ if (!name || !foldedName || names.has(foldedName) || null === nativeId || nativeIds.has(nativeId)) normalizedIdentity = true;
35
+ if (foldedName) names.add(foldedName);
36
+ if (null !== nativeId) nativeIds.add(nativeId);
37
+ }
38
+ if (normalizedIdentity) issues.push(bookmarkIssue('docx.bookmarks.identity', 'Invalid, duplicate, or over-40-character bookmark names are made unique and Word-compatible. Missing or reused numeric identifiers are reassigned, and matching internal links are redirected to the retained target.'));
39
+ if (starts.some((start)=>null !== attribute(start, 'colFirst') || null !== attribute(start, 'colLast'))) issues.push(bookmarkIssue('docx.bookmarks.columns', 'Column-scoped table bookmarks are imported as ordinary editable bookmark ranges; column boundary metadata is normalized.'));
40
+ const targetNames = new Set(starts.flatMap((start)=>{
41
+ const name = attribute(start, 'name')?.trim().toLowerCase() ?? '';
42
+ return name ? [
43
+ name
44
+ ] : [];
45
+ }));
46
+ const bookmarkReferences = docxFieldOccurrences(document).filter((field)=>{
47
+ const target = docxBookmarkReferenceTarget(field.instruction);
48
+ return Boolean(target && targetNames.has(target.toLowerCase()));
49
+ });
50
+ if (bookmarkReferences.some((field)=>!supportedDocxBookmarkReferenceInstruction(field.instruction))) issues.push(bookmarkIssue('docx.bookmark-references.switches', 'Bookmark REF fields with relative-position, paragraph-number, or other advanced switches normalize to bookmarked text with an optional hyperlink switch.'));
51
+ const danglingAnchors = hyperlinks.some((hyperlink)=>{
52
+ const anchor = attribute(hyperlink, 'anchor')?.trim();
53
+ return Boolean(anchor && !targetNames.has(anchor.toLowerCase()));
54
+ });
55
+ if (danglingAnchors) issues.push(bookmarkIssue('docx.hyperlinks.missing-target', 'One or more internal hyperlinks do not resolve to a body bookmark. Their anchors are retained and shown with an explicit missing-target state.'));
56
+ const relationships = await archive.relationships('word/document.xml');
57
+ const unsupportedExternalLink = hyperlinks.some((hyperlink)=>{
58
+ const relationshipId = attribute(hyperlink, 'r:id')?.trim();
59
+ if (!relationshipId) return false;
60
+ const relationship = relationships.get(relationshipId);
61
+ if (!relationship) return true;
62
+ return !relationship.type.endsWith('/hyperlink') || relationship.targetMode?.toLowerCase() !== 'external' || null === normalizeDocumentHref(relationship.target);
63
+ });
64
+ if (unsupportedExternalLink) issues.push(bookmarkIssue('docx.hyperlinks.external', 'Hyperlink relationships outside http, https, and mailto, or unresolved hyperlink relationships, are converted to plain linked text.'));
65
+ if (hyperlinks.some((hyperlink)=>null !== attribute(hyperlink, 'tooltip') || null !== attribute(hyperlink, 'tgtFrame') || null !== attribute(hyperlink, 'docLocation') || null !== attribute(hyperlink, 'anchor') && null !== attribute(hyperlink, 'r:id'))) issues.push(bookmarkIssue('docx.hyperlinks.metadata', 'Hyperlink tooltips, target frames, external document locations, and combined external-plus-anchor destinations normalize to the supported link destination.'));
66
+ return issues;
67
+ }
68
+ function groupedByAttribute(elements, name) {
69
+ const groups = new Map();
70
+ for (const element of elements){
71
+ const value = attribute(element, name)?.trim() ?? '';
72
+ const matches = groups.get(value) ?? [];
73
+ matches.push(element);
74
+ groups.set(value, matches);
75
+ }
76
+ return groups;
77
+ }
78
+ function bookmarkIssue(code, message, severity = 'warning') {
79
+ return {
80
+ code,
81
+ feature: 'Bookmarks and hyperlinks',
82
+ message,
83
+ severity
84
+ };
85
+ }
8
86
  function diagnoseDocxCaptions(document) {
9
87
  const fields = docxFieldOccurrences(document);
10
88
  const sequences = fields.filter((field)=>docxCaptionSequenceKind(field.instruction));
11
- const bodyFields = fields.filter((field)=>docxDocumentFieldKind(field.instruction));
12
- const bookmarkNames = captionBookmarkNames(sequences);
89
+ const bodyFields = fields.filter((field)=>'orphan' !== field.syntax && Boolean(docxDocumentFieldKind(field.instruction)));
90
+ const editableBodyFields = bodyFields.filter(docxFieldOccurrenceIsInlineEditable);
91
+ const hasUnsupportedFieldStructure = hasInvalidDocxFieldStructure(document) || bodyFields.some((field)=>!docxFieldOccurrenceIsInlineEditable(field));
92
+ const bookmarkNames = new Set([
93
+ ...captionBookmarkNames(sequences),
94
+ ...pairedBookmarkNames(document)
95
+ ]);
13
96
  return {
14
97
  issues: [
15
98
  ...sequences.length ? [
@@ -20,16 +103,24 @@ function diagnoseDocxCaptions(document) {
20
103
  severity: 'info'
21
104
  }
22
105
  ] : [],
23
- ...bodyFields.length ? [
106
+ ...editableBodyFields.length ? [
24
107
  {
25
108
  code: 'docx.fields.body',
26
109
  feature: 'Body fields',
27
110
  message: 'PAGE, NUMPAGES, SECTION, SECTIONPAGES, DATE, and TIME fields remain live, editable body fields and update in preview, PDF, and native DOCX output.',
28
111
  severity: 'info'
29
112
  }
113
+ ] : [],
114
+ ...hasUnsupportedFieldStructure ? [
115
+ {
116
+ code: 'docx.fields.structure',
117
+ feature: 'Field structure',
118
+ message: 'Incomplete, nested, cross-paragraph, deleted, or instructionless fields cannot form one editable inline field; their current results are retained as text.',
119
+ severity: 'warning'
120
+ }
30
121
  ] : []
31
122
  ],
32
- hasUnsupportedFields: fields.some((field)=>!isSupportedCaptionField(field.instruction, bookmarkNames))
123
+ hasUnsupportedFields: hasUnsupportedFieldStructure || fields.some((field)=>!isSupportedCaptionField(field.instruction, bookmarkNames))
33
124
  };
34
125
  }
35
126
  function captionBookmarkNames(fields) {
@@ -39,7 +130,7 @@ function captionBookmarkNames(fields) {
39
130
  if (!paragraph) continue;
40
131
  const bookmark = docxCaptionBookmark(paragraph, field);
41
132
  const name = attribute(bookmark ?? paragraph, 'name')?.trim();
42
- if (name) names.add(name);
133
+ if (name) names.add(name.toLowerCase());
43
134
  }
44
135
  return names;
45
136
  }
@@ -47,8 +138,18 @@ function isSupportedCaptionField(instruction, bookmarkNames) {
47
138
  if (documentCitationTagsFromInstruction(instruction).length || /^\s*BIBLIOGRAPHY\b/i.test(instruction)) return true;
48
139
  if (docxDocumentFieldKind(instruction)) return true;
49
140
  if (docxCaptionSequenceKind(instruction)) return true;
50
- const target = docxCaptionReferenceTarget(instruction);
51
- return Boolean(target && bookmarkNames.has(target));
141
+ const target = docxBookmarkReferenceTarget(instruction);
142
+ return Boolean(target && bookmarkNames.has(target.toLowerCase()));
143
+ }
144
+ function pairedBookmarkNames(document) {
145
+ const endIds = new Set(descendants(document, 'bookmarkEnd').map((bookmark)=>attribute(bookmark, 'id')?.trim() ?? ''));
146
+ return new Set(descendants(document, 'bookmarkStart').flatMap((bookmark)=>{
147
+ const id = attribute(bookmark, 'id')?.trim() ?? '';
148
+ const name = attribute(bookmark, 'name')?.trim().toLowerCase() ?? '';
149
+ return id && name && endIds.has(id) ? [
150
+ name
151
+ ] : [];
152
+ }));
52
153
  }
53
154
  function closestAncestor(element, localName) {
54
155
  let current = element;
@@ -114,21 +215,99 @@ async function diagnoseDocxCitations(archive, document) {
114
215
  });
115
216
  return issues;
116
217
  }
218
+ const EQUATION_PART_PATTERN = /^word\/(?:header\d*|footer\d*|footnotes|endnotes)\.xml$/i;
219
+ const MAX_EDITABLE_EQUATIONS = 4096;
220
+ async function diagnoseDocxEquations(archive, document) {
221
+ const parts = document ? [
222
+ {
223
+ path: 'word/document.xml',
224
+ document
225
+ }
226
+ ] : [];
227
+ for (const path of archive.paths('word/').filter((candidate)=>EQUATION_PART_PATTERN.test(candidate)))parts.push({
228
+ path,
229
+ document: await archive.xml(path)
230
+ });
231
+ let supported = 0;
232
+ let unsupported = 0;
233
+ let spoofed = 0;
234
+ for (const part of parts)for (const element of Array.from(part.document.querySelectorAll('*')).filter((candidate)=>'oMath' === candidate.localName || 'oMathPara' === candidate.localName)){
235
+ if (closestEquationRoot(element.parentElement)) continue;
236
+ const inspection = inspectDocxEquation(element);
237
+ if ('supported' === inspection.status && isSupportedDocxEquationPlacement(element)) supported += 1;
238
+ else if ('spoofed' === inspection.status) spoofed += 1;
239
+ else unsupported += 1;
240
+ }
241
+ const total = supported + unsupported + spoofed;
242
+ if (!total) return [];
243
+ const issues = [];
244
+ if (supported) issues.push(equationIssue('docx.equations', `${supported} native OMML equation(s) use the editable structured subset. Inline equations and display equations with left, right, center, or center-group paragraph justification, Unicode math runs with literal/normal-text semantics, six math scripts, four styles, manual breaks, alignment points, ordered core Word run formatting for fonts/theme references, emphasis, casing, strike, relief effects, legacy text animations, bounded line borders, proofing/grid flags, visibility, colors, bounded character spacing, horizontal scaling, kerning thresholds, signed baseline positions, half-point sizes, named highlights, patterned shading, bounded manual run widths with optional grouping IDs, explicit baseline/superscript/subscript run alignment, all five Word emphasis-mark values, underlines, script direction, languages, native-only East Asian typography with signed run IDs, two-lines-in-one brackets, rotation, and compression, inert paragraph-mark visibility resets, and Office 2010 text glow, shadow, reflection, text-outline, text-fill, 3D-scene, and 3D-property effects with bounded radii, offsets, outline widths, extrusion heights, and contour widths, exact direction and reflection opacity/position/fade geometry, signed scale and skew, rectangle and pen alignment, glow/shadow/outline/fill/extrusion/contour RGB or theme colors and ordered transform chains, none/solid/gradient outline and text fills with bounded stops and linear/path shading, preset dashes, round/bevel/miter joins, all camera, light-rig, bevel, and material presets, all light directions, exact optional rotation angles, ordered top/bottom bevel plus extrusion/contour color branches, all 16 ligature combinations, three numeral forms, three numeral-spacing modes, bounded Office 2010 stylistic-set lists, and explicit contextual-alternate controls with exact combined CSS OpenType projection and distinct clig/calt behavior, with exact direct RGB and default-black text fills projected to MathML while complex effects remain native metadata, and the same bounded Word formatting in ordered object-level control properties and native-only argument-slot control properties, bounded insertion, deletion, move-source, and move-destination provenance around those math controls, ordered fractions with four native types and a bar default, ordered right-side scripts with aligned sub/superscripts, left-side pre-sub/superscripts with empty script slots, radicals with optional degrees and canonical square-root slots, functions with required, optionally empty name/argument slots, canonical empty arguments across every supported construct, ordered argument/control properties, bounded relative argument sizes with Word-effective MathML script-level projection and native-only preservation elsewhere, and strictly aligned matrix-cell, equation-array-row, and delimiter-argument metadata, ordered n-ary operators with default integrals, canonical empty limit slots, and optional operand growth, combining accents, overbars and underbars, group characters with explicit character position and baseline justification, phantoms with visible or hidden bases, zeroed width/ascent/descent, and transparent spacing, border boxes with independently visible edges and four strike directions, semantic boxes with operator-emulation, no-break, differential-spacing, manual-break, and alignment properties, bounded rectangular matrices with ordered row-spacing, column-gap, and minimum-width controls, equation arrays with bounded rows, vertical base alignment, distribution, row-spacing, and alignment/spacer markers, lower and upper limit objects, ordered delimiters with distinct omitted/empty characters, bounded empty argument slots, growing or fixed sizing, and centered or content-matched shape, and their accessible MathML previews round-trip through body text, headers, footers, footnotes, and endnotes.`, 'info'));
245
+ if (unsupported || spoofed) issues.push(equationIssue('docx.equations.unsupported', `${unsupported + spoofed} equation-like object(s) use unsupported, malformed, misplaced, namespace-spoofed, relationship-bound, or ambiguous markup. They are flattened to bounded text instead of being treated as trusted structured OMML. Invalid or non-combining accent characters, malformed math-run, script, function, argument-property, or math-paragraph structures, unknown, duplicated, reordered, spoofed, out-of-range, or contradictory Word math-run casing, strike, relief, animation, line-border, visibility, geometry, manual-width, vertical-alignment, emphasis-mark, East Asian typography, paragraph-mark visibility, Office 2010 glow/shadow/outline/text-fill color transforms, glow/shadow/reflection geometry, outline fill/gradient/dash/join structure, text-fill wrapper/fill/gradient structure, 3D-scene camera/light structure, or 3D-property extrusion/contour/bevel/color structure, missing, malformed, or non-leaf Office 2010 ligature, numeral-form, or numeral-spacing values, malformed or over-limit stylistic-set containers, entries, IDs, or on/off values, malformed contextual-alternate leaves or on/off values, coordinate values, preset values, directions, or rotation angles, highlight, shading, object-control, or argument-control formatting, malformed control-revision identities, dates, children, or nesting, out-of-range or malformed argument sizes, invalid or contradictory fraction, radical, n-ary, delimiter, bar, group-character, phantom, border-box, box, or equation-array properties, malformed pre-script or lower/upper limit structures, malformed, duplicated, reordered, or out-of-range matrix spacing/gap properties, ragged or over-limit matrices, over-limit equation arrays, and nested Office Math remain outside the structured subset.`));
246
+ if (total > MAX_EDITABLE_EQUATIONS) issues.push(equationIssue('docx.equations.limit', `Only the first ${MAX_EDITABLE_EQUATIONS} valid equations enter the editable structured model; later equations are flattened to bounded text.`));
247
+ return issues;
248
+ }
249
+ function closestEquationRoot(element) {
250
+ let current = element;
251
+ while(current){
252
+ if ('oMath' === current.localName || 'oMathPara' === current.localName) return current;
253
+ current = current.parentElement;
254
+ }
255
+ return null;
256
+ }
257
+ function equationIssue(code, message, severity = 'warning') {
258
+ return {
259
+ code,
260
+ feature: 'Equations',
261
+ message,
262
+ severity
263
+ };
264
+ }
265
+ const WORDPROCESSINGML_NAMESPACES = new Set([
266
+ 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
267
+ 'http://purl.oclc.org/ooxml/wordprocessingml/main'
268
+ ]);
269
+ const WORDPROCESSING_DRAWING_NAMESPACES = new Set([
270
+ 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
271
+ 'http://purl.oclc.org/ooxml/drawingml/wordprocessingDrawing'
272
+ ]);
273
+ const DRAWINGML_NAMESPACES = new Set([
274
+ 'http://schemas.openxmlformats.org/drawingml/2006/main',
275
+ 'http://purl.oclc.org/ooxml/drawingml/main'
276
+ ]);
277
+ const PICTURE_NAMESPACES = new Set([
278
+ 'http://schemas.openxmlformats.org/drawingml/2006/picture',
279
+ 'http://purl.oclc.org/ooxml/drawingml/picture'
280
+ ]);
281
+ const RELATIONSHIP_NAMESPACES = new Set([
282
+ 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
283
+ 'http://purl.oclc.org/ooxml/officeDocument/relationships'
284
+ ]);
117
285
  async function diagnoseDocxNotes(archive, document) {
118
286
  const noteParts = [
119
- 'word/footnotes.xml',
120
- 'word/endnotes.xml'
121
- ].filter((part)=>archive.has(part));
122
- const noteDocuments = await Promise.all(noteParts.map((part)=>archive.xml(part)));
123
- const hasNotes = Boolean(document && (descendants(document, 'footnoteReference').length || descendants(document, 'endnoteReference').length)) || noteDocuments.some((notes)=>[
124
- ...descendants(notes, 'footnote'),
125
- ...descendants(notes, 'endnote')
126
- ].some((note)=>Number(attribute(note, 'id')) > 0));
287
+ {
288
+ path: 'word/footnotes.xml',
289
+ kind: 'footnote',
290
+ reference: 'footnoteReference'
291
+ },
292
+ {
293
+ path: 'word/endnotes.xml',
294
+ kind: 'endnote',
295
+ reference: 'endnoteReference'
296
+ }
297
+ ].filter(({ path })=>archive.has(path));
298
+ const noteDocuments = await Promise.all(noteParts.map(async ({ path, kind, reference })=>({
299
+ kind,
300
+ reference,
301
+ document: await archive.xml(path)
302
+ })));
303
+ const hasNotes = Boolean(document && (descendants(document, 'footnoteReference').length || descendants(document, 'endnoteReference').length)) || noteDocuments.some(({ document: notes, kind })=>normalNoteDefinitions(notes, kind).length);
127
304
  if (!hasNotes) return [];
128
305
  const issues = [
129
- noteIssue('docx.notes', 'Footnote and endnote references, editable note text, common inline formatting, preview placement, and native DOCX note parts are preserved.', 'info')
306
+ noteIssue('docx.notes', 'Footnote and endnote references, stable native IDs, editable note text, native tables, DrawingML pictures, supported structured OMML equations, common inline formatting, safe web, mail, and internal hyperlinks, eligible static text content controls, preview placement, native DOCX note parts, and eligible passive definition, paragraph, table, drawing, wrapper, and text-stable run metadata are preserved.', 'info')
130
307
  ];
131
- if (noteDocuments.some((notes)=>descendants(notes, 'tbl').length > 0 || descendants(notes, 'drawing').length > 0 || descendants(notes, 'pict').length > 0)) issues.push(noteIssue('docx.notes.rich-content', 'Tables, drawings, and embedded media inside notes may be flattened or converted to inline content.'));
308
+ if (hasInvalidNoteStructure(document, noteDocuments)) issues.push(noteIssue('docx.notes.structure', 'Missing, duplicate, unreferenced, or nested footnote and endnote identities cannot form a unique editable pair; unmatched content is omitted and repeated references receive new identities during editing import.'));
309
+ if (noteDocuments.some(({ document: notes })=>descendants(notes, 'pict').length > 0 || noteHasUnsupportedEquation(notes) || descendants(notes, 'drawing').some((drawing)=>!isSupportedNotePicture(drawing)))) issues.push(noteIssue('docx.notes.rich-content', 'Legacy VML pictures, shapes, SmartArt, unsupported or malformed equations, and non-picture drawings inside notes may be flattened or converted to bounded inline content. Native paragraphs, tables, validated DrawingML pictures, and supported structured OMML equations remain editable within the declared static-content boundary.'));
310
+ if (noteDocuments.some(({ document: notes })=>descendants(notes, 'sdt').length > 0)) issues.push(noteIssue('docx.notes.content-controls', 'Text-stable static rich-text and plain-text controls retain eligible inline or contiguous block wrappers and metadata. Rich-text block controls may include uniquely matched stable tables and nested tables while generated geometry remains authoritative. Data-bound, placeholder, form, nested, relationship-bound, ambiguous, edited-structure, math, drawing-bearing, or mixed-hyperlink control wrappers normalize instead of being reattached unsafely.'));
132
311
  const settings = archive.has('word/settings.xml') ? await archive.xml('word/settings.xml') : null;
133
312
  const noteProperties = [
134
313
  ...document ? descendants(document, 'footnotePr') : [],
@@ -139,6 +318,58 @@ async function diagnoseDocxNotes(archive, document) {
139
318
  if (noteProperties.some((properties)=>directChildren(properties).length > 0)) issues.push(noteIssue('docx.notes.numbering', 'Custom note symbols, numbering formats, restart rules, separators, and placement settings normalize to continuous Arabic numbering with footnotes per page and endnotes at document end.'));
140
319
  return issues;
141
320
  }
321
+ function noteHasUnsupportedEquation(document) {
322
+ return Array.from(document.querySelectorAll('*')).some((element)=>('oMath' === element.localName || 'oMathPara' === element.localName) && ('supported' !== inspectDocxEquation(element).status || !isSupportedDocxEquationPlacement(element)));
323
+ }
324
+ function isSupportedNotePicture(drawing) {
325
+ if (!WORDPROCESSINGML_NAMESPACES.has(drawing.namespaceURI ?? '')) return false;
326
+ const containers = directChildren(drawing).filter((element)=>('anchor' === element.localName || 'inline' === element.localName) && WORDPROCESSING_DRAWING_NAMESPACES.has(element.namespaceURI ?? ''));
327
+ if (1 !== containers.length) return false;
328
+ const container = containers[0];
329
+ const graphicData = descendants(container, 'graphicData').filter((element)=>DRAWINGML_NAMESPACES.has(element.namespaceURI ?? ''));
330
+ const pictures = descendants(container, 'pic').filter((element)=>PICTURE_NAMESPACES.has(element.namespaceURI ?? ''));
331
+ const blips = descendants(container, 'blip').filter((element)=>DRAWINGML_NAMESPACES.has(element.namespaceURI ?? ''));
332
+ return 1 === graphicData.length && PICTURE_NAMESPACES.has(graphicData[0].getAttribute('uri') ?? '') && 1 === pictures.length && 1 === blips.length && hasRelationshipAttribute(blips[0], 'embed');
333
+ }
334
+ function hasRelationshipAttribute(element, name) {
335
+ return Array.from(element.attributes).some((item)=>xmlAttributeLocalName(item) === name && RELATIONSHIP_NAMESPACES.has(xmlAttributeNamespace(element, item) ?? '') && Boolean(item.value.trim()));
336
+ }
337
+ function hasInvalidNoteStructure(document, parts) {
338
+ for (const part of parts){
339
+ const definitions = normalNoteDefinitions(part.document, part.kind);
340
+ const definitionsById = groupedById(definitions);
341
+ const references = document ? descendants(document, part.reference) : [];
342
+ const referencesById = groupedById(references);
343
+ const referenceIds = new Set(references.flatMap((reference)=>{
344
+ const id = attribute(reference, 'id')?.trim() ?? '';
345
+ return id ? [
346
+ id
347
+ ] : [];
348
+ }));
349
+ if (references.some((reference)=>!attribute(reference, 'id')?.trim()) || Array.from(referencesById.values()).some((matches)=>matches.length > 1) || references.some((reference)=>{
350
+ const id = attribute(reference, 'id')?.trim() ?? '';
351
+ return id && (definitionsById.get(id)?.length ?? 0) !== 1;
352
+ }) || definitions.some((definition)=>!attribute(definition, 'id')?.trim()) || Array.from(definitionsById.values()).some((matches)=>matches.length > 1) || Array.from(definitionsById.keys()).some((id)=>!referenceIds.has(id)) || descendants(part.document, 'footnoteReference').length > 0 || descendants(part.document, 'endnoteReference').length > 0) return true;
353
+ }
354
+ if (!document) return false;
355
+ return descendants(document, 'footnoteReference').length > 0 && !parts.some(({ kind })=>'footnote' === kind) || descendants(document, 'endnoteReference').length > 0 && !parts.some(({ kind })=>'endnote' === kind);
356
+ }
357
+ function normalNoteDefinitions(document, kind) {
358
+ return descendants(document, kind).filter((note)=>{
359
+ const type = attribute(note, 'type')?.trim().toLowerCase() ?? '';
360
+ return !type || 'normal' === type;
361
+ });
362
+ }
363
+ function groupedById(elements) {
364
+ const groups = new Map();
365
+ for (const element of elements){
366
+ const id = attribute(element, 'id')?.trim() ?? '';
367
+ const matches = groups.get(id) ?? [];
368
+ matches.push(element);
369
+ groups.set(id, matches);
370
+ }
371
+ return groups;
372
+ }
142
373
  function noteIssue(code, message, severity = 'warning') {
143
374
  return {
144
375
  code,
@@ -147,6 +378,67 @@ function noteIssue(code, message, severity = 'warning') {
147
378
  severity
148
379
  };
149
380
  }
381
+ async function diagnoseDocxPageBorders(archive, document) {
382
+ const themePath = archive.paths('word/theme/').find((path)=>/\/theme\d*\.xml$/i.test(path));
383
+ const themeDocument = themePath ? await archive.xml(themePath) : null;
384
+ const settingsDocument = archive.has('word/settings.xml') ? await archive.xml('word/settings.xml') : null;
385
+ const theme = createDocxThemeResolver(themeDocument, settingsDocument);
386
+ const sections = descendants(document, 'sectPr').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '') && !hasAncestor(element, 'sectPrChange'));
387
+ const inspected = sections.map((section)=>inspectDocxPageBorders(section, theme));
388
+ const valid = inspected.flatMap((item)=>'valid' === item.status && item.pageBorders ? [
389
+ item.pageBorders
390
+ ] : []);
391
+ const invalidCount = inspected.reduce((count, item)=>count + item.invalidCount, 0);
392
+ const spoofedCount = inspected.reduce((count, item)=>count + item.spoofedCount, 0);
393
+ if (!valid.length && !invalidCount && !spoofedCount) return [];
394
+ const issues = [];
395
+ if (valid.length) {
396
+ const edgeCount = valid.reduce((count, pageBorders)=>count + Object.values(pageBorders.edges).filter(Boolean).length, 0);
397
+ const artCount = valid.reduce((count, pageBorders)=>count + Object.values(pageBorders.edges).filter((border)=>border && isDocumentParagraphArtBorderStyle(border.style)).length, 0);
398
+ issues.push({
399
+ code: 'docx.page-borders',
400
+ severity: 'info',
401
+ feature: 'Page borders',
402
+ message: `${valid.length} section page-border set(s) with ${edgeCount} native edge(s) preserve page/text offsets, first/not-first-page display, front/back z-order, theme colors, widths, spacing, shadows, frames, and all Word line or art styles. The paginated editor and PDF surface honor section/page visibility and Word defaults; ${artCount} art edge(s) use a bounded browser approximation while native OOXML remains authoritative on DOCX export.`
403
+ });
404
+ }
405
+ if (invalidCount || spoofedCount) issues.push({
406
+ code: 'docx.page-borders.invalid',
407
+ severity: 'warning',
408
+ feature: 'Page borders',
409
+ message: `${invalidCount + spoofedCount} malformed, out-of-order, duplicated, namespace-spoofed, relationship-bound, or unresolved theme page-border value(s) are ignored or normalized to explicit nil edges instead of applying unsafe or stale section formatting.`
410
+ });
411
+ const modifiers = settingsDocument ? [
412
+ 'alignBordersAndEdges',
413
+ 'bordersDoNotSurroundHeader',
414
+ 'bordersDoNotSurroundFooter'
415
+ ].filter((name)=>enabledSetting(settingsDocument, name)) : [];
416
+ if (valid.length && modifiers.length) issues.push({
417
+ code: 'docx.page-borders.settings',
418
+ severity: 'warning',
419
+ feature: 'Page-border compatibility settings',
420
+ message: `${modifiers.join(', ')} modifies Word's interaction between page borders, page edges, headers, or footers. Native section borders remain editable and exact, but the browser preview uses the standardized pgBorders geometry and may not reproduce these application-specific document-wide adjustments.`
421
+ });
422
+ return issues;
423
+ }
424
+ function enabledSetting(document, localName) {
425
+ const element = descendants(document, localName).find((candidate)=>DOCX_WORDPROCESSING_NAMESPACES.has(candidate.namespaceURI ?? ''));
426
+ if (!element) return false;
427
+ const value = attribute(element, 'val')?.trim().toLowerCase();
428
+ return !value || ![
429
+ '0',
430
+ 'false',
431
+ 'off'
432
+ ].includes(value);
433
+ }
434
+ function hasAncestor(element, localName) {
435
+ let ancestor = element.parentElement;
436
+ while(ancestor){
437
+ if (ancestor.localName === localName) return true;
438
+ ancestor = ancestor.parentElement;
439
+ }
440
+ return false;
441
+ }
150
442
  const PAGE_FIELD = /^\s*PAGE(?:\s|\\|$)/i;
151
443
  const ADVANCED_POSITIONING = new Set([
152
444
  'anchor',
@@ -176,11 +468,12 @@ async function diagnoseDocxPageChrome(archive) {
176
468
  document: await archive.xml(path)
177
469
  })));
178
470
  const issues = [
179
- pageChromeIssue('docx.headers', 'Rich default, first-page, and even-page headers and footers, common formatting, tables, links, inline raster images, and PAGE numbering are preserved, editable, and used by preview, PDF, and native DOCX output.', 'info')
471
+ pageChromeIssue('docx.headers', 'Rich default, first-page, and even-page headers and footers, common formatting, tables, links, inline raster images, supported structured OMML equations, and PAGE numbering are preserved, editable, and used by preview, PDF, and native DOCX output.', 'info')
180
472
  ];
181
473
  const instructions = documents.flatMap(({ document })=>docxFieldInstructions(document));
182
474
  if (instructions.some((instruction)=>!PAGE_FIELD.test(instruction))) issues.push(pageChromeIssue('docx.headers.fields', 'PAGE numbering is preserved. Other header/footer field codes are flattened to their current displayed text and no longer update automatically.'));
183
475
  if (documents.some(({ path, document })=>path.startsWith('word/header') && docxFieldInstructions(document).some((instruction)=>PAGE_FIELD.test(instruction)))) issues.push(pageChromeIssue('docx.headers.page-field-position', "PAGE fields placed in a header are preserved through Work's centered footer page-number slot."));
476
+ if (documents.some(({ document })=>Array.from(document.querySelectorAll('*')).some((element)=>('oMath' === element.localName || 'oMathPara' === element.localName) && ('supported' !== inspectDocxEquation(element).status || !isSupportedDocxEquationPlacement(element))))) issues.push(pageChromeIssue('docx.headers.equations', 'Unsupported, malformed, misplaced, or namespace-spoofed header/footer equations are flattened to bounded text instead of entering the editable OMML model.'));
184
477
  if (documents.some(({ document })=>descendants(document, 'sdt').length > 0)) issues.push(pageChromeIssue('docx.headers.content-controls', 'Header/footer content controls are flattened to editable content; bindings, locking, and repeating behavior are not preserved.'));
185
478
  if (documents.some(({ document })=>Array.from(document.querySelectorAll('*')).some((element)=>ADVANCED_POSITIONING.has(element.localName)))) issues.push(pageChromeIssue('docx.headers.positioning', 'Floating drawings, text boxes, tab stops, indents, and advanced header/footer positioning are normalized to inline flow.'));
186
479
  return issues;
@@ -193,6 +486,178 @@ function pageChromeIssue(code, message, severity = 'warning') {
193
486
  severity
194
487
  };
195
488
  }
489
+ async function diagnoseDocxPageMargins(archive, document) {
490
+ const settingsDocument = archive.has('word/settings.xml') ? await archive.xml('word/settings.xml') : null;
491
+ const settings = inspectDocxPageMarginSettings(settingsDocument);
492
+ const sections = descendants(document, 'sectPr').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '') && !work_docx_page_margins_diagnostics_hasAncestor(element, 'sectPrChange'));
493
+ const inspected = sections.map((section)=>inspectDocxPageMargins(section, settings));
494
+ const valid = inspected.flatMap((item, index)=>'valid' === item.status && item.pageMargins ? [
495
+ {
496
+ section: sections[index],
497
+ pageMargins: item.pageMargins
498
+ }
499
+ ] : []);
500
+ const invalidCount = settings.invalidCount + inspected.reduce((count, item)=>count + item.invalidCount, 0);
501
+ const spoofedCount = settings.spoofedCount + inspected.reduce((count, item)=>count + item.spoofedCount, 0);
502
+ if (!valid.length && !invalidCount && !spoofedCount) return [];
503
+ const issues = [];
504
+ if (valid.length) {
505
+ const gutterSections = valid.filter(({ pageMargins })=>pageMargins.gutter > 0).length;
506
+ const overlapSections = valid.filter(({ pageMargins })=>pageMargins.top < 0 || pageMargins.bottom < 0).length;
507
+ issues.push({
508
+ code: 'docx.page-margins',
509
+ severity: 'info',
510
+ feature: 'Page margins',
511
+ message: `${valid.length} section page-margin set(s) preserve all seven native pgMar values in exact twips, including header and footer distances, ${gutterSections} binding gutter(s), ${overlapSections} signed header/footer-overlap geometry set(s), document-wide mirror/top-gutter settings, per-section right-side gutters, strict namespaces, editing controls, paginated preview, and exact DOCX output.`
512
+ });
513
+ }
514
+ if (invalidCount || spoofedCount) issues.push({
515
+ code: 'docx.page-margins.invalid',
516
+ severity: 'warning',
517
+ feature: 'Page margins',
518
+ message: `${invalidCount + spoofedCount} malformed, duplicated, incomplete, out-of-range, namespace-spoofed, relationship-bound, or structurally invalid pgMar, mirrorMargins, gutterAtTop, or rtlGutter value(s) are ignored instead of becoming trusted page geometry.`
519
+ });
520
+ const incompatible = settings.incompatible;
521
+ if (valid.some(({ pageMargins })=>pageMargins.gutterAtTop) && incompatible.length) issues.push({
522
+ code: 'docx.page-margins.gutter-conflict',
523
+ severity: 'warning',
524
+ feature: 'Page-margin compatibility settings',
525
+ message: `${incompatible.join(', ')} conflicts with gutterAtTop under WordprocessingML. Native values remain explicit, but the browser applies the facing-page or print-layout setting before the top-gutter request.`
526
+ });
527
+ if (valid.some(({ pageMargins })=>pageMargins.mirrorMargins && (pageMargins.left !== pageMargins.right || pageMargins.gutter > 0))) issues.push({
528
+ code: 'docx.page-margins.facing-pages',
529
+ severity: 'warning',
530
+ feature: 'Facing-page margins',
531
+ message: 'PDF pages and page decorations swap facing-page margins and the binding gutter per physical page. The continuous live editing surface keeps the same text width and native geometry but projects the first-page horizontal origin between page breaks.'
532
+ });
533
+ const bounded = valid.filter(({ section, pageMargins })=>{
534
+ const inspectedSize = inspectDocxPageSize(section);
535
+ const width = inspectedSize.pageGeometry?.width ?? 11906;
536
+ const height = inspectedSize.pageGeometry?.height ?? 16838;
537
+ const topGutter = true === pageMargins.gutterAtTop && true !== pageMargins.mirrorMargins;
538
+ return pageMargins.left + pageMargins.right + (topGutter ? 0 : pageMargins.gutter) >= width || Math.abs(pageMargins.top) + Math.abs(pageMargins.bottom) + (topGutter ? pageMargins.gutter : 0) >= height;
539
+ }).length;
540
+ if (bounded) issues.push({
541
+ code: 'docx.page-margins.body-bounds',
542
+ severity: 'warning',
543
+ feature: 'Page-margin body bounds',
544
+ message: `${bounded} section(s) leave no positive body rectangle. Exact native values remain authoritative for DOCX output; browser rendering proportionally bounds the affected margin pair to retain a one-millimetre inspectable body surface.`
545
+ });
546
+ return issues;
547
+ }
548
+ function work_docx_page_margins_diagnostics_hasAncestor(element, localName) {
549
+ let ancestor = element.parentElement;
550
+ while(ancestor){
551
+ if (ancestor.localName === localName) return true;
552
+ ancestor = ancestor.parentElement;
553
+ }
554
+ return false;
555
+ }
556
+ function diagnoseDocxPageSize(document) {
557
+ const sections = descendants(document, 'sectPr').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '') && !work_docx_page_size_diagnostics_hasAncestor(element, 'sectPrChange'));
558
+ const sizes = sections.map(inspectDocxPageSize);
559
+ const sources = sections.map(inspectDocxPaperSource);
560
+ const validSizes = sizes.flatMap((item)=>'valid' === item.status && item.pageGeometry ? [
561
+ item.pageGeometry
562
+ ] : []);
563
+ const validSources = sources.flatMap((item)=>'valid' === item.status && item.paperSource ? [
564
+ item.paperSource
565
+ ] : []);
566
+ const invalidCount = [
567
+ ...sizes,
568
+ ...sources
569
+ ].reduce((count, item)=>count + item.invalidCount + item.spoofedCount, 0);
570
+ if (!validSizes.length && !validSources.length && !invalidCount) return [];
571
+ const issues = [];
572
+ if (validSizes.length) {
573
+ const customCodes = validSizes.filter((geometry)=>void 0 !== geometry.code).length;
574
+ const explicitOrientations = validSizes.filter((geometry)=>void 0 !== geometry.orientation).length;
575
+ issues.push({
576
+ code: 'docx.page-size',
577
+ severity: 'info',
578
+ feature: 'Page size',
579
+ message: `${validSizes.length} explicit section page-size set(s) preserve exact native width and height in twips, ${explicitOrientations} explicit orientation value(s), and ${customCodes} Word paper code(s) through editing, preview, PDF, and DOCX output. Strict OOXML universal measures are accepted only when they convert to an exact integer twip.`
580
+ });
581
+ }
582
+ if (validSources.length) issues.push({
583
+ code: 'docx.paper-source',
584
+ severity: 'info',
585
+ feature: 'Printer paper source',
586
+ message: `${validSources.length} section printer paper-source set(s) preserve their exact first-page and other-page tray codes in DOCX. The browser does not reinterpret printer-driver-specific tray numbers.`
587
+ });
588
+ if (invalidCount) issues.push({
589
+ code: 'docx.page-size.invalid',
590
+ severity: 'warning',
591
+ feature: 'Page setup',
592
+ message: `${invalidCount} malformed, duplicated, incomplete, out-of-range, namespace-spoofed, relationship-bound, or structurally invalid pgSz or paperSrc value(s) are ignored instead of becoming trusted page or printer geometry.`
593
+ });
594
+ const bounded = validSizes.filter((geometry)=>geometry.width < 1440 || geometry.height < 1440).length;
595
+ if (bounded) issues.push({
596
+ code: 'docx.page-size.browser-bounds',
597
+ severity: 'warning',
598
+ feature: 'Small page rendering',
599
+ message: `${bounded} valid section page-size set(s) use an edge below one inch. Exact native values remain authoritative for DOCX output; browser editing and PDF projection bound the affected edge to one inch so the page remains inspectable.`
600
+ });
601
+ return issues;
602
+ }
603
+ function work_docx_page_size_diagnostics_hasAncestor(element, localName) {
604
+ let ancestor = element.parentElement;
605
+ while(ancestor){
606
+ if (ancestor.localName === localName) return true;
607
+ ancestor = ancestor.parentElement;
608
+ }
609
+ return false;
610
+ }
611
+ async function diagnoseDocxParagraphBorders(archive, document) {
612
+ const stylesDocument = archive.has('word/styles.xml') ? await archive.xml('word/styles.xml') : null;
613
+ const themePath = archive.paths('word/theme/').find((path)=>/\/theme\d*\.xml$/i.test(path));
614
+ const themeDocument = themePath ? await archive.xml(themePath) : null;
615
+ const settingsDocument = archive.has('word/settings.xml') ? await archive.xml('word/settings.xml') : null;
616
+ const markers = markDocxParagraphBorders(document.cloneNode(true), createDocxParagraphStyleResolver(stylesDocument), createDocxThemeResolver(themeDocument, settingsDocument), createDocxTableStyleResolver(stylesDocument));
617
+ const nativeCount = Array.from(document.getElementsByTagName('*')).filter((element)=>'pBdr' === element.localName && element.parentElement?.localName === 'pPr' && DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '')).length;
618
+ if (!nativeCount && !markers.paragraphs.length && !markers.invalidCount && !markers.spoofedCount) return [];
619
+ const issues = [];
620
+ if (markers.paragraphs.length) {
621
+ const artCount = markers.paragraphs.reduce((count, paragraph)=>count + Object.values(paragraph.borders).filter((border)=>border && isDocumentParagraphArtBorderStyle(border.style)).length, 0);
622
+ const specialCount = markers.paragraphs.reduce((count, paragraph)=>count + Number(Boolean(paragraph.borders.between)) + Number(Boolean(paragraph.borders.bar)), 0);
623
+ issues.push({
624
+ code: 'docx.paragraph-borders',
625
+ severity: 'info',
626
+ feature: 'Paragraph borders',
627
+ message: `${markers.paragraphs.length} paragraph border set(s) resolve through document defaults, based-on paragraph styles, conditional table styles, and direct formatting. All six native edges, theme colors, widths, spacing, shadows, frames, and all Word line or art styles round-trip; ${artCount + specialCount} art, between-paragraph, or facing-page edge(s) use a bounded browser approximation while retaining native OOXML semantics.`
628
+ });
629
+ }
630
+ if (markers.invalidCount || markers.spoofedCount) issues.push({
631
+ code: 'docx.paragraph-borders.invalid',
632
+ severity: 'warning',
633
+ feature: 'Paragraph borders',
634
+ message: `${markers.invalidCount + markers.spoofedCount} malformed, out-of-order, duplicated, namespace-spoofed, relationship-bound, or unresolved theme paragraph border value(s) are ignored or normalized to explicit nil resets instead of inheriting stale formatting.`
635
+ });
636
+ return issues;
637
+ }
638
+ async function diagnoseDocxParagraphShading(archive, document) {
639
+ const stylesDocument = archive.has('word/styles.xml') ? await archive.xml('word/styles.xml') : null;
640
+ const themePath = archive.paths('word/theme/').find((path)=>/\/theme\d*\.xml$/i.test(path));
641
+ const themeDocument = themePath ? await archive.xml(themePath) : null;
642
+ const settingsDocument = archive.has('word/settings.xml') ? await archive.xml('word/settings.xml') : null;
643
+ const markers = markDocxParagraphShading(document.cloneNode(true), createDocxParagraphStyleResolver(stylesDocument), createDocxThemeResolver(themeDocument, settingsDocument), createDocxTableStyleResolver(stylesDocument));
644
+ const nativeCount = Array.from(document.getElementsByTagName('*')).filter((element)=>'shd' === element.localName && element.parentElement?.localName === 'pPr' && DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '')).length;
645
+ if (!nativeCount && !markers.paragraphs.length && !markers.invalidCount && !markers.spoofedCount) return [];
646
+ const issues = [];
647
+ if (markers.paragraphs.length) issues.push({
648
+ code: 'docx.paragraph-shading',
649
+ severity: 'info',
650
+ feature: 'Paragraph shading',
651
+ message: `${markers.paragraphs.length} paragraph shading value(s) resolve through document defaults, based-on paragraph styles, conditional table styles, and direct formatting. All Word pattern masks, direct or automatic foreground/background colors, and independently tinted or shaded theme references remain editable and round-trip to native w:shd markup.`
652
+ });
653
+ if (markers.invalidCount || markers.spoofedCount) issues.push({
654
+ code: 'docx.paragraph-shading.invalid',
655
+ severity: 'warning',
656
+ feature: 'Paragraph shading',
657
+ message: `${markers.invalidCount + markers.spoofedCount} malformed, duplicated, namespace-spoofed, relationship-bound, or unresolved theme paragraph shading value(s) are ignored or normalized to an explicit nil reset instead of inheriting stale formatting.`
658
+ });
659
+ return issues;
660
+ }
196
661
  const SUPPORTED_CHART_ELEMENTS = new Set([
197
662
  'barChart',
198
663
  'lineChart',
@@ -1163,35 +1628,64 @@ async function diagnoseXlsxPivots(archive) {
1163
1628
  }
1164
1629
  async function analyzeDocxCompatibility(file, messages) {
1165
1630
  const issues = [
1166
- work_office_diagnostics_issue('docx.page-layout', 'Page layout', 'Per-section paper size, orientation, basic margins, one-to-six equal or custom-width columns, section breaks, and explicit page breaks are preserved; exact pagination and line wrapping may normalize.')
1631
+ work_office_diagnostics_issue('docx.page-layout', 'Page layout', 'Per-section paper size, orientation, exact native page margins, one-to-six equal or custom-width columns, section breaks, and explicit page breaks are preserved; exact pagination and line wrapping may normalize.'),
1632
+ work_office_diagnostics_issue('docx.package-state', 'OOXML package state', 'Source-backed export retains safe source-only parts byte-for-byte and reconnects their content types and relationships. Passive relationship-free extensions in settings XML, uniquely matched style or numbering identities, stable picture drawings, unchanged native-identity paragraphs, stable table, row, or cell scopes, and uniquely matched footnote, endnote, comment, or comment-thread records are preserved against the final package graph. Text-stable direct, supported-hyperlink-wrapped, and eligible static-content-control note and comment runs retain paragraph, table, wrapper, run, and run-property metadata; native note tables and DrawingML pictures remain editable, note image relationships and media targets are repaired and validated, bounded structured OMML equations remain atomically updateable in supported Word stories, uniquely matched table-bearing rich-text controls are reconstructed, safe web, mail, and internal note/comment links are rebound to collision-free final relationship IDs, and content-control ID collisions are rewritten. Native note, comment, and note-picture identities survive reorderings, comment durable IDs are rebound to regenerated paragraph IDs, and eligible source font-table metadata is retained. Generated Word semantics remain authoritative; source-only, changed-text or table structure, malformed, duplicate or cross-kind, active, unsupported wrappers, mixed-semantic, unsafe relationship-bound, legacy VML, non-picture drawings, or unsupported rich content may normalize.', 'info')
1167
1633
  ];
1168
1634
  for (const message of messages)issues.push(work_office_diagnostics_issue(`docx.converter.${message.type}`, 'Document conversion', message.message, 'error' === message.type ? 'error' : 'warning'));
1169
1635
  try {
1170
1636
  const archive = await OoxmlPackage.load(await file.arrayBuffer());
1637
+ const packagePaths = archive.paths('');
1638
+ const normalizedPackagePaths = packagePaths.map((path)=>path.toLowerCase());
1171
1639
  const document = archive.has('word/document.xml') ? await archive.xml('word/document.xml') : null;
1640
+ if (normalizedPackagePaths.some((path)=>path.startsWith('_xmlsignatures/'))) issues.push(work_office_diagnostics_issue('docx.signatures.removed', 'Digital signatures', 'Package signatures become invalid after an edit and are deliberately omitted from the exported DOCX.'));
1641
+ if (normalizedPackagePaths.some((path)=>'word/vbaproject.bin' === path || 'word/vbadata.xml' === path || path.startsWith('word/activex/') || path.startsWith('customui/'))) issues.push(work_office_diagnostics_issue('docx.active-content.removed', 'Active content', 'VBA, ActiveX, and custom-ribbon parts are never executed and are omitted from the macro-free DOCX export.'));
1642
+ if (archive.has('word/fontTable.xml')) {
1643
+ const fontTable = await archive.xml('word/fontTable.xml');
1644
+ const embeddedFontReferences = [
1645
+ 'embedRegular',
1646
+ 'embedBold',
1647
+ 'embedItalic',
1648
+ 'embedBoldItalic'
1649
+ ].reduce((count, localName)=>count + descendants(fontTable, localName).length, 0);
1650
+ if (embeddedFontReferences) issues.push(work_office_diagnostics_issue('docx.embedded-fonts', 'Embedded fonts', `${embeddedFontReferences} embedded font reference(s) were found. Eligible internal obfuscated-font payloads, metadata, relationships, and remapped IDs survive source-backed DOCX export, but the browser editor, preview, and PDF renderer use registered A3S fonts or substitution and may wrap text differently.`));
1651
+ }
1172
1652
  if (archive.has('word/comments.xml')) {
1173
1653
  const comments = await archive.xml('word/comments.xml');
1174
1654
  const commentDefinitions = descendants(comments, 'comment');
1175
1655
  if (commentDefinitions.length) {
1176
- issues.push(work_office_diagnostics_issue('docx.comments', 'Comments', `${commentDefinitions.length} comment or reply record(s), text anchors, authors, dates, thread relationships, and resolved state are preserved and editable.`, 'info'));
1656
+ issues.push(work_office_diagnostics_issue('docx.comments', 'Comments', `${commentDefinitions.length} comment or reply record(s), stable native IDs, text anchors, authors, dates, thread relationships, resolved state, eligible durable IDs, unchanged direct-run formatting, safely rebound web, mail, or internal hyperlinks, and eligible static text content controls are preserved. Comment text remains editable.`, 'info'));
1177
1657
  if ([
1178
1658
  'tbl',
1179
1659
  'drawing',
1180
1660
  'pict',
1181
1661
  'sdt',
1182
1662
  'altChunk'
1183
- ].some((name)=>descendants(comments, name).length) || descendants(comments, 'rPr').length) issues.push(work_office_diagnostics_issue('docx.comments.formatting', 'Comment formatting', 'Comment text is editable, but rich formatting, tables, images, and content controls inside comments are normalized to plain text.'));
1663
+ ].some((name)=>descendants(comments, name).length) || descendants(comments, 'rPr').length || descendants(comments, 'hyperlink').length) issues.push(work_office_diagnostics_issue('docx.comments.formatting', 'Comment formatting', 'Relationship-free formatting on uniquely matched unchanged direct text runs and eligible reconstructed control runs is retained. Supported HTTP(S), mailto, and internal hyperlink wrappers keep stable formatting, safe tooltips, and collision-free relationship IDs. Eligible static rich-text or plain-text controls retain inline or contiguous block wrappers, aliases, tags, locks, rewritten collision IDs, appearance, color, end formatting, and passive metadata. Editing comment text or using active bindings, placeholder state, form or nested controls, tables, images, math, mixed hyperlinks, unsupported wrappers, malformed relationships, or relationship-bound properties normalizes the affected content to safe plain text.'));
1664
+ if (archive.has('word/commentsExtensible.xml') || archive.has('word/people.xml')) issues.push(work_office_diagnostics_issue('docx.comments.modern-sidecars', 'Modern comment metadata', 'Durable comment IDs are safely rebound, but follow-up flags, reactions, and people metadata in modern comment sidecars are not editable and are omitted rather than reattached to a stale comment identity.'));
1184
1665
  }
1185
1666
  }
1186
1667
  issues.push(...await diagnoseDocxNotes(archive, document));
1668
+ issues.push(...await diagnoseDocxEquations(archive, document));
1187
1669
  issues.push(...await diagnoseDocxPageChrome(archive));
1188
- if (archive.paths('word/embeddings/').length) issues.push(work_office_diagnostics_issue('docx.embedded', 'Embedded objects', 'Embedded Office and OLE objects remain in the original file only.'));
1670
+ if (archive.paths('word/embeddings/').length) issues.push(work_office_diagnostics_issue('docx.embedded', 'Embedded objects', 'Embedded Office and OLE payload parts plus safe relationships are retained in source-backed exports, but Work does not render or edit their object anchors; placement inside regenerated document XML may normalize.'));
1189
1671
  if (document) {
1672
+ issues.push(...diagnoseDocxPageSize(document));
1673
+ issues.push(...await diagnoseDocxPageMargins(archive, document));
1674
+ issues.push(...await diagnoseDocxPageBorders(archive, document));
1675
+ issues.push(...await diagnoseDocxParagraphBorders(archive, document));
1676
+ issues.push(...await diagnoseDocxParagraphShading(archive, document));
1677
+ const defaultCollapsedStates = descendants(document, 'pPr').map(parseDocxParagraphDefaultCollapsed).filter((state)=>'absent' !== state.status);
1678
+ if (defaultCollapsedStates.length) {
1679
+ const invalid = defaultCollapsedStates.filter((state)=>'invalid' === state.status).length;
1680
+ issues.push(work_office_diagnostics_issue('docx.headings.default-collapsed', 'Default-collapsed headings', invalid ? `Office 2013 default-collapsed heading state is preserved for exact core Word on/off values, but ${invalid} malformed or duplicated paragraph property value(s) are ignored instead of inheriting a stale state.` : "Office 2013 default-collapsed heading state is preserved as native paragraph metadata. Browser content remains expanded and editable because the property controls Word's initial document view rather than content visibility.", invalid ? 'warning' : 'info'));
1681
+ }
1682
+ if (descendants(document, 'AlternateContent').length) issues.push(work_office_diagnostics_issue('docx.markup-compatibility', 'Markup compatibility', '`mc:AlternateContent` branches outside supported stable paragraph, picture-drawing, table, row, or cell scopes can normalize. Safe settings-level and uniquely matched passive branches are preserved separately, but source-backed package preservation does not imply general body-content fallback preservation.'));
1683
+ issues.push(...await diagnoseDocxBookmarksAndLinks(archive, document));
1190
1684
  issues.push(...await diagnoseDocxCitations(archive, document));
1191
1685
  const captionDiagnostics = diagnoseDocxCaptions(document);
1192
1686
  issues.push(...captionDiagnostics.issues);
1193
- if (descendants(document, 'tbl').length) issues.push(work_office_diagnostics_issue('docx.tables', 'Tables', 'Table rows, non-splitting rows, repeated headers, cell shading, vertical alignment, per-edge borders, and paragraph-boundary row continuation remain editable. Layout algorithm, preferred auto, percentage, or pixel width, alignment, indent, table-level cell margins, and cell-level margin overrides are preserved independently across edit, preview, and DOCX export. Common inherited Word table styles apply whole-table, banded row or column, first or last row or column, corner-cell, border, fill, text-emphasis, paragraph alignment, direction, indents, spacing, line, pagination, and tab-stop rules before direct table, cell, paragraph, and run formatting. Theme tint and shade values resolve to stable RGB for edit, preview, and export; less-common conditional paragraph properties, semantic theme references after export, nested tables, and complex merged-cell flow may be normalized.'));
1194
- if (descendants(document, 'drawing').length || descendants(document, 'pict').length) issues.push(work_office_diagnostics_issue('docx.images', 'Images', 'Inline images and supported square or top-and-bottom floating images remain embedded with editable size, alternative text, alignment, and wrap distance. Precise offsets, crop, contour wrapping, layering, and unsupported drawing types may be normalized.'));
1687
+ if (descendants(document, 'tbl').length) issues.push(work_office_diagnostics_issue('docx.tables', 'Tables', 'Table rows, non-splitting rows, repeated headers, cell shading, vertical alignment, per-edge borders, and paragraph-boundary row continuation remain editable. Native row identities survive body and page-chrome HTML; uniquely matched passive extensions on stable table, row, and cell scopes and their property nodes are retained, while duplicate, cross-kind, relationship-bound, or semantic branches fail closed. Layout algorithm, preferred auto, percentage, or pixel width, alignment, indent, percentage or pixel column widths, table-level cell margins, and cell-level margin overrides are preserved independently across edit, preview, and DOCX export. Percentage column preferences use pixel grid widths as responsive browser fallbacks and remain coherent through merged cells. Nested tables retain independent edit and DOCX geometry, and tall outer rows can paginate at nested-row boundaries. Row-spanning cells continue through every covered physical row with in-cell page breaks and contiguous content ranges; combined row and column spans retain native DOCX merge semantics. Common inherited Word table styles apply whole-table, banded row or column, first or last row or column, corner-cell, border, fill, text-emphasis, paragraph alignment, direction, indents, spacing, line, pagination, and tab-stop rules before direct table, cell, paragraph, and run formatting. Theme tint and shade values resolve to stable RGB for edit and preview, while untouched run colors, run shading, cell fills, and per-edge borders retain their semantic theme references on export; explicit color edits use direct RGB. Less-common conditional paragraph properties may be normalized.'));
1688
+ if (descendants(document, 'drawing').length || descendants(document, 'pict').length) issues.push(work_office_diagnostics_issue('docx.images', 'Images', 'Inline images and supported square, tight, through, top-and-bottom, or no-wrap free-floating images remain embedded with editable size, alternative text, alignment, wrap side and distance where applicable, signed horizontal or vertical offsets relative to the column, paragraph, margin, or page, four-edge percentage cropping, and drawing-layer options. Aligned and precise DOCX anchors retain their distinct position semantics; inline and floating crop geometry round-trips as DrawingML source rectangles; tight or through anchors retain their ordered wrap polygons; no-wrap anchors remain outside the body text flow and use behind-text placement to choose their side of the text; and supported floating images preserve relative Z-order, overlap and cell-layout policy, and anchor locking. Inline and floating pictures retain unique drawing-property and anchor IDs together with their edit IDs. Copies receive independent identities while move, delete, undo, and relationship regeneration retain the original object identity. Unsupported drawing types may be normalized.'));
1195
1689
  const textRevisions = [
1196
1690
  ...descendants(document, 'ins'),
1197
1691
  ...descendants(document, 'del')
@@ -1208,7 +1702,7 @@ async function analyzeDocxCompatibility(file, messages) {
1208
1702
  'sectPrChange',
1209
1703
  'numberingChange'
1210
1704
  ].some((name)=>descendants(document, name).length)) issues.push(work_office_diagnostics_issue('docx.revisions.structural', 'Structural revisions', 'Moved content plus formatting, numbering, section, row, cell, and table-property revisions may be normalized; Work currently reviews body-text insertions and deletions.'));
1211
- if (captionDiagnostics.hasUnsupportedFields) issues.push(work_office_diagnostics_issue('docx.fields', 'Fields', 'Fields beyond supported body fields, citations, bibliographies, caption SEQ fields, and caption REF fields are converted to their current displayed value.'));
1705
+ if (captionDiagnostics.hasUnsupportedFields) issues.push(work_office_diagnostics_issue('docx.fields', 'Fields', 'Fields beyond supported body fields, citations, bibliographies, caption SEQ fields, and bookmark or caption REF fields are converted to their current displayed value.'));
1212
1706
  const sectionProperties = descendants(document, 'sectPr');
1213
1707
  const columnProperties = descendants(document, 'cols');
1214
1708
  if (sectionProperties.length > 1 || columnProperties.length) issues.push(work_office_diagnostics_issue('docx.sections', 'Sections and columns', `${sectionProperties.length || 1} section(s) and equal or custom-width column settings are preserved, editable, and applied to document PDF output.`, 'info'));