aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth@simponic.xyz>2024-08-01 09:15:33 -0700
committerElizabeth Hunt <elizabeth@simponic.xyz>2024-08-01 09:15:33 -0700
commit5dbd16878546886cae5b56b67de6185bfbae0d07 (patch)
tree8dd29c83d8f56b254d964ec040be9bcea0bc108b /src
parentad74ff999589e0df2b60ba6e94362ed5215af312 (diff)
downloadmon.hatecomputers.club-5dbd16878546886cae5b56b67de6185bfbae0d07.tar.gz
mon.hatecomputers.club-5dbd16878546886cae5b56b67de6185bfbae0d07.zip
add arg parser
Diffstat (limited to 'src')
-rw-r--r--src/args.ts97
-rw-r--r--src/canary/index.ts3
-rw-r--r--src/canary/test.ts (renamed from src/canary/testable.ts)10
-rw-r--r--src/config.ts4
-rw-r--r--src/index.ts18
-rw-r--r--src/util/duration.ts44
6 files changed, 142 insertions, 34 deletions
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<string>;
+ readonly testType: O.Option<TestType>;
+}
+
+interface ArgsBuilder {
+ readonly testsFile: O.Option<string>;
+ readonly testName: O.Option<string>;
+ readonly testType: O.Option<string>;
}
-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<string, ArgsBuilderField> = {
+ "--tests-file": withTestsFile,
+ "--test-name": withTestName,
+ "--test-type": withTestType,
+};
+
+const buildArgs = (builder: ArgsBuilder): E.Either<string, Args> => {
+ 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<string, Args> => {
+ 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,
+ );
};
diff --git a/src/canary/index.ts b/src/canary/index.ts
index 1d42dec..055a256 100644
--- a/src/canary/index.ts
+++ b/src/canary/index.ts
@@ -1,2 +1,3 @@
export * from "./job";
-export * from "./testable";
+export * from "./test";
+export * from "./email";
diff --git a/src/canary/testable.ts b/src/canary/test.ts
index d79aa99..c03fb30 100644
--- a/src/canary/testable.ts
+++ b/src/canary/test.ts
@@ -1,4 +1,5 @@
-import type { TaskEither } from "fp-ts/lib/TaskEither";
+import * as TE from "fp-ts/lib/TaskEither";
+import * as O from "fp-ts/lib/Option";
import type { Job } from "./job";
import type { D } from "../util";
@@ -21,4 +22,9 @@ export interface Test {
schedule: Schedule;
}
-export type Testable<T extends Job> = (job: T) => TaskEither<Error, boolean>;
+export type Testable<T extends Job> = (job: T) => TE.TaskEither<Error, boolean>;
+
+export const parseTestType = (testType: string): O.Option<TestType> =>
+ Object.values(TestType).includes(testType as TestType)
+ ? O.some(testType as TestType)
+ : O.none;
diff --git a/src/config.ts b/src/config.ts
index 2da569f..d4527d9 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,11 +1,13 @@
import * as IO from "fp-ts/IO";
import type { Publisher } from "./publisher";
import { readFileSync } from "fs";
+import type { Test } from "./canary";
export interface Config {
result_publishers: Publisher[];
dns: string[];
- timeout: string;
+ http_timeout: string;
+ tests: Test[];
}
export const readConfig =
diff --git a/src/index.ts b/src/index.ts
index 95fd41f..2b3e95e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,16 @@
-import * as IO from "fp-ts/IO";
-import { readFileSync } from "fs";
-
-const main: IO.IO<void> = ConsoleLogger.log("Hello, world!");
+import * as TE from "fp-ts/lib/TaskEither";
+import { pipe } from "fp-ts/lib/function";
+import { toError } from "fp-ts/lib/Either";
+import { readConfig } from "./config";
+import { parseArgs } from "./args";
+const main: TE.TaskEither<Error, void> = pipe(
+ TE.fromEither(parseArgs(Bun.argv)),
+ TE.bindTo("args"),
+ TE.bind("config", ({ args }) => TE.fromIO(readConfig(args.testsFile))),
+ TE.fold(
+ (e) => TE.left(toError(e)),
+ () => TE.right(undefined),
+ ),
+);
main();
diff --git a/src/util/duration.ts b/src/util/duration.ts
index 9c10375..3d1a44c 100644
--- a/src/util/duration.ts
+++ b/src/util/duration.ts
@@ -1,6 +1,6 @@
import { flow, pipe } from "fp-ts/function";
-import * as E from "fp-ts/Either";
-import * as S from "fp-ts/String";
+import * as E from "fp-ts/lib/Either";
+import * as S from "fp-ts/lib/string";
import * as O from "fp-ts/lib/Option";
import * as R from "fp-ts/lib/ReadonlyArray";
@@ -60,30 +60,30 @@ export const createDurationBuilder = (): DurationBuilder => ({
hours: 0,
});
-export const withMillis =
- (millis: number) =>
- (builder: DurationBuilder): DurationBuilder => ({
+export type DurationBuilderField<T> = (
+ arg: T,
+) => (builder: DurationBuilder) => DurationBuilder;
+
+export const withMillis: DurationBuilderField<number> =
+ (millis) => (builder) => ({
...builder,
millis,
});
-export const withSeconds =
- (seconds: number) =>
- (builder: DurationBuilder): DurationBuilder => ({
+export const withSeconds: DurationBuilderField<number> =
+ (seconds) => (builder) => ({
...builder,
seconds,
});
-export const withMinutes =
- (minutes: number) =>
- (builder: DurationBuilder): DurationBuilder => ({
+export const withMinutes: DurationBuilderField<number> =
+ (minutes) => (builder) => ({
...builder,
minutes,
});
-export const withHours =
- (hours: number) =>
- (builder: DurationBuilder): DurationBuilder => ({
+export const withHours: DurationBuilderField<number> =
+ (hours) => (builder) => ({
...builder,
hours,
});
@@ -99,7 +99,7 @@ export const parse = (duration: string): E.Either<string, Duration> => {
duration,
S.split(" "),
R.map(S.trim),
- R.filter((part) => !S.isEmpty(part))
+ R.filter((part) => !S.isEmpty(part)),
);
const valueUnitPairs = pipe(
@@ -120,9 +120,9 @@ export const parse = (duration: string): E.Either<string, Duration> => {
E.map(
flow(
R.filter(O.isSome),
- R.map(({ value }) => value)
- )
- )
+ R.map(({ value }) => value),
+ ),
+ ),
);
return pipe(
@@ -146,10 +146,10 @@ export const parse = (duration: string): E.Either<string, Duration> => {
default:
return E.left(`unknown unit: ${unit}`);
}
- })
- )
- )
+ }),
+ ),
+ ),
),
- E.map(build)
+ E.map(build),
);
};