diff --git a/src/lib/options.test.ts b/src/lib/options.test.ts new file mode 100644 index 0000000..77c08cd --- /dev/null +++ b/src/lib/options.test.ts @@ -0,0 +1,28 @@ +import { parse } from "../parser"; +import { Script, TextPiece } from "../words"; +import { getOpt, Options } from "./options"; + +describe("getOpt", () => { + const expectOpts =
(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"]));
+});
diff --git a/src/lib/options.ts b/src/lib/options.ts
index 3568f9d..7843fc3 100644
--- a/src/lib/options.ts
+++ b/src/lib/options.ts
@@ -1,11 +1,11 @@
-import { AsText, TextPiece } from '../words';
+import { AsText, TextPiece } from "../words";
-type SwitchPattern = Record = {
- [K in keyof P]: K extends "min" | "max"
+type ParsedOptions = {
+ [K in keyof P]: K extends "$min" | "$max"
? never
: P[K] extends 0
? boolean
@@ -14,20 +14,39 @@ type SwitchOutput = {
error?: string;
};
-// TODO: tests and error handling
-export function getOpt (
+export function getOpt (
argv: TextPiece[],
- switches: P
-): [SwitchOutput , ...string[]] {
- const [flags, textPieces] = getOptRaw(argv, switches);
+ options: P
+): [ParsedOptions , ...string[]] {
+ const [flags, textPieces] = getOptRaw(argv, options);
return [flags, ...textPieces.map(AsText)];
}
-export function getOptRaw (
+export function getOptRaw (
argv: TextPiece[],
- switches: P
-): [SwitchOutput , TextPiece[]] {
- const [, ...words] = argv;
- // TODO: handle min/max
- return [{} as SwitchOutput , words];
+ options: P
+): [ParsedOptions , TextPiece[]] {
+ const [cmd, ...words] = argv;
+ const result: ParsedOptions = 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 ,
+ [],
+ ];
+ }
+ if (options.$max !== undefined && options.$max < words.length) {
+ return [
+ { error: `${AsText(cmd)}: Too many arguments` } as ParsedOptions ,
+ [],
+ ];
+ }
+
+ return [result, words];
}