39 lines
1.7 KiB
TypeScript
39 lines
1.7 KiB
TypeScript
// Tiny argv parser: positionals, --flag, --key value, --key=value.
|
|
export interface Args {
|
|
_: string[];
|
|
has(name: string): boolean;
|
|
get(name: string): string | undefined;
|
|
str(name: string, d: string): string;
|
|
num(name: string, d: number): number;
|
|
list(name: string): string[];
|
|
/** Every value of a flag given more than once (--param a=1 --param b=2), in order. */
|
|
many(name: string): string[];
|
|
}
|
|
|
|
export function parseArgs(argv: string[], booleans: string[] = []): Args {
|
|
const flags = new Map<string, string>();
|
|
const repeated = new Map<string, string[]>();
|
|
const set = (k: string, v: string) => { flags.set(k, v); repeated.set(k, [...(repeated.get(k) ?? []), v]); };
|
|
const _: string[] = [];
|
|
const bool = new Set(['dry', 'yes', 'help', 'json', 'verbose', 'all-pages', 'apply', 'resume', 'force', 'force-unlock', 'include-drafts', ...booleans]);
|
|
for (let i = 0; i < argv.length; i++) {
|
|
const a = argv[i]!;
|
|
if (!a.startsWith('--')) { _.push(a); continue; }
|
|
const eq = a.indexOf('=');
|
|
if (eq > 0) { set(a.slice(2, eq), a.slice(eq + 1)); continue; }
|
|
const name = a.slice(2);
|
|
const next = argv[i + 1];
|
|
if (bool.has(name) || name.startsWith('no-') || next === undefined || next.startsWith('--')) set(name, 'true');
|
|
else { set(name, next); i++; }
|
|
}
|
|
const get = (n: string) => flags.get(n);
|
|
return {
|
|
_,
|
|
has: n => flags.has(n),
|
|
get,
|
|
str: (n, d) => get(n) ?? d,
|
|
num: (n, d) => { const v = get(n); const x = v === undefined ? d : Number(v); if (Number.isNaN(x)) throw new Error(`--${n}: not a number`); return x; },
|
|
list: n => (get(n) ?? '').split(',').map(s => s.trim()).filter(Boolean),
|
|
many: n => repeated.get(n) ?? [],
|
|
};
|
|
}
|