@goflag/cli 0.2.11 → 0.2.12
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 +42 -4
- package/dist/{chunk-CWEJ6EXT.js → chunk-QKXUKHXB.js} +790 -17
- package/dist/chunk-QKXUKHXB.js.map +1 -0
- package/dist/cli.js +94 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +121 -1
- package/dist/index.js +3 -1
- package/flags.json +1 -1
- package/package.json +2 -2
- package/rules.json +58 -1
- package/dist/chunk-CWEJ6EXT.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -9,11 +9,12 @@ import {
|
|
|
9
9
|
SITE_PROSE_RULES,
|
|
10
10
|
SITE_RULES,
|
|
11
11
|
exitCode,
|
|
12
|
+
renderPreview,
|
|
12
13
|
renderSummaryTerminal,
|
|
13
14
|
renderTerminal,
|
|
14
15
|
runAudit,
|
|
15
16
|
summarize
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-QKXUKHXB.js";
|
|
17
18
|
|
|
18
19
|
// src/report/diff.ts
|
|
19
20
|
function collectFindings(report) {
|
|
@@ -313,7 +314,9 @@ var FLAGS = [
|
|
|
313
314
|
group: "output",
|
|
314
315
|
help: [
|
|
315
316
|
"Roll findings up (dedup by link/rule/code). Pairs",
|
|
316
|
-
"with --json for a compact, agent-friendly payload."
|
|
317
|
+
"with --json for a compact, agent-friendly payload.",
|
|
318
|
+
"Not available with --baseline: there the diff is the",
|
|
319
|
+
"answer, and --report writes the full report."
|
|
317
320
|
],
|
|
318
321
|
takesValue: false,
|
|
319
322
|
apply: ({ parsed }) => {
|
|
@@ -754,6 +757,16 @@ var COMMANDS = [
|
|
|
754
757
|
"table this help is rendered from, so the two cannot",
|
|
755
758
|
"disagree."
|
|
756
759
|
]
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
name: "preview",
|
|
763
|
+
usage: "preview <url>",
|
|
764
|
+
help: [
|
|
765
|
+
"Write .goflag/preview.html \u2014 the page's share cards",
|
|
766
|
+
"as Google, Open Graph, X, LinkedIn, Slack, Discord",
|
|
767
|
+
"and WhatsApp make them, each with the rigor of its",
|
|
768
|
+
"source. Never gates: exits 0 unless the run failed."
|
|
769
|
+
]
|
|
757
770
|
}
|
|
758
771
|
];
|
|
759
772
|
var DESCRIPTION_COLUMN = 25;
|
|
@@ -772,8 +785,9 @@ function renderHelp() {
|
|
|
772
785
|
];
|
|
773
786
|
for (const command of COMMANDS) {
|
|
774
787
|
const pad = " ".repeat(28);
|
|
788
|
+
const label = command.usage ?? command.name;
|
|
775
789
|
command.help.forEach((line, i) => {
|
|
776
|
-
lines.push(i === 0 ? ` goflag ${
|
|
790
|
+
lines.push(i === 0 ? ` goflag ${label.padEnd(19)}${line}` : `${pad}${line}`);
|
|
777
791
|
});
|
|
778
792
|
}
|
|
779
793
|
lines.push("", "Options:");
|
|
@@ -787,6 +801,9 @@ function renderHelp() {
|
|
|
787
801
|
// src/cli-args.ts
|
|
788
802
|
var HELP = renderHelp();
|
|
789
803
|
var COMMAND_NAMES = COMMANDS.map((c) => c.name);
|
|
804
|
+
function isCommand(arg) {
|
|
805
|
+
return COMMAND_NAMES.includes(arg);
|
|
806
|
+
}
|
|
790
807
|
function parseArgs(argv) {
|
|
791
808
|
const parsed = {
|
|
792
809
|
json: false,
|
|
@@ -819,10 +836,25 @@ function parseArgs(argv) {
|
|
|
819
836
|
continue;
|
|
820
837
|
}
|
|
821
838
|
if (arg && arg.startsWith("-")) throw new Error(`unknown option: ${arg}`);
|
|
822
|
-
if (arg &&
|
|
839
|
+
if (arg && isCommand(arg) && !parsed.url && !parsed.command) parsed.command = arg;
|
|
823
840
|
else if (arg && !parsed.url) parsed.url = arg;
|
|
824
841
|
else if (arg) throw new Error(`unexpected argument: ${arg}`);
|
|
825
842
|
}
|
|
843
|
+
if (parsed.command === "preview") {
|
|
844
|
+
const inert = [
|
|
845
|
+
parsed.json && "--json",
|
|
846
|
+
parsed.summary && "--summary",
|
|
847
|
+
parsed.baseline && "--baseline",
|
|
848
|
+
parsed.updateBaseline && "--update-baseline",
|
|
849
|
+
parsed.regressionsOnly && "--regressions-only",
|
|
850
|
+
parsed.maxDebt !== void 0 && "--max-debt"
|
|
851
|
+
].filter((flag) => typeof flag === "string");
|
|
852
|
+
if (inert.length > 0) {
|
|
853
|
+
throw new Error(
|
|
854
|
+
`preview renders what the crawl saw, it does not gate or reformat, so ${inert.join(", ")} would change nothing: drop them, or ask for the JSON with --report <file>`
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
826
858
|
if (parsed.updateBaseline && !parsed.baseline) {
|
|
827
859
|
throw new Error("--update-baseline needs a --baseline <file> to write to");
|
|
828
860
|
}
|
|
@@ -834,6 +866,11 @@ function parseArgs(argv) {
|
|
|
834
866
|
if (parsed.regressionsOnly && !parsed.baseline) {
|
|
835
867
|
throw new Error("--regressions-only needs a --baseline <file> to compare against");
|
|
836
868
|
}
|
|
869
|
+
if (parsed.summary && parsed.baseline) {
|
|
870
|
+
throw new Error(
|
|
871
|
+
"--summary cannot summarise a diff, and --baseline prints the diff: drop --summary, or use --report <file> to keep the full report"
|
|
872
|
+
);
|
|
873
|
+
}
|
|
837
874
|
return parsed;
|
|
838
875
|
}
|
|
839
876
|
|
|
@@ -1370,13 +1407,17 @@ async function readVersion() {
|
|
|
1370
1407
|
return "0.0.0";
|
|
1371
1408
|
}
|
|
1372
1409
|
}
|
|
1373
|
-
async function
|
|
1410
|
+
async function writeText(path, contents) {
|
|
1374
1411
|
const { mkdirSync, writeFileSync } = await import("fs");
|
|
1375
1412
|
const { dirname } = await import("path");
|
|
1376
1413
|
mkdirSync(dirname(path), { recursive: true });
|
|
1377
|
-
writeFileSync(path,
|
|
1378
|
-
|
|
1414
|
+
writeFileSync(path, contents, "utf8");
|
|
1415
|
+
}
|
|
1416
|
+
async function writeJson(path, value) {
|
|
1417
|
+
await writeText(path, `${JSON.stringify(value, null, 2)}
|
|
1418
|
+
`);
|
|
1379
1419
|
}
|
|
1420
|
+
var PREVIEW_PATH = ".goflag/preview.html";
|
|
1380
1421
|
async function main() {
|
|
1381
1422
|
let args;
|
|
1382
1423
|
try {
|
|
@@ -1433,7 +1474,14 @@ ${HELP}
|
|
|
1433
1474
|
});
|
|
1434
1475
|
}
|
|
1435
1476
|
logger.note(`goflag: auditing ${args.url} \u2026`);
|
|
1436
|
-
report = await runAudit(args.url, {
|
|
1477
|
+
report = await runAudit(args.url, {
|
|
1478
|
+
...args.options,
|
|
1479
|
+
// The preview is drawn from what the pages declared, and only this
|
|
1480
|
+
// section carries that. Nothing else asks for it, so nothing else pays
|
|
1481
|
+
// for it.
|
|
1482
|
+
...args.command === "preview" ? { extractions: true } : {},
|
|
1483
|
+
onProgress: logger.onProgress
|
|
1484
|
+
});
|
|
1437
1485
|
logger.stop();
|
|
1438
1486
|
} catch (err) {
|
|
1439
1487
|
logger.stop();
|
|
@@ -1453,6 +1501,22 @@ goflag: retry, or pass --no-sitemap to audit by crawling on purpose.
|
|
|
1453
1501
|
);
|
|
1454
1502
|
return 2;
|
|
1455
1503
|
}
|
|
1504
|
+
if (args.command === "preview") {
|
|
1505
|
+
if (args.report) {
|
|
1506
|
+
await writeJson(args.report, report);
|
|
1507
|
+
process.stderr.write(`goflag: report written to ${args.report}
|
|
1508
|
+
`);
|
|
1509
|
+
}
|
|
1510
|
+
await writeText(PREVIEW_PATH, renderPreview(report));
|
|
1511
|
+
const pages = report.extractions?.length ?? 0;
|
|
1512
|
+
process.stderr.write(
|
|
1513
|
+
`goflag: preview written to ${PREVIEW_PATH} \u2014 ${pages} page${pages === 1 ? "" : "s"}
|
|
1514
|
+
`
|
|
1515
|
+
);
|
|
1516
|
+
process.stdout.write(`${PREVIEW_PATH}
|
|
1517
|
+
`);
|
|
1518
|
+
return 0;
|
|
1519
|
+
}
|
|
1456
1520
|
if (args.baseline) {
|
|
1457
1521
|
const { existsSync, readFileSync } = await import("fs");
|
|
1458
1522
|
if (existsSync(args.baseline) || !args.updateBaseline) {
|
|
@@ -1468,6 +1532,11 @@ goflag: retry, or pass --no-sitemap to audit by crawling on purpose.
|
|
|
1468
1532
|
}
|
|
1469
1533
|
}
|
|
1470
1534
|
}
|
|
1535
|
+
if (args.report) {
|
|
1536
|
+
await writeJson(args.report, report);
|
|
1537
|
+
process.stderr.write(`goflag: report written to ${args.report}
|
|
1538
|
+
`);
|
|
1539
|
+
}
|
|
1471
1540
|
if (args.updateBaseline && args.baseline) {
|
|
1472
1541
|
await writeJson(args.baseline, report);
|
|
1473
1542
|
const total2 = totalFindings(report);
|
|
@@ -1493,11 +1562,6 @@ goflag: retry, or pass --no-sitemap to audit by crawling on purpose.
|
|
|
1493
1562
|
);
|
|
1494
1563
|
return 0;
|
|
1495
1564
|
}
|
|
1496
|
-
if (args.report) {
|
|
1497
|
-
await writeJson(args.report, report);
|
|
1498
|
-
process.stderr.write(`goflag: report written to ${args.report}
|
|
1499
|
-
`);
|
|
1500
|
-
}
|
|
1501
1565
|
if (report.diff && !args.json) {
|
|
1502
1566
|
process.stdout.write(`${renderDiffTerminal(report.diff, { color: args.color })}
|
|
1503
1567
|
`);
|
|
@@ -1537,9 +1601,25 @@ goflag: retry, or pass --no-sitemap to audit by crawling on purpose.
|
|
|
1537
1601
|
}
|
|
1538
1602
|
return exitCode(report, args.failOn);
|
|
1539
1603
|
}
|
|
1540
|
-
|
|
1604
|
+
function flush(stream) {
|
|
1605
|
+
return new Promise((resolve) => {
|
|
1606
|
+
if (stream.writableEnded || stream.destroyed) return resolve();
|
|
1607
|
+
stream.write("", () => resolve());
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
var undelivered = false;
|
|
1611
|
+
for (const stream of [process.stdout, process.stderr]) {
|
|
1612
|
+
stream.on("error", (err) => {
|
|
1613
|
+
if (err.code !== "EPIPE") undelivered = true;
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
main().then(async (code) => {
|
|
1617
|
+
await Promise.all([flush(process.stdout), flush(process.stderr)]);
|
|
1618
|
+
process.exit(undelivered ? 2 : code);
|
|
1619
|
+
}).catch(async (err) => {
|
|
1541
1620
|
process.stderr.write(`goflag: unexpected error: ${err.stack ?? err}
|
|
1542
1621
|
`);
|
|
1622
|
+
await flush(process.stderr);
|
|
1543
1623
|
process.exit(2);
|
|
1544
1624
|
});
|
|
1545
1625
|
//# sourceMappingURL=cli.js.map
|