@hawkeyexl/manni 2.0.0 → 2.1.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.
@@ -2,10 +2,12 @@
2
2
  import {
3
3
  DocmetaError,
4
4
  ENCRYPTION_KEY_ENV,
5
- FILE_SCHEMA_KEY,
6
- KEYED_PIN_PREFIX,
7
5
  LEGACY_CONFIG_NAMES,
6
+ LineRangeError,
7
+ MAX_RANGE_LINES,
8
8
  META_CONTEXT,
9
+ MOVE_BUDGET_BYTES,
10
+ MOVE_WINDOW_LINES,
9
11
  PATH_JOIN,
10
12
  STDIN_LABEL,
11
13
  STDIN_TOKEN,
@@ -15,7 +17,6 @@ import {
15
17
  classifyRef,
16
18
  committedKeyWarning,
17
19
  decryptValue,
18
- deepEqual,
19
20
  encryptValue,
20
21
  ensureEncryptionKey,
21
22
  errorMessage,
@@ -28,23 +29,29 @@ import {
28
29
  findConfigFile,
29
30
  findFamilyConfigFile,
30
31
  findGitRoot,
32
+ findWindows,
31
33
  generateEncryptionKey,
32
34
  gitignoreOptions,
33
- integrityOf,
35
+ hashLines,
36
+ hashRange,
34
37
  isEncryptedValue,
35
38
  isErrorSeverity,
36
39
  isIgnoredByGit,
40
+ isKeyedPin,
37
41
  isMember,
38
42
  isValidEncryptionKey,
39
- keyedPin,
43
+ lineSpec,
40
44
  loadExternalMetadata,
41
45
  locateFrontmatter,
42
46
  memberOf,
43
47
  mergeExternalMetadata,
48
+ normalizeText,
44
49
  orphanEntries,
45
50
  orphanError,
46
51
  orphanJoins,
47
52
  palette,
53
+ parseLines,
54
+ pinOfLines,
48
55
  readConfigFile,
49
56
  readFamilyConfigFile,
50
57
  resolveBaselineRequest,
@@ -52,11 +59,17 @@ import {
52
59
  resolveTargetSet,
53
60
  selectCollections,
54
61
  settleBaseline,
62
+ sliceLines,
63
+ spellLines,
64
+ spliceManifestValue,
65
+ splitLines,
55
66
  supportedExtensions,
67
+ toBodyLines,
68
+ toFileLines,
56
69
  withValueAt,
57
70
  writeEncryptionKey,
58
71
  writeFileAtomic
59
- } from "./chunk-XU2QTJQQ.js";
72
+ } from "./chunk-2DC2GSRH.js";
60
73
 
61
74
  // src/meta/core/reencrypt.ts
62
75
  import { extname } from "node:path";
@@ -200,7 +213,7 @@ __export(cite_exports, {
200
213
  formatStatement: () => formatStatement,
201
214
  gitClient: () => gitClient,
202
215
  hashLines: () => hashLines,
203
- hashRange: () => hashRange,
216
+ hashRange: () => hashRange2,
204
217
  historyOf: () => historyOf,
205
218
  insertStatementBefore: () => insertStatementBefore,
206
219
  insideFence: () => insideFence,
@@ -249,7 +262,7 @@ __export(cite_exports, {
249
262
  shortPin: () => shortPin,
250
263
  shortSrc: () => shortSrc,
251
264
  sidecarsFor: () => sidecarsFor,
252
- sliceLines: () => sliceLines,
265
+ sliceLines: () => sliceLines2,
253
266
  sourceRange: () => sourceRange,
254
267
  spellLines: () => spellLines,
255
268
  spellSource: () => spellSource,
@@ -292,6 +305,14 @@ var CiteError = class extends ToolError {
292
305
  this.name = "CiteError";
293
306
  }
294
307
  };
308
+ function asCiteError(call) {
309
+ try {
310
+ return call();
311
+ } catch (error) {
312
+ if (error instanceof LineRangeError) throw new CiteError(error.message);
313
+ throw error;
314
+ }
315
+ }
295
316
 
296
317
  // src/cite/core/severity.ts
297
318
  var DEFAULT_SEVERITY = {
@@ -324,7 +345,6 @@ function resolveSeverity(overrides) {
324
345
  // src/cite/core/range.ts
325
346
  var FILE_PATTERN = /^(?:~[A-Za-z0-9_-]{82,}|(?!~)(?:(?!\.\.?(?:\/|$))[^/\\:\r\n\t]+)(?:\/(?:(?!\.\.?(?:\/|$))[^/\\:\r\n\t]+))*)$/;
326
347
  var SRC_PATTERN = /^(?:~[A-Za-z0-9_-]{82,}|(?!~)(?:(?!\.\.?(?:\/|:|$))[^/\\:\r\n\t]+)(?:\/(?:(?!\.\.?(?:\/|:|$))[^/\\:\r\n\t]+))*)(?::[1-9][0-9]*(?:-[1-9][0-9]*)?)?$/;
327
- var RANGE_SPEC = /^([1-9][0-9]*)(?:-([1-9][0-9]*))?$/;
328
348
  function parseSrc(src) {
329
349
  if (!SRC_PATTERN.test(src)) {
330
350
  throw new CiteError(
@@ -351,24 +371,6 @@ function formatSrc(range) {
351
371
  if (end === void 0 || end === start) return `${path}:${start}`;
352
372
  return `${path}:${start}-${end}`;
353
373
  }
354
- function parseLines(spec) {
355
- if (typeof spec === "number") {
356
- return Number.isInteger(spec) && spec >= 1 ? { start: spec, end: spec } : void 0;
357
- }
358
- const m = RANGE_SPEC.exec(spec);
359
- const startText = m?.[1];
360
- if (startText === void 0) return void 0;
361
- const start = Number(startText);
362
- const endText = m?.[2];
363
- const end = endText === void 0 ? start : Number(endText);
364
- return end < start ? void 0 : { start, end };
365
- }
366
- function lineSpec(lines) {
367
- return lines.start === lines.end ? lines.start : `${String(lines.start)}-${String(lines.end)}`;
368
- }
369
- function spellLines(lines) {
370
- return String(lineSpec(lines));
371
- }
372
374
  function sourceRange(source) {
373
375
  const range = { path: source.file, encrypted: isEncryptedValue(source.file) };
374
376
  if (source.lines === void 0) return range;
@@ -388,33 +390,11 @@ function rangeLines(range) {
388
390
  }
389
391
 
390
392
  // src/cite/core/hash.ts
391
- function normalizeText(text) {
392
- const body = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
393
- return body.replace(/\r\n/g, "\n");
394
- }
395
- function splitLines(text) {
396
- const parts = normalizeText(text).split("\n");
397
- if (parts.length > 0 && parts[parts.length - 1] === "") parts.pop();
398
- return parts;
399
- }
400
- function sliceLines(lines, range, label) {
401
- const start = range?.start;
402
- if (start === void 0) return lines.join("\n");
403
- const end = range?.end ?? start;
404
- if (start > lines.length || end > lines.length) {
405
- const first = start > lines.length ? start : end;
406
- throw new CiteError(`${label ?? "the source"} has ${lines.length} lines; line ${first} is out of range.`);
407
- }
408
- return lines.slice(start - 1, end).join("\n");
393
+ function sliceLines2(lines, range, label) {
394
+ return asCiteError(() => sliceLines(lines, range, label));
409
395
  }
410
- function hashRange(text, range, key) {
411
- return hashLines(sliceLines(splitLines(text), range), key);
412
- }
413
- function hashLines(joined, key) {
414
- return key === void 0 ? integrityOf(Buffer.from(joined, "utf8")) : keyedPin(joined, key);
415
- }
416
- function isKeyedPin(pin) {
417
- return pin.startsWith(KEYED_PIN_PREFIX);
396
+ function hashRange2(text, range, key) {
397
+ return asCiteError(() => hashRange(text, range, key));
418
398
  }
419
399
 
420
400
  // src/cite/core/spell.ts
@@ -855,141 +835,6 @@ function offsetOfLine(content, line) {
855
835
  return pos;
856
836
  }
857
837
 
858
- // src/cite/core/classify.ts
859
- var MOVE_WINDOW_LINES = 2e3;
860
- var MOVE_BUDGET_BYTES = 64 * 1024 * 1024;
861
- var MAX_RANGE_LINES = 5e3;
862
- function findWindows(lines, length, pin, key, opts) {
863
- const starts = [];
864
- const lastStart = lines.length - length + 1;
865
- if (length < 1 || lastStart < 1) return { starts, truncated: false };
866
- const joined = (start) => lines.slice(start - 1, start - 1 + length).join("\n");
867
- const original = opts?.original;
868
- if (original !== void 0) {
869
- const first = original[0];
870
- for (let start = 1; start <= lastStart; start++) {
871
- if (lines[start - 1] !== first) continue;
872
- let same = true;
873
- for (let i = 1; i < length; i++) {
874
- if (lines[start - 1 + i] !== original[i]) {
875
- same = false;
876
- break;
877
- }
878
- }
879
- if (same && hashLines(joined(start), key) === pin) starts.push(start);
880
- }
881
- return { starts, truncated: false };
882
- }
883
- const budget = opts?.budget ?? MOVE_BUDGET_BYTES;
884
- const around = opts?.around ?? 1;
885
- const bandStart = Math.max(1, around - MOVE_WINDOW_LINES);
886
- const bandEnd = Math.min(lastStart, around + MOVE_WINDOW_LINES);
887
- const order = [];
888
- for (let start = bandStart; start <= bandEnd; start++) order.push(start);
889
- for (let start = 1; start < bandStart; start++) order.push(start);
890
- for (let start = bandEnd + 1; start <= lastStart; start++) order.push(start);
891
- let spent = 0;
892
- for (const start of order) {
893
- const text = joined(start);
894
- const bytes = Buffer.byteLength(text, "utf8");
895
- if (spent + bytes > budget) return { starts, truncated: true };
896
- spent += bytes;
897
- if (hashLines(text, key) === pin) starts.push(start);
898
- }
899
- return { starts, truncated: false };
900
- }
901
- async function historyOf(git, commit, path, range, pin, key, budget) {
902
- const shown = await git.showFile(commit, path);
903
- if ("missing" in shown) {
904
- return shown.missing === "commit" ? { kind: "unavailable" } : { kind: "never-true" };
905
- }
906
- const then = splitLines(shown.text);
907
- let joined;
908
- try {
909
- joined = sliceLines(then, range);
910
- } catch {
911
- joined = void 0;
912
- }
913
- if (joined !== void 0 && hashLines(joined, key) === pin) {
914
- return { kind: "original", lines: joined.split("\n") };
915
- }
916
- if (range.start === void 0) return { kind: "never-true" };
917
- const length = (range.end ?? range.start) - range.start + 1;
918
- const search = { around: range.start };
919
- if (budget !== void 0) search.budget = budget;
920
- const found = findWindows(then, length, pin, key, search);
921
- const [first] = found.starts;
922
- if (first !== void 0) {
923
- return { kind: "original", lines: then.slice(first - 1, first - 1 + length) };
924
- }
925
- return found.truncated ? { kind: "unknown" } : { kind: "never-true" };
926
- }
927
- async function classifyCitation(entry, opts) {
928
- const { citation } = entry;
929
- const range = sourceRange(citation.source);
930
- const commit = citation.source["commit-sha"];
931
- const result = { src: spellSource(citation.source), status: "missing" };
932
- if (commit !== void 0) result.commitSha = commit;
933
- const source = await readSource(opts.root, opts.index, range, opts.key);
934
- if (source.kind === "missing") {
935
- result.missingReason = source.reason;
936
- return result;
937
- }
938
- result.resolvedPath = source.resolvedPath;
939
- const key = range.encrypted ? opts.key : void 0;
940
- const pin = citation.source.integrity;
941
- const lines = splitLines(source.text);
942
- let here;
943
- try {
944
- here = hashLines(sliceLines(lines, range), key);
945
- } catch {
946
- here = void 0;
947
- }
948
- if (here === pin) {
949
- result.status = "current";
950
- return result;
951
- }
952
- let history = { kind: "none" };
953
- if (commit !== void 0 && await opts.git.available()) {
954
- history = await historyOf(opts.git, commit, source.resolvedPath, range, pin, key, opts.budget);
955
- }
956
- if (range.start !== void 0) {
957
- const start = range.start;
958
- const end = range.end ?? start;
959
- const search = { around: start };
960
- if (history.kind === "original") search.original = history.lines;
961
- if (opts.budget !== void 0) search.budget = opts.budget;
962
- const found = findWindows(lines, end - start + 1, pin, key, search);
963
- if (found.truncated) result.truncatedSearch = true;
964
- const spell = (at2) => formatSrc({ ...range, start: at2, end: at2 + (end - start) });
965
- const [only] = found.starts;
966
- if (found.starts.length === 1 && only !== void 0) {
967
- result.status = "moved";
968
- result.newSrc = spell(only);
969
- result.newLines = String(lineSpec({ start: only, end: only + (end - start) }));
970
- return result;
971
- }
972
- if (found.starts.length > 1) {
973
- result.status = "moved-ambiguous";
974
- result.candidates = found.starts.map(spell);
975
- return result;
976
- }
977
- }
978
- if (history.kind === "never-true") {
979
- result.status = "never-true";
980
- return result;
981
- }
982
- result.status = "changed";
983
- if (history.kind === "unavailable") result.historyAvailable = false;
984
- if (history.kind === "unknown") result.truncatedSearch = true;
985
- if (history.kind === "original" && commit !== void 0) {
986
- result.historyAvailable = true;
987
- result.commitsSince = await opts.git.subjectsSince(commit, source.resolvedPath);
988
- result.diff = await opts.git.diffSince(commit, source.resolvedPath);
989
- }
990
- return result;
991
- }
992
-
993
838
  // src/cite/core/claims.ts
994
839
  function normalizeWhitespace(text) {
995
840
  return text.replace(/\s+/g, " ").trim();
@@ -1002,19 +847,9 @@ function normalizeBlock(text) {
1002
847
  function blockMatches(blockText, citedJoined) {
1003
848
  return normalizeBlock(blockText) === normalizeBlock(citedJoined);
1004
849
  }
1005
- function toFileLines(lines, bodyLine) {
1006
- return { start: bodyLine + lines.start - 1, end: bodyLine + lines.end - 1 };
1007
- }
1008
- function toBodyLines(lines, bodyLine) {
1009
- return { start: lines.start - bodyLine + 1, end: lines.end - bodyLine + 1 };
1010
- }
1011
850
  function textAt(lines, range) {
1012
851
  return lines.slice(range.start - 1, Math.min(range.end, lines.length));
1013
852
  }
1014
- function pinOfLines(lines, range) {
1015
- if (range.start < 1 || range.end > lines.length) return void 0;
1016
- return hashLines(lines.slice(range.start - 1, range.end).join("\n"));
1017
- }
1018
853
  function claimLine(claim) {
1019
854
  const at2 = claim.fileLines === void 0 ? void 0 : parseLines(claim.fileLines);
1020
855
  return at2?.start;
@@ -1188,6 +1023,99 @@ function noGit() {
1188
1023
  };
1189
1024
  }
1190
1025
 
1026
+ // src/cite/core/classify.ts
1027
+ async function historyOf(git, commit, path, range, pin, key, budget) {
1028
+ const shown = await git.showFile(commit, path);
1029
+ if ("missing" in shown) {
1030
+ return shown.missing === "commit" ? { kind: "unavailable" } : { kind: "never-true" };
1031
+ }
1032
+ const then = splitLines(shown.text);
1033
+ let joined;
1034
+ try {
1035
+ joined = sliceLines2(then, range);
1036
+ } catch {
1037
+ joined = void 0;
1038
+ }
1039
+ if (joined !== void 0 && hashLines(joined, key) === pin) {
1040
+ return { kind: "original", lines: joined.split("\n") };
1041
+ }
1042
+ if (range.start === void 0) return { kind: "never-true" };
1043
+ const length = (range.end ?? range.start) - range.start + 1;
1044
+ const search = { around: range.start };
1045
+ if (budget !== void 0) search.budget = budget;
1046
+ const found = findWindows(then, length, pin, key, search);
1047
+ const [first] = found.starts;
1048
+ if (first !== void 0) {
1049
+ return { kind: "original", lines: then.slice(first - 1, first - 1 + length) };
1050
+ }
1051
+ return found.truncated ? { kind: "unknown" } : { kind: "never-true" };
1052
+ }
1053
+ async function classifyCitation(entry, opts) {
1054
+ const { citation } = entry;
1055
+ const range = sourceRange(citation.source);
1056
+ const commit = citation.source["commit-sha"];
1057
+ const result = { src: spellSource(citation.source), status: "missing" };
1058
+ if (commit !== void 0) result.commitSha = commit;
1059
+ const source = await readSource(opts.root, opts.index, range, opts.key);
1060
+ if (source.kind === "missing") {
1061
+ result.missingReason = source.reason;
1062
+ return result;
1063
+ }
1064
+ result.resolvedPath = source.resolvedPath;
1065
+ const key = range.encrypted ? opts.key : void 0;
1066
+ const pin = citation.source.integrity;
1067
+ const lines = splitLines(source.text);
1068
+ let here;
1069
+ try {
1070
+ here = hashLines(sliceLines2(lines, range), key);
1071
+ } catch {
1072
+ here = void 0;
1073
+ }
1074
+ if (here === pin) {
1075
+ result.status = "current";
1076
+ return result;
1077
+ }
1078
+ let history = { kind: "none" };
1079
+ if (commit !== void 0 && await opts.git.available()) {
1080
+ history = await historyOf(opts.git, commit, source.resolvedPath, range, pin, key, opts.budget);
1081
+ }
1082
+ if (range.start !== void 0) {
1083
+ const start = range.start;
1084
+ const end = range.end ?? start;
1085
+ const search = { around: start };
1086
+ if (history.kind === "original") search.original = history.lines;
1087
+ if (opts.budget !== void 0) search.budget = opts.budget;
1088
+ const found = findWindows(lines, end - start + 1, pin, key, search);
1089
+ if (found.truncated) result.truncatedSearch = true;
1090
+ const spell = (at2) => formatSrc({ ...range, start: at2, end: at2 + (end - start) });
1091
+ const [only] = found.starts;
1092
+ if (found.starts.length === 1 && only !== void 0) {
1093
+ result.status = "moved";
1094
+ result.newSrc = spell(only);
1095
+ result.newLines = String(lineSpec({ start: only, end: only + (end - start) }));
1096
+ return result;
1097
+ }
1098
+ if (found.starts.length > 1) {
1099
+ result.status = "moved-ambiguous";
1100
+ result.candidates = found.starts.map(spell);
1101
+ return result;
1102
+ }
1103
+ }
1104
+ if (history.kind === "never-true") {
1105
+ result.status = "never-true";
1106
+ return result;
1107
+ }
1108
+ result.status = "changed";
1109
+ if (history.kind === "unavailable") result.historyAvailable = false;
1110
+ if (history.kind === "unknown") result.truncatedSearch = true;
1111
+ if (history.kind === "original" && commit !== void 0) {
1112
+ result.historyAvailable = true;
1113
+ result.commitsSince = await opts.git.subjectsSince(commit, source.resolvedPath);
1114
+ result.diff = await opts.git.diffSince(commit, source.resolvedPath);
1115
+ }
1116
+ return result;
1117
+ }
1118
+
1191
1119
  // src/cite/core/page.ts
1192
1120
  import { extname as extname2 } from "node:path";
1193
1121
  import * as Ajv2020Ns from "ajv/dist/2020.js";
@@ -1308,326 +1236,6 @@ var citations_default = {
1308
1236
  }
1309
1237
  };
1310
1238
 
1311
- // src/meta/core/external-metadata-write.ts
1312
- import { posix } from "node:path";
1313
- import {
1314
- LineCounter,
1315
- isMap,
1316
- isNode,
1317
- isPair,
1318
- isScalar,
1319
- isSeq,
1320
- parseDocument,
1321
- stringify
1322
- } from "yaml";
1323
- function spliceManifestValue(text, options) {
1324
- const { entry, key, value, file } = options;
1325
- const join4 = options.join ?? PATH_JOIN;
1326
- const at2 = (line2) => {
1327
- const name = file === void 0 ? "Manifest" : `Manifest ${file}`;
1328
- if (line2 === void 0) return name;
1329
- return file === void 0 ? `${name} line ${String(line2)}` : `${name}:${String(line2)}`;
1330
- };
1331
- if (key === FILE_SCHEMA_KEY) {
1332
- throw new DocmetaError(
1333
- `${at2()}: refusing to write "${FILE_SCHEMA_KEY}" for "${entry}"; a manifest never chooses the schema a document is judged by. Use "overrides" in the config.`
1334
- );
1335
- }
1336
- if (value === void 0) {
1337
- throw new DocmetaError(`${at2()}: refusing to write "${key}" for "${entry}" with no value.`);
1338
- }
1339
- const eol = detectEol2(text);
1340
- const lc = new LineCounter();
1341
- const doc = parseDocument(text, { lineCounter: lc, uniqueKeys: false });
1342
- const problem = doc.errors[0];
1343
- if (problem) {
1344
- throw new DocmetaError(`${at2()} is not valid YAML: ${problem.message}`);
1345
- }
1346
- const keyLine = (node) => {
1347
- const r = rangeOf(node);
1348
- return r ? lc.linePos(r[0]).line : void 0;
1349
- };
1350
- const same = join4 === PATH_JOIN ? (a, b) => posix.normalize(a) === posix.normalize(b) : (a, b) => a === b;
1351
- const root = doc.contents;
1352
- let spelled = entry;
1353
- let edit;
1354
- if (root === null || isScalar(root) && root.value === null && emptySource(text, root)) {
1355
- edit = startManifest(text, entry, key, value, eol);
1356
- } else if (!isMap(root)) {
1357
- throw new DocmetaError(
1358
- `${at2()}: the manifest must be a mapping from document ${join4 === PATH_JOIN ? "path" : `"${join4}"`} to owned keys.`
1359
- );
1360
- } else {
1361
- const style = detectStyle(text, root, eol);
1362
- const matches = root.items.filter((p) => same(keyString(p.key), entry));
1363
- const [first, second] = matches;
1364
- if (first && second) {
1365
- throw new DocmetaError(
1366
- `${at2(keyLine(second.key))}: "${keyString(second.key)}" is named twice (first at line ${String(keyLine(first.key) ?? "?")}). Merge the two entries into one.`
1367
- );
1368
- }
1369
- if (first === void 0) {
1370
- if (root.flow === true && root.items.length > 0) {
1371
- throw new DocmetaError(
1372
- `${at2()}: the manifest is a flow mapping ({ \u2026 }), which this writer does not add entries to. Rewrite it in block style.`
1373
- );
1374
- }
1375
- edit = appendEntry(text, root, entry, key, value, style);
1376
- } else {
1377
- spelled = keyString(first.key);
1378
- const where = at2(keyLine(first.key));
1379
- const v = first.value;
1380
- if (!isMap(v)) {
1381
- throw new DocmetaError(`${where}: "${spelled}" must be a mapping of owned keys to values.`);
1382
- }
1383
- const hits = v.items.filter((kv) => keyString(kv.key) === key);
1384
- const [hit, again] = hits;
1385
- if (hit && again) {
1386
- throw new DocmetaError(
1387
- `${at2(keyLine(again.key))}: "${spelled}" sets "${key}" twice (first at line ${String(keyLine(hit.key) ?? "?")}). Remove one.`
1388
- );
1389
- }
1390
- const flowRefusal = () => new DocmetaError(
1391
- `${where}: "${spelled}" is a flow mapping ({ \u2026 }), which this writer does not add keys to. Rewrite the entry in block style.`
1392
- );
1393
- const formRefusal = () => new DocmetaError(
1394
- `${where}: "${spelled}" writes a key in a form this writer does not edit. Write it as "${key}: \u2026".`
1395
- );
1396
- let made;
1397
- if (v.flow === true) {
1398
- if (hit) made = replaceFlowValue(text, hit, value);
1399
- else if (v.items.length === 0) made = fillEmptyEntry(text, first, key, value, style);
1400
- else throw flowRefusal();
1401
- if (!made) throw hit ? flowRefusal() : formRefusal();
1402
- } else {
1403
- made = hit ? replaceBlockValue(text, hit, value, style) : insertKey(text, v, key, value, style);
1404
- if (!made) throw formRefusal();
1405
- }
1406
- edit = made;
1407
- }
1408
- }
1409
- const out = text.slice(0, edit.start) + edit.insert + text.slice(edit.end);
1410
- const line = readBack(
1411
- doc,
1412
- out,
1413
- spelled,
1414
- key,
1415
- value,
1416
- (why) => new DocmetaError(
1417
- `${at2()}: writing "${key}" for "${entry}" did not read back as written, so nothing was written. ${why}`
1418
- )
1419
- );
1420
- return { text: out, line };
1421
- }
1422
- function startManifest(text, entry, key, value, eol) {
1423
- const style = { step: 2, indentSeq: true, eol };
1424
- const block = blockLines({ [entry]: { [key]: value } }, 0, style);
1425
- let insert;
1426
- if (text === "" || text.endsWith("\n")) insert = block + eol;
1427
- else insert = eol + block;
1428
- return { start: text.length, end: text.length, insert };
1429
- }
1430
- function appendEntry(text, root, entry, key, value, style) {
1431
- const body = { [entry]: { [key]: value } };
1432
- if (root.flow === true) {
1433
- const r = rangeOf(root);
1434
- const start = r ? r[0] : text.length;
1435
- const end = contentEnd(text, root) ?? start;
1436
- return { start, end, insert: blockLines(body, colOf(text, start), style) };
1437
- }
1438
- const firstKey = rangeOf(root.items[0]?.key);
1439
- const col = firstKey ? colOf(text, firstKey[0]) : 0;
1440
- const pos = lineEnd2(text, contentEnd(text, root) ?? text.length);
1441
- const last = root.items.at(-1);
1442
- const spaced = root.items.length > 1 && isNode(last?.key) && last.key.spaceBefore === true;
1443
- return {
1444
- start: pos,
1445
- end: pos,
1446
- insert: style.eol + (spaced ? style.eol : "") + blockLines(body, col, style)
1447
- };
1448
- }
1449
- function insertKey(text, entryMap, key, value, style) {
1450
- const firstKey = rangeOf(entryMap.items[0]?.key);
1451
- const end = contentEnd(text, entryMap);
1452
- if (!firstKey || end === void 0) return void 0;
1453
- const pos = lineEnd2(text, end);
1454
- return {
1455
- start: pos,
1456
- end: pos,
1457
- insert: style.eol + blockLines({ [key]: value }, colOf(text, firstKey[0]), style)
1458
- };
1459
- }
1460
- function fillEmptyEntry(text, entryPair, key, value, style) {
1461
- const start = colonEnd(text, entryPair);
1462
- const keyRange = rangeOf(entryPair.key);
1463
- const end = contentEnd(text, entryPair.value);
1464
- if (start === void 0 || !keyRange || end === void 0) return void 0;
1465
- const col = colOf(text, keyRange[0]) + style.step;
1466
- return { start, end, insert: style.eol + blockLines({ [key]: value }, col, style) };
1467
- }
1468
- function replaceBlockValue(text, pair, value, style) {
1469
- const colon = colonEnd(text, pair);
1470
- const keyRange = rangeOf(pair.key);
1471
- if (colon === void 0 || !keyRange) return void 0;
1472
- const keyCol = colOf(text, keyRange[0]);
1473
- let start = colon;
1474
- let ownLine = false;
1475
- let i = colon;
1476
- while (text.charAt(i) === " " || text.charAt(i) === " ") i++;
1477
- if (text.charAt(i) === "#") {
1478
- start = lineEnd2(text, i);
1479
- ownLine = true;
1480
- }
1481
- const old = pair.value;
1482
- const oldEnd = isScalar(old) && old.value === null && emptySource(text, old) ? start : contentEnd(text, old) ?? start;
1483
- const end = Math.max(start, oldEnd);
1484
- let insert = afterColon(value, keyCol, style);
1485
- if (ownLine && !insert.startsWith(style.eol)) {
1486
- insert = style.eol + " ".repeat(keyCol + style.step) + insert.trimStart();
1487
- }
1488
- return { start, end, insert };
1489
- }
1490
- function replaceFlowValue(text, pair, value) {
1491
- const r = rangeOf(pair.value);
1492
- if (!r || emptySource(text, pair.value)) return void 0;
1493
- const end = contentEnd(text, pair.value) ?? r[1];
1494
- return { start: r[0], end, insert: flowText(value) };
1495
- }
1496
- function readBack(before, out, spelled, key, value, fail) {
1497
- const lc = new LineCounter();
1498
- const after = parseDocument(out, { lineCounter: lc, uniqueKeys: false });
1499
- const problem = after.errors[0];
1500
- if (problem) throw fail(`The result is not valid YAML: ${problem.message}`);
1501
- const was = before.toJS({ maxAliasCount: 100 });
1502
- const now = after.toJS({ maxAliasCount: 100 });
1503
- const wasRoot = isRecord(was) ? was : {};
1504
- const wasEntry = wasRoot[spelled];
1505
- const expected = {
1506
- ...wasRoot,
1507
- [spelled]: { ...isRecord(wasEntry) ? wasEntry : {}, [key]: value }
1508
- };
1509
- const nowEntry = isRecord(now) ? now[spelled] : void 0;
1510
- if (!isRecord(nowEntry) || !deepEqual(nowEntry[key], value)) {
1511
- throw fail(
1512
- "The value reads back differently. A Date, an undefined member, or another value YAML cannot hold does not survive the trip."
1513
- );
1514
- }
1515
- if (!deepEqual(now, expected)) {
1516
- throw fail("Another value in the manifest would have changed.");
1517
- }
1518
- const root = after.contents;
1519
- const pair = isMap(root) ? root.items.find((p) => keyString(p.key) === spelled) : void 0;
1520
- const entryMap = pair?.value;
1521
- const kv = isMap(entryMap) ? entryMap.items.find((p) => keyString(p.key) === key) : void 0;
1522
- const r = rangeOf(kv?.value) ?? rangeOf(kv?.key);
1523
- if (!r) throw fail("The written value could not be found again.");
1524
- return lc.linePos(r[0]).line;
1525
- }
1526
- function blockLines(pair, col, style) {
1527
- const s = stringify(pair, { lineWidth: 0, indent: style.step, indentSeq: style.indentSeq });
1528
- return indentLines(s.replace(/\n$/, "").split("\n"), col, 0).join(style.eol);
1529
- }
1530
- function afterColon(value, col, style) {
1531
- const s = stringify({ k: value }, { lineWidth: 0, indent: style.step, indentSeq: style.indentSeq });
1532
- const lines = s.replace(/\n$/, "").slice("k:".length).split("\n");
1533
- return indentLines(lines, col, 1).join(style.eol);
1534
- }
1535
- function indentLines(lines, col, from) {
1536
- const pad = " ".repeat(col);
1537
- return lines.map((l, i) => i < from || l === "" ? l : pad + l);
1538
- }
1539
- function flowText(value) {
1540
- const s = stringify(value, { lineWidth: 0, collectionStyle: "flow" }).replace(/\n$/, "");
1541
- return s.includes("\n") ? JSON.stringify(value) : s;
1542
- }
1543
- function detectEol2(text) {
1544
- const i = text.indexOf("\n");
1545
- return i > 0 && text.charAt(i - 1) === "\r" ? "\r\n" : "\n";
1546
- }
1547
- function detectStyle(text, root, eol) {
1548
- let step = 2;
1549
- for (const pair of root.items) {
1550
- const v = pair.value;
1551
- const entryKey = rangeOf(pair.key);
1552
- const ownedKey = isMap(v) && v.flow !== true ? rangeOf(v.items[0]?.key) : void 0;
1553
- if (entryKey && ownedKey) {
1554
- const d = colOf(text, ownedKey[0]) - colOf(text, entryKey[0]);
1555
- if (d > 0) {
1556
- step = d;
1557
- break;
1558
- }
1559
- }
1560
- }
1561
- return { step, indentSeq: seqIndented(text, root) ?? true, eol };
1562
- }
1563
- function seqIndented(text, node) {
1564
- if (isMap(node)) {
1565
- for (const pair of node.items) {
1566
- const v = pair.value;
1567
- if (isSeq(v) && v.flow !== true && v.items.length > 0) {
1568
- const k = rangeOf(pair.key);
1569
- const s = rangeOf(v);
1570
- if (k && s) return colOf(text, s[0]) > colOf(text, k[0]);
1571
- }
1572
- const inner = seqIndented(text, v);
1573
- if (inner !== void 0) return inner;
1574
- }
1575
- } else if (isSeq(node)) {
1576
- for (const item of node.items) {
1577
- const inner = seqIndented(text, item);
1578
- if (inner !== void 0) return inner;
1579
- }
1580
- }
1581
- return void 0;
1582
- }
1583
- function contentEnd(text, node) {
1584
- if (isMap(node) && node.flow !== true) {
1585
- const last = node.items.at(-1);
1586
- if (last) return contentEnd(text, last.value) ?? contentEnd(text, last.key);
1587
- } else if (isSeq(node) && node.flow !== true) {
1588
- const last = node.items.at(-1);
1589
- if (last !== void 0) {
1590
- return isPair(last) ? contentEnd(text, last.value) ?? contentEnd(text, last.key) : contentEnd(text, last);
1591
- }
1592
- }
1593
- const r = rangeOf(node);
1594
- if (!r) return void 0;
1595
- let end = r[1];
1596
- while (end > r[0] && /\s/.test(text.charAt(end - 1))) end--;
1597
- return end;
1598
- }
1599
- function colonEnd(text, pair) {
1600
- const r = rangeOf(pair.key);
1601
- if (!r) return void 0;
1602
- let i = r[1];
1603
- while (text.charAt(i) === " " || text.charAt(i) === " ") i++;
1604
- return text.charAt(i) === ":" ? i + 1 : void 0;
1605
- }
1606
- function lineEnd2(text, i) {
1607
- const j = text.indexOf("\n", i);
1608
- if (j < 0) return text.length;
1609
- return j > 0 && text.charAt(j - 1) === "\r" ? j - 1 : j;
1610
- }
1611
- function colOf(text, offset) {
1612
- if (offset === 0) return 0;
1613
- let start = text.lastIndexOf("\n", offset - 1) + 1;
1614
- if (start === 0 && text.startsWith("\uFEFF")) start = 1;
1615
- return offset - start;
1616
- }
1617
- function rangeOf(node) {
1618
- return isNode(node) ? node.range ?? void 0 : void 0;
1619
- }
1620
- function emptySource(text, node) {
1621
- const r = rangeOf(node);
1622
- return !r || text.slice(r[0], r[1]).trim() === "";
1623
- }
1624
- function keyString(key) {
1625
- return isScalar(key) ? String(key.value) : String(key);
1626
- }
1627
- function isRecord(x) {
1628
- return typeof x === "object" && x !== null && !Array.isArray(x);
1629
- }
1630
-
1631
1239
  // src/cite/core/page.ts
1632
1240
  var MAX_MARKERS_PER_PAGE = 500;
1633
1241
  var ELEMENT_BACKED = /* @__PURE__ */ new Set(["html", "xml"]);
@@ -1653,11 +1261,11 @@ function validateEntry(entry) {
1653
1261
  if (!first) return "invalid entry";
1654
1262
  return `${first.instancePath} ${first.message ?? "is invalid"}`.trim();
1655
1263
  }
1656
- function isRecord2(value) {
1264
+ function isRecord(value) {
1657
1265
  return typeof value === "object" && value !== null && !Array.isArray(value);
1658
1266
  }
1659
1267
  function toCitation(entry) {
1660
- const source = isRecord2(entry.source) ? entry.source : {};
1268
+ const source = isRecord(entry.source) ? entry.source : {};
1661
1269
  const citation = {
1662
1270
  source: {
1663
1271
  file: String(source.file),
@@ -1671,7 +1279,7 @@ function toCitation(entry) {
1671
1279
  citation.source["commit-sha"] = source["commit-sha"];
1672
1280
  }
1673
1281
  if (typeof entry.id === "string") citation.id = entry.id;
1674
- if (isRecord2(entry.claim)) {
1282
+ if (isRecord(entry.claim)) {
1675
1283
  const claim = entry.claim;
1676
1284
  citation.claim = { integrity: String(claim.integrity) };
1677
1285
  if (typeof claim.lines === "number" || typeof claim.lines === "string") {
@@ -1703,9 +1311,9 @@ function named(id, text) {
1703
1311
  }
1704
1312
  function subjectOf(entry) {
1705
1313
  const out = {};
1706
- if (!isRecord2(entry)) return out;
1314
+ if (!isRecord(entry)) return out;
1707
1315
  if (typeof entry.id === "string") out.id = entry.id;
1708
- if (isRecord2(entry.source) && typeof entry.source.file === "string") out.src = entry.source.file;
1316
+ if (isRecord(entry.source) && typeof entry.source.file === "string") out.src = entry.source.file;
1709
1317
  return out;
1710
1318
  }
1711
1319
  function pickExtractor(file, format) {
@@ -1786,7 +1394,7 @@ function readPage(file, content, opts) {
1786
1394
  if (origin.kind === "manifest") where.file = origin.file;
1787
1395
  const entry = input.entry;
1788
1396
  const error = validateEntry(entry);
1789
- if (error !== void 0 || !isRecord2(entry)) {
1397
+ if (error !== void 0 || !isRecord(entry)) {
1790
1398
  findings.push(finding("entry-invalid", error ?? "must be object", { ...where, ...subjectOf(entry) }));
1791
1399
  return;
1792
1400
  }
@@ -2046,8 +1654,8 @@ function sidecarsFor(run3, over = {}) {
2046
1654
 
2047
1655
  // src/cite/core/manifest.ts
2048
1656
  import { readFile as readFile2 } from "node:fs/promises";
2049
- import { posix as posix2 } from "node:path";
2050
- import { LineCounter as LineCounter2, isMap as isMap2, isNode as isNode2, isScalar as isScalar2, isSeq as isSeq2, parseDocument as parseDocument2 } from "yaml";
1657
+ import { posix } from "node:path";
1658
+ import { LineCounter, isMap, isNode, isScalar, isSeq, parseDocument } from "yaml";
2051
1659
 
2052
1660
  // src/cite/core/write.ts
2053
1661
  function extractorFor(format) {
@@ -2159,12 +1767,12 @@ function spliceEntryField(content, format, index, path, value) {
2159
1767
  const out = content.slice(0, start) + parts.lead + spelled + parts.trail + content.slice(end);
2160
1768
  const check = extractor.extract(out, "page").data.citations;
2161
1769
  const entry = Array.isArray(check) ? check[index] : void 0;
2162
- const block = isRecord3(entry) ? entry[which] : void 0;
2163
- const readBack2 = isRecord3(block) ? block[field] : void 0;
2164
- if (readBack2 !== value) throw refuse();
1770
+ const block = isRecord2(entry) ? entry[which] : void 0;
1771
+ const readBack = isRecord2(block) ? block[field] : void 0;
1772
+ if (readBack !== value) throw refuse();
2165
1773
  return out;
2166
1774
  }
2167
- function isRecord3(value) {
1775
+ function isRecord2(value) {
2168
1776
  return typeof value === "object" && value !== null && !Array.isArray(value);
2169
1777
  }
2170
1778
  function insertStatementBefore(content, offset, statement) {
@@ -2290,25 +1898,25 @@ function splice(text, options) {
2290
1898
  }
2291
1899
  }
2292
1900
  function itemLine(text, entry, index, join4) {
2293
- const lc = new LineCounter2();
2294
- const doc = parseDocument2(text, { lineCounter: lc, uniqueKeys: false });
1901
+ const lc = new LineCounter();
1902
+ const doc = parseDocument(text, { lineCounter: lc, uniqueKeys: false });
2295
1903
  if (doc.errors.length > 0) return void 0;
2296
1904
  const root = doc.contents;
2297
- if (!isMap2(root)) return void 0;
1905
+ if (!isMap(root)) return void 0;
2298
1906
  const same = (key) => {
2299
- const spelled = isScalar2(key) ? String(key.value) : String(key);
2300
- return join4 === "path" ? posix2.normalize(spelled) === posix2.normalize(entry) : spelled === entry;
1907
+ const spelled = isScalar(key) ? String(key.value) : String(key);
1908
+ return join4 === "path" ? posix.normalize(spelled) === posix.normalize(entry) : spelled === entry;
2301
1909
  };
2302
1910
  const pair = root.items.find((p) => same(p.key));
2303
1911
  const value = pair?.value;
2304
- if (!isMap2(value)) return void 0;
1912
+ if (!isMap(value)) return void 0;
2305
1913
  const kv = value.items.find(
2306
- (p) => (isScalar2(p.key) ? String(p.key.value) : String(p.key)) === CITATIONS_KEY2
1914
+ (p) => (isScalar(p.key) ? String(p.key.value) : String(p.key)) === CITATIONS_KEY2
2307
1915
  );
2308
1916
  const list = kv?.value;
2309
- if (!isSeq2(list)) return void 0;
1917
+ if (!isSeq(list)) return void 0;
2310
1918
  const item = list.items[index];
2311
- const range = isNode2(item) ? item.range : void 0;
1919
+ const range = isNode(item) ? item.range : void 0;
2312
1920
  return range ? lc.linePos(range[0]).line : void 0;
2313
1921
  }
2314
1922
 
@@ -2509,7 +2117,7 @@ async function citedNow(input, source, entry) {
2509
2117
  if (read.kind === "missing") return void 0;
2510
2118
  const at2 = source.status === "moved" && source.newSrc !== void 0 ? parseSrc(source.newSrc) : range;
2511
2119
  try {
2512
- return sliceLines(splitLines(read.text), at2);
2120
+ return sliceLines2(splitLines(read.text), at2);
2513
2121
  } catch {
2514
2122
  return void 0;
2515
2123
  }
@@ -2713,7 +2321,7 @@ async function mintCitation(opts) {
2713
2321
  const index = opts.sourceIndex ?? await buildSourceIndex(opts.root, { gitClient: opts.gitClient });
2714
2322
  const read = await readSource(opts.root, index, range, key);
2715
2323
  if (read.kind === "missing") throw refusalFor(read.reason, range.path, range.encrypted);
2716
- const joined = sliceLines(splitLines(read.text), range, range.path);
2324
+ const joined = sliceLines2(splitLines(read.text), range, range.path);
2717
2325
  const pinKey = encrypt ? key : void 0;
2718
2326
  const file = pinKey !== void 0 && !range.encrypted ? encryptSourcePath(read.resolvedPath, pinKey) : range.path;
2719
2327
  const lines = rangeLines(range);
@@ -3137,7 +2745,7 @@ async function citedText(root, index, src, key) {
3137
2745
  if (source.kind === "missing") {
3138
2746
  throw new CiteError(`Source not readable: ${range.path} could not be read.`);
3139
2747
  }
3140
- return sliceLines(splitLines(source.text), range, range.path);
2748
+ return sliceLines2(splitLines(source.text), range, range.path);
3141
2749
  }
3142
2750
  async function runAdd(opts) {
3143
2751
  const cwd = resolve4(opts.cwd ?? process.cwd());
@@ -3376,12 +2984,12 @@ function apply(content, format, plan) {
3376
2984
  }
3377
2985
  }
3378
2986
  }
3379
- function isRecord4(value) {
2987
+ function isRecord3(value) {
3380
2988
  return typeof value === "object" && value !== null && !Array.isArray(value);
3381
2989
  }
3382
2990
  function applyToEntry(entry, plan) {
3383
- if (!isRecord4(entry)) return false;
3384
- const end = (name) => isRecord4(entry[name]) ? entry[name] : void 0;
2991
+ if (!isRecord3(entry)) return false;
2992
+ const end = (name) => isRecord3(entry[name]) ? entry[name] : void 0;
3385
2993
  switch (plan.kind) {
3386
2994
  case "claim-moved": {
3387
2995
  const claim = end("claim");
@@ -3622,7 +3230,7 @@ async function pinnedLines(ctx, citation, range, path, key) {
3622
3230
  const pin = citation.source.integrity;
3623
3231
  let joined;
3624
3232
  try {
3625
- joined = sliceLines(splitLines(source.text), range);
3233
+ joined = sliceLines2(splitLines(source.text), range);
3626
3234
  } catch {
3627
3235
  joined = void 0;
3628
3236
  }
@@ -4472,6 +4080,7 @@ export {
4472
4080
  meetsSeverity,
4473
4081
  reencryptMetadata,
4474
4082
  CiteError,
4083
+ asCiteError,
4475
4084
  spellSource,
4476
4085
  runAdd,
4477
4086
  runCheck,
@@ -4489,4 +4098,4 @@ export {
4489
4098
  runKeyRotate,
4490
4099
  runKeySet
4491
4100
  };
4492
- //# sourceMappingURL=chunk-7ZN43F3Y.js.map
4101
+ //# sourceMappingURL=chunk-UTXTVCBV.js.map