// Parses report CLI output arguments and writes optional artifacts. import { mkdir, writeFile } from "node:fs/promises"; import path from "node:path"; import { booleanFlag, classifyBoundedUnsignedDecimal, parseFlagArgs, stringFlag, } from "./arg-utils.mts"; type ReportCliArgs = { jsonPath: string | null; markdownPath: string | null; rootDir: string }; export const REPORT_CLI_PARSE_OPTIONS = { duplicateOptionMessage: (flag: string) => `${flag} was provided more than once.`, onUnhandledArg(arg: string) { throw new Error(`Unsupported argument: ${arg}`); }, }; export function parseReportCliArgs(argv: string[]) { const options: ReportCliArgs = { rootDir: process.cwd(), jsonPath: null, markdownPath: null, }; const flagEntries = [ ["--root", "rootDir"], ["--json", "jsonPath"], ["--markdown", "markdownPath"], ] satisfies Array<[string, keyof ReportCliArgs]>; const flagSpecs = flagEntries.map(([flag, key]) => stringFlag(flag, key, { allowInline: false, missingValueMessage: `Expected ${flag} .`, rejectShortOptions: true, }), ); return parseFlagArgs(argv, options, flagSpecs, REPORT_CLI_PARSE_OPTIONS); } export function parseInventoryReportCliArgs( argv: string[], options: { allowIncludeAllowed?: boolean } = {}, ) { const args = { help: false, includeAllowed: false, json: false, limit: 120, repoRoot: process.cwd(), }; const flags = [ booleanFlag("--help", "help", true, { repeatable: true }), booleanFlag("-h", "help", true, { repeatable: true }), booleanFlag("--json", "json", true, { repeatable: true }), stringFlag("--repo-root", "repoRoot", { allowInline: false, repeatable: true, rejectShortOptions: true, missingValueMessage: "--repo-root expects a path", }), stringFlag("--limit", "limit", { allowInline: false, repeatable: true, missingValueMessage: "--limit expects a non-negative integer", transform(raw) { const result = classifyBoundedUnsignedDecimal(raw, 0, Number.MAX_SAFE_INTEGER); if (result.kind !== "value") { throw new Error("--limit expects a non-negative integer"); } return result.value; }, }), ]; if (options.allowIncludeAllowed) { flags.push( booleanFlag("--include-allowed", "includeAllowed", true, { repeatable: true }), ); } return parseFlagArgs(argv, args, flags, { onUnhandledArg(arg) { throw new Error(`Unknown argument: ${arg}`); }, }); } /** * Writes an optional report artifact, creating its parent directory first. */ export async function writeReportArtifact(filePath: string | null, content: string) { if (!filePath) { return; } await mkdir(path.dirname(filePath), { recursive: true }); await writeFile(filePath, content, "utf8"); }