@hawkeyexl/manni 2.3.9 → 2.3.10

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.3.9
101
+ rev: v2.3.10
102
102
  hooks:
103
103
  - id: manni-meta
104
104
  ```
@@ -70,7 +70,7 @@ import {
70
70
  withValueAt,
71
71
  writeEncryptionKey,
72
72
  writeFileAtomic
73
- } from "./chunk-LC4H35XX.js";
73
+ } from "./chunk-TNT3ZROC.js";
74
74
 
75
75
  // src/meta/core/reencrypt.ts
76
76
  import { extname } from "node:path";
@@ -260,6 +260,7 @@ __export(cite_exports, {
260
260
  runCheck: () => runCheck,
261
261
  runUpdate: () => runUpdate,
262
262
  shortCommit: () => shortCommit,
263
+ shortLine: () => shortLine,
263
264
  shortPin: () => shortPin,
264
265
  shortSrc: () => shortSrc,
265
266
  sidecarsFor: () => sidecarsFor,
@@ -420,6 +421,11 @@ function shortSrc(src) {
420
421
  const lines = colon === -1 ? "" : src.slice(colon);
421
422
  return token.length <= 5 ? src : `${token.slice(0, 5)}\u2026${lines}`;
422
423
  }
424
+ var LINE_WIDTH = 60;
425
+ function shortLine(text) {
426
+ const one = text.replace(/\s+/g, " ").trim();
427
+ return one.length <= LINE_WIDTH ? one : `${one.slice(0, LINE_WIDTH)}\u2026`;
428
+ }
423
429
 
424
430
  // src/cite/core/sources.ts
425
431
  import fg from "fast-glob";
@@ -2866,6 +2872,50 @@ async function citedText(root, index, src, key) {
2866
2872
  function spellAt(lines) {
2867
2873
  return lines.start === lines.end ? `line ${String(lines.start)}` : `lines ${String(lines.start)}-${String(lines.end)}`;
2868
2874
  }
2875
+ function entryName(entry) {
2876
+ return entry.citation.id ?? `/citations/${String(entry.origin.index)}`;
2877
+ }
2878
+ function duplicateOf(page, src, pageLines) {
2879
+ const wanted = formatSrc(parseSrc(src));
2880
+ return page.citations.find((entry) => {
2881
+ const { citation } = entry;
2882
+ if (spellSource(citation.source) !== wanted) return false;
2883
+ if (pageLines === void 0) return citation.claim === void 0;
2884
+ const spec = citation.claim?.lines;
2885
+ if (spec === void 0) return false;
2886
+ const recorded = parseLines(spec);
2887
+ if (recorded === void 0) return false;
2888
+ const file = toFileLines(recorded, page.bodyLine);
2889
+ return file.start === pageLines.start && file.end === pageLines.end;
2890
+ });
2891
+ }
2892
+ function holdsNoText(text) {
2893
+ return text.trim() === "" || ANY_FENCE.test(text);
2894
+ }
2895
+ function emptyClaimRefusal(lines, pageLines, at2) {
2896
+ const span = lines.slice(pageLines.start - 1, pageLines.end);
2897
+ if (span.some((text) => !holdsNoText(text))) return void 0;
2898
+ if (pageLines.start !== pageLines.end) return `${at2} holds no claim text.`;
2899
+ const only = span[0] ?? "";
2900
+ return only.trim() === "" ? `${at2} is blank.` : `${at2} is a fence line, not claim text.`;
2901
+ }
2902
+ function otherClaimSpans(lines, pageLines, pin, bodyLine) {
2903
+ const width = pageLines.end - pageLines.start + 1;
2904
+ const found = findWindows(lines.slice(bodyLine - 1), width, pin, void 0, {
2905
+ around: toBodyLines(pageLines, bodyLine).start
2906
+ });
2907
+ return found.starts.map((start) => toFileLines({ start, end: start + width - 1 }, bodyLine)).filter((span) => span.start !== pageLines.start);
2908
+ }
2909
+ var NAMED_SPANS = 3;
2910
+ function spellElsewhere(spans) {
2911
+ const first = spans[0];
2912
+ const noun = spans.length === 1 && first !== void 0 && first.start === first.end ? "line" : "lines";
2913
+ const named3 = spans.slice(0, NAMED_SPANS).map((span) => spellLines(span));
2914
+ const rest = spans.length - named3.length;
2915
+ if (rest > 0) return `${noun} ${named3.join(", ")} and ${String(rest)} more`;
2916
+ const last = named3.pop() ?? "";
2917
+ return named3.length === 0 ? `${noun} ${last}` : `${noun} ${named3.join(", ")} and ${last}`;
2918
+ }
2869
2919
  function shiftedEntries(citations, insertLine, bodyLine, label) {
2870
2920
  const out = { frontmatter: [], manifest: /* @__PURE__ */ new Map() };
2871
2921
  for (const { citation, origin } of citations) {
@@ -2964,6 +3014,12 @@ async function runAdd(opts) {
2964
3014
  );
2965
3015
  }
2966
3016
  }
3017
+ const duplicate = marker ? void 0 : duplicateOf(page, opts.src, pageLines);
3018
+ if (duplicate !== void 0) {
3019
+ const src = shortSrc(spellSource(duplicate.citation.source));
3020
+ const what = pageLines === void 0 ? `a bare pin for ${src}` : `an entry for ${spellAt(pageLines)} and ${src}`;
3021
+ throw new CiteError(`${label} already has ${what} (${entryName(duplicate)}).`);
3022
+ }
2967
3023
  const lines = splitLines(content);
2968
3024
  if (pageLines !== void 0) {
2969
3025
  if (pageLines.end > lines.length) {
@@ -2977,6 +3033,9 @@ async function runAdd(opts) {
2977
3033
  if (span === void 0 || span.end !== pageLines.end) {
2978
3034
  throw new CiteError(`${at2} is not a fenced block, so it cannot be a quote.`);
2979
3035
  }
3036
+ } else if (!marker) {
3037
+ const empty = emptyClaimRefusal(lines, pageLines, at2);
3038
+ if (empty !== void 0) throw new CiteError(empty);
2980
3039
  }
2981
3040
  }
2982
3041
  const client = opts.gitClient ?? gitClient(root);
@@ -2985,6 +3044,7 @@ async function runAdd(opts) {
2985
3044
  let markerAt;
2986
3045
  let claimSpan;
2987
3046
  let claim;
3047
+ let elsewhere = [];
2988
3048
  let shifted = { frontmatter: [], manifest: /* @__PURE__ */ new Map() };
2989
3049
  if (marker && pageLines !== void 0) {
2990
3050
  const holding = unitHolding(content, pageLines.start, format, {
@@ -3027,6 +3087,7 @@ async function runAdd(opts) {
3027
3087
  }
3028
3088
  claimSpan = pageLines;
3029
3089
  claim = { lines: lineSpec(toBodyLines(pageLines, page.bodyLine)), integrity: pin };
3090
+ elsewhere = otherClaimSpans(lines, pageLines, pin, page.bodyLine);
3030
3091
  }
3031
3092
  const mint = (key, encrypt) => mintCitation({
3032
3093
  root,
@@ -3063,6 +3124,12 @@ async function runAdd(opts) {
3063
3124
  });
3064
3125
  citation = await mint(key, true);
3065
3126
  }
3127
+ const srcRange = parseSrc(opts.src);
3128
+ let sourceLine;
3129
+ if (srcRange.start !== void 0 && !isEncryptedValue(citation.source.file)) {
3130
+ const read = await readSource(root, sourceIndex, srcRange, void 0);
3131
+ if (read.kind === "ok") sourceLine = splitLines(read.text)[srcRange.start - 1];
3132
+ }
3066
3133
  const manifests = new ManifestSet();
3067
3134
  let placed;
3068
3135
  if (owner !== void 0) {
@@ -3095,6 +3162,7 @@ async function runAdd(opts) {
3095
3162
  content: after,
3096
3163
  diff: unifiedDiff(label, content, after),
3097
3164
  written: false,
3165
+ ...sourceLine === void 0 ? {} : { sourceLine },
3098
3166
  ...placed === void 0 ? {} : { manifest: placed }
3099
3167
  };
3100
3168
  if (markerAt !== void 0) result.markerLine = markerAt + shift;
@@ -3107,6 +3175,13 @@ async function runAdd(opts) {
3107
3175
  for (const changed of manifests.changed()) await writeFileAtomic(changed.path, changed.text);
3108
3176
  result.manifest.written = true;
3109
3177
  }
3178
+ if (elsewhere.length > 0) {
3179
+ const named3 = elsewhere.map((span) => ({ start: span.start + shift, end: span.end + shift }));
3180
+ const who = citation.id === void 0 ? "" : `${citation.id}: `;
3181
+ opts.onNotice?.(
3182
+ `${who}the claim's text also appears at ${spellElsewhere(named3)}, so a move would be ambiguous. Use --marker, or pin more lines.`
3183
+ );
3184
+ }
3110
3185
  if (opts.commitSha !== false && !await client.available()) {
3111
3186
  opts.onNotice?.(GIT_UNAVAILABLE_COMMIT);
3112
3187
  }
@@ -4290,13 +4365,14 @@ export {
4290
4365
  RULE_ID_PREFIX,
4291
4366
  isCiteRule,
4292
4367
  spellSource,
4368
+ shortPin,
4369
+ shortCommit,
4370
+ shortSrc,
4371
+ shortLine,
4293
4372
  runAdd,
4294
4373
  errorSite,
4295
4374
  runCheck,
4296
4375
  runUpdate,
4297
- shortPin,
4298
- shortCommit,
4299
- shortSrc,
4300
4376
  renderCheckPretty,
4301
4377
  renderUpdatePretty,
4302
4378
  findingMessage,
@@ -4308,4 +4384,4 @@ export {
4308
4384
  runKeyRotate,
4309
4385
  runKeySet
4310
4386
  };
4311
- //# sourceMappingURL=chunk-YSI2VNKE.js.map
4387
+ //# sourceMappingURL=chunk-LORLZO3J.js.map