Start getOpt tests, impl min/max args
This commit is contained in:
parent
e2f00d3e5b
commit
594d81b745
2 changed files with 64 additions and 17 deletions
28
src/lib/options.test.ts
Normal file
28
src/lib/options.test.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { parse } from "../parser";
|
||||
import { Script, TextPiece } from "../words";
|
||||
import { getOpt, Options } from "./options";
|
||||
|
||||
describe("getOpt", () => {
|
||||
const expectOpts = <P extends Options>(command: string, opts: P) => {
|
||||
const [ok, script] = parse(command);
|
||||
expect(ok).toBeTruthy();
|
||||
return expect(getOpt((script as Script)[0] as TextPiece[], opts));
|
||||
};
|
||||
|
||||
it("parses empty arguments", () => expectOpts("cmd", {}).toEqual([{}]));
|
||||
it("parses single positional arguments", () =>
|
||||
expectOpts("cmd apple", {}).toEqual([{}, "apple"]));
|
||||
it("parses multiple positional arguments", () =>
|
||||
expectOpts("cmd apple banana", {}).toEqual([{}, "apple", "banana"]));
|
||||
|
||||
it("enforces minimum # of arguments", () =>
|
||||
expectOpts("cmd", { $min: 1 }).toEqual([
|
||||
{ error: "cmd: Not enough arguments" },
|
||||
]));
|
||||
it("enforces maximum # of arguments", () =>
|
||||
expectOpts("cmd apple banana", { $max: 1 }).toEqual([
|
||||
{ error: "cmd: Too many arguments" },
|
||||
]));
|
||||
it("allows # of arguments in-spec", () =>
|
||||
expectOpts("cmd apple", { $min: 1, $max: 1 }).toEqual([{}, "apple"]));
|
||||
});
|
|
@ -1,11 +1,11 @@
|
|||
import { AsText, TextPiece } from '../words';
|
||||
import { AsText, TextPiece } from "../words";
|
||||
|
||||
type SwitchPattern = Record<string, number> & {
|
||||
min?: number;
|
||||
max?: number;
|
||||
export type Options = Record<string, number> & {
|
||||
$min?: number;
|
||||
$max?: number;
|
||||
};
|
||||
type SwitchOutput<P extends SwitchPattern> = {
|
||||
[K in keyof P]: K extends "min" | "max"
|
||||
type ParsedOptions<P extends Options> = {
|
||||
[K in keyof P]: K extends "$min" | "$max"
|
||||
? never
|
||||
: P[K] extends 0
|
||||
? boolean
|
||||
|
@ -14,20 +14,39 @@ type SwitchOutput<P extends SwitchPattern> = {
|
|||
error?: string;
|
||||
};
|
||||
|
||||
// TODO: tests and error handling
|
||||
export function getOpt<P extends SwitchPattern>(
|
||||
export function getOpt<P extends Options>(
|
||||
argv: TextPiece[],
|
||||
switches: P
|
||||
): [SwitchOutput<P>, ...string[]] {
|
||||
const [flags, textPieces] = getOptRaw(argv, switches);
|
||||
options: P
|
||||
): [ParsedOptions<P>, ...string[]] {
|
||||
const [flags, textPieces] = getOptRaw(argv, options);
|
||||
return [flags, ...textPieces.map(AsText)];
|
||||
}
|
||||
|
||||
export function getOptRaw<P extends SwitchPattern>(
|
||||
export function getOptRaw<P extends Options>(
|
||||
argv: TextPiece[],
|
||||
switches: P
|
||||
): [SwitchOutput<P>, TextPiece[]] {
|
||||
const [, ...words] = argv;
|
||||
// TODO: handle min/max
|
||||
return [{} as SwitchOutput<P>, words];
|
||||
options: P
|
||||
): [ParsedOptions<P>, TextPiece[]] {
|
||||
const [cmd, ...words] = argv;
|
||||
const result: ParsedOptions<P> = Object.fromEntries(
|
||||
Object.entries(options)
|
||||
.filter(([name]) => name != "$min" && name != "$max")
|
||||
.map(([name]) => [])
|
||||
);
|
||||
|
||||
// TODO: parse switches
|
||||
|
||||
if (options.$min !== undefined && options.$min > words.length) {
|
||||
return [
|
||||
{ error: `${AsText(cmd)}: Not enough arguments` } as ParsedOptions<P>,
|
||||
[],
|
||||
];
|
||||
}
|
||||
if (options.$max !== undefined && options.$max < words.length) {
|
||||
return [
|
||||
{ error: `${AsText(cmd)}: Too many arguments` } as ParsedOptions<P>,
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
return [result, words];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue