From 5dbd16878546886cae5b56b67de6185bfbae0d07 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Thu, 1 Aug 2024 09:15:33 -0700 Subject: add arg parser --- src/args.ts | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 4 deletions(-) (limited to 'src/args.ts') diff --git a/src/args.ts b/src/args.ts index 31fa2ee..d233c18 100644 --- a/src/args.ts +++ b/src/args.ts @@ -1,9 +1,98 @@ +import * as E from "fp-ts/lib/Either"; +import * as O from "fp-ts/lib/Option"; +import * as R from "fp-ts/lib/ReadonlyArray"; +import { pipe } from "fp-ts/lib/function"; +import { parseTestType, type TestType } from "./canary"; + export interface Args { - testFile: string; + readonly testsFile: string; + readonly testName: O.Option; + readonly testType: O.Option; +} + +interface ArgsBuilder { + readonly testsFile: O.Option; + readonly testName: O.Option; + readonly testType: O.Option; } -export const parseArgs = (argv: string[]): Args => { - const useful = argv.slice(2); // skip bun path and script path +type ArgsBuilderField = (arg: string) => (builder: ArgsBuilder) => ArgsBuilder; + +const createArgsBuilder = (): ArgsBuilder => ({ + testsFile: O.none, + testName: O.none, + testType: O.none, +}); + +const withTestsFile: ArgsBuilderField = (testsFile) => (builder) => ({ + ...builder, + testsFile: O.some(testsFile), +}); + +const withTestName: ArgsBuilderField = (testName) => (builder) => ({ + ...builder, + testName: O.some(testName), +}); + +const withTestType: ArgsBuilderField = (testType) => (builder) => ({ + ...builder, + testType: O.some(testType), +}); + +const flagBuilders: Record = { + "--tests-file": withTestsFile, + "--test-name": withTestName, + "--test-type": withTestType, +}; + +const buildArgs = (builder: ArgsBuilder): E.Either => { + if (O.isNone(builder.testsFile)) { + return E.left("please specify a test file"); + } + + const testType = pipe(builder.testType, O.flatMap(parseTestType)); + if (O.isSome(builder.testType) && !O.isSome(testType)) { + return E.left("bad test type " + builder.testType.value); + } + + return E.right({ + testsFile: builder.testsFile.value, + testName: builder.testName, + testType, + }); +}; + +const isArg = (arg: string) => arg.startsWith("--") && arg in flagBuilders; + +export const parseArgs = (argv: string[]): E.Either => { + if (argv.length < 2) return E.left("bad argv"); + + const useful = argv.slice(2); + const argApplicators = pipe( + useful, + R.mapWithIndex((i, arg) => (isArg(arg) ? O.some({ arg, i }) : O.none)), + R.compact, + R.map(({ arg, i }) => + pipe( + O.fromNullable(flagBuilders[arg]), + O.bindTo("argApplicator"), + O.bind("val", () => + pipe( + O.fromNullable(useful.at(i + 1)), + O.flatMap((argValue) => + isArg(argValue) ? O.none : O.some(argValue), + ), + ), + ), + O.map(({ val, argApplicator }) => argApplicator(val)), + ), + ), + ); - const flags = useful.map((x, i) => x.startsWith("--") && i); + return pipe( + argApplicators, + R.compact, + R.reduce(createArgsBuilder(), (builder, applyArgTo) => applyArgTo(builder)), + buildArgs, + ); }; -- cgit v1.3