have getOptsRaw preserve TextPieces instead of folding into raw strings

This commit is contained in:
Tangent Wantwight 2023-11-20 20:15:56 -05:00
parent c8fc4678fc
commit 8cba197ffd
1 changed files with 49 additions and 23 deletions

View File

@ -4,12 +4,12 @@ export type Options = Record<string, number> & {
$min?: number;
$max?: number;
};
type ParsedOptions<P extends Options> = {
type ParsedOptions<P extends Options, V extends string | TextPiece> = {
[K in keyof P]: K extends "$min" | "$max"
? never
: P[K] extends 0
? boolean
: string[] | [];
: V[] | [];
} & {
error?: string;
};
@ -17,44 +17,69 @@ type ParsedOptions<P extends Options> = {
export function getOpt<P extends Options>(
argv: TextPiece[],
options: P,
procBody: (switches: ParsedOptions<P>, ...argv: string[]) => ProcResult
procBody: (
switches: ParsedOptions<P, string>,
...argv: string[]
) => ProcResult
): ProcResult;
export function getOpt<P extends Options>(
argv: TextPiece[],
options: P
): [ParsedOptions<P>, ...string[]];
): [ParsedOptions<P, string>, ...string[]];
export function getOpt<P extends Options>(
argv: TextPiece[],
options: P,
procBody?: (switches: ParsedOptions<P>, ...argv: string[]) => ProcResult
): [ParsedOptions<P>, ...string[]] | ProcResult {
procBody?: (
switches: ParsedOptions<P, string>,
...argv: string[]
) => ProcResult
): [ParsedOptions<P, string>, ...string[]] | ProcResult {
const [flags, textPieces] = getOptCore(argv, options);
if (procBody) {
if ("error" in flags) {
if ("error" in flags) {
if (procBody) {
return flags as ErrorResult;
} else {
return procBody(flags, ...textPieces.map(AsText));
return [flags as ParsedOptions<P, string>];
}
}
const simpleFlags = Object.fromEntries(
Object.entries(flags).map(([name, textPieces]) => [
name,
typeof textPieces == "boolean"
? textPieces
: (textPieces as TextPiece[]).map(AsText),
])
) as ParsedOptions<P, string>;
if (procBody) {
return procBody(simpleFlags, ...textPieces.map(AsText));
} else {
return [flags, ...textPieces.map(AsText)];
return [simpleFlags, ...textPieces.map(AsText)];
}
}
export function getOptRaw<P extends Options>(
argv: TextPiece[],
options: P,
procBody: (switches: ParsedOptions<P>, argv: TextPiece[]) => ProcResult
procBody: (
switches: ParsedOptions<P, TextPiece>,
argv: TextPiece[]
) => ProcResult
): ProcResult;
export function getOptRaw<P extends Options>(
argv: TextPiece[],
options: P
): [ParsedOptions<P>, TextPiece[]];
): [ParsedOptions<P, TextPiece>, TextPiece[]];
export function getOptRaw<P extends Options>(
argv: TextPiece[],
options: P,
procBody?: (switches: ParsedOptions<P>, argv: TextPiece[]) => ProcResult
): [ParsedOptions<P>, TextPiece[]] | ProcResult {
procBody?: (
switches: ParsedOptions<P, TextPiece>,
argv: TextPiece[]
) => ProcResult
): [ParsedOptions<P, TextPiece>, TextPiece[]] | ProcResult {
const [flags, textPieces] = getOptCore(argv, options);
if (procBody) {
@ -73,14 +98,14 @@ const SWITCH_REGEX = /^-([^]*)/;
function getOptCore<P extends Options>(
argv: TextPiece[],
options: P
): [ParsedOptions<P>, TextPiece[]] {
): [ParsedOptions<P, TextPiece>, TextPiece[]] {
const [cmd, ...textPieces] = argv;
const positionalArgs: TextPiece[] = [];
const flags: ParsedOptions<P> = Object.fromEntries(
const flags: ParsedOptions<P, TextPiece> = Object.fromEntries(
Object.entries(options)
.filter(([name]) => name != "$min" && name != "$max")
.map(([name]) => [name, options[name] == 0 ? false : []])
) as ParsedOptions<P>;
) as ParsedOptions<P, TextPiece>;
// loop over args & extract switches
for (let i = 0; i < textPieces.length; i++) {
@ -96,14 +121,15 @@ function getOptCore<P extends Options>(
continue;
}
const switchName = switchMatch[1] as keyof ParsedOptions<P> & string;
const switchName = switchMatch[1] as keyof ParsedOptions<P, TextPiece> &
string;
if (!(switchName in flags)) {
return [
{
error: `${AsText(
cmd
)}: -${switchName} is not a switch this command knows about`,
} as ParsedOptions<P>,
} as ParsedOptions<P, TextPiece>,
[],
];
}
@ -115,13 +141,13 @@ function getOptCore<P extends Options>(
return [
{
error: `${AsText(cmd)}: Not enough arguments to -${switchName}`,
} as ParsedOptions<P>,
} as ParsedOptions<P, TextPiece>,
[],
];
} else {
const takeUntil = i + switchArgCount;
for (i++; i <= takeUntil; i++) {
(flags[switchName] as string[]).push(AsText(textPieces[i]));
(flags[switchName] as TextPiece[]).push(textPieces[i]);
}
}
}
@ -131,7 +157,7 @@ function getOptCore<P extends Options>(
return [
{
error: `${AsText(cmd)}: Not enough arguments`,
} as ParsedOptions<P>,
} as ParsedOptions<P, TextPiece>,
[],
];
}
@ -139,7 +165,7 @@ function getOptCore<P extends Options>(
return [
{
error: `${AsText(cmd)}: Too many arguments`,
} as ParsedOptions<P>,
} as ParsedOptions<P, TextPiece>,
[],
];
}