have getOptsRaw preserve TextPieces instead of folding into raw strings
This commit is contained in:
parent
c8fc4678fc
commit
8cba197ffd
1 changed files with 49 additions and 23 deletions
|
@ -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>,
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue