@hawkeyexl/manni 2.8.0 → 2.8.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.
package/README.md CHANGED
@@ -98,7 +98,7 @@ actually reads rather than hand-written:
98
98
  ```yaml
99
99
  repos:
100
100
  - repo: https://github.com/hawkeyexl/manni
101
- rev: v2.8.0
101
+ rev: v2.8.1
102
102
  hooks:
103
103
  - id: manni-meta
104
104
  ```
@@ -71,7 +71,7 @@ import {
71
71
  withValueAt,
72
72
  writeEncryptionKey,
73
73
  writeFileAtomic
74
- } from "./chunk-MB3DIO7S.js";
74
+ } from "./chunk-RLHN765L.js";
75
75
 
76
76
  // src/meta/core/reencrypt.ts
77
77
  import { extname } from "node:path";
@@ -855,6 +855,10 @@ var TABLE_ROW = /^[ \t]*\|/;
855
855
  function isTableRow(line) {
856
856
  return TABLE_ROW.test(line);
857
857
  }
858
+ var TABLE_RULE = /^(?=[^|]*\|)[ \t]*\|?(?:[ \t]*:?-+:?[ \t]*\|)*[ \t]*:?-+:?[ \t]*\|?[ \t]*$/;
859
+ function isTableSeparator(line) {
860
+ return TABLE_RULE.test(line);
861
+ }
858
862
  function isBoundLine(line, format) {
859
863
  if (ADORNMENT.test(line)) return true;
860
864
  switch (format) {
@@ -1697,36 +1701,61 @@ function claimEnd(page, entry, lines, misplaced) {
1697
1701
  }
1698
1702
  return { status: "changed" };
1699
1703
  }
1700
- function rowsAt(line, lines, recorded) {
1704
+ function otherClaimSpans(lines, pageLines, pin, bodyLine) {
1705
+ const width = pageLines.end - pageLines.start + 1;
1706
+ const found = findWindows(lines.slice(bodyLine - 1), width, pin, void 0, {
1707
+ around: toBodyLines(pageLines, bodyLine).start
1708
+ });
1709
+ return found.starts.map((start) => toFileLines({ start, end: start + width - 1 }, bodyLine)).filter((span) => span.start !== pageLines.start);
1710
+ }
1711
+ var NAMED_SPANS = 3;
1712
+ function spellElsewhere(spans) {
1713
+ const first = spans[0];
1714
+ const noun = spans.length === 1 && first !== void 0 && first.start === first.end ? "line" : "lines";
1715
+ const named4 = spans.slice(0, NAMED_SPANS).map((span) => spellLines(span));
1716
+ const rest = spans.length - named4.length;
1717
+ if (rest > 0) return `${noun} ${named4.join(", ")} and ${String(rest)} more`;
1718
+ const last = named4.pop() ?? "";
1719
+ return named4.length === 0 ? `${noun} ${last}` : `${noun} ${named4.join(", ")} and ${last}`;
1720
+ }
1721
+ function rowsAt(line, lines, recorded, named4) {
1701
1722
  const width = recorded === void 0 ? 1 : Math.max(1, recorded.end - recorded.start + 1);
1702
1723
  const end = line + width - 1;
1703
1724
  if (end > lines.length) return "table-short";
1704
1725
  for (let n = line; n <= end; n++) {
1705
1726
  if (!isTableRow(lines[n - 1] ?? "")) return "table-short";
1706
1727
  }
1707
- return { lines: { start: line, end }, kind: "paragraph", text: lines.slice(line - 1, end) };
1728
+ const text = lines.slice(line - 1, end);
1729
+ if (!named4 && text.every((row) => isTableSeparator(row))) return "table-rule";
1730
+ return { lines: { start: line, end }, kind: "paragraph", text };
1708
1731
  }
1709
- function unitOrWhy(page, line, lines, recorded) {
1732
+ function unitOrWhy(page, line, lines, recorded, named4 = false) {
1710
1733
  if (line < page.bodyLine || line > lines.length) return "outside";
1711
1734
  const own = lines[line - 1] ?? "";
1712
1735
  if (own.trim() === "") return "blank";
1736
+ const marker = isMarkerLine(own, page.format);
1737
+ if (marker && !named4) return "marker";
1713
1738
  const block = fenceSpanAt(page.content, line, page.format);
1714
1739
  if (block !== void 0) {
1715
1740
  return { lines: block, kind: "block", text: lines.slice(block.start - 1, block.end) };
1716
1741
  }
1717
1742
  if (insideFence(page.content, page.bodyOffset, line, page.format)) return "fenced";
1718
- if (isTableRow(own)) return rowsAt(line, lines, recorded);
1719
- const paragraph = paragraphAfter(page.content, offsetOfLine(page.content, line));
1743
+ if (isTableRow(own)) return rowsAt(line, lines, recorded, named4);
1744
+ const paragraph = paragraphAfter(
1745
+ page.content,
1746
+ offsetOfLine(page.content, line),
1747
+ marker ? void 0 : page.format
1748
+ );
1720
1749
  if (paragraph === void 0 || paragraph.line !== line) return "not-a-paragraph";
1721
1750
  const span = { start: line, end: lineAt(page.content, paragraph.end) };
1722
1751
  return { lines: span, kind: "paragraph", text: lines.slice(span.start - 1, span.end) };
1723
1752
  }
1724
- function unitAt(page, line, lines, recorded) {
1725
- const found = unitOrWhy(page, line, lines, recorded);
1753
+ function unitAt(page, line, lines, recorded, named4 = false) {
1754
+ const found = unitOrWhy(page, line, lines, recorded, named4);
1726
1755
  return typeof found === "string" ? void 0 : found;
1727
1756
  }
1728
- function noUnitAt(page, line, lines, recorded) {
1729
- const found = unitOrWhy(page, line, lines, recorded);
1757
+ function noUnitAt(page, line, lines, recorded, named4 = false) {
1758
+ const found = unitOrWhy(page, line, lines, recorded, named4);
1730
1759
  return typeof found === "string" ? found : void 0;
1731
1760
  }
1732
1761
  function markerUnit(page, entry, lines) {
@@ -1870,6 +1899,19 @@ function sharesSentence(a, b) {
1870
1899
  const left = new Set(sentencesOf(a));
1871
1900
  return sentencesOf(b).some((sentence) => left.has(sentence));
1872
1901
  }
1902
+ function wordSet(text) {
1903
+ return new Set(
1904
+ text.toLowerCase().split(/\s+/).filter((word) => word !== "")
1905
+ );
1906
+ }
1907
+ function wordShare(was, now) {
1908
+ const left = wordSet(was);
1909
+ if (left.size === 0) return 1;
1910
+ const right = wordSet(now);
1911
+ let held = 0;
1912
+ for (const word of left) if (right.has(word)) held++;
1913
+ return held / left.size;
1914
+ }
1873
1915
  function holdsWords(outer, inner) {
1874
1916
  if (inner === "") return true;
1875
1917
  if (outer === inner) return true;
@@ -3648,23 +3690,6 @@ function emptyClaimRefusal(lines, pageLines, at2) {
3648
3690
  const only = span[0] ?? "";
3649
3691
  return only.trim() === "" ? `${at2} is blank.` : `${at2} is a fence line, not claim text.`;
3650
3692
  }
3651
- function otherClaimSpans(lines, pageLines, pin, bodyLine) {
3652
- const width = pageLines.end - pageLines.start + 1;
3653
- const found = findWindows(lines.slice(bodyLine - 1), width, pin, void 0, {
3654
- around: toBodyLines(pageLines, bodyLine).start
3655
- });
3656
- return found.starts.map((start) => toFileLines({ start, end: start + width - 1 }, bodyLine)).filter((span) => span.start !== pageLines.start);
3657
- }
3658
- var NAMED_SPANS = 3;
3659
- function spellElsewhere(spans) {
3660
- const first = spans[0];
3661
- const noun = spans.length === 1 && first !== void 0 && first.start === first.end ? "line" : "lines";
3662
- const named4 = spans.slice(0, NAMED_SPANS).map((span) => spellLines(span));
3663
- const rest = spans.length - named4.length;
3664
- if (rest > 0) return `${noun} ${named4.join(", ")} and ${String(rest)} more`;
3665
- const last = named4.pop() ?? "";
3666
- return named4.length === 0 ? `${noun} ${last}` : `${noun} ${named4.join(", ")} and ${last}`;
3667
- }
3668
3693
  async function runAdd(opts) {
3669
3694
  const cwd = resolve4(opts.cwd ?? process.cwd());
3670
3695
  const run3 = await resolveCiteRun({
@@ -4111,10 +4136,14 @@ function sayNoUnit(reason) {
4111
4136
  return "the line is blank";
4112
4137
  case "fenced":
4113
4138
  return "the line sits inside a fenced block";
4139
+ case "marker":
4140
+ return "that line now holds a cite marker, not claim text";
4114
4141
  case "not-a-paragraph":
4115
4142
  return "the line does not start a paragraph";
4116
4143
  case "table-short":
4117
4144
  return "the table no longer holds every row the claim covers";
4145
+ case "table-rule":
4146
+ return "that line is a table rule, not claim text";
4118
4147
  }
4119
4148
  }
4120
4149
  function settles(plan) {
@@ -4317,7 +4346,8 @@ function rewriteOf(plan) {
4317
4346
  fromPin: plan.pin,
4318
4347
  toPin: plan.would,
4319
4348
  at: plan.at,
4320
- commitSha: plan.commitSha
4349
+ commitSha: plan.commitSha,
4350
+ ...plan.wordShare === void 0 ? {} : { wordShare: plan.wordShare }
4321
4351
  };
4322
4352
  case "claim-shifted":
4323
4353
  return {
@@ -4383,12 +4413,17 @@ function rewriteOf(plan) {
4383
4413
  }
4384
4414
  }
4385
4415
  }
4416
+ var CLAIM_WORD_SHARE = 0.5;
4386
4417
  function replacementAt(claim, text, format) {
4387
4418
  const was = claim.baselineText;
4388
4419
  const commit = claim.commitSha;
4389
4420
  if (was === void 0 || commit === void 0) return void 0;
4390
- if (sharesSentence(claimWords(was, format), claimWords(text, format))) return void 0;
4391
- return commit;
4421
+ const before = claimWords(was, format);
4422
+ const now = claimWords(text, format);
4423
+ if (!sharesSentence(before, now)) return { commit };
4424
+ const share = wordShare(before, now);
4425
+ if (share < CLAIM_WORD_SHARE) return { commit, share };
4426
+ return void 0;
4392
4427
  }
4393
4428
  var QUOTE_CAP = 200;
4394
4429
  function quoted(text) {
@@ -4578,7 +4613,8 @@ async function runUpdate(opts) {
4578
4613
  if (claim !== null && claim.status === "changed" && entry !== void 0 && result.anchor !== "marker") {
4579
4614
  const held = claim.fileLines === void 0 ? void 0 : parseLines(claim.fileLines);
4580
4615
  const at2 = held?.start;
4581
- const unit = at2 === void 0 ? void 0 : unitAt(page, at2, lines, held);
4616
+ const named4 = only !== void 0;
4617
+ const unit = at2 === void 0 ? void 0 : unitAt(page, at2, lines, held, named4);
4582
4618
  const wantsBlock = entry.citation.quote === true;
4583
4619
  const pin = unit === void 0 ? void 0 : pinOfLines(lines, unit.lines);
4584
4620
  const wide = unit === void 0 ? void 0 : tooWide(unit.lines);
@@ -4588,7 +4624,7 @@ async function runUpdate(opts) {
4588
4624
  why: `Not re-pinned: the ${unit.kind} ${wide}.`
4589
4625
  });
4590
4626
  } else if (unit === void 0) {
4591
- const why = at2 === void 0 ? void 0 : noUnitAt(page, at2, lines, held);
4627
+ const why = at2 === void 0 ? void 0 : noUnitAt(page, at2, lines, held, named4);
4592
4628
  if (why !== void 0) {
4593
4629
  declined.set(result.origin.index, {
4594
4630
  rule: "claim-changed",
@@ -4596,16 +4632,25 @@ async function runUpdate(opts) {
4596
4632
  });
4597
4633
  }
4598
4634
  } else if (pin !== void 0 && (!wantsBlock || unit.kind === "block")) {
4635
+ const elsewhere = named4 ? [] : otherClaimSpans(lines, unit.lines, pin, page.bodyLine);
4599
4636
  const replaced = replacementAt(claim, unit.text, page.format);
4600
4637
  if (replaced !== void 0 && only === void 0) {
4601
4638
  out.push({
4602
4639
  kind: "claim-replaced",
4603
4640
  result,
4604
4641
  at: unit.lines.start,
4605
- commitSha: replaced,
4642
+ commitSha: replaced.commit,
4643
+ ...replaced.share === void 0 ? {} : { wordShare: replaced.share },
4606
4644
  pin: entry.citation.claim?.integrity ?? "",
4607
4645
  would: pin
4608
4646
  });
4647
+ } else if (elsewhere.length > 0) {
4648
+ const id = result.citation.id;
4649
+ const anyway = id === void 0 ? "" : ` Re-run with --only ${id} to accept it anyway.`;
4650
+ declined.set(result.origin.index, {
4651
+ rule: "claim-changed",
4652
+ why: `Not re-pinned: the text there also appears at ${spellElsewhere(elsewhere)}, so a pin cannot identify it.${anyway}`
4653
+ });
4609
4654
  } else {
4610
4655
  const plan = { kind: "claim-accepted", result, unit, pin };
4611
4656
  if (replaced !== void 0) plan.replaced = true;
@@ -4732,7 +4777,8 @@ async function runUpdate(opts) {
4732
4777
  kind: "claim-replaced",
4733
4778
  result,
4734
4779
  at: now.span.start,
4735
- commitSha: replaced,
4780
+ commitSha: replaced.commit,
4781
+ ...replaced.share === void 0 ? {} : { wordShare: replaced.share },
4736
4782
  pin: recorded,
4737
4783
  would: now.pin
4738
4784
  }
@@ -5260,7 +5306,12 @@ function movedSpan(rewrite) {
5260
5306
  }
5261
5307
  function refusalLine(rewrite) {
5262
5308
  const at2 = shortCommit(rewrite.commitSha ?? "");
5263
- return `claim at ${spellAtSpec(String(rewrite.at ?? 0))} skipped: that line now holds different text than the claim at ${at2}. Re-add it with cite add.`;
5309
+ const where = `claim at ${spellAtSpec(String(rewrite.at ?? 0))} skipped:`;
5310
+ if (rewrite.wordShare !== void 0) {
5311
+ const share = Math.round(rewrite.wordShare * 100);
5312
+ return `${where} that line now holds text sharing ${String(share)}% of the claim's words at ${at2}. Re-add it with cite add.`;
5313
+ }
5314
+ return `${where} that line now holds different text than the claim at ${at2}. Re-add it with cite add.`;
5264
5315
  }
5265
5316
  function rewriteLine(rewrite) {
5266
5317
  const word = rewrite.from.includes("-") ? "lines" : "line";
@@ -5922,4 +5973,4 @@ export {
5922
5973
  runKeyRotate,
5923
5974
  runKeySet
5924
5975
  };
5925
- //# sourceMappingURL=chunk-O6RXG33V.js.map
5976
+ //# sourceMappingURL=chunk-FWB6LGBB.js.map