@hawkeyexl/manni 4.11.0 → 4.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +1 -1
  2. package/dist/{batch-UAULUMGH.js → batch-EFSFG6GC.js} +20 -19
  3. package/dist/build-NIO3UIWJ.js +36 -0
  4. package/dist/calibrate-6VO7URRV.js +41 -0
  5. package/dist/capture-NMBVJO3C.js +38 -0
  6. package/dist/check-SHOYX2B5.js +30 -0
  7. package/dist/check-XMJKH3KV.js +34 -0
  8. package/dist/{check-VELUQAUW.js → check-Y62BJNC4.js} +35 -34
  9. package/dist/{check-VELUQAUW.js.map → check-Y62BJNC4.js.map} +1 -1
  10. package/dist/{check-YEOYBFST.js → check-ZMO3ZLMW.js} +19 -18
  11. package/dist/{chunk-BKVHX6FU.js → chunk-24AJK2RG.js} +5 -10
  12. package/dist/chunk-24AJK2RG.js.map +1 -0
  13. package/dist/{chunk-M42DZCOU.js → chunk-2OZF2VUB.js} +2 -2
  14. package/dist/chunk-2UJZXVHR.js +1868 -0
  15. package/dist/chunk-2UJZXVHR.js.map +1 -0
  16. package/dist/{chunk-HQR2ZBHW.js → chunk-3BRJCQPY.js} +36 -7
  17. package/dist/chunk-3BRJCQPY.js.map +1 -0
  18. package/dist/{chunk-U7CTFN2J.js → chunk-42VFJOAF.js} +7 -7
  19. package/dist/{chunk-LBSCW232.js → chunk-4Q24OYI3.js} +7 -7
  20. package/dist/{chunk-OPXWPJDA.js → chunk-4WJTURRO.js} +14 -14
  21. package/dist/{chunk-GDVZ5VII.js → chunk-5SID2SVL.js} +4 -4
  22. package/dist/{chunk-FUCPZVRY.js → chunk-AANUY4BH.js} +2 -2
  23. package/dist/chunk-ANPIIYRH.js +2272 -0
  24. package/dist/chunk-ANPIIYRH.js.map +1 -0
  25. package/dist/{chunk-WDWXAYVH.js → chunk-AYVKN3PG.js} +4 -4
  26. package/dist/{chunk-FQXWVS6J.js → chunk-CH6IOGXV.js} +9 -9
  27. package/dist/{chunk-4CK6ZSOK.js → chunk-D5Z6B4M7.js} +3 -3
  28. package/dist/{chunk-HA6MQMOY.js → chunk-D6SELXQ2.js} +6 -6
  29. package/dist/{chunk-2DRHT73U.js → chunk-DDILEF5F.js} +890 -1399
  30. package/dist/chunk-DDILEF5F.js.map +1 -0
  31. package/dist/{chunk-PCS4VJBV.js → chunk-DGRLHDM4.js} +9 -9
  32. package/dist/{chunk-2MJ62AYQ.js → chunk-DHGB4JBG.js} +4 -3
  33. package/dist/chunk-DHGB4JBG.js.map +1 -0
  34. package/dist/{chunk-Y6DOMTQD.js → chunk-DLU5FCFT.js} +27 -27
  35. package/dist/chunk-DLU5FCFT.js.map +1 -0
  36. package/dist/chunk-DSWKBZWW.js +16 -0
  37. package/dist/chunk-DSWKBZWW.js.map +1 -0
  38. package/dist/{chunk-KGEQJ5CC.js → chunk-F564FHMQ.js} +8 -8
  39. package/dist/{chunk-J6IDQGJL.js → chunk-FKAZUZQU.js} +469 -85
  40. package/dist/chunk-FKAZUZQU.js.map +1 -0
  41. package/dist/{chunk-IGSHYP74.js → chunk-G3MBUL5M.js} +4 -4
  42. package/dist/{chunk-ADMEPUBT.js → chunk-GQ3KRY3B.js} +3 -3
  43. package/dist/{chunk-T7JAOYE5.js → chunk-HDPN46JP.js} +6 -6
  44. package/dist/{chunk-R4WXQIOZ.js → chunk-IQQAJROD.js} +3 -3
  45. package/dist/{chunk-2IR4T5PO.js → chunk-IZXN3WI6.js} +2 -2
  46. package/dist/{chunk-NCPWXHDO.js → chunk-JEUFYSFQ.js} +4 -4
  47. package/dist/{chunk-LKP7QDFN.js → chunk-JSSM7VVV.js} +4 -4
  48. package/dist/{chunk-2IAZEB45.js → chunk-KFGZPVFA.js} +229 -821
  49. package/dist/chunk-KFGZPVFA.js.map +1 -0
  50. package/dist/{chunk-EIFCP6CZ.js → chunk-KGFSPJLD.js} +2 -2
  51. package/dist/{chunk-RLT5SEML.js → chunk-KMORGMCW.js} +6 -6
  52. package/dist/{chunk-WQWKYAAK.js → chunk-NUQF5F5J.js} +2 -2
  53. package/dist/{chunk-54F74XR3.js → chunk-NZ6KSHFD.js} +19 -19
  54. package/dist/{chunk-4D5IZSXM.js → chunk-OHUDZRLK.js} +3 -3
  55. package/dist/{chunk-FBMZJEB3.js → chunk-OKMTUAWO.js} +4 -4
  56. package/dist/{chunk-QLWC7MKD.js → chunk-OTJOBZJ5.js} +135 -135
  57. package/dist/chunk-OTJOBZJ5.js.map +1 -0
  58. package/dist/{chunk-6HWBRZIN.js → chunk-PS257NIU.js} +252 -193
  59. package/dist/chunk-PS257NIU.js.map +1 -0
  60. package/dist/chunk-QDC7JPFG.js +685 -0
  61. package/dist/chunk-QDC7JPFG.js.map +1 -0
  62. package/dist/{chunk-PCQ7ELJH.js → chunk-QEAGL4V5.js} +109 -5
  63. package/dist/chunk-QEAGL4V5.js.map +1 -0
  64. package/dist/{chunk-BBT6AVUG.js → chunk-QMY57PVW.js} +2 -2
  65. package/dist/{chunk-LPIF5LIE.js → chunk-QNDDPXFR.js} +2 -2
  66. package/dist/{chunk-PWBH7DCQ.js → chunk-QSIXNTRV.js} +4 -4
  67. package/dist/{chunk-VSEBFHAY.js → chunk-RGLFV4KO.js} +11369 -10218
  68. package/dist/chunk-RGLFV4KO.js.map +1 -0
  69. package/dist/{chunk-D4N2V43Z.js → chunk-SGR7ZAVE.js} +13 -7
  70. package/dist/chunk-SGR7ZAVE.js.map +1 -0
  71. package/dist/{chunk-GV56WGL2.js → chunk-SMHAYK6I.js} +1036 -883
  72. package/dist/chunk-SMHAYK6I.js.map +1 -0
  73. package/dist/{chunk-JPQDNYXH.js → chunk-STPGIKPY.js} +8 -2
  74. package/dist/chunk-STPGIKPY.js.map +1 -0
  75. package/dist/{chunk-NSBXVPZL.js → chunk-U22TOL5Y.js} +17 -17
  76. package/dist/{chunk-NGTVREIH.js → chunk-U6IHLEWT.js} +2 -2
  77. package/dist/{chunk-ODRPL3WB.js → chunk-UUCCV3SI.js} +2 -2
  78. package/dist/{chunk-MSRU4D4P.js → chunk-UXMCHBOJ.js} +2 -2
  79. package/dist/{chunk-B7XYNRJQ.js → chunk-VFAKGIDG.js} +2 -2
  80. package/dist/{chunk-QCHVR4ZM.js → chunk-VM7VAFJW.js} +33 -7
  81. package/dist/chunk-VM7VAFJW.js.map +1 -0
  82. package/dist/{chunk-VQK4VHLF.js → chunk-YQV75FIL.js} +2 -2
  83. package/dist/chunk-YUTVAMWW.js +2 -0
  84. package/dist/{cli-4MF37HAQ.js → cli-4CR7QIOK.js} +26 -25
  85. package/dist/{cli-4MF37HAQ.js.map → cli-4CR7QIOK.js.map} +1 -1
  86. package/dist/{cli-6KZTHWGP.js → cli-6R4W3HAH.js} +37 -36
  87. package/dist/{cli-6KZTHWGP.js.map → cli-6R4W3HAH.js.map} +1 -1
  88. package/dist/{cli-I62SRH3R.js → cli-BOMA2FMP.js} +14 -13
  89. package/dist/{cli-DRMZBZLB.js → cli-EDQPQOCE.js} +43 -42
  90. package/dist/{cli-DRMZBZLB.js.map → cli-EDQPQOCE.js.map} +1 -1
  91. package/dist/{cli-VID7PJS3.js → cli-GBF76EXT.js} +23 -22
  92. package/dist/{cli-VID7PJS3.js.map → cli-GBF76EXT.js.map} +1 -1
  93. package/dist/{cli-3BTCK4AB.js → cli-MQYCF3SR.js} +27 -26
  94. package/dist/{cli-3BTCK4AB.js.map → cli-MQYCF3SR.js.map} +1 -1
  95. package/dist/{cli-ONTC5PKT.js → cli-OJKFXQOM.js} +9 -9
  96. package/dist/{cli-VUKMWSSF.js → cli-PHZAO4LZ.js} +4 -4
  97. package/dist/{cli-RORDPAPE.js → cli-PTKFFNOW.js} +59 -38
  98. package/dist/cli-PTKFFNOW.js.map +1 -0
  99. package/dist/{cli-O4ABTN4Z.js → cli-UW2K5Z5J.js} +31 -30
  100. package/dist/{cli-O4ABTN4Z.js.map → cli-UW2K5Z5J.js.map} +1 -1
  101. package/dist/{cli-JJMOVIKS.js → cli-XXTNPPKB.js} +14 -14
  102. package/dist/cli.js +19 -13
  103. package/dist/cli.js.map +1 -1
  104. package/dist/{config-XDA42RJL.js → config-JJW75SBX.js} +5 -5
  105. package/dist/docmeta.js +13 -12
  106. package/dist/docmeta.js.map +1 -1
  107. package/dist/github-6VQKSB67.js +35 -0
  108. package/dist/github-RBSEM7ZK.js +30 -0
  109. package/dist/graph/runtime.d.ts +4 -1
  110. package/dist/graph/runtime.js +20 -9
  111. package/dist/graph/runtime.js.map +1 -1
  112. package/dist/{host-6GURH5HE.js → host-YSTYO5DX.js} +3 -3
  113. package/dist/index.d.ts +192 -26
  114. package/dist/index.js +129 -124
  115. package/dist/index.js.map +1 -1
  116. package/dist/{json-BXY44ED7.js → json-PU2HLHDQ.js} +18 -17
  117. package/dist/labels-SJNSOPBI.js +73 -0
  118. package/dist/labels-SJNSOPBI.js.map +1 -0
  119. package/dist/lint-KIVTHLGU.js +34 -0
  120. package/dist/list-RDEJDDJF.js +32 -0
  121. package/dist/list-SUTDWL2J.js +35 -0
  122. package/dist/{page-EV7OUBAU.js → page-UMAA3NCM.js} +18 -16
  123. package/dist/{prepare-JHJDJB6I.js → prepare-3I3LOXXD.js} +22 -21
  124. package/dist/{prepare-JHJDJB6I.js.map → prepare-3I3LOXXD.js.map} +1 -1
  125. package/dist/{pretty-SCRK66M5.js → pretty-ANLRHU4O.js} +18 -17
  126. package/dist/{pretty-Q5Y2PA64.js → pretty-Q3ZFKOR7.js} +18 -17
  127. package/dist/{provider-527CO4DM.js → provider-LBX4IXGX.js} +3 -3
  128. package/dist/{release-3D5PK6M7.js → release-VV3UTKE5.js} +3 -3
  129. package/dist/{reporters-M6LJ2IYU.js → reporters-26H3N2KW.js} +3 -3
  130. package/dist/{reporters-RBYTASMI.js → reporters-ILT36CIH.js} +7 -7
  131. package/dist/{reporters-A5ADKDYR.js → reporters-PNDLWT6K.js} +16 -15
  132. package/dist/run-QXCK33Z4.js +37 -0
  133. package/dist/{term-CQAGNG3Q.js → term-D2N7UN4P.js} +981 -141
  134. package/dist/term-D2N7UN4P.js.map +1 -0
  135. package/dist/validate-BRUCOT2O.js +19 -0
  136. package/package.json +3 -2
  137. package/plugin/manni/.claude-plugin/plugin.json +1 -1
  138. package/shapes/graph/shapes-1.1.0.ttl +785 -0
  139. package/dist/build-QSPNK5AL.js +0 -35
  140. package/dist/calibrate-KXN4URPM.js +0 -40
  141. package/dist/capture-JHTSUPUC.js +0 -37
  142. package/dist/check-MDGXEUWL.js +0 -20
  143. package/dist/check-WOQRKNZK.js +0 -29
  144. package/dist/chunk-2DRHT73U.js.map +0 -1
  145. package/dist/chunk-2IAZEB45.js.map +0 -1
  146. package/dist/chunk-2MJ62AYQ.js.map +0 -1
  147. package/dist/chunk-4VBSTXN6.js +0 -392
  148. package/dist/chunk-4VBSTXN6.js.map +0 -1
  149. package/dist/chunk-6HWBRZIN.js.map +0 -1
  150. package/dist/chunk-BKVHX6FU.js.map +0 -1
  151. package/dist/chunk-D4N2V43Z.js.map +0 -1
  152. package/dist/chunk-EFW7CAG4.js +0 -387
  153. package/dist/chunk-EFW7CAG4.js.map +0 -1
  154. package/dist/chunk-GV56WGL2.js.map +0 -1
  155. package/dist/chunk-HQR2ZBHW.js.map +0 -1
  156. package/dist/chunk-J6IDQGJL.js.map +0 -1
  157. package/dist/chunk-JPQDNYXH.js.map +0 -1
  158. package/dist/chunk-JROBZ7JA.js +0 -818
  159. package/dist/chunk-JROBZ7JA.js.map +0 -1
  160. package/dist/chunk-PCQ7ELJH.js.map +0 -1
  161. package/dist/chunk-QCHVR4ZM.js.map +0 -1
  162. package/dist/chunk-QLWC7MKD.js.map +0 -1
  163. package/dist/chunk-TU2WUBVZ.js +0 -2
  164. package/dist/chunk-VSEBFHAY.js.map +0 -1
  165. package/dist/chunk-Y6DOMTQD.js.map +0 -1
  166. package/dist/cli-RORDPAPE.js.map +0 -1
  167. package/dist/github-RY3FRA6P.js +0 -29
  168. package/dist/github-YKQSH7FS.js +0 -34
  169. package/dist/lint-YJ2L22BW.js +0 -33
  170. package/dist/list-NSG24VVX.js +0 -31
  171. package/dist/list-V6EGCSHX.js +0 -34
  172. package/dist/run-BUE2DDXN.js +0 -36
  173. package/dist/term-CQAGNG3Q.js.map +0 -1
  174. package/dist/validate-ZBW44RHT.js +0 -18
  175. /package/dist/{batch-UAULUMGH.js.map → batch-EFSFG6GC.js.map} +0 -0
  176. /package/dist/{build-QSPNK5AL.js.map → build-NIO3UIWJ.js.map} +0 -0
  177. /package/dist/{calibrate-KXN4URPM.js.map → calibrate-6VO7URRV.js.map} +0 -0
  178. /package/dist/{capture-JHTSUPUC.js.map → capture-NMBVJO3C.js.map} +0 -0
  179. /package/dist/{check-MDGXEUWL.js.map → check-SHOYX2B5.js.map} +0 -0
  180. /package/dist/{check-WOQRKNZK.js.map → check-XMJKH3KV.js.map} +0 -0
  181. /package/dist/{check-YEOYBFST.js.map → check-ZMO3ZLMW.js.map} +0 -0
  182. /package/dist/{chunk-M42DZCOU.js.map → chunk-2OZF2VUB.js.map} +0 -0
  183. /package/dist/{chunk-U7CTFN2J.js.map → chunk-42VFJOAF.js.map} +0 -0
  184. /package/dist/{chunk-LBSCW232.js.map → chunk-4Q24OYI3.js.map} +0 -0
  185. /package/dist/{chunk-OPXWPJDA.js.map → chunk-4WJTURRO.js.map} +0 -0
  186. /package/dist/{chunk-GDVZ5VII.js.map → chunk-5SID2SVL.js.map} +0 -0
  187. /package/dist/{chunk-FUCPZVRY.js.map → chunk-AANUY4BH.js.map} +0 -0
  188. /package/dist/{chunk-WDWXAYVH.js.map → chunk-AYVKN3PG.js.map} +0 -0
  189. /package/dist/{chunk-FQXWVS6J.js.map → chunk-CH6IOGXV.js.map} +0 -0
  190. /package/dist/{chunk-4CK6ZSOK.js.map → chunk-D5Z6B4M7.js.map} +0 -0
  191. /package/dist/{chunk-HA6MQMOY.js.map → chunk-D6SELXQ2.js.map} +0 -0
  192. /package/dist/{chunk-PCS4VJBV.js.map → chunk-DGRLHDM4.js.map} +0 -0
  193. /package/dist/{chunk-KGEQJ5CC.js.map → chunk-F564FHMQ.js.map} +0 -0
  194. /package/dist/{chunk-IGSHYP74.js.map → chunk-G3MBUL5M.js.map} +0 -0
  195. /package/dist/{chunk-ADMEPUBT.js.map → chunk-GQ3KRY3B.js.map} +0 -0
  196. /package/dist/{chunk-T7JAOYE5.js.map → chunk-HDPN46JP.js.map} +0 -0
  197. /package/dist/{chunk-R4WXQIOZ.js.map → chunk-IQQAJROD.js.map} +0 -0
  198. /package/dist/{chunk-2IR4T5PO.js.map → chunk-IZXN3WI6.js.map} +0 -0
  199. /package/dist/{chunk-NCPWXHDO.js.map → chunk-JEUFYSFQ.js.map} +0 -0
  200. /package/dist/{chunk-LKP7QDFN.js.map → chunk-JSSM7VVV.js.map} +0 -0
  201. /package/dist/{chunk-EIFCP6CZ.js.map → chunk-KGFSPJLD.js.map} +0 -0
  202. /package/dist/{chunk-RLT5SEML.js.map → chunk-KMORGMCW.js.map} +0 -0
  203. /package/dist/{chunk-WQWKYAAK.js.map → chunk-NUQF5F5J.js.map} +0 -0
  204. /package/dist/{chunk-54F74XR3.js.map → chunk-NZ6KSHFD.js.map} +0 -0
  205. /package/dist/{chunk-4D5IZSXM.js.map → chunk-OHUDZRLK.js.map} +0 -0
  206. /package/dist/{chunk-FBMZJEB3.js.map → chunk-OKMTUAWO.js.map} +0 -0
  207. /package/dist/{chunk-BBT6AVUG.js.map → chunk-QMY57PVW.js.map} +0 -0
  208. /package/dist/{chunk-LPIF5LIE.js.map → chunk-QNDDPXFR.js.map} +0 -0
  209. /package/dist/{chunk-PWBH7DCQ.js.map → chunk-QSIXNTRV.js.map} +0 -0
  210. /package/dist/{chunk-NSBXVPZL.js.map → chunk-U22TOL5Y.js.map} +0 -0
  211. /package/dist/{chunk-NGTVREIH.js.map → chunk-U6IHLEWT.js.map} +0 -0
  212. /package/dist/{chunk-ODRPL3WB.js.map → chunk-UUCCV3SI.js.map} +0 -0
  213. /package/dist/{chunk-MSRU4D4P.js.map → chunk-UXMCHBOJ.js.map} +0 -0
  214. /package/dist/{chunk-B7XYNRJQ.js.map → chunk-VFAKGIDG.js.map} +0 -0
  215. /package/dist/{chunk-VQK4VHLF.js.map → chunk-YQV75FIL.js.map} +0 -0
  216. /package/dist/{chunk-TU2WUBVZ.js.map → chunk-YUTVAMWW.js.map} +0 -0
  217. /package/dist/{cli-I62SRH3R.js.map → cli-BOMA2FMP.js.map} +0 -0
  218. /package/dist/{cli-ONTC5PKT.js.map → cli-OJKFXQOM.js.map} +0 -0
  219. /package/dist/{cli-VUKMWSSF.js.map → cli-PHZAO4LZ.js.map} +0 -0
  220. /package/dist/{cli-JJMOVIKS.js.map → cli-XXTNPPKB.js.map} +0 -0
  221. /package/dist/{config-XDA42RJL.js.map → config-JJW75SBX.js.map} +0 -0
  222. /package/dist/{github-RY3FRA6P.js.map → github-6VQKSB67.js.map} +0 -0
  223. /package/dist/{github-YKQSH7FS.js.map → github-RBSEM7ZK.js.map} +0 -0
  224. /package/dist/{host-6GURH5HE.js.map → host-YSTYO5DX.js.map} +0 -0
  225. /package/dist/{json-BXY44ED7.js.map → json-PU2HLHDQ.js.map} +0 -0
  226. /package/dist/{lint-YJ2L22BW.js.map → lint-KIVTHLGU.js.map} +0 -0
  227. /package/dist/{list-NSG24VVX.js.map → list-RDEJDDJF.js.map} +0 -0
  228. /package/dist/{list-V6EGCSHX.js.map → list-SUTDWL2J.js.map} +0 -0
  229. /package/dist/{page-EV7OUBAU.js.map → page-UMAA3NCM.js.map} +0 -0
  230. /package/dist/{pretty-Q5Y2PA64.js.map → pretty-ANLRHU4O.js.map} +0 -0
  231. /package/dist/{pretty-SCRK66M5.js.map → pretty-Q3ZFKOR7.js.map} +0 -0
  232. /package/dist/{provider-527CO4DM.js.map → provider-LBX4IXGX.js.map} +0 -0
  233. /package/dist/{release-3D5PK6M7.js.map → release-VV3UTKE5.js.map} +0 -0
  234. /package/dist/{reporters-A5ADKDYR.js.map → reporters-26H3N2KW.js.map} +0 -0
  235. /package/dist/{reporters-M6LJ2IYU.js.map → reporters-ILT36CIH.js.map} +0 -0
  236. /package/dist/{reporters-RBYTASMI.js.map → reporters-PNDLWT6K.js.map} +0 -0
  237. /package/dist/{run-BUE2DDXN.js.map → run-QXCK33Z4.js.map} +0 -0
  238. /package/dist/{validate-ZBW44RHT.js.map → validate-BRUCOT2O.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cite/core/page.ts","../src/cite/errors.ts","../src/cite/core/hash.ts","../src/cite/core/range.ts","../src/cite/types.ts","../src/cite/core/severity.ts","../src/cite/core/statements.ts"],"sourcesContent":["/**\n * Read a page's citations and its markers.\n *\n * Entries come from the frontmatter (via meta's extractor for the format), or\n * from `CheckPageOptions.citations` when a manifest owns them; either way each\n * one is validated against the registered `manni:citations:1.0.0` schema and\n * carries where it sits.\n * Markers are `cite <id> [<id>…]` comments in the body, resolved to the\n * entries they name, so each citation knows what anchors it. Every id one\n * marker names anchors the same text, so every claim under it pins the same\n * bytes and holds the same hash (proposal 0056).\n *\n * The findings made here are the ones that need no source: `entry-invalid`,\n * `marker-invalid`, `marker-orphan`, `marker-repeated` and `anchor-invalid`.\n */\nimport { extname } from \"node:path\";\nimport * as Ajv2020Ns from \"ajv/dist/2020.js\";\nimport type { ValidateFunction } from \"ajv/dist/2020.js\";\nimport citationsSchema from \"../../meta/schemas/citations/1.0.0.json\" with { type: \"json\" };\nimport {\n extractorForExtension,\n locateFrontmatter,\n supportedExtensions,\n type ExtractedMetadata,\n type MetadataExtractor,\n} from \"../../meta/index.js\";\nimport { extractorByName, hasFrontmatterFence } from \"../../meta/internal.js\";\nimport { isEncryptedValue } from \"../../shared/encryption.js\";\nimport { CiteError } from \"../errors.js\";\nimport type {\n Citation,\n CitationFinding,\n CitationInput,\n CitationOrigin,\n CiteRule,\n PageCitation,\n PageCitations,\n} from \"../types.js\";\nimport { isKeyedPin } from \"./hash.js\";\nimport { parseLines, spellSource, tooWide } from \"./range.js\";\nimport { DEFAULT_SEVERITY, ruleId } from \"./severity.js\";\nimport { bodyLineOf } from \"../../shared/pin.js\";\nimport { parseStatements } from \"./statements.js\";\n\nexport { MAX_IDS_PER_MARKER } from \"./statements.js\";\nexport { bodyLineOf };\n\nexport const MAX_MARKERS_PER_PAGE = 500;\n\n/** Formats whose leading fenced block is frontmatter meta would read. */\nconst ELEMENT_BACKED = new Set([\"html\", \"xml\"]);\n/** Formats whose only metadata channel is a fenced block. */\nconst FENCE_ONLY = new Set([\"markdown\", \"mdx\"]);\n\n/** What a marker with a JSON payload is told, since an entry never lives in the body. */\nexport const MARKER_JSON =\n \"A marker names an entry by id. Write the entry in frontmatter or the sidecar.\";\n\nexport interface ReadPageOptions {\n /** Extractor name; derived from the file's extension when absent. */\n format?: string;\n /**\n * The page's citations as a manifest owns them, already merged. Given, the\n * page's own frontmatter `citations` is not read.\n */\n citations?: readonly CitationInput[];\n /**\n * The manifest that owns this page's `citations`, when one does. A page\n * that also carries its own is `entry-invalid`: neither channel wins, and\n * the discarded value would be exactly the one nobody checked.\n */\n owned?: { file: string; collection: string };\n /**\n * `false` reads the entries alone, for a caller that only counts them: no\n * marker is parsed, so no marker finding is raised and none is anchored.\n */\n markers?: boolean;\n}\n\n/** Meta's `external:owned` sentence, said by `cite check` under `entry-invalid`. */\nexport function ownedMessage(owner: { file: string; collection: string }): string {\n return `\"citations\" is owned by manifest ${owner.file} (collection ${owner.collection}); remove it from the document`;\n}\n\n// ajv is CommonJS with a default export; under NodeNext the constructor lives\n// on `.default`, as src/meta/core/validator.ts notes.\ntype AjvCtor = typeof import(\"ajv/dist/2020.js\").default;\nconst Ajv2020 = Ajv2020Ns.default as unknown as AjvCtor;\n\nlet entryValidator: ValidateFunction | undefined;\n\nfunction compileEntryValidator(): ValidateFunction {\n if (entryValidator) return entryValidator;\n const ajv = new Ajv2020({ allErrors: false, strict: false });\n ajv.addSchema(citationsSchema);\n entryValidator = ajv.compile({\n $ref: `${citationsSchema.$id}#/$defs/citationEntry`,\n });\n return entryValidator;\n}\n\n/** Ajv validation of one entry object against `$defs.citationEntry`; the first error text, or undefined. */\nexport function validateEntry(entry: unknown): string | undefined {\n const validate = compileEntryValidator();\n if (validate(entry)) return undefined;\n const first = validate.errors?.[0];\n if (!first) return \"invalid entry\";\n return `${first.instancePath} ${first.message ?? \"is invalid\"}`.trim();\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Copy a validated entry into the `Citation` shape, field by field. */\nfunction toCitation(entry: Record<string, unknown>): Citation {\n const source = isRecord(entry.source) ? entry.source : {};\n const citation: Citation = {\n source: {\n file: String(source.file),\n integrity: String(source.integrity),\n },\n };\n if (typeof source.lines === \"number\" || typeof source.lines === \"string\") {\n citation.source.lines = source.lines;\n }\n if (typeof source[\"commit-sha\"] === \"string\") {\n citation.source[\"commit-sha\"] = source[\"commit-sha\"];\n }\n if (typeof entry.id === \"string\") citation.id = entry.id;\n if (isRecord(entry.claim)) {\n const claim = entry.claim;\n citation.claim = { integrity: String(claim.integrity) };\n if (typeof claim.lines === \"number\" || typeof claim.lines === \"string\") {\n citation.claim.lines = claim.lines;\n }\n }\n if (typeof entry.quote === \"boolean\") citation.quote = entry.quote;\n return citation;\n}\n\ntype FindingExtra = Pick<CitationFinding, \"line\" | \"id\" | \"src\" | \"index\" | \"file\">;\n\nfunction finding(rule: CiteRule, message: string, extra: FindingExtra): CitationFinding {\n const level = DEFAULT_SEVERITY[rule];\n const out: CitationFinding = {\n rule,\n ruleId: ruleId(rule),\n // The caller re-applies the configured severity table; no page-side rule\n // defaults to `off`, so there is nothing to collapse.\n severity: level === \"off\" ? \"error\" : level,\n message,\n };\n if (extra.line !== undefined) out.line = extra.line;\n if (extra.file !== undefined) out.file = extra.file;\n if (extra.id !== undefined) out.id = extra.id;\n if (extra.src !== undefined) out.src = extra.src;\n if (extra.index !== undefined) out.index = extra.index;\n return out;\n}\n\n/** `<id>: <text>`, or the text alone for an entry with no id. */\nfunction named(id: string | undefined, text: string): string {\n return id === undefined ? text : `${id}: ${text}`;\n}\n\n/** The `id`/`src` a finding carries for an entry that may not have validated. */\nfunction subjectOf(entry: unknown): Pick<FindingExtra, \"id\" | \"src\"> {\n const out: Pick<FindingExtra, \"id\" | \"src\"> = {};\n if (!isRecord(entry)) return out;\n if (typeof entry.id === \"string\") out.id = entry.id;\n if (isRecord(entry.source) && typeof entry.source.file === \"string\") out.src = entry.source.file;\n return out;\n}\n\nexport function pickExtractor(file: string, format: string | undefined): MetadataExtractor {\n if (format !== undefined) {\n const forced = extractorByName(format);\n if (forced === undefined) {\n throw new CiteError(\n `Unknown format \"${format}\". Supported extensions: ${supportedExtensions().join(\", \")}.`,\n );\n }\n return forced;\n }\n const extension = extname(file);\n const byExt = extractorForExtension(extension);\n if (!byExt) {\n throw new CiteError(\n `Unsupported file type \"${extension}\" for \"${file}\". Supported: ${supportedExtensions().join(\", \")}. Use --as to override.`,\n );\n }\n return byExt;\n}\n\nfunction byLine(a: CitationFinding, b: CitationFinding): number {\n return (a.line ?? Number.MAX_SAFE_INTEGER) - (b.line ?? Number.MAX_SAFE_INTEGER);\n}\n\n\n/**\n * A page's citation entries as they are written, each with where it sits: the\n * manifest's when one owns them, else the page's own frontmatter. The entries\n * are raw, so one the schema refuses is still in the list at its own index,\n * which is how `remove` reaches an entry `check` can only report.\n */\nexport function citationInputs(\n file: string,\n extracted: ExtractedMetadata,\n injected?: readonly CitationInput[],\n): CitationInput[] {\n if (injected !== undefined) return [...injected];\n const raw: unknown = extracted.data.citations;\n const list: unknown[] = Array.isArray(raw) ? (raw as unknown[]) : [];\n return list.map((entry, index) => {\n const origin: CitationInput[\"origin\"] = { kind: \"frontmatter\", file };\n const line = extracted.lineFor(`/citations/${String(index)}`);\n if (line !== undefined) origin.line = line;\n return { entry, origin };\n });\n}\n\nexport function readPage(\n file: string,\n content: string,\n opts?: ReadPageOptions,\n): PageCitations {\n const extractor = pickExtractor(file, opts?.format);\n const format = extractor.name;\n // An opening fence with no close is not a block, so the extractor reads no\n // metadata and every entry the page carries would silently vanish. rst and\n // asciidoc read a stray fence as body on purpose, ahead of their native\n // headers; the fence-only formats have no such reading.\n if (FENCE_ONLY.has(format) && hasFrontmatterFence(content) && locateFrontmatter(content) === null) {\n throw new CiteError(\n `${file}: Unterminated front matter fence: the opening fence has no matching close, so the page's citations cannot be read. Add a closing fence.`,\n );\n }\n const extracted = extractor.extract(content, file);\n const data = extracted.data;\n const bodyOffset = ELEMENT_BACKED.has(format)\n ? 0\n : (locateFrontmatter(content)?.closeEnd ?? 0);\n const bodyLine = bodyLineOf(content, bodyOffset);\n\n const findings: CitationFinding[] = [];\n const citations: PageCitation[] = [];\n /** Entries by id, for marker resolution. */\n const byId = new Map<string, PageCitation>();\n /** Every id seen, for uniqueness. */\n const ids = new Set<string>();\n /** The first marker naming an entry, by entry. */\n const markedAt = new Map<PageCitation, number>();\n\n // The page root reserves the whole `citation-` prefix, so a typo fails\n // loudly rather than passing as a key of somebody else's.\n for (const key of Object.keys(data)) {\n if (!key.startsWith(\"citation-\")) continue;\n findings.push(\n finding(\n \"entry-invalid\",\n `\"${key}\" is not a citations key; the page root reserves the citation- prefix`,\n { line: extracted.lineFor(`/${key}`) },\n ),\n );\n }\n\n const injected = opts?.citations;\n const rawCitations = data.citations;\n // The page carries a key a manifest owns (0020 across files). The page's\n // own entries are still read and checked, so the report shows what the\n // page would publish; the finding says the manifest is the one authority.\n if (opts?.owned !== undefined && rawCitations !== undefined) {\n findings.push(\n finding(\"entry-invalid\", ownedMessage(opts.owned), {\n line: extracted.lineFor(\"/citations\"),\n }),\n );\n }\n if (injected === undefined && rawCitations !== undefined && !Array.isArray(rawCitations)) {\n findings.push(\n finding(\"entry-invalid\", \"citations must be an array of entries\", {\n line: extracted.lineFor(\"/citations\"),\n }),\n );\n }\n const inputs = citationInputs(file, extracted, injected);\n\n inputs.forEach((input, index) => {\n const origin: CitationOrigin = { ...input.origin, index };\n /** Where a finding about the entry itself sits: the entry's own line, in its own file. */\n const where: FindingExtra = { index };\n if (origin.line !== undefined) where.line = origin.line;\n if (origin.kind === \"manifest\") where.file = origin.file;\n\n const entry = input.entry;\n const error = validateEntry(entry);\n if (error !== undefined || !isRecord(entry)) {\n findings.push(finding(\"entry-invalid\", error ?? \"must be object\", { ...where, ...subjectOf(entry) }));\n return;\n }\n const citation = toCitation(entry);\n const subject: FindingExtra = { ...where, src: spellSource(citation.source) };\n if (citation.id !== undefined) subject.id = citation.id;\n\n // A range that ends before it starts: the schema cannot compare two\n // numbers, so the rule is kept here.\n const bad = ([\"claim\", \"source\"] as const).find((end) => {\n const lines = end === \"claim\" ? citation.claim?.lines : citation.source.lines;\n return lines !== undefined && parseLines(lines) === undefined;\n });\n if (bad !== undefined) {\n const lines = bad === \"claim\" ? citation.claim?.lines : citation.source.lines;\n findings.push(\n finding(\n \"entry-invalid\",\n named(citation.id, `${bad}.lines \"${String(lines)}\" ends before it starts`),\n subject,\n ),\n );\n return;\n }\n\n // A range wider than the cap is refused at either end (proposal 0044).\n const wide = ([\"claim\", \"source\"] as const)\n .map((end) => {\n const lines = end === \"claim\" ? citation.claim?.lines : citation.source.lines;\n const parsed = lines === undefined ? undefined : parseLines(lines);\n const reason = parsed === undefined ? undefined : tooWide(parsed);\n return reason === undefined ? undefined : `${end}.lines \"${String(lines)}\" ${reason}`;\n })\n .find((message) => message !== undefined);\n if (wide !== undefined) {\n findings.push(finding(\"entry-invalid\", named(citation.id, wide), subject));\n return;\n }\n\n // The pin's prefix says how it was taken, and only an encrypted source\n // carries a keyed one.\n const encrypted = isEncryptedValue(citation.source.file);\n if (encrypted !== isKeyedPin(citation.source.integrity)) {\n findings.push(\n finding(\n \"entry-invalid\",\n named(\n citation.id,\n encrypted\n ? \"an encrypted source is pinned with hmac-sha256-, not sha256-.\"\n : \"a plain source is pinned with sha256-, not hmac-sha256-.\",\n ),\n subject,\n ),\n );\n return;\n }\n\n const page: PageCitation = { citation, origin };\n citations.push(page);\n if (citation.id !== undefined) {\n if (ids.has(citation.id)) {\n findings.push(finding(\"entry-invalid\", `duplicate id \"${citation.id}\"`, subject));\n } else {\n ids.add(citation.id);\n byId.set(citation.id, page);\n }\n }\n });\n\n // Markers.\n const body = content.slice(bodyOffset);\n const statements =\n opts?.markers === false ? [] : parseStatements(body, format, { offset: bodyOffset, line: bodyLine });\n if (statements.length > MAX_MARKERS_PER_PAGE) {\n findings.push(\n finding(\n \"marker-invalid\",\n `more than ${String(MAX_MARKERS_PER_PAGE)} markers on one page (${String(statements.length)}); the rest are not read`,\n { line: statements[MAX_MARKERS_PER_PAGE]?.line },\n ),\n );\n }\n\n for (const statement of statements.slice(0, MAX_MARKERS_PER_PAGE)) {\n const { payload } = statement;\n if (payload.kind === \"bad\") {\n findings.push(\n finding(\n \"marker-invalid\",\n payload.json === true ? MARKER_JSON : `invalid marker: ${payload.reason}`,\n { line: statement.line },\n ),\n );\n continue;\n }\n // Each named id reports on its own: an orphan is a well-formed id with a\n // missing entry, so each one is its own subject and its own fix. A\n // malformed marker is one line and one fix, and was handled above.\n // The entries this marker actually anchors. An id the marker repeats is\n // reported and left to the marker that won it, so it never lands here.\n const anchored: PageCitation[] = [];\n for (const id of payload.ids) {\n const target = byId.get(id);\n if (target === undefined) {\n findings.push(\n finding(\"marker-orphan\", `no entry has id \"${id}\"`, {\n line: statement.line,\n id,\n }),\n );\n continue;\n }\n const first = markedAt.get(target);\n if (first !== undefined) {\n findings.push(\n finding(\n \"marker-repeated\",\n `${id} is named by markers at lines ${String(first)} and ${String(statement.line)}; the first anchors it.`,\n {\n line: statement.line,\n id,\n index: target.origin.index,\n src: spellSource(target.citation.source),\n },\n ),\n );\n continue;\n }\n markedAt.set(target, statement.line);\n target.marker = statement;\n anchored.push(target);\n }\n // A quote entry anchors the next fenced block and a plain one anchors the\n // paragraph, so a list that mixes them would mean two spans on one line,\n // and the page would not say which id got which.\n const quoted = anchored.find((entry) => entry.citation.quote === true);\n const plain = anchored.find((entry) => entry.citation.quote !== true);\n if (quoted !== undefined && plain !== undefined) {\n const mixed: FindingExtra = {\n line: statement.line,\n index: quoted.origin.index,\n src: spellSource(quoted.citation.source),\n };\n if (quoted.citation.id !== undefined) mixed.id = quoted.citation.id;\n findings.push(\n finding(\n \"anchor-invalid\",\n named(\n quoted.citation.id,\n \"a quote entry shares a marker with a non-quote entry. Give the quote its own marker.\",\n ),\n mixed,\n ),\n );\n }\n }\n\n // Anchors: exactly one way in, and a quote needs one of them.\n for (const entry of citations) {\n const { citation, origin, marker } = entry;\n const subject: FindingExtra = { index: origin.index, src: spellSource(citation.source) };\n if (citation.id !== undefined) subject.id = citation.id;\n if (origin.line !== undefined) subject.line = origin.line;\n if (origin.kind === \"manifest\") subject.file = origin.file;\n\n if (citation.claim?.lines !== undefined && marker !== undefined) {\n // A marker names an id, so an entry with both always has one. The\n // finding sits on the marker, which is the half a reader can see.\n const onPage: FindingExtra = { index: origin.index, line: marker.line, src: subject.src };\n if (citation.id !== undefined) onPage.id = citation.id;\n findings.push(\n finding(\n \"anchor-invalid\",\n `${citation.id ?? \"the entry\"} has claim lines and a marker. Keep one.`,\n onPage,\n ),\n );\n continue;\n }\n if (citation.quote === true && citation.claim?.lines === undefined && marker === undefined) {\n findings.push(\n finding(\"anchor-invalid\", named(citation.id, \"quote needs a claim or a marker.\"), subject),\n );\n }\n }\n\n return {\n file,\n format,\n content,\n bodyOffset,\n bodyLine,\n citations,\n statements,\n findings: findings.sort(byLine),\n };\n}\n","import { ToolError } from \"../shared/errors.js\";\nimport { LineRangeError } from \"../shared/pin.js\";\n\n/** An operational or usage error in the citation tool: exit 2. */\nexport class CiteError extends ToolError {\n constructor(message: string) {\n super(message);\n this.name = \"CiteError\";\n }\n}\n\n/**\n * Run a shared pin-engine call under cite's error contract: a\n * `LineRangeError` comes back as a `CiteError` with the same message, which is\n * what cite's callers (and library users of the `cite` namespace) match on.\n */\nexport function asCiteError<T>(call: () => T): T {\n try {\n return call();\n } catch (error) {\n if (error instanceof LineRangeError) throw new CiteError(error.message);\n throw error;\n }\n}\n","/**\n * The hashing rule, as cite uses it. The engine is `src/shared/pin.ts`, shared\n * with meta; this module keeps cite's import path and its error contract: a\n * range past the end of the text throws `CiteError`.\n */\nimport {\n hashRange as sharedHashRange,\n sliceLines as sharedSliceLines,\n type LineRange,\n} from \"../../shared/pin.js\";\nimport { asCiteError } from \"../errors.js\";\n\nexport { hashLines, isKeyedPin, normalizeText, splitLines } from \"../../shared/pin.js\";\n\n/**\n * The cited lines joined by LF. Throws `CiteError` when the range runs past\n * the end of the text (`<path> has N lines; line M is out of range`).\n */\nexport function sliceLines(lines: readonly string[], range?: LineRange, label?: string): string {\n return asCiteError(() => sharedSliceLines(lines, range, label));\n}\n\n/** The pin of the cited lines: plain, or the keyed pin under `key` when one is given. Throws `CiteError` past the end. */\nexport function hashRange(text: string, range?: LineRange, key?: string): string {\n return asCiteError(() => sharedHashRange(text, range, key));\n}\n","/**\n * Source and line grammar.\n *\n * An entry's `source.file` is a path or an encrypted source (`~` and at least\n * 82 base64url characters, proposal 0045), and its `lines` an integer or\n * `\"L1-L2\"`. `FILE_PATTERN` is the schema's `$defs.fileRef.pattern`, spelled\n * once here and once in the registered `manni:citations:1.0.0` schema\n * (`src/meta/schemas/citations/1.0.0.json`); `test/cite/range.test.ts` pins\n * the two equal.\n *\n * The command line spells a source as one string, `path`, `path:L` or\n * `path:L1-L2` (`SRC_PATTERN`), and reports spell it that way too.\n */\nimport { isEncryptedValue } from \"../../shared/encryption.js\";\nimport { MAX_RANGE_LINES, lineSpec, parseLines } from \"../../shared/pin.js\";\nimport { CiteError } from \"../errors.js\";\nimport type { CitationSource, LineSpec, PageLines, SourceRange } from \"../types.js\";\n\n// The line grammar is the shared pin engine's; this path keeps cite's imports working.\nexport { lineSpec, parseLines, spellLines } from \"../../shared/pin.js\";\n\n/** The schema's `$defs.fileRef.pattern`, as a RegExp. */\nexport const FILE_PATTERN =\n /^(?:~[A-Za-z0-9_-]{82,}|(?!~)(?:(?!\\.\\.?(?:\\/|$))[^/\\\\:\\r\\n\\t]+)(?:\\/(?:(?!\\.\\.?(?:\\/|$))[^/\\\\:\\r\\n\\t]+))*)$/;\n\n/** A source on the command line: a `file`, then an optional `:L` or `:L1-L2`. */\nexport const SRC_PATTERN =\n /^(?:~[A-Za-z0-9_-]{82,}|(?!~)(?:(?!\\.\\.?(?:\\/|:|$))[^/\\\\:\\r\\n\\t]+)(?:\\/(?:(?!\\.\\.?(?:\\/|:|$))[^/\\\\:\\r\\n\\t]+))*)(?::[1-9][0-9]*(?:-[1-9][0-9]*)?)?$/;\n\n/**\n * Parse a command-line source. Throws `CiteError` on bad grammar or an end\n * line before the start. A one-line `path:L` comes back with `end` equal to\n * `start`, so a range's width is always `end - start + 1`.\n */\nexport function parseSrc(src: string): SourceRange {\n if (!SRC_PATTERN.test(src)) {\n throw new CiteError(\n `Invalid src \"${src}\": expected path, path:L, path:L1-L2, or an encrypted source (~ and at least 82 base64url characters) with the same line forms; ` +\n \"the path is repo-root-relative, posix, and free of . and .. segments.\",\n );\n }\n // The grammar keeps `:` out of every path segment and out of the base64url\n // alphabet, so the first one starts the line suffix.\n const colon = src.indexOf(\":\");\n const path = colon === -1 ? src : src.slice(0, colon);\n const range: SourceRange = { path, encrypted: isEncryptedValue(path) };\n if (colon === -1) return range;\n const [startText, endText] = src.slice(colon + 1).split(\"-\");\n const start = Number(startText);\n const end = endText === undefined ? start : Number(endText);\n if (end < start) {\n throw new CiteError(`Invalid range \"${src}\": end line ${end} is before start line ${start}.`);\n }\n range.start = start;\n range.end = end;\n return range;\n}\n\n/**\n * How a range too wide to cite is refused: `spans N lines, more than 5000`.\n * Undefined for a range of at most `MAX_RANGE_LINES` lines.\n */\nexport function tooWide(lines: PageLines): string | undefined {\n const width = lines.end - lines.start + 1;\n return width > MAX_RANGE_LINES\n ? `spans ${String(width)} lines, more than ${String(MAX_RANGE_LINES)}`\n : undefined;\n}\n\n/** The canonical spelling: `path:L` for one line, `path:L1-L2` otherwise. */\nexport function formatSrc(range: SourceRange): string {\n const { path, start, end } = range;\n if (start === undefined) return path;\n if (end === undefined || end === start) return `${path}:${start}`;\n return `${path}:${start}-${end}`;\n}\n\n/** An entry's source as a range. Its lines must already be valid (see `parseLines`). */\nexport function sourceRange(source: CitationSource): SourceRange {\n const range: SourceRange = { path: source.file, encrypted: isEncryptedValue(source.file) };\n if (source.lines === undefined) return range;\n const lines = parseLines(source.lines);\n if (lines !== undefined) {\n range.start = lines.start;\n range.end = lines.end;\n }\n return range;\n}\n\n/** An entry's source spelled as one string, `path:L1-L2`, the way the command line takes it. */\nexport function spellSource(source: CitationSource): string {\n return formatSrc(sourceRange(source));\n}\n\n/** A range's lines as an entry writes them; undefined for a whole file. */\nexport function rangeLines(range: SourceRange): LineSpec | undefined {\n if (range.start === undefined) return undefined;\n return lineSpec({ start: range.start, end: range.end ?? range.start });\n}\n","/**\n * The citation tool's types. Proposal 0044 is the record, and stress test 25\n * the shape: an entry has two ends, `claim` and `source`, each a line range\n * and a hash, and a check classifies both with one set of rules.\n *\n * Vocabulary: a page's `citations` live in its frontmatter, or in a manifest\n * a collection declares (handed in through `CheckPageOptions.citations`). A\n * body marker, `cite <id>` in the format's comment syntax, is the other way\n * to anchor an entry's claim.\n */\nimport type { ValidationResult } from \"../meta/index.js\";\nimport type { CollectionConfig } from \"../shared/collections.js\";\nimport type { ConfigFile } from \"../shared/config-file.js\";\nimport type { KeySource } from \"../shared/encryption-key.js\";\nimport type { LineSpec, PageLines } from \"../shared/pin.js\";\nimport type { Confirm } from \"../shared/prompt.js\";\nimport type { Severity } from \"../shared/severity.js\";\n\n/** A parsed `<src>` or `source`: a path or `~` ciphertext, and an optional line range. */\nexport interface SourceRange {\n /** Repo-root-relative posix path, or the `~` ciphertext when `encrypted`. */\n path: string;\n /** `true` when `path` is an encrypted source (`~` and 82+ base64url characters) rather than a path. */\n encrypted: boolean;\n /** 1-based, inclusive. Both absent for a whole-file citation. */\n start?: number;\n end?: number;\n}\n\n// The line shapes are the shared pin engine's, re-exported so cite's imports and its namespace keep them.\nexport type { LineSpec, PageLines };\n\n/** The page text a citation supports. */\nexport interface CitationClaim {\n /** Body lines: counted from the first line after the frontmatter. Absent when a marker anchors the entry. */\n lines?: LineSpec;\n /** `sha256-<64 hex>` over the claimed lines, always plain. */\n integrity: string;\n}\n\n/** The lines a claim rests on. */\nexport interface CitationSource {\n /** Root-relative posix path, or `~` and the path encrypted with the family key. */\n file: string;\n /** File lines. Absent pins the whole file. */\n lines?: LineSpec;\n /** `sha256-<64 hex>`, or `hmac-sha256-<64 hex>` exactly when `file` is encrypted. */\n integrity: string;\n /** The git commit hash the pin was taken at: 7 to 64 lowercase hex. */\n \"commit-sha\"?: string;\n}\n\n/** One entry of `citations`, as the schema (`manni:citations:1.0.0`) spells it. */\nexport interface Citation {\n id?: string;\n claim?: CitationClaim;\n source: CitationSource;\n quote?: boolean;\n}\n\n/** Where an entry is kept: the page's frontmatter, or a manifest a collection declares. */\nexport type OriginKind = \"frontmatter\" | \"manifest\";\n\n/** Where an entry sits. */\nexport interface CitationOrigin {\n kind: OriginKind;\n /** The file the entry sits in: the page for frontmatter, the manifest otherwise. */\n file: string;\n /** Line of the entry in that file. */\n line?: number;\n /** Index in the page's `citations` list. */\n index: number;\n}\n\n/**\n * One entry handed to `checkCitations` from outside the page, already merged\n * from a manifest. `entry` is the raw value and is validated as a frontmatter\n * entry is; its index is its position in the list.\n */\nexport interface CitationInput {\n entry: unknown;\n origin: { kind: OriginKind; file: string; line?: number };\n}\n\n/** How a citation's claim is anchored: by its lines, by a body marker, or not at all. */\nexport type CitationAnchor = \"claim\" | \"marker\" | null;\n\nexport type SourceStatus =\n | \"current\"\n | \"moved\"\n | \"moved-ambiguous\"\n | \"changed\"\n | \"missing\"\n | \"never-true\"\n | \"skipped\";\n\nexport type ClaimStatus =\n | \"current\"\n | \"moved\"\n | \"moved-ambiguous\"\n | \"reanchored\"\n | \"changed\"\n | \"skipped\";\n\n/** Where a misplaced marker is, and where it belongs (proposal 0054). */\nexport interface MisplacedMarkerReport {\n /** The paragraph the marker's run splits, in file lines. */\n unit: string;\n /** The file line the marker takes once its run has moved. */\n to: number;\n}\n\n/** The marker that anchors a citation: its line, and its misplacement when it has one. */\nexport interface MarkerEnd {\n /** File line of the marker. */\n line: number;\n /** Present only when the marker line sits inside a paragraph. */\n misplaced?: MisplacedMarkerReport;\n}\n\n/**\n * Why a source could not be read: not a tracked file under the root, an\n * encrypted source with no key to decrypt it, one that does not decrypt under\n * the key there is, or a tracked file that could not be read.\n */\nexport type MissingReason = \"untracked\" | \"no-key\" | \"undecryptable\" | \"unreadable\";\n\n/**\n * Every rule a finding can carry, stated once. The union and the default\n * severity table are derived from this array so the three cannot disagree.\n */\nexport const CITE_RULES = [\n \"source-moved\",\n \"source-moved-ambiguous\",\n \"source-changed\",\n \"source-never-true\",\n \"source-missing\",\n \"claim-moved\",\n \"claim-moved-ambiguous\",\n \"claim-reanchored\",\n \"claim-changed\",\n \"marker-orphan\",\n \"marker-invalid\",\n \"marker-repeated\",\n \"marker-misplaced\",\n \"anchor-invalid\",\n \"entry-invalid\",\n \"quote-drift\",\n] as const;\nexport type CiteRule = (typeof CITE_RULES)[number];\n\n/**\n * A rule's level: the family scale (`src/shared/severity.ts`) plus `off`,\n * which drops the rule's findings altogether.\n */\nexport type CiteSeverity = Severity | \"off\";\n\n/** The claim end of a classified citation. Line specs are `\"L\"` or `\"L1-L2\"`. */\nexport interface ClaimEnd {\n /** The entry's body lines. Absent when a marker anchors the claim. */\n lines?: string;\n /** Where the claim is judged, in file lines: the recorded lines, or what the marker anchors. */\n fileLines?: string;\n status: ClaimStatus;\n /** For `moved`: the new body lines. */\n newLines?: string;\n /** For `moved-ambiguous`: every candidate, in body lines. */\n candidates?: string[];\n /** For `moved`: the new file lines. Pretty-only. */\n newFileLines?: string;\n /** For `moved-ambiguous`: every candidate, in file lines. Pretty-only. */\n candidateFileLines?: string[];\n /** For `changed`: the page lines at the claim now, for `--show-diff`. Pretty-only. */\n text?: string[];\n /**\n * For `changed` and `reanchored`: the baseline, the newest commit whose\n * page held the pin. Derived from the page's history, never stored (0053).\n */\n commitSha?: string;\n /** For `changed`: `false` when the walk hit a shallow boundary or its cap. */\n historyAvailable?: boolean;\n /** Subjects of the commits that touched the page since the baseline. Pretty-only. */\n commitsSince?: string[];\n /** Unified diff of the claim's lines since the baseline. Pretty-only, `--show-diff`. */\n diff?: string;\n /**\n * The claim's lines as they were at the baseline. Never serialized: it is\n * what `update --accept` reads to tell an edit from a replacement.\n */\n baselineText?: string[];\n}\n\n/** The source end of a classified citation. */\nexport interface SourceEnd {\n /** `file` and `lines` as the entry spells them: `path`, `path:L`, `path:L1-L2`, the ciphertext for `path`. */\n src: string;\n status: SourceStatus;\n /**\n * The path an encrypted source decrypted to. Never printed except by the\n * pretty reporter under `--reveal`; never serialized to a machine format.\n */\n resolvedPath?: string;\n /**\n * The path a moved encrypted source's `newSrc` decrypts to. Printed only by\n * the pretty reporter under `--reveal`; never serialized to a machine format.\n */\n resolvedNewPath?: string;\n /** For `missing`: why the source could not be read. Composes the message, which never names a path. */\n missingReason?: MissingReason;\n /**\n * For `moved`: the new file lines. For `changed`: the span the pinned\n * range's old first and last lines now cover, when each sits exactly once\n * and in order (proposal 0055).\n */\n newLines?: string;\n /**\n * For `moved`: the new `src`, spelled as the entry spells sources. It names\n * another file when the pin followed its text across one, and carries the\n * new path encrypted for an encrypted source.\n */\n newSrc?: string;\n /** For `moved-ambiguous`: every candidate `src`. */\n candidates?: string[];\n /** The commit the pin was taken at. */\n commitSha?: string;\n /** For `changed` with a commit: whether git could show that commit. */\n historyAvailable?: boolean;\n /** Subjects of commits touching the path since the commit. Pretty-only. */\n commitsSince?: string[];\n /** Unified diff of the path since the commit. Pretty-only, `--show-diff`. */\n diff?: string;\n /** The move search hit its byte budget before covering the file. */\n truncatedSearch?: boolean;\n /**\n * The truncation happened across the files a commit touched rather than\n * inside one file, which is the other half of the notice a run raises. Never\n * serialized: `truncatedSearch` stays the one boolean the output carries.\n */\n truncatedAcross?: boolean;\n}\n\n/** One classified citation: both ends, and how it is anchored. */\nexport interface CitationResult {\n citation: Citation;\n origin: CitationOrigin;\n anchor: CitationAnchor;\n /** File line of the marker that names the entry, when one does. */\n markerLine?: number;\n /**\n * File line the citation anchors to now: the claim's first line, or the\n * first line of the text a marker anchors. Where its findings sit.\n */\n anchorLine?: number;\n /** The marker that names the entry, when one does, and its misplacement. */\n marker?: MarkerEnd;\n /** `null` for an entry with no `claim`: a bare pin, or a marker with no drift check. */\n claim: ClaimEnd | null;\n source: SourceEnd;\n}\n\nexport interface CitationFinding {\n rule: CiteRule;\n /** `manni:cite/<rule>`. */\n ruleId: string;\n /** On the family scale: an `error` fails the file; a `warning` or a `notice` is reported and never does. */\n severity: Severity;\n message: string;\n /** Line the finding anchors to: in the page, or in `file` when that is set. */\n line?: number;\n /** The manifest, when the finding sits there rather than on the page. */\n file?: string;\n id?: string;\n /** The source, spelled as the entry spells it. */\n src?: string;\n newSrc?: string;\n /** Index in the page's `citations` for a finding about one entry. */\n index?: number;\n}\n\nexport interface PageCitationReport {\n file: string;\n format: string;\n citations: CitationResult[];\n findings: CitationFinding[];\n /** Run-level advice, said once per run by the caller: shallow clone, root fallback. */\n notices: string[];\n}\n\n/** What `showFile` answers: the bytes, or why it could not. */\nexport type ShownFile = { text: string } | { missing: \"commit\" | \"path\" };\n\n/** One commit that touched a path. */\nexport interface PageCommit {\n /** The full hash. */\n sha: string;\n subject: string;\n}\n\n/**\n * What `pageCommits` answers: the commits that touched a path, newest first.\n * `shallow` is a repository whose oldest commit may have an unfetched parent,\n * and `truncated` a list the cap cut short. Either means a walk that exhausts\n * the list cannot say the pin never held.\n */\nexport interface PageHistory {\n commits: PageCommit[];\n shallow: boolean;\n truncated: boolean;\n}\n\n/**\n * A thin git client over `execFile(\"git\", …)`, memoized per call shape so a\n * page with a thousand citations against one path runs one `git show`.\n */\nexport interface GitClient {\n available(): Promise<boolean>;\n head(): Promise<string | null>;\n /** Tracked files, posix, relative to the root. */\n lsFiles(): Promise<string[]>;\n showFile(commit: string, path: string): Promise<ShownFile>;\n subjectsSince(commit: string, path: string): Promise<string[]>;\n diffSince(commit: string, path: string): Promise<string>;\n /**\n * Paths whose content differs between `commit` and `HEAD`: committed\n * changes only. The candidate list a pin is followed across (proposal\n * 0055). A client without it follows no source out of its own file.\n */\n changedSince?(commit: string): Promise<string[]>;\n /**\n * The commits that touched `path`, newest first, at most `cap` of them. A\n * client without it reads no claim history, so a claim that no longer holds\n * is `changed` with no baseline.\n */\n pageCommits?(path: string, cap: number): Promise<PageHistory>;\n /**\n * Whether the clone is shallow, so a commit it lacks may still be in the\n * history. A client without it, or without `isAncestor`, never re-records\n * a commit for being outside the history.\n */\n shallow?(): Promise<boolean>;\n /**\n * Whether `commit` is `of` or one of its ancestors. A commit the clone does\n * not have is not.\n */\n isAncestor?(commit: string, of: string): Promise<boolean>;\n}\n\n/**\n * The files a source may resolve to. Built from `git ls-files` when git is\n * available, else from a walk that follows no symlinks. Every entry is\n * realpath-contained in the root.\n */\nexport interface SourceIndex {\n files(): readonly string[];\n /** Whether `path` is a tracked file under the root. An encrypted source is decrypted first, then asked here. */\n has(path: string): boolean;\n}\n\n/**\n * What one run has read so far: each tracked file once, with its lines split\n * once. A run makes one with `createSourceCache` and passes it to every\n * `readSource` it makes, so a source cited a hundred times is read once. It\n * holds whatever the files said when first read, so a run that rewrites files\n * it may later read as sources makes none.\n */\nexport type SourceCache = Map<string, Promise<{ text: string; lines: readonly string[] } | undefined>>;\n\nexport interface CheckPageOptions {\n /** Absolute directory source paths resolve from. */\n root: string;\n /** Default true. False: page-side rules only; every source status is `skipped`. Claim ends are still judged. */\n checkSources?: boolean;\n /**\n * The encryption key: decrypts encrypted sources and keys their pins.\n * Absent, an encrypted citation is `missing` (no key to decrypt it).\n */\n key?: string;\n severity?: Partial<Record<CiteRule, CiteSeverity>>;\n /**\n * The git client the source index and history are read through. Defaults\n * to one over the root, which is used whenever git is on PATH and the root\n * is inside a work tree. A caller that wants no git at all passes `noGit()`.\n */\n gitClient?: GitClient;\n /**\n * Directory the page's own path resolves from, and so the repository its\n * history is read in. Defaults to `root`, the same directory unless\n * `--root` sent the sources to another checkout.\n */\n pageRoot?: string;\n /** The client the page's history is read through. Defaults to one over `pageRoot`. */\n pageGitClient?: GitClient;\n /** How many commits the claim history walk reads. Defaults to `MAX_PAGE_COMMITS`. */\n pageCommitCap?: number;\n sourceIndex?: SourceIndex;\n /** Source files already read this run (`createSourceCache`); absent, each citation reads its own. */\n sourceCache?: SourceCache;\n /**\n * The page's citations as merged from a manifest, each with where it sits.\n * Given, the page's own frontmatter `citations` is not read. Without it, a\n * grader calling `checkCitations` on a sidecar page would find no citations.\n */\n citations?: readonly CitationInput[];\n /**\n * The manifest that owns this page's `citations`, when one does. A page\n * that carries its own anyway is `entry-invalid`, in meta's `external:owned`\n * words.\n */\n owned?: { file: string; collection: string };\n}\n\nexport interface MintOptions {\n root: string;\n /** `path`, `path:L`, `path:L1-L2`, or an encrypted `~file` with the same line forms. */\n src: string;\n id?: string;\n /** The claim pin, already taken over the page lines. */\n claim?: CitationClaim;\n quote?: boolean;\n /** A commit to record; `false` records none; absent records HEAD when git has one. */\n commitSha?: string | false;\n /**\n * Write `file` encrypted and pin the lines with the keyed pin; needs `key`.\n * A source that is already encrypted stays encrypted either way.\n */\n encrypt?: boolean;\n /** The encryption key: encrypts, decrypts an encrypted source, and keys its pin. */\n key?: string;\n gitClient?: GitClient;\n sourceIndex?: SourceIndex;\n}\n\n/**\n * One replacement against a fixed text: the bytes `[start, end)` become\n * `text`. A writer that has a position from a parse hands back an edit rather\n * than a rewritten page, so several of them can be collected against that one\n * parse and applied together (`applyEdits`). Nothing is then read out of a\n * text that has already been written to.\n */\nexport interface TextEdit {\n start: number;\n end: number;\n text: string;\n}\n\n/** One marker found in a page body: `cite <id>` in the format's comment syntax. */\nexport interface InlineStatement {\n /** File line of the marker. */\n line: number;\n /** File line of the anchored text: the rest of the marker's line, else the paragraph or block that follows. */\n anchorLine?: number;\n /**\n * The ids the marker names, in the order written, or why the marker is not\n * read. A payload of one id is what proposal 0044 shipped; 0056 widened it\n * to a space-separated list, and every id in the list anchors the same text.\n */\n payload:\n | { kind: \"ref\"; ids: [string, ...string[]] }\n | { kind: \"bad\"; reason: string; json?: boolean };\n /** The marker text between the delimiters, trimmed. */\n raw: string;\n /** Character offsets of the whole marker in the file, for rewriting. */\n start: number;\n end: number;\n}\n\n/** A validated citation with where it sits and the marker that names it, before classification. */\nexport interface PageCitation {\n citation: Citation;\n origin: CitationOrigin;\n /** The first marker naming the entry's id. */\n marker?: InlineStatement;\n}\n\n/** What `readPage` returns: the entries, the markers, and page-side findings. */\nexport interface PageCitations {\n file: string;\n format: string;\n content: string;\n /** Offset where the body starts (just past the closing fence, or 0). */\n bodyOffset: number;\n /** File line of body line 1: the first line after the frontmatter, or 1. */\n bodyLine: number;\n citations: PageCitation[];\n statements: InlineStatement[];\n findings: CitationFinding[];\n}\n\nexport interface CheckOptions {\n /** Positional inputs; empty means the configured collections' `paths:` (0041). */\n inputs: string[];\n /**\n * `--collection <name>`, repeatable: the collections this run covers. Empty\n * or absent means every declared one; see `selectCollections`.\n */\n collection?: string[];\n exts?: string[];\n /** `--exclude`, appended to the selected collections' `exclude:` when the run reads from them. */\n exclude?: string[];\n as?: string;\n configPath?: string;\n noConfig?: boolean;\n cwd?: string;\n stdinContent?: string;\n allowEmpty?: boolean;\n respectGitignore?: boolean;\n onNotice?: (message: string) => void;\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n baseline?: string | boolean;\n writeBaseline?: string | boolean;\n /** `--no-check-sources` (false): page-side rules only. Absent leaves `checkSources:` in charge. */\n checkSources?: boolean;\n /**\n * `--show-diff`: the report will want diffs and commit subjects. The check\n * is the same either way; the run only says, once, when git is not there\n * to give them.\n */\n showDiff?: boolean;\n root?: string;\n /**\n * The git client every page is checked through. Defaults to one over the\n * root, used whenever git is on PATH and the root is inside a work tree; a\n * test hands in a fake.\n */\n gitClient?: GitClient;\n /**\n * The client every page's own history is read through, over the directory\n * the page paths resolve from. Defaults to one there; a test hands in a fake.\n */\n pageGitClient?: GitClient;\n /** Defaults to `process.env`; read for `MANNI_ENCRYPTION_KEY`. A test hands in its own. */\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface CheckRun {\n results: ValidationResult[];\n summary: import(\"../meta/index.js\").RunSummary;\n frame: import(\"../meta/index.js\").FingerprintContext;\n pages: PageCitationReport[];\n warnings: number;\n notices: number;\n}\n\n\nexport interface AddOptions {\n page: string;\n /** The claim's lines as an editor numbers them (`page:L`, `page:L1-L2`). Absent: a bare pin. */\n pageLines?: PageLines;\n src: string;\n id?: string;\n /** Write a marker above the page lines instead of claim lines, and pin the text it anchors. Needs `pageLines` and `id`. */\n marker?: boolean;\n /** The page lines are a fenced block that reproduces the source. Needs `pageLines`. */\n quote?: boolean;\n /**\n * `--encrypt`: write `file` encrypted, with a keyed pin, even when no key is\n * available yet, in which case `confirm` is asked whether to generate one.\n * An available key encrypts every add without it, so `false` and absent\n * are the same.\n */\n encrypt?: boolean;\n /** `false` records no `commit-sha`. */\n commitSha?: boolean;\n dryRun?: boolean;\n as?: string;\n configPath?: string;\n noConfig?: boolean;\n cwd?: string;\n stdinContent?: string;\n root?: string;\n /**\n * The git client HEAD and the source index are read through. Defaults to\n * one over the root; a test hands in a fake.\n */\n gitClient?: GitClient;\n /** Defaults to `process.env`; read for `MANNI_ENCRYPTION_KEY`. A test hands in its own. */\n env?: NodeJS.ProcessEnv;\n onNotice?: (message: string) => void;\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n /**\n * Asked when `encrypt` needs a key and there is none; the CLI passes\n * `terminalConfirm()`. Absent, the add refuses instead of asking.\n */\n confirm?: Confirm;\n}\n\n/** The manifest half of a write: what it says now, and whether it was saved. */\nexport interface ManifestWrite {\n /** The manifest as the run reports it. */\n file: string;\n /** 1-based line the written entry now sits on. */\n line: number;\n /** The whole manifest, rewritten. */\n content: string;\n diff: string;\n written: boolean;\n}\n\nexport interface AddResult {\n file: string;\n citation: Citation;\n /**\n * Where the entry was written: the page's frontmatter, or the manifest the\n * page's collection declares. The config decides, not a flag.\n */\n placed: \"frontmatter\" | \"manifest\";\n /** The manifest the entry went to, under `placed: \"manifest\"`. */\n manifest?: ManifestWrite;\n /** File lines of the claim after the write: the claim lines, or the text the marker anchors. */\n claimLines?: PageLines;\n /** File line of the marker that names the entry, under `marker`. */\n markerLine?: number;\n /**\n * Whether the id joined the list of a marker already there, rather than\n * getting a marker line of its own. A join moves no line on the page.\n */\n markerJoined?: boolean;\n /**\n * The first pinned source line, as the file holds it, so a mis-typed range\n * is visible at write time. Absent for a whole file, which has no first\n * line worth naming, and for an encrypted source, which no output reveals.\n */\n sourceLine?: string;\n /** The rewritten page. */\n content: string;\n diff: string;\n written: boolean;\n}\n\nexport interface UpdateOptions extends Omit<CheckOptions, \"baseline\" | \"writeBaseline\"> {\n accept?: boolean;\n only?: string[];\n dryRun?: boolean;\n /**\n * Re-record `commit-sha` where the recorded commit does not contain the\n * pinned lines. Rewrites that one field and nothing else.\n */\n recommit?: boolean;\n}\n\n/**\n * One end `update` rewrote.\n *\n * Read the typed pairs: `fromLines`/`toLines` for lines, `fromPin`/`toPin`\n * for pins. `from` and `to` carry the same values, but which of the two a row\n * holds depends on the row, so they are easy to misuse.\n */\n/** Why `--recommit` re-recorded a commit. */\nexport type RecommitReason = \"not-contained\" | \"not-in-history\";\n\nexport interface UpdateRewrite {\n id?: string;\n /** Index in the page's `citations`. */\n index: number;\n /** File line of the entry. */\n line?: number;\n end: \"claim\" | \"source\" | \"marker\";\n /**\n * `re-anchored` covers both re-pins: the pin held over another span (0054),\n * and the words held while the anchor moved (0053). `status` is what tells\n * those apart. `replaced` is a claim `--accept` refused to re-pin.\n */\n reason: \"moved\" | \"accepted\" | \"re-anchored\" | \"shifted\" | \"replaced\" | \"recommitted\";\n /**\n * The status that was repaired. `replaced` is a claim whose line held\n * wholly other text, accepted because `--only` named it.\n */\n status: \"moved\" | \"changed\" | \"reanchored\" | \"replaced\" | \"never-true\" | \"misplaced\" | \"current\";\n /**\n * Before and after. A moved or shifted claim, and a moved marker: file\n * lines. A moved source: its `src`. An accepted or re-anchored end: its pin.\n * The typed pairs below say which, so prefer them.\n */\n from: string;\n to: string;\n /** A moved marker, or a moved or shifted claim: its file lines, before and after. */\n fromLines?: string;\n toLines?: string;\n /** An accepted or re-anchored end: its pin, before and after. */\n fromPin?: string;\n toPin?: string;\n /** A re-committed source: the commit it recorded, and the one it records now. */\n fromCommit?: string;\n toCommit?: string;\n /**\n * A re-committed source: why the recorded commit could not stand.\n * `not-contained`: it does not hold the pinned lines. `not-in-history`: it\n * holds them, but is not in the history of HEAD.\n */\n because?: RecommitReason;\n /** A re-anchored claim: the span that held, in file lines. */\n lines?: string;\n /** A re-anchored claim: the span now pinned, in file lines. */\n newLines?: string;\n /** An accepted, re-anchored or refused claim: the file line of its first body line. */\n at?: number;\n /** An accepted claim a marker anchors: the marker's file line. Pretty-only. */\n markerLine?: number;\n /** An accepted claim: the text now pinned, whitespace collapsed. */\n text?: string;\n /** An accepted source: its `src`. */\n src?: string;\n /**\n * An accepted source: the commit recorded in the entry, when it records\n * one. A re-anchored or refused claim: the baseline its words were read\n * against.\n */\n commitSha?: string;\n /**\n * A refused claim the word-overlap test refused: the share of the claim's\n * words, from 0 to 1, that its line still holds. Absent on a claim the\n * sentence test refused, which is how a report tells the two apart.\n */\n wordShare?: number;\n}\n\nexport interface UpdatePage {\n file: string;\n rewritten: UpdateRewrite[];\n /**\n * Claims `--accept` refused to re-pin, because the stored first line now\n * holds text that shares no sentence with the claim at its baseline, or too\n * few of its words. Each carries `reason: \"replaced\"`, and each is work left\n * undone: exit 1.\n */\n refused: UpdateRewrite[];\n skipped: CitationFinding[];\n diff: string;\n written: boolean;\n /** The rewritten page, for the stdin input only: it has no file to be written to. */\n content?: string;\n}\n\n/** One manifest a run rewrote: what changed in it, and whether it was saved. */\nexport interface ManifestChange {\n /** The manifest as the run reports it. */\n file: string;\n diff: string;\n written: boolean;\n}\n\nexport interface UpdateRun {\n pages: UpdatePage[];\n rewritten: number;\n skipped: number;\n /** The manifests this run rewrote, each written once however many pages it holds. */\n manifests?: ManifestChange[];\n exitCode: 0 | 1;\n}\n\nexport interface RemoveOptions\n extends Omit<CheckOptions, \"baseline\" | \"writeBaseline\" | \"checkSources\" | \"showDiff\"> {\n /**\n * `--only <id>`, repeatable: the entries to remove, each named by its id or\n * by its pointer (`/citations/N`). Required, and an empty list is a\n * refusal: `remove` never takes every citation off a page.\n */\n only: string[];\n dryRun?: boolean;\n}\n\n/** One entry `remove` took out, and the markers that went with it. */\nexport interface Removal {\n id?: string;\n /** Index in the page's `citations`. Absent for a marker that named no entry. */\n index?: number;\n /** Where the entry was kept. Absent for a marker that named no entry. */\n origin?: { kind: OriginKind; file: string; line?: number };\n /** File lines of the markers removed with it, in the page as it was. */\n markerLines: number[];\n}\n\nexport interface RemovePage {\n file: string;\n removed: Removal[];\n diff: string;\n written: boolean;\n /** The rewritten page, for the stdin input only: it has no file to be written to. */\n content?: string;\n}\n\nexport interface RemoveRun {\n pages: RemovePage[];\n /** Entries removed, counting a marker that named no entry as one. */\n removed: number;\n /** The manifests this run rewrote, each written once however many pages it holds. */\n manifests?: ManifestChange[];\n}\n\n/** One citation `reencryptCitations` rewrote: where it sits, and its source before and after. */\nexport interface ReencryptedCitation {\n id?: string;\n /** Index in `citations`. */\n index?: number;\n /** File line of the entry. */\n line?: number;\n /** `file` and its line suffix, under the old key and under the new. */\n from: string;\n to: string;\n}\n\n/** What `reencryptCitations` did to one page. */\nexport interface ReencryptCitationsResult {\n /** The page with every re-encrypted citation rewritten; the input itself when none was. */\n content: string;\n rewritten: ReencryptedCitation[];\n /** Citations that could not be re-encrypted, and why. A message never names a path. */\n skipped: { id?: string; index?: number; line?: number; message: string }[];\n}\n\n/**\n * Config under `cite:` in manni.config.yaml, camelCase as `meta:` is. The\n * document set is not here: proposal 0041 moved `paths` and `exclude` to the\n * family-level `collections:` list, which every tool reads. Neither is the\n * encryption key, the top-level `encryptionKey:` every tool reads (0045).\n */\nexport interface CiteConfig {\n allowEmpty?: boolean;\n respectGitignore?: boolean;\n root?: string;\n baseline?: string;\n checkSources?: boolean;\n severity?: Partial<Record<CiteRule, CiteSeverity>>;\n}\n\nexport interface LoadedCiteConfig {\n config: CiteConfig;\n path: string;\n dir: string;\n /** The file as the user would name it, for messages. */\n source: string;\n /** The family file's top-level `collections:`, parsed by the shared layer (0041). */\n collections: CollectionConfig[];\n}\n\n/** What every command core resolves before touching a file. */\nexport interface CiteRun {\n config: CiteConfig | null;\n /** The positional inputs, or the selected collections' `paths:` in declaration order. */\n inputs: string[];\n /** Directory the inputs resolve from: cwd for positional inputs, the config directory for collections. */\n base: string;\n /**\n * The collections this run covers: every declared one, or the ones\n * `--collection` named. `[]` when no config governs the run.\n */\n collections: CollectionConfig[];\n /** Whether `inputs` came from the collections rather than the command line. */\n fromCollections: boolean;\n configDir?: string;\n configPath?: string;\n /** The config file as the user would name it, for messages. */\n configSource?: string;\n /** Absolute root source paths resolve from. */\n root: string;\n /**\n * The family encryption key (proposal 0045): `MANNI_ENCRYPTION_KEY`, else\n * the config's top-level `encryptionKey:`. Absent when neither is set.\n */\n key?: string;\n /** Where `key` came from. The environment wins over the config. */\n keySource: KeySource;\n /**\n * The config file that governs the run, as discovery found it. A write\n * that needs a key (`add --encrypt` with none) puts one there.\n */\n configFile?: ConfigFile;\n}\n","/**\n * Which rules fail a run, which only warn, and which are notices.\n *\n * Warnings and notices never affect the exit code (docevals' rule).\n * `source-moved` is a warning because `cite update` fixes it mechanically,\n * and a PR job that failed on it would make the ratchet noisy. `claim-moved`\n * is a notice: the text is found verbatim, so nothing drifted.\n * `claim-reanchored` is a notice for the same reason (proposal 0053): the\n * words the pin covered are found unchanged since the baseline, so only the\n * layout moved, and plain `cite update` re-pins it.\n * `claim-changed` is a warning, since it fires on any edit to a pinned\n * paragraph, a typo fix beside the cited sentence included. A repository that\n * wants either hard sets `severity: { claim-changed: error }`.\n * `marker-misplaced` is a warning too: it annotates the pull request, and one\n * `cite update` clears it, so a job that failed on it would block on a page\n * that was fine yesterday (proposal 0054, stress test 15).\n */\nimport { CITE_RULES, type CiteRule, type CiteSeverity } from \"../types.js\";\n\nexport const DEFAULT_SEVERITY: Readonly<Record<CiteRule, CiteSeverity>> = {\n \"source-moved\": \"warning\",\n \"source-moved-ambiguous\": \"error\",\n \"source-changed\": \"error\",\n \"source-never-true\": \"error\",\n \"source-missing\": \"error\",\n \"claim-moved\": \"notice\",\n \"claim-moved-ambiguous\": \"warning\",\n \"claim-reanchored\": \"notice\",\n \"claim-changed\": \"warning\",\n \"marker-orphan\": \"error\",\n \"marker-invalid\": \"error\",\n \"marker-repeated\": \"warning\",\n \"marker-misplaced\": \"warning\",\n \"anchor-invalid\": \"error\",\n \"entry-invalid\": \"error\",\n \"quote-drift\": \"error\",\n};\n\nexport const RULE_ID_PREFIX = \"manni:cite\";\n\n/** `manni:cite/<rule>`: the SARIF rule id and the JUnit failure type. */\nexport function ruleId(rule: CiteRule): string {\n return `${RULE_ID_PREFIX}/${rule}`;\n}\n\nexport function isCiteRule(value: string): value is CiteRule {\n return (CITE_RULES as readonly string[]).includes(value);\n}\n\n/** The effective severity table: defaults with the config's overrides. */\nexport function resolveSeverity(\n overrides?: Partial<Record<CiteRule, CiteSeverity>>,\n): Record<CiteRule, CiteSeverity> {\n return { ...DEFAULT_SEVERITY, ...(overrides ?? {}) };\n}\n","/**\n * Markers: `cite <id> [<id>…]` inside the format's comment syntax.\n *\n * | Format | Forms |\n * |---------------|------------------------------------------------------------------------------------|\n * | markdown, mdx | `<!-- cite a b -->`, `{/* cite a b *\\/}`, `[comment]: # (cite a b)` |\n * | html, xml | `<!-- cite a b -->` |\n * | asciidoc | `// (cite a b)` |\n * | rst | `.. (cite a b)` |\n *\n * A marker carries one or more ids, separated by spaces, and nothing else\n * (`cite true` names id `true`). Every id in the list anchors the text the\n * marker anchors, so a paragraph resting on four sources carries one comment\n * rather than four (proposal 0056). An id cannot hold `(`, `)`, `{`, `}`, `<`,\n * `>` or a leading `-`, so no list can close a parenthesised comment early.\n *\n * A word starting with `{` was the inline entry of proposal 0044's first\n * draft; it is `marker-invalid` now, because an entry lives in frontmatter or\n * a manifest and a source is never written into the body. The scanner uses\n * `indexOf` for the delimiters, never a regex over the whole page, and is\n * handed the body only, so a `cite` inside frontmatter is never matched.\n *\n * It does not read code. An opener inside a fenced block or a backtick span,\n * as `src/shared/code-regions.ts` finds them, is skipped, so a page that\n * documents the syntax carries no statements.\n *\n * Every form parses in both markdown and mdx. The first form is what\n * `formatStatement` writes: the html comment for markdown, the jsx comment\n * for mdx, which rejects an html comment.\n */\nimport type { InlineStatement, TextEdit } from \"../types.js\";\nimport { codeEndAt, codeRegions } from \"../../shared/code-regions.js\";\nimport { CiteError } from \"../errors.js\";\n\nexport interface StatementForm {\n open: string;\n close: string;\n}\n\nconst HTML_COMMENT: StatementForm = { open: \"<!--\", close: \"-->\" };\nconst JSX_COMMENT: StatementForm = { open: \"{/*\", close: \"*/}\" };\nconst LINK_REFERENCE: StatementForm = { open: \"[comment]: # (\", close: \")\" };\nconst MARKDOWN_FORMS: readonly StatementForm[] = [HTML_COMMENT, JSX_COMMENT, LINK_REFERENCE];\nconst MDX_FORMS: readonly StatementForm[] = [JSX_COMMENT, HTML_COMMENT, LINK_REFERENCE];\nconst COMMENT_FORMS: readonly StatementForm[] = [{ open: \"<!--\", close: \"-->\" }];\nconst ASCIIDOC_FORMS: readonly StatementForm[] = [{ open: \"// (\", close: \")\" }];\nconst RST_FORMS: readonly StatementForm[] = [{ open: \".. (\", close: \")\" }];\n\nconst ID = /^[a-z0-9][a-z0-9-]*$/;\n\n/**\n * A fence opener in any format. `paragraphAfter` reads it whether or not it\n * was given a format, and so does the claim search (`claims.ts`), so every\n * family's opener counts; the per-format locators below are what `quote`\n * anchoring uses.\n * A markdown fence keeps its meaning when indented, as inside a list item, so\n * it is read there too, matching the code skip in `src/shared/code-regions.ts`; the\n * asciidoc `----` stays at column 0.\n */\nexport const ANY_FENCE = /^(?:[ \\t]*(?:`{3,}|~{3,})|-{4,})/;\nconst MARKDOWN_FENCE = /^(`{3,}|~{3,})/;\nconst ASCIIDOC_FENCE = /^(-{4,})/;\n/** The forms per extractor name. Unknown formats have none. */\nexport function statementForms(format: string): readonly StatementForm[] {\n switch (format) {\n case \"markdown\":\n return MARKDOWN_FORMS;\n case \"mdx\":\n return MDX_FORMS;\n case \"html\":\n case \"xml\":\n return COMMENT_FORMS;\n case \"asciidoc\":\n return ASCIIDOC_FORMS;\n case \"rst\":\n return RST_FORMS;\n default:\n return [];\n }\n}\n\n/** The fence-opener pattern for a format, or undefined when it has no locator. */\nfunction fenceFor(format: string): RegExp | undefined {\n switch (format) {\n case \"markdown\":\n case \"mdx\":\n return MARKDOWN_FENCE;\n case \"asciidoc\":\n return ASCIIDOC_FENCE;\n default:\n return undefined;\n }\n}\n\n/** Offset of the terminator of the line containing `pos` (or the text length). */\nfunction lineEnd(content: string, pos: number): number {\n const nl = content.indexOf(\"\\n\", pos);\n return nl === -1 ? content.length : nl;\n}\n\n/** The text of the line `[pos, end)`, without a trailing CR. */\nfunction lineText(content: string, pos: number, end: number): string {\n const text = content.slice(pos, end);\n return text.endsWith(\"\\r\") ? text.slice(0, -1) : text;\n}\n\n/** `end` pulled back over a CR so a CRLF terminator is excluded whole. */\nfunction beforeCr(content: string, end: number): number {\n return end > 0 && content.charCodeAt(end - 1) === 13 ? end - 1 : end;\n}\n\n/**\n * Where a forward scan of whole lines starts from `offset`: the next line when\n * `offset` sits inside one (the rest of a statement's own line), the line\n * itself when `offset` is already at its start.\n */\nfunction nextLineStart(content: string, offset: number): number {\n if (offset === 0 || content.charCodeAt(offset - 1) === 10) return offset;\n return lineEnd(content, offset) + 1;\n}\n\n/**\n * A marker holds at most 25 ids. Past that it is `marker-invalid`, on the\n * same grounds as the 500 markers a page may hold: an unbounded list is an\n * unbounded allocation from a file the tool did not write. The cap counts\n * ids rather than characters, because a character cap moves with how long\n * the ids happen to be. Proposal 0056 is the record.\n */\nexport const MAX_IDS_PER_MARKER = 25;\n\n/**\n * The payload, as one or more ids separated by spaces. The checks run in a\n * stated order and the first defect is the finding, so one marker raises one\n * `marker-invalid` however many of its words are wrong.\n *\n * A run of spaces separates as one, which is what a soft-wrapped editor and a\n * shell both do. A comma is never a separator: `cite a,b` is one token, that\n * token is not an id, and the message quotes it back (proposal 0034's one\n * separator per list).\n */\nfunction payloadOf(payload: string): InlineStatement[\"payload\"] {\n if (payload === \"\") return { kind: \"bad\", reason: \"empty payload\" };\n // A marker is one line: `isMarkerLine` tests one line, so half a wrapped\n // marker would land inside the pin of the text below it.\n if (/[\\r\\n]/.test(payload)) {\n return { kind: \"bad\", reason: \"a marker is one line; write two markers\" };\n }\n // Destructured rather than cast: a `ref` carries at least one id, and the\n // head is what proves it to the compiler.\n const [head, ...rest] = payload.split(\" \").filter((word) => word !== \"\");\n if (head === undefined) return { kind: \"bad\", reason: \"empty payload\" };\n const words: [string, ...string[]] = [head, ...rest];\n // An entry lives in frontmatter or a manifest; the body carries names. This\n // runs before the id test so the more actionable message fires.\n if (words.some((word) => word.startsWith(\"{\"))) {\n return { kind: \"bad\", reason: \"a JSON payload\", json: true };\n }\n if (words.length > MAX_IDS_PER_MARKER) {\n return {\n kind: \"bad\",\n reason: `more than ${String(MAX_IDS_PER_MARKER)} ids in one marker (${String(words.length)}); write a second marker`,\n };\n }\n const bad = words.find((word) => !ID.test(word));\n if (bad !== undefined) return { kind: \"bad\", reason: `\"${bad}\" is not an id` };\n const seen = new Set<string>();\n for (const word of words) {\n // One id named twice inside one marker has no second anchor and no winner\n // to pick, so it is a typo in one line rather than `marker-repeated`.\n if (seen.has(word)) {\n return { kind: \"bad\", reason: `\"${word}\" is named twice in one marker` };\n }\n seen.add(word);\n }\n return { kind: \"ref\", ids: words };\n}\n\n/** Whether the text between a form's delimiters is a cite statement. */\nfunction isCite(inner: string): boolean {\n return inner === \"cite\" || (inner.startsWith(\"cite\") && /\\s/.test(inner.charAt(4)));\n}\n\n/**\n * Whether a line holds one marker and nothing else, in any of the format's\n * forms. Such a line is never text a marker anchors: markers stacked above a\n * paragraph all anchor the paragraph, and none of them is part of its pin.\n */\nexport function isMarkerLine(line: string, format: string): boolean {\n const text = line.trim();\n return statementForms(format).some((form) => {\n if (text.length < form.open.length + form.close.length) return false;\n if (!text.startsWith(form.open)) return false;\n // The first close is the last thing on the line, so there is one marker.\n const closeAt = text.indexOf(form.close, form.open.length);\n if (closeAt !== text.length - form.close.length) return false;\n return isCite(text.slice(form.open.length, closeAt).trim());\n });\n}\n\n/** An ATX heading: one to six `#`, then a space or the end of the line. */\nconst ATX_HEADING = /^[ \\t]*#{1,6}([ \\t]|$)/;\n/** An asciidoc section title: one to six `=`, then a space. */\nconst ASCIIDOC_TITLE = /^={1,6}[ \\t]/;\n/**\n * A line of one punctuation character repeated three or more times, spaces\n * allowed: a setext underline, a thematic break, an rst adornment.\n */\nconst ADORNMENT = /^[ \\t]*([-=~^\"'*+#_:<>])(?:[ \\t]*\\1){2,}[ \\t]*$/;\n/** A line that is nothing but one JSX or HTML tag, opening or closing. */\nconst TAG_LINE = /^[ \\t]*<\\/?[A-Za-z][^<>]*>[ \\t]*$/;\n/** A table row: a line whose first non-blank character is a pipe. */\nconst TABLE_ROW = /^[ \\t]*\\|/;\n\n/**\n * Whether a line is a table row. The header row, the `|---|---|` delimiter row\n * and every body row all open with a pipe, so all three read as rows. Leading\n * whitespace is allowed, because a table inside a list item is indented and is\n * still a table.\n *\n * A row is a statement of its own. Nothing else separates one row from the\n * next, so a paragraph walk reads a whole table as one paragraph, and a claim\n * pinned to one row would re-pin every row below it. `unitAt` in\n * `src/cite/core/claims.ts` reads this instead, so a re-pin covers the row and\n * no more.\n */\nexport function isTableRow(line: string): boolean {\n return TABLE_ROW.test(line);\n}\n\n/**\n * A table rule: the `|---|---|` line under a header row. The outer pipes are\n * optional, a cell may carry `:` alignment markers, and the whole line may be\n * indented, because a table inside a list item is indented and is still a\n * table.\n *\n * A rule has to carry at least one `|`, which is what the leading lookahead\n * asks. Every pipe in the pattern that follows is optional on its own, so\n * without that test a bare `---` reads as a table rule, and `---` is a\n * thematic break or the underline of a setext heading instead.\n *\n * `isTableRow` reads a rule as a row, deliberately: a claim over a header, its\n * rule and a body row covers three rows and keeps all three. This asks the\n * narrower question `unitAt` needs, which is whether a span holds nothing but\n * rules. Such a span carries no words, so `update --accept` refuses to pin one.\n */\nconst TABLE_RULE = /^(?=[^|]*\\|)[ \\t]*\\|?(?:[ \\t]*:?-+:?[ \\t]*\\|)*[ \\t]*:?-+:?[ \\t]*\\|?[ \\t]*$/;\n\nexport function isTableSeparator(line: string): boolean {\n return TABLE_RULE.test(line);\n}\n\n/**\n * Whether a line is a **bound line**: one the format makes a block on its own,\n * so no paragraph continues across it, and no pin covers it beside text.\n *\n * | Format | Bound lines |\n * |---|---|\n * | markdown, mdx | An ATX heading, and a line that is nothing but one tag. |\n * | html, xml | A line that is nothing but one tag. |\n * | asciidoc | A section title. |\n * | every format | An adornment: one of `-=~^\"'*+#_:<>` repeated three or more times. |\n *\n * Proposal 0054 is the record, and its stress tests 8 and 9 say why a heading\n * and a tag line are read this way rather than joined to the text below them.\n * A tag line is bound in every format that reads one, so a marker under\n * `<body>` anchors the element below it and never the whole document.\n */\nexport function isBoundLine(line: string, format: string): boolean {\n if (ADORNMENT.test(line)) return true;\n switch (format) {\n case \"markdown\":\n case \"mdx\":\n return ATX_HEADING.test(line) || TAG_LINE.test(line);\n case \"html\":\n case \"xml\":\n return TAG_LINE.test(line);\n case \"asciidoc\":\n return ASCIIDOC_TITLE.test(line);\n default:\n return false;\n }\n}\n\n/** Scan a body for statements. `from` maps body offsets/lines to file offsets/lines. */\nexport function parseStatements(\n body: string,\n format: string,\n from: { offset: number; line: number } = { offset: 0, line: 1 },\n): InlineStatement[] {\n const out: InlineStatement[] = [];\n const fileLine = (bodyOffset: number): number =>\n from.line + lineAt(body, bodyOffset) - 1;\n const code = codeRegions(body, format);\n\n for (const form of statementForms(format)) {\n let cursor = 0;\n for (;;) {\n const at = body.indexOf(form.open, cursor);\n if (at === -1) break;\n const codeEnd = codeEndAt(code, at);\n if (codeEnd !== undefined) {\n cursor = codeEnd;\n continue;\n }\n const closeAt = body.indexOf(form.close, at + form.open.length);\n if (closeAt === -1) break;\n const end = closeAt + form.close.length;\n cursor = end;\n const inner = body.slice(at + form.open.length, closeAt).trim();\n if (!isCite(inner)) continue;\n const payload = inner.slice(4).trim();\n\n // Anchor: the rest of the close delimiter's line when it carries text,\n // else the paragraph or fenced block that follows.\n const unit = anchoredLines(body, end, format);\n const anchorLine = unit === undefined ? undefined : from.line + unit.start - 1;\n\n const statement: InlineStatement = {\n line: fileLine(at),\n payload: payloadOf(payload),\n raw: inner,\n start: from.offset + at,\n end: from.offset + end,\n };\n if (anchorLine !== undefined) statement.anchorLine = anchorLine;\n out.push(statement);\n }\n }\n return out.sort((a, b) => a.start - b.start);\n}\n\n/** `\"\\r\\n\"` when the text's first line break is CRLF, else `\"\\n\"`. */\nexport function detectEol(text: string): \"\\n\" | \"\\r\\n\" {\n const nl = text.indexOf(\"\\n\");\n return nl > 0 && text.charCodeAt(nl - 1) === 13 ? \"\\r\\n\" : \"\\n\";\n}\n\n/**\n * The paragraph starting at or after `offset` (skipping blank lines), as\n * `{ start, end, line }` file offsets and the file line it starts on. A fence\n * opener ends the search with no paragraph. Given a `format`, a marker-only\n * line is skipped like a blank one before the paragraph, and ends it after,\n * and a bound line is a unit of one line: it ends a paragraph above it, and\n * stands alone when it is the first line found.\n */\nexport function paragraphAfter(\n content: string,\n offset: number,\n format?: string,\n): { start: number; end: number; line: number } | undefined {\n const marker = (text: string): boolean => format !== undefined && isMarkerLine(text, format);\n const bound = (text: string): boolean => format !== undefined && isBoundLine(text, format);\n let pos = offset;\n // The rest of the line `offset` sits in counts when it carries text; when\n // it is blank the paragraph can only start on a later line.\n const firstEnd = lineEnd(content, pos);\n if (lineText(content, pos, firstEnd).trim() === \"\") pos = firstEnd + 1;\n\n while (pos < content.length) {\n const end = lineEnd(content, pos);\n const text = lineText(content, pos, end);\n if (text.trim() === \"\" || marker(text)) {\n pos = end + 1;\n continue;\n }\n if (ANY_FENCE.test(text)) return undefined;\n const start = pos;\n let last = end;\n // A bound line is its own unit, so it never gathers the lines under it.\n let cursor = bound(text) ? content.length : end + 1;\n while (cursor < content.length) {\n const e = lineEnd(content, cursor);\n const t = lineText(content, cursor, e);\n if (t.trim() === \"\" || ANY_FENCE.test(t) || marker(t) || bound(t)) break;\n last = e;\n cursor = e + 1;\n }\n return { start, end: beforeCr(content, last), line: lineAt(content, start) };\n }\n return undefined;\n}\n\ninterface FencedBlock {\n start: number;\n end: number;\n line: number;\n text: string;\n}\n\n/**\n * The next fenced block whose opener matches `fence`, scanning whole lines\n * from `offset`, plus the offset just past its closing fence line so a caller\n * can continue.\n */\nfunction scanFence(\n content: string,\n offset: number,\n fence: RegExp,\n): (FencedBlock & { next: number }) | undefined {\n let pos = nextLineStart(content, offset);\n while (pos < content.length) {\n const end = lineEnd(content, pos);\n const text = lineText(content, pos, end);\n const opener = fence.exec(text)?.[1];\n if (opener === undefined) {\n pos = end + 1;\n continue;\n }\n const line = lineAt(content, pos);\n const start = Math.min(end + 1, content.length);\n let cursor = start;\n while (cursor < content.length) {\n const e = lineEnd(content, cursor);\n if (lineText(content, cursor, e).startsWith(opener)) {\n return {\n start,\n end: cursor,\n line,\n text: content.slice(start, cursor),\n next: e + 1,\n };\n }\n cursor = e + 1;\n }\n return undefined;\n }\n return undefined;\n}\n\n/**\n * The fenced code block starting at or after `offset` (``` or ~~~; asciidoc\n * `----`), as file offsets of its content lines and the file line of the\n * opening fence. `undefined` for formats with no locator (html, xml, rst).\n */\nexport function fencedBlockAfter(\n content: string,\n offset: number,\n format: string,\n): { start: number; end: number; line: number; text: string } | undefined {\n const fence = fenceFor(format);\n if (!fence) return undefined;\n const block = scanFence(content, offset, fence);\n if (!block) return undefined;\n const { start, end, line, text } = block;\n return { start, end, line, text };\n}\n\n/**\n * The fenced block at `offset` in any fence family, for callers that have no\n * format at hand (the claim search). Undefined when the line at `offset` is\n * not an opener.\n */\nexport function fencedBlockAt(\n content: string,\n offset: number,\n): { start: number; end: number; line: number; text: string } | undefined {\n const pos = nextLineStart(content, offset);\n if (!ANY_FENCE.test(lineText(content, pos, lineEnd(content, pos)))) {\n return undefined;\n }\n const block =\n scanFence(content, pos, MARKDOWN_FENCE) ?? scanFence(content, pos, ASCIIDOC_FENCE);\n if (!block || block.line !== lineAt(content, pos)) return undefined;\n const { start, end, line, text } = block;\n return { start, end, line, text };\n}\n\n/** Every fenced block in the body, for `--quote` without `--claim`. */\nexport function fencedBlocks(\n content: string,\n bodyOffset: number,\n format: string,\n): { start: number; end: number; line: number; text: string }[] {\n const fence = fenceFor(format);\n if (!fence) return [];\n const out: FencedBlock[] = [];\n let pos = bodyOffset;\n for (;;) {\n const block = scanFence(content, pos, fence);\n if (!block) return out;\n const { start, end, line, text } = block;\n out.push({ start, end, line, text });\n pos = block.next;\n }\n}\n\n/** The form `formatStatement` writes for a format, or a refusal naming the format. */\nfunction writtenForm(format: string): StatementForm {\n const form = statementForms(format)[0];\n if (!form) {\n throw new CiteError(`No marker syntax for format \"${format}\".`);\n }\n return form;\n}\n\n/** Render a marker in the format's first form, e.g. `<!-- cite fetch-timeout -->`. */\nexport function formatStatement(\n format: string,\n payload: { kind: \"ref\"; ids: readonly [string, ...string[]] },\n): string {\n const form = writtenForm(format);\n // `[comment]: # (`, `// (` and `.. (` hug their parentheses; the comment\n // forms take a space inside each delimiter.\n const pad = form.open.endsWith(\"(\") ? \"\" : \" \";\n return `${form.open}${pad}cite ${payload.ids.join(\" \")}${pad}${form.close}`;\n}\n\n/**\n * The one edit that replaces a marker's payload with `ids`, as a span of\n * `content` and the text to put in it. The marker keeps its own form rather\n * than being rendered afresh, so a page that spells its markers in a form\n * `formatStatement` would not choose keeps that form, along with its\n * indentation and inner spacing.\n *\n * Returned as an edit rather than applied, so a caller with several of them\n * can collect them all against one parse and apply them together. That is how\n * `remove` rewrites a page: nothing it reads a position from has been written\n * to yet.\n *\n * `content` must be the text the statement was parsed from; the payload is\n * found inside the span the statement recorded, and the answer is undefined\n * when it is not there. The marker must also open and close on one line, since\n * a payload spanning lines would be folded onto one here, changing the line\n * count and moving every claim below it. Both callers hold to that: `remove`\n * refuses a marker line it cannot read whole, and `add` joins only a marker\n * with no line break in it.\n */\nexport function respellEdit(\n content: string,\n statement: InlineStatement,\n ids: readonly [string, ...string[]],\n): TextEdit | undefined {\n const text = content.slice(statement.start, statement.end);\n // No open delimiter carries `cite`, so the first occurrence of the trimmed\n // inner text is the payload itself.\n const at = text.indexOf(statement.raw);\n if (at === -1) return undefined;\n return {\n start: statement.start + at,\n end: statement.start + at + statement.raw.length,\n text: `cite ${ids.join(\" \")}`,\n };\n}\n\n/**\n * `content` with the marker's payload replaced by `ids`. The one-edit form of\n * `respellEdit`, for a caller rewriting a single marker; `content` unchanged\n * when the payload is not where the statement says.\n */\nexport function respellStatement(\n content: string,\n statement: InlineStatement,\n ids: readonly [string, ...string[]],\n): string {\n const edit = respellEdit(content, statement, ids);\n if (edit === undefined) return content;\n return content.slice(0, edit.start) + edit.text + content.slice(edit.end);\n}\n\n/**\n * The first line at or after `offset` that is neither blank nor a marker on\n * its own, as a 1-based line of `text`.\n */\nfunction nextTextLine(text: string, offset: number, format: string): number | undefined {\n let pos = nextLineStart(text, offset);\n while (pos < text.length) {\n const end = lineEnd(text, pos);\n const line = lineText(text, pos, end);\n if (line.trim() !== \"\" && !isMarkerLine(line, format)) return lineAt(text, pos);\n pos = end + 1;\n }\n return undefined;\n}\n\n/**\n * The fenced block opening on `line`, as the lines it spans, fences included.\n * Undefined when that line is not an opener the format knows, or the block is\n * never closed.\n */\nexport function fenceSpanAt(\n text: string,\n line: number,\n format: string,\n): { start: number; end: number } | undefined {\n const fence = fenceFor(format);\n if (!fence) return undefined;\n const block = scanFence(text, offsetOfLine(text, line), fence);\n if (!block || block.line !== line) return undefined;\n return { start: line, end: lineAt(text, block.end) };\n}\n\n/**\n * The fenced block `line` sits inside rather than opens, as the lines it\n * spans, fences included. Undefined when the line opens a block, sits in no\n * block, or the format has no fence. The closing fence counts as inside, so a\n * caller that wants a content line asks whether its span ends before the\n * block does.\n */\nexport function fenceAround(\n text: string,\n bodyOffset: number,\n line: number,\n format: string,\n): { start: number; end: number } | undefined {\n const block = fencedBlocks(text, bodyOffset, format).find(\n (b) => line > b.line && line <= lineAt(text, b.end),\n );\n return block === undefined ? undefined : { start: block.line, end: lineAt(text, block.end) };\n}\n\n/** Whether `line` sits inside a fenced block rather than opening one. */\nexport function insideFence(\n text: string,\n bodyOffset: number,\n line: number,\n format: string,\n): boolean {\n return fenceAround(text, bodyOffset, line, format) !== undefined;\n}\n\n/**\n * The paragraph or fenced block that holds `line`, as the lines it spans,\n * fences included: what a marker written above it anchors. A paragraph runs\n * up to a blank line, a fence, a marker-only line, a bound line or the body's\n * start, and down as `paragraphAfter` reads it. Undefined for a blank line, a\n * marker-only line, or a line nothing can anchor.\n */\nexport function unitHolding(\n text: string,\n line: number,\n format: string,\n body: { offset: number; line: number },\n): { start: number; end: number; kind: \"paragraph\" | \"block\" } | undefined {\n const textOf = (n: number): string => lineText(text, offsetOfLine(text, n), lineEnd(text, offsetOfLine(text, n)));\n const own = textOf(line);\n if (own.trim() === \"\" || isMarkerLine(own, format)) return undefined;\n const block = fencedBlocks(text, body.offset, format).find(\n (b) => line >= b.line && line <= lineAt(text, b.end),\n );\n if (block !== undefined) {\n return { start: block.line, end: lineAt(text, block.end), kind: \"block\" };\n }\n if (ANY_FENCE.test(own)) return undefined;\n let start = line;\n // A bound line is its own unit, so the walk up never leaves it.\n while (start - 1 >= body.line && !isBoundLine(own, format)) {\n const above = textOf(start - 1);\n if (\n above.trim() === \"\" ||\n ANY_FENCE.test(above) ||\n isMarkerLine(above, format) ||\n isBoundLine(above, format)\n ) {\n break;\n }\n start--;\n }\n const paragraph = paragraphAfter(text, offsetOfLine(text, start), format);\n if (paragraph?.line !== start) return undefined;\n return { start, end: lineAt(text, paragraph.end), kind: \"paragraph\" };\n}\n\n/** A markdown list item's opening line: its indentation, its bullet or number, and the gap after. */\nconst LIST_ITEM = /^([ \\t]*)([-*+]|\\d{1,9}[.)])([ \\t]+|$)/;\n/** A thematic break, which a list item's pattern would otherwise read as `* * *`. */\nconst THEMATIC_BREAK = /^[ \\t]*([-*_])(?:[ \\t]*\\1){2,}[ \\t]*$/;\n\n/** The text of 1-based line `n` of `text`. */\nfunction textOfLine(text: string, n: number): string {\n const pos = offsetOfLine(text, n);\n return lineText(text, pos, lineEnd(text, pos));\n}\n\n/** The leading spaces and tabs of a line. */\nfunction indentOf(line: string): string {\n return /^[ \\t]*/.exec(line)?.[0] ?? \"\";\n}\n\n/** The column a run of spaces and tabs reaches, with tab stops every 4 columns. */\nfunction columnOf(indent: string): number {\n let column = 0;\n for (const ch of indent) column = ch === \"\\t\" ? column + 4 - (column % 4) : column + 1;\n return column;\n}\n\n/** The list item a markdown line opens, or undefined. */\nfunction listItemOf(line: string): { lead: string; bullet: string; gap: string } | undefined {\n if (THEMATIC_BREAK.test(line)) return undefined;\n const match = LIST_ITEM.exec(line);\n if (match === null) return undefined;\n const [, lead = \"\", bullet = \"\", gap = \"\"] = match;\n return { lead, bullet, gap };\n}\n\n/**\n * Whether the list item on `line` follows an earlier item of its list: the\n * nearest text above it, past blank and marker-only lines, is indented deeper\n * than the item, or sits in a paragraph holding an item at the same column.\n */\nfunction continuesList(\n text: string,\n line: number,\n format: string,\n bodyLine: number,\n column: number,\n): boolean {\n let n = line - 1;\n while (n >= bodyLine) {\n const above = textOfLine(text, n);\n if (above.trim() !== \"\" && !isMarkerLine(above, format)) break;\n n--;\n }\n if (n < bodyLine) return false;\n if (columnOf(indentOf(textOfLine(text, n))) > column) return true;\n for (; n >= bodyLine; n--) {\n const above = textOfLine(text, n);\n if (\n above.trim() === \"\" ||\n ANY_FENCE.test(above) ||\n isMarkerLine(above, format) ||\n isBoundLine(above, format)\n ) {\n break;\n }\n const item = listItemOf(above);\n if (item !== undefined && columnOf(item.lead) === column) return true;\n }\n return false;\n}\n\n/**\n * The indentation a marker written above `line` carries, so it stays in the\n * container the line is in. A paragraph's own leading spaces and tabs, copied\n * as they are. Above a markdown list item that follows an earlier item, the\n * column of the item's text, which keeps the marker inside the list: at the\n * item's own column it would end the list. asciidoc never indents one, since\n * a comment there starts at column 0.\n */\nexport function markerIndent(\n text: string,\n line: number,\n format: string,\n bodyLine: number,\n): string {\n if (format === \"asciidoc\") return \"\";\n const own = textOfLine(text, line);\n const indent = indentOf(own);\n if (format !== \"markdown\" && format !== \"mdx\") return indent;\n const item = listItemOf(own);\n if (item === undefined || !continuesList(text, line, format, bodyLine, columnOf(item.lead))) {\n return indent;\n }\n // A gap of five spaces or more is one space and indented code, so the text starts after one.\n const gap = item.gap === \"\" || columnOf(item.gap) > 4 ? \" \" : item.gap;\n return item.lead + \" \".repeat(item.bullet.length) + gap;\n}\n\n/**\n * The lines a marker anchors, as 1-based lines of `text`: the rest of its own\n * line when that carries text, else the paragraph or fenced block that\n * follows. Marker-only lines below it are skipped, so markers stacked above\n * one paragraph all anchor it, and none is part of the pin. With `quote`, the\n * next fenced block after it, wherever that is. Undefined when nothing\n * follows to anchor.\n */\nexport function anchoredLines(\n text: string,\n after: number,\n format: string,\n quote = false,\n): { start: number; end: number } | undefined {\n if (quote) {\n const block = fencedBlockAfter(text, after, format);\n return block === undefined ? undefined : { start: block.line, end: lineAt(text, block.end) };\n }\n const restEnd = lineEnd(text, after);\n if (text.slice(after, restEnd).trim() !== \"\") {\n const line = lineAt(text, after);\n return { start: line, end: line };\n }\n const paragraph = paragraphAfter(text, after, format);\n if (paragraph !== undefined) {\n return { start: paragraph.line, end: lineAt(text, paragraph.end) };\n }\n // A fence where a paragraph would be: the block is what the marker anchors.\n const line = nextTextLine(text, after, format);\n return line === undefined ? undefined : fenceSpanAt(text, line, format);\n}\n\n/**\n * The offset of every LF in a text, so a line number is a lookup rather than\n * a scan from the start. A page asks `lineAt` and `offsetOfLine` once per\n * citation, and a scan per question made a page of hundreds of citations\n * quadratic. Only the last few texts are kept, and the index is a pure\n * function of the text, so nothing carries from one run to the next.\n */\nconst LINE_INDEX_SLOTS = 4;\nconst lineIndexes: { text: string; newlines: number[] }[] = [];\n\nfunction newlinesOf(content: string): readonly number[] {\n const hit = lineIndexes.findIndex((entry) => entry.text === content);\n const found = hit === -1 ? undefined : lineIndexes[hit];\n if (found !== undefined) return found.newlines;\n const newlines: number[] = [];\n for (let at = content.indexOf(\"\\n\"); at !== -1; at = content.indexOf(\"\\n\", at + 1)) newlines.push(at);\n lineIndexes.unshift({ text: content, newlines });\n lineIndexes.length = Math.min(lineIndexes.length, LINE_INDEX_SLOTS);\n return newlines;\n}\n\n/** 1-based file line of a file offset, counting CRLF once. */\nexport function lineAt(content: string, offset: number): number {\n const stop = Math.min(offset, content.length);\n const newlines = newlinesOf(content);\n // The number of LFs before `stop`: a binary search for the first one at or past it.\n let low = 0;\n let high = newlines.length;\n while (low < high) {\n const mid = (low + high) >>> 1;\n if ((newlines[mid] ?? Infinity) < stop) low = mid + 1;\n else high = mid;\n }\n return low + 1;\n}\n\n/** File offset of the first character of a 1-based line (the length when past the end). */\nexport function offsetOfLine(content: string, line: number): number {\n if (line <= 1) return 0;\n const before = newlinesOf(content)[line - 2];\n return before === undefined ? content.length : before + 1;\n}\n"],"mappings":"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","names":["sliceLines","hashRange","line"]}
@@ -5,7 +5,7 @@ import {
5
5
  offerPrompt,
6
6
  planRelocation,
7
7
  relocationOffers
8
- } from "./chunk-GV56WGL2.js";
8
+ } from "./chunk-SMHAYK6I.js";
9
9
 
10
10
  // src/meta/core/location-writes.ts
11
11
  import { LineCounter, isMap, isNode, isScalar, parseDocument } from "yaml";
@@ -161,4 +161,4 @@ export {
161
161
  mergeMetaProvenance,
162
162
  metaProvenanceEntries
163
163
  };
164
- //# sourceMappingURL=chunk-M42DZCOU.js.map
164
+ //# sourceMappingURL=chunk-2OZF2VUB.js.map