@hawkeyexl/manni 2.0.1 → 2.2.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.
- package/README.md +1 -1
- package/dist/{chunk-MV2T7XAW.js → chunk-2Q5JUEIO.js} +380 -62
- package/dist/chunk-2Q5JUEIO.js.map +1 -0
- package/dist/{chunk-PDNSN5UJ.js → chunk-5O4FIGDJ.js} +4952 -758
- package/dist/chunk-5O4FIGDJ.js.map +1 -0
- package/dist/{chunk-QLVNSAHR.js → chunk-6JWX6JM2.js} +160 -550
- package/dist/chunk-6JWX6JM2.js.map +1 -0
- package/dist/cli.js +10 -18
- package/dist/cli.js.map +1 -1
- package/dist/docmeta.js +4 -3
- package/dist/docmeta.js.map +1 -1
- package/dist/index.d.ts +965 -565
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-MV2T7XAW.js.map +0 -1
- package/dist/chunk-PDNSN5UJ.js.map +0 -1
- package/dist/chunk-QLVNSAHR.js.map +0 -1
|
@@ -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
|
-
|
|
35
|
+
hashLines,
|
|
36
|
+
hashRange,
|
|
34
37
|
isEncryptedValue,
|
|
35
38
|
isErrorSeverity,
|
|
36
39
|
isIgnoredByGit,
|
|
40
|
+
isKeyedPin,
|
|
37
41
|
isMember,
|
|
38
42
|
isValidEncryptionKey,
|
|
39
|
-
|
|
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-
|
|
72
|
+
} from "./chunk-5O4FIGDJ.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: () =>
|
|
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: () =>
|
|
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
|
|
392
|
-
|
|
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
|
|
411
|
-
return
|
|
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";
|
|
@@ -1195,8 +1123,8 @@ import * as Ajv2020Ns from "ajv/dist/2020.js";
|
|
|
1195
1123
|
// src/cite/schema/citations.json
|
|
1196
1124
|
var citations_default = {
|
|
1197
1125
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1198
|
-
$id: "manni:citations:1.0.0-proposal.
|
|
1199
|
-
title: "manni citations vocabulary (1.0.0-proposal.
|
|
1126
|
+
$id: "manni:citations:1.0.0-proposal.4",
|
|
1127
|
+
title: "manni citations vocabulary (1.0.0-proposal.4)",
|
|
1200
1128
|
description: "What do this page's claims rest on? For each claim, the page lines that make it, the source lines it was written from, and a hash of each. A manni common vocabulary: any drift check can implement it, and other schemas may compose on top of it. A pin is a record of the past, not a copy of the present. It says what the lines were when the sentence was written. The check compares that record with the files as they are now. Recompute it on every run and there is nothing to compare against. `source-of-truth` (manni:stewardship) names the file a page answers to; a citation names the lines a sentence answers to. The page root stays open so sibling tools' keys pass untouched. The `citation-` prefix is reserved, so an unrecognized `citation-*` key is rejected and a typo fails loudly.",
|
|
1201
1129
|
type: "object",
|
|
1202
1130
|
additionalProperties: true,
|
|
@@ -1207,7 +1135,8 @@ var citations_default = {
|
|
|
1207
1135
|
items: {
|
|
1208
1136
|
$ref: "#/$defs/citationEntry"
|
|
1209
1137
|
},
|
|
1210
|
-
description: "The page's citations, one entry per claim or pin. An empty list is not a declaration; a page with no citations omits the key. Ids are unique within a page, and two entries claiming one id is an error. JSON Schema cannot say that over a list whose members may omit the id. So it is a requirement on implementations, stated here so every tool agrees."
|
|
1138
|
+
description: "The page's citations, one entry per claim or pin. An empty list is not a declaration; a page with no citations omits the key. Ids are unique within a page, and two entries claiming one id is an error. JSON Schema cannot say that over a list whose members may omit the id. So it is a requirement on implementations, stated here so every tool agrees.",
|
|
1139
|
+
"x-manni-location": "external"
|
|
1211
1140
|
}
|
|
1212
1141
|
},
|
|
1213
1142
|
patternProperties: {
|
|
@@ -1308,326 +1237,6 @@ var citations_default = {
|
|
|
1308
1237
|
}
|
|
1309
1238
|
};
|
|
1310
1239
|
|
|
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
1240
|
// src/cite/core/page.ts
|
|
1632
1241
|
var MAX_MARKERS_PER_PAGE = 500;
|
|
1633
1242
|
var ELEMENT_BACKED = /* @__PURE__ */ new Set(["html", "xml"]);
|
|
@@ -1653,11 +1262,11 @@ function validateEntry(entry) {
|
|
|
1653
1262
|
if (!first) return "invalid entry";
|
|
1654
1263
|
return `${first.instancePath} ${first.message ?? "is invalid"}`.trim();
|
|
1655
1264
|
}
|
|
1656
|
-
function
|
|
1265
|
+
function isRecord(value) {
|
|
1657
1266
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1658
1267
|
}
|
|
1659
1268
|
function toCitation(entry) {
|
|
1660
|
-
const source =
|
|
1269
|
+
const source = isRecord(entry.source) ? entry.source : {};
|
|
1661
1270
|
const citation = {
|
|
1662
1271
|
source: {
|
|
1663
1272
|
file: String(source.file),
|
|
@@ -1671,7 +1280,7 @@ function toCitation(entry) {
|
|
|
1671
1280
|
citation.source["commit-sha"] = source["commit-sha"];
|
|
1672
1281
|
}
|
|
1673
1282
|
if (typeof entry.id === "string") citation.id = entry.id;
|
|
1674
|
-
if (
|
|
1283
|
+
if (isRecord(entry.claim)) {
|
|
1675
1284
|
const claim = entry.claim;
|
|
1676
1285
|
citation.claim = { integrity: String(claim.integrity) };
|
|
1677
1286
|
if (typeof claim.lines === "number" || typeof claim.lines === "string") {
|
|
@@ -1703,9 +1312,9 @@ function named(id, text) {
|
|
|
1703
1312
|
}
|
|
1704
1313
|
function subjectOf(entry) {
|
|
1705
1314
|
const out = {};
|
|
1706
|
-
if (!
|
|
1315
|
+
if (!isRecord(entry)) return out;
|
|
1707
1316
|
if (typeof entry.id === "string") out.id = entry.id;
|
|
1708
|
-
if (
|
|
1317
|
+
if (isRecord(entry.source) && typeof entry.source.file === "string") out.src = entry.source.file;
|
|
1709
1318
|
return out;
|
|
1710
1319
|
}
|
|
1711
1320
|
function pickExtractor(file, format) {
|
|
@@ -1786,7 +1395,7 @@ function readPage(file, content, opts) {
|
|
|
1786
1395
|
if (origin.kind === "manifest") where.file = origin.file;
|
|
1787
1396
|
const entry = input.entry;
|
|
1788
1397
|
const error = validateEntry(entry);
|
|
1789
|
-
if (error !== void 0 || !
|
|
1398
|
+
if (error !== void 0 || !isRecord(entry)) {
|
|
1790
1399
|
findings.push(finding("entry-invalid", error ?? "must be object", { ...where, ...subjectOf(entry) }));
|
|
1791
1400
|
return;
|
|
1792
1401
|
}
|
|
@@ -2046,8 +1655,8 @@ function sidecarsFor(run3, over = {}) {
|
|
|
2046
1655
|
|
|
2047
1656
|
// src/cite/core/manifest.ts
|
|
2048
1657
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
2049
|
-
import { posix
|
|
2050
|
-
import { LineCounter
|
|
1658
|
+
import { posix } from "node:path";
|
|
1659
|
+
import { LineCounter, isMap, isNode, isScalar, isSeq, parseDocument } from "yaml";
|
|
2051
1660
|
|
|
2052
1661
|
// src/cite/core/write.ts
|
|
2053
1662
|
function extractorFor(format) {
|
|
@@ -2159,12 +1768,12 @@ function spliceEntryField(content, format, index, path, value) {
|
|
|
2159
1768
|
const out = content.slice(0, start) + parts.lead + spelled + parts.trail + content.slice(end);
|
|
2160
1769
|
const check = extractor.extract(out, "page").data.citations;
|
|
2161
1770
|
const entry = Array.isArray(check) ? check[index] : void 0;
|
|
2162
|
-
const block =
|
|
2163
|
-
const
|
|
2164
|
-
if (
|
|
1771
|
+
const block = isRecord2(entry) ? entry[which] : void 0;
|
|
1772
|
+
const readBack = isRecord2(block) ? block[field] : void 0;
|
|
1773
|
+
if (readBack !== value) throw refuse();
|
|
2165
1774
|
return out;
|
|
2166
1775
|
}
|
|
2167
|
-
function
|
|
1776
|
+
function isRecord2(value) {
|
|
2168
1777
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2169
1778
|
}
|
|
2170
1779
|
function insertStatementBefore(content, offset, statement) {
|
|
@@ -2290,25 +1899,25 @@ function splice(text, options) {
|
|
|
2290
1899
|
}
|
|
2291
1900
|
}
|
|
2292
1901
|
function itemLine(text, entry, index, join4) {
|
|
2293
|
-
const lc = new
|
|
2294
|
-
const doc =
|
|
1902
|
+
const lc = new LineCounter();
|
|
1903
|
+
const doc = parseDocument(text, { lineCounter: lc, uniqueKeys: false });
|
|
2295
1904
|
if (doc.errors.length > 0) return void 0;
|
|
2296
1905
|
const root = doc.contents;
|
|
2297
|
-
if (!
|
|
1906
|
+
if (!isMap(root)) return void 0;
|
|
2298
1907
|
const same = (key) => {
|
|
2299
|
-
const spelled =
|
|
2300
|
-
return join4 === "path" ?
|
|
1908
|
+
const spelled = isScalar(key) ? String(key.value) : String(key);
|
|
1909
|
+
return join4 === "path" ? posix.normalize(spelled) === posix.normalize(entry) : spelled === entry;
|
|
2301
1910
|
};
|
|
2302
1911
|
const pair = root.items.find((p) => same(p.key));
|
|
2303
1912
|
const value = pair?.value;
|
|
2304
|
-
if (!
|
|
1913
|
+
if (!isMap(value)) return void 0;
|
|
2305
1914
|
const kv = value.items.find(
|
|
2306
|
-
(p) => (
|
|
1915
|
+
(p) => (isScalar(p.key) ? String(p.key.value) : String(p.key)) === CITATIONS_KEY2
|
|
2307
1916
|
);
|
|
2308
1917
|
const list = kv?.value;
|
|
2309
|
-
if (!
|
|
1918
|
+
if (!isSeq(list)) return void 0;
|
|
2310
1919
|
const item = list.items[index];
|
|
2311
|
-
const range =
|
|
1920
|
+
const range = isNode(item) ? item.range : void 0;
|
|
2312
1921
|
return range ? lc.linePos(range[0]).line : void 0;
|
|
2313
1922
|
}
|
|
2314
1923
|
|
|
@@ -2509,7 +2118,7 @@ async function citedNow(input, source, entry) {
|
|
|
2509
2118
|
if (read.kind === "missing") return void 0;
|
|
2510
2119
|
const at2 = source.status === "moved" && source.newSrc !== void 0 ? parseSrc(source.newSrc) : range;
|
|
2511
2120
|
try {
|
|
2512
|
-
return
|
|
2121
|
+
return sliceLines2(splitLines(read.text), at2);
|
|
2513
2122
|
} catch {
|
|
2514
2123
|
return void 0;
|
|
2515
2124
|
}
|
|
@@ -2713,7 +2322,7 @@ async function mintCitation(opts) {
|
|
|
2713
2322
|
const index = opts.sourceIndex ?? await buildSourceIndex(opts.root, { gitClient: opts.gitClient });
|
|
2714
2323
|
const read = await readSource(opts.root, index, range, key);
|
|
2715
2324
|
if (read.kind === "missing") throw refusalFor(read.reason, range.path, range.encrypted);
|
|
2716
|
-
const joined =
|
|
2325
|
+
const joined = sliceLines2(splitLines(read.text), range, range.path);
|
|
2717
2326
|
const pinKey = encrypt ? key : void 0;
|
|
2718
2327
|
const file = pinKey !== void 0 && !range.encrypted ? encryptSourcePath(read.resolvedPath, pinKey) : range.path;
|
|
2719
2328
|
const lines = rangeLines(range);
|
|
@@ -3137,7 +2746,7 @@ async function citedText(root, index, src, key) {
|
|
|
3137
2746
|
if (source.kind === "missing") {
|
|
3138
2747
|
throw new CiteError(`Source not readable: ${range.path} could not be read.`);
|
|
3139
2748
|
}
|
|
3140
|
-
return
|
|
2749
|
+
return sliceLines2(splitLines(source.text), range, range.path);
|
|
3141
2750
|
}
|
|
3142
2751
|
async function runAdd(opts) {
|
|
3143
2752
|
const cwd = resolve4(opts.cwd ?? process.cwd());
|
|
@@ -3376,12 +2985,12 @@ function apply(content, format, plan) {
|
|
|
3376
2985
|
}
|
|
3377
2986
|
}
|
|
3378
2987
|
}
|
|
3379
|
-
function
|
|
2988
|
+
function isRecord3(value) {
|
|
3380
2989
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3381
2990
|
}
|
|
3382
2991
|
function applyToEntry(entry, plan) {
|
|
3383
|
-
if (!
|
|
3384
|
-
const end = (name) =>
|
|
2992
|
+
if (!isRecord3(entry)) return false;
|
|
2993
|
+
const end = (name) => isRecord3(entry[name]) ? entry[name] : void 0;
|
|
3385
2994
|
switch (plan.kind) {
|
|
3386
2995
|
case "claim-moved": {
|
|
3387
2996
|
const claim = end("claim");
|
|
@@ -3622,7 +3231,7 @@ async function pinnedLines(ctx, citation, range, path, key) {
|
|
|
3622
3231
|
const pin = citation.source.integrity;
|
|
3623
3232
|
let joined;
|
|
3624
3233
|
try {
|
|
3625
|
-
joined =
|
|
3234
|
+
joined = sliceLines2(splitLines(source.text), range);
|
|
3626
3235
|
} catch {
|
|
3627
3236
|
joined = void 0;
|
|
3628
3237
|
}
|
|
@@ -4472,6 +4081,7 @@ export {
|
|
|
4472
4081
|
meetsSeverity,
|
|
4473
4082
|
reencryptMetadata,
|
|
4474
4083
|
CiteError,
|
|
4084
|
+
asCiteError,
|
|
4475
4085
|
spellSource,
|
|
4476
4086
|
runAdd,
|
|
4477
4087
|
runCheck,
|
|
@@ -4489,4 +4099,4 @@ export {
|
|
|
4489
4099
|
runKeyRotate,
|
|
4490
4100
|
runKeySet
|
|
4491
4101
|
};
|
|
4492
|
-
//# sourceMappingURL=chunk-
|
|
4102
|
+
//# sourceMappingURL=chunk-6JWX6JM2.js.map
|