1export interface ParsedArgs {
2 command?: string;
3 options: Record<string, string | boolean>;
4 positional: string[];
5}
6
7export function parseArgs(args: string[]): ParsedArgs {
8 const [, , command, ...rest] = args;
9 const options: Record<string, string | boolean> = {};
10 const positional: string[] = [];
11
12 for (let i = 0; i < rest.length; i += 1) {
13 const arg = rest[i];
14 if (!arg) continue;
15
16 if (arg.startsWith("--")) {
17 const eqIndex = arg.indexOf("=", 2);
18 let key: string;
19 let value: string | undefined;
20 if (eqIndex !== -1) {
21 key = arg.slice(2, eqIndex);
22 value = arg.slice(eqIndex + 1);
23 } else {
24 key = arg.slice(2);
25 }
26 if (!key) continue;
27 if (value !== undefined) {
28 options[key] = value;
29 } else if (rest[i + 1] && !rest[i + 1]?.startsWith("-")) {
30 options[key] = rest[i + 1] as string;
31 i += 1;
32 } else {
33 options[key] = true;
34 }
35 } else if (arg.startsWith("-")) {
36 const short = arg.slice(1);
37 if (short === "u") {
38 if (rest[i + 1] && !rest[i + 1]!.startsWith("-")) {
39 options["uri"] = rest[i + 1] as string;
40 i += 1;
41 }
42 // else: -u with no value — uri stays unset, command handler validates
43 } else if (short === "f") {
44 options["full"] = true;
45 } else if (short === "v") {
46 options["version"] = true;
47 } else {
48 options[short] = true;
49 }
50 } else {
51 positional.push(arg);
52 }
53 }
54
55 return { command, options, positional };
56}