102 lines
2.9 KiB
JavaScript
102 lines
2.9 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { readFileSync } from "node:fs";
|
|
|
|
const lines = readFileSync("src/index.ts", "utf8").split(/\r?\n/);
|
|
const docs = readFileSync("COMMANDS.md", "utf8");
|
|
|
|
function hasDocRef(commandText) {
|
|
return (
|
|
docs.includes(`\`${commandText}\``) ||
|
|
docs.includes(` ${commandText} \``) ||
|
|
docs.includes(`\`${commandText} `)
|
|
);
|
|
}
|
|
|
|
const varToCommand = new Map();
|
|
const commandSet = new Set();
|
|
|
|
let pendingParentVar = null;
|
|
let currentChainBase = null;
|
|
|
|
for (const line of lines) {
|
|
const varAssign = line.match(/^\s*const\s+(\w+)\s*=\s*program\s*$/);
|
|
if (varAssign) {
|
|
pendingParentVar = varAssign[1];
|
|
continue;
|
|
}
|
|
|
|
const lineRef = line.match(/^\s*(\w+)\s*$/);
|
|
if (lineRef) {
|
|
const mapped = varToCommand.get(lineRef[1]);
|
|
if (mapped) currentChainBase = mapped;
|
|
continue;
|
|
}
|
|
|
|
const dotCommand = line.match(/^\s*\.command\(\s*(?:"([^"]+)"|'([^']+)')/);
|
|
if (dotCommand) {
|
|
const raw = (dotCommand[1] ?? dotCommand[2]).trim();
|
|
if (pendingParentVar) {
|
|
varToCommand.set(pendingParentVar, raw);
|
|
commandSet.add(raw);
|
|
currentChainBase = raw;
|
|
pendingParentVar = null;
|
|
} else if (currentChainBase) {
|
|
commandSet.add(`${currentChainBase} ${raw}`);
|
|
} else {
|
|
commandSet.add(raw);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
const childCommand = line.match(/^\s*(\w+)\.command\(\s*(?:"([^"]+)"|'([^']+)')/);
|
|
if (childCommand) {
|
|
const varName = childCommand[1];
|
|
const raw = (childCommand[2] ?? childCommand[3]).trim();
|
|
const base = varToCommand.get(varName);
|
|
if (base) commandSet.add(`${base} ${raw}`);
|
|
else if (currentChainBase) commandSet.add(`${currentChainBase} ${raw}`);
|
|
else commandSet.add(raw);
|
|
currentChainBase = base ?? currentChainBase ?? raw;
|
|
pendingParentVar = null;
|
|
continue;
|
|
}
|
|
|
|
// keep context across chained calls
|
|
if (/^\s*\./.test(line)) {
|
|
continue;
|
|
}
|
|
|
|
pendingParentVar = null;
|
|
currentChainBase = null;
|
|
}
|
|
|
|
const fullText = lines.join("\n");
|
|
const optionMatches = [...fullText.matchAll(/\.option\(\s*(?:"([^"]+)"|'([^']+)')/g)];
|
|
const options = [...new Set(
|
|
optionMatches
|
|
.map((m) => m[1] ?? m[2])
|
|
.filter((opt) => opt.includes("--") && !opt.includes("<"))
|
|
.map((opt) => opt.match(/--[^\s,>]+/)?.[0])
|
|
.filter(Boolean)
|
|
)];
|
|
|
|
const commandList = [...commandSet];
|
|
const missingCommands = commandList.filter((cmd) => !hasDocRef(cmd));
|
|
const missingOptions = options.filter((opt) => !docs.includes(opt));
|
|
|
|
if (missingCommands.length || missingOptions.length) {
|
|
console.error("DOCS PARITY CHECK FAILED");
|
|
if (missingCommands.length) {
|
|
console.error("Missing command entries:");
|
|
for (const cmd of missingCommands) console.error(` - ${cmd}`);
|
|
}
|
|
if (missingOptions.length) {
|
|
console.error("Missing long options:");
|
|
for (const opt of missingOptions) console.error(` - ${opt}`);
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`DOCS PARITY CHECK OK: ${commandSet.size} commands, ${options.length} options`);
|