122 lines
3.9 KiB
TypeScript
122 lines
3.9 KiB
TypeScript
export interface CLIConfig {
|
|
// path to config file
|
|
config_filepath: string,
|
|
git_client: "gitea" | "github",
|
|
log_file: string | undefined,
|
|
// verbose logging
|
|
verbose: boolean,
|
|
// doesn't log to stdout/stderr (still logs to file if --log-file)
|
|
quiet: boolean
|
|
}
|
|
|
|
export const defaults: CLIConfig = {
|
|
config_filepath: "config.toml",
|
|
git_client: "gitea",
|
|
log_file: undefined,
|
|
verbose: false,
|
|
quiet: false
|
|
}
|
|
|
|
export class EmptyArgumentError extends Error {}
|
|
export class NoValueExpected extends Error {}
|
|
export class InvalidValue extends Error {}
|
|
|
|
|
|
/**
|
|
* Searches for first argument from flags options
|
|
* Valid values don't start with dashes
|
|
* @example Flag + Valid value
|
|
* getFlagValue(["--config", "config.toml"], ["--config", "-c"])
|
|
* // result: "config.toml"
|
|
* @example Flag + No value
|
|
* getFlagValue(["-c", "--verbose"], ["--config", "-c"])
|
|
* // result: null
|
|
* @example No Flag
|
|
* getFlagValue(["config.toml"], ["--config", "-c"])
|
|
* // result: undefined
|
|
*
|
|
* @param args An array of all command-line arguments
|
|
* @param flags An array of flag strings to search for
|
|
* @return {string}: When a flag is found and has a valid value
|
|
* @return {null}: When a flag is found but has no valid value
|
|
* @return {undefined}: When no flag is found in the arguments
|
|
*
|
|
*/
|
|
export function getFlagValue(args: string[], flags: string[]): string | null | undefined {
|
|
const index = args.findIndex(arg => flags.includes(arg))
|
|
if (index == -1) return undefined
|
|
if (index == args.length - 1) return null
|
|
|
|
const next = args[index + 1]!
|
|
if (next.startsWith("-")) {
|
|
return null
|
|
}
|
|
return next
|
|
}
|
|
|
|
/**
|
|
* Used for when the flag is optional, but a value is required if the flag appears.
|
|
* @throws EmptyArgumentError when the flag is present but has no value.
|
|
* @returns string | undefined — string when present with value, undefined when flag not present
|
|
*/
|
|
export function optionalStringFlag(args: string[], flags: string[]): string | undefined {
|
|
const value = getFlagValue(args, flags)
|
|
if (value === null) {
|
|
const errorMessage = `${flags.join(", ")} flag requires a value`
|
|
throw new EmptyArgumentError(errorMessage)
|
|
}
|
|
return value
|
|
}
|
|
|
|
export function optionalStringLiteralFlag<Option extends string>(
|
|
args: string[], flags: string[], options: Option[]
|
|
): Option | undefined {
|
|
const value = getFlagValue(args, flags)
|
|
if (value === null) {
|
|
const errorMessage = `${flags.join(", ")} flag requires a value`
|
|
throw new EmptyArgumentError(errorMessage)
|
|
}
|
|
|
|
if (value && !(options as string[]).includes(value)) {
|
|
const errorMessage = `${flags.join(", ")} flag requires one of these options ${options.join(", ")}`
|
|
throw new InvalidValue(errorMessage)
|
|
}
|
|
|
|
return value as (Option | undefined)
|
|
}
|
|
|
|
/**
|
|
* ...
|
|
*/
|
|
export function optionalBooleanFlag(args: string[], flags: string[]): boolean {
|
|
const value = getFlagValue(args, flags)
|
|
if (typeof value === "string") {
|
|
throw new NoValueExpected()
|
|
}
|
|
|
|
return value === null;
|
|
}
|
|
|
|
/**
|
|
* Parse command line arguments from a string array (process.argv)
|
|
* @param args Command line arguments
|
|
* @return {CLIConfig} Parsed flags
|
|
*/
|
|
export function parseArgs(args: string[]): CLIConfig {
|
|
const config = defaults
|
|
|
|
const configValue = optionalStringFlag(args, ["--config", "-c"])
|
|
if (configValue) config.config_filepath = configValue
|
|
|
|
const gitClientValue = optionalStringLiteralFlag(args, ["--git-client", "-gc"], ["gitea", "github"])
|
|
if (gitClientValue) config.git_client = gitClientValue
|
|
const logFileValue = optionalStringFlag(args, ["--log-file", "-lf"])
|
|
if (logFileValue) config.log_file = logFileValue
|
|
const verboseValue = optionalBooleanFlag(args, ["--verbose"])
|
|
if (verboseValue) config.verbose = verboseValue
|
|
const quietValue = optionalBooleanFlag(args, ["--quiet"])
|
|
if (quietValue) config.quiet = quietValue
|
|
|
|
return config
|
|
}
|