@arbidocs/blocks 0.5.107 → 0.5.108

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 (341) hide show
  1. package/dist/{ConnectedCallDock-TDYRHPAK.js → ConnectedCallDock-DV4FU376.js} +8 -8
  2. package/dist/{ConnectedCallDock-TDYRHPAK.js.map → ConnectedCallDock-DV4FU376.js.map} +1 -1
  3. package/dist/{ConnectedCallDock-H3WWFGXF.cjs → ConnectedCallDock-EM2VVGZK.cjs} +10 -10
  4. package/dist/{ConnectedCallDock-H3WWFGXF.cjs.map → ConnectedCallDock-EM2VVGZK.cjs.map} +1 -1
  5. package/dist/{ConnectedCallRoom-55O5OUN7.cjs → ConnectedCallRoom-7WEPEWUJ.cjs} +9 -9
  6. package/dist/{ConnectedCallRoom-55O5OUN7.cjs.map → ConnectedCallRoom-7WEPEWUJ.cjs.map} +1 -1
  7. package/dist/{ConnectedCallRoom-Z6F6WCLH.js → ConnectedCallRoom-RYTZP34O.js} +8 -8
  8. package/dist/{ConnectedCallRoom-Z6F6WCLH.js.map → ConnectedCallRoom-RYTZP34O.js.map} +1 -1
  9. package/dist/{ConnectedNativeDocxComparison-NVZRVNOS.js → ConnectedNativeDocxComparison-2NDXXZLQ.js} +15 -15
  10. package/dist/{ConnectedNativeDocxComparison-NVZRVNOS.js.map → ConnectedNativeDocxComparison-2NDXXZLQ.js.map} +1 -1
  11. package/dist/{ConnectedNativeDocxComparison-DGBZJ4XA.cjs → ConnectedNativeDocxComparison-7HOY3AVI.cjs} +16 -16
  12. package/dist/{ConnectedNativeDocxComparison-DGBZJ4XA.cjs.map → ConnectedNativeDocxComparison-7HOY3AVI.cjs.map} +1 -1
  13. package/dist/{ConnectedNativeDocxEditor-R4WINUUB.cjs → ConnectedNativeDocxEditor-CUWDPHXN.cjs} +16 -16
  14. package/dist/{ConnectedNativeDocxEditor-R4WINUUB.cjs.map → ConnectedNativeDocxEditor-CUWDPHXN.cjs.map} +1 -1
  15. package/dist/{ConnectedNativeDocxEditor-RSVBN7DY.js → ConnectedNativeDocxEditor-SPZB6Y27.js} +14 -14
  16. package/dist/{ConnectedNativeDocxEditor-RSVBN7DY.js.map → ConnectedNativeDocxEditor-SPZB6Y27.js.map} +1 -1
  17. package/dist/{ConnectedProductionSetDialog-2DFBXE2X.js → ConnectedProductionSetDialog-N3EDG3SU.js} +4 -4
  18. package/dist/{ConnectedProductionSetDialog-2DFBXE2X.js.map → ConnectedProductionSetDialog-N3EDG3SU.js.map} +1 -1
  19. package/dist/{ConnectedProductionSetDialog-KYDPQ7SG.cjs → ConnectedProductionSetDialog-XAEFEN3N.cjs} +4 -4
  20. package/dist/{ConnectedProductionSetDialog-KYDPQ7SG.cjs.map → ConnectedProductionSetDialog-XAEFEN3N.cjs.map} +1 -1
  21. package/dist/{ConnectedStreamedWordArtifact-HLJ5IIOU.js → ConnectedStreamedWordArtifact-6LTGEAJO.js} +15 -15
  22. package/dist/ConnectedStreamedWordArtifact-6LTGEAJO.js.map +1 -0
  23. package/dist/{ConnectedStreamedWordArtifact-JQ34AOUU.cjs → ConnectedStreamedWordArtifact-HNCRKZTV.cjs} +16 -16
  24. package/dist/ConnectedStreamedWordArtifact-HNCRKZTV.cjs.map +1 -0
  25. package/dist/{DocumentReviewCard-7JSXRJZ2.js → DocumentReviewCard-RJD3CO32.js} +8 -8
  26. package/dist/{DocumentReviewCard-7JSXRJZ2.js.map → DocumentReviewCard-RJD3CO32.js.map} +1 -1
  27. package/dist/{DocumentReviewCard-C4HVT3WM.cjs → DocumentReviewCard-VON7LOOY.cjs} +8 -8
  28. package/dist/{DocumentReviewCard-C4HVT3WM.cjs.map → DocumentReviewCard-VON7LOOY.cjs.map} +1 -1
  29. package/dist/{FilesViewerDialog-IMQTZWKD.js → FilesViewerDialog-7SJGY72Q.js} +21 -21
  30. package/dist/{FilesViewerDialog-IMQTZWKD.js.map → FilesViewerDialog-7SJGY72Q.js.map} +1 -1
  31. package/dist/{FilesViewerDialog-UP7GFHYN.cjs → FilesViewerDialog-VIPTC6OT.cjs} +27 -27
  32. package/dist/{FilesViewerDialog-UP7GFHYN.cjs.map → FilesViewerDialog-VIPTC6OT.cjs.map} +1 -1
  33. package/dist/{RechartsRenderer-GIRCW7DB.cjs → RechartsRenderer-THES2SE5.cjs} +6 -5
  34. package/dist/RechartsRenderer-THES2SE5.cjs.map +1 -0
  35. package/dist/{RechartsRenderer-23OF4H6X.js → RechartsRenderer-XIZLV6GH.js} +6 -5
  36. package/dist/RechartsRenderer-XIZLV6GH.js.map +1 -0
  37. package/dist/{WorkspaceTableView-PJM47B5F.cjs → WorkspaceTableView-FNME7TL6.cjs} +9 -9
  38. package/dist/{WorkspaceTableView-PJM47B5F.cjs.map → WorkspaceTableView-FNME7TL6.cjs.map} +1 -1
  39. package/dist/{WorkspaceTableView-YDA7A4UJ.js → WorkspaceTableView-XQ6J2JKI.js} +7 -7
  40. package/dist/{WorkspaceTableView-YDA7A4UJ.js.map → WorkspaceTableView-XQ6J2JKI.js.map} +1 -1
  41. package/dist/agents/index.cjs +202 -202
  42. package/dist/agents/index.js +8 -8
  43. package/dist/{ai-ADS6YSS2.cjs → ai-3SAMEYBB.cjs} +20 -20
  44. package/dist/ai-3SAMEYBB.cjs.map +1 -0
  45. package/dist/{ai-KHWTGBT5.js → ai-OTQWSYVK.js} +12 -12
  46. package/dist/ai-OTQWSYVK.js.map +1 -0
  47. package/dist/calls/index.cjs +57 -57
  48. package/dist/calls/index.js +9 -9
  49. package/dist/chat/index.cjs +3 -3
  50. package/dist/chat/index.js +3 -3
  51. package/dist/{chunk-O27K7KTZ.cjs → chunk-2TBQBF4Y.cjs} +5 -5
  52. package/dist/{chunk-O27K7KTZ.cjs.map → chunk-2TBQBF4Y.cjs.map} +1 -1
  53. package/dist/{chunk-YJWAGXYM.js → chunk-4ZA2RSQH.js} +3 -3
  54. package/dist/{chunk-YJWAGXYM.js.map → chunk-4ZA2RSQH.js.map} +1 -1
  55. package/dist/{chunk-6A4GNM4T.cjs → chunk-5D2ZINOJ.cjs} +16 -16
  56. package/dist/{chunk-6A4GNM4T.cjs.map → chunk-5D2ZINOJ.cjs.map} +1 -1
  57. package/dist/{chunk-BFVCYBND.cjs → chunk-5HXQOM3I.cjs} +5 -5
  58. package/dist/{chunk-BFVCYBND.cjs.map → chunk-5HXQOM3I.cjs.map} +1 -1
  59. package/dist/{chunk-GSD5U553.cjs → chunk-5KKT65WU.cjs} +3 -3
  60. package/dist/{chunk-GSD5U553.cjs.map → chunk-5KKT65WU.cjs.map} +1 -1
  61. package/dist/{chunk-AVGHTUPE.js → chunk-5PWLXLHY.js} +5 -5
  62. package/dist/chunk-5PWLXLHY.js.map +1 -0
  63. package/dist/{chunk-BBWLFK3C.js → chunk-5XIMUQ63.js} +3 -3
  64. package/dist/{chunk-BBWLFK3C.js.map → chunk-5XIMUQ63.js.map} +1 -1
  65. package/dist/{chunk-AHMRYY7J.cjs → chunk-6DAJXQZZ.cjs} +13 -13
  66. package/dist/{chunk-AHMRYY7J.cjs.map → chunk-6DAJXQZZ.cjs.map} +1 -1
  67. package/dist/{chunk-3PV25ICC.js → chunk-6KKVJ2V6.js} +3 -3
  68. package/dist/{chunk-3PV25ICC.js.map → chunk-6KKVJ2V6.js.map} +1 -1
  69. package/dist/{chunk-OLAYDOPC.js → chunk-6LUHNFEE.js} +6 -6
  70. package/dist/{chunk-OLAYDOPC.js.map → chunk-6LUHNFEE.js.map} +1 -1
  71. package/dist/{chunk-FSXQHEFQ.cjs → chunk-7CDV7Y4U.cjs} +25 -25
  72. package/dist/{chunk-FSXQHEFQ.cjs.map → chunk-7CDV7Y4U.cjs.map} +1 -1
  73. package/dist/{chunk-OAIOOVFN.cjs → chunk-7SJXYEZI.cjs} +36 -36
  74. package/dist/chunk-7SJXYEZI.cjs.map +1 -0
  75. package/dist/{chunk-LFYKB7KF.cjs → chunk-7V6APLF7.cjs} +19 -19
  76. package/dist/{chunk-LFYKB7KF.cjs.map → chunk-7V6APLF7.cjs.map} +1 -1
  77. package/dist/{chunk-4WMGFGYP.cjs → chunk-AJZ66VJC.cjs} +4 -4
  78. package/dist/{chunk-4WMGFGYP.cjs.map → chunk-AJZ66VJC.cjs.map} +1 -1
  79. package/dist/{chunk-KCP42W67.cjs → chunk-ARGQ5YZ5.cjs} +3 -3
  80. package/dist/{chunk-KCP42W67.cjs.map → chunk-ARGQ5YZ5.cjs.map} +1 -1
  81. package/dist/{chunk-BH6IKGZ3.js → chunk-AUAHGQY6.js} +5 -5
  82. package/dist/{chunk-BH6IKGZ3.js.map → chunk-AUAHGQY6.js.map} +1 -1
  83. package/dist/{chunk-KIXFXCHL.js → chunk-CEOCA7ID.js} +3 -3
  84. package/dist/{chunk-KIXFXCHL.js.map → chunk-CEOCA7ID.js.map} +1 -1
  85. package/dist/{chunk-TNKPQ3EF.js → chunk-CIRSOYGK.js} +12 -12
  86. package/dist/{chunk-TNKPQ3EF.js.map → chunk-CIRSOYGK.js.map} +1 -1
  87. package/dist/{chunk-BAUZUIHB.js → chunk-COL2TJGO.js} +83 -83
  88. package/dist/chunk-COL2TJGO.js.map +1 -0
  89. package/dist/{chunk-XHN5KOI2.cjs → chunk-DRLD4P2C.cjs} +8 -8
  90. package/dist/{chunk-XHN5KOI2.cjs.map → chunk-DRLD4P2C.cjs.map} +1 -1
  91. package/dist/{chunk-5AC52BHL.cjs → chunk-DYPFNQTQ.cjs} +140 -140
  92. package/dist/chunk-DYPFNQTQ.cjs.map +1 -0
  93. package/dist/{chunk-SCLGUHLU.cjs → chunk-E7TGSOPR.cjs} +4 -4
  94. package/dist/{chunk-SCLGUHLU.cjs.map → chunk-E7TGSOPR.cjs.map} +1 -1
  95. package/dist/{chunk-CRLFLMTK.cjs → chunk-EOXA4VJH.cjs} +3 -3
  96. package/dist/{chunk-CRLFLMTK.cjs.map → chunk-EOXA4VJH.cjs.map} +1 -1
  97. package/dist/{chunk-DBKZANTC.js → chunk-GA47YVW5.js} +3 -3
  98. package/dist/{chunk-DBKZANTC.js.map → chunk-GA47YVW5.js.map} +1 -1
  99. package/dist/{chunk-RCZRI72J.cjs → chunk-GMODJT4N.cjs} +4 -4
  100. package/dist/{chunk-RCZRI72J.cjs.map → chunk-GMODJT4N.cjs.map} +1 -1
  101. package/dist/{chunk-22KAKJ3W.cjs → chunk-GS5MFUPC.cjs} +4 -4
  102. package/dist/{chunk-22KAKJ3W.cjs.map → chunk-GS5MFUPC.cjs.map} +1 -1
  103. package/dist/{chunk-62OMGQHS.js → chunk-H6W3VXHU.js} +3 -3
  104. package/dist/{chunk-62OMGQHS.js.map → chunk-H6W3VXHU.js.map} +1 -1
  105. package/dist/{chunk-DX3Z2COD.cjs → chunk-HUYKO2ES.cjs} +3 -3
  106. package/dist/{chunk-DX3Z2COD.cjs.map → chunk-HUYKO2ES.cjs.map} +1 -1
  107. package/dist/{chunk-U5F5P4YU.js → chunk-IK234EFX.js} +12 -12
  108. package/dist/{chunk-U5F5P4YU.js.map → chunk-IK234EFX.js.map} +1 -1
  109. package/dist/{chunk-UQ2OBHMV.js → chunk-JUGEFTRC.js} +1010 -1010
  110. package/dist/chunk-JUGEFTRC.js.map +1 -0
  111. package/dist/{chunk-CHQMVIHR.js → chunk-LPGBRMYS.js} +36 -36
  112. package/dist/chunk-LPGBRMYS.js.map +1 -0
  113. package/dist/{chunk-D35EHOK5.cjs → chunk-M23W7IID.cjs} +12 -12
  114. package/dist/chunk-M23W7IID.cjs.map +1 -0
  115. package/dist/{chunk-FPOKWML2.js → chunk-MIVNNQO3.js} +21 -4
  116. package/dist/chunk-MIVNNQO3.js.map +1 -0
  117. package/dist/{chunk-WI3BVKEC.cjs → chunk-MNFI66H5.cjs} +5 -5
  118. package/dist/{chunk-WI3BVKEC.cjs.map → chunk-MNFI66H5.cjs.map} +1 -1
  119. package/dist/{chunk-T5ZMG6MC.js → chunk-NF4M7PUB.js} +3 -3
  120. package/dist/{chunk-T5ZMG6MC.js.map → chunk-NF4M7PUB.js.map} +1 -1
  121. package/dist/{chunk-ZNY5W3VX.js → chunk-NPSFPBIB.js} +3 -3
  122. package/dist/{chunk-ZNY5W3VX.js.map → chunk-NPSFPBIB.js.map} +1 -1
  123. package/dist/{chunk-LYW5A35J.js → chunk-OMIYTUVR.js} +12 -12
  124. package/dist/{chunk-LYW5A35J.js.map → chunk-OMIYTUVR.js.map} +1 -1
  125. package/dist/{chunk-ZMVF7EYJ.cjs → chunk-PBPO54KZ.cjs} +21 -3
  126. package/dist/chunk-PBPO54KZ.cjs.map +1 -0
  127. package/dist/{chunk-7V4OCZS6.cjs → chunk-RA3EGF6K.cjs} +6 -6
  128. package/dist/{chunk-7V4OCZS6.cjs.map → chunk-RA3EGF6K.cjs.map} +1 -1
  129. package/dist/{chunk-PL7O3RJJ.cjs → chunk-RKBAY7GZ.cjs} +3 -3
  130. package/dist/{chunk-PL7O3RJJ.cjs.map → chunk-RKBAY7GZ.cjs.map} +1 -1
  131. package/dist/{chunk-J3E5CSSC.js → chunk-RKFWBIKS.js} +3 -3
  132. package/dist/{chunk-J3E5CSSC.js.map → chunk-RKFWBIKS.js.map} +1 -1
  133. package/dist/{chunk-YLKHTBYA.js → chunk-RRP7MQAO.js} +3 -3
  134. package/dist/{chunk-YLKHTBYA.js.map → chunk-RRP7MQAO.js.map} +1 -1
  135. package/dist/{chunk-U6LQ6Z3P.cjs → chunk-SP3IKIPA.cjs} +6 -6
  136. package/dist/{chunk-U6LQ6Z3P.cjs.map → chunk-SP3IKIPA.cjs.map} +1 -1
  137. package/dist/{chunk-GX75YCWJ.cjs → chunk-SQUOXOY3.cjs} +560 -560
  138. package/dist/chunk-SQUOXOY3.cjs.map +1 -0
  139. package/dist/{chunk-6ZYOUT73.js → chunk-T5LORFHL.js} +7 -7
  140. package/dist/{chunk-6ZYOUT73.js.map → chunk-T5LORFHL.js.map} +1 -1
  141. package/dist/{chunk-45OU2UAA.cjs → chunk-TEMTKBBL.cjs} +10 -10
  142. package/dist/{chunk-45OU2UAA.cjs.map → chunk-TEMTKBBL.cjs.map} +1 -1
  143. package/dist/{chunk-PHDUN4SG.cjs → chunk-THCMGAFX.cjs} +41 -41
  144. package/dist/{chunk-PHDUN4SG.cjs.map → chunk-THCMGAFX.cjs.map} +1 -1
  145. package/dist/{chunk-HTGEAQOA.js → chunk-TOMDMKOD.js} +7 -7
  146. package/dist/{chunk-HTGEAQOA.js.map → chunk-TOMDMKOD.js.map} +1 -1
  147. package/dist/{chunk-WJHRWXWJ.js → chunk-TXIAF4PX.js} +3 -3
  148. package/dist/{chunk-WJHRWXWJ.js.map → chunk-TXIAF4PX.js.map} +1 -1
  149. package/dist/{chunk-6M5NAAWX.js → chunk-UCSEE52D.js} +3 -3
  150. package/dist/{chunk-6M5NAAWX.js.map → chunk-UCSEE52D.js.map} +1 -1
  151. package/dist/{chunk-I7CJDF3V.cjs → chunk-UHMP6S7M.cjs} +104 -103
  152. package/dist/chunk-UHMP6S7M.cjs.map +1 -0
  153. package/dist/{chunk-PGCKTXYH.js → chunk-UHUI6A36.js} +3 -3
  154. package/dist/{chunk-PGCKTXYH.js.map → chunk-UHUI6A36.js.map} +1 -1
  155. package/dist/{chunk-6KQVTMRL.cjs → chunk-UOGXKHTJ.cjs} +3 -3
  156. package/dist/{chunk-6KQVTMRL.cjs.map → chunk-UOGXKHTJ.cjs.map} +1 -1
  157. package/dist/{chunk-7S7YVBFK.js → chunk-VDSDG4FR.js} +3 -3
  158. package/dist/{chunk-7S7YVBFK.js.map → chunk-VDSDG4FR.js.map} +1 -1
  159. package/dist/{chunk-3GFQNJYE.js → chunk-VGWCHX6G.js} +104 -103
  160. package/dist/chunk-VGWCHX6G.js.map +1 -0
  161. package/dist/{chunk-VY3HTT37.js → chunk-VUH547VQ.js} +3 -3
  162. package/dist/{chunk-VY3HTT37.js.map → chunk-VUH547VQ.js.map} +1 -1
  163. package/dist/{chunk-AZCMKGDG.js → chunk-W37PFYFL.js} +4 -4
  164. package/dist/{chunk-AZCMKGDG.js.map → chunk-W37PFYFL.js.map} +1 -1
  165. package/dist/{chunk-JGUM4EXE.cjs → chunk-W3IX3GZS.cjs} +8 -8
  166. package/dist/{chunk-JGUM4EXE.cjs.map → chunk-W3IX3GZS.cjs.map} +1 -1
  167. package/dist/{chunk-UCA4JLLJ.cjs → chunk-X7GT57KW.cjs} +3 -3
  168. package/dist/{chunk-UCA4JLLJ.cjs.map → chunk-X7GT57KW.cjs.map} +1 -1
  169. package/dist/{chunk-IXL2KJOZ.cjs → chunk-XBEGD33U.cjs} +40 -40
  170. package/dist/{chunk-IXL2KJOZ.cjs.map → chunk-XBEGD33U.cjs.map} +1 -1
  171. package/dist/{chunk-FDNIK5YS.cjs → chunk-XBKIFGBB.cjs} +8 -8
  172. package/dist/{chunk-FDNIK5YS.cjs.map → chunk-XBKIFGBB.cjs.map} +1 -1
  173. package/dist/{chunk-HZE5MHQO.js → chunk-XT7HKQ4H.js} +3 -3
  174. package/dist/{chunk-HZE5MHQO.js.map → chunk-XT7HKQ4H.js.map} +1 -1
  175. package/dist/{chunk-M3OK6KGR.js → chunk-ZGQKED5T.js} +3 -3
  176. package/dist/{chunk-M3OK6KGR.js.map → chunk-ZGQKED5T.js.map} +1 -1
  177. package/dist/{chunk-NWBCZ4PA.js → chunk-ZKBYG6MN.js} +4 -4
  178. package/dist/{chunk-NWBCZ4PA.js.map → chunk-ZKBYG6MN.js.map} +1 -1
  179. package/dist/collaboration/index.cjs +1 -1
  180. package/dist/collaboration/index.js +1 -1
  181. package/dist/connect/docx.cjs +19 -19
  182. package/dist/connect/docx.js +15 -15
  183. package/dist/connect/index.cjs +762 -762
  184. package/dist/connect/index.js +63 -63
  185. package/dist/connect/viewer.cjs +14 -14
  186. package/dist/connect/viewer.js +13 -13
  187. package/dist/connection/dashboards/ConnectedDashboardsPage.d.ts +6 -0
  188. package/dist/dashboards/chartModel.d.ts +12 -0
  189. package/dist/dashboards/index.cjs +113 -42
  190. package/dist/dashboards/index.cjs.map +1 -1
  191. package/dist/dashboards/index.js +95 -24
  192. package/dist/dashboards/index.js.map +1 -1
  193. package/dist/embed/index.cjs +29 -29
  194. package/dist/embed/index.js +23 -23
  195. package/dist/facts/index.cjs +43 -43
  196. package/dist/facts/index.js +2 -2
  197. package/dist/files/index.cjs +1 -1
  198. package/dist/files/index.js +1 -1
  199. package/dist/home/index.cjs +31 -31
  200. package/dist/home/index.js +3 -3
  201. package/dist/index.cjs +383 -383
  202. package/dist/index.js +21 -21
  203. package/dist/settings/index.cjs +153 -153
  204. package/dist/settings/index.js +4 -4
  205. package/dist/shell/index.cjs +36 -36
  206. package/dist/shell/index.js +4 -4
  207. package/dist/site/index.cjs +5 -5
  208. package/dist/site/index.js +1 -1
  209. package/dist/studio/index.cjs +19 -19
  210. package/dist/studio/index.js +14 -14
  211. package/dist/styles.css +1 -1
  212. package/dist/workflow-canvas/index.cjs +33 -33
  213. package/dist/workflow-canvas/index.js +22 -22
  214. package/node_modules/@arbidocs/coedit/package.json +2 -2
  215. package/node_modules/@docx-editor.dev/core/dist/automation.cjs +1 -1
  216. package/node_modules/@docx-editor.dev/core/dist/automation.d.ts +60 -13
  217. package/node_modules/@docx-editor.dev/core/dist/automation.js +1 -1
  218. package/node_modules/@docx-editor.dev/core/dist/binding.cjs +1 -1
  219. package/node_modules/@docx-editor.dev/core/dist/binding.d.ts +21 -13
  220. package/node_modules/@docx-editor.dev/core/dist/binding.js +1 -1
  221. package/node_modules/@docx-editor.dev/core/dist/{index-Bsg7oIKP.d.ts → chrome-print-CAs51cpq.d.ts} +31 -21
  222. package/node_modules/@docx-editor.dev/core/dist/{chunk-VDNNLG6X.js → chunk-236O4YQW.js} +1 -1
  223. package/node_modules/@docx-editor.dev/core/dist/chunk-4HENIAFG.js +1 -0
  224. package/node_modules/@docx-editor.dev/core/dist/{chunk-SRPILEWV.cjs → chunk-6JPL6ZAS.cjs} +5 -5
  225. package/node_modules/@docx-editor.dev/core/dist/{chunk-2RC2EPND.js → chunk-6ZQP4HQ7.js} +1 -1
  226. package/node_modules/@docx-editor.dev/core/dist/{chunk-ZUHOMK52.cjs → chunk-7WQ7AAHW.cjs} +1 -1
  227. package/node_modules/@docx-editor.dev/core/dist/{chunk-Z6WBFXJU.js → chunk-BCXH4BXB.js} +3 -3
  228. package/node_modules/@docx-editor.dev/core/dist/{chunk-QMLCVPCD.cjs → chunk-BY2ACZZ6.cjs} +1 -1
  229. package/node_modules/@docx-editor.dev/core/dist/chunk-CAJEXXVG.cjs +4 -0
  230. package/node_modules/@docx-editor.dev/core/dist/chunk-CPWLFPWC.js +30 -0
  231. package/node_modules/@docx-editor.dev/core/dist/{chunk-6APGXLBB.cjs → chunk-D7ZMDMPX.cjs} +2 -2
  232. package/node_modules/@docx-editor.dev/core/dist/chunk-DOHF6FA7.cjs +30 -0
  233. package/node_modules/@docx-editor.dev/core/dist/chunk-DVX32P2P.js +27 -0
  234. package/node_modules/@docx-editor.dev/core/dist/{chunk-6EYYL7FL.js → chunk-E4LOMDNL.js} +1 -1
  235. package/node_modules/@docx-editor.dev/core/dist/chunk-EKLM7NWB.cjs +7 -0
  236. package/node_modules/@docx-editor.dev/core/dist/chunk-G3K63G7P.cjs +27 -0
  237. package/node_modules/@docx-editor.dev/core/dist/{chunk-5CSUYANV.js → chunk-G4HOFIKJ.js} +1 -1
  238. package/node_modules/@docx-editor.dev/core/dist/{chunk-K5U2PLDP.cjs → chunk-JLVBDYVQ.cjs} +1 -1
  239. package/node_modules/@docx-editor.dev/core/dist/chunk-LQX36Z5P.js +7 -0
  240. package/node_modules/@docx-editor.dev/core/dist/{chunk-TSLBZ26X.js → chunk-LSZ6KPKK.js} +1 -1
  241. package/node_modules/@docx-editor.dev/core/dist/{chunk-O2AL2HSJ.cjs → chunk-MM5QBMTE.cjs} +1 -1
  242. package/node_modules/@docx-editor.dev/core/dist/{chunk-ETTO6GK3.js → chunk-OMCG63ZF.js} +1 -1
  243. package/node_modules/@docx-editor.dev/core/dist/chunk-OSFOJTHU.cjs +18 -0
  244. package/node_modules/@docx-editor.dev/core/dist/{chunk-E7BQA6UP.js → chunk-RCLZXP3B.js} +1 -1
  245. package/node_modules/@docx-editor.dev/core/dist/chunk-T6K2QYNZ.cjs +2 -0
  246. package/node_modules/@docx-editor.dev/core/dist/chunk-TRGAVV2Y.js +4 -0
  247. package/node_modules/@docx-editor.dev/core/dist/chunk-U4JZVSOE.js +2 -0
  248. package/node_modules/@docx-editor.dev/core/dist/{chunk-2GO5T2JU.cjs → chunk-UHHYFIDT.cjs} +1 -1
  249. package/node_modules/@docx-editor.dev/core/dist/chunk-V3N4SOAK.cjs +1 -0
  250. package/node_modules/@docx-editor.dev/core/dist/{chunk-6AWEKBLB.cjs → chunk-W35WTWAO.cjs} +1 -1
  251. package/node_modules/@docx-editor.dev/core/dist/chunk-YQ5G6LC7.js +18 -0
  252. package/node_modules/@docx-editor.dev/core/dist/collaboration/replication.cjs +1 -1
  253. package/node_modules/@docx-editor.dev/core/dist/collaboration/replication.d.ts +5 -5
  254. package/node_modules/@docx-editor.dev/core/dist/collaboration/replication.js +1 -1
  255. package/node_modules/@docx-editor.dev/core/dist/collaboration.d.ts +4 -4
  256. package/node_modules/@docx-editor.dev/core/dist/contracts/document.d.ts +3 -3
  257. package/node_modules/@docx-editor.dev/core/dist/contracts/editor.d.ts +9 -10
  258. package/node_modules/@docx-editor.dev/core/dist/contracts/interaction.d.ts +2 -2
  259. package/node_modules/@docx-editor.dev/core/dist/contracts/modules.cjs +1 -1
  260. package/node_modules/@docx-editor.dev/core/dist/contracts/modules.d.ts +33 -9
  261. package/node_modules/@docx-editor.dev/core/dist/contracts/modules.js +1 -1
  262. package/node_modules/@docx-editor.dev/core/dist/contracts/types.d.ts +2 -2
  263. package/node_modules/@docx-editor.dev/core/dist/{custom-node-writes-cvL5rhcD.d.ts → custom-node-writes-Bn6uciLb.d.ts} +2 -2
  264. package/node_modules/@docx-editor.dev/core/dist/diagnostic-context-B8M79cfK.d.ts +30 -0
  265. package/node_modules/@docx-editor.dev/core/dist/diagnostic-hints-BeVjfNOv.d.ts +113 -0
  266. package/node_modules/@docx-editor.dev/core/dist/{document-protection-BAGVGqaP.d.ts → document-protection-CUb55pl_.d.ts} +2 -2
  267. package/node_modules/@docx-editor.dev/core/dist/{editor-Ci7IZGmG.d.ts → editor-CZQZmTIU.d.ts} +386 -9
  268. package/node_modules/@docx-editor.dev/core/dist/{editor-scope-OHPwVQ5l.d.ts → editor-scope-7o9xweiJ.d.ts} +1 -1
  269. package/node_modules/@docx-editor.dev/core/dist/editor.cjs +1 -1
  270. package/node_modules/@docx-editor.dev/core/dist/editor.d.ts +54 -33
  271. package/node_modules/@docx-editor.dev/core/dist/editor.js +1 -1
  272. package/node_modules/@docx-editor.dev/core/dist/export.cjs +2 -2
  273. package/node_modules/@docx-editor.dev/core/dist/export.d.ts +13 -14
  274. package/node_modules/@docx-editor.dev/core/dist/export.js +1 -1
  275. package/node_modules/@docx-editor.dev/core/dist/{font-resolver-BVQB14qT.d.ts → font-resolver-lSBLirLR.d.ts} +3 -3
  276. package/node_modules/@docx-editor.dev/core/dist/{headless-document-view-qH331moE.d.ts → headless-document-view-pp3q7wIh.d.ts} +2 -2
  277. package/node_modules/@docx-editor.dev/core/dist/{image-resources-BN-hUgCn.d.ts → image-resources-tXLQShoC.d.ts} +2 -2
  278. package/node_modules/@docx-editor.dev/core/dist/index.cjs +1 -1
  279. package/node_modules/@docx-editor.dev/core/dist/index.d.ts +65 -20
  280. package/node_modules/@docx-editor.dev/core/dist/index.js +1 -1
  281. package/node_modules/@docx-editor.dev/core/dist/{layout-shaping-BEyuiQOk.d.ts → layout-shaping-BD-dF_rn.d.ts} +1 -1
  282. package/node_modules/@docx-editor.dev/core/dist/layout.cjs +1 -1
  283. package/node_modules/@docx-editor.dev/core/dist/layout.d.ts +17 -20
  284. package/node_modules/@docx-editor.dev/core/dist/layout.js +1 -1
  285. package/node_modules/@docx-editor.dev/core/dist/{note-properties-4Y9o6Gyk.d.ts → note-properties-qQUjO1GQ.d.ts} +3 -3
  286. package/node_modules/@docx-editor.dev/core/dist/{omml-equation-CuzBL5DD.d.ts → omml-equation-BUbU0utM.d.ts} +1 -1
  287. package/node_modules/@docx-editor.dev/core/dist/output.cjs +1 -1
  288. package/node_modules/@docx-editor.dev/core/dist/output.d.ts +8 -9
  289. package/node_modules/@docx-editor.dev/core/dist/output.js +1 -1
  290. package/node_modules/@docx-editor.dev/core/dist/{protocol-Bqk4Izjc.d.ts → protocol-DYzzz2ej.d.ts} +2 -2
  291. package/node_modules/@docx-editor.dev/core/dist/{review-paragraph-order-DT-n6ouC.d.ts → review-paragraph-order-CN_0l2Cb.d.ts} +1 -1
  292. package/node_modules/@docx-editor.dev/core/dist/{semantic-cell-selection-D9D1KSXq.d.ts → semantic-cell-selection-eYag3P47.d.ts} +4 -211
  293. package/node_modules/@docx-editor.dev/core/dist/{semantic-interaction-CIC-PooQ.d.ts → semantic-interaction-kR_QB845.d.ts} +1 -1
  294. package/node_modules/@docx-editor.dev/core/dist/{semantic-paint-BME37OMv.d.ts → semantic-paint-ZayFF3tD.d.ts} +17 -5
  295. package/node_modules/@docx-editor.dev/core/dist/{semantic-record-queries-CBlZqZNa.d.ts → semantic-record-queries-Bsgth6lv.d.ts} +1 -1
  296. package/node_modules/@docx-editor.dev/core/dist/{semantic-records-4B3WwFAi.d.ts → semantic-records-DQmumPgL.d.ts} +1279 -828
  297. package/node_modules/@docx-editor.dev/core/dist/store.cjs +1 -1
  298. package/node_modules/@docx-editor.dev/core/dist/store.d.ts +1466 -1464
  299. package/node_modules/@docx-editor.dev/core/dist/store.js +1 -1
  300. package/node_modules/@docx-editor.dev/core/dist/{tree-package-fragment-BeeKxDw8.d.ts → tree-package-store-CovjNARF.d.ts} +83 -83
  301. package/node_modules/@docx-editor.dev/core/dist/{tree-session-contract-CVbmlMlq.d.ts → tree-session-contract-CZVAGl51.d.ts} +6 -6
  302. package/node_modules/@docx-editor.dev/core/dist/{types-barrel-D3xCgQX6.d.ts → types-barrel-DuC5QBNC.d.ts} +548 -527
  303. package/node_modules/@docx-editor.dev/core/package.json +3 -3
  304. package/node_modules/@docx-editor.dev/react/dist/index.js +3 -3
  305. package/node_modules/@docx-editor.dev/react/dist/index.mjs +3 -3
  306. package/node_modules/@docx-editor.dev/react/package.json +4 -4
  307. package/package.json +8 -8
  308. package/dist/ConnectedStreamedWordArtifact-HLJ5IIOU.js.map +0 -1
  309. package/dist/ConnectedStreamedWordArtifact-JQ34AOUU.cjs.map +0 -1
  310. package/dist/RechartsRenderer-23OF4H6X.js.map +0 -1
  311. package/dist/RechartsRenderer-GIRCW7DB.cjs.map +0 -1
  312. package/dist/ai-ADS6YSS2.cjs.map +0 -1
  313. package/dist/ai-KHWTGBT5.js.map +0 -1
  314. package/dist/chunk-3GFQNJYE.js.map +0 -1
  315. package/dist/chunk-5AC52BHL.cjs.map +0 -1
  316. package/dist/chunk-AVGHTUPE.js.map +0 -1
  317. package/dist/chunk-BAUZUIHB.js.map +0 -1
  318. package/dist/chunk-CHQMVIHR.js.map +0 -1
  319. package/dist/chunk-D35EHOK5.cjs.map +0 -1
  320. package/dist/chunk-FPOKWML2.js.map +0 -1
  321. package/dist/chunk-GX75YCWJ.cjs.map +0 -1
  322. package/dist/chunk-I7CJDF3V.cjs.map +0 -1
  323. package/dist/chunk-OAIOOVFN.cjs.map +0 -1
  324. package/dist/chunk-UQ2OBHMV.js.map +0 -1
  325. package/dist/chunk-ZMVF7EYJ.cjs.map +0 -1
  326. package/node_modules/@docx-editor.dev/core/dist/chunk-4GBTELJV.cjs +0 -28
  327. package/node_modules/@docx-editor.dev/core/dist/chunk-4R3TEXMN.js +0 -18
  328. package/node_modules/@docx-editor.dev/core/dist/chunk-EO4C5QJW.cjs +0 -2
  329. package/node_modules/@docx-editor.dev/core/dist/chunk-FIJZIQXA.cjs +0 -18
  330. package/node_modules/@docx-editor.dev/core/dist/chunk-FRXAOVTB.js +0 -28
  331. package/node_modules/@docx-editor.dev/core/dist/chunk-J6BVWIDB.js +0 -2
  332. package/node_modules/@docx-editor.dev/core/dist/chunk-JGNVNT2A.cjs +0 -2
  333. package/node_modules/@docx-editor.dev/core/dist/chunk-KKIJG3C6.js +0 -2
  334. package/node_modules/@docx-editor.dev/core/dist/chunk-LWDSDCMO.js +0 -27
  335. package/node_modules/@docx-editor.dev/core/dist/chunk-NBCVVZOM.cjs +0 -1
  336. package/node_modules/@docx-editor.dev/core/dist/chunk-O5INAWZQ.js +0 -1
  337. package/node_modules/@docx-editor.dev/core/dist/chunk-RCHS4ZEH.cjs +0 -27
  338. package/node_modules/@docx-editor.dev/core/dist/chunk-VHAVHCQY.js +0 -7
  339. package/node_modules/@docx-editor.dev/core/dist/chunk-VX43VBAX.cjs +0 -7
  340. package/node_modules/@docx-editor.dev/core/dist/review-pane-D9jm8DcY.d.ts +0 -128
  341. package/node_modules/@docx-editor.dev/core/dist/revision-projection-DZ4kKVev.d.ts +0 -242
@@ -1,991 +1,1474 @@
1
- import { o as RevisionAttribution, b as RevisionDisplayMode } from './revision-projection-DZ4kKVev.js';
2
- import { X as OoxmlProperty, Z as OoxmlElement, N as OoxmlNode, O as OoxmlPart, aJ as TableBorderStyle, aK as DrawingAccessibility, aL as DrawingImageEffects, al as SourceCrop, aM as DrawingTransform, aN as VectorShapeProjection, aw as DrawingHorizontalReferenceFrame, ax as DrawingVerticalReferenceFrame, an as ImageWrapTarget, a0 as DrawingProjection, aO as OoxmlDrawingNode } from './types-barrel-D3xCgQX6.js';
3
- import { b as ImageResourceState } from './image-resources-BN-hUgCn.js';
4
- import { O as OmmlEquationProjection } from './omml-equation-CuzBL5DD.js';
1
+ import { N as OoxmlNode, ah as OoxmlProperty, O as OoxmlPart, ak as OoxmlElement, aM as TableBorderStyle, aN as DrawingAccessibility, aO as DrawingImageEffects, aI as SourceCrop, aP as DrawingTransform, aQ as VectorShapeProjection, X as DrawingHorizontalReferenceFrame, $ as DrawingVerticalReferenceFrame, a1 as ImageWrapTarget, an as DrawingProjection, aR as OoxmlDrawingNode } from './types-barrel-DuC5QBNC.js';
2
+ import { I as ImageResourceState } from './image-resources-tXLQShoC.js';
3
+ import { O as OmmlEquationProjection } from './omml-equation-BUbU0utM.js';
5
4
 
6
- /** A strikeout stroke at the drawn size, in points. `offsetPt` is the stroke TOP. @public */
7
- interface StrikeoutStrokePt {
8
- /** Distance from the baseline UP to the top of the stroke. */
9
- readonly offsetPt: number;
10
- /** Stroke height. Always positive. */
11
- readonly thicknessPt: number;
5
+ /** Named revision colors. Identifiers are stable and never contain CSS. @public */
6
+ declare const REVISION_MARKUP_COLORS: readonly ['black', 'blue', 'turquoise', 'green', 'pink', 'red', 'yellow', 'white', 'darkBlue', 'teal', 'darkGreen', 'violet', 'darkRed', 'darkYellow', 'gray50', 'gray25', 'lightBlue', 'lightYellow', 'lightOrange', 'lightPurple', 'lightGreen', 'gray'];
7
+ /** @public */
8
+ type RevisionMarkupNamedColor = (typeof REVISION_MARKUP_COLORS)[number];
9
+ /** @public */
10
+ type RevisionMarkupColor = RevisionMarkupNamedColor | 'byAuthor' | 'auto';
11
+ /** @public */
12
+ type RevisionMarkupMark = 'none' | 'colorOnly' | 'bold' | 'italic' | 'underline' | 'doubleUnderline' | 'strikethrough' | 'doubleStrikethrough';
13
+ /** @public */
14
+ type RevisionDeletionMark = RevisionMarkupMark | 'hidden' | 'caret' | 'pound';
15
+ /** @public */
16
+ type RevisionChangedLinesMark = 'none' | 'leftBorder' | 'rightBorder' | 'outsideBorder';
17
+ /** @public */
18
+ interface RevisionMarkupStyle<Mark extends string = RevisionMarkupMark> {
19
+ readonly mark: Mark;
20
+ readonly color: RevisionMarkupColor;
21
+ }
22
+ /** Viewer-only text styling. Document highlighting remains unchanged. @public */
23
+ interface RevisionMarkupTextStyle<Mark extends string = RevisionMarkupMark> extends RevisionMarkupStyle<Mark> {
24
+ /** Background color behind revision text. Defaults to `none`. */
25
+ readonly background: RevisionMarkupNamedColor | 'byAuthor' | 'none';
26
+ }
27
+ /** Fully resolved, immutable viewer preferences. @public */
28
+ interface ResolvedRevisionMarkup {
29
+ readonly insertions: RevisionMarkupTextStyle;
30
+ readonly deletions: RevisionMarkupTextStyle<RevisionDeletionMark>;
31
+ readonly movedFrom: RevisionMarkupTextStyle<RevisionDeletionMark>;
32
+ readonly movedTo: RevisionMarkupTextStyle;
33
+ readonly formatting: RevisionMarkupTextStyle;
34
+ readonly changedLines: RevisionMarkupStyle<RevisionChangedLinesMark>;
35
+ readonly cells: {
36
+ readonly inserted: RevisionMarkupNamedColor | 'byAuthor' | 'none';
37
+ readonly deleted: RevisionMarkupNamedColor | 'byAuthor' | 'none';
38
+ readonly merged: RevisionMarkupNamedColor | 'byAuthor' | 'none';
39
+ readonly split: RevisionMarkupNamedColor | 'byAuthor' | 'none';
40
+ };
41
+ readonly trackMoves: boolean;
42
+ readonly trackFormatting: boolean;
43
+ }
44
+ /** Partial viewer preferences. Omitted values keep the previous value. @public */
45
+ type RevisionMarkupOptions = {
46
+ readonly [K in keyof ResolvedRevisionMarkup]?: ResolvedRevisionMarkup[K] extends boolean ? boolean : Partial<ResolvedRevisionMarkup[K]>;
47
+ };
48
+ /** Initial viewer preferences. @public */
49
+ declare const DEFAULT_REVISION_MARKUP: ResolvedRevisionMarkup;
50
+ /** Validate and merge preferences without modifying the input. @public */
51
+ declare function resolveRevisionMarkup(input?: RevisionMarkupOptions, previous?: ResolvedRevisionMarkup): ResolvedRevisionMarkup;
52
+ /** A local settings draft owned by the editor. @public */
53
+ interface RevisionMarkupDialogSession {
54
+ /** Aborts on close, replacement, load, detach, destroy, or renderer disposal. */
55
+ readonly signal: AbortSignal;
56
+ /** Read the immutable draft. */
57
+ get(): ResolvedRevisionMarkup;
58
+ /** Merge validated options into the draft without committing preferences. */
59
+ set(options: RevisionMarkupOptions): void;
60
+ /** Restore default preferences in the draft only. */
61
+ reset(): void;
62
+ /** Observe draft changes, including effective external preference changes. */
63
+ subscribe(listener: () => void): () => void;
64
+ canApply(): boolean;
65
+ /** Commit the draft and close. Returns false after cancellation. */
66
+ apply(): boolean;
67
+ /** Close without committing the draft. */
68
+ cancel(): void;
69
+ }
70
+ /** Host rendering for the Track changes options dialog. @public */
71
+ interface RevisionMarkupChromeHandlers {
72
+ readonly onRequest?: (session: RevisionMarkupDialogSession) => void;
12
73
  }
13
74
 
14
75
  /**
15
- * `w:tblpPr/@w:horzAnchor` (17.4.58) and `@w:vertAnchor` (17.4.66): the box a floated
16
- * table's offsets are measured from. Absent means `text` for both.
76
+ * What a revision wrapper asserts about the content inside it.
77
+ *
78
+ * `moveFrom` / `moveTo` are deliberately distinct from `delete` / `insert`: a move is one
79
+ * decision with two halves, and presenting it as an unrelated deletion and insertion invites
80
+ * resolving one without the other, which duplicates or loses the content.
17
81
  */
18
- type TableFloatAnchor = 'text' | 'margin' | 'page';
19
- /** `w:tblpPr/@w:tblpXSpec` (17.4.63, ST_XAlign). */
20
- type TableFloatXSpec = 'left' | 'center' | 'right' | 'inside' | 'outside';
21
- /** `w:tblpPr/@w:tblpYSpec` (17.4.65, ST_YAlign). */
22
- type TableFloatYSpec = 'inline' | 'top' | 'center' | 'bottom' | 'inside' | 'outside';
82
+ type RevisionKind = 'insert' | 'delete' | 'moveFrom' | 'moveTo' | 'format';
23
83
  /**
24
- * `w:tblPr/w:tblpPr` (17.4.57) — a table positioned against an anchor box rather than at
25
- * the point in the text where it was authored.
84
+ * One revision wrapper's provenance, as authored.
26
85
  *
27
- * A spec (`tblpXSpec`/`tblpYSpec`) supersedes the matching offset when both are present:
28
- * 17.4.57 states the alignment outright, and the offset only answers "how far from the
29
- * anchor" for the case where no alignment was stated.
86
+ * `id` is the verbatim `@w:id` string rather than a number: `ST_DecimalNumber` restricts
87
+ * `xsd:integer` with no bounds, so a file may carry a value outside the safe integer range, and
88
+ * parsing it to a number would silently merge two distinct revisions.
89
+ *
90
+ * `date` is absent when the file omits it. `@w:date` is optional on `CT_TrackChange`, and
91
+ * inventing one is a silent content change.
30
92
  */
31
- interface TableFloatPosition {
32
- readonly horzAnchor: TableFloatAnchor;
33
- readonly vertAnchor: TableFloatAnchor;
34
- readonly xSpec?: TableFloatXSpec;
35
- /** `w:tblpX` in points; signed, so a table can be pulled into the margin. */
36
- readonly xPt: number;
37
- readonly ySpec?: TableFloatYSpec;
38
- /** `w:tblpY` in points; signed. */
39
- readonly yPt: number;
40
- readonly distances?: {
41
- readonly top: number;
42
- readonly right: number;
43
- readonly bottom: number;
44
- readonly left: number;
45
- };
93
+ interface RevisionAttribution {
94
+ readonly kind: RevisionKind;
95
+ readonly id: string;
96
+ readonly author: string;
97
+ readonly date?: string;
98
+ /** The wrapper's node id, so a surface can address this exact site. */
99
+ readonly nodeId: string;
46
100
  }
47
-
48
101
  /**
49
- * One `w:numPicBullet`: the image a level draws instead of its `w:lvlText`.
102
+ * Which revisions layout resolves before producing pages.
50
103
  *
51
- * `relationshipId` is unresolved on purpose — it names a relationship of the numbering part,
52
- * and resolving it is the image-resource lookup's job, under its own validation and caps.
53
- * @public
104
+ * - `all-markup` shows both halves of every change.
105
+ * - `proposed` shows what the document becomes if every change is accepted.
106
+ * - `original` shows what it was before any of them.
107
+ *
108
+ * The last two are specified as equal to accept-all and reject-all OUTPUT, which is what makes
109
+ * them testable, without either applying an op.
54
110
  */
55
- interface NumberingPictureBullet {
56
- /** `w:numPicBulletId` — what a level's `w:lvlPicBulletId` names. */
57
- readonly picBulletId: string;
58
- /** `v:imagedata/@r:id`, relative to the NUMBERING part's relationships. */
59
- readonly relationshipId: string;
60
- /** Authored `v:shape` width in points. */
61
- readonly width: number;
62
- /** Authored `v:shape` height in points. */
63
- readonly height: number;
64
- }
111
+ type RevisionDisplayMode = 'all-markup' | 'proposed' | 'original';
65
112
  /**
66
- * A level's picture bullet with the size it is actually DRAWN at.
113
+ * The views the review chrome offers, in Word's terms: the three layout projections plus
114
+ * Simple Markup, which reads as the proposed result with a red change bar beside every line
115
+ * a change touched — the document as accepting everything would leave it, and where.
116
+ */
117
+ type ReviewDisplayMode = RevisionDisplayMode | 'simple-markup';
118
+ /**
119
+ * How a document renders tracked changes when nothing says otherwise.
67
120
  *
68
- * Separate from {@link NumberingPictureBullet} because the authored `v:shape` extent is not
69
- * the painted extent: Word scales it by the marker run's font size. Layout, hit testing and
70
- * both paint sinks read `width` / `height`; `authored` is kept so the scale stays inspectable.
71
- * @public
121
+ * `all-markup` matches Word's own default: a reader who opens a document with pending changes
122
+ * sees them, rather than a clean-looking document hiding edits nobody has accepted.
72
123
  */
73
- interface ResolvedPictureBullet {
74
- /** `v:imagedata/@r:id`, relative to the NUMBERING part's relationships. */
75
- readonly relationshipId: string;
76
- /** Painted width in points, after the marker font scale. */
77
- readonly width: number;
78
- /** Painted height in points, after the marker font scale. */
79
- readonly height: number;
80
- /** The `v:shape` extent exactly as the file authored it. */
81
- readonly authored: NumberingPictureBullet;
82
- }
83
-
84
- /** Soft ceiling on abstractNum / num entries read from one part. */
85
- declare const MAX_NUMBERING_DEFINITIONS = 512;
86
- /** Soft ceiling on override entries per `w:num`. */
87
- declare const MAX_LVL_OVERRIDES = 9;
88
- /** `w:suff` — what separates a list marker from the text after it. */
89
- type ListSuffix = 'tab' | 'space' | 'nothing';
90
- /** `w:lvlJc` — how a list marker aligns within its own indent. */
91
- type ListMarkerAlign = 'left' | 'center' | 'right';
124
+ declare const DEFAULT_REVISION_DISPLAY_MODE: RevisionDisplayMode;
92
125
  /**
93
- * One level's indent, plus which parts the level actually AUTHORED.
126
+ * A view-time tracked-change filter. Revisions rejected by `includes` use the filter's accepted
127
+ * or rejected projection, while included revisions keep the display mode's normal projection.
94
128
  *
95
- * The provenance matters: `w:ind` cascades per-attribute, so a level that authored only `left`
96
- * must not overwrite an inherited `hanging` with a synthesized zero.
129
+ * `cacheKey` is a canonical, content-based identity for layout caches. The set itself is kept
130
+ * because author names are attacker-controlled strings and must never be parsed back from a
131
+ * delimiter-based key.
97
132
  */
98
- interface NumberingLevelIndent {
99
- /**
100
- * The sides as the level spells them, in points. `left` and `start` both name the leading
101
- * indent, and `right` and `end` the trailing one; `left`/`right` below hold those two.
102
- */
103
- readonly authored?: {
104
- readonly left?: number;
105
- readonly right?: number;
106
- readonly start?: number;
107
- readonly end?: number;
108
- };
109
- readonly left: number;
110
- readonly right: number;
111
- readonly hanging: number;
112
- readonly firstLine: number;
133
+ interface RevisionFilter {
134
+ readonly revisionMarkup?: ResolvedRevisionMarkup;
135
+ readonly hiddenAuthors: ReadonlySet<string>;
136
+ readonly includes?: (revision: RevisionAttribution) => boolean;
137
+ readonly includesNode?: (nodeId: string, author: string) => boolean;
138
+ /** Accepted/original projection for a revision excluded by `includesNode`. */
139
+ readonly excludedNodeMode?: (nodeId: string, author: string) => 'proposed' | 'original';
113
140
  /**
114
- * Which of these the LEVEL actually authored.
115
- *
116
- * A level's `w:pPr/w:ind` sits between the formatting it outranks and the formatting that
117
- * outranks it (`mergeListIndent`), so the merge has to tell "the level says left = 0" from
118
- * "the level says nothing about left and the style's value stands". Absent (the default) reads as "says nothing", which is what a
119
- * hand-built level in a test means.
141
+ * In a resolved view, content the view keeps paints as ORDINARY text: no author ink, no
142
+ * decoration, no change bar of its own. This is Word's No Markup, Original and Simple
143
+ * Markup, which the review chrome asks for. Without it the accepted projection keeps the
144
+ * attribution on kept insertions, which is what the engine paints when no review module
145
+ * is registered — colour by author, deletions resolved — and what its roster reads.
120
146
  */
121
- readonly stated?: {
122
- readonly left: boolean;
123
- readonly right: boolean;
124
- /** `w:hanging`/`w:firstLine` are one mutually exclusive slot (§17.3.1.10, §17.3.1.12). */
125
- readonly firstLineOffset: boolean;
126
- };
147
+ readonly resolvedMarkup?: 'plain';
148
+ readonly cacheKey: string;
127
149
  }
128
- /** One `w:lvl`: how this depth numbers, what its marker looks like, and how it indents. */
129
- interface NumberingLevel {
130
- readonly ilvl: number;
131
- readonly start: number;
132
- readonly numFmt: string;
133
- readonly lvlText: string;
134
- readonly lvlJc: ListMarkerAlign;
135
- readonly suff: ListSuffix;
136
- readonly indent: NumberingLevelIndent;
137
- /**
138
- * `w:lvlRestart` one-based trigger level, or `0` when the level never restarts.
139
- * Omitted in XML → restart when the previous level (or any earlier level) is used.
140
- */
141
- readonly lvlRestart?: number;
142
- /**
143
- * `w:isLgl` (§17.9.9): render EVERY level referenced by this level's `w:lvlText` in
144
- * decimal, whatever number format those levels declare for themselves.
145
- */
146
- readonly isLgl: boolean;
147
- /**
148
- * `w:lvlPicBulletId` (§17.9.12): this level's marker is the `w:numPicBullet` of that id,
149
- * drawn INSTEAD of `w:lvlText`. Absent on every ordinary level.
150
- */
151
- readonly picBulletId?: string;
152
- /** Level `w:rPr` as flat properties (for marker face / vanish). */
153
- readonly runProperties: readonly OoxmlProperty[];
154
- /** True when level run props request vanish — marker must not paint. */
155
- readonly vanish: boolean;
150
+ /** @deprecated Use {@link RevisionFilter}. */
151
+ interface RevisionAuthorFilter extends RevisionFilter {
156
152
  }
153
+ /** Build a canonical reviewer filter. An empty input returns `undefined` for the fast path. */
154
+ declare function revisionAuthorFilter(hiddenAuthors: Iterable<string>): RevisionAuthorFilter | undefined;
157
155
  /**
158
- * One `w:lvlOverride` on a `w:num`: a restart value, a replacement level, or both.
156
+ * Whether content under this stack of revisions is laid out in the given mode.
159
157
  *
160
- * How two lists share an abstract definition while numbering independently.
158
+ * Containment governs, so a single enclosing wrapper the mode resolves away suppresses
159
+ * everything inside it regardless of what the inner wrappers say. An insertion inside a
160
+ * deletion does not survive the proposed result: the deletion it sits in was accepted.
161
161
  */
162
- interface LevelOverride {
163
- readonly startOverride?: number;
164
- /** Full level replacement when `w:lvl` is present under the override. */
165
- readonly level?: NumberingLevel;
166
- }
162
+ declare function revisionsVisible(revisions: readonly RevisionAttribution[], mode: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): boolean;
167
163
  /**
168
- * One `w:abstractNum` — the shape of a list, without being a list.
164
+ * Every revision on a paragraph's own MARK, from `w:pPr/w:rPr/w:ins|w:del|w:moveFrom|w:moveTo`.
169
165
  *
170
- * Never referenced by a paragraph directly. Paragraphs name a {@link NumDefinition}, which names
171
- * one of these, so several lists can share a definition and still count separately.
166
+ * All four members of `EG_ParaRPrTrackChanges`. A moved paragraph carries `w:moveFrom` on the
167
+ * mark of the copy it left and `w:moveTo` on the mark of the copy it arrived at, so a move
168
+ * that spans whole paragraphs is recorded here and nowhere else.
169
+ *
170
+ * `EG_ParaRPrTrackChanges` records that the pilcrow itself was inserted or deleted, which is how
171
+ * Word writes a paragraph split or merge. It is not content — there is no text to decorate — so
172
+ * a surface shows it as a mark of its own beside the paragraph, the way Word draws a struck-
173
+ * through ¶.
174
+ *
175
+ * A LIST, because the group is `ins? del? moveFrom? moveTo?` and the first two can both be
176
+ * there: that pair is what Word writes when a second author proposes removing a mark the first
177
+ * proposed adding, and it is what this engine's own writer emits (`tree-op-tracked.ts`).
178
+ * Answering with the first one hid the second author's decision from the PAGE. The review pane
179
+ * walks the tree itself and always listed both, which is the worse shape of the two: a card
180
+ * offering a decision the reader could see no sign of.
181
+ *
182
+ * Ordered as the file orders them, which is the order the group declares.
183
+ *
184
+ * Property-position `w:ins`/`w:del` stay `generic` in the tree deliberately, so this reads them
185
+ * by name rather than by kind.
172
186
  */
173
- interface AbstractNumDefinition {
174
- readonly abstractNumId: string;
175
- readonly levels: ReadonlyMap<number, NumberingLevel>;
176
- /**
177
- * `w:numStyleLink` (§17.9.21): this definition carries no levels of its own — the numbering
178
- * lives on the named style. Word follows the link; resolve it with
179
- * {@link resolveNumberingStyleLinks} before reading levels, or every paragraph on this
180
- * abstract renders with NO marker at all.
181
- */
182
- readonly numStyleLink?: string;
183
- /**
184
- * `w:styleLink` (§17.9.23): the definition side of the same pair — this abstract IS the
185
- * numbering of the named style. Kept so a link can be verified rather than assumed.
186
- */
187
- readonly styleLink?: string;
188
- }
187
+ declare function paragraphMarkRevisionsOf(paragraph: OoxmlNode): readonly RevisionAttribution[];
189
188
  /**
190
- * One `w:num` — the thing a paragraph's `w:numId` actually names.
189
+ * The tracked FORMAT change on a paragraph's own mark, from `w:pPr/w:rPr/w:rPrChange`.
191
190
  *
192
- * Points at an {@link AbstractNumDefinition} and may override any of its levels.
191
+ * `CT_ParaRPr` ends with it (§17.13.5.32), and Word writes it when a user changes the mark's
192
+ * own run properties with tracking on. It reaches the fragment rather than a span because it
193
+ * decorates no characters, and it is not in `props`: a fragment's `props` carry the mark's
194
+ * `w:rPr` by NAME only, with none of its children.
195
+ *
196
+ * Note that `w:rPrChange/w:rPr` is `CT_ParaRPrOriginal`, which may carry its own revision
197
+ * marks. Those describe the mark as it WAS and must not be read as live ones, which is why
198
+ * this reads the change element's own attributes and never descends into it.
193
199
  */
194
- interface NumDefinition {
195
- readonly numId: string;
196
- readonly abstractNumId: string;
197
- readonly overrides: ReadonlyMap<number, LevelOverride>;
198
- }
200
+ declare function paragraphMarkFormatRevisionOf(paragraph: OoxmlNode): RevisionAttribution | null;
199
201
  /**
200
- * The bounded projection of `numbering.xml` that list layout resolves against.
202
+ * The single decision a one-field reader sees.
201
203
  *
202
- * Projection ONLY — never a mutation or serialization authority. Hostile values are dropped or
203
- * clamped, and a missing definition resolves to "no list" rather than a guess.
204
+ * A DELETION wins when a mark carries both, for the reason paint draws it that way: a break
205
+ * proposed and then unproposed ends up removed, so that is the decision a reader who can only
206
+ * see one must see. One function decides it, so the deprecated field, the deprecated function
207
+ * and the painted glyph cannot answer differently.
204
208
  */
205
- interface NumberingIndex {
206
- readonly abstractNums: ReadonlyMap<string, AbstractNumDefinition>;
207
- readonly nums: ReadonlyMap<string, NumDefinition>;
208
- /**
209
- * `w:numPicBullet` declarations keyed by `w:numPicBulletId` (§17.9.20).
210
- *
211
- * Optional so a hand-built index stays valid; absent reads as "this part declares none",
212
- * which is what a level's `w:lvlPicBulletId` then falls back from.
213
- */
214
- readonly pictureBullets?: ReadonlyMap<string, NumberingPictureBullet>;
215
- }
209
+ declare function shownMarkRevision(revisions: readonly RevisionAttribution[]): RevisionAttribution | undefined;
216
210
  /**
217
- * Build a numbering index from the root of a numbering part (`w:numbering`).
211
+ * Does this decision, taken, remove the paragraph mark?
218
212
  *
219
- * Empty / missing roots yield an empty index. Duplicate ids keep the first definition.
213
+ * A deletion does, and so does a `moveFrom`: the copy the paragraph moved OUT of goes away
214
+ * when the move is accepted. `insert` and `moveTo` are the other half of each pair, and they
215
+ * keep the break. Paint, the change bar and the resolved views all ask this one question, so
216
+ * a `moveFrom` cannot end up struck through in the margin and blue on the glyph.
220
217
  */
218
+ declare function markRevisionRemovesMark(revision: RevisionAttribution): boolean;
221
219
  /**
222
- * Project `numbering.xml` into the bounded index.
220
+ * The one decision on a paragraph's mark that a single-field reader sees.
223
221
  *
224
- * Every ceiling here exists because the input is file-derived: definition counts, override
225
- * counts, indent magnitudes and style-link hop depth are all capped, and nothing from the file
226
- * becomes a loop bound or an allocation size.
222
+ * @deprecated Reads one of the revisions a mark can carry. Use {@link paragraphMarkRevisionsOf},
223
+ * which answers with all of them.
227
224
  */
228
- declare function buildNumberingIndex(root: OoxmlElement | null | undefined): NumberingIndex;
229
- /** Resolve the effective level for a `numId` + `ilvl`, applying overrides. */
225
+ declare function paragraphMarkRevisionOf(paragraph: OoxmlNode): RevisionAttribution | null;
230
226
  /**
231
- * The effective level for one paragraph's numbering reference, after overrides and style links.
227
+ * The tracked FORMAT change on a property list, from `w:rPrChange` or `w:pPrChange`.
232
228
  *
233
- * Answers null for a reference the index cannot resolve — a paragraph naming a definition the
234
- * file never declared is an unnumbered paragraph, not an error.
229
+ * A property change alters no characters, so it has no span of its own to strike or underline.
230
+ * Word marks the affected text and says what changed; the minimum a reader needs is to see that
231
+ * this text's formatting is itself a pending decision.
232
+ *
233
+ * Read from the flattened property list because that is what layout already carries — the
234
+ * change wrapper is a `w:rPr`/`w:pPr` child like any other.
235
235
  */
236
- declare function resolveNumberingLevel(index: NumberingIndex, numId: string, ilvl: number): {
237
- readonly abstractNumId: string;
238
- readonly level: NumberingLevel;
239
- readonly startOverride?: number;
240
- } | null;
241
- /** Empty index for tests / documents without numbering. */
242
- declare const EMPTY_NUMBERING_INDEX: NumberingIndex;
236
+ declare function formatRevisionOf(properties: readonly {
237
+ readonly localName: string;
238
+ readonly attributes?: Readonly<Record<string, string>>;
239
+ }[]): RevisionAttribution | null;
240
+ /** True when this stack of revisions marks its content as deleted from the live document. */
241
+ declare function revisionsAreDeletion(revisions: readonly RevisionAttribution[]): boolean;
242
+
243
+ /** A strikeout stroke at the drawn size, in points. `offsetPt` is the stroke TOP. @public */
244
+ interface StrikeoutStrokePt {
245
+ /** Distance from the baseline UP to the top of the stroke. */
246
+ readonly offsetPt: number;
247
+ /** Stroke height. Always positive. */
248
+ readonly thicknessPt: number;
249
+ }
243
250
 
244
251
  /**
245
- * A face, as something asks for it: family plus the two axes this engine admits.
252
+ * Whether a paragraph must start a new page (`w:pageBreakBefore`).
246
253
  *
247
- * Only static weights and slants. Variable-font axes are deliberately outside this vocabulary —
248
- * the shaper refuses variation axes, and a variable file admitted here would render bold at
249
- * regular weight.
254
+ * LAST WINS, like every other toggle read off the cascade (`paragraphKeeps` does the same
255
+ * for `w:keepNext`). An any-wins `.some()` cannot be switched off: a Chapter or Heading style
256
+ * carries `w:pageBreakBefore`, and Word writes `w:val="0"` on the one instance whose author
257
+ * unchecked the box — that paragraph still broke, so the document grew a blank page and every
258
+ * page number after it was wrong.
259
+ *
260
+ * An absent `w:val` is on (§17.17.4), and the off vocabulary is the whole of it — `off` is a
261
+ * spelling too, which {@link isOn} beside this already accepts.
250
262
  */
251
- interface FontRequest {
252
- readonly family: string;
253
- readonly weight: number;
254
- readonly style: 'normal' | 'italic';
255
- }
263
+ declare function paragraphBreaksBefore(props: readonly OoxmlProperty[]): boolean;
256
264
  /**
257
- * A request that was answered by a DIFFERENT face than the one asked for.
265
+ * Soft ceiling matching the spike's resolved-style limit (31_680 twips ≈ 22"). Beyond
266
+ * that an attacker-authored spacing would push pagination into pathological page counts.
267
+ */
268
+ declare const MAX_PARAGRAPH_SPACING_PT: number;
269
+ /** Soft ceiling on border width (96 eighths = 12pt). Word's UI tops out well below this. */
270
+ declare const MAX_BORDER_WIDTH_PT = 12;
271
+ /** Soft ceiling on border-to-text gap (`w:space`, already in points). */
272
+ declare const MAX_BORDER_SPACE_PT = 3168;
273
+ /**
274
+ * A paragraph's resolved space before and after, in points.
258
275
  *
259
- * Recorded rather than silently applied, because a substitution changes measurement: it is part
260
- * of the shaping fingerprint, so a cached run shaped against a substitute is never reused for the
261
- * real face.
276
+ * Already collapsed against `w:contextualSpacing`, so adjacent same-style paragraphs that suppress
277
+ * their gap arrive here with it removed rather than leaving that to whoever stacks them.
262
278
  */
263
- interface FontSubstitution {
264
- readonly requested: FontRequest;
265
- readonly resolved: FontRequest;
266
- readonly lineMetrics?: {
267
- readonly heightEm: number;
268
- readonly baselineEm: number;
269
- };
279
+ interface ParagraphSpacing {
280
+ /** `w:spacing/@before`, in points. */
281
+ readonly before: number;
282
+ /** `w:spacing/@after`, in points. */
283
+ readonly after: number;
270
284
  }
271
- declare const RESOLVED_FONT_BRAND: unique symbol;
272
285
  /**
273
- * A face that passed admission: the bytes are present, within limits, hash-verified, and parse as
274
- * a font.
286
+ * The gap Word substitutes when `w:beforeAutospacing` / `w:afterAutospacing` is on
287
+ * (ECMA-376 §17.3.1.33, the `w:spacing` clause both attributes belong to).
275
288
  *
276
- * Branded, so a `ResolvedFont` cannot be constructed by an object literal. Holding one is proof
277
- * the checks ran — which is what lets shaping skip re-validating on every call.
289
+ * The attribute means "the consumer decides", and the authored `@before` / `@after` beside it
290
+ * is IGNORED rather than used as the value. Word's answer is HTML's default `<p>` margin,
291
+ * 14pt, which is what a document round-tripped through Word's HTML filter carries — and this
292
+ * one is everywhere, because Word writes `w:before="100" w:beforeAutospacing="1"` for it. Reading
293
+ * only the literal 100 twips lays every such paragraph out 9pt tight, which moves page breaks.
278
294
  */
279
- interface ResolvedFont {
280
- readonly [RESOLVED_FONT_BRAND]: true;
281
- readonly id: string;
282
- readonly identity: string;
283
- readonly request: FontRequest;
284
- readonly family: string;
285
- /** Owned byte length, available without creating a defensive byte copy. */
286
- readonly byteLength: number;
287
- readonly bytes: Uint8Array;
288
- readonly hash: string;
289
- readonly faceIndex: number;
290
- readonly substitution: FontSubstitution | null;
291
- }
295
+ declare const AUTO_PARAGRAPH_SPACING_PT = 14;
292
296
  /**
293
- * Largest single face this engine will ever admit, whatever a caller configures.
297
+ * Where a paragraph sits, for the contexts in which Word's auto spacing resolves to 0
298
+ * instead of {@link AUTO_PARAGRAPH_SPACING_PT}.
294
299
  *
295
- * A CEILING, not a default: a host may set a smaller `maxFontBytes`, but nothing can raise it
296
- * past this. Font bytes come from files, and an unbounded face is a memory-exhaustion vector.
297
- */
298
- declare const HARD_MAX_FONT_BYTES: number;
299
- /** Most faces one snapshot may hold, whatever a caller configures. */
300
- declare const HARD_MAX_FONT_SOURCES = 256;
301
- /** Most bytes all admitted faces may total, whatever a caller configures. */
302
- declare const HARD_MAX_AGGREGATE_FONT_BYTES: number;
303
- /**
304
- * Why a face was not admitted.
300
+ * This resolves the interior list-item value. Body layout restores each outer list margin
301
+ * in `resolveListAutoSpacing`, where neighboring blocks are available. A caller that says
302
+ * nothing gets the body answer.
305
303
  *
306
- * `forbidden` and `hashMismatch` are adversarial signals rather than ordinary failures: the first
307
- * is a face the host declared off-limits, the second is bytes that are not what their source
308
- * claimed.
304
+ * A TABLE CELL is not such a context. Measured on a captured control at 10pt, where the
305
+ * line pitch is 11.52pt: the reference puts 26.16pt between two paragraphs in the body with
306
+ * auto spacing on, and the SAME 26.16pt between two paragraphs inside a cell. With an empty
307
+ * paragraph between them it is 52.32, exactly twice. Reading it as 0 in a cell lays every
308
+ * such paragraph 13.92pt tight, which is enough to pull a signature block back onto the
309
+ * previous page. See `.cache/pdf/claude-autospacing/`.
309
310
  */
310
- type FontResolutionErrorCode = 'missing' | 'forbidden' | 'overLimit' | 'malformed' | 'hashMismatch';
311
+ interface ParagraphAutoSpacingContext {
312
+ /** The paragraph participates in numbering (`w:numPr`), i.e. it is a list item. */
313
+ readonly inList?: boolean;
314
+ /**
315
+ * The paragraph lives in a table cell. Kept because callers describe position with it and
316
+ * list resolution reads it; it does NOT zero auto spacing.
317
+ */
318
+ readonly inTableCell?: boolean;
319
+ /** Section grid pitch in points; no grid uses Word's fixed 12pt line unit. */
320
+ readonly lineUnitPt?: number;
321
+ /**
322
+ * `w:doNotUseHTMLParagraphAutoSpacing` is on: automatic spacing outside a list resolves to
323
+ * the fixed 5pt before and 10pt after instead of {@link AUTO_PARAGRAPH_SPACING_PT}.
324
+ */
325
+ readonly fixedAutoSpacing?: boolean;
326
+ }
311
327
  /**
312
- * A face that could not be admitted, carrying whatever evidence the refusal produced.
328
+ * Resolved line spacing (`w:spacing/@line` + `@lineRule`, ECMA-376 17.3.1.33).
313
329
  *
314
- * RETURNED rather than thrown by `FontResourceSnapshot.resolve`, because a missing face is an
315
- * ordinary condition — layout falls back and carries on. It extends `Error` so a caller that
316
- * would rather throw can.
330
+ * `auto` is the interesting one: `@line` is 240ths of a line, so 240 is single, 360 is
331
+ * one-and-a-half, 480 is double — and Word's own Normal style since 2013 is 259, i.e.
332
+ * 1.08. A document laid out at a flat single spacing is ~8% tight on EVERY line, which
333
+ * moves every page break, so this is not a cosmetic detail.
334
+ *
335
+ * `exact` fixes the line box at `@line` twips and lets tall glyphs clip, the way Word
336
+ * does. `atLeast` uses it as a floor.
317
337
  */
318
- declare class FontResolutionError extends Error {
319
- readonly name = "FontResolutionError";
320
- readonly request: FontRequest;
321
- readonly code: FontResolutionErrorCode;
322
- readonly limit?: number;
323
- readonly actual?: number;
324
- readonly diagnostic?: string;
325
- readonly expectedHash?: string;
326
- readonly actualHash?: string;
327
- constructor(code: FontResolutionErrorCode, request: FontRequest, details?: {
328
- readonly limit?: number;
329
- readonly actual?: number;
330
- readonly diagnostic?: string;
331
- readonly expectedHash?: string;
332
- readonly actualHash?: string;
333
- });
334
- }
338
+ type LineSpacingRule = 'auto' | 'exact' | 'atLeast';
335
339
  /**
336
- * One face offered to a snapshot, before admission.
340
+ * Resolved line spacing: the rule, and the value it applies.
337
341
  *
338
- * `hash` is checked against the bytes, so a source cannot claim a face it did not supply. Setting
339
- * `availability` to `forbidden` declares a face that exists but must not be used, which resolves
340
- * as a typed refusal rather than as "missing".
342
+ * `value` means different things per rule — 240ths of a line under `auto`, points under `exact`
343
+ * and `atLeast` — which is why the two travel together and neither is useful alone.
341
344
  */
342
- interface FontResourceDefinition {
343
- readonly request: FontRequest;
344
- readonly id: string;
345
- readonly bytes: Uint8Array;
346
- readonly hash: string;
347
- readonly faceIndex: number;
348
- readonly availability?: 'available' | 'forbidden';
345
+ interface ParagraphLineSpacing {
346
+ readonly rule: LineSpacingRule;
347
+ /** `auto`: the 240ths-of-a-line multiplier numerator. Otherwise points. */
348
+ readonly value: number;
349
+ /** Legacy noExtraLineSpacing: retain the natural baseline within an exact-height box. */
350
+ readonly preserveExactBaseline?: true;
351
+ /**
352
+ * Active section line-grid pitch in points (`w:docGrid/@w:linePitch`). Present only when
353
+ * the paragraph snaps to the grid; only with `auto`. See `line-grid.ts`.
354
+ */
355
+ readonly gridPitch?: number;
349
356
  }
357
+ /** Single spacing: what a paragraph that says nothing gets. */
358
+ declare const SINGLE_LINE_SPACING: ParagraphLineSpacing;
350
359
  /**
351
- * A host-declared redirect: requests for `from` resolve to `to`.
360
+ * One resolved `w:pBdr` edge: its style, colour, thickness and gap.
352
361
  *
353
- * How a metric-compatible substitute is wired in — a document naming Calibri resolves to Carlito
354
- * without the document being rewritten.
362
+ * `widthPt` and `spacePt` are already converted and CLAMPED — both come from a file, and an
363
+ * unbounded border width becomes a layout dimension.
355
364
  */
356
- interface DeclaredFontSubstitution {
357
- readonly from: FontRequest;
358
- readonly to: FontRequest;
359
- readonly lineMetrics?: {
360
- readonly heightEm: number;
361
- readonly baselineEm: number;
362
- };
365
+ interface ParagraphBorderEdge {
366
+ /** Authored `ST_Border` value (`single`, `dashed`, …). */
367
+ readonly val: string;
368
+ /** RRGGBB, or null when auto/missing (paint defaults to black). */
369
+ readonly color: string | null;
370
+ /** Border thickness in points (`w:sz` is eighths of a point). */
371
+ readonly widthPt: number;
372
+ /** Gap from text to the rule, in points (`w:space`). */
373
+ readonly spacePt: number;
374
+ /**
375
+ * `w:shadow` — Word offsets a drop shadow behind the rule.
376
+ *
377
+ * Present only when authored true, so an edge that says nothing keeps the shape earlier
378
+ * fixtures assert. Resolved and carried; drawing it is deferred.
379
+ */
380
+ readonly shadow?: true;
363
381
  }
364
- /** Whether bytes parse as a usable font, with a diagnostic when they do not. */
365
- type FontValidationResult = {
366
- readonly valid: true;
367
- } | {
368
- readonly valid: false;
369
- readonly diagnostic: string;
370
- };
382
+ /** The six `CT_PBdr` children, in schema order (ECMA-376 §17.3.1.24). */
383
+ declare const PARAGRAPH_BORDER_SIDES: readonly ['top', 'left', 'bottom', 'right', 'between', 'bar'];
371
384
  /**
372
- * The injected check that bytes really are a font.
385
+ * Which of the six `CT_PBdr` edges.
373
386
  *
374
- * Injected because it is the shaper that knows — HarfBuzz can open a face and read its tables,
375
- * and this layer must not duplicate that judgement. Every byte reaching it is file input.
387
+ * Four are physical box edges; `between` and `bar` are group-relative, drawn only where
388
+ * consecutive paragraphs share a border definition.
376
389
  */
377
- type FontByteValidator = (bytes: Uint8Array, faceIndex: number) => FontValidationResult;
390
+ type ParagraphBorderSide = (typeof PARAGRAPH_BORDER_SIDES)[number];
378
391
  /**
379
- * An immutable set of admitted faces, and the only way to reach one.
392
+ * A paragraph's resolved `w:pBdr` (ECMA-376 §17.3.1.24).
380
393
  *
381
- * `epoch` identifies the snapshot: fonts change by REPLACING it, never by mutation, so a layout
382
- * pass holds one snapshot for its whole run and cannot observe a face appearing or vanishing
383
- * midway.
394
+ * `top`/`left`/`bottom`/`right` are the four physical edges of the box. The other two are
395
+ * group-relative: `between` draws at a boundary INSIDE a run of consecutive paragraphs whose
396
+ * border settings are identical, and `bar` is the vertical change-bar rule beside the
397
+ * paragraph, drawn whether or not the paragraph groups with its neighbours.
384
398
  */
385
- interface FontResourceSnapshot {
386
- readonly epoch: number;
387
- /** The admitted face, or a typed refusal. Never throws. */
388
- resolve(request: FontRequest): ResolvedFont | FontResolutionError;
399
+ interface ParagraphBorders {
400
+ readonly top?: ParagraphBorderEdge;
401
+ readonly left?: ParagraphBorderEdge;
402
+ readonly bottom?: ParagraphBorderEdge;
403
+ readonly right?: ParagraphBorderEdge;
404
+ readonly between?: ParagraphBorderEdge;
405
+ readonly bar?: ParagraphBorderEdge;
389
406
  }
390
407
  /**
391
- * How a snapshot is built: which faces, under what limits, validated how.
408
+ * Resolve `w:spacing` before/after from flat paragraph properties.
392
409
  *
393
- * `maxFontBytes` is clamped to {@link HARD_MAX_FONT_BYTES} — a caller may tighten the budget but
394
- * never widen it past the engine's own ceiling.
395
- */
396
- interface FontResourceSnapshotOptions {
397
- readonly epoch: number;
398
- readonly maxFontBytes: number;
399
- readonly resources: readonly FontResourceDefinition[];
400
- readonly substitutions?: readonly DeclaredFontSubstitution[];
401
- readonly validateFont: FontByteValidator;
402
- readonly instrumentation?: FontResourceInstrumentation;
403
- }
404
- /**
405
- * Optional counters for the operations font admission is expected to do RARELY.
410
+ * Line spacing (`w:line` / `w:lineRule`) is a separate concern — it changes measured line
411
+ * height, not the gap between paragraphs — and is not resolved here.
406
412
  *
407
- * Exists so tests can assert the absence of work: hashing and byte-copying a 64 MB face on every
408
- * resolve would not be visible in output, only in a stalled document, so the checks assert these
409
- * fire once rather than per call.
413
+ * `w:beforeAutospacing` / `w:afterAutospacing` REPLACE the authored measurement on their own
414
+ * side rather than adding to it; see {@link AUTO_PARAGRAPH_SPACING_PT}.
410
415
  */
411
- interface FontResourceInstrumentation {
412
- readonly onOwnedByteCopy?: () => void;
413
- readonly onHash?: () => void;
414
- readonly onTableScan?: () => void;
415
- readonly onAdmission?: () => void;
416
- }
416
+ declare function paragraphSpacing(props: readonly OoxmlProperty[], context?: ParagraphAutoSpacingContext): ParagraphSpacing;
417
417
  /**
418
- * The canonical string identifying one face request.
418
+ * Resolve `w:line` / `w:lineRule` from flat paragraph properties.
419
419
  *
420
- * Case- and whitespace-normalized, so `"Times New Roman"` and `"times new roman"` are one key —
421
- * a document may name a family either way and both must reach the same face.
420
+ * Merged per attribute for the same reason as before/after: `w:spacing` is one element
421
+ * carrying independent attributes, and a style that states only `@line` must not reset the
422
+ * rule an earlier entry in the cascade set.
422
423
  */
423
- declare const fontRequestKey: (request: FontRequest) => string;
424
- /** Bounded minimum sfnt/TTC check; Task 4 supplies full parser-backed validation. */
425
- declare const boundedStructuralFontValidator: FontByteValidator;
424
+ declare function paragraphLineSpacing(props: readonly OoxmlProperty[]): ParagraphLineSpacing;
426
425
  /**
427
- * Admit a set of faces and return the immutable snapshot layout resolves against.
426
+ * Apply resolved line spacing to a line's natural (glyph-derived) box.
428
427
  *
429
- * Admission is the trust boundary for font bytes: counts and sizes are checked against the hard
430
- * ceilings, each face's hash is re-derived and compared, and the bytes are handed to the injected
431
- * validator. A face failing any of these is recorded as a typed refusal rather than dropped, so
432
- * `resolve` can explain itself instead of answering "missing".
433
- */
434
- declare const createFontResourceSnapshot: (options: FontResourceSnapshotOptions) => FontResourceSnapshot;
435
-
436
- declare const FIXED_POINT: unique symbol;
437
- /** Fixed-point coordinates are safe integers in units declared by ShapingEnvironment.fixedPointScale. */
438
- type FixedPoint = number & {
439
- readonly [FIXED_POINT]: true;
440
- };
428
+ * `auto` places its extra BELOW the line — the last line's multiple spacing still separates
429
+ * it from the next paragraph. Putting that delta above inverted cover-page rhythm:
430
+ * `w:line="460"` on "between" opened a large gap above the word and almost none before
431
+ * "MERIDIAN".
432
+ *
433
+ * `atLeast` does the OPPOSITE: the box grows upward and the glyphs sit on its floor. A
434
+ * captured control settles it — Times New Roman 12 pt at `w:line="360" w:lineRule="atLeast"`
435
+ * puts the reference's baseline at 15.36 pt, which is `18 - descent` snapped to the device
436
+ * grid, where treating it like `auto` leaves the baseline at 11.28 and the text 4.08 pt too
437
+ * high. `w:line="240" atLeast` is below the natural line, falls through to the natural
438
+ * height, and is unaffected. See `.cache/pdf/claude-linerule/`.
439
+ *
440
+ * Exact-height boxes place their baseline at 80% of the height; the legacy
441
+ * noExtraLineSpacing switch instead preserves the face baseline within the box.
442
+ *
443
+ * An `auto` or `atLeast` line of a snapping paragraph under an active line grid takes whole
444
+ * pitches instead ({@link gridLineBox}); `trailing` then names the box below the glyphs.
445
+ */
446
+ declare function applyLineSpacing(spacing: ParagraphLineSpacing, naturalHeight: number, naturalBaseline: number): {
447
+ height: number;
448
+ baseline: number;
449
+ trailing?: number;
450
+ };
441
451
  /**
442
- * Brand a safe integer as a {@link FixedPoint} coordinate.
452
+ * `w:contextualSpacing` (17.3.1.9): drop before/after between paragraphs of the SAME
453
+ * style. Word's built-in `ListParagraph` sets it, so every list authored in Word gets a
454
+ * paragraph gap between items without this.
455
+ */
456
+ declare function paragraphContextualSpacing(props: readonly OoxmlProperty[]): boolean;
457
+ /**
458
+ * Resolve `w:pBdr` from the paragraph-properties node.
443
459
  *
444
- * Fixed point rather than float throughout shaping so that two runs shaped identically compare
445
- * EQUAL — float accumulation would make the same text measure differently depending on how it was
446
- * split, and pagination is decided on those measurements.
460
+ * Nested — every edge is a child of `pBdr`, not an attribute — so this reads the typed tree
461
+ * rather than the flattened `OoxmlProperty[]` bag `propertiesOf` builds for leaf props.
462
+ */
463
+ declare function paragraphBorders(pPr: OoxmlNode | undefined): ParagraphBorders;
464
+ /**
465
+ * `w:pBdr` after the style cascade: a later `w:pBdr` replaces an earlier one WHOLESALE.
447
466
  *
448
- * @throws RangeError when the value is not a safe integer.
467
+ * Word does not merge edges across the cascade. A style that states only `w:bottom` discards
468
+ * the box its `basedOn` ancestor declared, so folding edge by edge would leave a lone
469
+ * underline surrounded by a box no one authored. Absence inherits; `nil`/`none` clear.
449
470
  */
450
- declare const fixedPoint: (value: number) => FixedPoint;
451
- /** Which way a run reads. The parity projection of its bidi embedding level. */
452
- type TextDirection = 'ltr' | 'rtl';
453
- /** How fixed-point conversion breaks ties. Part of the shaping fingerprint. */
454
- type FixedPointRoundingMode = 'halfAwayFromZero' | 'halfToEven' | 'towardZero';
455
- /** Which Unicode normalization is applied before shaping, if any. */
456
- type NormalizationPolicy = 'none' | 'NFC' | 'NFD' | 'NFKC' | 'NFKD';
471
+ declare function cascadedParagraphBorders(paragraphPropertyNodes: readonly OoxmlNode[]): ParagraphBorders;
457
472
  /**
458
- * The shaping library and its exact version.
473
+ * Visual stroke thickness layout publishes for one edge (points).
459
474
  *
460
- * Versioned because a library upgrade can change glyph positioning, and a cached measurement
461
- * taken under the old one must not be reused under the new one.
475
+ * Compound `ST_Border` values (`double`, …) use the shared inflated band so a thin
476
+ * `w:sz="3"` double still occupies a visible double-line box — matching table borders.
462
477
  */
463
- interface VersionedShapingLibrary {
464
- readonly name: string;
465
- readonly version: string;
466
- }
478
+ declare function paragraphBorderStrokeWidthPt(edge: ParagraphBorderEdge): number;
467
479
  /**
468
- * Everything that determines how text shapes — the complete input to a
469
- * {@link ShapingEnvironment}.
480
+ * Extent one border edge occupies away from the text it decorates: gap plus rule, in points.
470
481
  *
471
- * Exhaustive on purpose. Any field that could change a glyph's position belongs here, because the
472
- * environment's fingerprint is what decides whether a cached shaped run may be reused.
482
+ * Vertically that is flow height — a top rule pushes the first line down, a bottom rule holds
483
+ * the page open below the last one — so pagination has to see it. Horizontally it is
484
+ * publish-only: Word draws left/right paragraph rules OUTSIDE the text column and never
485
+ * re-breaks the lines, which is why adding a box to a paragraph in Word does not reflow it.
473
486
  */
474
- interface ShapingEnvironmentInput {
475
- readonly font: ResolvedFont;
476
- readonly variationAxes: Readonly<Record<string, number>>;
477
- readonly shapingLibrary: VersionedShapingLibrary;
478
- readonly unicodeDataVersion: string;
479
- readonly normalization: NormalizationPolicy;
480
- readonly script: string;
481
- readonly language: string;
482
- readonly direction: TextDirection;
483
- readonly features: Readonly<Record<string, number>>;
484
- readonly fallbackOrder: readonly ResolvedFont[];
485
- readonly fixedPointScale: number;
486
- readonly roundingMode: FixedPointRoundingMode;
487
- }
487
+ declare function paragraphBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;
488
+ /** Vertical extent a bottom border adds below the last line (gap + rule). */
489
+ declare function bottomBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;
488
490
  /**
489
- * A validated {@link ShapingEnvironmentInput} — build one with `createShapingEnvironment`.
491
+ * Identity of a paragraph's border set, for the `w:between` group rule.
490
492
  *
491
- * Structurally identical to its input, but the nominal distinction is the point: holding one
492
- * means the tags, axes and fonts inside it have already been checked.
493
+ * Word treats consecutive paragraphs whose border settings are IDENTICAL as ONE bordered
494
+ * block: the top rule draws above the first, the bottom rule below the last, and each
495
+ * interior boundary gets `w:between` or nothing (§17.3.1.24). That is why applying a box to
496
+ * three selected paragraphs in Word draws one box and not three.
497
+ *
498
+ * Empty string means "no borders", which never groups with anything.
493
499
  */
494
- interface ShapingEnvironment extends ShapingEnvironmentInput {
500
+ declare function paragraphBordersFingerprint(borders: ParagraphBorders): string;
501
+ /**
502
+ * Gap to insert before a paragraph once the previous paragraph's `after` is already in the
503
+ * flow cursor — Word takes the larger of the two rather than summing them.
504
+ */
505
+ declare function collapsedSpaceBefore(before: number, previousAfter: number): number;
506
+ /**
507
+ * Applied before-spacing for placement (Word 2013+ / compat mode 15).
508
+ *
509
+ * Adjacent before/after still collapse to the larger gap, but before is dropped entirely when
510
+ * the paragraph naturally moves to the top of a page mid-section. An explicit page-break-before
511
+ * paragraph, or the first paragraph of a document/section, retains before. Callers publish this
512
+ * applied value on the fragment so shading, borders,
513
+ * selection, and paint share one geometry.
514
+ */
515
+ declare function appliedSpaceBefore(before: number, previousAfter: number, atTopOfPage: boolean, preserveAtPageStart: boolean): number;
516
+
517
+ /**
518
+ * The four physical sides of `CT_PageBorders`.
519
+ *
520
+ * Four, not the six of `w:pBdr`: `w:between` and `w:bar` are paragraph-group rules and the
521
+ * page has no analogue for either.
522
+ */
523
+ declare const PAGE_BORDER_SIDES: readonly ['top', 'left', 'bottom', 'right'];
524
+ /** Which of the four page-frame edges. */
525
+ type PageBorderSide = (typeof PAGE_BORDER_SIDES)[number];
526
+ /**
527
+ * `w:offsetFrom` (`ST_PgBorderOffset`) — what `w:space` on each edge is measured from.
528
+ *
529
+ * The schema default is `text`, NOT `page`. Word's own UI opens on "Edge of page", which is
530
+ * why the wrong default is easy to assume and expensive to hold: at `text` the rule sits
531
+ * `w:space` points outside the TEXT, so its distance from the sheet edge is the margin minus
532
+ * the space — a number that moves whenever the margins do.
533
+ */
534
+ type PageBorderOffsetFrom = 'page' | 'text';
535
+ /** `w:display` (`ST_PgBorderDisplay`) — which pages of the section carry the frame. */
536
+ type PageBorderDisplay = 'allPages' | 'firstPage' | 'notFirstPage';
537
+ /** `w:zOrder` (`ST_PgBorderZOrder`) — whether the frame paints over the text or under it. */
538
+ type PageBorderZOrder = 'front' | 'back';
539
+ /**
540
+ * One section's resolved `w:pgBorders`.
541
+ *
542
+ * Resolved, not raw: every attribute the file omitted is filled in with the SCHEMA default,
543
+ * so a consumer never has to know which of the three were authored. An edge is present only
544
+ * when it paints — `nil` / `none` and art borders are already gone (see {@link parsePageBorders}).
545
+ */
546
+ interface SectionPageBorders {
547
+ /** `w:offsetFrom`; absent attribute reads as `text` (§17.6.10). */
548
+ readonly offsetFrom: PageBorderOffsetFrom;
549
+ /** `w:display`; absent attribute reads as `allPages`. */
550
+ readonly display: PageBorderDisplay;
551
+ /** `w:zOrder`; absent attribute reads as `front`. */
552
+ readonly zOrder: PageBorderZOrder;
553
+ readonly top?: ParagraphBorderEdge;
554
+ readonly left?: ParagraphBorderEdge;
555
+ readonly bottom?: ParagraphBorderEdge;
556
+ readonly right?: ParagraphBorderEdge;
495
557
  }
496
- /** One shaping call: the text, its size, its bidi level, and the environment to shape it in. */
497
- interface ShapeInput {
498
- readonly text: string;
499
- readonly fontSizeHalfPoints: number;
500
- /** Exact UAX #9 embedding/isolate level; direction is its parity projection. */
501
- readonly bidiLevel: number;
502
- readonly environment: ShapingEnvironment;
558
+ /**
559
+ * Parse `w:pgBorders` off one `w:sectPr`.
560
+ *
561
+ * Undefined when the element is absent AND when it paints nothing — every edge off, or every
562
+ * edge an art border. Unlike `w:pgNumType`, an empty-but-present element is not distinguished:
563
+ * these properties are a LAYOUT input, serialization re-emits the canonical tree, and a frame
564
+ * with no edges has exactly one meaning downstream.
565
+ */
566
+ declare function parsePageBorders(sectPr: OoxmlNode): SectionPageBorders | undefined;
567
+ /**
568
+ * Identity of one section's page frame, for incremental-layout context keys.
569
+ *
570
+ * A `w:pgBorders` edit changes nothing the flow measures — the frame is drawn beside the text,
571
+ * never through it — so no per-paragraph key moves and every reuse path would hand back the
572
+ * previous sheets with the previous frame. This token goes in the pass context so it does not.
573
+ */
574
+ declare function pageBordersFingerprint(borders: SectionPageBorders | undefined): string;
575
+
576
+ /**
577
+ * Hard ceiling on sections enumerated from a document (matches write-path
578
+ * `MAX_SECTIONS` in note/hf lifecycle). Hostile packages with unbounded `w:sectPr`
579
+ * marks fail closed here rather than amplifying layout props arrays.
580
+ */
581
+ declare const MAX_DOCUMENT_SECTIONS = 4096;
582
+ /** A section's margins in twips, including the header and footer reserve bands. */
583
+ interface SectionMargins {
584
+ readonly topTwips: number;
585
+ readonly rightTwips: number;
586
+ readonly bottomTwips: number;
587
+ readonly leftTwips: number;
588
+ readonly headerTwips: number;
589
+ readonly footerTwips: number;
590
+ readonly gutterTwips: number;
591
+ }
592
+ /** One explicit `w:col`: its width and the gap after it. */
593
+ interface SectionColumnDefinition {
594
+ readonly widthTwips: number;
595
+ /** Space after this column; zero on the final column. */
596
+ readonly gapTwips: number;
597
+ }
598
+ /**
599
+ * A section's column layout.
600
+ *
601
+ * Equal-width and explicit-width columns are one type because a file may declare `w:num` with no
602
+ * `w:col` children at all, and layout must handle both without branching at every use site.
603
+ */
604
+ interface SectionColumns {
605
+ readonly count: number;
606
+ /** Shared gap for equal-width columns and fallback gap for incomplete explicit definitions. */
607
+ readonly gapTwips: number;
608
+ readonly equalWidth?: boolean;
609
+ readonly separator?: boolean;
610
+ /** Authored `w:col` geometry when `equalWidth` is false. */
611
+ readonly definitions?: readonly SectionColumnDefinition[];
612
+ }
613
+ /**
614
+ * How this section is placed relative to the previous one (ECMA-376 17.6.22,
615
+ * `ST_SectionMark`).
616
+ *
617
+ * All five schema values are read. `nextColumn` paginates like `nextPage` for now: in a
618
+ * single-column section that IS Word's behaviour, and multi-column flow is not modelled,
619
+ * so collapsing it at the parse boundary would only hide the authored value from a
620
+ * consumer that asks.
621
+ */
622
+ type SectionBreakType = 'nextPage' | 'continuous' | 'evenPage' | 'oddPage' | 'nextColumn';
623
+ /**
624
+ * Authored `w:pgNumType` (ECMA-376 CT_PageNumber).
625
+ *
626
+ * Distinguishes three states via {@link SectionProperties.pageNumbering}:
627
+ * - element absent → `undefined` (Word defaults; no empty element to re-emit)
628
+ * - empty `<w:pgNumType/>` → `{}` (present, no authored attrs; must round-trip empty)
629
+ * - attributes set → only those keys appear (never invent schema defaults like `fmt=decimal`)
630
+ *
631
+ * `chapStyle` / `chapSep` are preserved for consumers; PAGE projection does not yet compose
632
+ * chapter numbers (heading outline resolution is out of this slice).
633
+ */
634
+ interface SectionPageNumbering {
635
+ /** Authored `@w:start` when present and in range; otherwise omitted. */
636
+ readonly start?: number;
637
+ /** Authored `@w:fmt` (ST_NumberFormat) when present; otherwise omitted. */
638
+ readonly fmt?: string;
639
+ /** Authored `@w:chapStyle` outline level when present and in range. */
640
+ readonly chapStyle?: number;
641
+ /** Authored `@w:chapSep` when present (hyphen / period / colon / emDash / enDash). */
642
+ readonly chapSep?: string;
643
+ }
644
+ /**
645
+ * One section's resolved `w:sectPr`, as layout needs it.
646
+ *
647
+ * Resolved, not raw: defaults the file omitted are filled in here (an absent `w:type` is
648
+ * `nextPage`), so layout never has to know which attributes were authored and which were
649
+ * inherited.
650
+ */
651
+ interface SectionProperties {
652
+ /** Active document grid line pitch: line-unit paragraph margins and line snapping. */
653
+ readonly gridLinePitchTwips?: number;
654
+ readonly pageSize: {
655
+ readonly widthTwips: number;
656
+ readonly heightTwips: number;
657
+ };
658
+ readonly margins: SectionMargins;
659
+ readonly columns: SectionColumns;
660
+ readonly landscape: boolean;
661
+ readonly titlePage: boolean;
662
+ /** Absent `w:type` defaults to `nextPage`. */
663
+ readonly breakType: SectionBreakType;
503
664
  /**
504
- * Logical text around `text` that the shaper reads for contextual forms but never
505
- * shapes: HarfBuzz pre- and post-context. A word split across two formatting runs joins
506
- * across the split only when each half sees the other's letters. At most
507
- * {@link MAX_SHAPING_CONTEXT} UTF-16 units each; glyphs and clusters cover `text` alone.
665
+ * Authored page-number type. Absent when `w:pgNumType` is missing; empty object when the
666
+ * element is present with no attributes (comprehensive-fixture shape).
508
667
  */
509
- readonly context?: ShapingContext;
510
- }
511
- /** Pre- and post-context for one shaping call. See {@link ShapeInput.context}. @public */
512
- interface ShapingContext {
513
- readonly before: string;
514
- readonly after: string;
668
+ readonly pageNumbering?: SectionPageNumbering;
669
+ /**
670
+ * Resolved `w:pgBorders` (§17.6.10). Absent when the section declares none, or when every
671
+ * edge it declares is off or an art border — see {@link parsePageBorders}.
672
+ */
673
+ readonly pageBorders?: SectionPageBorders;
515
674
  }
516
- /** Longest context on either side, in UTF-16 units. Joining needs only the nearest letters. @public */
517
- declare const MAX_SHAPING_CONTEXT = 16;
518
675
  /**
519
- * One positioned glyph.
676
+ * One section of the body story: contiguous top-level blocks plus the properties that end it.
520
677
  *
521
- * `id` is a glyph index in its FACE, not a character — a ligature is one glyph spanning several
522
- * characters, and a single character may produce several glyphs. Use `cluster` to get back to
523
- * text.
678
+ * `blockStart` / `blockEndExclusive` index into `storyBlocks(part)`.
524
679
  */
525
- interface ShapedGlyph {
526
- readonly id: number;
527
- /** Optional synthetic glyph-size factor; positions and advances already include it. */
528
- readonly drawScale?: number;
529
- /** UTF-16 text offset identifying the cluster that produced this glyph. */
530
- readonly cluster: number;
531
- /** Pen origin before this glyph's shaping offsets, in fixed-point run coordinates. */
532
- readonly originX: FixedPoint;
533
- readonly originY: FixedPoint;
534
- readonly advanceX: FixedPoint;
535
- readonly advanceY: FixedPoint;
536
- readonly offsetX: FixedPoint;
537
- readonly offsetY: FixedPoint;
538
- /** Exact monochrome outline returned by the admitted HarfBuzz face. */
539
- readonly outline: GlyphOutline;
680
+ interface DocumentSection {
681
+ readonly index: number;
682
+ readonly properties: SectionProperties;
683
+ readonly blockStart: number;
684
+ readonly blockEndExclusive: number;
540
685
  }
541
- /** A glyph's outline as SVG path data, in font design units. */
542
- interface GlyphOutline {
543
- readonly path: string;
544
- /** Design units per em — divide by this to scale the path to a point size. */
545
- readonly unitsPerEm: number;
686
+ /** US Letter, portrait, one-inch margins: Word's own default when a section says nothing. */
687
+ declare const DEFAULT_SECTION_PROPERTIES: SectionProperties;
688
+ /**
689
+ * Parse authored `w:pgNumType` without inventing schema defaults.
690
+ *
691
+ * Returns `undefined` when the element is absent. An empty element yields `{}` so callers
692
+ * can tell "present but unauthored" from "missing" and serialization can re-emit empty.
693
+ * Hostile / out-of-range attribute values are dropped rather than clamped into meaning.
694
+ */
695
+ declare function parsePageNumbering(sectPr: OoxmlNode): SectionPageNumbering | undefined;
696
+ /** Parse one `w:sectPr` into geometry/break properties (null reads as Word's defaults). */
697
+ declare function parseSectionProperties(sectPr: OoxmlNode | null | undefined): SectionProperties;
698
+ /** `w:sectPr` nested under a paragraph's `w:pPr`, if present. */
699
+ declare function paragraphSectionNode(paragraph: OoxmlElement): OoxmlElement | undefined;
700
+ /**
701
+ * The section properties a part declares, or Word's defaults where it says nothing.
702
+ *
703
+ * Returns the FINAL section (body-level `w:sectPr`, else the last paragraph-level one).
704
+ * Multi-section geometry belongs to `enumerateDocumentSections`; chrome that needs "the
705
+ * document's page" still reads the last section, which is what Word's body-level sectPr is.
706
+ */
707
+ declare function readSectionProperties(part: OoxmlPart): SectionProperties;
708
+ /**
709
+ * Split the body story into sections.
710
+ *
711
+ * A paragraph carrying `w:pPr/w:sectPr` ends the current section (that paragraph is IN the
712
+ * section being ended). The body-level `w:sectPr` ends the final section. A document with
713
+ * neither yields one section of Word defaults covering every block.
714
+ *
715
+ * Enumeration is capped at {@link MAX_DOCUMENT_SECTIONS}. Further paragraph-level section
716
+ * breaks are ignored and remaining blocks fold into the last accepted section (fail closed).
717
+ *
718
+ * `displayMode` MUST match the one the caller passes to `storyBlocks`. `blockStart` /
719
+ * `blockEndExclusive` are indices into that list, and the list changes shape with the mode:
720
+ * the proposed view drops a paragraph whose mark and content a revision both removed. Slicing
721
+ * a filtered list with indices counted over an unfiltered one puts body text under another
722
+ * section's page geometry — the wrong paper size, the wrong margins, the wrong header.
723
+ */
724
+ declare function enumerateDocumentSections(part: OoxmlPart, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): DocumentSection[];
725
+ /**
726
+ * Canonical section index behind each section in a revision-projected body.
727
+ *
728
+ * A removed paragraph mark can collapse an entire section. The projected section keeps the
729
+ * surviving paragraph's geometry, while package APIs such as header/footer resolution remain
730
+ * indexed over the canonical tree. This bridge prevents those two index spaces from being
731
+ * paired positionally.
732
+ */
733
+ declare function projectedSectionSourceIndexes(part: OoxmlPart, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): readonly number[];
734
+ /**
735
+ * Every section in a document, with a flag saying whether the list was cut short.
736
+ *
737
+ * `truncated` is reported rather than silent: section count comes from a file, so a crafted
738
+ * document declaring thousands of paragraph-level `w:sectPr` marks is bounded, and a reader
739
+ * should be able to tell that happened.
740
+ */
741
+ interface DocumentSectionsEnumeration {
742
+ readonly sections: DocumentSection[];
743
+ /** True when paragraph-level sectPr marks beyond {@link MAX_DOCUMENT_SECTIONS} were dropped. */
744
+ readonly truncated: boolean;
546
745
  }
547
746
  /**
548
- * One cluster: the smallest indivisible text-to-glyph correspondence.
747
+ * Like {@link enumerateDocumentSections}, but reports whether the section bound clipped
748
+ * hostile input. Prefer the plain enumerator for normal layout; use this when a caller
749
+ * needs a named fail-closed diagnostic.
750
+ */
751
+ declare function enumerateDocumentSectionsBounded(part: OoxmlPart, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): DocumentSectionsEnumeration;
752
+ /**
753
+ * Section properties as the geometry layout paginates against.
549
754
  *
550
- * The unit the CARET moves by. A cluster may be several characters (a ligature) or several glyphs
551
- * (a decomposed mark), so neither a character index nor a glyph index is a valid caret position —
552
- * `caretEdges` is, and it includes both endpoints.
755
+ * The gutter is added to the LEFT margin: it is binding allowance, extra space on the inner
756
+ * edge, and folding it into the content width instead would silently narrow every line.
757
+ *
758
+ * Top and bottom keep the authored sign of `w:pgMar`: a negative value is an exact inset that
759
+ * header and footer height never moves. Read them through `page-body-margins.ts`.
553
760
  */
554
- interface ShapedCluster {
555
- /** Half-open logical UTF-16 range in ShapedRun.text. */
556
- readonly textStart: number;
557
- readonly textEnd: number;
558
- /** Half-open visual glyph range in ShapedRun.glyphs. */
559
- readonly glyphStart: number;
560
- readonly glyphEnd: number;
561
- readonly advance: FixedPoint;
562
- /** Fixed-point edges from this cluster's visual origin, including both endpoints. */
563
- readonly caretEdges: readonly FixedPoint[];
564
- /** Index into ShapedRun.fontSpans, preserving the exact fallback choice. */
565
- readonly fontSpan: number;
761
+ declare function geometryOfSection(section: SectionProperties): PageGeometry;
762
+
763
+ /**
764
+ * `w:tblpPr/@w:horzAnchor` (17.4.58) and `@w:vertAnchor` (17.4.66): the box a floated
765
+ * table's offsets are measured from. Absent means `text` for both.
766
+ */
767
+ type TableFloatAnchor = 'text' | 'margin' | 'page';
768
+ /** `w:tblpPr/@w:tblpXSpec` (17.4.63, ST_XAlign). */
769
+ type TableFloatXSpec = 'left' | 'center' | 'right' | 'inside' | 'outside';
770
+ /** `w:tblpPr/@w:tblpYSpec` (17.4.65, ST_YAlign). */
771
+ type TableFloatYSpec = 'inline' | 'top' | 'center' | 'bottom' | 'inside' | 'outside';
772
+ /**
773
+ * `w:tblPr/w:tblpPr` (17.4.57) — a table positioned against an anchor box rather than at
774
+ * the point in the text where it was authored.
775
+ *
776
+ * A spec (`tblpXSpec`/`tblpYSpec`) supersedes the matching offset when both are present:
777
+ * 17.4.57 states the alignment outright, and the offset only answers "how far from the
778
+ * anchor" for the case where no alignment was stated.
779
+ */
780
+ interface TableFloatPosition {
781
+ readonly horzAnchor: TableFloatAnchor;
782
+ readonly vertAnchor: TableFloatAnchor;
783
+ readonly xSpec?: TableFloatXSpec;
784
+ /** `w:tblpX` in points; signed, so a table can be pulled into the margin. */
785
+ readonly xPt: number;
786
+ readonly ySpec?: TableFloatYSpec;
787
+ /** `w:tblpY` in points; signed. */
788
+ readonly yPt: number;
789
+ readonly distances?: {
790
+ readonly top: number;
791
+ readonly right: number;
792
+ readonly bottom: number;
793
+ readonly left: number;
794
+ };
566
795
  }
567
- /** A run's vertical metrics, from the face that shaped it. Drives line height and baseline. */
568
- interface ShapedVerticalMetrics {
569
- readonly ascent: FixedPoint;
570
- readonly descent: FixedPoint;
571
- readonly lineGap: FixedPoint;
796
+
797
+ /**
798
+ * One `w:numPicBullet`: the image a level draws instead of its `w:lvlText`.
799
+ *
800
+ * `relationshipId` is unresolved on purpose — it names a relationship of the numbering part,
801
+ * and resolving it is the image-resource lookup's job, under its own validation and caps.
802
+ * @public
803
+ */
804
+ interface NumberingPictureBullet {
805
+ /** `w:numPicBulletId` — what a level's `w:lvlPicBulletId` names. */
806
+ readonly picBulletId: string;
807
+ /** `v:imagedata/@r:id`, relative to the NUMBERING part's relationships. */
808
+ readonly relationshipId: string;
809
+ /** Authored `v:shape` width in points. */
810
+ readonly width: number;
811
+ /** Authored `v:shape` height in points. */
812
+ readonly height: number;
572
813
  }
573
814
  /**
574
- * A stretch of glyphs that came from ONE face.
815
+ * A level's picture bullet with the size it is actually DRAWN at.
575
816
  *
576
- * A run whose text needed fallback has several of these. Recording the exact face per span is
577
- * what lets a re-shape reproduce the same result rather than re-running fallback selection and
578
- * possibly choosing differently.
817
+ * Separate from {@link NumberingPictureBullet} because the authored `v:shape` extent is not
818
+ * the painted extent: Word scales it by the marker run's font size. Layout, hit testing and
819
+ * both paint sinks read `width` / `height`; `authored` is kept so the scale stays inspectable.
820
+ * @public
579
821
  */
580
- interface ShapedFontSpan {
581
- readonly glyphStart: number;
582
- readonly glyphEnd: number;
583
- readonly font: ResolvedFont;
584
- /** null denotes the primary font; otherwise this is the environment fallback-order index. */
585
- readonly fallbackIndex: number | null;
822
+ interface ResolvedPictureBullet {
823
+ /** `v:imagedata/@r:id`, relative to the NUMBERING part's relationships. */
824
+ readonly relationshipId: string;
825
+ /** Painted width in points, after the marker font scale. */
826
+ readonly width: number;
827
+ /** Painted height in points, after the marker font scale. */
828
+ readonly height: number;
829
+ /** The `v:shape` extent exactly as the file authored it. */
830
+ readonly authored: NumberingPictureBullet;
586
831
  }
832
+
833
+ /** Soft ceiling on abstractNum / num entries read from one part. */
834
+ declare const MAX_NUMBERING_DEFINITIONS = 512;
835
+ /** Soft ceiling on override entries per `w:num`. */
836
+ declare const MAX_LVL_OVERRIDES = 9;
837
+ /** `w:suff` — what separates a list marker from the text after it. */
838
+ type ListSuffix = 'tab' | 'space' | 'nothing';
839
+ /** `w:lvlJc` — how a list marker aligns within its own indent. */
840
+ type ListMarkerAlign = 'left' | 'center' | 'right';
587
841
  /**
588
- * One shaped run: text turned into positioned glyphs, with everything needed to measure it, paint
589
- * it, and put a caret in it.
842
+ * One level's indent, plus which parts the level actually AUTHORED.
590
843
  *
591
- * The engine's measurement unit. Layout never measures characters — it measures these.
844
+ * The provenance matters: `w:ind` cascades per-attribute, so a level that authored only `left`
845
+ * must not overwrite an inherited `hanging` with a synthesized zero.
592
846
  */
593
- interface ShapedRun {
594
- readonly text: string;
595
- readonly direction: TextDirection;
596
- readonly bidiLevel: number;
597
- readonly glyphs: readonly ShapedGlyph[];
598
- readonly clusters: readonly ShapedCluster[];
599
- readonly fontSpans: readonly ShapedFontSpan[];
600
- readonly metrics: ShapedVerticalMetrics;
847
+ interface NumberingLevelIndent {
601
848
  /**
602
- * The same horizontal advances as `glyphs[i].advanceX`, in the same fixed-point units, but
603
- * BEFORE the per-glyph rounding to the fixed-point grid. Parallel to `glyphs`.
849
+ * The sides as the level spells them, in points. `left` and `start` both name the leading
850
+ * indent, and `right` and `end` the trailing one; `left`/`right` below hold those two.
851
+ */
852
+ readonly authored?: {
853
+ readonly left?: number;
854
+ readonly right?: number;
855
+ readonly start?: number;
856
+ readonly end?: number;
857
+ };
858
+ readonly left: number;
859
+ readonly right: number;
860
+ readonly hanging: number;
861
+ readonly firstLine: number;
862
+ /**
863
+ * Which of these the LEVEL actually authored.
604
864
  *
605
- * Measurement and line breaking read `advanceX` and must keep doing so: pagination is decided
606
- * on those numbers, and two runs shaped identically have to compare equal. A painter that
607
- * gives every glyph its own absolute position sums the advances instead, and a sum of ROUNDED
608
- * advances drifts by up to half a fixed-point unit per glyph — an error that only grows along
609
- * a line. Summing these and rounding once, at the position actually written, does not.
865
+ * A level's `w:pPr/w:ind` sits between the formatting it outranks and the formatting that
866
+ * outranks it (`mergeListIndent`), so the merge has to tell "the level says left = 0" from
867
+ * "the level says nothing about left and the style's value stands". Absent (the default) reads as "says nothing", which is what a
868
+ * hand-built level in a test means.
869
+ */
870
+ readonly stated?: {
871
+ readonly left: boolean;
872
+ readonly right: boolean;
873
+ /** `w:hanging`/`w:firstLine` are one mutually exclusive slot (§17.3.1.10, §17.3.1.12). */
874
+ readonly firstLineOffset: boolean;
875
+ };
876
+ }
877
+ /** One `w:lvl`: how this depth numbers, what its marker looks like, and how it indents. */
878
+ interface NumberingLevel {
879
+ readonly ilvl: number;
880
+ readonly start: number;
881
+ readonly numFmt: string;
882
+ readonly lvlText: string;
883
+ readonly lvlJc: ListMarkerAlign;
884
+ readonly suff: ListSuffix;
885
+ readonly indent: NumberingLevelIndent;
886
+ /**
887
+ * `w:lvlRestart` one-based trigger level, or `0` when the level never restarts.
888
+ * Omitted in XML → restart when the previous level (or any earlier level) is used.
889
+ */
890
+ readonly lvlRestart?: number;
891
+ /**
892
+ * `w:isLgl` (§17.9.9): render EVERY level referenced by this level's `w:lvlText` in
893
+ * decimal, whatever number format those levels declare for themselves.
894
+ */
895
+ readonly isLgl: boolean;
896
+ /**
897
+ * `w:lvlPicBulletId` (§17.9.12): this level's marker is the `w:numPicBullet` of that id,
898
+ * drawn INSTEAD of `w:lvlText`. Absent on every ordinary level.
899
+ */
900
+ readonly picBulletId?: string;
901
+ /** Level `w:rPr` as flat properties (for marker face / vanish). */
902
+ readonly runProperties: readonly OoxmlProperty[];
903
+ /** True when level run props request vanish — marker must not paint. */
904
+ readonly vanish: boolean;
905
+ }
906
+ /**
907
+ * One `w:lvlOverride` on a `w:num`: a restart value, a replacement level, or both.
908
+ *
909
+ * How two lists share an abstract definition while numbering independently.
910
+ */
911
+ interface LevelOverride {
912
+ readonly startOverride?: number;
913
+ /** Full level replacement when `w:lvl` is present under the override. */
914
+ readonly level?: NumberingLevel;
915
+ }
916
+ /**
917
+ * One `w:abstractNum` — the shape of a list, without being a list.
918
+ *
919
+ * Never referenced by a paragraph directly. Paragraphs name a {@link NumDefinition}, which names
920
+ * one of these, so several lists can share a definition and still count separately.
921
+ */
922
+ interface AbstractNumDefinition {
923
+ readonly abstractNumId: string;
924
+ readonly levels: ReadonlyMap<number, NumberingLevel>;
925
+ /**
926
+ * `w:numStyleLink` (§17.9.21): this definition carries no levels of its own — the numbering
927
+ * lives on the named style. Word follows the link; resolve it with
928
+ * {@link resolveNumberingStyleLinks} before reading levels, or every paragraph on this
929
+ * abstract renders with NO marker at all.
930
+ */
931
+ readonly numStyleLink?: string;
932
+ /**
933
+ * `w:styleLink` (§17.9.23): the definition side of the same pair — this abstract IS the
934
+ * numbering of the named style. Kept so a link can be verified rather than assumed.
935
+ */
936
+ readonly styleLink?: string;
937
+ }
938
+ /**
939
+ * One `w:num` — the thing a paragraph's `w:numId` actually names.
940
+ *
941
+ * Points at an {@link AbstractNumDefinition} and may override any of its levels.
942
+ */
943
+ interface NumDefinition {
944
+ readonly numId: string;
945
+ readonly abstractNumId: string;
946
+ readonly overrides: ReadonlyMap<number, LevelOverride>;
947
+ }
948
+ /**
949
+ * The bounded projection of `numbering.xml` that list layout resolves against.
950
+ *
951
+ * Projection ONLY — never a mutation or serialization authority. Hostile values are dropped or
952
+ * clamped, and a missing definition resolves to "no list" rather than a guess.
953
+ */
954
+ interface NumberingIndex {
955
+ readonly abstractNums: ReadonlyMap<string, AbstractNumDefinition>;
956
+ readonly nums: ReadonlyMap<string, NumDefinition>;
957
+ /**
958
+ * `w:numPicBullet` declarations keyed by `w:numPicBulletId` (§17.9.20).
610
959
  *
611
- * Absent on runs an assembly path cannot state exactly; a reader falls back to `originX`.
960
+ * Optional so a hand-built index stays valid; absent reads as "this part declares none",
961
+ * which is what a level's `w:lvlPicBulletId` then falls back from.
612
962
  */
613
- readonly exactAdvancesX?: readonly number[];
963
+ readonly pictureBullets?: ReadonlyMap<string, NumberingPictureBullet>;
614
964
  }
615
965
  /**
616
- * A {@link ShapedRun} reduced to the fields two shaping results must agree on to be considered
617
- * identical.
966
+ * Build a numbering index from the root of a numbering part (`w:numbering`).
618
967
  *
619
- * Fonts appear as {@link FontFingerprintInputs} rather than whole `ResolvedFont` objects, so the
620
- * comparison is over VALUES and does not depend on object identity — which is what makes it work
621
- * across a reload or a worker boundary.
968
+ * Empty / missing roots yield an empty index. Duplicate ids keep the first definition.
622
969
  */
623
- interface ShapedRunComparatorInputs {
624
- readonly text: string;
625
- readonly direction: TextDirection;
626
- readonly script: string;
627
- readonly language: string;
628
- readonly bidiLevel: number;
629
- readonly glyphs: readonly ShapedGlyph[];
630
- readonly clusters: readonly ShapedCluster[];
631
- readonly fontSpans: readonly {
632
- readonly glyphStart: number;
633
- readonly glyphEnd: number;
634
- readonly fallbackIndex: number | null;
635
- readonly font: FontFingerprintInputs;
636
- }[];
637
- readonly metrics: ShapedVerticalMetrics;
970
+ /**
971
+ * Project `numbering.xml` into the bounded index.
972
+ *
973
+ * Every ceiling here exists because the input is file-derived: definition counts, override
974
+ * counts, indent magnitudes and style-link hop depth are all capped, and nothing from the file
975
+ * becomes a loop bound or an allocation size.
976
+ */
977
+ declare function buildNumberingIndex(root: OoxmlElement | null | undefined): NumberingIndex;
978
+ /** Resolve the effective level for a `numId` + `ilvl`, applying overrides. */
979
+ /**
980
+ * The effective level for one paragraph's numbering reference, after overrides and style links.
981
+ *
982
+ * Answers null for a reference the index cannot resolve — a paragraph naming a definition the
983
+ * file never declared is an unnumbered paragraph, not an error.
984
+ */
985
+ declare function resolveNumberingLevel(index: NumberingIndex, numId: string, ilvl: number): {
986
+ readonly abstractNumId: string;
987
+ readonly level: NumberingLevel;
988
+ readonly startOverride?: number;
989
+ } | null;
990
+ /** Empty index for tests / documents without numbering. */
991
+ declare const EMPTY_NUMBERING_INDEX: NumberingIndex;
992
+
993
+ /**
994
+ * A face, as something asks for it: family plus the two axes this engine admits.
995
+ *
996
+ * Only static weights and slants. Variable-font axes are deliberately outside this vocabulary —
997
+ * the shaper refuses variation axes, and a variable file admitted here would render bold at
998
+ * regular weight.
999
+ */
1000
+ interface FontRequest {
1001
+ readonly family: string;
1002
+ readonly weight: number;
1003
+ readonly style: 'normal' | 'italic';
638
1004
  }
639
1005
  /**
640
- * The one thing layout needs from a shaping backend.
1006
+ * A request that was answered by a DIFFERENT face than the one asked for.
641
1007
  *
642
- * Injected rather than imported, which is what keeps layout DOM-free and testable: a fixed-metric
643
- * shaper measures deterministically in a test, HarfBuzz measures for real in a browser, and
644
- * layout cannot tell the difference.
1008
+ * Recorded rather than silently applied, because a substitution changes measurement: it is part
1009
+ * of the shaping fingerprint, so a cached run shaped against a substitute is never reused for the
1010
+ * real face.
645
1011
  */
646
- interface TextShaper {
647
- shape(input: ShapeInput): ShapedRun;
1012
+ interface FontSubstitution {
1013
+ readonly requested: FontRequest;
1014
+ readonly resolved: FontRequest;
1015
+ readonly lineMetrics?: {
1016
+ readonly heightEm: number;
1017
+ readonly baselineEm: number;
1018
+ };
648
1019
  }
1020
+ declare const RESOLVED_FONT_BRAND: unique symbol;
649
1021
  /**
650
- * A font reduced to the values that identify it for fingerprinting.
1022
+ * A face that passed admission: the bytes are present, within limits, hash-verified, and parse as
1023
+ * a font.
651
1024
  *
652
- * Includes the content `hash` and `faceIndex`, so two faces with the same family name but
653
- * different bytes fingerprint differently — which is what stops a cached measurement being reused
654
- * against a substituted face.
1025
+ * Branded, so a `ResolvedFont` cannot be constructed by an object literal. Holding one is proof
1026
+ * the checks ran — which is what lets shaping skip re-validating on every call.
655
1027
  */
656
- interface FontFingerprintInputs {
657
- readonly identity: string;
1028
+ interface ResolvedFont {
1029
+ readonly [RESOLVED_FONT_BRAND]: true;
658
1030
  readonly id: string;
659
- readonly family: string;
1031
+ readonly identity: string;
660
1032
  readonly request: FontRequest;
1033
+ readonly family: string;
1034
+ /** Owned byte length, available without creating a defensive byte copy. */
1035
+ readonly byteLength: number;
1036
+ readonly bytes: Uint8Array;
661
1037
  readonly hash: string;
662
1038
  readonly faceIndex: number;
663
- readonly byteLength: number;
664
1039
  readonly substitution: FontSubstitution | null;
665
1040
  }
666
1041
  /**
667
- * A {@link ShapingEnvironment} reduced to comparable values.
1042
+ * Largest single face this engine will ever admit, whatever a caller configures.
668
1043
  *
669
- * Records and axis maps become SORTED entry arrays, because two environments differing only in
670
- * key insertion order must fingerprint the same — otherwise a cache would miss on a difference
671
- * that changes no glyph.
1044
+ * A CEILING, not a default: a host may set a smaller `maxFontBytes`, but nothing can raise it
1045
+ * past this. Font bytes come from files, and an unbounded face is a memory-exhaustion vector.
672
1046
  */
673
- interface ShapingEnvironmentFingerprintInputs {
674
- readonly font: FontFingerprintInputs;
675
- readonly variationAxes: readonly (readonly [string, number])[];
676
- readonly shapingLibrary: VersionedShapingLibrary;
677
- readonly unicodeDataVersion: string;
678
- readonly normalization: NormalizationPolicy;
679
- readonly script: string;
680
- readonly language: string;
681
- readonly direction: TextDirection;
682
- readonly features: readonly (readonly [string, number])[];
683
- readonly fallbackOrder: readonly FontFingerprintInputs[];
684
- readonly fixedPointScale: number;
685
- readonly roundingMode: FixedPointRoundingMode;
686
- }
1047
+ declare const HARD_MAX_FONT_BYTES: number;
1048
+ /** Most faces one snapshot may hold, whatever a caller configures. */
1049
+ declare const HARD_MAX_FONT_SOURCES = 256;
1050
+ /** Most bytes all admitted faces may total, whatever a caller configures. */
1051
+ declare const HARD_MAX_AGGREGATE_FONT_BYTES: number;
687
1052
  /**
688
- * Validate and freeze a shaping environment.
689
- *
690
- * Checks every field that could silently corrupt a measurement: OpenType tags must be four ASCII
691
- * bytes, script and language must be non-blank and control-character free, fonts must already be
692
- * validated. Throws rather than coercing — a bad tag that shapes anyway produces a document that
693
- * measures wrong everywhere and looks fine.
1053
+ * Why a face was not admitted.
694
1054
  *
695
- * @throws TypeError on a malformed tag, name, or axis value.
1055
+ * `forbidden` and `hashMismatch` are adversarial signals rather than ordinary failures: the first
1056
+ * is a face the host declared off-limits, the second is bytes that are not what their source
1057
+ * claimed.
696
1058
  */
697
- declare const createShapingEnvironment: (input: ShapingEnvironmentInput) => ShapingEnvironment;
1059
+ type FontResolutionErrorCode = 'missing' | 'forbidden' | 'overLimit' | 'malformed' | 'hashMismatch';
698
1060
  /**
699
- * Reduce an environment to its comparable form, with records sorted so key order cannot affect
700
- * the result.
1061
+ * A face that could not be admitted, carrying whatever evidence the refusal produced.
1062
+ *
1063
+ * RETURNED rather than thrown by `FontResourceSnapshot.resolve`, because a missing face is an
1064
+ * ordinary condition — layout falls back and carries on. It extends `Error` so a caller that
1065
+ * would rather throw can.
701
1066
  */
702
- declare const shapingEnvironmentFingerprintInputs: (input: ShapingEnvironmentInput) => ShapingEnvironmentFingerprintInputs;
703
- /** Canonical serialization of every shaping variable, including byte hash and provenance. */
704
- declare const shapingEnvironmentFingerprint: (environment: ShapingEnvironmentInput) => string;
1067
+ declare class FontResolutionError extends Error {
1068
+ readonly name = "FontResolutionError";
1069
+ readonly request: FontRequest;
1070
+ readonly code: FontResolutionErrorCode;
1071
+ readonly limit?: number;
1072
+ readonly actual?: number;
1073
+ readonly diagnostic?: string;
1074
+ readonly expectedHash?: string;
1075
+ readonly actualHash?: string;
1076
+ constructor(code: FontResolutionErrorCode, request: FontRequest, details?: {
1077
+ readonly limit?: number;
1078
+ readonly actual?: number;
1079
+ readonly diagnostic?: string;
1080
+ readonly expectedHash?: string;
1081
+ readonly actualHash?: string;
1082
+ });
1083
+ }
705
1084
  /**
706
- * Validate and freeze a shaped run against the environment that produced it.
707
- *
708
- * Checks the internal consistency a shaper must satisfy: direction matches the environment,
709
- * cluster ranges tile the text without gaps or overlap, glyph ranges stay in bounds, font spans
710
- * cover every glyph, and caret edges are monotonic. A shaper that violates any of these produces
711
- * a caret that lands in the wrong place, which is far harder to diagnose downstream than here.
1085
+ * One face offered to a snapshot, before admission.
712
1086
  *
713
- * @throws TypeError when the run and environment disagree, or the run is internally inconsistent.
1087
+ * `hash` is checked against the bytes, so a source cannot claim a face it did not supply. Setting
1088
+ * `availability` to `forbidden` declares a face that exists but must not be used, which resolves
1089
+ * as a typed refusal rather than as "missing".
714
1090
  */
715
- declare const createShapedRun: (input: ShapedRun, environmentInput: ShapingEnvironmentInput) => ShapedRun;
1091
+ interface FontResourceDefinition {
1092
+ readonly request: FontRequest;
1093
+ readonly id: string;
1094
+ readonly bytes: Uint8Array;
1095
+ readonly hash: string;
1096
+ readonly faceIndex: number;
1097
+ readonly availability?: 'available' | 'forbidden';
1098
+ }
716
1099
  /**
717
- * Reduce a shaped run to its comparable form, validating it on the way through.
1100
+ * A host-declared redirect: requests for `from` resolve to `to`.
718
1101
  *
719
- * What the D9 determinism oracles compare: two shaping runs of the same text in the same
720
- * environment must produce byte-identical structures here.
1102
+ * How a metric-compatible substitute is wired in — a document naming Calibri resolves to Carlito
1103
+ * without the document being rewritten.
721
1104
  */
722
- declare const shapedRunComparatorInputs: (input: ShapedRun, environment: ShapingEnvironmentInput) => ShapedRunComparatorInputs;
723
-
1105
+ interface DeclaredFontSubstitution {
1106
+ readonly from: FontRequest;
1107
+ readonly to: FontRequest;
1108
+ readonly lineMetrics?: {
1109
+ readonly heightEm: number;
1110
+ readonly baselineEm: number;
1111
+ };
1112
+ }
1113
+ /** Whether bytes parse as a usable font, with a diagnostic when they do not. */
1114
+ type FontValidationResult = {
1115
+ readonly valid: true;
1116
+ } | {
1117
+ readonly valid: false;
1118
+ readonly diagnostic: string;
1119
+ };
724
1120
  /**
725
- * Whether a paragraph must start a new page (`w:pageBreakBefore`).
1121
+ * The injected check that bytes really are a font.
726
1122
  *
727
- * LAST WINS, like every other toggle read off the cascade (`paragraphKeeps` does the same
728
- * for `w:keepNext`). An any-wins `.some()` cannot be switched off: a Chapter or Heading style
729
- * carries `w:pageBreakBefore`, and Word writes `w:val="0"` on the one instance whose author
730
- * unchecked the box — that paragraph still broke, so the document grew a blank page and every
731
- * page number after it was wrong.
1123
+ * Injected because it is the shaper that knows — HarfBuzz can open a face and read its tables,
1124
+ * and this layer must not duplicate that judgement. Every byte reaching it is file input.
1125
+ */
1126
+ type FontByteValidator = (bytes: Uint8Array, faceIndex: number) => FontValidationResult;
1127
+ /**
1128
+ * An immutable set of admitted faces, and the only way to reach one.
732
1129
  *
733
- * An absent `w:val` is on (§17.17.4), and the off vocabulary is the whole of it — `off` is a
734
- * spelling too, which {@link isOn} beside this already accepts.
1130
+ * `epoch` identifies the snapshot: fonts change by REPLACING it, never by mutation, so a layout
1131
+ * pass holds one snapshot for its whole run and cannot observe a face appearing or vanishing
1132
+ * midway.
735
1133
  */
736
- declare function paragraphBreaksBefore(props: readonly OoxmlProperty[]): boolean;
1134
+ interface FontResourceSnapshot {
1135
+ readonly epoch: number;
1136
+ /** The admitted face, or a typed refusal. Never throws. */
1137
+ resolve(request: FontRequest): ResolvedFont | FontResolutionError;
1138
+ }
737
1139
  /**
738
- * Soft ceiling matching the spike's resolved-style limit (31_680 twips ≈ 22"). Beyond
739
- * that an attacker-authored spacing would push pagination into pathological page counts.
1140
+ * How a snapshot is built: which faces, under what limits, validated how.
1141
+ *
1142
+ * `maxFontBytes` is clamped to {@link HARD_MAX_FONT_BYTES} — a caller may tighten the budget but
1143
+ * never widen it past the engine's own ceiling.
740
1144
  */
741
- declare const MAX_PARAGRAPH_SPACING_PT: number;
742
- /** Soft ceiling on border width (96 eighths = 12pt). Word's UI tops out well below this. */
743
- declare const MAX_BORDER_WIDTH_PT = 12;
744
- /** Soft ceiling on border-to-text gap (`w:space`, already in points). */
745
- declare const MAX_BORDER_SPACE_PT = 3168;
1145
+ interface FontResourceSnapshotOptions {
1146
+ readonly epoch: number;
1147
+ readonly maxFontBytes: number;
1148
+ readonly resources: readonly FontResourceDefinition[];
1149
+ readonly substitutions?: readonly DeclaredFontSubstitution[];
1150
+ readonly validateFont: FontByteValidator;
1151
+ readonly instrumentation?: FontResourceInstrumentation;
1152
+ }
746
1153
  /**
747
- * A paragraph's resolved space before and after, in points.
1154
+ * Optional counters for the operations font admission is expected to do RARELY.
748
1155
  *
749
- * Already collapsed against `w:contextualSpacing`, so adjacent same-style paragraphs that suppress
750
- * their gap arrive here with it removed rather than leaving that to whoever stacks them.
1156
+ * Exists so tests can assert the absence of work: hashing and byte-copying a 64 MB face on every
1157
+ * resolve would not be visible in output, only in a stalled document, so the checks assert these
1158
+ * fire once rather than per call.
751
1159
  */
752
- interface ParagraphSpacing {
753
- /** `w:spacing/@before`, in points. */
754
- readonly before: number;
755
- /** `w:spacing/@after`, in points. */
756
- readonly after: number;
1160
+ interface FontResourceInstrumentation {
1161
+ readonly onOwnedByteCopy?: () => void;
1162
+ readonly onHash?: () => void;
1163
+ readonly onTableScan?: () => void;
1164
+ readonly onAdmission?: () => void;
757
1165
  }
758
1166
  /**
759
- * The gap Word substitutes when `w:beforeAutospacing` / `w:afterAutospacing` is on
760
- * (ECMA-376 §17.3.1.33, the `w:spacing` clause both attributes belong to).
1167
+ * The canonical string identifying one face request.
761
1168
  *
762
- * The attribute means "the consumer decides", and the authored `@before` / `@after` beside it
763
- * is IGNORED rather than used as the value. Word's answer is HTML's default `<p>` margin,
764
- * 14pt, which is what a document round-tripped through Word's HTML filter carries — and this
765
- * one is everywhere, because Word writes `w:before="100" w:beforeAutospacing="1"` for it. Reading
766
- * only the literal 100 twips lays every such paragraph out 9pt tight, which moves page breaks.
1169
+ * Case- and whitespace-normalized, so `"Times New Roman"` and `"times new roman"` are one key —
1170
+ * a document may name a family either way and both must reach the same face.
767
1171
  */
768
- declare const AUTO_PARAGRAPH_SPACING_PT = 14;
1172
+ declare const fontRequestKey: (request: FontRequest) => string;
1173
+ /** Bounded minimum sfnt/TTC check; Task 4 supplies full parser-backed validation. */
1174
+ declare const boundedStructuralFontValidator: FontByteValidator;
769
1175
  /**
770
- * Where a paragraph sits, for the contexts in which Word's auto spacing resolves to 0
771
- * instead of {@link AUTO_PARAGRAPH_SPACING_PT}.
772
- *
773
- * This resolves the interior list-item value. Body layout restores each outer list margin
774
- * in `resolveListAutoSpacing`, where neighboring blocks are available. A caller that says
775
- * nothing gets the body answer.
1176
+ * Admit a set of faces and return the immutable snapshot layout resolves against.
776
1177
  *
777
- * A TABLE CELL is not such a context. Measured on a captured control at 10pt, where the
778
- * line pitch is 11.52pt: the reference puts 26.16pt between two paragraphs in the body with
779
- * auto spacing on, and the SAME 26.16pt between two paragraphs inside a cell. With an empty
780
- * paragraph between them it is 52.32, exactly twice. Reading it as 0 in a cell lays every
781
- * such paragraph 13.92pt tight, which is enough to pull a signature block back onto the
782
- * previous page. See `.cache/pdf/claude-autospacing/`.
1178
+ * Admission is the trust boundary for font bytes: counts and sizes are checked against the hard
1179
+ * ceilings, each face's hash is re-derived and compared, and the bytes are handed to the injected
1180
+ * validator. A face failing any of these is recorded as a typed refusal rather than dropped, so
1181
+ * `resolve` can explain itself instead of answering "missing".
783
1182
  */
784
- interface ParagraphAutoSpacingContext {
785
- /** The paragraph participates in numbering (`w:numPr`), i.e. it is a list item. */
786
- readonly inList?: boolean;
787
- /**
788
- * The paragraph lives in a table cell. Kept because callers describe position with it and
789
- * list resolution reads it; it does NOT zero auto spacing.
790
- */
791
- readonly inTableCell?: boolean;
792
- /** Section grid pitch in points; no grid uses Word's fixed 12pt line unit. */
793
- readonly lineUnitPt?: number;
794
- /**
795
- * `w:doNotUseHTMLParagraphAutoSpacing` is on: automatic spacing outside a list resolves to
796
- * the fixed 5pt before and 10pt after instead of {@link AUTO_PARAGRAPH_SPACING_PT}.
797
- */
798
- readonly fixedAutoSpacing?: boolean;
799
- }
1183
+ declare const createFontResourceSnapshot: (options: FontResourceSnapshotOptions) => FontResourceSnapshot;
1184
+
1185
+ declare const FIXED_POINT: unique symbol;
1186
+ /** Fixed-point coordinates are safe integers in units declared by ShapingEnvironment.fixedPointScale. */
1187
+ type FixedPoint = number & {
1188
+ readonly [FIXED_POINT]: true;
1189
+ };
800
1190
  /**
801
- * Resolved line spacing (`w:spacing/@line` + `@lineRule`, ECMA-376 17.3.1.33).
1191
+ * Brand a safe integer as a {@link FixedPoint} coordinate.
802
1192
  *
803
- * `auto` is the interesting one: `@line` is 240ths of a line, so 240 is single, 360 is
804
- * one-and-a-half, 480 is double — and Word's own Normal style since 2013 is 259, i.e.
805
- * 1.08. A document laid out at a flat single spacing is ~8% tight on EVERY line, which
806
- * moves every page break, so this is not a cosmetic detail.
1193
+ * Fixed point rather than float throughout shaping so that two runs shaped identically compare
1194
+ * EQUAL — float accumulation would make the same text measure differently depending on how it was
1195
+ * split, and pagination is decided on those measurements.
807
1196
  *
808
- * `exact` fixes the line box at `@line` twips and lets tall glyphs clip, the way Word
809
- * does. `atLeast` uses it as a floor.
1197
+ * @throws RangeError when the value is not a safe integer.
810
1198
  */
811
- type LineSpacingRule = 'auto' | 'exact' | 'atLeast';
1199
+ declare const fixedPoint: (value: number) => FixedPoint;
1200
+ /** Which way a run reads. The parity projection of its bidi embedding level. */
1201
+ type TextDirection = 'ltr' | 'rtl';
1202
+ /** How fixed-point conversion breaks ties. Part of the shaping fingerprint. */
1203
+ type FixedPointRoundingMode = 'halfAwayFromZero' | 'halfToEven' | 'towardZero';
1204
+ /** Which Unicode normalization is applied before shaping, if any. */
1205
+ type NormalizationPolicy = 'none' | 'NFC' | 'NFD' | 'NFKC' | 'NFKD';
812
1206
  /**
813
- * Resolved line spacing: the rule, and the value it applies.
1207
+ * The shaping library and its exact version.
814
1208
  *
815
- * `value` means different things per rule — 240ths of a line under `auto`, points under `exact`
816
- * and `atLeast` — which is why the two travel together and neither is useful alone.
1209
+ * Versioned because a library upgrade can change glyph positioning, and a cached measurement
1210
+ * taken under the old one must not be reused under the new one.
817
1211
  */
818
- interface ParagraphLineSpacing {
819
- readonly rule: LineSpacingRule;
820
- /** `auto`: the 240ths-of-a-line multiplier numerator. Otherwise points. */
821
- readonly value: number;
822
- /** Legacy noExtraLineSpacing: retain the natural baseline within an exact-height box. */
823
- readonly preserveExactBaseline?: true;
824
- /**
825
- * Active section line-grid pitch in points (`w:docGrid/@w:linePitch`). Present only when
826
- * the paragraph snaps to the grid; only with `auto`. See `line-grid.ts`.
827
- */
828
- readonly gridPitch?: number;
1212
+ interface VersionedShapingLibrary {
1213
+ readonly name: string;
1214
+ readonly version: string;
829
1215
  }
830
- /** Single spacing: what a paragraph that says nothing gets. */
831
- declare const SINGLE_LINE_SPACING: ParagraphLineSpacing;
832
1216
  /**
833
- * One resolved `w:pBdr` edge: its style, colour, thickness and gap.
1217
+ * Everything that determines how text shapes — the complete input to a
1218
+ * {@link ShapingEnvironment}.
834
1219
  *
835
- * `widthPt` and `spacePt` are already converted and CLAMPED — both come from a file, and an
836
- * unbounded border width becomes a layout dimension.
1220
+ * Exhaustive on purpose. Any field that could change a glyph's position belongs here, because the
1221
+ * environment's fingerprint is what decides whether a cached shaped run may be reused.
837
1222
  */
838
- interface ParagraphBorderEdge {
839
- /** Authored `ST_Border` value (`single`, `dashed`, …). */
840
- readonly val: string;
841
- /** RRGGBB, or null when auto/missing (paint defaults to black). */
842
- readonly color: string | null;
843
- /** Border thickness in points (`w:sz` is eighths of a point). */
844
- readonly widthPt: number;
845
- /** Gap from text to the rule, in points (`w:space`). */
846
- readonly spacePt: number;
1223
+ interface ShapingEnvironmentInput {
1224
+ readonly font: ResolvedFont;
1225
+ readonly variationAxes: Readonly<Record<string, number>>;
1226
+ readonly shapingLibrary: VersionedShapingLibrary;
1227
+ readonly unicodeDataVersion: string;
1228
+ readonly normalization: NormalizationPolicy;
1229
+ readonly script: string;
1230
+ readonly language: string;
1231
+ readonly direction: TextDirection;
1232
+ readonly features: Readonly<Record<string, number>>;
1233
+ readonly fallbackOrder: readonly ResolvedFont[];
1234
+ readonly fixedPointScale: number;
1235
+ readonly roundingMode: FixedPointRoundingMode;
1236
+ }
1237
+ /**
1238
+ * A validated {@link ShapingEnvironmentInput} — build one with `createShapingEnvironment`.
1239
+ *
1240
+ * Structurally identical to its input, but the nominal distinction is the point: holding one
1241
+ * means the tags, axes and fonts inside it have already been checked.
1242
+ */
1243
+ interface ShapingEnvironment extends ShapingEnvironmentInput {
1244
+ }
1245
+ /** One shaping call: the text, its size, its bidi level, and the environment to shape it in. */
1246
+ interface ShapeInput {
1247
+ readonly text: string;
1248
+ readonly fontSizeHalfPoints: number;
1249
+ /** Exact UAX #9 embedding/isolate level; direction is its parity projection. */
1250
+ readonly bidiLevel: number;
1251
+ readonly environment: ShapingEnvironment;
847
1252
  /**
848
- * `w:shadow` — Word offsets a drop shadow behind the rule.
849
- *
850
- * Present only when authored true, so an edge that says nothing keeps the shape earlier
851
- * fixtures assert. Resolved and carried; drawing it is deferred.
1253
+ * Logical text around `text` that the shaper reads for contextual forms but never
1254
+ * shapes: HarfBuzz pre- and post-context. A word split across two formatting runs joins
1255
+ * across the split only when each half sees the other's letters. At most
1256
+ * {@link MAX_SHAPING_CONTEXT} UTF-16 units each; glyphs and clusters cover `text` alone.
852
1257
  */
853
- readonly shadow?: true;
1258
+ readonly context?: ShapingContext;
854
1259
  }
855
- /** The six `CT_PBdr` children, in schema order (ECMA-376 §17.3.1.24). */
856
- declare const PARAGRAPH_BORDER_SIDES: readonly ['top', 'left', 'bottom', 'right', 'between', 'bar'];
1260
+ /** Pre- and post-context for one shaping call. See {@link ShapeInput.context}. @public */
1261
+ interface ShapingContext {
1262
+ readonly before: string;
1263
+ readonly after: string;
1264
+ }
1265
+ /** Longest context on either side, in UTF-16 units. Joining needs only the nearest letters. @public */
1266
+ declare const MAX_SHAPING_CONTEXT = 16;
857
1267
  /**
858
- * Which of the six `CT_PBdr` edges.
1268
+ * One positioned glyph.
859
1269
  *
860
- * Four are physical box edges; `between` and `bar` are group-relative, drawn only where
861
- * consecutive paragraphs share a border definition.
1270
+ * `id` is a glyph index in its FACE, not a character — a ligature is one glyph spanning several
1271
+ * characters, and a single character may produce several glyphs. Use `cluster` to get back to
1272
+ * text.
862
1273
  */
863
- type ParagraphBorderSide = (typeof PARAGRAPH_BORDER_SIDES)[number];
1274
+ interface ShapedGlyph {
1275
+ readonly id: number;
1276
+ /** Optional synthetic glyph-size factor; positions and advances already include it. */
1277
+ readonly drawScale?: number;
1278
+ /** UTF-16 text offset identifying the cluster that produced this glyph. */
1279
+ readonly cluster: number;
1280
+ /** Pen origin before this glyph's shaping offsets, in fixed-point run coordinates. */
1281
+ readonly originX: FixedPoint;
1282
+ readonly originY: FixedPoint;
1283
+ readonly advanceX: FixedPoint;
1284
+ readonly advanceY: FixedPoint;
1285
+ readonly offsetX: FixedPoint;
1286
+ readonly offsetY: FixedPoint;
1287
+ /** Exact monochrome outline returned by the admitted HarfBuzz face. */
1288
+ readonly outline: GlyphOutline;
1289
+ }
1290
+ /** A glyph's outline as SVG path data, in font design units. */
1291
+ interface GlyphOutline {
1292
+ readonly path: string;
1293
+ /** Design units per em — divide by this to scale the path to a point size. */
1294
+ readonly unitsPerEm: number;
1295
+ }
864
1296
  /**
865
- * A paragraph's resolved `w:pBdr` (ECMA-376 §17.3.1.24).
1297
+ * One cluster: the smallest indivisible text-to-glyph correspondence.
866
1298
  *
867
- * `top`/`left`/`bottom`/`right` are the four physical edges of the box. The other two are
868
- * group-relative: `between` draws at a boundary INSIDE a run of consecutive paragraphs whose
869
- * border settings are identical, and `bar` is the vertical change-bar rule beside the
870
- * paragraph, drawn whether or not the paragraph groups with its neighbours.
1299
+ * The unit the CARET moves by. A cluster may be several characters (a ligature) or several glyphs
1300
+ * (a decomposed mark), so neither a character index nor a glyph index is a valid caret position —
1301
+ * `caretEdges` is, and it includes both endpoints.
871
1302
  */
872
- interface ParagraphBorders {
873
- readonly top?: ParagraphBorderEdge;
874
- readonly left?: ParagraphBorderEdge;
875
- readonly bottom?: ParagraphBorderEdge;
876
- readonly right?: ParagraphBorderEdge;
877
- readonly between?: ParagraphBorderEdge;
878
- readonly bar?: ParagraphBorderEdge;
1303
+ interface ShapedCluster {
1304
+ /** Half-open logical UTF-16 range in ShapedRun.text. */
1305
+ readonly textStart: number;
1306
+ readonly textEnd: number;
1307
+ /** Half-open visual glyph range in ShapedRun.glyphs. */
1308
+ readonly glyphStart: number;
1309
+ readonly glyphEnd: number;
1310
+ readonly advance: FixedPoint;
1311
+ /** Fixed-point edges from this cluster's visual origin, including both endpoints. */
1312
+ readonly caretEdges: readonly FixedPoint[];
1313
+ /** Index into ShapedRun.fontSpans, preserving the exact fallback choice. */
1314
+ readonly fontSpan: number;
1315
+ }
1316
+ /** A run's vertical metrics, from the face that shaped it. Drives line height and baseline. */
1317
+ interface ShapedVerticalMetrics {
1318
+ readonly ascent: FixedPoint;
1319
+ readonly descent: FixedPoint;
1320
+ readonly lineGap: FixedPoint;
879
1321
  }
880
1322
  /**
881
- * Resolve `w:spacing` before/after from flat paragraph properties.
882
- *
883
- * Line spacing (`w:line` / `w:lineRule`) is a separate concern — it changes measured line
884
- * height, not the gap between paragraphs — and is not resolved here.
1323
+ * A stretch of glyphs that came from ONE face.
885
1324
  *
886
- * `w:beforeAutospacing` / `w:afterAutospacing` REPLACE the authored measurement on their own
887
- * side rather than adding to it; see {@link AUTO_PARAGRAPH_SPACING_PT}.
1325
+ * A run whose text needed fallback has several of these. Recording the exact face per span is
1326
+ * what lets a re-shape reproduce the same result rather than re-running fallback selection and
1327
+ * possibly choosing differently.
888
1328
  */
889
- declare function paragraphSpacing(props: readonly OoxmlProperty[], context?: ParagraphAutoSpacingContext): ParagraphSpacing;
1329
+ interface ShapedFontSpan {
1330
+ readonly glyphStart: number;
1331
+ readonly glyphEnd: number;
1332
+ readonly font: ResolvedFont;
1333
+ /** null denotes the primary font; otherwise this is the environment fallback-order index. */
1334
+ readonly fallbackIndex: number | null;
1335
+ }
890
1336
  /**
891
- * Resolve `w:line` / `w:lineRule` from flat paragraph properties.
1337
+ * One shaped run: text turned into positioned glyphs, with everything needed to measure it, paint
1338
+ * it, and put a caret in it.
892
1339
  *
893
- * Merged per attribute for the same reason as before/after: `w:spacing` is one element
894
- * carrying independent attributes, and a style that states only `@line` must not reset the
895
- * rule an earlier entry in the cascade set.
1340
+ * The engine's measurement unit. Layout never measures characters — it measures these.
896
1341
  */
897
- declare function paragraphLineSpacing(props: readonly OoxmlProperty[]): ParagraphLineSpacing;
1342
+ interface ShapedRun {
1343
+ readonly text: string;
1344
+ readonly direction: TextDirection;
1345
+ readonly bidiLevel: number;
1346
+ readonly glyphs: readonly ShapedGlyph[];
1347
+ readonly clusters: readonly ShapedCluster[];
1348
+ readonly fontSpans: readonly ShapedFontSpan[];
1349
+ readonly metrics: ShapedVerticalMetrics;
1350
+ /**
1351
+ * The same horizontal advances as `glyphs[i].advanceX`, in the same fixed-point units, but
1352
+ * BEFORE the per-glyph rounding to the fixed-point grid. Parallel to `glyphs`.
1353
+ *
1354
+ * Measurement and line breaking read `advanceX` and must keep doing so: pagination is decided
1355
+ * on those numbers, and two runs shaped identically have to compare equal. A painter that
1356
+ * gives every glyph its own absolute position sums the advances instead, and a sum of ROUNDED
1357
+ * advances drifts by up to half a fixed-point unit per glyph — an error that only grows along
1358
+ * a line. Summing these and rounding once, at the position actually written, does not.
1359
+ *
1360
+ * Absent on runs an assembly path cannot state exactly; a reader falls back to `originX`.
1361
+ */
1362
+ readonly exactAdvancesX?: readonly number[];
1363
+ }
898
1364
  /**
899
- * Apply resolved line spacing to a line's natural (glyph-derived) box.
900
- *
901
- * `auto` places its extra BELOW the line — the last line's multiple spacing still separates
902
- * it from the next paragraph. Putting that delta above inverted cover-page rhythm:
903
- * `w:line="460"` on "between" opened a large gap above the word and almost none before
904
- * "MERIDIAN".
905
- *
906
- * `atLeast` does the OPPOSITE: the box grows upward and the glyphs sit on its floor. A
907
- * captured control settles it — Times New Roman 12 pt at `w:line="360" w:lineRule="atLeast"`
908
- * puts the reference's baseline at 15.36 pt, which is `18 - descent` snapped to the device
909
- * grid, where treating it like `auto` leaves the baseline at 11.28 and the text 4.08 pt too
910
- * high. `w:line="240" atLeast` is below the natural line, falls through to the natural
911
- * height, and is unaffected. See `.cache/pdf/claude-linerule/`.
912
- *
913
- * Exact-height boxes place their baseline at 80% of the height; the legacy
914
- * noExtraLineSpacing switch instead preserves the face baseline within the box.
1365
+ * A {@link ShapedRun} reduced to the fields two shaping results must agree on to be considered
1366
+ * identical.
915
1367
  *
916
- * An `auto` or `atLeast` line of a snapping paragraph under an active line grid takes whole
917
- * pitches instead ({@link gridLineBox}); `trailing` then names the box below the glyphs.
1368
+ * Fonts appear as {@link FontFingerprintInputs} rather than whole `ResolvedFont` objects, so the
1369
+ * comparison is over VALUES and does not depend on object identity — which is what makes it work
1370
+ * across a reload or a worker boundary.
918
1371
  */
919
- declare function applyLineSpacing(spacing: ParagraphLineSpacing, naturalHeight: number, naturalBaseline: number): {
920
- height: number;
921
- baseline: number;
922
- trailing?: number;
923
- };
1372
+ interface ShapedRunComparatorInputs {
1373
+ readonly text: string;
1374
+ readonly direction: TextDirection;
1375
+ readonly script: string;
1376
+ readonly language: string;
1377
+ readonly bidiLevel: number;
1378
+ readonly glyphs: readonly ShapedGlyph[];
1379
+ readonly clusters: readonly ShapedCluster[];
1380
+ readonly fontSpans: readonly {
1381
+ readonly glyphStart: number;
1382
+ readonly glyphEnd: number;
1383
+ readonly fallbackIndex: number | null;
1384
+ readonly font: FontFingerprintInputs;
1385
+ }[];
1386
+ readonly metrics: ShapedVerticalMetrics;
1387
+ }
924
1388
  /**
925
- * `w:contextualSpacing` (17.3.1.9): drop before/after between paragraphs of the SAME
926
- * style. Word's built-in `ListParagraph` sets it, so every list authored in Word gets a
927
- * paragraph gap between items without this.
1389
+ * The one thing layout needs from a shaping backend.
1390
+ *
1391
+ * Injected rather than imported, which is what keeps layout DOM-free and testable: a fixed-metric
1392
+ * shaper measures deterministically in a test, HarfBuzz measures for real in a browser, and
1393
+ * layout cannot tell the difference.
928
1394
  */
929
- declare function paragraphContextualSpacing(props: readonly OoxmlProperty[]): boolean;
1395
+ interface TextShaper {
1396
+ shape(input: ShapeInput): ShapedRun;
1397
+ }
930
1398
  /**
931
- * Resolve `w:pBdr` from the paragraph-properties node.
1399
+ * A font reduced to the values that identify it for fingerprinting.
932
1400
  *
933
- * Nested — every edge is a child of `pBdr`, not an attribute — so this reads the typed tree
934
- * rather than the flattened `OoxmlProperty[]` bag `propertiesOf` builds for leaf props.
1401
+ * Includes the content `hash` and `faceIndex`, so two faces with the same family name but
1402
+ * different bytes fingerprint differently — which is what stops a cached measurement being reused
1403
+ * against a substituted face.
935
1404
  */
936
- declare function paragraphBorders(pPr: OoxmlNode | undefined): ParagraphBorders;
1405
+ interface FontFingerprintInputs {
1406
+ readonly identity: string;
1407
+ readonly id: string;
1408
+ readonly family: string;
1409
+ readonly request: FontRequest;
1410
+ readonly hash: string;
1411
+ readonly faceIndex: number;
1412
+ readonly byteLength: number;
1413
+ readonly substitution: FontSubstitution | null;
1414
+ }
937
1415
  /**
938
- * `w:pBdr` after the style cascade: a later `w:pBdr` replaces an earlier one WHOLESALE.
1416
+ * A {@link ShapingEnvironment} reduced to comparable values.
939
1417
  *
940
- * Word does not merge edges across the cascade. A style that states only `w:bottom` discards
941
- * the box its `basedOn` ancestor declared, so folding edge by edge would leave a lone
942
- * underline surrounded by a box no one authored. Absence inherits; `nil`/`none` clear.
1418
+ * Records and axis maps become SORTED entry arrays, because two environments differing only in
1419
+ * key insertion order must fingerprint the same — otherwise a cache would miss on a difference
1420
+ * that changes no glyph.
943
1421
  */
944
- declare function cascadedParagraphBorders(paragraphPropertyNodes: readonly OoxmlNode[]): ParagraphBorders;
1422
+ interface ShapingEnvironmentFingerprintInputs {
1423
+ readonly font: FontFingerprintInputs;
1424
+ readonly variationAxes: readonly (readonly [string, number])[];
1425
+ readonly shapingLibrary: VersionedShapingLibrary;
1426
+ readonly unicodeDataVersion: string;
1427
+ readonly normalization: NormalizationPolicy;
1428
+ readonly script: string;
1429
+ readonly language: string;
1430
+ readonly direction: TextDirection;
1431
+ readonly features: readonly (readonly [string, number])[];
1432
+ readonly fallbackOrder: readonly FontFingerprintInputs[];
1433
+ readonly fixedPointScale: number;
1434
+ readonly roundingMode: FixedPointRoundingMode;
1435
+ }
945
1436
  /**
946
- * Visual stroke thickness layout publishes for one edge (points).
1437
+ * Validate and freeze a shaping environment.
947
1438
  *
948
- * Compound `ST_Border` values (`double`, …) use the shared inflated band so a thin
949
- * `w:sz="3"` double still occupies a visible double-line box — matching table borders.
1439
+ * Checks every field that could silently corrupt a measurement: OpenType tags must be four ASCII
1440
+ * bytes, script and language must be non-blank and control-character free, fonts must already be
1441
+ * validated. Throws rather than coercing — a bad tag that shapes anyway produces a document that
1442
+ * measures wrong everywhere and looks fine.
1443
+ *
1444
+ * @throws TypeError on a malformed tag, name, or axis value.
950
1445
  */
951
- declare function paragraphBorderStrokeWidthPt(edge: ParagraphBorderEdge): number;
1446
+ declare const createShapingEnvironment: (input: ShapingEnvironmentInput) => ShapingEnvironment;
952
1447
  /**
953
- * Extent one border edge occupies away from the text it decorates: gap plus rule, in points.
954
- *
955
- * Vertically that is flow height — a top rule pushes the first line down, a bottom rule holds
956
- * the page open below the last one — so pagination has to see it. Horizontally it is
957
- * publish-only: Word draws left/right paragraph rules OUTSIDE the text column and never
958
- * re-breaks the lines, which is why adding a box to a paragraph in Word does not reflow it.
1448
+ * Reduce an environment to its comparable form, with records sorted so key order cannot affect
1449
+ * the result.
959
1450
  */
960
- declare function paragraphBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;
961
- /** Vertical extent a bottom border adds below the last line (gap + rule). */
962
- declare function bottomBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;
1451
+ declare const shapingEnvironmentFingerprintInputs: (input: ShapingEnvironmentInput) => ShapingEnvironmentFingerprintInputs;
1452
+ /** Canonical serialization of every shaping variable, including byte hash and provenance. */
1453
+ declare const shapingEnvironmentFingerprint: (environment: ShapingEnvironmentInput) => string;
963
1454
  /**
964
- * Identity of a paragraph's border set, for the `w:between` group rule.
1455
+ * Validate and freeze a shaped run against the environment that produced it.
965
1456
  *
966
- * Word treats consecutive paragraphs whose border settings are IDENTICAL as ONE bordered
967
- * block: the top rule draws above the first, the bottom rule below the last, and each
968
- * interior boundary gets `w:between` or nothing (§17.3.1.24). That is why applying a box to
969
- * three selected paragraphs in Word draws one box and not three.
1457
+ * Checks the internal consistency a shaper must satisfy: direction matches the environment,
1458
+ * cluster ranges tile the text without gaps or overlap, glyph ranges stay in bounds, font spans
1459
+ * cover every glyph, and caret edges are monotonic. A shaper that violates any of these produces
1460
+ * a caret that lands in the wrong place, which is far harder to diagnose downstream than here.
970
1461
  *
971
- * Empty string means "no borders", which never groups with anything.
972
- */
973
- declare function paragraphBordersFingerprint(borders: ParagraphBorders): string;
974
- /**
975
- * Gap to insert before a paragraph once the previous paragraph's `after` is already in the
976
- * flow cursor — Word takes the larger of the two rather than summing them.
1462
+ * @throws TypeError when the run and environment disagree, or the run is internally inconsistent.
977
1463
  */
978
- declare function collapsedSpaceBefore(before: number, previousAfter: number): number;
1464
+ declare const createShapedRun: (input: ShapedRun, environmentInput: ShapingEnvironmentInput) => ShapedRun;
979
1465
  /**
980
- * Applied before-spacing for placement (Word 2013+ / compat mode 15).
1466
+ * Reduce a shaped run to its comparable form, validating it on the way through.
981
1467
  *
982
- * Adjacent before/after still collapse to the larger gap, but before is dropped entirely when
983
- * the paragraph naturally moves to the top of a page mid-section. An explicit page-break-before
984
- * paragraph, or the first paragraph of a document/section, retains before. Callers publish this
985
- * applied value on the fragment so shading, borders,
986
- * selection, and paint share one geometry.
1468
+ * What the D9 determinism oracles compare: two shaping runs of the same text in the same
1469
+ * environment must produce byte-identical structures here.
987
1470
  */
988
- declare function appliedSpaceBefore(before: number, previousAfter: number, atTopOfPage: boolean, preserveAtPageStart: boolean): number;
1471
+ declare const shapedRunComparatorInputs: (input: ShapedRun, environment: ShapingEnvironmentInput) => ShapedRunComparatorInputs;
989
1472
 
990
1473
  /** `w:vertAlign` — script position, which also scales the run's effective size. */
991
1474
  type VerticalAlign = 'baseline' | 'superscript' | 'subscript';
@@ -2404,65 +2887,6 @@ interface EquationSpanRecord {
2404
2887
  /** Compose one bounded OMML projection into paint-ready point geometry. */
2405
2888
  declare function layoutEquation(projection: OmmlEquationProjection, measurer: TextMeasurer, style: ResolvedRunStyle): EquationSpanRecord;
2406
2889
 
2407
- /**
2408
- * The four physical sides of `CT_PageBorders`.
2409
- *
2410
- * Four, not the six of `w:pBdr`: `w:between` and `w:bar` are paragraph-group rules and the
2411
- * page has no analogue for either.
2412
- */
2413
- declare const PAGE_BORDER_SIDES: readonly ['top', 'left', 'bottom', 'right'];
2414
- /** Which of the four page-frame edges. */
2415
- type PageBorderSide = (typeof PAGE_BORDER_SIDES)[number];
2416
- /**
2417
- * `w:offsetFrom` (`ST_PgBorderOffset`) — what `w:space` on each edge is measured from.
2418
- *
2419
- * The schema default is `text`, NOT `page`. Word's own UI opens on "Edge of page", which is
2420
- * why the wrong default is easy to assume and expensive to hold: at `text` the rule sits
2421
- * `w:space` points outside the TEXT, so its distance from the sheet edge is the margin minus
2422
- * the space — a number that moves whenever the margins do.
2423
- */
2424
- type PageBorderOffsetFrom = 'page' | 'text';
2425
- /** `w:display` (`ST_PgBorderDisplay`) — which pages of the section carry the frame. */
2426
- type PageBorderDisplay = 'allPages' | 'firstPage' | 'notFirstPage';
2427
- /** `w:zOrder` (`ST_PgBorderZOrder`) — whether the frame paints over the text or under it. */
2428
- type PageBorderZOrder = 'front' | 'back';
2429
- /**
2430
- * One section's resolved `w:pgBorders`.
2431
- *
2432
- * Resolved, not raw: every attribute the file omitted is filled in with the SCHEMA default,
2433
- * so a consumer never has to know which of the three were authored. An edge is present only
2434
- * when it paints — `nil` / `none` and art borders are already gone (see {@link parsePageBorders}).
2435
- */
2436
- interface SectionPageBorders {
2437
- /** `w:offsetFrom`; absent attribute reads as `text` (§17.6.10). */
2438
- readonly offsetFrom: PageBorderOffsetFrom;
2439
- /** `w:display`; absent attribute reads as `allPages`. */
2440
- readonly display: PageBorderDisplay;
2441
- /** `w:zOrder`; absent attribute reads as `front`. */
2442
- readonly zOrder: PageBorderZOrder;
2443
- readonly top?: ParagraphBorderEdge;
2444
- readonly left?: ParagraphBorderEdge;
2445
- readonly bottom?: ParagraphBorderEdge;
2446
- readonly right?: ParagraphBorderEdge;
2447
- }
2448
- /**
2449
- * Parse `w:pgBorders` off one `w:sectPr`.
2450
- *
2451
- * Undefined when the element is absent AND when it paints nothing — every edge off, or every
2452
- * edge an art border. Unlike `w:pgNumType`, an empty-but-present element is not distinguished:
2453
- * these properties are a LAYOUT input, serialization re-emits the canonical tree, and a frame
2454
- * with no edges has exactly one meaning downstream.
2455
- */
2456
- declare function parsePageBorders(sectPr: OoxmlNode): SectionPageBorders | undefined;
2457
- /**
2458
- * Identity of one section's page frame, for incremental-layout context keys.
2459
- *
2460
- * A `w:pgBorders` edit changes nothing the flow measures — the frame is drawn beside the text,
2461
- * never through it — so no per-paragraph key moves and every reuse path would hand back the
2462
- * previous sheets with the previous frame. This token goes in the pass context so it does not.
2463
- */
2464
- declare function pageBordersFingerprint(borders: SectionPageBorders | undefined): string;
2465
-
2466
2890
  /** Published root story containing an artifact occurrence. @public */
2467
2891
  type SemanticArtifactRootStoryKind = 'body' | 'header' | 'footer' | 'footnote' | 'endnote' | 'note-separator';
2468
2892
  /** Exact story in which a review artifact's source anchor was laid out. @public */
@@ -2550,6 +2974,24 @@ interface SemanticCommentArtifactRecord {
2550
2974
  /** Exporter-neutral review artifact normalized by core. @public */
2551
2975
  type SemanticReviewArtifactRecord = SemanticTrackedChangeArtifactRecord | SemanticCommentArtifactRecord;
2552
2976
 
2977
+ /** Page geometry, in points. */
2978
+ interface PageGeometry {
2979
+ readonly width: number;
2980
+ readonly height: number;
2981
+ readonly margin: {
2982
+ readonly top: number;
2983
+ readonly right: number;
2984
+ readonly bottom: number;
2985
+ readonly left: number;
2986
+ };
2987
+ /** `w:pgMar/@header` — sheet edge to header top, in points. Defaults to 36 (720 twips). */
2988
+ readonly headerDistance?: number;
2989
+ /** `w:pgMar/@footer` — sheet edge to footer bottom, in points. Defaults to 36. */
2990
+ readonly footerDistance?: number;
2991
+ }
2992
+ /** US Letter with one-inch margins, in points. */
2993
+ declare const DEFAULT_PAGE_GEOMETRY: PageGeometry;
2994
+
2553
2995
  /** A half-open UTF-16 range inside one paragraph, addressed by its canonical node id. */
2554
2996
  interface SourceRange {
2555
2997
  readonly paragraphId: string;
@@ -2789,6 +3231,8 @@ interface StyleSpanRecord {
2789
3231
  interface LineRecord {
2790
3232
  /** An authored manual line break ends this line; optional display furniture can show ↵. */
2791
3233
  readonly manualBreakAfter?: true;
3234
+ /** An authored page or column break ends this line; optional furniture can label it. */
3235
+ readonly breakAfter?: 'page' | 'column';
2792
3236
  readonly id: string;
2793
3237
  readonly range: SourceRange;
2794
3238
  readonly spans: readonly StyleSpanRecord[];
@@ -3487,6 +3931,13 @@ interface SemanticLayout {
3487
3931
  * reuse paths that would otherwise return previous pages by identity with stale boundaries.
3488
3932
  */
3489
3933
  readonly controlContextToken?: string;
3934
+ /** Body section breaks in document order, each named by the section that FOLLOWS it. */
3935
+ readonly sectionBreaks?: readonly SectionBreakMarkRecord[];
3936
+ }
3937
+ /** The paragraph whose `w:sectPr` ends a section, and how the next section starts. */
3938
+ interface SectionBreakMarkRecord {
3939
+ readonly paragraphId: string;
3940
+ readonly kind: SectionBreakType;
3490
3941
  }
3491
3942
 
3492
3943
  /**
@@ -3528,5 +3979,5 @@ interface TextMeasurer {
3528
3979
  };
3529
3980
  }
3530
3981
 
3531
- export { PAGE_BORDER_SIDES as a$, AUTO_PARAGRAPH_SPACING_PT as a4, HARD_MAX_AGGREGATE_FONT_BYTES as aG, HARD_MAX_FONT_BYTES as aH, HARD_MAX_FONT_SOURCES as aI, MAX_BORDER_SPACE_PT as aO, MAX_BORDER_WIDTH_PT as aP, MAX_LVL_OVERRIDES as aQ, MAX_NUMBERING_DEFINITIONS as aR, MAX_PARAGRAPH_SPACING_PT as aS, MAX_SHAPING_CONTEXT as aT, MAX_STYLE_DEFINITIONS as aU, MAX_TABLE_BORDER_STROKES as aV, MAX_TAB_POSITION_TWIPS as aW, MAX_TAB_STOPS as aX, DEFAULT_RUN_STYLE as ae, DEFAULT_TAB_INTERVAL_PT as af, DEFAULT_TAB_INTERVAL_TWIPS as ag, EMPTY_NUMBERING_INDEX as al, EMPTY_TAB_STOPS as am, FontResolutionError as ax, bottomBorderExtentPt as b$, PARAGRAPH_BORDER_SIDES as b0, TAB_LEADER_GLYPH as bJ, UnsupportedScriptError as bU, appliedSpaceBefore as bW, applyLineSpacing as bX, baselineShiftPtOf as bY, borderExtentPt as bZ, borderWeight as b_, SINGLE_LINE_SPACING as bp, boundedStructuralFontValidator as c0, buildNumberingIndex as c1, buildStyleCascadeTable as c2, cascadeParagraphFormatting as c3, cascadeRunProperties as c4, cascadedBottomBorder as c5, cascadedParagraphBorders as c6, cascadedTabStops as c7, collapsedSpaceBefore as c8, createFontResourceSnapshot as c9, readCellBorders as cA, readNumPr as cB, readTableBorders as cC, resolveBorderConflict as cD, resolveNumberingLevel as cE, resolveParagraphLayoutInputs as cF, resolveRunStyle as cG, resolveStoryListItems as cH, resolveStoryRefFields as cI, resolveTableCellBorderGrid as cJ, runStylesEqual as cK, shapedRunComparatorInputs as cL, shapingEnvironmentFingerprint as cM, shapingEnvironmentFingerprintInputs as cN, styleForFontSlot as cO, tabAdvanceWidth as cP, tabStopsFingerprint as cQ, withDefaultTabInterval as cR, withNumberingStyleLinks as cS, withResolvedListItems as cT, createShapedRun as ca, createShapingEnvironment as cb, defaultTabIntervalFromSettings as cc, displayText as cd, fixedPoint as ce, fontRequestKey as cf, glyphSizeFactorOf as cg, isValidStyleId as ch, itemizeScriptFontSlots as ci, layoutEquation as cj, measureDisplayText as ck, mergeListIndent as cl, nextTabDestination as cm, pageBordersFingerprint as cn, paragraphBorderExtentPt as co, paragraphBorderStrokeWidthPt as cp, paragraphBorders as cq, paragraphBordersFingerprint as cr, paragraphBreaksBefore as cs, paragraphContextualSpacing as ct, paragraphLineSpacing as cu, paragraphSpacing as cv, paragraphTabStops as cw, parsePageBorders as cx, parseRefInstruction as cy, readBorderSide as cz };
3532
- export type { HyperlinkFieldSpec as $, AnchoredDrawingRecord as A, BlockFragmentRecord as B, ContentControlBoundaryRecord as C, DrawingPoint as D, InlineDrawingLayoutContext as E, FontResourceSnapshot as F, CellBorderBox as G, HeaderFooterStoryRecord as H, InlineDrawingRecord as I, TableBorderBox as J, TableCellStyleFormatting as K, LineRecord as L, ModelRange as M, NoteAreaRecord as N, TableFloatPosition as O, ParagraphFragmentRecord as P, StyleCascadeTable as Q, ResolvedRunStyle as R, SemanticLayout as S, TextMeasurer as T, FixedPoint as U, VersionedShapingLibrary as V, FontByteValidator as W, SourceRange as X, HyperlinkProjector as Y, FieldLinkProjector as Z, StoryPageFieldNeeds as _, PageRecord as a, SpanLinkRecord as a0, PageBorderFrameRecord as a1, ParagraphBorderStrokeRecord as a2, StrikeoutStrokePt as a3, AbstractNumDefinition as a5, AnchoredDrawingLayoutFallback as a6, BidiEmbeddingLevels as a7, BorderGridGeometry as a8, CascadedParagraphFormatting as a9, FontResourceInstrumentation as aA, FontResourceSnapshotOptions as aB, FontSlot as aC, FontValidationResult as aD, GlyphOutline as aE, GroupTextboxStoryRecord as aF, LevelOverride as aJ, LineSpacingRule as aK, ListMarkerAlign as aL, ListMarkerRecord as aM, ListSuffix as aN, NumDefinition as aY, NumberingLevelIndent as aZ, NumberingPictureBullet as a_, CjkTypographySettings as aa, ContentControlGeometryFragment as ab, ContentControlLevel as ac, ContentControlMappedType as ad, DeclaredFontSubstitution as ah, DrawingClipFallback as ai, DrawingGeometry as aj, DrawingGroupPictureRecord as ak, EquationFractionGeometry as an, EquationGeometry as ao, EquationNaryGeometry as ap, EquationRadicalGeometry as aq, EquationRowGeometry as ar, EquationScriptGeometry as as, EquationSpanRecord as at, EquationTextGeometry as au, FieldAtomMarker as av, FontFingerprintInputs as aw, FontResolutionErrorCode as ay, FontResourceDefinition as az, LayoutBox as b, PageBorderDisplay as b1, PageBorderOffsetFrom as b2, PageBorderSide as b3, PageBorderStrokeRecord as b4, PageBorderZOrder as b5, PageRefCalibrationCell as b6, PageRefFieldProjection as b7, ParagraphAutoSpacingContext as b8, ParagraphBorderEdge as b9, ShapedCluster as bA, ShapedFontSpan as bB, ShapedGlyph as bC, ShapedRunComparatorInputs as bD, ShapedVerticalMetrics as bE, ShapingContext as bF, ShapingEnvironment as bG, ShapingEnvironmentFingerprintInputs as bH, StyleDefinition as bI, TabAlignment as bK, TabDestination as bL, TabLeader as bM, TabStop as bN, TableBorderSideName as bO, TableBorderStrokeRecord as bP, TableFragmentRecord as bQ, TextDirection as bR, TextboxStoryFallbackReason as bS, TextboxStoryLayout as bT, VerticalAlign as bV, ParagraphBorderSide as ba, ParagraphBorders as bb, ParagraphBottomBorderRecord as bc, ParagraphIndent as bd, ParagraphLayoutInputs as be, ParagraphLineSpacing as bf, ParagraphSpacing as bg, RefFieldSpec as bh, RefNoteParts as bi, ResolvedCellBorders as bj, ResolvedPictureBullet as bk, ResolvedTabStops as bl, ResolvedTableBorderEdge as bm, ResolvedTableBorderEdgeSegment as bn, ResolvedUnderline as bo, ScriptItem as bq, SemanticArtifactRootStoryKind as br, SemanticArtifactStoryKind as bs, SemanticCommentArtifactRecord as bt, SemanticReviewArtifactOccurrence as bu, SemanticReviewArtifactOccurrenceGeometry as bv, SemanticReviewArtifactPosition as bw, SemanticReviewArtifactSource as bx, SemanticTrackedChangeArtifactRecord as by, ShapeInput as bz, NoteStoryRecord as c, ContentControlLock as d, StyleSpanRecord as e, SectionPageBorders as f, TableRowFragmentRecord as g, TableCellFragmentRecord as h, ShapingEnvironmentInput as i, TextShaper as j, ResolvedFont as k, NormalizationPolicy as l, FixedPointRoundingMode as m, FontRequest as n, SemanticReviewArtifactRecord as o, ListMarkerPictureRecord as p, FontSubstitution as q, ShapedRun as r, NumberingLevel as s, NumberingIndex as t, DrawingInsets as u, TableBorderSide as v, TableFloatXSpec as w, TableFloatYSpec as x, ResolvedListItem as y, RefFieldContext as z };
3982
+ export { DEFAULT_REVISION_MARKUP as D, resolveRevisionMarkup as Q, DEFAULT_REVISION_DISPLAY_MODE as aA, DEFAULT_RUN_STYLE as aB, DEFAULT_SECTION_PROPERTIES as aC, DEFAULT_TAB_INTERVAL_PT as aD, DEFAULT_TAB_INTERVAL_TWIPS as aE, EMPTY_NUMBERING_INDEX as aL, EMPTY_TAB_STOPS as aM, FontResolutionError as aX, AUTO_PARAGRAPH_SPACING_PT as ap, DEFAULT_PAGE_GEOMETRY as az, HARD_MAX_AGGREGATE_FONT_BYTES as b4, HARD_MAX_FONT_BYTES as b5, HARD_MAX_FONT_SOURCES as b6, SINGLE_LINE_SPACING as bS, MAX_BORDER_SPACE_PT as bc, MAX_BORDER_WIDTH_PT as bd, MAX_DOCUMENT_SECTIONS as be, MAX_LVL_OVERRIDES as bf, MAX_NUMBERING_DEFINITIONS as bg, MAX_PARAGRAPH_SPACING_PT as bh, MAX_SHAPING_CONTEXT as bi, MAX_STYLE_DEFINITIONS as bj, MAX_TABLE_BORDER_STROKES as bk, MAX_TAB_POSITION_TWIPS as bl, MAX_TAB_STOPS as bm, PAGE_BORDER_SIDES as bq, PARAGRAPH_BORDER_SIDES as br, paragraphBorderExtentPt as c$, buildStyleCascadeTable as cA, cascadeParagraphFormatting as cB, cascadeRunProperties as cC, cascadedBottomBorder as cD, cascadedParagraphBorders as cE, cascadedTabStops as cF, collapsedSpaceBefore as cG, createFontResourceSnapshot as cH, createShapedRun as cI, createShapingEnvironment as cJ, defaultTabIntervalFromSettings as cK, displayText as cL, enumerateDocumentSections as cM, enumerateDocumentSectionsBounded as cN, fixedPoint as cO, fontRequestKey as cP, formatRevisionOf as cQ, geometryOfSection as cR, glyphSizeFactorOf as cS, isValidStyleId as cT, itemizeScriptFontSlots as cU, layoutEquation as cV, markRevisionRemovesMark as cW, measureDisplayText as cX, mergeListIndent as cY, nextTabDestination as cZ, pageBordersFingerprint as c_, TAB_LEADER_GLYPH as cf, UnsupportedScriptError as cq, appliedSpaceBefore as cs, applyLineSpacing as ct, baselineShiftPtOf as cu, borderExtentPt as cv, borderWeight as cw, bottomBorderExtentPt as cx, boundedStructuralFontValidator as cy, buildNumberingIndex as cz, paragraphBorderStrokeWidthPt as d0, paragraphBorders as d1, paragraphBordersFingerprint as d2, paragraphBreaksBefore as d3, paragraphContextualSpacing as d4, paragraphLineSpacing as d5, paragraphMarkFormatRevisionOf as d6, paragraphMarkRevisionOf as d7, paragraphMarkRevisionsOf as d8, paragraphSectionNode as d9, shapingEnvironmentFingerprintInputs as dA, shownMarkRevision as dB, styleForFontSlot as dC, tabAdvanceWidth as dD, tabStopsFingerprint as dE, withDefaultTabInterval as dF, withNumberingStyleLinks as dG, withResolvedListItems as dH, paragraphSpacing as da, paragraphTabStops as db, parsePageBorders as dc, parsePageNumbering as dd, parseRefInstruction as de, parseSectionProperties as df, projectedSectionSourceIndexes as dg, readBorderSide as dh, readCellBorders as di, readNumPr as dj, readSectionProperties as dk, readTableBorders as dl, resolveBorderConflict as dm, resolveNumberingLevel as dn, resolveParagraphLayoutInputs as dp, resolveRunStyle as dq, resolveStoryListItems as dr, resolveStoryRefFields as ds, resolveTableCellBorderGrid as dt, revisionAuthorFilter as du, revisionsAreDeletion as dv, revisionsVisible as dw, runStylesEqual as dx, shapedRunComparatorInputs as dy, shapingEnvironmentFingerprint as dz, REVISION_MARKUP_COLORS as w };
3983
+ export type { TableBorderSide as $, AnchoredDrawingRecord as A, BlockFragmentRecord as B, ContentControlBoundaryRecord as C, RevisionMarkupColor as E, FontResourceSnapshot as F, RevisionMarkupMark as G, HeaderFooterStoryRecord as H, InlineDrawingRecord as I, RevisionMarkupNamedColor as J, RevisionMarkupStyle as K, LineRecord as L, RevisionMarkupTextStyle as M, NoteAreaRecord as N, SectionProperties as O, ParagraphFragmentRecord as P, RevisionMarkupDialogSession as R, SemanticLayout as S, TextMeasurer as T, NumberingLevel as U, VersionedShapingLibrary as V, NumberingIndex as W, DrawingPoint as X, DrawingInsets as Y, ModelRange as Z, RevisionAttribution as _, ReviewDisplayMode as a, FontResourceSnapshotOptions as a$, TableFloatXSpec as a0, TableFloatYSpec as a1, ResolvedListItem as a2, RefFieldContext as a3, InlineDrawingLayoutContext as a4, CellBorderBox as a5, TableBorderBox as a6, TableCellStyleFormatting as a7, TableFloatPosition as a8, StyleCascadeTable as a9, DeclaredFontSubstitution as aF, DocumentSection as aG, DocumentSectionsEnumeration as aH, DrawingClipFallback as aI, DrawingGeometry as aJ, DrawingGroupPictureRecord as aK, EquationFractionGeometry as aN, EquationGeometry as aO, EquationNaryGeometry as aP, EquationRadicalGeometry as aQ, EquationRowGeometry as aR, EquationScriptGeometry as aS, EquationSpanRecord as aT, EquationTextGeometry as aU, FieldAtomMarker as aV, FontFingerprintInputs as aW, FontResolutionErrorCode as aY, FontResourceDefinition as aZ, FontResourceInstrumentation as a_, RevisionAuthorFilter as aa, FixedPoint as ab, FontByteValidator as ac, SourceRange as ad, HyperlinkProjector as ae, FieldLinkProjector as af, StoryPageFieldNeeds as ag, HyperlinkFieldSpec as ah, SpanLinkRecord as ai, PageGeometry as aj, SectionColumns as ak, SectionPageBorders as al, PageBorderFrameRecord as am, ParagraphBorderStrokeRecord as an, StrikeoutStrokePt as ao, AbstractNumDefinition as aq, AnchoredDrawingLayoutFallback as ar, BidiEmbeddingLevels as as, BorderGridGeometry as at, CascadedParagraphFormatting as au, CjkTypographySettings as av, ContentControlGeometryFragment as aw, ContentControlLevel as ax, ContentControlMappedType as ay, RevisionDisplayMode as b, SemanticCommentArtifactRecord as b$, FontSlot as b0, FontValidationResult as b1, GlyphOutline as b2, GroupTextboxStoryRecord as b3, LevelOverride as b7, LineSpacingRule as b8, ListMarkerAlign as b9, ParagraphBorderEdge as bA, ParagraphBorderSide as bB, ParagraphBorders as bC, ParagraphBottomBorderRecord as bD, ParagraphIndent as bE, ParagraphLayoutInputs as bF, ParagraphLineSpacing as bG, ParagraphSpacing as bH, RefFieldSpec as bI, RefNoteParts as bJ, ResolvedCellBorders as bK, ResolvedPictureBullet as bL, ResolvedTabStops as bM, ResolvedTableBorderEdge as bN, ResolvedTableBorderEdgeSegment as bO, ResolvedUnderline as bP, RevisionFilter as bQ, RevisionKind as bR, ScriptItem as bT, SectionBreakMarkRecord as bU, SectionBreakType as bV, SectionColumnDefinition as bW, SectionMargins as bX, SectionPageNumbering as bY, SemanticArtifactRootStoryKind as bZ, SemanticArtifactStoryKind as b_, ListMarkerRecord as ba, ListSuffix as bb, NumDefinition as bn, NumberingLevelIndent as bo, NumberingPictureBullet as bp, PageBorderDisplay as bs, PageBorderOffsetFrom as bt, PageBorderSide as bu, PageBorderStrokeRecord as bv, PageBorderZOrder as bw, PageRefCalibrationCell as bx, PageRefFieldProjection as by, ParagraphAutoSpacingContext as bz, PageRecord as c, SemanticReviewArtifactOccurrence as c0, SemanticReviewArtifactOccurrenceGeometry as c1, SemanticReviewArtifactPosition as c2, SemanticReviewArtifactSource as c3, SemanticTrackedChangeArtifactRecord as c4, ShapeInput as c5, ShapedCluster as c6, ShapedFontSpan as c7, ShapedGlyph as c8, ShapedRunComparatorInputs as c9, ShapedVerticalMetrics as ca, ShapingContext as cb, ShapingEnvironment as cc, ShapingEnvironmentFingerprintInputs as cd, StyleDefinition as ce, TabAlignment as cg, TabDestination as ch, TabLeader as ci, TabStop as cj, TableBorderSideName as ck, TableBorderStrokeRecord as cl, TableFragmentRecord as cm, TextDirection as cn, TextboxStoryFallbackReason as co, TextboxStoryLayout as cp, VerticalAlign as cr, LayoutBox as d, NoteStoryRecord as e, ContentControlLock as f, StyleSpanRecord as g, TableRowFragmentRecord as h, TableCellFragmentRecord as i, ShapingEnvironmentInput as j, TextShaper as k, ResolvedRunStyle as l, ResolvedFont as m, NormalizationPolicy as n, FixedPointRoundingMode as o, FontRequest as p, ResolvedRevisionMarkup as q, SemanticReviewArtifactRecord as r, ListMarkerPictureRecord as s, RevisionMarkupOptions as t, FontSubstitution as u, ShapedRun as v, RevisionChangedLinesMark as x, RevisionDeletionMark as y, RevisionMarkupChromeHandlers as z };