@hawkeyexl/manni 2.12.0 → 3.0.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 +16 -12
- package/dist/{chunk-S7S34HVI.js → chunk-G7INFKNJ.js} +25 -9
- package/dist/chunk-G7INFKNJ.js.map +1 -0
- package/dist/{chunk-P4V5IMHM.js → chunk-I6PYC7EP.js} +5430 -1058
- package/dist/chunk-I6PYC7EP.js.map +1 -0
- package/dist/{chunk-UKRYPLZS.js → chunk-W75SLU7Z.js} +116 -156
- package/dist/chunk-W75SLU7Z.js.map +1 -0
- package/dist/cli.js +26 -11
- package/dist/cli.js.map +1 -1
- package/dist/docmeta.js +2 -2
- package/dist/index.d.ts +355 -184
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-P4V5IMHM.js.map +0 -1
- package/dist/chunk-S7S34HVI.js.map +0 -1
- package/dist/chunk-UKRYPLZS.js.map +0 -1
|
@@ -12,10 +12,12 @@ import {
|
|
|
12
12
|
STDIN_LABEL,
|
|
13
13
|
STDIN_TOKEN,
|
|
14
14
|
ToolError,
|
|
15
|
+
__default,
|
|
15
16
|
__export,
|
|
16
17
|
assertNonEmpty,
|
|
17
18
|
classifyRef,
|
|
18
19
|
committedKeyWarning,
|
|
20
|
+
configMarks,
|
|
19
21
|
decryptValue,
|
|
20
22
|
encryptValue,
|
|
21
23
|
ensureEncryptionKey,
|
|
@@ -50,11 +52,12 @@ import {
|
|
|
50
52
|
loadExternalMetadata,
|
|
51
53
|
locateFrontmatter,
|
|
52
54
|
memberOf,
|
|
53
|
-
|
|
55
|
+
mergeWithMarks,
|
|
54
56
|
normalizeText,
|
|
55
57
|
orphanEntries,
|
|
56
58
|
orphanError,
|
|
57
59
|
orphanJoins,
|
|
60
|
+
ownsKey,
|
|
58
61
|
pageManifestPath,
|
|
59
62
|
palette,
|
|
60
63
|
parseLines,
|
|
@@ -81,7 +84,7 @@ import {
|
|
|
81
84
|
withValueAt,
|
|
82
85
|
writeEncryptionKey,
|
|
83
86
|
writeFileAtomic
|
|
84
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-I6PYC7EP.js";
|
|
85
88
|
|
|
86
89
|
// src/meta/core/reencrypt.ts
|
|
87
90
|
import { extname } from "node:path";
|
|
@@ -577,123 +580,6 @@ async function readTracked(root, path) {
|
|
|
577
580
|
import { extname as extname2 } from "node:path";
|
|
578
581
|
import * as Ajv2020Ns from "ajv/dist/2020.js";
|
|
579
582
|
|
|
580
|
-
// src/cite/schema/citations.json
|
|
581
|
-
var citations_default = {
|
|
582
|
-
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
583
|
-
$id: "manni:citations:1.0.0-proposal.4",
|
|
584
|
-
title: "manni citations vocabulary (1.0.0-proposal.4)",
|
|
585
|
-
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.",
|
|
586
|
-
type: "object",
|
|
587
|
-
additionalProperties: true,
|
|
588
|
-
properties: {
|
|
589
|
-
citations: {
|
|
590
|
-
type: "array",
|
|
591
|
-
minItems: 1,
|
|
592
|
-
items: {
|
|
593
|
-
$ref: "#/$defs/citationEntry"
|
|
594
|
-
},
|
|
595
|
-
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.",
|
|
596
|
-
"x-manni-location": "external"
|
|
597
|
-
}
|
|
598
|
-
},
|
|
599
|
-
patternProperties: {
|
|
600
|
-
"^citation-": false
|
|
601
|
-
},
|
|
602
|
-
$defs: {
|
|
603
|
-
citationEntry: {
|
|
604
|
-
type: "object",
|
|
605
|
-
additionalProperties: false,
|
|
606
|
-
required: [
|
|
607
|
-
"source"
|
|
608
|
-
],
|
|
609
|
-
description: "One citation: the page text it supports, the source lines it rests on, and how the two are anchored. Both ends share one shape, a line range and a hash.",
|
|
610
|
-
properties: {
|
|
611
|
-
id: {
|
|
612
|
-
type: "string",
|
|
613
|
-
pattern: "^[a-z0-9][a-z0-9-]*$",
|
|
614
|
-
description: "A kebab-case name for this citation, unique within the page. A body marker names an entry by it, and findings are reported under it. Optional for an entry anchored by its claim lines or pinned bare. Required when a marker names the entry."
|
|
615
|
-
},
|
|
616
|
-
claim: {
|
|
617
|
-
$ref: "#/$defs/claim"
|
|
618
|
-
},
|
|
619
|
-
source: {
|
|
620
|
-
$ref: "#/$defs/source"
|
|
621
|
-
},
|
|
622
|
-
quote: {
|
|
623
|
-
type: "boolean",
|
|
624
|
-
default: false,
|
|
625
|
-
description: "The claim is a fenced block that reproduces the source lines. The pinned claim covers the whole block, fences included. An implementer compares the lines inside the fences with the source under the pin's rule. So a quoted snippet that drifts from its source is a finding even while the pin still holds. Under a marker, the block is the next fence after the marker. Default false."
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
},
|
|
629
|
-
claim: {
|
|
630
|
-
type: "object",
|
|
631
|
-
additionalProperties: false,
|
|
632
|
-
required: [
|
|
633
|
-
"integrity"
|
|
634
|
-
],
|
|
635
|
-
description: "The page text the citation supports, pinned by lines and a hash. Absent, the entry is a bare pin, or a marker with no drift check on its sentence. Without `lines`, the text pinned is what a body marker naming this entry anchors.",
|
|
636
|
-
properties: {
|
|
637
|
-
lines: {
|
|
638
|
-
$ref: "#/$defs/lines",
|
|
639
|
-
description: "Lines of the page body. The body starts on the first line after the closing frontmatter fence, or on line 1 with no frontmatter. So editing the frontmatter never moves a claim. Required unless a marker names the entry, and never inside the frontmatter."
|
|
640
|
-
},
|
|
641
|
-
integrity: {
|
|
642
|
-
type: "string",
|
|
643
|
-
pattern: "^sha256-[0-9a-f]{64}$",
|
|
644
|
-
description: "`sha256-` and sixty-four lowercase hex digits over the claimed lines, under the rule `source.integrity` states. Always plain, never keyed: the page is public, so there is nothing to hide. With a marker, the lines hashed are the ones the marker anchors."
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
},
|
|
648
|
-
source: {
|
|
649
|
-
type: "object",
|
|
650
|
-
additionalProperties: false,
|
|
651
|
-
required: [
|
|
652
|
-
"file",
|
|
653
|
-
"integrity"
|
|
654
|
-
],
|
|
655
|
-
description: "The lines the claim rests on: a file, an optional line range, a pin, and the commit the pin was taken at.",
|
|
656
|
-
properties: {
|
|
657
|
-
file: {
|
|
658
|
-
$ref: "#/$defs/fileRef"
|
|
659
|
-
},
|
|
660
|
-
lines: {
|
|
661
|
-
$ref: "#/$defs/lines",
|
|
662
|
-
description: "File lines. Absent, the whole file is pinned. The lines stay readable even when `file` is encrypted."
|
|
663
|
-
},
|
|
664
|
-
integrity: {
|
|
665
|
-
type: "string",
|
|
666
|
-
pattern: "^(?:sha256|hmac-sha256)-[0-9a-f]{64}$",
|
|
667
|
-
description: "The pin: an algorithm prefix and sixty-four lowercase hex digits over the cited lines under one rule. Decode as UTF-8 and drop one leading byte-order mark. Turn CRLF into LF, split on LF, and discard the empty element a trailing LF leaves. Take lines L1 to L2 inclusive, or every line for a whole file. Join with LF and no trailing LF, and keep trailing whitespace. A plain `file` is pinned `sha256-` over that text. An encrypted `file` is pinned `hmac-sha256-`: the HMAC-SHA256 of that text under a key derived from the encryption key. So a public page carries no verifier a reader could run against a guessed private line. The prefix follows `file`, and any other pairing is an invalid entry."
|
|
668
|
-
},
|
|
669
|
-
"commit-sha": {
|
|
670
|
-
type: "string",
|
|
671
|
-
pattern: "^[0-9a-f]{7,64}$",
|
|
672
|
-
description: "The git commit hash the source pin was taken at, as lowercase hex. Seven digits is what git abbreviates to; sixty-four covers a SHA-256 repository. A tool writes the full hash, because an abbreviation that is unique today need not be next year. Without it, a check can still say the lines changed. With it, the check can say since when, and whether the pin was ever true."
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
},
|
|
676
|
-
lines: {
|
|
677
|
-
oneOf: [
|
|
678
|
-
{
|
|
679
|
-
type: "integer",
|
|
680
|
-
minimum: 1
|
|
681
|
-
},
|
|
682
|
-
{
|
|
683
|
-
type: "string",
|
|
684
|
-
pattern: "^[1-9][0-9]*-[1-9][0-9]*$"
|
|
685
|
-
}
|
|
686
|
-
],
|
|
687
|
-
description: 'A line range, 1-based and inclusive: an integer for one line, or `"L1-L2"` for several. `L1 <= L2` is a rule on implementations, since a pattern cannot compare two numbers. There is no line 0 to cite.'
|
|
688
|
-
},
|
|
689
|
-
fileRef: {
|
|
690
|
-
type: "string",
|
|
691
|
-
pattern: "^(?:~[A-Za-z0-9_-]{82,}|(?!~)(?:(?!\\.\\.?(?:/|$))[^/\\\\:\\r\\n\\t]+)(?:/(?:(?!\\.\\.?(?:/|$))[^/\\\\:\\r\\n\\t]+))*)$",
|
|
692
|
-
description: "The file: a path relative to the repository root, posix-separated, and free of `.` and `..` segments. Segments may hold spaces and dots but not `/`, `\\`, `:` or a line break. So a URL, a drive letter, a Windows path and an absolute path all fail here. In place of the path, `~` and at least 82 base64url characters is the path encrypted with the family key. Proposal 0045 states the construction. Only a checkout with the key and the files can decrypt the path and read the lines. So a public docs repo can cite a private code repo without publishing its paths. The value carries no encryption mark, because the citation tool encrypts it, and a plain path stays valid."
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
};
|
|
696
|
-
|
|
697
583
|
// src/shared/code-regions.ts
|
|
698
584
|
var SKIP_MARKDOWN_FENCE = /^[ \t]*(`{3,}|~{3,})/;
|
|
699
585
|
var SKIP_ASCIIDOC_FENCE = /^(-{4,})/;
|
|
@@ -1215,9 +1101,9 @@ var entryValidator;
|
|
|
1215
1101
|
function compileEntryValidator() {
|
|
1216
1102
|
if (entryValidator) return entryValidator;
|
|
1217
1103
|
const ajv = new Ajv2020({ allErrors: false, strict: false });
|
|
1218
|
-
ajv.addSchema(
|
|
1104
|
+
ajv.addSchema(__default);
|
|
1219
1105
|
entryValidator = ajv.compile({
|
|
1220
|
-
$ref: `${
|
|
1106
|
+
$ref: `${__default.$id}#/$defs/citationEntry`
|
|
1221
1107
|
});
|
|
1222
1108
|
return entryValidator;
|
|
1223
1109
|
}
|
|
@@ -1900,6 +1786,19 @@ function gitClient(root) {
|
|
|
1900
1786
|
});
|
|
1901
1787
|
return {
|
|
1902
1788
|
available,
|
|
1789
|
+
shallow,
|
|
1790
|
+
// `merge-base --is-ancestor` exits 0 for yes and 1 for no. For a commit
|
|
1791
|
+
// it does not have it exits 128, `Not a valid commit name`, which reads
|
|
1792
|
+
// as git failing. So `hasCommit` answers first, and is required rather
|
|
1793
|
+
// than an optimization: a commit git lacks is in no history it holds,
|
|
1794
|
+
// which is a no, and exactly the pin a deleted branch leaves behind.
|
|
1795
|
+
isAncestor: (commit, of) => once(`ancestor\0${commit}\0${of}`, async () => {
|
|
1796
|
+
if (!await hasCommit(commit)) return false;
|
|
1797
|
+
const out = await run2(root, ["merge-base", "--is-ancestor", "--end-of-options", commit, of]);
|
|
1798
|
+
if (out.ok) return true;
|
|
1799
|
+
if (out.code === 1) return false;
|
|
1800
|
+
throw failed("merge-base", out);
|
|
1801
|
+
}),
|
|
1903
1802
|
head: () => once("head", async () => {
|
|
1904
1803
|
if (!await available()) return null;
|
|
1905
1804
|
const out = await run2(root, ["rev-parse", "HEAD"]);
|
|
@@ -1966,6 +1865,7 @@ function gitClient(root) {
|
|
|
1966
1865
|
var UNIT = "";
|
|
1967
1866
|
var GIT_UNAVAILABLE_HISTORY = "git is not available here, so citations are checked without history: no never-true, no reanchored claims, no diffs, no commit subjects.";
|
|
1968
1867
|
var PAGE_HISTORY_UNAVAILABLE = "the page history ends before the pin held; use fetch-depth: 0 to tell reanchored claims from changed ones";
|
|
1868
|
+
var SHALLOW_RECOMMIT = "this clone is shallow, so --recommit re-recorded only commits that do not contain their lines. Fetch full history to check the rest.";
|
|
1969
1869
|
var GIT_UNAVAILABLE_COMMIT = "git is not available here, so the citation records no commit.";
|
|
1970
1870
|
function noGit() {
|
|
1971
1871
|
return {
|
|
@@ -2502,52 +2402,80 @@ function twoManifestsRefusal(label, a, b) {
|
|
|
2502
2402
|
return `${label} is in collections ${a} and ${b}, and both keep citations in a manifest.`;
|
|
2503
2403
|
}
|
|
2504
2404
|
function ownsCitations(manifest) {
|
|
2505
|
-
return manifest.keys.includes(CITATIONS_KEY2);
|
|
2405
|
+
return manifest.keys === void 0 || manifest.keys.includes(CITATIONS_KEY2);
|
|
2406
|
+
}
|
|
2407
|
+
function emptyIndex() {
|
|
2408
|
+
return { owners: /* @__PURE__ */ new Map(), byPath: /* @__PURE__ */ new Map(), byField: /* @__PURE__ */ new Map(), entries: [] };
|
|
2506
2409
|
}
|
|
2507
2410
|
async function loadCitationSidecars(opts) {
|
|
2508
2411
|
const toError = opts.toError ?? ((message) => new CiteError(message));
|
|
2509
2412
|
const manifests = [];
|
|
2413
|
+
const urls = [];
|
|
2510
2414
|
const scoped = [];
|
|
2511
2415
|
for (const collection of opts.collections) {
|
|
2512
2416
|
const owning = collection.externalMetadata.filter(ownsCitations);
|
|
2513
2417
|
if (owning.length === 0) continue;
|
|
2418
|
+
const loaded = [];
|
|
2514
2419
|
for (const manifest of owning) {
|
|
2420
|
+
const implied = manifest.keys === void 0 ? { implied: { collection, manifest } } : {};
|
|
2515
2421
|
if (classifyRef(manifest.file).kind === "url") {
|
|
2516
|
-
|
|
2422
|
+
if (manifest.keys !== void 0) {
|
|
2423
|
+
throw toError(urlManifestRefusal(opts.configSource, collection.name));
|
|
2424
|
+
}
|
|
2425
|
+
urls.push({ collection: collection.name, path: manifest.file, file: manifest.file, join: externalMetadataJoin(manifest), ...implied });
|
|
2426
|
+
continue;
|
|
2517
2427
|
}
|
|
2428
|
+
loaded.push(manifest);
|
|
2518
2429
|
const path = isAbsolute(manifest.file) ? manifest.file : resolve(opts.configDir, manifest.file);
|
|
2519
2430
|
manifests.push({
|
|
2520
2431
|
collection: collection.name,
|
|
2521
2432
|
path,
|
|
2522
2433
|
file: reportedPath(path, opts.base),
|
|
2523
2434
|
join: externalMetadataJoin(manifest),
|
|
2524
|
-
...hasPagePlaceholder(manifest.file) ? { pattern: manifest.file } : {}
|
|
2435
|
+
...hasPagePlaceholder(manifest.file) ? { pattern: manifest.file } : {},
|
|
2436
|
+
...implied
|
|
2525
2437
|
});
|
|
2526
2438
|
}
|
|
2527
|
-
scoped.push({ ...collection, externalMetadata:
|
|
2439
|
+
if (loaded.length > 0) scoped.push({ ...collection, externalMetadata: loaded });
|
|
2528
2440
|
}
|
|
2529
|
-
if (manifests.length === 0) return null;
|
|
2441
|
+
if (manifests.length === 0 && urls.length === 0) return null;
|
|
2530
2442
|
const index = await loadExternalMetadata(scoped, {
|
|
2531
2443
|
configDir: opts.configDir,
|
|
2532
2444
|
base: opts.base,
|
|
2533
2445
|
...opts.pages === void 0 ? {} : { pages: opts.pages }
|
|
2534
|
-
});
|
|
2446
|
+
}) ?? (urls.length > 0 ? emptyIndex() : null);
|
|
2535
2447
|
if (index === null) return null;
|
|
2536
|
-
return sidecars(index, manifests, scoped, opts);
|
|
2448
|
+
return sidecars(index, manifests, urls, scoped, opts);
|
|
2537
2449
|
}
|
|
2538
|
-
function sidecars(index, manifests, collections, opts) {
|
|
2450
|
+
function sidecars(index, manifests, urls, collections, opts) {
|
|
2539
2451
|
const toError = opts.toError ?? ((message) => new CiteError(message));
|
|
2540
2452
|
const { configDir, base } = opts;
|
|
2453
|
+
let marks;
|
|
2454
|
+
const marksOnce = () => marks ??= opts.marks?.() ?? Promise.resolve(void 0);
|
|
2541
2455
|
const pageOwner = (owner, label) => {
|
|
2542
2456
|
if (owner.pattern === void 0) return owner;
|
|
2543
2457
|
const resolved = pageManifestPath(owner.pattern, configDir, resolve(base, label));
|
|
2544
2458
|
if ("outside" in resolved) return void 0;
|
|
2545
2459
|
return { ...owner, path: resolved.abs, file: reportedPath(resolved.abs, base) };
|
|
2546
2460
|
};
|
|
2547
|
-
const forPage = (label, content, format) => {
|
|
2461
|
+
const forPage = async (label, content, format) => {
|
|
2462
|
+
const declaredMembers = memberOf(opts.collections, configDir, base, label);
|
|
2463
|
+
if (declaredMembers.length === 0) return { joins: [] };
|
|
2548
2464
|
const members = memberOf(collections, configDir, base, label);
|
|
2549
|
-
|
|
2550
|
-
|
|
2465
|
+
const memberOfCollection = (m) => declaredMembers.includes(m.collection);
|
|
2466
|
+
let extracted;
|
|
2467
|
+
const extract = () => extracted ??= pickExtractor(label, format).extract(content, label);
|
|
2468
|
+
const candidates2 = [...manifests, ...urls].filter((m) => m.implied !== void 0 && memberOfCollection(m));
|
|
2469
|
+
let marked;
|
|
2470
|
+
if (candidates2.length > 0) {
|
|
2471
|
+
const read = await marksOnce();
|
|
2472
|
+
const data = extract().data;
|
|
2473
|
+
marked = read === void 0 ? void 0 : await read(label, Object.hasOwn(data, CITATIONS_KEY2) ? data : { ...data, [CITATIONS_KEY2]: null }, declaredMembers);
|
|
2474
|
+
}
|
|
2475
|
+
const keeps = (m) => m.implied === void 0 || ownsKey(m.implied.collection, m.implied.manifest, CITATIONS_KEY2, marked);
|
|
2476
|
+
const url = urls.find((m) => memberOfCollection(m) && keeps(m));
|
|
2477
|
+
if (url !== void 0) throw toError(urlManifestRefusal(opts.configSource, url.collection));
|
|
2478
|
+
const mine = manifests.filter((m) => members.includes(m.collection) && keeps(m));
|
|
2551
2479
|
const [declared, second] = mine;
|
|
2552
2480
|
if (declared === void 0) return { joins: [] };
|
|
2553
2481
|
if (second !== void 0) {
|
|
@@ -2555,17 +2483,17 @@ function sidecars(index, manifests, collections, opts) {
|
|
|
2555
2483
|
}
|
|
2556
2484
|
const owner = pageOwner(declared, label);
|
|
2557
2485
|
if (owner === void 0) return { joins: [] };
|
|
2558
|
-
const
|
|
2559
|
-
const
|
|
2560
|
-
|
|
2561
|
-
|
|
2486
|
+
const readMarks = await marksOnce();
|
|
2487
|
+
const merged = await mergeWithMarks(label, extract(), index, members, base, {
|
|
2488
|
+
encryptionKey: () => opts.key,
|
|
2489
|
+
...readMarks === void 0 ? {} : { marks: readMarks }
|
|
2562
2490
|
});
|
|
2563
2491
|
const out = { owner, joins: merged.joins };
|
|
2564
2492
|
if (owner.join === PATH_JOIN) {
|
|
2565
2493
|
out.entry = toPosix(relative(configDir, resolve(base, label)));
|
|
2566
2494
|
} else {
|
|
2567
2495
|
const value = merged.joins.find((j) => j.field === owner.join)?.value;
|
|
2568
|
-
const raw = value ??
|
|
2496
|
+
const raw = value ?? extract().data[owner.join];
|
|
2569
2497
|
if (typeof raw === "string" && raw !== "") out.entry = raw;
|
|
2570
2498
|
else if (typeof raw === "number" || typeof raw === "boolean") out.entry = String(raw);
|
|
2571
2499
|
}
|
|
@@ -2624,6 +2552,7 @@ function duplicateJoinRefusal(field, value, file, labels) {
|
|
|
2624
2552
|
function sidecarsFor(run3, over = {}) {
|
|
2625
2553
|
const declared = run3.configFile?.collections ?? [];
|
|
2626
2554
|
if (run3.configDir === void 0 || declared.length === 0) return Promise.resolve(null);
|
|
2555
|
+
const { configPath } = run3;
|
|
2627
2556
|
return loadCitationSidecars({
|
|
2628
2557
|
// Every declared collection, whatever `--collection` or the paths chose.
|
|
2629
2558
|
collections: declared,
|
|
@@ -2632,7 +2561,10 @@ function sidecarsFor(run3, over = {}) {
|
|
|
2632
2561
|
configSource: run3.configSource ?? run3.configPath ?? "the config",
|
|
2633
2562
|
...run3.key === void 0 ? {} : { key: run3.key },
|
|
2634
2563
|
...over.toError === void 0 ? {} : { toError: over.toError },
|
|
2635
|
-
...over.pages === void 0 ? {} : { pages: over.pages }
|
|
2564
|
+
...over.pages === void 0 ? {} : { pages: over.pages },
|
|
2565
|
+
// A keyless manifest (proposal 0068) keeps what a page's schemas mark,
|
|
2566
|
+
// read from meta's section of the same file.
|
|
2567
|
+
...configPath === void 0 ? {} : { marks: () => configMarks(configPath, run3.base) }
|
|
2636
2568
|
});
|
|
2637
2569
|
}
|
|
2638
2570
|
|
|
@@ -3400,7 +3332,7 @@ async function checkCitations(page, opts) {
|
|
|
3400
3332
|
page: read,
|
|
3401
3333
|
lines,
|
|
3402
3334
|
root: opts.root,
|
|
3403
|
-
index: index ??
|
|
3335
|
+
index: index ?? emptyIndex2,
|
|
3404
3336
|
checkSources,
|
|
3405
3337
|
...opts.key === void 0 ? {} : { key: opts.key }
|
|
3406
3338
|
};
|
|
@@ -3511,7 +3443,7 @@ function skippedSource(entry) {
|
|
|
3511
3443
|
if (source["commit-sha"] !== void 0) out.commitSha = source["commit-sha"];
|
|
3512
3444
|
return out;
|
|
3513
3445
|
}
|
|
3514
|
-
var
|
|
3446
|
+
var emptyIndex2 = { files: () => [], has: () => false };
|
|
3515
3447
|
|
|
3516
3448
|
// src/cite/core/mint.ts
|
|
3517
3449
|
var COMMIT_PATTERN = /^[0-9a-f]{7,64}$/;
|
|
@@ -3868,8 +3800,8 @@ async function prepareRun(opts, action, verb, sources = {}) {
|
|
|
3868
3800
|
};
|
|
3869
3801
|
if (checkSources) pageOptions.sourceIndex = await sourceIndexFor(run3.root, git);
|
|
3870
3802
|
const sidecars2 = await sidecarsFor(run3, { pages: files.map((file) => resolve3(base, file)) });
|
|
3871
|
-
const setupFor = (label, content) => {
|
|
3872
|
-
const page = sidecars2?.forPage(label, content, forced?.name);
|
|
3803
|
+
const setupFor = async (label, content) => {
|
|
3804
|
+
const page = await sidecars2?.forPage(label, content, forced?.name);
|
|
3873
3805
|
if (page?.owner === void 0) return { options: pageOptions };
|
|
3874
3806
|
return {
|
|
3875
3807
|
sidecar: page,
|
|
@@ -3933,7 +3865,7 @@ async function runCheck(opts) {
|
|
|
3933
3865
|
const hits = joinHits();
|
|
3934
3866
|
const pages = [];
|
|
3935
3867
|
const checkOne = async (label, content) => {
|
|
3936
|
-
const setup = prepared.setupFor(label, content);
|
|
3868
|
+
const setup = await prepared.setupFor(label, content);
|
|
3937
3869
|
if (setup.sidecar !== void 0) hits.record(setup.sidecar, label);
|
|
3938
3870
|
pages.push(await checkCitations({ file: label, content, format: forced?.name }, setup.options));
|
|
3939
3871
|
};
|
|
@@ -4055,7 +3987,7 @@ async function runAdd(opts) {
|
|
|
4055
3987
|
`A page read from stdin has no path, and its citations live in ${firstManifest.file}, which is keyed by ${keyedBy}.`
|
|
4056
3988
|
);
|
|
4057
3989
|
}
|
|
4058
|
-
const sidecar = usingStdin ? void 0 : sidecars2?.forPage(label, content, opts.as);
|
|
3990
|
+
const sidecar = usingStdin ? void 0 : await sidecars2?.forPage(label, content, opts.as);
|
|
4059
3991
|
const owner = sidecar?.owner;
|
|
4060
3992
|
const page = readPage(label, content, {
|
|
4061
3993
|
...opts.as === void 0 ? {} : { format: opts.as },
|
|
@@ -4351,7 +4283,7 @@ async function runRemove(opts) {
|
|
|
4351
4283
|
const pageCount = files.length + (usingStdin ? 1 : 0);
|
|
4352
4284
|
const planned = [];
|
|
4353
4285
|
const removeOne = async (label, content, path) => {
|
|
4354
|
-
const setup = prepared.setupFor(label, content);
|
|
4286
|
+
const setup = await prepared.setupFor(label, content);
|
|
4355
4287
|
if (setup.sidecar !== void 0) hits.record(setup.sidecar, label);
|
|
4356
4288
|
const owner = setup.sidecar?.owner;
|
|
4357
4289
|
const page = readPage(label, content, {
|
|
@@ -4806,6 +4738,7 @@ function rewriteOf(plan) {
|
|
|
4806
4738
|
reason: "recommitted",
|
|
4807
4739
|
// The source itself held. Only its date was wrong.
|
|
4808
4740
|
status: "current",
|
|
4741
|
+
because: plan.because,
|
|
4809
4742
|
from: plan.from,
|
|
4810
4743
|
to: plan.commitSha,
|
|
4811
4744
|
fromCommit: plan.from,
|
|
@@ -5017,19 +4950,29 @@ async function runUpdate(opts) {
|
|
|
5017
4950
|
"--recommit needs git to verify recorded commits, and git is not available here."
|
|
5018
4951
|
);
|
|
5019
4952
|
}
|
|
4953
|
+
const outsideHistory = async (commit, head) => {
|
|
4954
|
+
if (git.shallow === void 0 || git.isAncestor === void 0) return false;
|
|
4955
|
+
if (await git.shallow()) return false;
|
|
4956
|
+
return !await git.isAncestor(commit, head);
|
|
4957
|
+
};
|
|
5020
4958
|
const recommitFor = async (result) => {
|
|
5021
4959
|
const recorded = result.citation.source["commit-sha"];
|
|
5022
4960
|
const path = result.source.resolvedPath;
|
|
5023
4961
|
if (recorded === void 0 || path === void 0) return void 0;
|
|
4962
|
+
const head = await git.head();
|
|
4963
|
+
if (head === null || head === recorded) return void 0;
|
|
5024
4964
|
const range = sourceRange(result.citation.source);
|
|
5025
4965
|
const pin = result.citation.source.integrity;
|
|
5026
4966
|
const key = range.encrypted ? run3.key : void 0;
|
|
5027
|
-
|
|
5028
|
-
if (
|
|
5029
|
-
|
|
5030
|
-
|
|
4967
|
+
let because;
|
|
4968
|
+
if (await outsideHistory(recorded, head)) because = "not-in-history";
|
|
4969
|
+
else {
|
|
4970
|
+
const was = await historyOf(git, recorded, path, range, pin, key, void 0);
|
|
4971
|
+
if (was.kind !== "never-true") return void 0;
|
|
4972
|
+
because = "not-contained";
|
|
4973
|
+
}
|
|
5031
4974
|
const now = await historyOf(git, head, path, range, pin, key, void 0);
|
|
5032
|
-
return now.kind === "original" ? head : void 0;
|
|
4975
|
+
return now.kind === "original" ? { commit: head, because } : void 0;
|
|
5033
4976
|
};
|
|
5034
4977
|
const plansFor = async (result, entry, page, lines, lineNow, declined) => {
|
|
5035
4978
|
const out = [];
|
|
@@ -5129,7 +5072,8 @@ async function runUpdate(opts) {
|
|
|
5129
5072
|
kind: "source-recommitted",
|
|
5130
5073
|
result,
|
|
5131
5074
|
from: result.citation.source["commit-sha"] ?? "",
|
|
5132
|
-
commitSha: to
|
|
5075
|
+
commitSha: to.commit,
|
|
5076
|
+
because: to.because
|
|
5133
5077
|
});
|
|
5134
5078
|
}
|
|
5135
5079
|
}
|
|
@@ -5227,7 +5171,7 @@ async function runUpdate(opts) {
|
|
|
5227
5171
|
};
|
|
5228
5172
|
const pages = [];
|
|
5229
5173
|
const updateOne = async (label, content, path) => {
|
|
5230
|
-
const setup = prepared.setupFor(label, content);
|
|
5174
|
+
const setup = await prepared.setupFor(label, content);
|
|
5231
5175
|
if (setup.sidecar !== void 0) hits.record(setup.sidecar, label);
|
|
5232
5176
|
const report = await checkCitations({ file: label, content, format: forced?.name }, setup.options);
|
|
5233
5177
|
const { format } = report;
|
|
@@ -5444,7 +5388,12 @@ async function runUpdate(opts) {
|
|
|
5444
5388
|
const reminted = pages.some(
|
|
5445
5389
|
(page) => page.rewritten.some((r) => r.reason === "accepted" && r.end === "source")
|
|
5446
5390
|
);
|
|
5447
|
-
|
|
5391
|
+
const also = [];
|
|
5392
|
+
if (reminted && !await git.available()) also.push(GIT_UNAVAILABLE_COMMIT);
|
|
5393
|
+
if (recommit && git.shallow !== void 0 && git.isAncestor !== void 0 && await git.shallow()) {
|
|
5394
|
+
also.push(SHALLOW_RECOMMIT);
|
|
5395
|
+
}
|
|
5396
|
+
sayNotices(reports, opts.onNotice, also);
|
|
5448
5397
|
const rewritten = pages.reduce((n, page) => n + citationsIn(page.rewritten), 0);
|
|
5449
5398
|
const skipped = pages.reduce((n, page) => n + page.skipped.length + page.refused.length, 0);
|
|
5450
5399
|
const undone = pages.some(
|
|
@@ -5871,6 +5820,15 @@ function refusalLine(rewrite) {
|
|
|
5871
5820
|
}
|
|
5872
5821
|
return `${where} that line now holds different text than the claim at ${at2}. Re-add it with cite add.`;
|
|
5873
5822
|
}
|
|
5823
|
+
function recommitWhy(because) {
|
|
5824
|
+
switch (because) {
|
|
5825
|
+
case "not-in-history":
|
|
5826
|
+
return "not in this branch's history";
|
|
5827
|
+
case "not-contained":
|
|
5828
|
+
case void 0:
|
|
5829
|
+
return "did not contain the pinned lines";
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5874
5832
|
function rewriteLine(rewrite) {
|
|
5875
5833
|
const word = rewrite.from.includes("-") ? "lines" : "line";
|
|
5876
5834
|
const status = rewrite.status === "never-true" ? "never true" : rewrite.status;
|
|
@@ -5880,7 +5838,7 @@ function rewriteLine(rewrite) {
|
|
|
5880
5838
|
if (rewrite.reason === "recommitted") {
|
|
5881
5839
|
const from = shortCommit(rewrite.fromCommit ?? "");
|
|
5882
5840
|
const to = shortCommit(rewrite.toCommit ?? "");
|
|
5883
|
-
return `source ${shortSrc(rewrite.src ?? "")} commit ${from} -> ${to} (
|
|
5841
|
+
return `source ${shortSrc(rewrite.src ?? "")} commit ${from} -> ${to} (${recommitWhy(rewrite.because)})`;
|
|
5884
5842
|
}
|
|
5885
5843
|
if (rewrite.reason === "shifted") {
|
|
5886
5844
|
return `claim ${word} ${rewrite.from} -> ${rewrite.to} (shifted by a marker)`;
|
|
@@ -6164,7 +6122,7 @@ function encryptedCitations(file, content, format) {
|
|
|
6164
6122
|
async function rotateManifestCitations(sidecars2, manifests, page, opts) {
|
|
6165
6123
|
const none = { rewritten: [], skipped: [], wantsHistory: false };
|
|
6166
6124
|
if (sidecars2 === null) return none;
|
|
6167
|
-
const sidecar = sidecars2.forPage(page.file, page.content, page.format);
|
|
6125
|
+
const sidecar = await sidecars2.forPage(page.file, page.content, page.format);
|
|
6168
6126
|
const owner = sidecar.owner;
|
|
6169
6127
|
if (owner === void 0 || sidecar.citations === void 0) return none;
|
|
6170
6128
|
if (!sidecar.citations.some((input) => ANY_CIPHERTEXT.test(JSON.stringify(input.entry)))) {
|
|
@@ -6384,6 +6342,8 @@ async function runKeyRotate(opts) {
|
|
|
6384
6342
|
configSource: file.source,
|
|
6385
6343
|
key: current,
|
|
6386
6344
|
toError: toKeyError,
|
|
6345
|
+
// A keyless manifest (proposal 0068) keeps what a page's schemas mark.
|
|
6346
|
+
marks: () => configMarks(file.path, file.dir),
|
|
6387
6347
|
// A `{page}` manifest (0058) is read for exactly the pages rotated.
|
|
6388
6348
|
pages: files.map((rel) => resolve7(base, rel))
|
|
6389
6349
|
});
|
|
@@ -6578,4 +6538,4 @@ export {
|
|
|
6578
6538
|
runKeyRotate,
|
|
6579
6539
|
runKeySet
|
|
6580
6540
|
};
|
|
6581
|
-
//# sourceMappingURL=chunk-
|
|
6541
|
+
//# sourceMappingURL=chunk-W75SLU7Z.js.map
|