@beyondwork/docx-react-component 1.0.29 → 1.0.31

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 (383) hide show
  1. package/package.json +65 -96
  2. package/src/README.md +85 -0
  3. package/src/api/README.md +26 -0
  4. package/src/api/public-types.ts +1952 -0
  5. package/src/api/session-state.ts +62 -0
  6. package/src/compare/diff-engine.ts +623 -0
  7. package/src/compare/export-redlines.ts +280 -0
  8. package/src/compare/index.ts +25 -0
  9. package/src/compare/snapshot.ts +97 -0
  10. package/src/component-inventory.md +99 -0
  11. package/src/core/README.md +10 -0
  12. package/src/core/commands/README.md +3 -0
  13. package/{dist/chunk-TJBP2K4T.js → src/core/commands/formatting-commands.ts} +536 -196
  14. package/src/core/commands/image-commands.ts +373 -0
  15. package/src/core/commands/index.ts +1879 -0
  16. package/src/core/commands/list-commands.ts +565 -0
  17. package/src/core/commands/paragraph-layout-commands.ts +339 -0
  18. package/src/core/commands/review-commands.ts +108 -0
  19. package/{dist/core/commands/section-layout-commands.cjs → src/core/commands/section-layout-commands.ts} +340 -137
  20. package/src/core/commands/structural-helpers.ts +309 -0
  21. package/{dist/core/commands/style-commands.cjs → src/core/commands/style-commands.ts} +113 -65
  22. package/src/core/commands/table-structure-commands.ts +854 -0
  23. package/{dist/chunk-UZXBISGO.js → src/core/commands/text-commands.ts} +142 -86
  24. package/src/core/schema/README.md +3 -0
  25. package/src/core/schema/text-schema.ts +516 -0
  26. package/src/core/search/search-text.ts +357 -0
  27. package/src/core/selection/README.md +3 -0
  28. package/src/core/selection/mapping.ts +289 -0
  29. package/src/core/selection/review-anchors.ts +183 -0
  30. package/src/core/state/README.md +3 -0
  31. package/src/core/state/editor-state.ts +892 -0
  32. package/src/core/state/text-transaction.ts +869 -0
  33. package/src/formats/xlsx/io/parse-shared-strings.ts +41 -0
  34. package/src/formats/xlsx/io/parse-sheet.ts +459 -0
  35. package/src/formats/xlsx/io/parse-styles.ts +59 -0
  36. package/src/formats/xlsx/io/parse-workbook.ts +75 -0
  37. package/src/formats/xlsx/io/serialize-shared-strings.ts +72 -0
  38. package/src/formats/xlsx/io/serialize-sheet.ts +333 -0
  39. package/src/formats/xlsx/io/serialize-styles.ts +98 -0
  40. package/src/formats/xlsx/io/serialize-workbook.ts +429 -0
  41. package/src/formats/xlsx/io/xlsx-session.ts +314 -0
  42. package/src/formats/xlsx/model/cell.ts +189 -0
  43. package/src/formats/xlsx/model/sheet.ts +326 -0
  44. package/src/formats/xlsx/model/styles.ts +118 -0
  45. package/src/formats/xlsx/model/workbook.ts +453 -0
  46. package/src/formats/xlsx/runtime/cell-commands.ts +567 -0
  47. package/src/formats/xlsx/runtime/sheet-commands.ts +206 -0
  48. package/src/formats/xlsx/runtime/workbook-runtime.ts +177 -0
  49. package/src/formats/xlsx/runtime/workbook-transaction.ts +822 -0
  50. package/src/index.ts +142 -0
  51. package/src/io/README.md +10 -0
  52. package/src/io/docx-session.ts +3175 -0
  53. package/src/io/export/README.md +3 -0
  54. package/src/io/export/export-session.ts +220 -0
  55. package/src/io/export/minimal-docx.ts +115 -0
  56. package/src/io/export/reattach-preserved-parts.ts +54 -0
  57. package/src/io/export/serialize-comments.ts +947 -0
  58. package/src/io/export/serialize-footnotes.ts +394 -0
  59. package/src/io/export/serialize-headers-footers.ts +368 -0
  60. package/src/io/export/serialize-main-document.ts +1342 -0
  61. package/src/io/export/serialize-numbering.ts +218 -0
  62. package/src/io/export/serialize-revisions.ts +389 -0
  63. package/src/io/export/serialize-runtime-revisions.ts +463 -0
  64. package/src/io/export/serialize-tables.ts +174 -0
  65. package/src/io/export/split-review-boundaries.ts +356 -0
  66. package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
  67. package/src/io/export/table-properties-xml.ts +318 -0
  68. package/src/io/normalize/README.md +3 -0
  69. package/src/io/normalize/normalize-text.ts +670 -0
  70. package/src/io/ooxml/README.md +3 -0
  71. package/src/io/ooxml/highlight-colors.ts +39 -0
  72. package/src/io/ooxml/numbering-sentinels.ts +44 -0
  73. package/src/io/ooxml/parse-comments.ts +852 -0
  74. package/src/io/ooxml/parse-complex-content.ts +287 -0
  75. package/src/io/ooxml/parse-fields.ts +834 -0
  76. package/src/io/ooxml/parse-footnotes.ts +952 -0
  77. package/src/io/ooxml/parse-headers-footers.ts +1212 -0
  78. package/src/io/ooxml/parse-inline-media.ts +461 -0
  79. package/src/io/ooxml/parse-main-document.ts +2947 -0
  80. package/src/io/ooxml/parse-numbering.ts +747 -0
  81. package/src/io/ooxml/parse-revisions.ts +1045 -0
  82. package/src/io/ooxml/parse-settings.ts +184 -0
  83. package/src/io/ooxml/parse-shapes.ts +296 -0
  84. package/src/io/ooxml/parse-styles.ts +639 -0
  85. package/src/io/ooxml/parse-tables.ts +627 -0
  86. package/src/io/ooxml/parse-theme.ts +346 -0
  87. package/src/io/ooxml/part-manifest.ts +136 -0
  88. package/src/io/ooxml/revision-boundaries.ts +475 -0
  89. package/src/io/ooxml/workflow-payload.ts +544 -0
  90. package/src/io/opc/README.md +3 -0
  91. package/src/io/opc/corrupt-package.ts +166 -0
  92. package/src/io/opc/docx-package.ts +74 -0
  93. package/src/io/opc/package-reader.ts +325 -0
  94. package/src/io/opc/package-writer.ts +273 -0
  95. package/src/io/source-package-provenance.ts +241 -0
  96. package/{dist/chunk-RMH72RZI.js → src/legal/bookmarks.ts} +130 -44
  97. package/src/legal/cross-references.ts +414 -0
  98. package/src/legal/defined-terms.ts +203 -0
  99. package/src/legal/index.ts +32 -0
  100. package/src/legal/signature-blocks.ts +259 -0
  101. package/src/model/README.md +3 -0
  102. package/src/model/canonical-document.ts +2722 -0
  103. package/src/model/cds-1.0.0.ts +212 -0
  104. package/src/model/snapshot.ts +760 -0
  105. package/src/preservation/README.md +3 -0
  106. package/src/preservation/markup-compatibility.ts +48 -0
  107. package/src/preservation/opaque-fragment-store.ts +89 -0
  108. package/src/preservation/opaque-region.ts +233 -0
  109. package/src/preservation/package-preservation.ts +113 -0
  110. package/src/preservation/preserved-part-manifest.ts +56 -0
  111. package/src/preservation/relationship-retention.ts +57 -0
  112. package/src/preservation/store.ts +255 -0
  113. package/src/review/README.md +16 -0
  114. package/src/review/store/README.md +3 -0
  115. package/src/review/store/comment-anchors.ts +70 -0
  116. package/src/review/store/comment-remapping.ts +154 -0
  117. package/src/review/store/comment-store.ts +349 -0
  118. package/src/review/store/comment-thread.ts +109 -0
  119. package/src/review/store/revision-actions.ts +423 -0
  120. package/src/review/store/revision-store.ts +323 -0
  121. package/src/review/store/revision-types.ts +182 -0
  122. package/src/review/store/runtime-comment-store.ts +43 -0
  123. package/src/runtime/README.md +3 -0
  124. package/src/runtime/ai-action-policy.ts +764 -0
  125. package/src/runtime/context-analytics.ts +824 -0
  126. package/src/runtime/document-layout.ts +332 -0
  127. package/src/runtime/document-locations.ts +521 -0
  128. package/src/runtime/document-navigation.ts +616 -0
  129. package/src/runtime/document-outline.ts +440 -0
  130. package/src/runtime/document-runtime.ts +4055 -0
  131. package/src/runtime/document-search.ts +145 -0
  132. package/src/runtime/event-refresh-hints.ts +137 -0
  133. package/src/runtime/numbering-prefix.ts +244 -0
  134. package/src/runtime/page-layout-estimation.ts +305 -0
  135. package/src/runtime/read-only-diagnostics-runtime.ts +241 -0
  136. package/src/runtime/resolved-numbering-geometry.ts +293 -0
  137. package/src/runtime/review-runtime.ts +44 -0
  138. package/src/runtime/revision-runtime.ts +107 -0
  139. package/src/runtime/session-capabilities.ts +192 -0
  140. package/src/runtime/story-context.ts +164 -0
  141. package/src/runtime/story-targeting.ts +162 -0
  142. package/src/runtime/suggestions-snapshot.ts +137 -0
  143. package/src/runtime/surface-projection.ts +1553 -0
  144. package/src/runtime/table-commands.ts +173 -0
  145. package/src/runtime/table-schema.ts +309 -0
  146. package/src/runtime/table-style-resolver.ts +409 -0
  147. package/src/runtime/view-state.ts +493 -0
  148. package/src/runtime/virtualized-rendering.ts +258 -0
  149. package/src/runtime/workflow-markup.ts +393 -0
  150. package/src/ui/README.md +30 -0
  151. package/src/ui/WordReviewEditor.tsx +5268 -0
  152. package/src/ui/browser-export.ts +52 -0
  153. package/src/ui/comments/README.md +3 -0
  154. package/src/ui/compatibility/README.md +3 -0
  155. package/src/ui/editor-command-bag.ts +127 -0
  156. package/src/ui/editor-runtime-boundary.ts +1558 -0
  157. package/src/ui/editor-shell-view.tsx +144 -0
  158. package/src/ui/editor-surface/README.md +3 -0
  159. package/src/ui/editor-surface-controller.tsx +66 -0
  160. package/src/ui/headless/comment-decoration-model.ts +124 -0
  161. package/src/ui/headless/preserve-editor-selection.ts +5 -0
  162. package/src/ui/headless/revision-decoration-model.ts +128 -0
  163. package/src/ui/headless/selection-helpers.ts +54 -0
  164. package/src/ui/headless/selection-tool-context.ts +19 -0
  165. package/src/ui/headless/selection-tool-resolver.ts +752 -0
  166. package/src/ui/headless/selection-tool-types.ts +129 -0
  167. package/src/ui/headless/selection-toolbar-model.ts +11 -0
  168. package/src/ui/headless/use-editor-keyboard.ts +103 -0
  169. package/src/ui/review/README.md +3 -0
  170. package/src/ui/runtime-shortcut-dispatch.ts +365 -0
  171. package/src/ui/runtime-snapshot-selectors.ts +197 -0
  172. package/src/ui/shared/revision-filters.ts +31 -0
  173. package/src/ui/status/README.md +3 -0
  174. package/src/ui/theme/README.md +3 -0
  175. package/src/ui/toolbar/README.md +3 -0
  176. package/src/ui/workflow-surface-blocked-rails.ts +94 -0
  177. package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
  178. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
  179. package/src/ui-tailwind/chrome/responsive-chrome.ts +46 -0
  180. package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
  181. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +64 -0
  182. package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
  183. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +121 -0
  184. package/src/ui-tailwind/chrome/tw-layout-panel.tsx +114 -0
  185. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +30 -0
  186. package/src/ui-tailwind/chrome/tw-page-ruler.tsx +365 -0
  187. package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
  188. package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
  189. package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
  190. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +303 -0
  191. package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
  192. package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
  193. package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
  194. package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +186 -0
  195. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +139 -0
  196. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +250 -0
  197. package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +58 -0
  198. package/src/ui-tailwind/chrome/use-before-unload.ts +20 -0
  199. package/src/ui-tailwind/editor-surface/perf-probe.ts +179 -0
  200. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +189 -0
  201. package/src/ui-tailwind/editor-surface/pm-contextual-ui.ts +31 -0
  202. package/src/ui-tailwind/editor-surface/pm-decorations.ts +411 -0
  203. package/src/ui-tailwind/editor-surface/pm-position-map.ts +123 -0
  204. package/src/ui-tailwind/editor-surface/pm-schema.ts +927 -0
  205. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +567 -0
  206. package/src/ui-tailwind/editor-surface/search-plugin.ts +168 -0
  207. package/src/ui-tailwind/editor-surface/surface-build-keys.ts +63 -0
  208. package/src/ui-tailwind/editor-surface/tw-caret.tsx +12 -0
  209. package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +150 -0
  210. package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +129 -0
  211. package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +58 -0
  212. package/src/ui-tailwind/editor-surface/tw-paragraph-block.tsx +151 -0
  213. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +1047 -0
  214. package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +111 -0
  215. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +503 -0
  216. package/src/ui-tailwind/index.ts +62 -0
  217. package/src/ui-tailwind/page-chrome-model.ts +27 -0
  218. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +406 -0
  219. package/src/ui-tailwind/review/tw-health-panel.tsx +149 -0
  220. package/src/ui-tailwind/review/tw-review-rail.tsx +130 -0
  221. package/src/ui-tailwind/review/tw-revision-sidebar.tsx +164 -0
  222. package/src/ui-tailwind/status/tw-status-bar.tsx +65 -0
  223. package/{dist → src}/ui-tailwind/theme/editor-theme.css +58 -40
  224. package/src/ui-tailwind/toolbar/toolbar-layout.ts +47 -0
  225. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +52 -0
  226. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +1478 -0
  227. package/src/ui-tailwind/tw-review-workspace.tsx +1587 -0
  228. package/src/validation/README.md +3 -0
  229. package/src/validation/compatibility-engine.ts +878 -0
  230. package/src/validation/compatibility-report.ts +161 -0
  231. package/src/validation/diagnostics.ts +204 -0
  232. package/src/validation/docx-comment-proof.ts +720 -0
  233. package/src/validation/import-diagnostics.ts +128 -0
  234. package/src/validation/low-priority-word-surfaces.ts +373 -0
  235. package/dist/canonical-document-BLEbzL2J.d.cts +0 -844
  236. package/dist/canonical-document-BLEbzL2J.d.ts +0 -844
  237. package/dist/chunk-2FJS5GZM.js +0 -763
  238. package/dist/chunk-2FJS5GZM.js.map +0 -1
  239. package/dist/chunk-2OQBZS3F.js +0 -446
  240. package/dist/chunk-2OQBZS3F.js.map +0 -1
  241. package/dist/chunk-2S7W4KFO.js +0 -127
  242. package/dist/chunk-2S7W4KFO.js.map +0 -1
  243. package/dist/chunk-2TG72QSW.js +0 -3874
  244. package/dist/chunk-2TG72QSW.js.map +0 -1
  245. package/dist/chunk-36QNIZBO.js +0 -532
  246. package/dist/chunk-36QNIZBO.js.map +0 -1
  247. package/dist/chunk-4AQOYAW4.js +0 -3069
  248. package/dist/chunk-4AQOYAW4.js.map +0 -1
  249. package/dist/chunk-4D5EWJ3P.js +0 -77
  250. package/dist/chunk-4D5EWJ3P.js.map +0 -1
  251. package/dist/chunk-5FN54NDH.js +0 -2257
  252. package/dist/chunk-5FN54NDH.js.map +0 -1
  253. package/dist/chunk-BOYGQYRQ.js +0 -7306
  254. package/dist/chunk-BOYGQYRQ.js.map +0 -1
  255. package/dist/chunk-CN3XMECL.js +0 -212
  256. package/dist/chunk-CN3XMECL.js.map +0 -1
  257. package/dist/chunk-EBI3BX6U.js +0 -164
  258. package/dist/chunk-EBI3BX6U.js.map +0 -1
  259. package/dist/chunk-EILUG3VB.js +0 -1275
  260. package/dist/chunk-EILUG3VB.js.map +0 -1
  261. package/dist/chunk-FUDY333O.js +0 -70
  262. package/dist/chunk-FUDY333O.js.map +0 -1
  263. package/dist/chunk-GBVOWFIK.js +0 -1237
  264. package/dist/chunk-GBVOWFIK.js.map +0 -1
  265. package/dist/chunk-H4TQ3H3Y.js +0 -262
  266. package/dist/chunk-H4TQ3H3Y.js.map +0 -1
  267. package/dist/chunk-JGB3IXZO.js +0 -189
  268. package/dist/chunk-JGB3IXZO.js.map +0 -1
  269. package/dist/chunk-KD2QRQPY.js +0 -4342
  270. package/dist/chunk-KD2QRQPY.js.map +0 -1
  271. package/dist/chunk-KLMXQVYK.js +0 -369
  272. package/dist/chunk-KLMXQVYK.js.map +0 -1
  273. package/dist/chunk-KZUG5KFQ.js +0 -214
  274. package/dist/chunk-KZUG5KFQ.js.map +0 -1
  275. package/dist/chunk-QDAQ4CJU.js +0 -345
  276. package/dist/chunk-QDAQ4CJU.js.map +0 -1
  277. package/dist/chunk-RMH72RZI.js.map +0 -1
  278. package/dist/chunk-SWKWQZXM.js +0 -117
  279. package/dist/chunk-SWKWQZXM.js.map +0 -1
  280. package/dist/chunk-TJBP2K4T.js.map +0 -1
  281. package/dist/chunk-TLCEAQDQ.js +0 -542
  282. package/dist/chunk-TLCEAQDQ.js.map +0 -1
  283. package/dist/chunk-UZXBISGO.js.map +0 -1
  284. package/dist/chunk-WGBAKP3Q.js +0 -3220
  285. package/dist/chunk-WGBAKP3Q.js.map +0 -1
  286. package/dist/compare/index.cjs +0 -5475
  287. package/dist/compare/index.cjs.map +0 -1
  288. package/dist/compare/index.d.cts +0 -114
  289. package/dist/compare/index.d.ts +0 -114
  290. package/dist/compare/index.js +0 -731
  291. package/dist/compare/index.js.map +0 -1
  292. package/dist/core/commands/formatting-commands.cjs +0 -828
  293. package/dist/core/commands/formatting-commands.cjs.map +0 -1
  294. package/dist/core/commands/formatting-commands.d.cts +0 -63
  295. package/dist/core/commands/formatting-commands.d.ts +0 -63
  296. package/dist/core/commands/formatting-commands.js +0 -37
  297. package/dist/core/commands/formatting-commands.js.map +0 -1
  298. package/dist/core/commands/image-commands.cjs +0 -2023
  299. package/dist/core/commands/image-commands.cjs.map +0 -1
  300. package/dist/core/commands/image-commands.d.cts +0 -58
  301. package/dist/core/commands/image-commands.d.ts +0 -58
  302. package/dist/core/commands/image-commands.js +0 -18
  303. package/dist/core/commands/image-commands.js.map +0 -1
  304. package/dist/core/commands/section-layout-commands.cjs.map +0 -1
  305. package/dist/core/commands/section-layout-commands.d.cts +0 -62
  306. package/dist/core/commands/section-layout-commands.d.ts +0 -62
  307. package/dist/core/commands/section-layout-commands.js +0 -21
  308. package/dist/core/commands/section-layout-commands.js.map +0 -1
  309. package/dist/core/commands/style-commands.cjs.map +0 -1
  310. package/dist/core/commands/style-commands.d.cts +0 -13
  311. package/dist/core/commands/style-commands.d.ts +0 -13
  312. package/dist/core/commands/style-commands.js +0 -9
  313. package/dist/core/commands/style-commands.js.map +0 -1
  314. package/dist/core/commands/table-structure-commands.cjs +0 -1883
  315. package/dist/core/commands/table-structure-commands.cjs.map +0 -1
  316. package/dist/core/commands/table-structure-commands.d.cts +0 -59
  317. package/dist/core/commands/table-structure-commands.d.ts +0 -59
  318. package/dist/core/commands/table-structure-commands.js +0 -12
  319. package/dist/core/commands/table-structure-commands.js.map +0 -1
  320. package/dist/core/commands/text-commands.cjs +0 -2391
  321. package/dist/core/commands/text-commands.cjs.map +0 -1
  322. package/dist/core/commands/text-commands.d.cts +0 -24
  323. package/dist/core/commands/text-commands.d.ts +0 -24
  324. package/dist/core/commands/text-commands.js +0 -28
  325. package/dist/core/commands/text-commands.js.map +0 -1
  326. package/dist/core/selection/mapping.cjs +0 -200
  327. package/dist/core/selection/mapping.cjs.map +0 -1
  328. package/dist/core/selection/mapping.d.cts +0 -2
  329. package/dist/core/selection/mapping.d.ts +0 -2
  330. package/dist/core/selection/mapping.js +0 -31
  331. package/dist/core/selection/mapping.js.map +0 -1
  332. package/dist/core/state/editor-state.cjs +0 -2278
  333. package/dist/core/state/editor-state.cjs.map +0 -1
  334. package/dist/core/state/editor-state.d.cts +0 -2
  335. package/dist/core/state/editor-state.d.ts +0 -2
  336. package/dist/core/state/editor-state.js +0 -26
  337. package/dist/core/state/editor-state.js.map +0 -1
  338. package/dist/index.cjs +0 -38553
  339. package/dist/index.cjs.map +0 -1
  340. package/dist/index.d.cts +0 -15
  341. package/dist/index.d.ts +0 -15
  342. package/dist/index.js +0 -7856
  343. package/dist/index.js.map +0 -1
  344. package/dist/io/docx-session.cjs +0 -16236
  345. package/dist/io/docx-session.cjs.map +0 -1
  346. package/dist/io/docx-session.d.cts +0 -21
  347. package/dist/io/docx-session.d.ts +0 -21
  348. package/dist/io/docx-session.js +0 -18
  349. package/dist/io/docx-session.js.map +0 -1
  350. package/dist/legal/index.cjs +0 -3900
  351. package/dist/legal/index.cjs.map +0 -1
  352. package/dist/legal/index.d.cts +0 -86
  353. package/dist/legal/index.d.ts +0 -86
  354. package/dist/legal/index.js +0 -616
  355. package/dist/legal/index.js.map +0 -1
  356. package/dist/public-types-7ZL_94cz.d.ts +0 -1573
  357. package/dist/public-types-CeMaDueh.d.cts +0 -1573
  358. package/dist/public-types.cjs +0 -19
  359. package/dist/public-types.cjs.map +0 -1
  360. package/dist/public-types.d.cts +0 -2
  361. package/dist/public-types.d.ts +0 -2
  362. package/dist/public-types.js +0 -1
  363. package/dist/public-types.js.map +0 -1
  364. package/dist/runtime/document-runtime.cjs +0 -11140
  365. package/dist/runtime/document-runtime.cjs.map +0 -1
  366. package/dist/runtime/document-runtime.d.cts +0 -231
  367. package/dist/runtime/document-runtime.d.ts +0 -231
  368. package/dist/runtime/document-runtime.js +0 -21
  369. package/dist/runtime/document-runtime.js.map +0 -1
  370. package/dist/structural-helpers-CilgOVhh.d.cts +0 -10
  371. package/dist/structural-helpers-q0Gd-eBN.d.ts +0 -10
  372. package/dist/ui-tailwind/editor-surface/search-plugin.cjs +0 -313
  373. package/dist/ui-tailwind/editor-surface/search-plugin.cjs.map +0 -1
  374. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +0 -67
  375. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +0 -67
  376. package/dist/ui-tailwind/editor-surface/search-plugin.js +0 -23
  377. package/dist/ui-tailwind/editor-surface/search-plugin.js.map +0 -1
  378. package/dist/ui-tailwind/index.cjs +0 -4833
  379. package/dist/ui-tailwind/index.cjs.map +0 -1
  380. package/dist/ui-tailwind/index.d.cts +0 -617
  381. package/dist/ui-tailwind/index.d.ts +0 -617
  382. package/dist/ui-tailwind/index.js +0 -575
  383. package/dist/ui-tailwind/index.js.map +0 -1
@@ -0,0 +1,1045 @@
1
+ import { createDetachedAnchor } from "../../core/selection/mapping.ts";
2
+ import {
3
+ createRevisionRecord,
4
+ type RevisionRecord,
5
+ } from "../../review/store/revision-store.ts";
6
+ import {
7
+ createRevisionRangeAnchor,
8
+ type MoveData,
9
+ type PropertyChangeData,
10
+ type RevisionKind,
11
+ } from "../../review/store/revision-types.ts";
12
+ import {
13
+ findChildElement,
14
+ findRequiredChildElement,
15
+ localName,
16
+ mapRevisionBoundaries,
17
+ parseXmlWithPositions,
18
+ type RevisionParagraphBoundary,
19
+ type XmlElementNode,
20
+ type XmlNode,
21
+ } from "./revision-boundaries.ts";
22
+
23
+ export interface PreservedRevisionMarkup {
24
+ revisionId: string;
25
+ rawXml: string;
26
+ xmlStart: number;
27
+ xmlEnd: number;
28
+ originalRevisionType: string;
29
+ paragraphIndex?: number;
30
+ containerXmlStart?: number;
31
+ containerXmlEnd?: number;
32
+ beforeContainerXml?: string;
33
+ }
34
+
35
+ export interface RevisionImportDiagnostic {
36
+ revisionId: string;
37
+ code:
38
+ | "preserve_only_move_revision"
39
+ | "preserve_only_formatting_revision"
40
+ | "nested_revision_preserve_only"
41
+ | "shallow_nested_revision_promoted"
42
+ | "linked_move_pair"
43
+ | "unlinked_move_revision"
44
+ | "ambiguous_revision_anchor"
45
+ | "table_structural_revision_preserve_only"
46
+ | "table_property_revision_parsed";
47
+ message: string;
48
+ featureClass: "preserve-only" | "supported" | "informational";
49
+ }
50
+
51
+ export interface ParsedRevisionsResult {
52
+ revisions: RevisionRecord[];
53
+ preservedMarkup: PreservedRevisionMarkup[];
54
+ diagnostics: RevisionImportDiagnostic[];
55
+ boundaries: RevisionParagraphBoundary[];
56
+ }
57
+
58
+ interface ParseState {
59
+ documentXml: string;
60
+ boundaries: RevisionParagraphBoundary[];
61
+ revisions: RevisionRecord[];
62
+ preservedMarkup: PreservedRevisionMarkup[];
63
+ diagnostics: RevisionImportDiagnostic[];
64
+ nextGeneratedIndex: number;
65
+ }
66
+
67
+ interface RevisionMetadata {
68
+ revisionId: string;
69
+ ooxmlRevisionId?: string;
70
+ authorId: string;
71
+ createdAt: string;
72
+ }
73
+
74
+ const SUPPORTED_CONTAINER_TYPES = new Set(["ins", "del"]);
75
+ const PRESERVE_ONLY_CONTAINER_TYPES = new Set(["moveFrom", "moveTo"]);
76
+ const PROPERTY_CHANGE_REVISION_TYPES = new Set(["rPrChange", "pPrChange"]);
77
+ const STRUCTURAL_TABLE_REVISION_TYPES = new Set(["cellIns", "cellDel", "cellMerge"]);
78
+
79
+ export function parseRevisionsFromDocumentXml(
80
+ documentXml: string,
81
+ ): ParsedRevisionsResult {
82
+ const root = parseXmlWithPositions(documentXml);
83
+ const documentElement = findRequiredChildElement(root, "document");
84
+ const bodyElement = findRequiredChildElement(documentElement, "body");
85
+ const boundaries = mapRevisionBoundaries(documentXml);
86
+ const state: ParseState = {
87
+ documentXml,
88
+ boundaries,
89
+ revisions: [],
90
+ preservedMarkup: [],
91
+ diagnostics: [],
92
+ nextGeneratedIndex: 1,
93
+ };
94
+
95
+ let paragraphIndex = -1;
96
+ let cursor = 0;
97
+ let previousWasParagraph = false;
98
+
99
+ for (const child of bodyElement.children) {
100
+ if (child.type !== "element") {
101
+ continue;
102
+ }
103
+
104
+ const childType = localName(child.name);
105
+
106
+ if (childType !== "p") {
107
+ if (childType === "tbl") {
108
+ parseTblPropertyRevisions(child, cursor, state);
109
+ const nested = parseNestedParagraphContainers(
110
+ child.children,
111
+ paragraphIndex,
112
+ cursor,
113
+ previousWasParagraph,
114
+ state,
115
+ );
116
+ paragraphIndex = nested.paragraphIndex;
117
+ cursor = nested.cursor;
118
+ previousWasParagraph = nested.previousWasParagraph;
119
+ } else if (childType === "sectPr") {
120
+ parseSectPrRevisions(child, cursor, state);
121
+ cursor += 1;
122
+ previousWasParagraph = false;
123
+ } else {
124
+ cursor += 1;
125
+ previousWasParagraph = false;
126
+ }
127
+ continue;
128
+ }
129
+
130
+ if (previousWasParagraph) {
131
+ cursor += 1;
132
+ }
133
+ paragraphIndex += 1;
134
+ const paragraphBoundary = boundaries[paragraphIndex];
135
+ if (!paragraphBoundary) {
136
+ continue;
137
+ }
138
+
139
+ parseParagraphMarkRevisions(child, paragraphBoundary, state);
140
+ walkParagraphContent(child.children, paragraphIndex, state, () => cursor, (next) => {
141
+ cursor = next;
142
+ });
143
+ previousWasParagraph = true;
144
+ }
145
+
146
+ linkMoveRevisionPairs(state);
147
+
148
+ return {
149
+ revisions: state.revisions,
150
+ preservedMarkup: state.preservedMarkup.sort((left, right) => left.xmlStart - right.xmlStart),
151
+ diagnostics: state.diagnostics,
152
+ boundaries,
153
+ };
154
+ }
155
+
156
+ function parseNestedParagraphContainers(
157
+ nodes: XmlNode[],
158
+ paragraphIndex: number,
159
+ cursor: number,
160
+ previousWasParagraph: boolean,
161
+ state: ParseState,
162
+ ): {
163
+ paragraphIndex: number;
164
+ cursor: number;
165
+ previousWasParagraph: boolean;
166
+ } {
167
+ let nextParagraphIndex = paragraphIndex;
168
+ let nextCursor = cursor;
169
+ let nextPreviousWasParagraph = previousWasParagraph;
170
+
171
+ for (const node of nodes) {
172
+ if (node.type !== "element") {
173
+ continue;
174
+ }
175
+
176
+ const type = localName(node.name);
177
+ if (type === "p") {
178
+ nextParagraphIndex += 1;
179
+ const paragraphBoundary = state.boundaries[nextParagraphIndex];
180
+ if (!paragraphBoundary) {
181
+ continue;
182
+ }
183
+ parseParagraphMarkRevisions(node, paragraphBoundary, state);
184
+ walkParagraphContent(node.children, nextParagraphIndex, state, () => nextCursor, (next) => {
185
+ nextCursor = next;
186
+ });
187
+ nextPreviousWasParagraph = false;
188
+ continue;
189
+ }
190
+
191
+ if (
192
+ type === "tbl" ||
193
+ type === "tr" ||
194
+ type === "tc" ||
195
+ type === "sdtContent" ||
196
+ type === "customXml" ||
197
+ type === "smartTag"
198
+ ) {
199
+ const nested = parseNestedParagraphContainers(
200
+ node.children,
201
+ nextParagraphIndex,
202
+ nextCursor,
203
+ nextPreviousWasParagraph,
204
+ state,
205
+ );
206
+ nextParagraphIndex = nested.paragraphIndex;
207
+ nextCursor = nested.cursor;
208
+ nextPreviousWasParagraph = nested.previousWasParagraph;
209
+ continue;
210
+ }
211
+
212
+ if (
213
+ type === "tblPr" ||
214
+ type === "tblGrid" ||
215
+ type === "gridCol" ||
216
+ type === "trPr" ||
217
+ type === "tcPr"
218
+ ) {
219
+ continue;
220
+ }
221
+
222
+ nextCursor += 1;
223
+ nextPreviousWasParagraph = false;
224
+ }
225
+
226
+ return {
227
+ paragraphIndex: nextParagraphIndex,
228
+ cursor: nextCursor,
229
+ previousWasParagraph: nextPreviousWasParagraph,
230
+ };
231
+ }
232
+
233
+ export function parseRevisionsFromStoryXml(
234
+ storyXml: string,
235
+ ): ParsedRevisionsResult {
236
+ const xmlDeclMatch = storyXml.match(/^<\?xml[\s\S]*?\?>\s*/u);
237
+ const withoutDecl = xmlDeclMatch ? storyXml.slice(xmlDeclMatch[0].length) : storyXml;
238
+ const rootMatch = withoutDecl.match(/^<([A-Za-z0-9:._-]+)([^>]*)>([\s\S]*)<\/\1>\s*$/u);
239
+ if (!rootMatch) {
240
+ return {
241
+ revisions: [],
242
+ preservedMarkup: [],
243
+ diagnostics: [],
244
+ boundaries: [],
245
+ };
246
+ }
247
+
248
+ const innerXml = rootMatch[3] ?? "";
249
+ const wrapped =
250
+ `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
251
+ `<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">` +
252
+ `<w:body>${innerXml}</w:body></w:document>`;
253
+ return parseRevisionsFromDocumentXml(wrapped);
254
+ }
255
+
256
+ function parseParagraphMarkRevisions(
257
+ paragraph: XmlElementNode,
258
+ boundary: RevisionParagraphBoundary,
259
+ state: ParseState,
260
+ ): void {
261
+ const paragraphProperties = findChildElement(paragraph, "pPr");
262
+ const paragraphRunProperties = paragraphProperties
263
+ ? findChildElement(paragraphProperties, "rPr")
264
+ : undefined;
265
+
266
+ if (!paragraphProperties) {
267
+ return;
268
+ }
269
+
270
+ const paragraphRange =
271
+ boundary.start === boundary.end
272
+ ? createRevisionRangeAnchor(boundary.end, boundary.end)
273
+ : createRevisionRangeAnchor(boundary.start, boundary.end);
274
+
275
+ for (const child of paragraphProperties.children) {
276
+ if (child.type !== "element") {
277
+ continue;
278
+ }
279
+
280
+ const type = localName(child.name);
281
+ if (type === "pPrChange") {
282
+ const metadata = readRevisionMetadata(child, state, "property-change");
283
+ const innerPPr = findChildElement(child, "pPr");
284
+ const beforeXml = innerPPr ? state.documentXml.slice(innerPPr.start, innerPPr.end) : "";
285
+ const propertyChangeData: PropertyChangeData = {
286
+ xmlTag: "pPrChange",
287
+ beforeXml,
288
+ };
289
+ state.revisions.push(
290
+ createRevisionRecord({
291
+ revisionId: metadata.revisionId,
292
+ kind: "property-change",
293
+ anchor: paragraphRange,
294
+ authorId: metadata.authorId,
295
+ createdAt: metadata.createdAt,
296
+ metadata: {
297
+ source: "import",
298
+ originalRevisionType: "pPrChange",
299
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
300
+ propertyChangeData,
301
+ },
302
+ }),
303
+ );
304
+ state.preservedMarkup.push({
305
+ revisionId: metadata.revisionId,
306
+ rawXml: state.documentXml.slice(child.start, child.end),
307
+ xmlStart: child.start,
308
+ xmlEnd: child.end,
309
+ originalRevisionType: "pPrChange",
310
+ containerXmlStart: paragraphProperties.start,
311
+ containerXmlEnd: paragraphProperties.end,
312
+ beforeContainerXml: beforeXml,
313
+ });
314
+ }
315
+ }
316
+
317
+ if (!paragraphRunProperties) {
318
+ return;
319
+ }
320
+
321
+ for (const child of paragraphRunProperties.children) {
322
+ if (child.type !== "element") {
323
+ continue;
324
+ }
325
+
326
+ const type = localName(child.name);
327
+ if (!SUPPORTED_CONTAINER_TYPES.has(type)) {
328
+ continue;
329
+ }
330
+
331
+ const metadata = readRevisionMetadata(child, state, type);
332
+ state.revisions.push(
333
+ createRevisionRecord({
334
+ revisionId: metadata.revisionId,
335
+ kind: type === "ins" ? "insertion" : "deletion",
336
+ anchor: createRevisionRangeAnchor(boundary.end, boundary.end),
337
+ authorId: metadata.authorId,
338
+ createdAt: metadata.createdAt,
339
+ metadata: {
340
+ source: "import",
341
+ semanticKind: "structural-change",
342
+ importedRevisionForm:
343
+ type === "ins" ? "paragraph-insertion" : "paragraph-deletion",
344
+ originalRevisionType: `paragraph-${type}`,
345
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
346
+ },
347
+ }),
348
+ );
349
+ state.preservedMarkup.push({
350
+ revisionId: metadata.revisionId,
351
+ rawXml: state.documentXml.slice(child.start, child.end),
352
+ xmlStart: child.start,
353
+ xmlEnd: child.end,
354
+ originalRevisionType: `paragraph-${type}`,
355
+ paragraphIndex: boundary.paragraphIndex,
356
+ });
357
+ }
358
+ }
359
+
360
+ function walkParagraphContent(
361
+ nodes: XmlNode[],
362
+ paragraphIndex: number,
363
+ state: ParseState,
364
+ getCursor: () => number,
365
+ setCursor: (next: number) => void,
366
+ ): void {
367
+ for (const node of nodes) {
368
+ walkContentNode(node, paragraphIndex, state, getCursor, setCursor);
369
+ }
370
+ }
371
+
372
+ function walkContentNode(
373
+ node: XmlNode,
374
+ paragraphIndex: number,
375
+ state: ParseState,
376
+ getCursor: () => number,
377
+ setCursor: (next: number) => void,
378
+ ): void {
379
+ if (node.type !== "element") {
380
+ return;
381
+ }
382
+
383
+ const type = localName(node.name);
384
+ if (type === "pPr") {
385
+ return;
386
+ }
387
+
388
+ if (type === "r") {
389
+ parseRunFormattingRevisions(node, paragraphIndex, state, getCursor());
390
+ for (const child of node.children) {
391
+ walkContentNode(child, paragraphIndex, state, getCursor, setCursor);
392
+ }
393
+ return;
394
+ }
395
+
396
+ if (SUPPORTED_CONTAINER_TYPES.has(type) || PRESERVE_ONLY_CONTAINER_TYPES.has(type)) {
397
+ const start = getCursor();
398
+ const length = measureStoryLength(node);
399
+ const end = start + length;
400
+ const hasNestedRevision = containsNestedRevision(node);
401
+ const metadata = readRevisionMetadata(
402
+ node,
403
+ state,
404
+ type === "moveFrom" || type === "moveTo" ? "move" : type,
405
+ );
406
+
407
+ if (hasNestedRevision) {
408
+ const nestedKind = type === "ins" ? "insertion" : type === "del" ? "deletion" : "move";
409
+ const isShallowNesting = isShallowPropertyChangeNesting(node);
410
+
411
+ if (isShallowNesting && SUPPORTED_CONTAINER_TYPES.has(type)) {
412
+ state.revisions.push(
413
+ createRevisionRecord({
414
+ revisionId: metadata.revisionId,
415
+ kind: nestedKind as "insertion" | "deletion",
416
+ anchor:
417
+ length > 0
418
+ ? createRevisionRangeAnchor(start, end)
419
+ : createDetachedAnchor({ from: start, to: end }, "importAmbiguity"),
420
+ authorId: metadata.authorId,
421
+ createdAt: metadata.createdAt,
422
+ metadata: {
423
+ source: "import",
424
+ importedRevisionForm:
425
+ type === "ins" ? "run-insertion" : "run-deletion",
426
+ originalRevisionType: type,
427
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
428
+ },
429
+ }),
430
+ );
431
+ state.preservedMarkup.push({
432
+ revisionId: metadata.revisionId,
433
+ rawXml: state.documentXml.slice(node.start, node.end),
434
+ xmlStart: node.start,
435
+ xmlEnd: node.end,
436
+ originalRevisionType: type,
437
+ });
438
+ state.diagnostics.push({
439
+ revisionId: metadata.revisionId,
440
+ code: "shallow_nested_revision_promoted",
441
+ message: "Shallow nested revision (property changes inside ins/del) promoted to supported rendering.",
442
+ featureClass: "supported",
443
+ });
444
+ parseNestedPropertyChangeRevisions(node, paragraphIndex, state, start);
445
+ advanceCursor(node, setCursor, getCursor);
446
+ return;
447
+ }
448
+
449
+ state.revisions.push(
450
+ createRevisionRecord({
451
+ revisionId: metadata.revisionId,
452
+ kind: nestedKind,
453
+ anchor:
454
+ length > 0
455
+ ? createRevisionRangeAnchor(start, end)
456
+ : createDetachedAnchor({ from: start, to: end }, "importAmbiguity"),
457
+ authorId: metadata.authorId,
458
+ createdAt: metadata.createdAt,
459
+ metadata: {
460
+ source: "import",
461
+ originalRevisionType: type,
462
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
463
+ preserveOnlyReason: "Nested revision markup remains preserve-only.",
464
+ },
465
+ }),
466
+ );
467
+ state.preservedMarkup.push({
468
+ revisionId: metadata.revisionId,
469
+ rawXml: state.documentXml.slice(node.start, node.end),
470
+ xmlStart: node.start,
471
+ xmlEnd: node.end,
472
+ originalRevisionType: type,
473
+ });
474
+ state.diagnostics.push({
475
+ revisionId: metadata.revisionId,
476
+ code: "nested_revision_preserve_only",
477
+ message: "Nested revision markup remains preserve-only and is exported unchanged.",
478
+ featureClass: "preserve-only",
479
+ });
480
+ advanceCursor(node, setCursor, getCursor);
481
+ return;
482
+ }
483
+
484
+ if (type === "moveFrom" || type === "moveTo") {
485
+ const moveData: MoveData = {
486
+ moveId: metadata.ooxmlRevisionId ?? `generated-${metadata.revisionId}`,
487
+ direction: type === "moveFrom" ? "from" : "to",
488
+ };
489
+ state.revisions.push(
490
+ createRevisionRecord({
491
+ revisionId: metadata.revisionId,
492
+ kind: "move",
493
+ anchor:
494
+ length > 0
495
+ ? createRevisionRangeAnchor(start, end)
496
+ : createDetachedAnchor({ from: start, to: end }, "importAmbiguity"),
497
+ authorId: metadata.authorId,
498
+ createdAt: metadata.createdAt,
499
+ metadata: {
500
+ source: "import",
501
+ originalRevisionType: type,
502
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
503
+ preserveOnlyReason: "Imported preserve-only revision.",
504
+ moveData,
505
+ },
506
+ }),
507
+ );
508
+ state.preservedMarkup.push({
509
+ revisionId: metadata.revisionId,
510
+ rawXml: state.documentXml.slice(node.start, node.end),
511
+ xmlStart: node.start,
512
+ xmlEnd: node.end,
513
+ originalRevisionType: type,
514
+ });
515
+ state.diagnostics.push({
516
+ revisionId: metadata.revisionId,
517
+ code: "preserve_only_move_revision",
518
+ message: "Move revision parsed as preserve-only. Content is preserved for round-trip; linking resolved in post-parse step.",
519
+ featureClass: "preserve-only",
520
+ });
521
+ advanceCursor(node, setCursor, getCursor);
522
+ return;
523
+ }
524
+
525
+ state.revisions.push(
526
+ createRevisionRecord({
527
+ revisionId: metadata.revisionId,
528
+ kind: type === "ins" ? "insertion" : "deletion",
529
+ anchor: createRevisionRangeAnchor(start, end),
530
+ authorId: metadata.authorId,
531
+ createdAt: metadata.createdAt,
532
+ metadata: {
533
+ source: "import",
534
+ importedRevisionForm:
535
+ type === "ins" ? "run-insertion" : "run-deletion",
536
+ originalRevisionType: type,
537
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
538
+ },
539
+ }),
540
+ );
541
+ state.preservedMarkup.push({
542
+ revisionId: metadata.revisionId,
543
+ rawXml: state.documentXml.slice(node.start, node.end),
544
+ xmlStart: node.start,
545
+ xmlEnd: node.end,
546
+ originalRevisionType: type,
547
+ });
548
+ advanceCursor(node, setCursor, getCursor);
549
+ return;
550
+ }
551
+
552
+ switch (type) {
553
+ case "t":
554
+ case "delText":
555
+ case "instrText":
556
+ case "delInstrText": {
557
+ const text = node.children
558
+ .filter((child): child is XmlElementNode["children"][number] & { type: "text" } => child.type === "text")
559
+ .map((child) => child.text)
560
+ .join("");
561
+ setCursor(getCursor() + Array.from(text).length);
562
+ return;
563
+ }
564
+ case "tab":
565
+ case "br":
566
+ case "cr":
567
+ setCursor(getCursor() + 1);
568
+ return;
569
+ default:
570
+ for (const child of node.children) {
571
+ walkContentNode(child, paragraphIndex, state, getCursor, setCursor);
572
+ }
573
+ }
574
+ }
575
+
576
+ function parseRunFormattingRevisions(
577
+ run: XmlElementNode,
578
+ _paragraphIndex: number,
579
+ state: ParseState,
580
+ runStart: number,
581
+ ): void {
582
+ const runProperties = findChildElement(run, "rPr");
583
+ if (!runProperties) {
584
+ return;
585
+ }
586
+
587
+ const runLength = measureStoryLength(run);
588
+ const anchor =
589
+ runLength > 0
590
+ ? createRevisionRangeAnchor(runStart, runStart + runLength)
591
+ : createDetachedAnchor({ from: runStart, to: runStart }, "importAmbiguity");
592
+
593
+ for (const child of runProperties.children) {
594
+ if (child.type !== "element" || !PROPERTY_CHANGE_REVISION_TYPES.has(localName(child.name))) {
595
+ continue;
596
+ }
597
+
598
+ const childLocalName = localName(child.name) as "rPrChange" | "pPrChange";
599
+ const metadata = readRevisionMetadata(child, state, "property-change");
600
+ const innerRPr = findChildElement(child, "rPr");
601
+ const beforeXml = innerRPr ? state.documentXml.slice(innerRPr.start, innerRPr.end) : "";
602
+ const propertyChangeData: PropertyChangeData = {
603
+ xmlTag: childLocalName === "rPrChange" ? "rPrChange" : "pPrChange",
604
+ beforeXml,
605
+ };
606
+ state.revisions.push(
607
+ createRevisionRecord({
608
+ revisionId: metadata.revisionId,
609
+ kind: "property-change",
610
+ anchor,
611
+ authorId: metadata.authorId,
612
+ createdAt: metadata.createdAt,
613
+ metadata: {
614
+ source: "import",
615
+ originalRevisionType: childLocalName,
616
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
617
+ propertyChangeData,
618
+ },
619
+ }),
620
+ );
621
+ state.preservedMarkup.push({
622
+ revisionId: metadata.revisionId,
623
+ rawXml: state.documentXml.slice(child.start, child.end),
624
+ xmlStart: child.start,
625
+ xmlEnd: child.end,
626
+ originalRevisionType: childLocalName,
627
+ containerXmlStart: runProperties.start,
628
+ containerXmlEnd: runProperties.end,
629
+ beforeContainerXml: beforeXml,
630
+ });
631
+ }
632
+ }
633
+
634
+ function parseTblPropertyRevisions(
635
+ table: XmlElementNode,
636
+ position: number,
637
+ state: ParseState,
638
+ ): void {
639
+ const tblPr = findChildElement(table, "tblPr");
640
+ if (tblPr) {
641
+ const tblPrChange = findChildElement(tblPr, "tblPrChange");
642
+ if (tblPrChange) {
643
+ const metadata = readRevisionMetadata(tblPrChange, state, "property-change");
644
+ const innerTblPr = findChildElement(tblPrChange, "tblPr");
645
+ const beforeXml = innerTblPr ? state.documentXml.slice(innerTblPr.start, innerTblPr.end) : "";
646
+ const propertyChangeData: PropertyChangeData = { xmlTag: "tblPrChange", beforeXml };
647
+
648
+ state.revisions.push(
649
+ createRevisionRecord({
650
+ revisionId: metadata.revisionId,
651
+ kind: "property-change",
652
+ anchor: createRevisionRangeAnchor(position, position),
653
+ authorId: metadata.authorId,
654
+ createdAt: metadata.createdAt,
655
+ metadata: {
656
+ source: "import",
657
+ originalRevisionType: "tblPrChange",
658
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
659
+ propertyChangeData,
660
+ },
661
+ }),
662
+ );
663
+ state.preservedMarkup.push({
664
+ revisionId: metadata.revisionId,
665
+ rawXml: state.documentXml.slice(tblPrChange.start, tblPrChange.end),
666
+ xmlStart: tblPrChange.start,
667
+ xmlEnd: tblPrChange.end,
668
+ originalRevisionType: "tblPrChange",
669
+ containerXmlStart: tblPr.start,
670
+ containerXmlEnd: tblPr.end,
671
+ beforeContainerXml: beforeXml,
672
+ });
673
+ state.diagnostics.push({
674
+ revisionId: metadata.revisionId,
675
+ code: "table_property_revision_parsed",
676
+ message: "Table property change (tblPrChange) parsed as actionable property-change revision.",
677
+ featureClass: "supported",
678
+ });
679
+ }
680
+ }
681
+
682
+ parseTableRowAndCellRevisions(table, position, state);
683
+ }
684
+
685
+ function parseTableRowAndCellRevisions(
686
+ table: XmlElementNode,
687
+ position: number,
688
+ state: ParseState,
689
+ ): void {
690
+ for (const child of table.children) {
691
+ if (child.type !== "element" || localName(child.name) !== "tr") {
692
+ continue;
693
+ }
694
+
695
+ const trPr = findChildElement(child, "trPr");
696
+ if (trPr) {
697
+ const trPrChange = findChildElement(trPr, "trPrChange");
698
+ if (trPrChange) {
699
+ const metadata = readRevisionMetadata(trPrChange, state, "property-change");
700
+ const innerTrPr = findChildElement(trPrChange, "trPr");
701
+ const beforeXml = innerTrPr ? state.documentXml.slice(innerTrPr.start, innerTrPr.end) : "";
702
+ const propertyChangeData: PropertyChangeData = { xmlTag: "tblPrChange", beforeXml };
703
+
704
+ state.revisions.push(
705
+ createRevisionRecord({
706
+ revisionId: metadata.revisionId,
707
+ kind: "property-change",
708
+ anchor: createRevisionRangeAnchor(position, position),
709
+ authorId: metadata.authorId,
710
+ createdAt: metadata.createdAt,
711
+ metadata: {
712
+ source: "import",
713
+ originalRevisionType: "trPrChange",
714
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
715
+ propertyChangeData,
716
+ preserveOnlyReason: "Row property changes remain preserve-only for export safety.",
717
+ },
718
+ }),
719
+ );
720
+ state.preservedMarkup.push({
721
+ revisionId: metadata.revisionId,
722
+ rawXml: state.documentXml.slice(trPrChange.start, trPrChange.end),
723
+ xmlStart: trPrChange.start,
724
+ xmlEnd: trPrChange.end,
725
+ originalRevisionType: "trPrChange",
726
+ containerXmlStart: trPr.start,
727
+ containerXmlEnd: trPr.end,
728
+ beforeContainerXml: beforeXml,
729
+ });
730
+ }
731
+ }
732
+
733
+ for (const tcNode of child.children) {
734
+ if (tcNode.type !== "element" || localName(tcNode.name) !== "tc") {
735
+ continue;
736
+ }
737
+
738
+ const tcPr = findChildElement(tcNode, "tcPr");
739
+ if (!tcPr) {
740
+ continue;
741
+ }
742
+
743
+ const tcPrChange = findChildElement(tcPr, "tcPrChange");
744
+ if (tcPrChange) {
745
+ const metadata = readRevisionMetadata(tcPrChange, state, "property-change");
746
+ const innerTcPr = findChildElement(tcPrChange, "tcPr");
747
+ const beforeXml = innerTcPr ? state.documentXml.slice(innerTcPr.start, innerTcPr.end) : "";
748
+ const propertyChangeData: PropertyChangeData = { xmlTag: "tblPrChange", beforeXml };
749
+
750
+ state.revisions.push(
751
+ createRevisionRecord({
752
+ revisionId: metadata.revisionId,
753
+ kind: "property-change",
754
+ anchor: createRevisionRangeAnchor(position, position),
755
+ authorId: metadata.authorId,
756
+ createdAt: metadata.createdAt,
757
+ metadata: {
758
+ source: "import",
759
+ originalRevisionType: "tcPrChange",
760
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
761
+ propertyChangeData,
762
+ preserveOnlyReason: "Cell property changes remain preserve-only for export safety.",
763
+ },
764
+ }),
765
+ );
766
+ state.preservedMarkup.push({
767
+ revisionId: metadata.revisionId,
768
+ rawXml: state.documentXml.slice(tcPrChange.start, tcPrChange.end),
769
+ xmlStart: tcPrChange.start,
770
+ xmlEnd: tcPrChange.end,
771
+ originalRevisionType: "tcPrChange",
772
+ containerXmlStart: tcPr.start,
773
+ containerXmlEnd: tcPr.end,
774
+ beforeContainerXml: beforeXml,
775
+ });
776
+ }
777
+
778
+ for (const tcChild of tcPr.children) {
779
+ if (tcChild.type !== "element") {
780
+ continue;
781
+ }
782
+
783
+ const tcChildName = localName(tcChild.name);
784
+ if (STRUCTURAL_TABLE_REVISION_TYPES.has(tcChildName)) {
785
+ const metadata = readRevisionMetadata(tcChild, state, tcChildName);
786
+ state.preservedMarkup.push({
787
+ revisionId: metadata.revisionId,
788
+ rawXml: state.documentXml.slice(tcChild.start, tcChild.end),
789
+ xmlStart: tcChild.start,
790
+ xmlEnd: tcChild.end,
791
+ originalRevisionType: tcChildName,
792
+ });
793
+ state.diagnostics.push({
794
+ revisionId: metadata.revisionId,
795
+ code: "table_structural_revision_preserve_only",
796
+ message: `Structural table revision (${tcChildName}) remains preserve-only; topology-altering changes cannot be safely applied.`,
797
+ featureClass: "preserve-only",
798
+ });
799
+ }
800
+ }
801
+ }
802
+ }
803
+ }
804
+
805
+ function parseSectPrRevisions(
806
+ sectPr: XmlElementNode,
807
+ position: number,
808
+ state: ParseState,
809
+ ): void {
810
+ const sectPrChange = findChildElement(sectPr, "sectPrChange");
811
+ if (!sectPrChange) {
812
+ return;
813
+ }
814
+
815
+ const metadata = readRevisionMetadata(sectPrChange, state, "property-change");
816
+ const innerSectPr = findChildElement(sectPrChange, "sectPr");
817
+ const beforeXml = innerSectPr ? state.documentXml.slice(innerSectPr.start, innerSectPr.end) : "";
818
+ const propertyChangeData: PropertyChangeData = { xmlTag: "sectPrChange", beforeXml };
819
+
820
+ state.revisions.push(
821
+ createRevisionRecord({
822
+ revisionId: metadata.revisionId,
823
+ kind: "property-change",
824
+ anchor: createRevisionRangeAnchor(position, position),
825
+ authorId: metadata.authorId,
826
+ createdAt: metadata.createdAt,
827
+ metadata: {
828
+ source: "import",
829
+ originalRevisionType: "sectPrChange",
830
+ ooxmlRevisionId: metadata.ooxmlRevisionId,
831
+ propertyChangeData,
832
+ },
833
+ }),
834
+ );
835
+ state.preservedMarkup.push({
836
+ revisionId: metadata.revisionId,
837
+ rawXml: state.documentXml.slice(sectPrChange.start, sectPrChange.end),
838
+ xmlStart: sectPrChange.start,
839
+ xmlEnd: sectPrChange.end,
840
+ originalRevisionType: "sectPrChange",
841
+ containerXmlStart: sectPr.start,
842
+ containerXmlEnd: sectPr.end,
843
+ beforeContainerXml: beforeXml,
844
+ });
845
+ }
846
+
847
+ function readRevisionMetadata(
848
+ node: XmlElementNode,
849
+ state: ParseState,
850
+ prefix: string,
851
+ ): RevisionMetadata {
852
+ const rawId = node.attributes["w:id"] ?? node.attributes.id;
853
+ const ooxmlRevisionId = rawId ? rawId : undefined;
854
+ const revisionId = rawId
855
+ ? `revision:${sanitizeRevisionToken(prefix)}-${sanitizeRevisionToken(rawId)}`
856
+ : `revision:${sanitizeRevisionToken(prefix)}-generated-${state.nextGeneratedIndex++}`;
857
+ const authorId =
858
+ node.attributes["w:author"] ??
859
+ node.attributes.author ??
860
+ "word:unknown-author";
861
+ const createdAt =
862
+ normalizeImportedTimestamp(
863
+ node.attributes["w:date"] ?? node.attributes.date,
864
+ ) ??
865
+ "1970-01-01T00:00:00.000Z";
866
+
867
+ return {
868
+ revisionId,
869
+ ooxmlRevisionId,
870
+ authorId,
871
+ createdAt,
872
+ };
873
+ }
874
+
875
+ function normalizeImportedTimestamp(value: string | undefined): string | undefined {
876
+ if (!value) {
877
+ return undefined;
878
+ }
879
+
880
+ const parsed = new Date(value);
881
+ if (Number.isNaN(parsed.valueOf())) {
882
+ return undefined;
883
+ }
884
+
885
+ return parsed.toISOString();
886
+ }
887
+
888
+ function sanitizeRevisionToken(value: string): string {
889
+ const sanitized = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
890
+ return sanitized.length > 0 ? sanitized : "unknown";
891
+ }
892
+
893
+ function linkMoveRevisionPairs(state: ParseState): void {
894
+ const moveRevisions = state.revisions.filter(
895
+ (r) => r.kind === "move" && r.metadata.moveData,
896
+ );
897
+
898
+ const byMoveId = new Map<string, typeof moveRevisions>();
899
+ for (const revision of moveRevisions) {
900
+ const moveId = revision.metadata.moveData!.moveId;
901
+ const group = byMoveId.get(moveId) ?? [];
902
+ group.push(revision);
903
+ byMoveId.set(moveId, group);
904
+ }
905
+
906
+ for (const [moveId, group] of byMoveId) {
907
+ const fromRevision = group.find(
908
+ (r) => r.metadata.moveData!.direction === "from",
909
+ );
910
+ const toRevision = group.find(
911
+ (r) => r.metadata.moveData!.direction === "to",
912
+ );
913
+
914
+ if (fromRevision && toRevision) {
915
+ fromRevision.metadata.moveData!.linkedRevisionId = toRevision.revisionId;
916
+ toRevision.metadata.moveData!.linkedRevisionId = fromRevision.revisionId;
917
+
918
+ state.diagnostics.push({
919
+ revisionId: fromRevision.revisionId,
920
+ code: "linked_move_pair",
921
+ message: `Move-from revision linked to move-to revision ${toRevision.revisionId} via moveId ${moveId}.`,
922
+ featureClass: "informational",
923
+ });
924
+ state.diagnostics.push({
925
+ revisionId: toRevision.revisionId,
926
+ code: "linked_move_pair",
927
+ message: `Move-to revision linked to move-from revision ${fromRevision.revisionId} via moveId ${moveId}.`,
928
+ featureClass: "informational",
929
+ });
930
+ } else {
931
+ for (const revision of group) {
932
+ state.diagnostics.push({
933
+ revisionId: revision.revisionId,
934
+ code: "unlinked_move_revision",
935
+ message: `Move revision has no matching counterpart for moveId ${moveId}. Remains preserve-only.`,
936
+ featureClass: "preserve-only",
937
+ });
938
+ }
939
+ }
940
+ }
941
+ }
942
+
943
+ function isShallowPropertyChangeNesting(node: XmlElementNode): boolean {
944
+ for (const child of node.children) {
945
+ if (child.type !== "element") {
946
+ continue;
947
+ }
948
+
949
+ const name = localName(child.name);
950
+
951
+ if (SUPPORTED_CONTAINER_TYPES.has(name) || PRESERVE_ONLY_CONTAINER_TYPES.has(name)) {
952
+ return false;
953
+ }
954
+
955
+ if (name === "r") {
956
+ const runProperties = findChildElement(child, "rPr");
957
+ if (runProperties) {
958
+ for (const rpChild of runProperties.children) {
959
+ if (rpChild.type !== "element") {
960
+ continue;
961
+ }
962
+
963
+ const rpChildName = localName(rpChild.name);
964
+ if (
965
+ SUPPORTED_CONTAINER_TYPES.has(rpChildName) ||
966
+ PRESERVE_ONLY_CONTAINER_TYPES.has(rpChildName)
967
+ ) {
968
+ return false;
969
+ }
970
+ }
971
+ }
972
+ continue;
973
+ }
974
+
975
+ if (!isShallowPropertyChangeNesting(child)) {
976
+ return false;
977
+ }
978
+ }
979
+
980
+ return true;
981
+ }
982
+
983
+ function parseNestedPropertyChangeRevisions(
984
+ container: XmlElementNode,
985
+ paragraphIndex: number,
986
+ state: ParseState,
987
+ containerStart: number,
988
+ ): void {
989
+ for (const child of container.children) {
990
+ if (child.type !== "element") {
991
+ continue;
992
+ }
993
+
994
+ if (localName(child.name) === "r") {
995
+ parseRunFormattingRevisions(child, paragraphIndex, state, containerStart);
996
+ }
997
+ }
998
+ }
999
+
1000
+ function containsNestedRevision(node: XmlElementNode): boolean {
1001
+ return node.children.some(
1002
+ (child) =>
1003
+ child.type === "element" &&
1004
+ (SUPPORTED_CONTAINER_TYPES.has(localName(child.name)) ||
1005
+ PRESERVE_ONLY_CONTAINER_TYPES.has(localName(child.name)) ||
1006
+ PROPERTY_CHANGE_REVISION_TYPES.has(localName(child.name)) ||
1007
+ containsNestedRevision(child)),
1008
+ );
1009
+ }
1010
+
1011
+ function advanceCursor(
1012
+ node: XmlElementNode,
1013
+ setCursor: (next: number) => void,
1014
+ getCursor: () => number,
1015
+ ): void {
1016
+ setCursor(getCursor() + measureStoryLength(node));
1017
+ }
1018
+
1019
+ function measureStoryLength(node: XmlNode): number {
1020
+ if (node.type !== "element") {
1021
+ return 0;
1022
+ }
1023
+
1024
+ switch (localName(node.name)) {
1025
+ case "t":
1026
+ case "delText":
1027
+ case "instrText":
1028
+ case "delInstrText":
1029
+ return node.children
1030
+ .filter((child): child is XmlElementNode["children"][number] & { type: "text" } => child.type === "text")
1031
+ .map((child) => Array.from(child.text).length)
1032
+ .reduce((total, length) => total + length, 0);
1033
+ case "tab":
1034
+ case "br":
1035
+ case "cr":
1036
+ return 1;
1037
+ case "pPr":
1038
+ case "rPr":
1039
+ case "rPrChange":
1040
+ case "pPrChange":
1041
+ return 0;
1042
+ default:
1043
+ return node.children.reduce((total, child) => total + measureStoryLength(child), 0);
1044
+ }
1045
+ }