feat(parse): add loadConfig function to load config files

- Add `loadConfig` function to load config files using `cosmiconfig`
- Update `parseOptions` function to handle `ZodObject` schema
- Add `TupleOfLength` type helper for tuple types
- Export `parseOptions` and `TupleOfLength` for external use
This commit is contained in:
Fanis Tharropoulos 2025-01-30 18:06:23 +02:00
parent 15f885a277
commit c2f628a712
No known key found for this signature in database

View File

@ -1,11 +1,14 @@
import type { ErrorWithMessage } from "@/utils/error";
import type { ResultAsync } from "neverthrow";
import type { Ora } from "ora";
import type { z, ZodType } from "zod";
import type { z, ZodObject, ZodRawShape, ZodType } from "zod";
import { errAsync, okAsync } from "neverthrow";
import { cosmiconfig } from "cosmiconfig";
import { errAsync, okAsync, ResultAsync } from "neverthrow";
function parseOptions<T extends ZodType>(
import { toErrorWithMessage } from "@/utils/error";
import { logger } from "@/utils/logger";
export function parseOptions<T extends ZodType>(
options: Record<string, unknown>,
schema: T,
spinner: Ora,
@ -24,4 +27,43 @@ function parseOptions<T extends ZodType>(
return okAsync(parsedOpts.data as z.infer<T>);
}
export { parseOptions };
export type TupleOfLength<T, L extends number> = number extends L ? T[] : TupleOfLengthHelper<T, L, []>;
type TupleOfLengthHelper<T, L extends number, R extends unknown[]> =
R["length"] extends L ? R : TupleOfLengthHelper<T, L, [T, ...R]>;
export function loadConfig<T extends ZodRawShape>({
configPath,
schema,
defaultSchema,
spinner,
}: {
configPath?: string;
schema: ZodObject<T>;
defaultSchema: z.infer<typeof schema>;
spinner: Ora;
}): ResultAsync<z.infer<typeof schema>, ErrorWithMessage> {
const explorer = cosmiconfig("typesense-benchmark", {
searchPlaces: [
"package.json",
".typesense-benchmarkrc",
".typesense-benchmarkrc.json",
".typesense-benchmarkrc.yaml",
".typesense-benchmarkrc.yml",
".typesense-benchmarkrc.js",
"typesense-benchmark.config.js",
],
});
return ResultAsync.fromPromise(
configPath ? explorer.load(configPath) : explorer.search(),
toErrorWithMessage,
).andThen((result) => {
if (!result) {
logger.info("No config file found. Using default configuration.");
return okAsync(defaultSchema);
}
return parseOptions(result.config as Record<string, unknown>, schema, spinner);
});
}