@hawkeyexl/manni 4.3.1 → 4.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/batch-GFNLTGOH.js +36 -0
- package/dist/build-COYIQ25L.js +31 -0
- package/dist/calibrate-MDBLJKEE.js +31 -0
- package/dist/capture-LRML2PKV.js +32 -0
- package/dist/check-ASPIHA6B.js +40 -0
- package/dist/check-ASPIHA6B.js.map +1 -0
- package/dist/check-EDLBYL5N.js +27 -0
- package/dist/check-EDLBYL5N.js.map +1 -0
- package/dist/check-HYNGXYJV.js +18 -0
- package/dist/check-HYNGXYJV.js.map +1 -0
- package/dist/chunk-2B7ZNTPV.js +230 -0
- package/dist/chunk-2B7ZNTPV.js.map +1 -0
- package/dist/chunk-2H7UOFLK.js +11 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-37LP5HMZ.js +1042 -0
- package/dist/chunk-37LP5HMZ.js.map +1 -0
- package/dist/chunk-3VK37OR2.js +2957 -0
- package/dist/chunk-3VK37OR2.js.map +1 -0
- package/dist/chunk-4IUC2MNL.js +2165 -0
- package/dist/chunk-4IUC2MNL.js.map +1 -0
- package/dist/{chunk-3R23C5DT.js → chunk-4TSWU2SU.js} +2 -14
- package/dist/chunk-4TSWU2SU.js.map +1 -0
- package/dist/chunk-57NEQRVO.js +10921 -0
- package/dist/chunk-57NEQRVO.js.map +1 -0
- package/dist/chunk-6JSSEWBG.js +6737 -0
- package/dist/chunk-6JSSEWBG.js.map +1 -0
- package/dist/chunk-6OYEI2VV.js +88 -0
- package/dist/chunk-6OYEI2VV.js.map +1 -0
- package/dist/chunk-77AINBYM.js +19 -0
- package/dist/chunk-77AINBYM.js.map +1 -0
- package/dist/chunk-7UKO3ASZ.js +54 -0
- package/dist/chunk-7UKO3ASZ.js.map +1 -0
- package/dist/chunk-A5ULMVHQ.js +164 -0
- package/dist/chunk-A5ULMVHQ.js.map +1 -0
- package/dist/chunk-C4SQM22E.js +299 -0
- package/dist/chunk-C4SQM22E.js.map +1 -0
- package/dist/chunk-CK7SKVHR.js +1042 -0
- package/dist/chunk-CK7SKVHR.js.map +1 -0
- package/dist/{chunk-G5CM2VGQ.js → chunk-DXNZS72W.js} +8 -94
- package/dist/chunk-DXNZS72W.js.map +1 -0
- package/dist/chunk-EPH54CAY.js +374 -0
- package/dist/chunk-EPH54CAY.js.map +1 -0
- package/dist/{chunk-KJR7OVDX.js → chunk-FBEQCK47.js} +56 -137
- package/dist/chunk-FBEQCK47.js.map +1 -0
- package/dist/{chunk-IOYXPBCL.js → chunk-G3T47CFV.js} +1 -7
- package/dist/{chunk-IOYXPBCL.js.map → chunk-G3T47CFV.js.map} +1 -1
- package/dist/chunk-GCQRPUSB.js +1287 -0
- package/dist/chunk-GCQRPUSB.js.map +1 -0
- package/dist/chunk-GLP5PSXB.js +72 -0
- package/dist/chunk-GLP5PSXB.js.map +1 -0
- package/dist/chunk-I2AH3CJJ.js +1192 -0
- package/dist/chunk-I2AH3CJJ.js.map +1 -0
- package/dist/chunk-IDV6HJCB.js +388 -0
- package/dist/chunk-IDV6HJCB.js.map +1 -0
- package/dist/chunk-IKEWBMCN.js +98 -0
- package/dist/chunk-IKEWBMCN.js.map +1 -0
- package/dist/chunk-JCDXE76J.js +52 -0
- package/dist/chunk-JCDXE76J.js.map +1 -0
- package/dist/chunk-JXLTXMJ7.js +455 -0
- package/dist/chunk-JXLTXMJ7.js.map +1 -0
- package/dist/chunk-LJ2RDH3F.js +49 -0
- package/dist/chunk-LJ2RDH3F.js.map +1 -0
- package/dist/chunk-M2JCK5F6.js +805 -0
- package/dist/chunk-M2JCK5F6.js.map +1 -0
- package/dist/chunk-M3W7J6MU.js +4398 -0
- package/dist/chunk-M3W7J6MU.js.map +1 -0
- package/dist/chunk-MMTSSTG7.js +23 -0
- package/dist/chunk-MMTSSTG7.js.map +1 -0
- package/dist/chunk-MNH7QO4Z.js +15 -0
- package/dist/chunk-MNH7QO4Z.js.map +1 -0
- package/dist/chunk-MWJLZMBL.js +934 -0
- package/dist/chunk-MWJLZMBL.js.map +1 -0
- package/dist/chunk-MYMBCTDE.js +387 -0
- package/dist/chunk-MYMBCTDE.js.map +1 -0
- package/dist/chunk-NCPWXHDO.js +683 -0
- package/dist/chunk-NCPWXHDO.js.map +1 -0
- package/dist/chunk-NLXTXE5Y.js +1661 -0
- package/dist/chunk-NLXTXE5Y.js.map +1 -0
- package/dist/{chunk-CFDUZRM2.js → chunk-NXV7WE2D.js} +32 -240
- package/dist/chunk-NXV7WE2D.js.map +1 -0
- package/dist/chunk-OWBRDNRZ.js +16 -0
- package/dist/chunk-OWBRDNRZ.js.map +1 -0
- package/dist/{chunk-KTSJ2ZHA.js → chunk-PAU352SV.js} +5 -3
- package/dist/{chunk-KTSJ2ZHA.js.map → chunk-PAU352SV.js.map} +1 -1
- package/dist/chunk-PCE7QHXJ.js +68 -0
- package/dist/chunk-PCE7QHXJ.js.map +1 -0
- package/dist/chunk-PIKOVN6W.js +1651 -0
- package/dist/chunk-PIKOVN6W.js.map +1 -0
- package/dist/chunk-PNPQTHBT.js +17 -0
- package/dist/chunk-PNPQTHBT.js.map +1 -0
- package/dist/chunk-PU6DFJMY.js +1975 -0
- package/dist/chunk-PU6DFJMY.js.map +1 -0
- package/dist/chunk-Q35YIDBV.js +1202 -0
- package/dist/chunk-Q35YIDBV.js.map +1 -0
- package/dist/{chunk-5HNHEUD5.js → chunk-QQUKGCAJ.js} +3 -3
- package/dist/chunk-QRWGPQKO.js +198 -0
- package/dist/chunk-QRWGPQKO.js.map +1 -0
- package/dist/{chunk-UBMMXS2Y.js → chunk-QZ6LRSNV.js} +69 -48
- package/dist/{chunk-UBMMXS2Y.js.map → chunk-QZ6LRSNV.js.map} +1 -1
- package/dist/chunk-RL5XWQOL.js +3872 -0
- package/dist/chunk-RL5XWQOL.js.map +1 -0
- package/dist/chunk-RNVYGWIC.js +30 -0
- package/dist/chunk-RNVYGWIC.js.map +1 -0
- package/dist/chunk-SE4JN5XN.js +19 -0
- package/dist/chunk-SE4JN5XN.js.map +1 -0
- package/dist/chunk-SKSDRUUK.js +622 -0
- package/dist/chunk-SKSDRUUK.js.map +1 -0
- package/dist/chunk-TIUTIOFB.js +25 -0
- package/dist/chunk-TIUTIOFB.js.map +1 -0
- package/dist/chunk-TK3FC4RF.js +3090 -0
- package/dist/chunk-TK3FC4RF.js.map +1 -0
- package/dist/chunk-TU2WUBVZ.js +2 -0
- package/dist/chunk-TU2WUBVZ.js.map +1 -0
- package/dist/chunk-TZOYZK2E.js +98 -0
- package/dist/chunk-TZOYZK2E.js.map +1 -0
- package/dist/chunk-UJCVAWP7.js +178 -0
- package/dist/chunk-UJCVAWP7.js.map +1 -0
- package/dist/chunk-UKZNLVJW.js +17 -0
- package/dist/chunk-UKZNLVJW.js.map +1 -0
- package/dist/{chunk-HAPTXWU2.js → chunk-UQISLDAV.js} +4 -4
- package/dist/chunk-WB3QM6PP.js +5440 -0
- package/dist/chunk-WB3QM6PP.js.map +1 -0
- package/dist/chunk-YB4IBW3M.js +96 -0
- package/dist/chunk-YB4IBW3M.js.map +1 -0
- package/dist/chunk-YEUYKR62.js +72 -0
- package/dist/chunk-YEUYKR62.js.map +1 -0
- package/dist/chunk-YJOGUXGP.js +634 -0
- package/dist/chunk-YJOGUXGP.js.map +1 -0
- package/dist/chunk-YNHZHSSM.js +41 -0
- package/dist/chunk-YNHZHSSM.js.map +1 -0
- package/dist/chunk-YTURO7SI.js +979 -0
- package/dist/chunk-YTURO7SI.js.map +1 -0
- package/dist/chunk-ZXRAE55H.js +31 -0
- package/dist/chunk-ZXRAE55H.js.map +1 -0
- package/dist/cli-3BIBYHFK.js +473 -0
- package/dist/cli-3BIBYHFK.js.map +1 -0
- package/dist/cli-673OTRGE.js +28 -0
- package/dist/cli-673OTRGE.js.map +1 -0
- package/dist/cli-6HIDIFVT.js +1203 -0
- package/dist/cli-6HIDIFVT.js.map +1 -0
- package/dist/cli-6UB5N6CU.js +232 -0
- package/dist/cli-6UB5N6CU.js.map +1 -0
- package/dist/cli-LFP5ZGYS.js +346 -0
- package/dist/cli-LFP5ZGYS.js.map +1 -0
- package/dist/cli-MN7PYMBI.js +552 -0
- package/dist/cli-MN7PYMBI.js.map +1 -0
- package/dist/cli-PYPX6O6E.js +739 -0
- package/dist/cli-PYPX6O6E.js.map +1 -0
- package/dist/cli-RPM5PELX.js +626 -0
- package/dist/cli-RPM5PELX.js.map +1 -0
- package/dist/cli-VI7VHWNZ.js +423 -0
- package/dist/cli-VI7VHWNZ.js.map +1 -0
- package/dist/cli.d.ts +12 -2
- package/dist/cli.js +109 -7661
- package/dist/cli.js.map +1 -1
- package/dist/docmeta.js +15 -3
- package/dist/docmeta.js.map +1 -1
- package/dist/github-6QMYOHC3.js +27 -0
- package/dist/github-6QMYOHC3.js.map +1 -0
- package/dist/github-SXPGP5DB.js +32 -0
- package/dist/github-SXPGP5DB.js.map +1 -0
- package/dist/index.d.ts +65 -3
- package/dist/index.js +407 -337
- package/dist/index.js.map +1 -1
- package/dist/json-7WV7KL6H.js +17 -0
- package/dist/json-7WV7KL6H.js.map +1 -0
- package/dist/json-SY7KLNC7.js +35 -0
- package/dist/json-SY7KLNC7.js.map +1 -0
- package/dist/lint-ASMJLLPA.js +28 -0
- package/dist/lint-ASMJLLPA.js.map +1 -0
- package/dist/list-KZNVTNVC.js +31 -0
- package/dist/list-KZNVTNVC.js.map +1 -0
- package/dist/list-Q57YTFUQ.js +29 -0
- package/dist/list-Q57YTFUQ.js.map +1 -0
- package/dist/page-KSGV5RD4.js +41 -0
- package/dist/page-KSGV5RD4.js.map +1 -0
- package/dist/picker-3XF36MJF.js +14 -0
- package/dist/picker-3XF36MJF.js.map +1 -0
- package/dist/pretty-A5EGTN35.js +37 -0
- package/dist/pretty-A5EGTN35.js.map +1 -0
- package/dist/pretty-CXSDXNAS.js +43 -0
- package/dist/pretty-CXSDXNAS.js.map +1 -0
- package/dist/reporters-HUY7UXFS.js +42 -0
- package/dist/reporters-HUY7UXFS.js.map +1 -0
- package/dist/reporters-K2VUKSAK.js +71 -0
- package/dist/reporters-K2VUKSAK.js.map +1 -0
- package/dist/reporters-M6LJ2IYU.js +21 -0
- package/dist/reporters-M6LJ2IYU.js.map +1 -0
- package/dist/run-3DYJNRIG.js +33 -0
- package/dist/run-3DYJNRIG.js.map +1 -0
- package/dist/term-BIQUPMOR.js +1592 -0
- package/dist/term-BIQUPMOR.js.map +1 -0
- package/dist/types-Y6TXHM7M.js +10 -0
- package/dist/types-Y6TXHM7M.js.map +1 -0
- package/dist/validate-53RKM2XG.js +16 -0
- package/dist/validate-53RKM2XG.js.map +1 -0
- package/package.json +1 -1
- package/plugin/manni/.claude-plugin/plugin.json +9 -0
- package/plugin/manni/hooks/hooks.json +69 -0
- package/plugin/manni/hooks/manni.mjs +157 -0
- package/plugin/manni/skills/check/SKILL.md +20 -0
- package/plugin/manni/skills/evals/SKILL.md +27 -0
- package/plugin/manni/skills/fix/SKILL.md +56 -0
- package/plugin/manni/skills/setup/SKILL.md +41 -0
- package/dist/batch-A5HZKYIW.js +0 -18
- package/dist/calibrate-S5K6QHUY.js +0 -13
- package/dist/capture-OZEZDABQ.js +0 -15
- package/dist/chunk-3R23C5DT.js.map +0 -1
- package/dist/chunk-CFDUZRM2.js.map +0 -1
- package/dist/chunk-G5CM2VGQ.js.map +0 -1
- package/dist/chunk-KJR7OVDX.js.map +0 -1
- package/dist/chunk-V4KUVE47.js +0 -27170
- package/dist/chunk-V4KUVE47.js.map +0 -1
- package/dist/chunk-ZQBTK3DO.js +0 -26518
- package/dist/chunk-ZQBTK3DO.js.map +0 -1
- package/dist/picker-6HRMETE7.js +0 -12
- package/plugin/tracevals/.claude-plugin/plugin.json +0 -9
- package/plugin/tracevals/hooks/hooks.json +0 -17
- /package/dist/{batch-A5HZKYIW.js.map → batch-GFNLTGOH.js.map} +0 -0
- /package/dist/{calibrate-S5K6QHUY.js.map → build-COYIQ25L.js.map} +0 -0
- /package/dist/{capture-OZEZDABQ.js.map → calibrate-MDBLJKEE.js.map} +0 -0
- /package/dist/{picker-6HRMETE7.js.map → capture-LRML2PKV.js.map} +0 -0
- /package/dist/{chunk-5HNHEUD5.js.map → chunk-QQUKGCAJ.js.map} +0 -0
- /package/dist/{chunk-HAPTXWU2.js.map → chunk-UQISLDAV.js.map} +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
bundledShapesPath,
|
|
4
|
+
compactIri,
|
|
5
|
+
loadGraph,
|
|
6
|
+
parseGraph,
|
|
7
|
+
validateGraph
|
|
8
|
+
} from "./chunk-MYMBCTDE.js";
|
|
9
|
+
import {
|
|
10
|
+
loadRunConfig
|
|
11
|
+
} from "./chunk-M2JCK5F6.js";
|
|
12
|
+
import {
|
|
13
|
+
escapeWorkflowCommandMessage,
|
|
14
|
+
escapeWorkflowCommandProperty
|
|
15
|
+
} from "./chunk-MNH7QO4Z.js";
|
|
16
|
+
|
|
17
|
+
// src/graph/commands/check.ts
|
|
18
|
+
import { resolve } from "node:path";
|
|
19
|
+
|
|
20
|
+
// src/graph/reporters/github.ts
|
|
21
|
+
function renderCheckGithub(report) {
|
|
22
|
+
const lines = [];
|
|
23
|
+
for (const f of report.findings) {
|
|
24
|
+
const file = f.docs[0];
|
|
25
|
+
const where = file === void 0 ? "" : ` file=${escapeWorkflowCommandProperty(file)}`;
|
|
26
|
+
const message = escapeWorkflowCommandMessage(
|
|
27
|
+
`${f.message} (${compactIri(f.focusNode)})`
|
|
28
|
+
);
|
|
29
|
+
lines.push(`::${f.severity}${where}::${message}`);
|
|
30
|
+
}
|
|
31
|
+
return lines.join("\n");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/graph/commands/check.ts
|
|
35
|
+
async function runCheck(opts = {}) {
|
|
36
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
37
|
+
const config = loadRunConfig(
|
|
38
|
+
{
|
|
39
|
+
...opts.config === void 0 ? {} : { configPath: opts.config },
|
|
40
|
+
...opts.noConfig === void 0 ? {} : { noConfig: opts.noConfig }
|
|
41
|
+
},
|
|
42
|
+
cwd
|
|
43
|
+
);
|
|
44
|
+
const store = opts.turtle === void 0 ? loadGraph(resolve(cwd, opts.graph ?? config.out)) : parseGraph(opts.turtle, "the built graph");
|
|
45
|
+
const shapesInput = opts.shapes && opts.shapes.length > 0 ? opts.shapes : config.check.shapes;
|
|
46
|
+
const shapes = shapesInput.length > 0 ? shapesInput.map((p) => resolve(cwd, p)) : [bundledShapesPath(import.meta.url)];
|
|
47
|
+
const findings = await validateGraph(store, shapes);
|
|
48
|
+
const count = (severity) => findings.filter((f) => f.severity === severity).length;
|
|
49
|
+
const errors = count("error");
|
|
50
|
+
return {
|
|
51
|
+
findings,
|
|
52
|
+
errors,
|
|
53
|
+
warnings: count("warning"),
|
|
54
|
+
notices: count("notice"),
|
|
55
|
+
shapes,
|
|
56
|
+
// Only an `error` fails the run; a warning and a notice are reported and
|
|
57
|
+
// pass, as they were when they were called violations and warnings.
|
|
58
|
+
exitCode: errors > 0 ? 1 : 0
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function plural(n, word) {
|
|
62
|
+
return `${String(n)} ${word}${n === 1 ? "" : "s"}`;
|
|
63
|
+
}
|
|
64
|
+
function renderCheck(report, format) {
|
|
65
|
+
if (format === "json") {
|
|
66
|
+
const { exitCode: _exitCode, ...rest } = report;
|
|
67
|
+
return JSON.stringify(rest, null, 2);
|
|
68
|
+
}
|
|
69
|
+
if (format === "github") return renderCheckGithub(report);
|
|
70
|
+
const lines = [];
|
|
71
|
+
for (const f of report.findings) {
|
|
72
|
+
const where = f.docs.length > 0 ? ` [${f.docs.join(", ")}]` : "";
|
|
73
|
+
lines.push(
|
|
74
|
+
`${f.severity}: ${compactIri(f.focusNode)}${f.path ? ` ${compactIri(f.path)}` : ""} \u2014 ${f.message}${where}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
if (report.findings.length > 0) lines.push("");
|
|
78
|
+
lines.push(
|
|
79
|
+
`${plural(report.errors, "error")}, ${plural(report.warnings, "warning")}, ${plural(report.notices, "notice")}`
|
|
80
|
+
);
|
|
81
|
+
return lines.join("\n");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
runCheck,
|
|
86
|
+
renderCheck
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=chunk-6OYEI2VV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/graph/commands/check.ts","../src/graph/reporters/github.ts"],"sourcesContent":["/**\n * `manni graph check` — graph-level validation: run the published SHACL shapes\n * (plus the TS-side SKOS integrity checks) over the built graph and report\n * findings with the doc paths responsible. Errors exit 1; warnings and\n * notices are reported but pass.\n */\nimport { resolve } from \"node:path\";\nimport type { Severity } from \"../../shared/severity.js\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { loadGraph, compactIri, parseGraph } from \"../core/load.js\";\nimport { bundledShapesPath } from \"../core/pkg.js\";\nimport { validateGraph, type CheckFinding } from \"../core/shacl.js\";\nimport { renderCheckGithub } from \"../reporters/github.js\";\nimport type { CheckFormat } from \"../reporters/index.js\";\n\nexport interface CheckOptions {\n config?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n /** Graph .ttl path (default: config `out`). */\n graph?: string;\n /** Shapes .ttl paths (default: config `check.shapes`, then bundled). */\n shapes?: string[];\n cwd?: string;\n /**\n * The graph as Turtle, in place of reading `graph`: what `buildGraph`\n * returns, so `manni check` checks a build it never wrote.\n */\n turtle?: string;\n}\n\nexport interface CheckReport {\n findings: CheckFinding[];\n /** Counts on the family's scale, not SHACL's (proposal 0051 §2). */\n errors: number;\n warnings: number;\n notices: number;\n /** Shapes files used, as given (for reporting). */\n shapes: string[];\n exitCode: 0 | 1;\n}\n\nexport async function runCheck(opts: CheckOptions = {}): Promise<CheckReport> {\n const cwd = opts.cwd ?? process.cwd();\n const config = loadRunConfig(\n {\n ...(opts.config === undefined ? {} : { configPath: opts.config }),\n ...(opts.noConfig === undefined ? {} : { noConfig: opts.noConfig }),\n },\n cwd,\n );\n const store =\n opts.turtle === undefined\n ? loadGraph(resolve(cwd, opts.graph ?? config.out))\n : parseGraph(opts.turtle, \"the built graph\");\n\n // CLI flag over config over the bundled contract — same precedence as\n // every other knob.\n const shapesInput =\n opts.shapes && opts.shapes.length > 0 ? opts.shapes : config.check.shapes;\n const shapes =\n shapesInput.length > 0\n ? shapesInput.map((p) => resolve(cwd, p))\n : [bundledShapesPath(import.meta.url)];\n\n const findings = await validateGraph(store, shapes);\n const count = (severity: Severity): number =>\n findings.filter((f) => f.severity === severity).length;\n const errors = count(\"error\");\n\n return {\n findings,\n errors,\n warnings: count(\"warning\"),\n notices: count(\"notice\"),\n shapes,\n // Only an `error` fails the run; a warning and a notice are reported and\n // pass, as they were when they were called violations and warnings.\n exitCode: errors > 0 ? 1 : 0,\n };\n}\n\n/** `2 errors`, `1 warning`, `0 notices` — each count pluralized on its own. */\nfunction plural(n: number, word: string): string {\n return `${String(n)} ${word}${n === 1 ? \"\" : \"s\"}`;\n}\n\nexport function renderCheck(report: CheckReport, format: CheckFormat): string {\n if (format === \"json\") {\n const { exitCode: _exitCode, ...rest } = report;\n return JSON.stringify(rest, null, 2);\n }\n if (format === \"github\") return renderCheckGithub(report);\n const lines: string[] = [];\n for (const f of report.findings) {\n const where = f.docs.length > 0 ? ` [${f.docs.join(\", \")}]` : \"\";\n lines.push(\n `${f.severity}: ${compactIri(f.focusNode)}${\n f.path ? ` ${compactIri(f.path)}` : \"\"\n } — ${f.message}${where}`,\n );\n }\n if (report.findings.length > 0) lines.push(\"\");\n lines.push(\n `${plural(report.errors, \"error\")}, ${plural(report.warnings, \"warning\")}, ${plural(report.notices, \"notice\")}`,\n );\n return lines.join(\"\\n\");\n}\n","/**\n * `--format github`: one workflow-command annotation per `check` finding.\n *\n * `::error file=<first blamed doc>::<message> (<focus node>)`, with\n * `::warning` and `::notice` for the lower levels — the family scale is\n * GitHub's, so the level is the severity, exactly as a11y's and cite's\n * reporters have it.\n *\n * A SHACL finding carries no line number (stress test 5 of proposal 0051 says\n * why SARIF and JUnit are not here), and a finding about a shared node — a\n * concept, an agent, the scheme — may trace back to no document at all. Then\n * there is nothing to anchor to and the annotation goes out without `file=`,\n * which GitHub shows against the workflow run rather than dropping.\n *\n * Empty when the run is clean, so a clean CI step logs nothing.\n */\nimport {\n escapeWorkflowCommandMessage,\n escapeWorkflowCommandProperty,\n} from \"../../shared/github.js\";\nimport type { CheckReport } from \"../commands/check.js\";\nimport { compactIri } from \"../core/load.js\";\n\nexport function renderCheckGithub(report: CheckReport): string {\n const lines: string[] = [];\n for (const f of report.findings) {\n // The first, not all of them: one annotation lands on one file, and the\n // docs are sorted, so which one is stable across runs.\n const file = f.docs[0];\n const where =\n file === undefined ? \"\" : ` file=${escapeWorkflowCommandProperty(file)}`;\n const message = escapeWorkflowCommandMessage(\n `${f.message} (${compactIri(f.focusNode)})`,\n );\n lines.push(`::${f.severity}${where}::${message}`);\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAMA,SAAS,eAAe;;;ACiBjB,SAAS,kBAAkB,QAA6B;AAC7D,QAAM,QAAkB,CAAC;AACzB,aAAW,KAAK,OAAO,UAAU;AAG/B,UAAM,OAAO,EAAE,KAAK,CAAC;AACrB,UAAM,QACJ,SAAS,SAAY,KAAK,SAAS,8BAA8B,IAAI,CAAC;AACxE,UAAM,UAAU;AAAA,MACd,GAAG,EAAE,OAAO,KAAK,WAAW,EAAE,SAAS,CAAC;AAAA,IAC1C;AACA,UAAM,KAAK,KAAK,EAAE,QAAQ,GAAG,KAAK,KAAK,OAAO,EAAE;AAAA,EAClD;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ADKA,eAAsB,SAAS,OAAqB,CAAC,GAAyB;AAC5E,QAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;AACpC,QAAM,SAAS;AAAA,IACb;AAAA,MACE,GAAI,KAAK,WAAW,SAAY,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO;AAAA,MAC/D,GAAI,KAAK,aAAa,SAAY,CAAC,IAAI,EAAE,UAAU,KAAK,SAAS;AAAA,IACnE;AAAA,IACA;AAAA,EACF;AACA,QAAM,QACJ,KAAK,WAAW,SACZ,UAAU,QAAQ,KAAK,KAAK,SAAS,OAAO,GAAG,CAAC,IAChD,WAAW,KAAK,QAAQ,iBAAiB;AAI/C,QAAM,cACJ,KAAK,UAAU,KAAK,OAAO,SAAS,IAAI,KAAK,SAAS,OAAO,MAAM;AACrE,QAAM,SACJ,YAAY,SAAS,IACjB,YAAY,IAAI,CAAC,MAAM,QAAQ,KAAK,CAAC,CAAC,IACtC,CAAC,kBAAkB,YAAY,GAAG,CAAC;AAEzC,QAAM,WAAW,MAAM,cAAc,OAAO,MAAM;AAClD,QAAM,QAAQ,CAAC,aACb,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ,EAAE;AAClD,QAAM,SAAS,MAAM,OAAO;AAE5B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,MAAM,SAAS;AAAA,IACzB,SAAS,MAAM,QAAQ;AAAA,IACvB;AAAA;AAAA;AAAA,IAGA,UAAU,SAAS,IAAI,IAAI;AAAA,EAC7B;AACF;AAGA,SAAS,OAAO,GAAW,MAAsB;AAC/C,SAAO,GAAG,OAAO,CAAC,CAAC,IAAI,IAAI,GAAG,MAAM,IAAI,KAAK,GAAG;AAClD;AAEO,SAAS,YAAY,QAAqB,QAA6B;AAC5E,MAAI,WAAW,QAAQ;AACrB,UAAM,EAAE,UAAU,WAAW,GAAG,KAAK,IAAI;AACzC,WAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,EACrC;AACA,MAAI,WAAW,SAAU,QAAO,kBAAkB,MAAM;AACxD,QAAM,QAAkB,CAAC;AACzB,aAAW,KAAK,OAAO,UAAU;AAC/B,UAAM,QAAQ,EAAE,KAAK,SAAS,IAAI,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,MAAM;AAC9D,UAAM;AAAA,MACJ,GAAG,EAAE,QAAQ,KAAK,WAAW,EAAE,SAAS,CAAC,GACvC,EAAE,OAAO,IAAI,WAAW,EAAE,IAAI,CAAC,KAAK,EACtC,WAAM,EAAE,OAAO,GAAG,KAAK;AAAA,IACzB;AAAA,EACF;AACA,MAAI,OAAO,SAAS,SAAS,EAAG,OAAM,KAAK,EAAE;AAC7C,QAAM;AAAA,IACJ,GAAG,OAAO,OAAO,QAAQ,OAAO,CAAC,KAAK,OAAO,OAAO,UAAU,SAAS,CAAC,KAAK,OAAO,OAAO,SAAS,QAAQ,CAAC;AAAA,EAC/G;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/shared/severity.ts
|
|
4
|
+
var SEVERITIES = ["notice", "warning", "error"];
|
|
5
|
+
var SEVERITY_LIST = SEVERITIES.join(" | ");
|
|
6
|
+
function isSeverity(value) {
|
|
7
|
+
return SEVERITIES.includes(value);
|
|
8
|
+
}
|
|
9
|
+
function meetsSeverity(severity, min) {
|
|
10
|
+
return SEVERITIES.indexOf(severity) >= SEVERITIES.indexOf(min);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
SEVERITIES,
|
|
15
|
+
SEVERITY_LIST,
|
|
16
|
+
isSeverity,
|
|
17
|
+
meetsSeverity
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=chunk-77AINBYM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/severity.ts"],"sourcesContent":["/**\n * The one severity scale every manni tool speaks. Least to most severe.\n *\n * Three values, chosen to match the sinks every tool writes to and the\n * linters that sit beside it. GitHub annotations are `error`, `warning` and\n * `notice`; so are ESLint's and Vale's levels, and pa11y's. A flag or config\n * key that two domains both have carries the same name and the same values,\n * and this is where the values for `severity` are defined once.\n *\n * A domain whose source speaks another scale maps onto this one and keeps\n * the source's value in a field of its own, so nothing is lost for lookup.\n * a11y is the first case: axe reports four impacts, the analyzer folds them\n * onto these three, and each finding still carries axe's word as `impact`.\n */\nexport const SEVERITIES = [\"notice\", \"warning\", \"error\"] as const;\nexport type Severity = (typeof SEVERITIES)[number];\n\n/** The list the way a usage message spells it: `notice | warning | error`. */\nexport const SEVERITY_LIST: string = SEVERITIES.join(\" | \");\n\nexport function isSeverity(value: string): value is Severity {\n return (SEVERITIES as readonly string[]).includes(value);\n}\n\n/** `true` when `severity` is at or above `min`. */\nexport function meetsSeverity(severity: Severity, min: Severity): boolean {\n return SEVERITIES.indexOf(severity) >= SEVERITIES.indexOf(min);\n}\n"],"mappings":";;;AAcO,IAAM,aAAa,CAAC,UAAU,WAAW,OAAO;AAIhD,IAAM,gBAAwB,WAAW,KAAK,KAAK;AAEnD,SAAS,WAAW,OAAkC;AAC3D,SAAQ,WAAiC,SAAS,KAAK;AACzD;AAGO,SAAS,cAAc,UAAoB,KAAwB;AACxE,SAAO,WAAW,QAAQ,QAAQ,KAAK,WAAW,QAAQ,GAAG;AAC/D;","names":[]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resultFor,
|
|
4
|
+
splitBaselined
|
|
5
|
+
} from "./chunk-JXLTXMJ7.js";
|
|
6
|
+
import {
|
|
7
|
+
errorSite
|
|
8
|
+
} from "./chunk-SKSDRUUK.js";
|
|
9
|
+
import {
|
|
10
|
+
escapeWorkflowCommandMessage,
|
|
11
|
+
escapeWorkflowCommandProperty
|
|
12
|
+
} from "./chunk-MNH7QO4Z.js";
|
|
13
|
+
|
|
14
|
+
// src/cite/reporters/github.ts
|
|
15
|
+
var NAMES_ITS_SUBJECT = /* @__PURE__ */ new Set([
|
|
16
|
+
"claim-moved",
|
|
17
|
+
"claim-moved-ambiguous",
|
|
18
|
+
"claim-changed",
|
|
19
|
+
"marker-orphan",
|
|
20
|
+
"marker-invalid",
|
|
21
|
+
"marker-repeated",
|
|
22
|
+
"anchor-invalid"
|
|
23
|
+
]);
|
|
24
|
+
function findingMessage(finding) {
|
|
25
|
+
const subject = finding.id ?? finding.src;
|
|
26
|
+
if (subject === void 0) return finding.message;
|
|
27
|
+
if (NAMES_ITS_SUBJECT.has(finding.rule)) return finding.message;
|
|
28
|
+
if (finding.id !== void 0 && finding.message.startsWith(finding.id)) return finding.message;
|
|
29
|
+
const where = finding.id !== void 0 && finding.src !== void 0 ? ` (${finding.src})` : "";
|
|
30
|
+
return `${subject}${where}: ${finding.message}`;
|
|
31
|
+
}
|
|
32
|
+
function renderCheckGithub(run) {
|
|
33
|
+
const lines = [];
|
|
34
|
+
run.pages.forEach((page, index) => {
|
|
35
|
+
const { reported } = splitBaselined(page, resultFor(run, index));
|
|
36
|
+
for (const finding of reported) {
|
|
37
|
+
const site = errorSite(finding);
|
|
38
|
+
const params = [`file=${escapeWorkflowCommandProperty(site.file ?? page.file)}`];
|
|
39
|
+
if (site.line !== void 0) params.push(`line=${String(site.line)}`);
|
|
40
|
+
params.push(`title=${escapeWorkflowCommandProperty(finding.ruleId)}`);
|
|
41
|
+
lines.push(
|
|
42
|
+
`::${finding.severity} ${params.join(",")}::${escapeWorkflowCommandMessage(findingMessage(finding))}`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return lines.join("\n");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
NAMES_ITS_SUBJECT,
|
|
51
|
+
findingMessage,
|
|
52
|
+
renderCheckGithub
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=chunk-7UKO3ASZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cite/reporters/github.ts"],"sourcesContent":["/**\n * GitHub workflow commands, one per finding:\n * `::error file=<file>,line=<n>,title=<ruleId>::<id or src> (<src>): <message>`\n * with `::warning` and `::notice` for the lower levels: the family scale is\n * GitHub's, so the level is the severity. Uses meta's escapes. A baselined\n * finding is not an annotation; a clean run is the empty string.\n */\nimport {\n escapeWorkflowCommandMessage,\n escapeWorkflowCommandProperty,\n} from \"../../meta/internal.js\";\nimport { errorSite } from \"../core/adapt.js\";\nimport type { CheckRun, CitationFinding, CiteRule } from \"../types.js\";\nimport { resultFor, splitBaselined } from \"./pretty.js\";\n\n/**\n * The rules whose message already names what it is about: every claim,\n * marker and anchor message is written as a sentence about the entry, so\n * prefixing it with the subject again would say the name twice. Exported so\n * a test asserting the composed messages reads this set rather than a copy.\n */\nexport const NAMES_ITS_SUBJECT = new Set<CiteRule>([\n \"claim-moved\",\n \"claim-moved-ambiguous\",\n \"claim-changed\",\n \"marker-orphan\",\n \"marker-invalid\",\n \"marker-repeated\",\n \"anchor-invalid\",\n]);\n\n/**\n * `<id> (<src>): <message>`, or `<src>: <message>` when the entry has no id.\n * A message that names its own subject, by its rule or by opening with the\n * id (an `entry-invalid` about a pin prefix does), is left to say it once.\n * SARIF and JUnit carry the same message.\n */\nexport function findingMessage(finding: CitationFinding): string {\n const subject = finding.id ?? finding.src;\n if (subject === undefined) return finding.message;\n if (NAMES_ITS_SUBJECT.has(finding.rule)) return finding.message;\n if (finding.id !== undefined && finding.message.startsWith(finding.id)) return finding.message;\n const where = finding.id !== undefined && finding.src !== undefined ? ` (${finding.src})` : \"\";\n return `${subject}${where}: ${finding.message}`;\n}\n\nexport function renderCheckGithub(run: CheckRun): string {\n const lines: string[] = [];\n run.pages.forEach((page, index) => {\n const { reported } = splitBaselined(page, resultFor(run, index));\n for (const finding of reported) {\n // A finding about an entry a manifest owns is annotated on the\n // manifest, unless that manifest is outside the tree, where an\n // annotation would land nowhere: then the page carries it.\n const site = errorSite(finding);\n const params = [`file=${escapeWorkflowCommandProperty(site.file ?? page.file)}`];\n if (site.line !== undefined) params.push(`line=${String(site.line)}`);\n params.push(`title=${escapeWorkflowCommandProperty(finding.ruleId)}`);\n lines.push(\n `::${finding.severity} ${params.join(\",\")}::${escapeWorkflowCommandMessage(findingMessage(finding))}`,\n );\n }\n });\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;;;AAqBO,IAAM,oBAAoB,oBAAI,IAAc;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAQM,SAAS,eAAe,SAAkC;AAC/D,QAAM,UAAU,QAAQ,MAAM,QAAQ;AACtC,MAAI,YAAY,OAAW,QAAO,QAAQ;AAC1C,MAAI,kBAAkB,IAAI,QAAQ,IAAI,EAAG,QAAO,QAAQ;AACxD,MAAI,QAAQ,OAAO,UAAa,QAAQ,QAAQ,WAAW,QAAQ,EAAE,EAAG,QAAO,QAAQ;AACvF,QAAM,QAAQ,QAAQ,OAAO,UAAa,QAAQ,QAAQ,SAAY,KAAK,QAAQ,GAAG,MAAM;AAC5F,SAAO,GAAG,OAAO,GAAG,KAAK,KAAK,QAAQ,OAAO;AAC/C;AAEO,SAAS,kBAAkB,KAAuB;AACvD,QAAM,QAAkB,CAAC;AACzB,MAAI,MAAM,QAAQ,CAAC,MAAM,UAAU;AACjC,UAAM,EAAE,SAAS,IAAI,eAAe,MAAM,UAAU,KAAK,KAAK,CAAC;AAC/D,eAAW,WAAW,UAAU;AAI9B,YAAM,OAAO,UAAU,OAAO;AAC9B,YAAM,SAAS,CAAC,QAAQ,8BAA8B,KAAK,QAAQ,KAAK,IAAI,CAAC,EAAE;AAC/E,UAAI,KAAK,SAAS,OAAW,QAAO,KAAK,QAAQ,OAAO,KAAK,IAAI,CAAC,EAAE;AACpE,aAAO,KAAK,SAAS,8BAA8B,QAAQ,MAAM,CAAC,EAAE;AACpE,YAAM;AAAA,QACJ,KAAK,QAAQ,QAAQ,IAAI,OAAO,KAAK,GAAG,CAAC,KAAK,6BAA6B,eAAe,OAAO,CAAC,CAAC;AAAA,MACrG;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
PATH_JOIN,
|
|
4
|
+
applyRelocation,
|
|
5
|
+
offerPrompt,
|
|
6
|
+
planRelocation,
|
|
7
|
+
relocationOffers
|
|
8
|
+
} from "./chunk-M3W7J6MU.js";
|
|
9
|
+
|
|
10
|
+
// src/meta/core/location-writes.ts
|
|
11
|
+
import { LineCounter, isMap, isNode, isScalar, parseDocument } from "yaml";
|
|
12
|
+
var dedupe = (xs) => [...new Set(xs)];
|
|
13
|
+
var pages = (n) => `${String(n)} page${n === 1 ? "" : "s"}`;
|
|
14
|
+
async function offerExternalHomes(ctx, writes, hooks) {
|
|
15
|
+
const applied = /* @__PURE__ */ new Set();
|
|
16
|
+
const groups = /* @__PURE__ */ new Map();
|
|
17
|
+
for (const w of writes) {
|
|
18
|
+
if (w.home.kind !== "collection") continue;
|
|
19
|
+
const group = groups.get(w.home.collection) ?? [];
|
|
20
|
+
group.push(w);
|
|
21
|
+
groups.set(w.home.collection, group);
|
|
22
|
+
}
|
|
23
|
+
for (const [collection, group] of groups) {
|
|
24
|
+
const require2 = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const w of group) {
|
|
26
|
+
const keys = require2.get(w.label) ?? [];
|
|
27
|
+
if (!keys.includes(w.key)) keys.push(w.key);
|
|
28
|
+
require2.set(w.label, keys);
|
|
29
|
+
}
|
|
30
|
+
const plan = await planRelocation(ctx, {
|
|
31
|
+
files: [...require2.keys()],
|
|
32
|
+
fields: dedupe(group.map((w) => w.key)),
|
|
33
|
+
require: require2
|
|
34
|
+
});
|
|
35
|
+
const offers = relocationOffers(plan);
|
|
36
|
+
if (offers.length === 0) continue;
|
|
37
|
+
let yes = true;
|
|
38
|
+
for (const offer of offers) {
|
|
39
|
+
const { notice, question } = offerPrompt(offer, "write");
|
|
40
|
+
hooks.onNotice?.(notice);
|
|
41
|
+
if (!await hooks.confirm(question)) {
|
|
42
|
+
yes = false;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!yes) continue;
|
|
47
|
+
const result = await applyRelocation(ctx, plan);
|
|
48
|
+
hooks.onRelocated?.(result);
|
|
49
|
+
applied.add(collection);
|
|
50
|
+
}
|
|
51
|
+
return applied;
|
|
52
|
+
}
|
|
53
|
+
function externalWriteWarnings(writes, dryRun) {
|
|
54
|
+
const verb = dryRun ? "would write" : "wrote";
|
|
55
|
+
const groups = /* @__PURE__ */ new Map();
|
|
56
|
+
const groupOf = (w) => w.home.kind === "collection" ? `c:${w.home.collection}` : `n:${w.home.reason}`;
|
|
57
|
+
for (const w of writes) {
|
|
58
|
+
const id = groupOf(w);
|
|
59
|
+
groups.set(id, [...groups.get(id) ?? [], w]);
|
|
60
|
+
}
|
|
61
|
+
const out = [];
|
|
62
|
+
for (const group of groups.values()) {
|
|
63
|
+
const [first] = group;
|
|
64
|
+
if (first === void 0) continue;
|
|
65
|
+
out.push(
|
|
66
|
+
externalWriteWarning({
|
|
67
|
+
verb,
|
|
68
|
+
keys: dedupe(group.map((w) => w.key)),
|
|
69
|
+
pages: new Set(group.map((w) => w.label)).size,
|
|
70
|
+
home: first.home,
|
|
71
|
+
createsHome: group.some(
|
|
72
|
+
(w) => w.home.kind === "collection" && (w.home.createsCollection || w.home.addsPath !== void 0)
|
|
73
|
+
)
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
function externalWriteWarning(line) {
|
|
80
|
+
const { verb, keys, home } = line;
|
|
81
|
+
const one = keys.length === 1;
|
|
82
|
+
const head = `${verb} ${keys.join(", ")} to ${pages(line.pages)}`;
|
|
83
|
+
const prefer = one ? "the schema prefers external metadata" : "their schemas prefer external metadata";
|
|
84
|
+
const them = one ? "it" : "them";
|
|
85
|
+
if (home.kind === "collection") {
|
|
86
|
+
if (!line.createsHome) {
|
|
87
|
+
return `${head} in collection ${home.collection}; ${prefer}, and no manifest owns ${them}. Run manni meta relocate to move ${them}.`;
|
|
88
|
+
}
|
|
89
|
+
return home.createsCollection || home.createsManifest ? `${head}; ${prefer}. Run manni meta relocate to give ${them} a manifest.` : `${head}; ${prefer}. Run manni meta relocate to add ${them} to collection ${home.collection}.`;
|
|
90
|
+
}
|
|
91
|
+
return home.reason === "no-config" ? `${head}; ${prefer}, and --no-config leaves ${them} no manifest.` : `${head} that ${line.pages === 1 ? "is" : "are"} in none of the ${String(home.collections)} collections; ${prefer}, and only a collection has a manifest.`;
|
|
92
|
+
}
|
|
93
|
+
function manifestKeyLine(text, entry, key, join) {
|
|
94
|
+
const norm = (e) => join === PATH_JOIN ? e.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/") : e;
|
|
95
|
+
const lc = new LineCounter();
|
|
96
|
+
const doc = parseDocument(text, { lineCounter: lc, uniqueKeys: false });
|
|
97
|
+
const root = doc.contents;
|
|
98
|
+
if (!isMap(root)) return void 0;
|
|
99
|
+
for (const pair of root.items) {
|
|
100
|
+
const spelled = isScalar(pair.key) ? String(pair.key.value) : String(pair.key);
|
|
101
|
+
if (norm(spelled) !== norm(entry) || !isMap(pair.value)) continue;
|
|
102
|
+
for (const kv of pair.value.items) {
|
|
103
|
+
const name = isScalar(kv.key) ? String(kv.key.value) : String(kv.key);
|
|
104
|
+
const range = isNode(kv.key) ? kv.key.range : void 0;
|
|
105
|
+
if (name === key && range) return lc.linePos(range[0]).line;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/meta/core/meta-provenance.ts
|
|
112
|
+
function isPlainRecord(value) {
|
|
113
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
114
|
+
}
|
|
115
|
+
function mergeMetaProvenance(held, model, key, proposed) {
|
|
116
|
+
if (held !== void 0 && !Array.isArray(held)) return void 0;
|
|
117
|
+
const list = held === void 0 ? [] : [...held];
|
|
118
|
+
const at = list.findIndex((e) => isPlainRecord(e) && e["generated-by"] === model);
|
|
119
|
+
const prior = list[at];
|
|
120
|
+
const kept = isPlainRecord(prior) ? prior : {};
|
|
121
|
+
const priorNames = kept[key];
|
|
122
|
+
const names = Array.isArray(priorNames) ? priorNames.filter((p) => typeof p === "string") : [];
|
|
123
|
+
const confidence = {};
|
|
124
|
+
if (isPlainRecord(kept.confidence)) {
|
|
125
|
+
for (const [k, v] of Object.entries(kept.confidence)) {
|
|
126
|
+
if (typeof v === "number") confidence[k] = v;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const p of proposed) {
|
|
130
|
+
if (!names.includes(p.name)) names.push(p.name);
|
|
131
|
+
confidence[p.name] = p.confidence;
|
|
132
|
+
}
|
|
133
|
+
const entry = {
|
|
134
|
+
...kept,
|
|
135
|
+
"generated-by": model,
|
|
136
|
+
[key]: names,
|
|
137
|
+
confidence
|
|
138
|
+
};
|
|
139
|
+
if (at === -1) list.push(entry);
|
|
140
|
+
else list[at] = entry;
|
|
141
|
+
return { list, entry, names };
|
|
142
|
+
}
|
|
143
|
+
function metaProvenanceEntries(value) {
|
|
144
|
+
if (!Array.isArray(value)) return [];
|
|
145
|
+
const strings = (list) => Array.isArray(list) ? list.filter((s) => typeof s === "string") : [];
|
|
146
|
+
const out = [];
|
|
147
|
+
for (const item of value) {
|
|
148
|
+
if (!isPlainRecord(item)) continue;
|
|
149
|
+
const machine = item["generated-by"];
|
|
150
|
+
if (typeof machine !== "string" || machine === "") continue;
|
|
151
|
+
out.push({ "generated-by": machine, fields: strings(item.fields), evals: strings(item.evals) });
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
offerExternalHomes,
|
|
158
|
+
externalWriteWarnings,
|
|
159
|
+
externalWriteWarning,
|
|
160
|
+
manifestKeyLine,
|
|
161
|
+
mergeMetaProvenance,
|
|
162
|
+
metaProvenanceEntries
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=chunk-A5ULMVHQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/meta/core/location-writes.ts","../src/meta/core/meta-provenance.ts"],"sourcesContent":["/**\n * What a writer (`derive`, `fill`) does with a value its schema prefers in\n * external metadata when no manifest owns the key (proposal 0047).\n *\n * On a terminal, one question per collection (P1) offers the relocation that\n * gives the key a manifest, and a yes applies it before anything is written.\n * Off a terminal, declined, or under a dry run, the value is written to the\n * page as before, and one warning per collection (W1), or per set of pages\n * with no possible home (W2), says so. The planning and the prompt's wording\n * are `relocation.ts`'s; this module is the writers' shared use of them.\n */\nimport { LineCounter, isMap, isNode, isScalar, parseDocument } from \"yaml\";\nimport type { Confirm } from \"../../shared/prompt.js\";\nimport {\n applyRelocation,\n offerPrompt,\n planRelocation,\n relocationOffers,\n type ProposedHome,\n type RelocateResult,\n type RelocationContext,\n} from \"./relocation.js\";\nimport { PATH_JOIN } from \"./external-metadata.js\";\n\n/** One key a writer is about to set on one page, which prefers external metadata and has no manifest. */\nexport interface ExternalWrite {\n label: string;\n key: string;\n home: ProposedHome;\n}\n\nconst dedupe = <T>(xs: readonly T[]): T[] => [...new Set(xs)];\nconst pages = (n: number): string => `${String(n)} page${n === 1 ? \"\" : \"s\"}`;\n\n/**\n * Ask P1 once per collection the writes would be homed in, and apply each\n * relocation the user accepts. Returns the collections whose relocation was\n * applied; their keys now have a manifest, and the caller re-reads what the\n * relocation changed before writing. Writes with no possible home are never\n * offered.\n */\nexport async function offerExternalHomes(\n ctx: RelocationContext,\n writes: readonly ExternalWrite[],\n hooks: {\n confirm: Confirm;\n onNotice?: (message: string) => void;\n onRelocated?: (result: RelocateResult) => void;\n },\n): Promise<Set<string>> {\n const applied = new Set<string>();\n const groups = new Map<string, ExternalWrite[]>();\n for (const w of writes) {\n if (w.home.kind !== \"collection\") continue;\n const group = groups.get(w.home.collection) ?? [];\n group.push(w);\n groups.set(w.home.collection, group);\n }\n for (const [collection, group] of groups) {\n const require = new Map<string, string[]>();\n for (const w of group) {\n const keys = require.get(w.label) ?? [];\n if (!keys.includes(w.key)) keys.push(w.key);\n require.set(w.label, keys);\n }\n // Planned against the config as it stands now: an earlier collection's\n // accepted relocation may have created the config file.\n const plan = await planRelocation(ctx, {\n files: [...require.keys()],\n fields: dedupe(group.map((w) => w.key)),\n require,\n });\n const offers = relocationOffers(plan);\n if (offers.length === 0) continue;\n let yes = true;\n for (const offer of offers) {\n const { notice, question } = offerPrompt(offer, \"write\");\n hooks.onNotice?.(notice);\n if (!(await hooks.confirm(question))) {\n yes = false;\n break;\n }\n }\n if (!yes) continue;\n const result = await applyRelocation(ctx, plan);\n hooks.onRelocated?.(result);\n applied.add(collection);\n }\n return applied;\n}\n\n/**\n * The W1 and W2 lines for the writes that landed on a page, or would under a\n * dry run: one per collection, one for the pages in none of several\n * collections, and one under `--no-config`. Without the `manni: ` prefix,\n * which `warn()` adds.\n */\nexport function externalWriteWarnings(\n writes: readonly ExternalWrite[],\n dryRun: boolean,\n): string[] {\n const verb = dryRun ? \"would write\" : \"wrote\";\n const groups = new Map<string, ExternalWrite[]>();\n const groupOf = (w: ExternalWrite): string =>\n w.home.kind === \"collection\" ? `c:${w.home.collection}` : `n:${w.home.reason}`;\n for (const w of writes) {\n const id = groupOf(w);\n groups.set(id, [...(groups.get(id) ?? []), w]);\n }\n const out: string[] = [];\n for (const group of groups.values()) {\n const [first] = group;\n /* c8 ignore next -- a group holds at least one write. */\n if (first === undefined) continue;\n out.push(\n externalWriteWarning({\n verb,\n keys: dedupe(group.map((w) => w.key)),\n pages: new Set(group.map((w) => w.label)).size,\n home: first.home,\n createsHome: group.some(\n (w) => w.home.kind === \"collection\" && (w.home.createsCollection || w.home.addsPath !== undefined),\n ),\n }),\n );\n }\n return out;\n}\n\n/**\n * One W1 or W2 line, without the `manni: ` prefix: `keys` were written (or\n * would be) to `pages` pages whose home is `home`. `createsHome` says\n * relocate would create the collection, manifest or path that gives them a\n * manifest. Where it would only add a path to a collection whose manifest\n * already exists, the line says so rather than promising a manifest. One key\n * reads in the singular, several in the plural.\n */\nexport function externalWriteWarning(line: {\n verb: \"wrote\" | \"would write\";\n keys: readonly string[];\n pages: number;\n home: ProposedHome;\n createsHome: boolean;\n}): string {\n const { verb, keys, home } = line;\n const one = keys.length === 1;\n const head = `${verb} ${keys.join(\", \")} to ${pages(line.pages)}`;\n const prefer = one ? \"the schema prefers external metadata\" : \"their schemas prefer external metadata\";\n const them = one ? \"it\" : \"them\";\n if (home.kind === \"collection\") {\n if (!line.createsHome) {\n return `${head} in collection ${home.collection}; ${prefer}, and no manifest owns ${them}. Run manni meta relocate to move ${them}.`;\n }\n // Whether the collection has a manifest is the collection's, so any write in the group answers it.\n return home.createsCollection || home.createsManifest\n ? `${head}; ${prefer}. Run manni meta relocate to give ${them} a manifest.`\n : `${head}; ${prefer}. Run manni meta relocate to add ${them} to collection ${home.collection}.`;\n }\n return home.reason === \"no-config\"\n ? `${head}; ${prefer}, and --no-config leaves ${them} no manifest.`\n : `${head} that ${line.pages === 1 ? \"is\" : \"are\"} in none of the ${String(home.collections)} collections; ${prefer}, and only a collection has a manifest.`;\n}\n\n/**\n * The 1-based line of `key` in the entry for `entry`, in a manifest's text:\n * where a writer's report points after the write. A path entry matches\n * however the manifest spells it (`./docs/a.md` is `docs/a.md`).\n */\nexport function manifestKeyLine(\n text: string,\n entry: string,\n key: string,\n join: string,\n): number | undefined {\n const norm = (e: string): string =>\n join === PATH_JOIN ? e.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/+/g, \"/\") : e;\n const lc = new LineCounter();\n const doc = parseDocument(text, { lineCounter: lc, uniqueKeys: false });\n const root = doc.contents;\n if (!isMap(root)) return undefined;\n for (const pair of root.items) {\n const spelled = isScalar(pair.key) ? String(pair.key.value) : String(pair.key);\n if (norm(spelled) !== norm(entry) || !isMap(pair.value)) continue;\n for (const kv of pair.value.items) {\n const name = isScalar(kv.key) ? String(kv.key.value) : String(kv.key);\n const range = isNode(kv.key) ? kv.key.range : undefined;\n if (name === key && range) return lc.linePos(range[0]).line;\n }\n }\n return undefined;\n}\n","/**\n * `meta-provenance` (proposal 0046): which model proposed which metadata, one\n * entry per model. `fields` names the values by JSON Pointer and `evals` names\n * the evals by id, and `confidence` is keyed by either, which cannot collide\n * because a pointer starts with `/` and an id cannot.\n *\n * Two tools write it: `manni meta fill` records the fields it writes, and\n * `manni docevals fill` records the evals it writes. They merge the same way,\n * so the merge lives here rather than in either command.\n */\n\n/** A name one run proposed, under `fields` or `evals`, and its confidence. */\nexport interface MetaProvenanceProposal {\n name: string;\n confidence: number;\n}\n\n/** Which list of an entry a run's proposals go under. */\nexport type MetaProvenanceKey = \"fields\" | \"evals\";\n\n/** An entry after a merge: whatever it held, with the run's names and confidences. */\nexport interface MergedMetaProvenanceEntry {\n \"generated-by\": string;\n confidence: Record<string, number>;\n [other: string]: unknown;\n}\n\nexport interface MergedMetaProvenance {\n /** The whole `meta-provenance` list, to write back. */\n list: unknown[];\n /** The entry the run merged into, as it now stands in `list`. */\n entry: MergedMetaProvenanceEntry;\n /** The entry's names under the merged key: its own first, then the run's new ones. */\n names: string[];\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * The page's `meta-provenance` list with one run's proposals merged in. The\n * first entry for `model` gains the new names under `key` after its own, and\n * their confidences; everything else in it, and every other entry, is kept.\n * Without one, a new entry is appended. `undefined` when the page holds\n * something other than a list, which there is no merging into.\n */\nexport function mergeMetaProvenance(\n held: unknown,\n model: string,\n key: MetaProvenanceKey,\n proposed: readonly MetaProvenanceProposal[],\n): MergedMetaProvenance | undefined {\n if (held !== undefined && !Array.isArray(held)) return undefined;\n const list: unknown[] = held === undefined ? [] : [...(held as unknown[])];\n const at = list.findIndex((e) => isPlainRecord(e) && e[\"generated-by\"] === model);\n const prior = list[at];\n const kept = isPlainRecord(prior) ? prior : {};\n const priorNames = kept[key];\n const names = Array.isArray(priorNames)\n ? (priorNames as unknown[]).filter((p): p is string => typeof p === \"string\")\n : [];\n const confidence: Record<string, number> = {};\n if (isPlainRecord(kept.confidence)) {\n for (const [k, v] of Object.entries(kept.confidence)) {\n if (typeof v === \"number\") confidence[k] = v;\n }\n }\n for (const p of proposed) {\n if (!names.includes(p.name)) names.push(p.name);\n confidence[p.name] = p.confidence;\n }\n const entry: MergedMetaProvenanceEntry = {\n ...kept,\n \"generated-by\": model,\n [key]: names,\n confidence,\n };\n if (at === -1) list.push(entry);\n else list[at] = entry;\n return { list, entry, names };\n}\n\n/** One `meta-provenance` entry as read: the model, and the names it proposed. */\nexport interface MetaProvenanceRecord {\n \"generated-by\": string;\n /** JSON Pointers, strings only; empty when the entry names none. */\n fields: string[];\n /** Eval ids, strings only; empty when the entry names none. */\n evals: string[];\n}\n\n/**\n * The readable entries of a `meta-provenance` value, in order. As with\n * `provenanceEntries`, an entry the schema would reject for its identity (not\n * a mapping, no model) is skipped rather than guessed at, and a malformed list\n * under `fields` or `evals` reads as naming nothing: the schema finding speaks\n * for it. A reader never throws on what a page holds.\n */\nexport function metaProvenanceEntries(value: unknown): MetaProvenanceRecord[] {\n if (!Array.isArray(value)) return [];\n const strings = (list: unknown): string[] =>\n Array.isArray(list)\n ? (list as unknown[]).filter((s): s is string => typeof s === \"string\")\n : [];\n const out: MetaProvenanceRecord[] = [];\n for (const item of value as unknown[]) {\n if (!isPlainRecord(item)) continue;\n const machine = item[\"generated-by\"];\n if (typeof machine !== \"string\" || machine === \"\") continue;\n out.push({ \"generated-by\": machine, fields: strings(item.fields), evals: strings(item.evals) });\n }\n return out;\n}\n"],"mappings":"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","names":["require"]}
|