@hawkeyexl/manni 4.3.1 → 4.4.1

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 (225) hide show
  1. package/README.md +9 -1
  2. package/dist/batch-GFNLTGOH.js +36 -0
  3. package/dist/build-COYIQ25L.js +31 -0
  4. package/dist/calibrate-MDBLJKEE.js +31 -0
  5. package/dist/capture-LRML2PKV.js +32 -0
  6. package/dist/check-ASPIHA6B.js +40 -0
  7. package/dist/check-ASPIHA6B.js.map +1 -0
  8. package/dist/check-EDLBYL5N.js +27 -0
  9. package/dist/check-EDLBYL5N.js.map +1 -0
  10. package/dist/check-HYNGXYJV.js +18 -0
  11. package/dist/check-HYNGXYJV.js.map +1 -0
  12. package/dist/chunk-2B7ZNTPV.js +230 -0
  13. package/dist/chunk-2B7ZNTPV.js.map +1 -0
  14. package/dist/chunk-2H7UOFLK.js +11 -0
  15. package/dist/chunk-2H7UOFLK.js.map +1 -0
  16. package/dist/chunk-37LP5HMZ.js +1042 -0
  17. package/dist/chunk-37LP5HMZ.js.map +1 -0
  18. package/dist/chunk-3VK37OR2.js +2957 -0
  19. package/dist/chunk-3VK37OR2.js.map +1 -0
  20. package/dist/chunk-4IUC2MNL.js +2165 -0
  21. package/dist/chunk-4IUC2MNL.js.map +1 -0
  22. package/dist/{chunk-3R23C5DT.js → chunk-4TSWU2SU.js} +2 -14
  23. package/dist/chunk-4TSWU2SU.js.map +1 -0
  24. package/dist/chunk-57NEQRVO.js +10921 -0
  25. package/dist/chunk-57NEQRVO.js.map +1 -0
  26. package/dist/chunk-6JSSEWBG.js +6737 -0
  27. package/dist/chunk-6JSSEWBG.js.map +1 -0
  28. package/dist/chunk-6OYEI2VV.js +88 -0
  29. package/dist/chunk-6OYEI2VV.js.map +1 -0
  30. package/dist/chunk-77AINBYM.js +19 -0
  31. package/dist/chunk-77AINBYM.js.map +1 -0
  32. package/dist/chunk-7UKO3ASZ.js +54 -0
  33. package/dist/chunk-7UKO3ASZ.js.map +1 -0
  34. package/dist/chunk-A5ULMVHQ.js +164 -0
  35. package/dist/chunk-A5ULMVHQ.js.map +1 -0
  36. package/dist/chunk-C4SQM22E.js +299 -0
  37. package/dist/chunk-C4SQM22E.js.map +1 -0
  38. package/dist/chunk-CK7SKVHR.js +1042 -0
  39. package/dist/chunk-CK7SKVHR.js.map +1 -0
  40. package/dist/{chunk-G5CM2VGQ.js → chunk-DXNZS72W.js} +8 -94
  41. package/dist/chunk-DXNZS72W.js.map +1 -0
  42. package/dist/chunk-EPH54CAY.js +374 -0
  43. package/dist/chunk-EPH54CAY.js.map +1 -0
  44. package/dist/{chunk-KJR7OVDX.js → chunk-FBEQCK47.js} +56 -137
  45. package/dist/chunk-FBEQCK47.js.map +1 -0
  46. package/dist/{chunk-IOYXPBCL.js → chunk-G3T47CFV.js} +1 -7
  47. package/dist/{chunk-IOYXPBCL.js.map → chunk-G3T47CFV.js.map} +1 -1
  48. package/dist/chunk-GCQRPUSB.js +1287 -0
  49. package/dist/chunk-GCQRPUSB.js.map +1 -0
  50. package/dist/chunk-GLP5PSXB.js +72 -0
  51. package/dist/chunk-GLP5PSXB.js.map +1 -0
  52. package/dist/chunk-I2AH3CJJ.js +1192 -0
  53. package/dist/chunk-I2AH3CJJ.js.map +1 -0
  54. package/dist/chunk-IDV6HJCB.js +388 -0
  55. package/dist/chunk-IDV6HJCB.js.map +1 -0
  56. package/dist/chunk-IKEWBMCN.js +98 -0
  57. package/dist/chunk-IKEWBMCN.js.map +1 -0
  58. package/dist/chunk-JCDXE76J.js +52 -0
  59. package/dist/chunk-JCDXE76J.js.map +1 -0
  60. package/dist/chunk-JXLTXMJ7.js +455 -0
  61. package/dist/chunk-JXLTXMJ7.js.map +1 -0
  62. package/dist/chunk-LJ2RDH3F.js +49 -0
  63. package/dist/chunk-LJ2RDH3F.js.map +1 -0
  64. package/dist/chunk-M2JCK5F6.js +805 -0
  65. package/dist/chunk-M2JCK5F6.js.map +1 -0
  66. package/dist/chunk-M3W7J6MU.js +4398 -0
  67. package/dist/chunk-M3W7J6MU.js.map +1 -0
  68. package/dist/chunk-MMTSSTG7.js +23 -0
  69. package/dist/chunk-MMTSSTG7.js.map +1 -0
  70. package/dist/chunk-MNH7QO4Z.js +15 -0
  71. package/dist/chunk-MNH7QO4Z.js.map +1 -0
  72. package/dist/chunk-MWJLZMBL.js +934 -0
  73. package/dist/chunk-MWJLZMBL.js.map +1 -0
  74. package/dist/chunk-MYMBCTDE.js +387 -0
  75. package/dist/chunk-MYMBCTDE.js.map +1 -0
  76. package/dist/chunk-NCPWXHDO.js +683 -0
  77. package/dist/chunk-NCPWXHDO.js.map +1 -0
  78. package/dist/chunk-NLXTXE5Y.js +1661 -0
  79. package/dist/chunk-NLXTXE5Y.js.map +1 -0
  80. package/dist/{chunk-CFDUZRM2.js → chunk-NXV7WE2D.js} +32 -240
  81. package/dist/chunk-NXV7WE2D.js.map +1 -0
  82. package/dist/chunk-OWBRDNRZ.js +16 -0
  83. package/dist/chunk-OWBRDNRZ.js.map +1 -0
  84. package/dist/{chunk-KTSJ2ZHA.js → chunk-PAU352SV.js} +5 -3
  85. package/dist/{chunk-KTSJ2ZHA.js.map → chunk-PAU352SV.js.map} +1 -1
  86. package/dist/chunk-PCE7QHXJ.js +68 -0
  87. package/dist/chunk-PCE7QHXJ.js.map +1 -0
  88. package/dist/chunk-PIKOVN6W.js +1651 -0
  89. package/dist/chunk-PIKOVN6W.js.map +1 -0
  90. package/dist/chunk-PNPQTHBT.js +17 -0
  91. package/dist/chunk-PNPQTHBT.js.map +1 -0
  92. package/dist/chunk-PU6DFJMY.js +1975 -0
  93. package/dist/chunk-PU6DFJMY.js.map +1 -0
  94. package/dist/chunk-Q35YIDBV.js +1202 -0
  95. package/dist/chunk-Q35YIDBV.js.map +1 -0
  96. package/dist/{chunk-5HNHEUD5.js → chunk-QQUKGCAJ.js} +3 -3
  97. package/dist/chunk-QRWGPQKO.js +198 -0
  98. package/dist/chunk-QRWGPQKO.js.map +1 -0
  99. package/dist/{chunk-UBMMXS2Y.js → chunk-QZ6LRSNV.js} +69 -48
  100. package/dist/{chunk-UBMMXS2Y.js.map → chunk-QZ6LRSNV.js.map} +1 -1
  101. package/dist/chunk-RL5XWQOL.js +3872 -0
  102. package/dist/chunk-RL5XWQOL.js.map +1 -0
  103. package/dist/chunk-RNVYGWIC.js +30 -0
  104. package/dist/chunk-RNVYGWIC.js.map +1 -0
  105. package/dist/chunk-SE4JN5XN.js +19 -0
  106. package/dist/chunk-SE4JN5XN.js.map +1 -0
  107. package/dist/chunk-SKSDRUUK.js +622 -0
  108. package/dist/chunk-SKSDRUUK.js.map +1 -0
  109. package/dist/chunk-TIUTIOFB.js +25 -0
  110. package/dist/chunk-TIUTIOFB.js.map +1 -0
  111. package/dist/chunk-TK3FC4RF.js +3090 -0
  112. package/dist/chunk-TK3FC4RF.js.map +1 -0
  113. package/dist/chunk-TU2WUBVZ.js +2 -0
  114. package/dist/chunk-TU2WUBVZ.js.map +1 -0
  115. package/dist/chunk-TZOYZK2E.js +98 -0
  116. package/dist/chunk-TZOYZK2E.js.map +1 -0
  117. package/dist/chunk-UJCVAWP7.js +178 -0
  118. package/dist/chunk-UJCVAWP7.js.map +1 -0
  119. package/dist/chunk-UKZNLVJW.js +17 -0
  120. package/dist/chunk-UKZNLVJW.js.map +1 -0
  121. package/dist/{chunk-HAPTXWU2.js → chunk-UQISLDAV.js} +4 -4
  122. package/dist/chunk-WB3QM6PP.js +5440 -0
  123. package/dist/chunk-WB3QM6PP.js.map +1 -0
  124. package/dist/chunk-YB4IBW3M.js +96 -0
  125. package/dist/chunk-YB4IBW3M.js.map +1 -0
  126. package/dist/chunk-YEUYKR62.js +72 -0
  127. package/dist/chunk-YEUYKR62.js.map +1 -0
  128. package/dist/chunk-YJOGUXGP.js +634 -0
  129. package/dist/chunk-YJOGUXGP.js.map +1 -0
  130. package/dist/chunk-YNHZHSSM.js +41 -0
  131. package/dist/chunk-YNHZHSSM.js.map +1 -0
  132. package/dist/chunk-YTURO7SI.js +979 -0
  133. package/dist/chunk-YTURO7SI.js.map +1 -0
  134. package/dist/chunk-ZXRAE55H.js +31 -0
  135. package/dist/chunk-ZXRAE55H.js.map +1 -0
  136. package/dist/cli-3BIBYHFK.js +473 -0
  137. package/dist/cli-3BIBYHFK.js.map +1 -0
  138. package/dist/cli-673OTRGE.js +28 -0
  139. package/dist/cli-673OTRGE.js.map +1 -0
  140. package/dist/cli-6HIDIFVT.js +1203 -0
  141. package/dist/cli-6HIDIFVT.js.map +1 -0
  142. package/dist/cli-6UB5N6CU.js +232 -0
  143. package/dist/cli-6UB5N6CU.js.map +1 -0
  144. package/dist/cli-LFP5ZGYS.js +346 -0
  145. package/dist/cli-LFP5ZGYS.js.map +1 -0
  146. package/dist/cli-MN7PYMBI.js +552 -0
  147. package/dist/cli-MN7PYMBI.js.map +1 -0
  148. package/dist/cli-PYPX6O6E.js +739 -0
  149. package/dist/cli-PYPX6O6E.js.map +1 -0
  150. package/dist/cli-RPM5PELX.js +626 -0
  151. package/dist/cli-RPM5PELX.js.map +1 -0
  152. package/dist/cli-VI7VHWNZ.js +423 -0
  153. package/dist/cli-VI7VHWNZ.js.map +1 -0
  154. package/dist/cli.d.ts +12 -2
  155. package/dist/cli.js +109 -7661
  156. package/dist/cli.js.map +1 -1
  157. package/dist/docmeta.js +15 -3
  158. package/dist/docmeta.js.map +1 -1
  159. package/dist/github-6QMYOHC3.js +27 -0
  160. package/dist/github-6QMYOHC3.js.map +1 -0
  161. package/dist/github-SXPGP5DB.js +32 -0
  162. package/dist/github-SXPGP5DB.js.map +1 -0
  163. package/dist/index.d.ts +65 -3
  164. package/dist/index.js +407 -337
  165. package/dist/index.js.map +1 -1
  166. package/dist/json-7WV7KL6H.js +17 -0
  167. package/dist/json-7WV7KL6H.js.map +1 -0
  168. package/dist/json-SY7KLNC7.js +35 -0
  169. package/dist/json-SY7KLNC7.js.map +1 -0
  170. package/dist/lint-ASMJLLPA.js +28 -0
  171. package/dist/lint-ASMJLLPA.js.map +1 -0
  172. package/dist/list-KZNVTNVC.js +31 -0
  173. package/dist/list-KZNVTNVC.js.map +1 -0
  174. package/dist/list-Q57YTFUQ.js +29 -0
  175. package/dist/list-Q57YTFUQ.js.map +1 -0
  176. package/dist/page-KSGV5RD4.js +41 -0
  177. package/dist/page-KSGV5RD4.js.map +1 -0
  178. package/dist/picker-3XF36MJF.js +14 -0
  179. package/dist/picker-3XF36MJF.js.map +1 -0
  180. package/dist/pretty-A5EGTN35.js +37 -0
  181. package/dist/pretty-A5EGTN35.js.map +1 -0
  182. package/dist/pretty-CXSDXNAS.js +43 -0
  183. package/dist/pretty-CXSDXNAS.js.map +1 -0
  184. package/dist/reporters-HUY7UXFS.js +42 -0
  185. package/dist/reporters-HUY7UXFS.js.map +1 -0
  186. package/dist/reporters-K2VUKSAK.js +71 -0
  187. package/dist/reporters-K2VUKSAK.js.map +1 -0
  188. package/dist/reporters-M6LJ2IYU.js +21 -0
  189. package/dist/reporters-M6LJ2IYU.js.map +1 -0
  190. package/dist/run-3DYJNRIG.js +33 -0
  191. package/dist/run-3DYJNRIG.js.map +1 -0
  192. package/dist/term-BIQUPMOR.js +1592 -0
  193. package/dist/term-BIQUPMOR.js.map +1 -0
  194. package/dist/types-Y6TXHM7M.js +10 -0
  195. package/dist/types-Y6TXHM7M.js.map +1 -0
  196. package/dist/validate-53RKM2XG.js +16 -0
  197. package/dist/validate-53RKM2XG.js.map +1 -0
  198. package/package.json +1 -1
  199. package/plugin/manni/.claude-plugin/plugin.json +9 -0
  200. package/plugin/manni/hooks/hooks.json +69 -0
  201. package/plugin/manni/hooks/manni.mjs +157 -0
  202. package/plugin/manni/skills/check/SKILL.md +20 -0
  203. package/plugin/manni/skills/evals/SKILL.md +27 -0
  204. package/plugin/manni/skills/fix/SKILL.md +56 -0
  205. package/plugin/manni/skills/setup/SKILL.md +41 -0
  206. package/dist/batch-A5HZKYIW.js +0 -18
  207. package/dist/calibrate-S5K6QHUY.js +0 -13
  208. package/dist/capture-OZEZDABQ.js +0 -15
  209. package/dist/chunk-3R23C5DT.js.map +0 -1
  210. package/dist/chunk-CFDUZRM2.js.map +0 -1
  211. package/dist/chunk-G5CM2VGQ.js.map +0 -1
  212. package/dist/chunk-KJR7OVDX.js.map +0 -1
  213. package/dist/chunk-V4KUVE47.js +0 -27170
  214. package/dist/chunk-V4KUVE47.js.map +0 -1
  215. package/dist/chunk-ZQBTK3DO.js +0 -26518
  216. package/dist/chunk-ZQBTK3DO.js.map +0 -1
  217. package/dist/picker-6HRMETE7.js +0 -12
  218. package/plugin/tracevals/.claude-plugin/plugin.json +0 -9
  219. package/plugin/tracevals/hooks/hooks.json +0 -17
  220. /package/dist/{batch-A5HZKYIW.js.map → batch-GFNLTGOH.js.map} +0 -0
  221. /package/dist/{calibrate-S5K6QHUY.js.map → build-COYIQ25L.js.map} +0 -0
  222. /package/dist/{capture-OZEZDABQ.js.map → calibrate-MDBLJKEE.js.map} +0 -0
  223. /package/dist/{picker-6HRMETE7.js.map → capture-LRML2PKV.js.map} +0 -0
  224. /package/dist/{chunk-5HNHEUD5.js.map → chunk-QQUKGCAJ.js.map} +0 -0
  225. /package/dist/{chunk-HAPTXWU2.js.map → chunk-UQISLDAV.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cite/core/spell.ts","../src/cite/core/adapt.ts","../src/cite/core/reanchor.ts","../src/cite/core/claims.ts"],"sourcesContent":["/**\n * How a citation reads on a terminal. A pin is sixty-four hex digits and a\n * ciphertext is longer still, so both are abbreviated for a person, and every\n * report and every `add` line abbreviates them the same way.\n */\nimport type { PageLines } from \"../types.js\";\n\n/** `sha256-78af1d33…`, `hmac-sha256-5e0c1a2b…`: the prefix and eight hex digits. */\nexport function shortPin(integrity: string): string {\n const m = /^((?:hmac-)?sha256-)([0-9a-f]{8})/i.exec(integrity);\n const prefix = m?.[1];\n const digits = m?.[2];\n if (prefix === undefined || digits === undefined) return integrity;\n return `${prefix}${digits}…`;\n}\n\n/** The seven characters a person reads a commit by. */\nexport function shortCommit(commit: string): string {\n return commit.slice(0, 7);\n}\n\n/**\n * `~AQx7…:2`: an encrypted source, abbreviated, with its line suffix kept. A\n * plain path is spelled in full, because that is what a reader has to find.\n */\nexport function shortSrc(src: string): string {\n if (!src.startsWith(\"~\")) return src;\n const colon = src.indexOf(\":\");\n const token = colon === -1 ? src : src.slice(0, colon);\n const lines = colon === -1 ? \"\" : src.slice(colon);\n return token.length <= 5 ? src : `${token.slice(0, 5)}…${lines}`;\n}\n\n/** The widest a quoted line of a file is printed at. */\nconst LINE_WIDTH = 60;\n\n/**\n * A line of a file as a report quotes it: whitespace collapsed to single\n * spaces, then sixty characters and an ellipsis. The report is one line, so\n * neither an indented source line nor a long one decides how it reads.\n */\nexport function shortLine(text: string): string {\n const one = text.replace(/\\s+/g, \" \").trim();\n return one.length <= LINE_WIDTH ? one : `${one.slice(0, LINE_WIDTH)}…`;\n}\n\n/**\n * `line 9`, or `lines 9-12`: where on a page a span sits. Every refusal,\n * report and message that names one reads it this way, so `add`, `update`\n * and the reporters spell it once.\n */\nexport function spellAt(lines: PageLines): string {\n return lines.start === lines.end\n ? `line ${String(lines.start)}`\n : `lines ${String(lines.start)}-${String(lines.end)}`;\n}\n\n/** `a`, `a and b`, `a, b and c`: a list as a sentence reads it. */\nexport function listOf(values: readonly string[]): string {\n if (values.length <= 1) return values.join(\"\");\n return `${values.slice(0, -1).join(\", \")} and ${values[values.length - 1] ?? \"\"}`;\n}\n","/**\n * Findings, their messages, and the bridge to meta's `ValidationResult`, so\n * the github/sarif/junit reporters and the baseline ratchet work unchanged.\n *\n * A claim or marker finding sits on the page line a reviewer reads. A finding\n * about the entry itself, `entry-invalid` or a bare pin whose source changed,\n * sits on the entry's own line, in the manifest when one owns it.\n *\n * FieldError: schema \"manni:cite\" (matches BUILTIN_ID, so canonicalSchemaRef\n * leaves it alone), keyword = rule, instancePath \"/citations/N\", subject =\n * id ?? source.integrity, never the claim's pin, so accepting a claim does\n * not reopen baselined findings. `ok` is true iff no error-severity finding.\n *\n * Every message spells the source as the entry spelled it. `resolvedPath`,\n * `commitsSince` and `diff` never enter a message: they are pretty-only\n * fields, shown under `--reveal` and `--show-diff`.\n */\nimport { isAbsolute } from \"node:path\";\nimport { isErrorSeverity, type FieldError, type ValidationResult } from \"../../meta/index.js\";\nimport type {\n CitationFinding,\n CitationResult,\n CiteRule,\n CiteSeverity,\n ClaimEnd,\n PageCitationReport,\n SourceEnd,\n SourceStatus,\n} from \"../types.js\";\nimport { claimLine } from \"./claims.js\";\nimport { parseSrc } from \"./range.js\";\nimport { RULE_ID_PREFIX, ruleId } from \"./severity.js\";\nimport { listOf, shortSrc } from \"./spell.js\";\n\n/** The seven characters a person reads a commit by. */\nfunction short(commit: string): string {\n return commit.slice(0, 7);\n}\n\nfunction plural(n: number, noun: string): string {\n return `${String(n)} ${noun}${n === 1 ? \"\" : \"s\"}`;\n}\n\n/** Whether the entry spelled this source encrypted. */\nfunction citesEncrypted(src: string): boolean {\n try {\n return parseSrc(src).encrypted;\n } catch {\n return false;\n }\n}\n\n/**\n * Why an encrypted source is missing, in words that never name the path. A\n * plain path names its own file, so the bare status says the rest.\n */\nfunction missingMessage(source: SourceEnd): string {\n if (!citesEncrypted(source.src)) return \"missing\";\n switch (source.missingReason) {\n case \"no-key\":\n return \"missing (no encryption key is available to decrypt it)\";\n case \"undecryptable\":\n return \"missing (does not decrypt under the current key)\";\n case \"untracked\":\n return \"missing (no tracked file matches; wrong --root?)\";\n case \"unreadable\":\n case undefined:\n return \"missing\";\n }\n}\n\n/** The one place a source end's message is composed, per status. */\nexport function messageFor(source: SourceEnd): string {\n switch (source.status) {\n case \"current\":\n return \"current\";\n case \"skipped\":\n return \"skipped\";\n case \"moved\":\n // An encrypted source's new path is a ciphertext, abbreviated as the\n // entry's own is: `--reveal` stays the only way to read either.\n return `moved -> ${shortSrc(source.newSrc ?? \"?\")}`;\n case \"moved-ambiguous\": {\n const candidates = source.candidates ?? [];\n return `moved, ${plural(candidates.length, \"candidate\")} (${candidates.map(shortSrc).join(\", \")}); widen the range`;\n }\n case \"changed\": {\n // Where the old first and last line sit now, when the in-range search\n // found each exactly once: the span `update --accept` re-mints at.\n const span = source.newLines === undefined ? \"\" : `; now at lines ${source.newLines}`;\n if (source.commitSha === undefined) return `changed${span}`;\n const at = short(source.commitSha);\n if (source.historyAvailable === false) {\n return `changed (history unavailable: commit ${at} not found; fetch-depth: 0)`;\n }\n if (source.commitsSince === undefined) return `changed since ${at}${span}`;\n return `changed since ${at}, ${plural(source.commitsSince.length, \"commit\")}${span}`;\n }\n case \"never-true\":\n return source.commitSha === undefined\n ? \"never true: the pin does not match at the recorded commit\"\n : `never true: the pin does not match at ${short(source.commitSha)}`;\n case \"missing\":\n return missingMessage(source);\n }\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/** `line 9`, or `lines 9-10` when the claim covers several. */\nfunction at(spec: string): string {\n return spec.includes(\"-\") ? `lines ${spec}` : `line ${spec}`;\n}\n\n/** The one place a claim end's message is composed, per status. */\nexport function claimMessageFor(result: CitationResult): string {\n const claim = result.claim;\n const id = result.citation.id;\n if (claim === null) return \"\";\n // A marker-anchored claim has no lines of its own; it is judged where the\n // marker's text sits, and that is what the message names.\n const where =\n claim.fileLines ??\n (result.markerLine === undefined ? undefined : String(result.markerLine));\n switch (claim.status) {\n case \"moved\":\n return named(\n id,\n `the claim moved from ${at(where ?? \"?\")} to ${at(claim.newFileLines ?? \"?\")}.`,\n );\n case \"moved-ambiguous\":\n return named(\n id,\n `the claim at ${at(where ?? \"?\")} now appears at lines ${listOf(claim.candidateFileLines ?? [])}.`,\n );\n case \"reanchored\": {\n const since = claim.commitSha === undefined ? \"\" : ` since ${short(claim.commitSha)}`;\n // A claim-lines entry moved onto its new run; a marker-anchored one\n // never moves, because the marker travels with its own text.\n const to =\n claim.newFileLines === undefined ? \"\" : `, to ${at(claim.newFileLines)}`;\n return named(\n id,\n `the claim at ${at(where ?? \"?\")} was reanchored${since}${to}. Its words are unchanged.`,\n );\n }\n case \"changed\":\n if (where === undefined) {\n return named(\n id,\n \"the claim has no lines and no marker names the entry, so its pin anchors nothing.\",\n );\n }\n return named(id, `the claim at ${at(where)} has ${claimChange(claim)}`);\n case \"current\":\n case \"skipped\":\n return \"\";\n }\n}\n\n/** How a changed claim says since when, which is what its history could say. */\nfunction claimChange(claim: ClaimEnd): string {\n if (claim.historyAvailable === false) {\n return \"changed since it was pinned (history unavailable; fetch-depth: 0).\";\n }\n if (claim.commitSha === undefined) return \"changed since it was pinned.\";\n const at = short(claim.commitSha);\n // Zero commits since would read as \"just now\". The working tree holding the\n // change is what it actually means, so it says that.\n const since = claim.commitsSince ?? [];\n const count = since.length === 0 ? \"uncommitted\" : plural(since.length, \"commit\");\n return `changed since ${at}, ${count}.`;\n}\n\n/**\n * The one place a `marker-misplaced` message is composed. A quote marker's\n * place is above the block it anchors; every other marker's is the first line\n * of the paragraph its run splits.\n */\nexport function misplacedMessageFor(\n id: string | undefined,\n marker: { line: number; unit: string; place: number; block: boolean },\n): string {\n const place = marker.block\n ? `above the block at line ${String(marker.place)}`\n : `above line ${String(marker.place)}`;\n return named(\n id,\n `the marker at line ${String(marker.line)} splits the paragraph at ${at(marker.unit)}. Its place is ${place}.`,\n );\n}\n\n/** The rule a source status reports under, or undefined for one that is not a finding. */\nfunction sourceRuleOf(status: SourceStatus): CiteRule | undefined {\n if (status === \"skipped\" || status === \"current\") return undefined;\n return `source-${status}`;\n}\n\n/** The rule a claim status reports under, or undefined. */\nfunction claimRuleOf(claim: ClaimEnd): CiteRule | undefined {\n const status = claim.status;\n if (status === \"skipped\" || status === \"current\") return undefined;\n return `claim-${status}`;\n}\n\n/** Where a finding about a whole entry sits: its own line, in its own file. */\nfunction entrySite(result: CitationResult): Pick<CitationFinding, \"line\" | \"file\"> {\n const site: Pick<CitationFinding, \"line\" | \"file\"> = {};\n if (result.origin.line !== undefined) site.line = result.origin.line;\n if (result.origin.kind === \"manifest\") site.file = result.origin.file;\n return site;\n}\n\n/** Where a finding about an anchored citation sits: the page line it anchors to. */\nfunction anchorSite(result: CitationResult): Pick<CitationFinding, \"line\" | \"file\"> {\n if (result.anchorLine !== undefined) return { line: result.anchorLine };\n return entrySite(result);\n}\n\n/** Findings for classified citations under a severity table; `off` rules produce none. */\nexport function findingsFor(\n results: readonly CitationResult[],\n severity: Readonly<Record<CiteRule, CiteSeverity>>,\n): CitationFinding[] {\n const out: CitationFinding[] = [];\n const push = (\n result: CitationResult,\n rule: CiteRule,\n message: string,\n site: Pick<CitationFinding, \"line\" | \"file\">,\n extra?: Pick<CitationFinding, \"newSrc\">,\n ): void => {\n const level = severity[rule];\n if (level === \"off\") return;\n const finding: CitationFinding = {\n rule,\n ruleId: ruleId(rule),\n severity: level,\n message,\n src: result.source.src,\n index: result.origin.index,\n };\n if (site.line !== undefined) finding.line = site.line;\n if (site.file !== undefined) finding.file = site.file;\n if (result.citation.id !== undefined) finding.id = result.citation.id;\n if (extra?.newSrc !== undefined) finding.newSrc = extra.newSrc;\n out.push(finding);\n };\n\n for (const result of results) {\n const claim = result.claim;\n if (claim !== null) {\n const rule = claimRuleOf(claim);\n // A claim pin that anchors nothing has no page line to sit on.\n if (rule !== undefined) {\n const site =\n claimLine(claim) === undefined && result.markerLine === undefined\n ? entrySite(result)\n : { line: claimLine(claim) ?? result.markerLine };\n push(result, rule, claimMessageFor(result), site);\n }\n }\n const rule = sourceRuleOf(result.source.status);\n if (rule === undefined) continue;\n const extra =\n result.source.newSrc === undefined ? undefined : { newSrc: result.source.newSrc };\n push(result, rule, messageFor(result.source), anchorSite(result), extra);\n }\n return out;\n}\n\n/**\n * The pin of the citation a finding is about, for the fingerprint subject of\n * an entry with no id. Always the source's: accepting a changed claim must\n * not reopen a baselined finding.\n */\nfunction integrityFor(\n finding: CitationFinding,\n results: readonly CitationResult[],\n): string | undefined {\n if (finding.index === undefined) return undefined;\n return results.find((r) => r.origin.index === finding.index)?.citation.source.integrity;\n}\n\n/**\n * Where a finding is located once it becomes a `FieldError`: the page, or\n * the manifest the entry sits in.\n *\n * A manifest outside the repository has no location any reporter can use —\n * SARIF drops a uri that rebases to `../…`, and a GitHub annotation on one\n * lands nowhere — so the finding falls back to the page, and its line goes\n * with the file it belonged to. Inside the tree, both travel, and `file`\n * is what every reporter reads to annotate the manifest instead.\n */\nexport function errorSite(\n finding: CitationFinding,\n): Pick<CitationFinding, \"line\" | \"file\"> {\n if (finding.file === undefined) {\n return finding.line === undefined ? {} : { line: finding.line };\n }\n if (finding.file.startsWith(\"../\") || isAbsolute(finding.file)) return {};\n return {\n file: finding.file,\n ...(finding.line === undefined ? {} : { line: finding.line }),\n };\n}\n\nexport function toValidationResult(report: PageCitationReport): ValidationResult {\n const errors: FieldError[] = report.findings.map((finding) => {\n const error: FieldError = {\n schema: RULE_ID_PREFIX,\n instancePath: finding.index === undefined ? \"\" : `/citations/${String(finding.index)}`,\n message: finding.message,\n keyword: finding.rule,\n severity: finding.severity,\n };\n const subject = finding.id ?? integrityFor(finding, report.citations);\n if (subject !== undefined) error.subject = subject;\n const site = errorSite(finding);\n if (site.file !== undefined) error.file = site.file;\n if (site.line !== undefined) error.line = site.line;\n return error;\n });\n return {\n file: report.file,\n format: report.format,\n ok: !errors.some(isErrorSeverity),\n schemas: [RULE_ID_PREFIX],\n errors,\n };\n}\n","/**\n * Misplaced markers, and what to do about them. Proposal 0054 is the record.\n *\n * A **marker run** is one or more consecutive lines that each hold one marker\n * and nothing else. A run is **misplaced** when the line directly above it and\n * the line directly below it are both unit text: deleting the run would join\n * them into one paragraph. Such a marker splits the paragraph for the renderer\n * and for the tool, and the lines above it are anchored by nothing.\n *\n * A misplaced marker belongs where `add --marker` writes one: above the first\n * line of the unit, or, for a `quote: true` entry, above the block it anchors.\n * A run moves in its own order, so two markers that were stacked stay stacked.\n *\n * The claim of a marker-anchored entry is read against three spans, in order:\n * the unit the marker belongs to, the span it anchors now, and the span it was\n * pinned over before PR #43 (marker lines included, down to the next blank\n * line or fence). The second or third holding means the pinned text is on the\n * page and the marker anchors a different span: `claim-moved`.\n */\nimport type { ClaimEnd, PageCitation, PageCitations, PageLines } from \"../types.js\";\nimport { hashLines } from \"./hash.js\";\nimport { MAX_MARKERS_PER_PAGE } from \"./page.js\";\nimport { spellLines } from \"../../shared/pin.js\";\nimport { ANY_FENCE, anchoredLines, isBoundLine, isMarkerLine } from \"./statements.js\";\n\n/** Whether a line is text a paragraph is made of. */\nexport function isUnitText(line: string | undefined, format: string): boolean {\n if (line === undefined) return false;\n if (line.trim() === \"\") return false;\n if (ANY_FENCE.test(line)) return false;\n if (isMarkerLine(line, format)) return false;\n return !isBoundLine(line, format);\n}\n\n/** Whether the file line `n` holds one marker and nothing else. */\nfunction markerAt(lines: readonly string[], n: number, format: string): boolean {\n const line = lines[n - 1];\n return line !== undefined && isMarkerLine(line, format);\n}\n\n/** The run of marker-only lines that holds `line`. */\nexport function markerRunAt(\n lines: readonly string[],\n line: number,\n format: string,\n bodyLine: number,\n): PageLines {\n let start = line;\n while (start - 1 >= bodyLine && markerAt(lines, start - 1, format)) start--;\n let end = line;\n while (end + 1 <= lines.length && markerAt(lines, end + 1, format)) end++;\n return { start, end };\n}\n\n/**\n * The paragraph a run splits, in file lines, marker lines included.\n * `undefined` when the run sits where `add` writes markers: after a blank\n * line, a fence, a bound line, or the body's first line.\n */\nexport function splitUnit(\n lines: readonly string[],\n run: PageLines,\n format: string,\n bodyLine: number,\n): PageLines | undefined {\n if (run.start - 1 < bodyLine) return undefined;\n if (!isUnitText(lines[run.start - 2], format)) return undefined;\n if (!isUnitText(lines[run.end], format)) return undefined;\n let start = run.start - 1;\n while (start - 1 >= bodyLine && isUnitText(lines[start - 2], format)) start--;\n let end = run.end + 1;\n while (end + 1 <= lines.length && isUnitText(lines[end], format)) end++;\n return { start, end };\n}\n\n/**\n * The span a marker was pinned over before PR #43: from the line below it\n * through the next blank line or fence, marker lines included. `undefined`\n * when the line below is blank or a fence, so the old reading covered nothing.\n */\nexport function pre43Span(\n lines: readonly string[],\n markerLine: number,\n): PageLines | undefined {\n const start = markerLine + 1;\n const first = lines[start - 1];\n if (first === undefined || first.trim() === \"\" || ANY_FENCE.test(first)) return undefined;\n let end = start;\n while (end + 1 <= lines.length) {\n const next = lines[end];\n if (next === undefined || next.trim() === \"\" || ANY_FENCE.test(next)) break;\n end++;\n }\n return { start, end };\n}\n\n/** One marker line that splits a paragraph. */\nexport interface MisplacedMarker {\n /** File line of the marker. */\n line: number;\n /** The whole run of marker-only lines it belongs to. */\n run: PageLines;\n /** Its position in that run, counted from zero, so stacked markers keep their order. */\n order: number;\n /** The paragraph the run splits, in file lines as the page reads now. */\n unit: PageLines;\n /** The file line the marker belongs above. */\n place: number;\n /** Whether `place` is a fenced block the entry quotes rather than the unit's first line. */\n block: boolean;\n /** The file line the marker takes once the whole run has moved. */\n to: number;\n /** The entry the marker names, when one is anchored by it. */\n entry?: PageCitation;\n}\n\n/** The lines of a run, which is `end - start + 1` markers. */\nfunction runLength(run: PageLines): number {\n return run.end - run.start + 1;\n}\n\n/** Whether a misplaced marker at `line` splits a paragraph, and where it belongs. */\nexport function misplacedMarkerAt(\n page: PageCitations,\n lines: readonly string[],\n line: number,\n entry?: PageCitation,\n): MisplacedMarker | undefined {\n if (!markerAt(lines, line, page.format)) return undefined;\n const run = markerRunAt(lines, line, page.format, page.bodyLine);\n const unit = splitUnit(lines, run, page.format, page.bodyLine);\n if (unit === undefined) return undefined;\n const order = line - run.start;\n const quote = entry?.citation.quote === true;\n const marker = entry?.marker;\n const blockAt =\n quote && marker !== undefined\n ? anchoredLines(page.content, marker.end, page.format, true)?.start\n : undefined;\n const out: MisplacedMarker = blockAt === undefined\n ? { line, run, order, unit, place: unit.start, block: false, to: unit.start + order }\n : {\n line,\n run,\n order,\n unit,\n place: blockAt,\n block: true,\n to: blockAt - runLength(run) + order,\n };\n if (entry !== undefined) out.entry = entry;\n return out;\n}\n\n/**\n * Every misplaced marker on a page, in the order the page reads. An orphan,\n * repeated or invalid marker is reported like any other: it splits the\n * paragraph whether or not it names an entry.\n */\nexport function misplacedMarkers(\n page: PageCitations,\n lines: readonly string[],\n): MisplacedMarker[] {\n const out: MisplacedMarker[] = [];\n for (const statement of page.statements.slice(0, MAX_MARKERS_PER_PAGE)) {\n const entry = page.citations.find((c) => c.marker?.line === statement.line);\n const found = misplacedMarkerAt(page, lines, statement.line, entry);\n if (found !== undefined) out.push(found);\n }\n return out;\n}\n\n/**\n * The span the pin covers once a misplaced run has moved: the joined unit,\n * pushed down by the markers now above it. A quote marker's pin covers its\n * block, which no move touches, so this is never asked of one.\n */\nexport function movedUnit(misplaced: MisplacedMarker): PageLines {\n return { start: misplaced.unit.start + runLength(misplaced.run), end: misplaced.unit.end };\n}\n\n/** The unit's text, the run's marker lines left out: what the pin covers after the move. */\nexport function unitText(lines: readonly string[], misplaced: MisplacedMarker): string[] {\n const { unit, run } = misplaced;\n const out: string[] = [];\n for (let n = unit.start; n <= unit.end; n++) {\n if (n >= run.start && n <= run.end) continue;\n const line = lines[n - 1];\n if (line !== undefined) out.push(line);\n }\n return out;\n}\n\n/** One marker line a rewrite moves, and the file line it goes above. */\nexport interface MarkerMove {\n from: number;\n place: number;\n}\n\n/** A page with its markers moved, and where its lines went. */\nexport interface MovedPage {\n content: string;\n /** The new file line of an old one. */\n line(old: number): number;\n}\n\n/** A page split into line texts and the terminator each position carries. */\nfunction splitKeepingEol(content: string): { texts: string[]; eols: string[] } {\n const parts = content.match(/[^\\n]*\\n|[^\\n]+$/g) ?? [];\n const texts: string[] = [];\n const eols: string[] = [];\n for (const part of parts) {\n const eol = /\\r?\\n$/.exec(part)?.[0] ?? \"\";\n texts.push(part.slice(0, part.length - eol.length));\n eols.push(eol);\n }\n return { texts, eols };\n}\n\n/**\n * The page with each named marker line lifted out and written above its place,\n * in the order the moves are given, so a run that was stacked stays stacked.\n * A moved marker takes the indentation `add` would write it at, and the file's\n * terminators stay where they are: the lines are permuted, never re-joined.\n *\n * Read the join carefully. A line's text comes from where it was, and its\n * terminator from where it now sits. That asymmetry is deliberate: the last\n * position of a page with no final newline carries no terminator, and it has\n * to stay the last position. Were terminators to travel with their lines, a\n * move that lifted that last line would carry the missing terminator into the\n * middle of the page and glue two lines together.\n *\n * The cost is that a page mixing `\\r\\n` and `\\n` has the endings of the two\n * swapped positions trade places. No byte is gained or lost, and the file\n * still ends as it began. A uniform page, which is what a checkout gives,\n * cannot tell the difference.\n */\nexport function applyMarkerMoves(\n content: string,\n moves: readonly MarkerMove[],\n indentAt: (line: number) => string,\n): MovedPage {\n const { texts, eols } = splitKeepingEol(content);\n const moving = new Set(moves.map((move) => move.from));\n const inserts = new Map<number, number[]>();\n for (const move of moves) {\n const list = inserts.get(move.place) ?? [];\n list.push(move.from);\n inserts.set(move.place, list);\n }\n const order: number[] = [];\n for (let n = 1; n <= texts.length; n++) {\n for (const from of inserts.get(n) ?? []) order.push(from);\n if (!moving.has(n)) order.push(n);\n }\n const moved = new Map<number, string>();\n for (const move of moves) {\n moved.set(move.from, indentAt(move.place) + (texts[move.from - 1] ?? \"\").trim());\n }\n const at = new Map<number, number>();\n order.forEach((old, index) => at.set(old, index + 1));\n const out = order\n .map((old, index) => (moved.get(old) ?? texts[old - 1] ?? \"\") + (eols[index] ?? \"\"))\n .join(\"\");\n return { content: out, line: (old) => at.get(old) ?? old };\n}\n\n/** The plain pin of a span of lines, or of an explicit list of them. */\nfunction pinOf(lines: readonly string[], span: PageLines): string | undefined {\n if (span.start < 1 || span.end > lines.length || span.end < span.start) return undefined;\n return hashLines(lines.slice(span.start - 1, span.end).join(\"\\n\"));\n}\n\n/**\n * The claim end of a marker-anchored entry, read against proposal 0054's\n * three spans. `misplaced` is the marker's misplacement, when it has one.\n *\n * For a misplaced marker at `moved`, `fileLines` is the span that held and\n * `newLines` the span the pin will cover once the marker moves. Both are file\n * lines: a marker-anchored claim has no body lines of its own.\n */\nexport function markerClaimEnd(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n misplaced: MisplacedMarker | undefined,\n): ClaimEnd {\n const { citation, marker } = entry;\n const pin = citation.claim?.integrity;\n const quote = citation.quote === true;\n if (marker === undefined || pin === undefined) return { status: \"changed\" };\n const current = anchoredLines(page.content, marker.end, page.format, quote);\n if (current === undefined) return { status: \"changed\" };\n\n /** The claim end this span reads as, and where the move will take it. */\n const claimAt = (span: PageLines, status: ClaimEnd[\"status\"], to?: PageLines): ClaimEnd => {\n const end: ClaimEnd = { fileLines: spellLines(span), status };\n if (to !== undefined) {\n end.newLines = spellLines(to);\n end.newFileLines = end.newLines;\n }\n if (status === \"changed\") end.text = lines.slice(span.start - 1, Math.min(span.end, lines.length));\n return end;\n };\n\n // A quote marker's pin covers its block, which no move touches, and the\n // block reading never changed, so there is one span to read it against.\n if (quote) {\n return claimAt(current, pinOf(lines, current) === pin ? \"current\" : \"changed\");\n }\n\n if (misplaced !== undefined) {\n const to = movedUnit(misplaced);\n if (hashLines(unitText(lines, misplaced).join(\"\\n\")) === pin) return claimAt(to, \"current\");\n if (pinOf(lines, current) === pin) return claimAt(current, \"moved\", to);\n const pre43 = pre43Span(lines, marker.line);\n if (pre43 !== undefined && pinOf(lines, pre43) === pin) return claimAt(pre43, \"moved\", to);\n return claimAt(current, \"changed\");\n }\n\n if (pinOf(lines, current) === pin) return claimAt(current, \"current\");\n // Stacked markers written before PR #43 were pinned over a sibling marker\n // line and the paragraph. That renders fine, so only the pin is repaired.\n const pre43 = pre43Span(lines, marker.line);\n if (pre43 !== undefined && pinOf(lines, pre43) === pin) return claimAt(pre43, \"moved\", current);\n return claimAt(current, \"changed\");\n}\n","/**\n * The claim end: the page text a citation supports, classified by the same\n * machinery as the source end and against the page as it is now.\n *\n * The claim's lines are body-relative, so editing the frontmatter never moves\n * them; every line a person reads is a file line, translated here. The pin\n * holds at the recorded lines: `current`. The same text is found verbatim\n * elsewhere in the body: `moved`, once, or `moved-ambiguous`. Nowhere:\n * `changed`, the sentence was edited. A marker-anchored claim pins what the\n * marker anchors, so its text never moves on the page; it is `current`,\n * `changed`, or, when the pin holds over a span the marker no longer anchors,\n * `moved`. `src/cite/core/reanchor.ts` reads those spans.\n */\nimport type {\n ClaimEnd,\n PageCitation,\n PageCitations,\n PageLines,\n} from \"../types.js\";\nimport {\n findWindows,\n parseLines,\n pinOfLines,\n spellLines,\n toBodyLines,\n toFileLines,\n} from \"../../shared/pin.js\";\nimport {\n markerClaimEnd,\n misplacedMarkerAt,\n type MisplacedMarker,\n} from \"./reanchor.js\";\nimport {\n anchoredLines,\n fenceAround,\n fenceSpanAt,\n isMarkerLine,\n isTableRow,\n isTableSeparator,\n lineAt,\n offsetOfLine,\n paragraphAfter,\n} from \"./statements.js\";\n\n// The line translation and the claim pin are the shared pin engine's; this path keeps cite's imports working.\nexport { pinOfLines, toBodyLines, toFileLines } from \"../../shared/pin.js\";\n\nexport function normalizeWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * The hashing rule's normalization for a whole quoted block: one BOM, CRLF →\n * LF, and one trailing LF dropped. It differs from the shared `normalizeText`\n * only in that last step, because a quote is compared as one joined block\n * rather than split into lines first.\n */\nfunction normalizeBlock(text: string): string {\n let out = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n out = out.replace(/\\r\\n/g, \"\\n\");\n return out.endsWith(\"\\n\") ? out.slice(0, -1) : out;\n}\n\n/** `true` when the block's normalized text equals the cited lines under the hashing rule. */\nexport function blockMatches(blockText: string, citedJoined: string): boolean {\n return normalizeBlock(blockText) === normalizeBlock(citedJoined);\n}\n\n/** The page lines a range covers, as far as the page reaches. */\nfunction textAt(lines: readonly string[], range: PageLines): string[] {\n return lines.slice(range.start - 1, Math.min(range.end, lines.length));\n}\n\n/** The first file line of a classified claim: where its findings sit. */\nexport function claimLine(claim: ClaimEnd): number | undefined {\n const at = claim.fileLines === undefined ? undefined : parseLines(claim.fileLines);\n return at?.start;\n}\n\n/** Where the claim is now: the moved-to lines when it moved, else the recorded ones. */\nexport function claimLineNow(claim: ClaimEnd): number | undefined {\n const spec = claim.newFileLines ?? claim.candidateFileLines?.[0] ?? claim.fileLines;\n const at = spec === undefined ? undefined : parseLines(spec);\n return at?.start;\n}\n\n/** The file lines the claim occupies now, for the quote check. */\nexport function claimLinesNow(claim: ClaimEnd): PageLines | undefined {\n const spec = claim.newFileLines ?? claim.candidateFileLines?.[0] ?? claim.fileLines;\n return spec === undefined ? undefined : parseLines(spec);\n}\n\n/**\n * Classify one entry's claim end against the page. `lines` is the page under\n * the hashing rule (`splitLines`). `null` for an entry with no `claim`: a\n * bare pin, or a marker with no drift check on its sentence.\n */\nexport function claimEnd(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n misplaced?: MisplacedMarker,\n): ClaimEnd | null {\n const { citation, marker } = entry;\n const claim = citation.claim;\n if (claim === undefined) return null;\n const body = page.bodyLine;\n\n if (claim.lines !== undefined) {\n const recorded = parseLines(claim.lines);\n // An unreadable range is `entry-invalid`, and that entry is never classified.\n if (recorded === undefined) return { status: \"skipped\" };\n const file = toFileLines(recorded, body);\n const end: ClaimEnd = {\n lines: spellLines(recorded),\n fileLines: spellLines(file),\n status: \"changed\",\n };\n // Lines and a marker both: `anchor-invalid`, and neither anchor is judged.\n if (marker !== undefined) return { ...end, status: \"skipped\" };\n if (pinOfLines(lines, file) === claim.integrity) return { ...end, status: \"current\" };\n\n const width = recorded.end - recorded.start + 1;\n const found = findWindows(lines.slice(body - 1), width, claim.integrity, undefined, {\n around: recorded.start,\n });\n const spans = found.starts.map((start) => ({ start, end: start + width - 1 }));\n const [only] = spans;\n if (spans.length === 1 && only !== undefined) {\n return {\n ...end,\n status: \"moved\",\n newLines: spellLines(only),\n newFileLines: spellLines(toFileLines(only, body)),\n };\n }\n if (spans.length > 1) {\n return {\n ...end,\n status: \"moved-ambiguous\",\n candidates: spans.map(spellLines),\n candidateFileLines: spans.map((span) => spellLines(toFileLines(span, body))),\n };\n }\n return { ...end, text: textAt(lines, file) };\n }\n\n if (marker !== undefined) {\n // The marker travels with its text, so what moves is the span the marker\n // anchors, not the text. `reanchor.ts` reads the three spans.\n return markerClaimEnd(\n page,\n entry,\n lines,\n misplaced ?? misplacedMarkerAt(page, lines, marker.line, entry),\n );\n }\n\n // A claim pin with neither lines nor a marker anchors nothing at all.\n return { status: \"changed\" };\n}\n\n/**\n * Where else in the body the claim's text sits, as file lines. A claim whose\n * text repeats is `moved-ambiguous` the moment it moves, so `add` says so\n * while the pin is still being written, and `update --accept` says so before\n * it mints a pin that cannot tell two copies apart. The search is the\n * classifier's own.\n */\nexport function otherClaimSpans(\n lines: readonly string[],\n pageLines: PageLines,\n pin: string,\n bodyLine: number,\n): PageLines[] {\n const width = pageLines.end - pageLines.start + 1;\n const found = findWindows(lines.slice(bodyLine - 1), width, pin, undefined, {\n around: toBodyLines(pageLines, bodyLine).start,\n });\n return found.starts\n .map((start) => toFileLines({ start, end: start + width - 1 }, bodyLine))\n .filter((span) => span.start !== pageLines.start);\n}\n\n/** How many other locations a notice names before it starts counting them. */\nconst NAMED_SPANS = 3;\n\n/** `line 17`, `lines 16 and 18`, `lines 16, 18, 20 and 2 more`. */\nexport function spellElsewhere(spans: readonly PageLines[]): string {\n const first = spans[0];\n const noun = spans.length === 1 && first !== undefined && first.start === first.end ? \"line\" : \"lines\";\n const named = spans.slice(0, NAMED_SPANS).map((span) => spellLines(span));\n const rest = spans.length - named.length;\n if (rest > 0) return `${noun} ${named.join(\", \")} and ${String(rest)} more`;\n const last = named.pop() ?? \"\";\n return named.length === 0 ? `${noun} ${last}` : `${noun} ${named.join(\", \")} and ${last}`;\n}\n\n/**\n * What `update --accept` re-pins over: the paragraph, whole fenced block, or\n * lines inside a fenced block at a line.\n *\n * The three kinds are not interchangeable. `\"block\"` covers a fence, its\n * content and its closing fence, which is the only shape a `quote: true`\n * entry may hold. `\"fenced-lines\"` covers content lines inside a block and\n * neither fence, which is what a claim minted over part of a code sample\n * holds. `\"paragraph\"` covers prose, and table rows too, since `ClaimUnit`\n * draws no line between them.\n */\nexport interface ClaimUnit {\n lines: PageLines;\n kind: \"paragraph\" | \"block\" | \"fenced-lines\";\n text: string[];\n}\n\n/**\n * Why no unit sits at a file line. Each one is a different problem with a\n * different repair, so `update --accept` names which it hit rather than\n * leaving the entry skipped with no reason.\n */\nexport type NoUnit =\n | \"outside\"\n | \"blank\"\n | \"fence-crossed\"\n | \"marker\"\n | \"not-a-paragraph\"\n | \"table-short\"\n | \"table-rule\";\n\n/**\n * The span a claim of the recorded width holds at a line. A unit whose extent\n * is the author's, rather than the page's, keeps the number of lines it was\n * minted over: table rows and lines inside a fenced block both. One recorded\n * line gives one line, and five give five.\n */\nfunction spanOf(line: number, recorded: PageLines | undefined): PageLines {\n const width = recorded === undefined ? 1 : Math.max(1, recorded.end - recorded.start + 1);\n return { start: line, end: line + width - 1 };\n}\n\n/**\n * The rows a claim on a table re-pins over, or why there are none.\n *\n * A row is a statement, so a claim over N rows is a claim over N statements.\n * The extent is the author's, and re-pinning re-mints the hash over it rather\n * than redesigning it: one recorded line gives one row, and five give five.\n * Rows below a one-line claim are other statements, and a table that no longer\n * reaches the recorded end is a question only the author can answer.\n *\n * The unit comes back as `kind: \"paragraph\"`, since `ClaimUnit` names how a\n * unit is bounded and not what it holds. A caller wanting to know whether it\n * holds rows has to ask `isTableRow` about the text, not read `kind`.\n *\n * A span of nothing but `|---|---|` rules is refused. Those lines carry no\n * words, so a pin over them says nothing about what the page claims, and a\n * claim that shifted onto one is a claim the page lost. A header, its rule and\n * a body row is three rows and keeps all three.\n */\nfunction rowsAt(\n line: number,\n lines: readonly string[],\n recorded: PageLines | undefined,\n named: boolean,\n): ClaimUnit | NoUnit {\n const end = spanOf(line, recorded).end;\n if (end > lines.length) return \"table-short\";\n for (let n = line; n <= end; n++) {\n if (!isTableRow(lines[n - 1] ?? \"\")) return \"table-short\";\n }\n const text = lines.slice(line - 1, end);\n if (!named && text.every((row) => isTableSeparator(row))) return \"table-rule\";\n return { lines: { start: line, end }, kind: \"paragraph\", text };\n}\n\n/**\n * The unit at a file line, or why there is none. `unitAt` and `noUnitAt` are\n * the two halves a caller reads, so the guards are written once. `recorded` is\n * the span the claim holds now, which only a table reads. `named` is the\n * operator having named the entry with `--only`: the structural refusals a\n * blanket accept would hit are the ones they have looked at, so they stand\n * down and the line is read as the text it is.\n */\nfunction unitOrWhy(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): ClaimUnit | NoUnit {\n if (line < page.bodyLine || line > lines.length) return \"outside\";\n const own = lines[line - 1] ?? \"\";\n if (own.trim() === \"\") return \"blank\";\n // A line that is one marker and nothing else is another entry's anchor, not\n // claim text. Reading it as text is how a shifted claim gets a confident pin\n // over a comment.\n const marker = isMarkerLine(own, page.format);\n if (marker && !named) return \"marker\";\n const block = fenceSpanAt(page.content, line, page.format);\n if (block !== undefined) {\n return { lines: block, kind: \"block\", text: lines.slice(block.start - 1, block.end) };\n }\n const around = fenceAround(page.content, page.bodyOffset, line, page.format);\n if (around !== undefined) {\n // The claim was minted over lines inside this block, so it is re-pinned\n // over as many lines as it recorded, at the line it starts on. Re-pinning\n // the block around them would widen what the pin covers, which is the one\n // thing an accept may never do. A span reaching the closing fence, or past\n // it, is not lines inside a block at all, and stays refused.\n const span = spanOf(line, recorded);\n return span.end < around.end\n ? { lines: span, kind: \"fenced-lines\", text: lines.slice(span.start - 1, span.end) }\n : \"fence-crossed\";\n }\n // A table row is a statement of its own, and nothing between two rows ends a\n // paragraph, so the walk below would read the rest of the table as one.\n if (isTableRow(own)) return rowsAt(line, lines, recorded, named);\n // The format ends the paragraph at a marker under it, so a re-pin never\n // swallows another entry's anchor. A named entry sitting on a marker is read\n // without it, because there the marker is the line being accepted.\n const paragraph = paragraphAfter(\n page.content,\n offsetOfLine(page.content, line),\n marker ? undefined : page.format,\n );\n if (paragraph === undefined || paragraph.line !== line) return \"not-a-paragraph\";\n const span: PageLines = { start: line, end: lineAt(page.content, paragraph.end) };\n return { lines: span, kind: \"paragraph\", text: lines.slice(span.start - 1, span.end) };\n}\n\n/**\n * The paragraph, fenced block, fenced lines or table rows at a file line.\n * Undefined when the line holds no claim at all: it is blank, outside the\n * body, another entry's marker, a table rule, or a line whose claim runs out\n * of the fenced block it starts in. Those are the claims `update --accept`\n * skips, and `noUnitAt` says which of them it is.\n *\n * A paragraph runs from this line to its end, not from the paragraph's own\n * first line. The line asked about is the claim's first line, and re-pinning\n * has to leave that where it is, so a claim that started mid-paragraph keeps\n * starting there. A paragraph that gained a sentence gained it as part of the\n * same statement, which is why a claim grows with it.\n *\n * A table does not work that way. Each row is a statement, so a claim keeps\n * the number of rows `recorded` gives it, and refuses when the table no longer\n * reaches that far. Callers that know the claim's current span pass it.\n */\nexport function unitAt(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): ClaimUnit | undefined {\n const found = unitOrWhy(page, line, lines, recorded, named);\n return typeof found === \"string\" ? undefined : found;\n}\n\n/** Why `unitAt` found nothing at a file line, or undefined when it found a unit. */\nexport function noUnitAt(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): NoUnit | undefined {\n const found = unitOrWhy(page, line, lines, recorded, named);\n return typeof found === \"string\" ? found : undefined;\n}\n\n/** The lines a marker anchors now, for `update --accept` on a marker-anchored claim. */\nexport function markerUnit(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n): ClaimUnit | undefined {\n const { marker, citation } = entry;\n if (marker === undefined) return undefined;\n const span = anchoredLines(page.content, marker.end, page.format, citation.quote === true);\n if (span === undefined || span.end > lines.length) return undefined;\n return {\n lines: span,\n kind: citation.quote === true ? \"block\" : \"paragraph\",\n text: lines.slice(span.start - 1, span.end),\n };\n}\n"],"mappings":"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","names":["at","pre43","at","named","span","at","rule"]}
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ToolError
4
+ } from "./chunk-G3T47CFV.js";
5
+
6
+ // src/shared/package-root.ts
7
+ import { existsSync } from "node:fs";
8
+ import { dirname, join } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ function packageRoot(moduleUrl) {
11
+ let dir = dirname(fileURLToPath(moduleUrl));
12
+ for (; ; ) {
13
+ if (existsSync(join(dir, "package.json"))) return dir;
14
+ const parent = dirname(dir);
15
+ if (parent === dir) {
16
+ throw new ToolError(`No package.json above ${fileURLToPath(moduleUrl)}`);
17
+ }
18
+ dir = parent;
19
+ }
20
+ }
21
+
22
+ export {
23
+ packageRoot
24
+ };
25
+ //# sourceMappingURL=chunk-TIUTIOFB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/package-root.ts"],"sourcesContent":["/**\n * The package root, for assets that ship beside the code.\n *\n * Some files are read by path at runtime rather than imported: a JSON Schema a\n * validator is pointed at, a template a linter loads. They live at the package\n * root (`schemas/<tool>/…`), listed in `files`, and are reached by walking up\n * from the calling module until a `package.json` appears. That is the one\n * rule that holds both in the source tree, where a module sits two or three\n * directories down, and in the bundle, where it sits in `dist/`.\n */\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { ToolError } from \"./errors.js\";\n\nexport function packageRoot(moduleUrl: string): string {\n let dir = dirname(fileURLToPath(moduleUrl));\n for (;;) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) {\n // A `ToolError`, not a bare one: the bin runner renders anything else as\n // \"Unexpected error:\" with a stack trace, which is what it says about a\n // bug. A package whose files did not ship is an operational failure and\n // reads as one line and exit 2, like every other.\n throw new ToolError(`No package.json above ${fileURLToPath(moduleUrl)}`);\n }\n dir = parent;\n }\n}\n"],"mappings":";;;;;;AAUA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAGvB,SAAS,YAAY,WAA2B;AACrD,MAAI,MAAM,QAAQ,cAAc,SAAS,CAAC;AAC1C,aAAS;AACP,QAAI,WAAW,KAAK,KAAK,cAAc,CAAC,EAAG,QAAO;AAClD,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,KAAK;AAKlB,YAAM,IAAI,UAAU,yBAAyB,cAAc,SAAS,CAAC,EAAE;AAAA,IACzE;AACA,UAAM;AAAA,EACR;AACF;","names":[]}