@stricli/core
Version:
Build complex CLIs with type safety and no dependencies
1,294 lines (1,274 loc) • 56 kB
TypeScript
/**
* Minimal expected interface for an output stream; used to narrow the types of NodeJS's stdout/stderr.
*/
interface Writable {
/**
* Write the provided string to this stream.
*/
readonly write: (str: string) => void;
/**
* Determine the available color depth of the underlying stream.
* Environment variables are also provided to control or suppress color output.
*/
readonly getColorDepth?: (env?: Readonly<Partial<Record<string, string>>>) => number;
}
interface WritableStreams {
/**
* Contains a writable stream connected to stdout (fd 1).
*/
readonly stdout: Writable;
/**
* Contains a writable stream connected to stderr (fd 2).
*/
readonly stderr: Writable;
}
/**
* Command-level context that provides necessary process information and is available to all command runs.
* This type should be extended to include context specific to your command implementations.
*/
interface CommandContext {
readonly process: WritableStreams;
}
/**
* Simple interface that mirrors NodeJS.Process but only requires the minimum API required by Stricli.
*/
interface StricliProcess extends WritableStreams {
/**
* Object that stores all available environment variables.
*
* @see {@link EnvironmentVariableName} for variable names used by Stricli.
*/
readonly env?: Readonly<Partial<Record<string, string>>>;
/**
* A number which will be the process exit code.
*/
exitCode?: number | string;
}
/**
* Environment variable names used by Stricli.
*
* - `STRICLI_SKIP_VERSION_CHECK` - If specified and non-0, skips the latest version check.
* - `STRICLI_NO_COLOR` - If specified and non-0, disables ANSI terminal coloring.
*/
type EnvironmentVariableName = "STRICLI_SKIP_VERSION_CHECK" | "STRICLI_NO_COLOR";
/**
* Top-level context that provides necessary process information to Stricli internals.
*/
interface ApplicationContext extends CommandContext {
readonly process: StricliProcess;
/**
* A string that represents the current user's locale.
* It is passed to {@link LocalizationConfiguration.loadText} which provides the text for Stricli to use
* when formatting built-in output.
*/
readonly locale?: string;
}
/**
* Contextual information about the current command.
*/
interface CommandInfo {
/**
* Prefix of command line inputs used to navigate to the current command.
*/
readonly prefix: readonly string[];
}
/**
* Function to build a generic CommandContext given the current command information.
*/
type StricliCommandContextBuilder<CONTEXT extends CommandContext> = (info: CommandInfo) => CONTEXT | Promise<CONTEXT>;
/**
* Dynamic context for command that contains either the generic CommandContext or simply the more limited
* ApplicationContext and a method that builds a specific instance of the generic CommandContext.
*/
type StricliDynamicCommandContext<CONTEXT extends CommandContext> = ApplicationContext & (CONTEXT | {
/**
* Method to build specific CommandContext instance for the current command.
*/
readonly forCommand: StricliCommandContextBuilder<CONTEXT>;
});
/**
* Keyword strings used to build help text.
*/
interface DocumentationKeywords {
/**
* Keyword to be included when flags or arguments have a default value.
*
* Defaults to `"default"`.
*/
readonly default: string;
}
/**
* Section header strings used to build help text.
*/
interface DocumentationHeaders {
/**
* Header for help text section that lists all usage lines.
*
* Defaults to `"USAGE"`.
*/
readonly usage: string;
/**
* Header for help text section that lists all aliases for the route.
*
* Defaults to `"ALIASES"`.
*/
readonly aliases: string;
/**
* Header for help text section that lists all commands in a route map.
*
* Defaults to `"COMMANDS"`.
*/
readonly commands: string;
/**
* Header for help text section that lists all flags accepted by the route.
*
* Defaults to `"FLAGS"`.
*/
readonly flags: string;
/**
* Header for help text section that lists all arguments accepted by the command.
*
* Defaults to `"ARGUMENTS"`.
*/
readonly arguments: string;
}
/**
* Short documentation brief strings used to build help text.
*/
interface DocumentationBriefs {
/**
* Documentation brief to be included alongside `--help` flag in help text.
*
* Defaults to `"Print help information and exit"`.
*/
readonly help: string;
/**
* Documentation brief to be included alongside `--helpAll` flag in help text.
*
* Defaults to `"Print help information (including hidden commands/flags) and exit"`.
*/
readonly helpAll: string;
/**
* Documentation brief to be included alongside `--version` flag in help text.
*
* Defaults to `"Print version information and exit"`.
*/
readonly version: string;
/**
* Documentation brief to be included alongside `--` escape sequence in help text.
* Only present when `scanner.allowArgumentEscapeSequence` is `true`.
*
* Defaults to `"All subsequent inputs should be interpreted as arguments"`.
*/
readonly argumentEscapeSequence: string;
}
/**
* Strings used to build help text.
*/
interface DocumentationText {
/**
* Keyword strings used to build help text.
*/
readonly keywords: DocumentationKeywords;
/**
* Section header strings used to build help text.
*/
readonly headers: DocumentationHeaders;
/**
* Short documentation brief strings used to build help text.
*/
readonly briefs: DocumentationBriefs;
}
/**
* Methods to customize the formatting of stderr messages handled by command execution.
*/
interface CommandErrorFormatting {
/**
* Formatted error message for the case where some exception was thrown while parsing the arguments.
*
* Exceptions intentionally thrown by this library while parsing arguments will extend from ArgumentScannerError.
* These subclasses provide additional context about the specific error.
* Use the {@link formatMessageForArgumentScannerError} helper to handle the different error types.
*
* If `ansiColor` is true, this string can use ANSI terminal codes.
* Codes may have already been applied so be aware you may have to reset to achieve the desired output.
*/
readonly exceptionWhileParsingArguments: (exc: unknown, ansiColor: boolean) => string;
/**
* Formatted error message for the case where some exception was thrown while loading the command function.
* This likely indicates an issue with the application itself or possibly the user's installation of the application.
*
* If `ansiColor` is true, this string can use ANSI terminal codes.
* Codes may have already been applied so be aware you may have to reset to achieve the desired output.
*/
readonly exceptionWhileLoadingCommandFunction: (exc: unknown, ansiColor: boolean) => string;
/**
* Formatted error message for the case where some exception was thrown while loading the context for the command run.
* This likely indicates an issue with the application itself or possibly the user's installation of the application.
*
* If `ansiColor` is true, this string can use ANSI terminal codes.
* Codes may have already been applied so be aware you may have to reset to achieve the desired output.
*/
readonly exceptionWhileLoadingCommandContext: (exc: unknown, ansiColor: boolean) => string;
/**
* Formatted error message for the case where some exception was thrown while running the command.
* Users are most likely to hit this case, so make sure that the error text provides practical, usable feedback.
*
* If `ansiColor` is true, this string can use ANSI terminal codes.
* Codes may have already been applied so be aware you may have to reset to achieve the desired output.
*/
readonly exceptionWhileRunningCommand: (exc: unknown, ansiColor: boolean) => string;
/**
* Formatted error message for the case where an Error was safely returned from the command.
* Users are most likely to hit this case, so make sure that the error text provides practical, usable feedback.
*
* If `ansiColor` is true, this string can use ANSI terminal codes.
* Codes may have already been applied so be aware you may have to reset to achieve the desired output.
*/
readonly commandErrorResult: (err: Error, ansiColor: boolean) => string;
}
/**
* Methods to customize the formatting of stderr messages handled by application execution.
*/
interface ApplicationErrorFormatting extends CommandErrorFormatting {
/**
* Formatted error message for the case where the supplied command line inputs do not resolve to a registered command.
* Supplied with arguments for the argument in question, and several possible corrections based on registered commands.
*
* If `ansiColor` is true, this string can use ANSI terminal codes.
* Codes may have already been applied so be aware you may have to reset to achieve the desired output.
*/
readonly noCommandRegisteredForInput: (args: {
readonly input: string;
readonly corrections: readonly string[];
readonly ansiColor: boolean;
}) => string;
/**
* Formatted error message for the case where the application does not provide text for the current requested locale.
* Should indicate that the default locale will be used instead.
*
* If `ansiColor` is true, this string can use ANSI terminal codes.
* Codes may have already been applied so be aware you may have to reset to achieve the desired output.
*/
readonly noTextAvailableForLocale: (args: {
readonly requestedLocale: string;
readonly defaultLocale: string;
readonly ansiColor: boolean;
}) => string;
}
/**
* The full set of static text and text-returning callbacks that are necessary for Stricli to write the necessary output.
*/
interface ApplicationText extends ApplicationErrorFormatting, DocumentationText {
/**
* Generate warning text to be written to stdout when the latest version is not installed.
* Should include brief instructions for how to update to that version.
*
* If `ansiColor` is true, this string can use ANSI terminal codes.
* Codes may have already been applied so be aware you may have to reset to achieve the desired output.
*/
readonly currentVersionIsNotLatest: (args: {
readonly currentVersion: string;
readonly latestVersion: string;
readonly upgradeCommand?: string;
readonly ansiColor: boolean;
}) => string;
}
/**
* Default English text implementation of {@link ApplicationText}.
*/
declare const text_en: ApplicationText;
/**
* The weights of various edit operations used when calculating the Damerau-Levenshtein distance.
*/
interface DamerauLevenshteinWeights {
/**
* The edit cost of inserting a character.
*
* Example: `"ab" -> "abc"`
*/
readonly insertion: number;
/**
* The edit cost of deleting a character.
*
* Example: `"abc" -> "ab"`
*/
readonly deletion: number;
/**
* The edit cost of replacing one character with another.
*
* Example: `"abc" -> "arc"`
*/
readonly substitution: number;
/**
* The edit cost of swapping two adjacent characters.
*
* Example: `"acb" -> "abc"`
*/
readonly transposition: number;
}
/**
* Customizable options for edit cost weights and threshold when calculating the Damerau-Levenshtein distance.
*/
interface DamerauLevenshteinOptions {
/**
* The upper threshold for edit distance when considering potential alternatives.
*/
readonly threshold: number;
/**
* The weights of various edit operations used when calculating the Damerau-Levenshtein distance.
*/
readonly weights: DamerauLevenshteinWeights;
}
/**
* Methods to determine application version information for `--version` flag or latest version check.
*/
type VersionInfo = ({
/**
* Statically known current version.
*/
readonly currentVersion: string;
} | {
/**
* Asynchonously determine the current version of this application.
*/
readonly getCurrentVersion: (this: ApplicationContext) => Promise<string>;
}) & {
/**
* Asynchonously determine the latest version of this application.
* If value is retrieved from cache, a change to the current version should invalidate that cache.
*/
readonly getLatestVersion?: (this: ApplicationContext, currentVersion: string) => Promise<string | undefined>;
/**
* Command to display to the end user that will upgrade this application.
* Passed to {@link ApplicationText.currentVersionIsNotLatest} to format/localize.
*/
readonly upgradeCommand?: string;
};
/**
* Case style configuration for parsing route and flag names from the command line.
* Each value has the following behavior:
* * `original` - Only accepts exact matches.
* * `allow-kebab-for-camel` - In addition to exact matches, allows kebab-case input for camelCase.
*/
type ScannerCaseStyle = "original" | "allow-kebab-for-camel";
/**
* Configuration for controlling the behavior of the command and argument scanners.
*/
interface ScannerConfiguration {
/**
* Case style configuration for scanning route and flag names.
*
* Default value is `original`
*/
readonly caseStyle: ScannerCaseStyle;
/**
* If true, when scanning inputs for a command will treat `--` as an escape sequence.
* This will force the scanner to treat all remaining inputs as arguments.
*
* Example for `false`
* ```shell
* $ cli --foo -- --bar
* # { foo: true, bar: true }, ["--"]
* ```
*
* Example for `true`
* ```shell
* $ cli --foo -- --bar
* # { foo: true }, ["--bar"]
* ```
*
* Default value is `false`
*/
readonly allowArgumentEscapeSequence: boolean;
/**
* Options used when calculating distance for alternative inputs ("did you mean?").
*
* Default value is equivalent to the empirically determined values used by git:
* ```json
* {
* "threshold": 7,
* "weights": {
* "insertion": 1,
* "deletion": 3,
* "substitution": 2,
* "transposition": 0
* }
* }
* ```
*/
readonly distanceOptions: DamerauLevenshteinOptions;
}
/**
* Case style configuration for displaying route and flag names in documentation text.
* Each value has the following behavior:
* * `original` - Displays the original names unchanged.
* * `convert-camel-to-kebab` - Converts all camelCase names to kebab-case in output. Only allowed if `scannerCaseStyle` is set to `allow-kebab-for-camel`.
*/
type DisplayCaseStyle = "original" | "convert-camel-to-kebab";
/**
* Configuration for controlling the content of the printed documentation.
*/
interface DocumentationConfiguration {
/**
* In addition to the `--help` flag, there is a `--helpAll`/`--help-all` flag that shows all documentation
* including entries for hidden commands/arguments.
* The `--helpAll` flag cannot be functionally disabled, but it is hidden when listing the built-in flags by default.
* Setting this option to `true` forces the output to always include this flag in the list of built-in flags.
*
* Defaults to `false`.
*/
readonly alwaysShowHelpAllFlag: boolean;
/**
* Controls whether or not to include alias of flags in the usage line.
* Only replaces name with alias when a single alias exists.
*
* Defaults to `false`.
*/
readonly useAliasInUsageLine: boolean;
/**
* Controls whether or not to include optional flags and positional parameters in the usage line.
* If enabled, all parameters that are optional at runtime (including parameters with defaults) will be hidden.
*
* Defaults to `false`.
*/
readonly onlyRequiredInUsageLine: boolean;
/**
* Case style configuration for displaying route and flag names.
* Cannot be `convert-camel-to-kebab` if {@link ScannerConfiguration.caseStyle} is `original`.
*
* Default value is derived from value for {@link ScannerConfiguration.caseStyle}:
* * Defaults to `original` for `original`.
* * Defaults to `convert-camel-to-kebab` for `allow-kebab-for-camel`.
*/
readonly caseStyle: DisplayCaseStyle;
/**
* By default, if the color depth of the stdout stream is greater than 4, ANSI terminal colors will be used.
* If this value is `true`, disables all ANSI terminal color output.
*
* Defaults to `false`.
*/
readonly disableAnsiColor: boolean;
}
/**
* Configuration for controlling the behavior of completion proposals.
*/
interface CompletionConfiguration {
/**
* This flag controls whether or not to include aliases of routes and flags.
*
* Defaults to match value of {@link DocumentationConfiguration.useAliasInUsageLine}.
*/
readonly includeAliases: boolean;
/**
* This flag controls whether or not to include hidden routes.
*
* Defaults to `false`.
*/
readonly includeHiddenRoutes: boolean;
}
/**
* Configuration for controlling the localization behavior.
*/
interface LocalizationConfiguration {
/**
* The default locale that should be used if the context does not have a locale.
*
* If unspecified, will default to `en`.
*/
readonly defaultLocale: string;
/**
* Mapping of locale to application text.
* Locale is optionally provided at runtime by the context.
*
* If unspecified, will return the default English implementation {@link text_en} for all "en" locales.
*/
readonly loadText: (locale: string) => ApplicationText | undefined;
}
/**
* Configuration for controlling the runtime behavior of the application.
*/
interface ApplicationConfiguration {
/**
* Unique name for this application.
* It should match the command that is used to run the application.
*/
readonly name: string;
/**
* If supplied, application will be aware of version info at runtime.
*
* Before every run, the application will fetch the latest version and warn if it differs from the current version.
* As well, a new flag `--version` (with alias `-v`) will be available on the base route, which will print the current
* version to stdout.
*/
readonly versionInfo?: VersionInfo;
/**
* If supplied, customizes the command/argument scanning behavior of the application.
*
* See documentation of inner types for default values.
*/
readonly scanner: ScannerConfiguration;
/**
* If supplied, customizes the formatting of documentation lines in help text.
*
* See documentation of inner types for default values.
*/
readonly documentation: DocumentationConfiguration;
/**
* If supplied, customizes command completion proposal behavior.
*
* See documentation of inner types for default values.
*/
readonly completion: CompletionConfiguration;
/**
* If supplied, customizes text localization.
*
* See documentation of inner types for default values.
*/
readonly localization: LocalizationConfiguration;
/**
* In the case where a command function throws some value unexpectedly or safely returns an Error,
* this function will translate that into an exit code.
*
* If unspecified, the exit code will default to 1 when a command function throws some value.
*/
readonly determineExitCode?: (exc: unknown) => number;
}
/**
* Partial configuration for application, see individual description for behavior when each value is unspecified.
*/
type PartialApplicationConfiguration = Pick<ApplicationConfiguration, "name" | "versionInfo" | "determineExitCode"> & {
[K in "scanner" | "documentation" | "completion" | "localization"]?: Partial<ApplicationConfiguration[K]>;
};
/**
* Contextual information used to format the usage text for a route/command.
*/
interface UsageFormattingArguments {
readonly prefix: readonly string[];
readonly config: DocumentationConfiguration;
readonly ansiColor: boolean;
}
interface BaseFlagParameter {
/**
* In-line documentation for this flag.
*/
readonly brief: string;
/**
* String that serves as placeholder for the value in the generated usage line. Defaults to "value".
*/
readonly placeholder?: string;
}
interface BaseBooleanFlagParameter extends BaseFlagParameter {
/**
* Indicates flag should be treated as a boolean.
*/
readonly kind: "boolean";
readonly optional?: boolean;
/**
* Default flag value if input is not provided at runtime.
*
* If no value is provided, boolean flags default to `false`.
*/
readonly default?: boolean;
}
type RequiredBooleanFlagParameter = BaseBooleanFlagParameter & {
/**
* Parameter is required and cannot be set as optional.
*/
readonly optional?: false;
} & ({
/**
* Parameter is required and cannot be set as hidden without a default value.
*/
readonly hidden?: false;
} | {
/**
* Default input value if one is not provided at runtime.
*/
readonly default: boolean;
/**
* Parameter should be hidden from all help text and proposed completions.
* Only available for runtime-optional parameters.
*/
readonly hidden: true;
});
interface OptionalBooleanFlagParameter extends BaseBooleanFlagParameter {
/**
* Parameter is optional and must be specified as such.
*/
readonly optional: true;
/**
* Parameter should be hidden from all help text and proposed completions.
* Only available for optional parameters.
*/
readonly hidden?: boolean;
/**
* Optional parameters should not have default values.
* This flag should be required if a value will always be provided.
*/
readonly default?: undefined;
}
type BooleanFlagParameter = RequiredBooleanFlagParameter | OptionalBooleanFlagParameter;
interface BaseCounterFlagParameter extends BaseFlagParameter {
/**
* Indicates flag should be treated as a counter.
*/
readonly kind: "counter";
readonly optional?: boolean;
}
interface RequiredCounterFlagParameter extends BaseCounterFlagParameter {
/**
* Parameter is required and cannot be set as optional.
*/
readonly optional?: false;
/**
* Parameter is required and cannot be set as hidden.
*/
readonly hidden?: false;
}
interface OptionalCounterFlagParameter extends BaseCounterFlagParameter {
/**
* Parameter is optional and must be specified as such.
*/
readonly optional: true;
/**
* Parameter should be hidden from all help text and proposed completions.
* Only available for optional parameters.
*/
readonly hidden?: boolean;
}
type CounterFlagParameter = RequiredCounterFlagParameter | OptionalCounterFlagParameter;
interface BaseEnumFlagParameter<T extends string> extends BaseFlagParameter {
/**
* Indicates flag should be treated as an enumeration of strings.
*/
readonly kind: "enum";
/**
* Array of all possible enumerations supported by this flag.
*/
readonly values: readonly T[];
/**
* Default input value if one is not provided at runtime.
*/
readonly default?: T;
readonly optional?: boolean;
readonly hidden?: boolean;
readonly variadic?: boolean;
}
interface RequiredEnumFlagParameter<T extends string> extends BaseEnumFlagParameter<T> {
/**
* Parameter is required and cannot be set as optional.
*/
readonly optional?: false;
/**
* Parameter is required and cannot be set as hidden.
*/
readonly hidden?: false;
/**
* Parameter does not extend array and cannot be set as variadic.
*/
readonly variadic?: false;
}
interface OptionalEnumFlagParameter<T extends string> extends BaseEnumFlagParameter<T> {
/**
* Parameter is optional and must be specified as such.
*/
readonly optional: true;
/**
* Parameter should be hidden from all help text and proposed completions.
* Only available for optional parameters.
*/
readonly hidden?: boolean;
/**
* Parameter does not extend array and cannot be set as variadic.
*/
readonly variadic?: false;
}
interface OptionalVariadicEnumFlagParameter<T extends string> extends BaseEnumFlagParameter<T> {
/**
* Default values are not supported for variadic parameters.
*/
readonly default?: undefined;
/**
* Optional variadic parameter will parse to an empty array if no arguments are found.
*/
readonly optional: true;
/**
* Parameter is required and cannot be set as hidden.
*/
readonly hidden?: false;
/**
* Parameter extends array and must be set as variadic.
*/
readonly variadic: true;
}
interface RequiredVariadicEnumFlagParameter<T extends string> extends BaseEnumFlagParameter<T> {
/**
* Default values are not supported for variadic parameters.
*/
readonly default?: undefined;
/**
* Parameter is required and cannot be set as optional.
* Expects at least one value to be satisfied.
*/
readonly optional?: false;
/**
* Parameter is required and cannot be set as hidden.
*/
readonly hidden?: false;
/**
* Parameter extends array and must be set as variadic.
*/
readonly variadic: true;
}
interface BaseParsedFlagParameter<T, CONTEXT extends CommandContext> extends ParsedParameter<T, CONTEXT>, BaseFlagParameter {
/**
* Indicates flag should be parsed with a specified input parser.
*/
readonly kind: "parsed";
/**
* Default input value if one is not provided at runtime.
*/
readonly default?: string;
/**
* If flag is specified with no corresponding input, infer an empty string `""` as the input.
*/
readonly inferEmpty?: boolean;
readonly optional?: boolean;
readonly variadic?: boolean;
readonly hidden?: boolean;
}
type RequiredParsedFlagParameter<T, CONTEXT extends CommandContext> = BaseParsedFlagParameter<T, CONTEXT> & {
/**
* Parameter is required and cannot be set as optional.
*/
readonly optional?: false;
/**
* Parameter does not extend array and cannot be set as variadic.
*/
readonly variadic?: false;
} & ({
/**
* Parameter is required and cannot be set as hidden without a default value.
*/
readonly hidden?: false;
} | {
/**
* Default input value if one is not provided at runtime.
*/
readonly default: string;
/**
* Parameter should be hidden from all help text and proposed completions.
* Only available for runtime-optional parameters.
*/
readonly hidden: true;
});
interface OptionalParsedFlagParameter<T, CONTEXT extends CommandContext> extends BaseParsedFlagParameter<T, CONTEXT> {
/**
* Parameter is optional and must be specified as such.
*/
readonly optional: true;
/**
* Optional parameters should not have default values.
* This flag should be required if a value will always be provided.
*/
readonly default?: undefined;
/**
* Parameter does not extend array and cannot be set as variadic.
*/
readonly variadic?: false;
/**
* Parameter should be hidden from all help text and proposed completions.
* Only available for runtime-optional parameters.
*/
readonly hidden?: boolean;
}
interface OptionalVariadicParsedFlagParameter<T, CONTEXT extends CommandContext> extends BaseParsedFlagParameter<T, CONTEXT> {
/**
* Variadic flags are always optional in that they will parse to an empty array if no arguments are found.
*/
readonly optional: true;
/**
* Parameter extends array and must be set as variadic.
*/
readonly variadic: true;
/**
* Default values are not supported for variadic parameters.
*/
readonly default?: undefined;
}
interface RequiredVariadicParsedFlagParameter<T, CONTEXT extends CommandContext> extends BaseParsedFlagParameter<T, CONTEXT> {
/**
* Parameter is required and cannot be set as optional.
* Expects at least one value to be satisfied.
*/
readonly optional?: false;
/**
* Parameter extends array and must be set as variadic.
*/
readonly variadic: true;
/**
* Default values are not supported for variadic parameters.
*/
readonly default?: undefined;
}
type TypedFlagParameter_Optional<T, CONTEXT extends CommandContext> = [T] extends [readonly (infer A)[]] ? [A] extends [string] ? OptionalVariadicParsedFlagParameter<A, CONTEXT> | OptionalParsedFlagParameter<T, CONTEXT> | OptionalVariadicEnumFlagParameter<A> : OptionalVariadicParsedFlagParameter<A, CONTEXT> | OptionalParsedFlagParameter<T, CONTEXT> : [T] extends [boolean] ? OptionalBooleanFlagParameter | OptionalParsedFlagParameter<boolean, CONTEXT> : [T] extends [number] ? OptionalCounterFlagParameter | OptionalParsedFlagParameter<number, CONTEXT> : string extends T ? OptionalParsedFlagParameter<string, CONTEXT> : [T] extends [string] ? OptionalEnumFlagParameter<T> | OptionalParsedFlagParameter<T, CONTEXT> : OptionalParsedFlagParameter<T, CONTEXT>;
type TypedFlagParameter_Required<T, CONTEXT extends CommandContext> = [T] extends [readonly (infer A)[]] ? [A] extends [string] ? RequiredVariadicParsedFlagParameter<A, CONTEXT> | RequiredParsedFlagParameter<readonly A[], CONTEXT> | RequiredVariadicEnumFlagParameter<A> : RequiredVariadicParsedFlagParameter<A, CONTEXT> | RequiredParsedFlagParameter<readonly A[], CONTEXT> : [T] extends [boolean] ? RequiredBooleanFlagParameter | RequiredParsedFlagParameter<boolean, CONTEXT> : [T] extends [number] ? RequiredCounterFlagParameter | RequiredParsedFlagParameter<number, CONTEXT> : string extends T ? RequiredParsedFlagParameter<string, CONTEXT> : [T] extends [string] ? RequiredEnumFlagParameter<T> | RequiredParsedFlagParameter<T, CONTEXT> : RequiredParsedFlagParameter<T, CONTEXT>;
/**
* Definition of a flag parameter that will eventually be parsed as a flag.
* Required properties may vary depending on the type argument `T`.
*/
type TypedFlagParameter<T, CONTEXT extends CommandContext = CommandContext> = undefined extends T ? TypedFlagParameter_Optional<NonNullable<T>, CONTEXT> : TypedFlagParameter_Required<T, CONTEXT>;
type FlagParameter<CONTEXT extends CommandContext> = BooleanFlagParameter | CounterFlagParameter | BaseEnumFlagParameter<string> | BaseParsedFlagParameter<unknown, CONTEXT>;
/**
* Definition of flags for each named parameter.
* Required properties may vary depending on the type argument `T`.
*/
type FlagParametersForType<T, CONTEXT extends CommandContext = CommandContext> = {
readonly [K in keyof T]: TypedFlagParameter<T[K], CONTEXT>;
};
/**
* Definition of flags for each named parameter.
* This is a separate version of {@link FlagParametersForType} without a type parameter and is primarily used internally
* and should only be used after the types are checked.
*/
type FlagParameters<CONTEXT extends CommandContext = CommandContext> = Record<string, FlagParameter<CONTEXT>>;
/**
* Generic function that synchronously or asynchronously parses a string to an arbitrary type.
*/
type InputParser<T, CONTEXT extends CommandContext = CommandContext> = (this: CONTEXT, input: string) => T | Promise<T>;
interface ParsedParameter<T, CONTEXT extends CommandContext> {
/**
* Function to parse an input string to the type of this parameter.
*/
readonly parse: InputParser<T, CONTEXT>;
/**
* Propose possible completions for a partial input string.
*/
readonly proposeCompletions?: (this: CONTEXT, partial: string) => readonly string[] | Promise<readonly string[]>;
}
type LowercaseLetter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z";
type UppercaseLetter = Capitalize<LowercaseLetter>;
type ReservedAlias = "h";
type AvailableAlias = Exclude<LowercaseLetter | UppercaseLetter, ReservedAlias>;
type Aliases<T> = Readonly<Partial<Record<AvailableAlias, T>>>;
type BaseFlags = Readonly<Record<string, unknown>>;
interface TypedCommandFlagParameters_<FLAGS extends BaseFlags, CONTEXT extends CommandContext> {
/**
* Typed definitions for all flag parameters.
*/
readonly flags: FlagParametersForType<FLAGS, CONTEXT>;
/**
* Object that aliases single characters to flag names.
*/
readonly aliases?: Aliases<keyof FLAGS & string>;
}
type TypedCommandFlagParameters<FLAGS extends BaseFlags, CONTEXT extends CommandContext> = Record<string, never> extends FLAGS ? Partial<TypedCommandFlagParameters_<FLAGS, CONTEXT>> : TypedCommandFlagParameters_<FLAGS, CONTEXT>;
interface TypedCommandPositionalParameters_<ARGS extends BaseArgs, CONTEXT extends CommandContext> {
/**
* Typed definitions for all positional parameters.
*/
readonly positional: TypedPositionalParameters<ARGS, CONTEXT>;
}
type TypedCommandPositionalParameters<ARGS extends BaseArgs, CONTEXT extends CommandContext> = [] extends ARGS ? Partial<TypedCommandPositionalParameters_<ARGS, CONTEXT>> : TypedCommandPositionalParameters_<ARGS, CONTEXT>;
/**
* Definitions for all parameters requested by the corresponding command.
*/
type TypedCommandParameters<FLAGS extends BaseFlags, ARGS extends BaseArgs, CONTEXT extends CommandContext> = TypedCommandFlagParameters<FLAGS, CONTEXT> & TypedCommandPositionalParameters<ARGS, CONTEXT>;
/**
* Definitions for all parameters requested by the corresponding command.
* This is a separate version of {@link TypedCommandParameters} without a type parameter and is primarily used
* internally and should only be used after the types are checked.
*/
interface CommandParameters {
readonly flags?: FlagParameters;
readonly aliases?: Aliases<string>;
readonly positional?: PositionalParameters;
}
interface BasePositionalParameter<T, CONTEXT extends CommandContext> extends ParsedParameter<T, CONTEXT> {
/**
* In-line documentation for this parameter.
*/
readonly brief: string;
/**
* String that serves as placeholder for the value in the generated usage line.
* Defaults to "argN" where N is the index of this parameter.
*/
readonly placeholder?: string;
/**
* Default input value if one is not provided at runtime.
*/
readonly default?: string;
readonly optional?: boolean;
}
interface RequiredPositionalParameter<T, CONTEXT extends CommandContext> extends BasePositionalParameter<T, CONTEXT> {
/**
* Parameter is required and cannot be set as optional.
*/
readonly optional?: false;
}
interface OptionalPositionalParameter<T, CONTEXT extends CommandContext> extends BasePositionalParameter<T, CONTEXT> {
/**
* Parameter is optional and must be specified as such.
*/
readonly optional: true;
}
/**
* Definition of a positional parameter that will eventually be parsed to an argument.
* Required properties may vary depending on the type argument `T`.
*/
type TypedPositionalParameter<T, CONTEXT extends CommandContext = CommandContext> = undefined extends T ? OptionalPositionalParameter<NonNullable<T>, CONTEXT> : RequiredPositionalParameter<T, CONTEXT>;
type PositionalParameter = BasePositionalParameter<unknown, CommandContext>;
interface PositionalParameterArray<T, CONTEXT extends CommandContext> {
readonly kind: "array";
readonly parameter: TypedPositionalParameter<T, CONTEXT>;
readonly minimum?: number;
readonly maximum?: number;
}
type PositionalParametersForTuple<T, CONTEXT extends CommandContext> = {
readonly [K in keyof T]: TypedPositionalParameter<T[K], CONTEXT>;
};
interface PositionalParameterTuple<T> {
readonly kind: "tuple";
readonly parameters: T;
}
type BaseArgs = readonly unknown[];
/**
* Definition of all positional parameters.
* Required properties may vary depending on the type argument `T`.
*/
type TypedPositionalParameters<T, CONTEXT extends CommandContext> = [T] extends [readonly (infer E)[]] ? number extends T["length"] ? PositionalParameterArray<E, CONTEXT> : PositionalParameterTuple<PositionalParametersForTuple<T, CONTEXT>> : PositionalParameterTuple<PositionalParametersForTuple<T, CONTEXT>>;
/**
* Definition of all positional parameters.
* This is a separate version of {@link TypedPositionalParameters} without a type parameter and is primarily used
* internally and should only be used after the types are checked.
*/
type PositionalParameters = PositionalParameterArray<unknown, CommandContext> | PositionalParameterTuple<readonly PositionalParameter[]>;
/**
* All command functions are required to have a general signature:
* ```ts
* (flags: {...}, ...args: [...]) => void | Promise<void>
* ```
* - `args` should be an array/tuple of any length or type.
* - `flags` should be an object with any key-value pairs.
*
* The specific types of `args` and `flags` are customizable to the individual use case
* and will be used to determine the structure of the positional arguments and flags.
*/
type CommandFunction<FLAGS extends BaseFlags, ARGS extends BaseArgs, CONTEXT extends CommandContext> = (this: CONTEXT, flags: FLAGS, ...args: ARGS) => void | Error | Promise<void | Error>;
/**
* A command module exposes the target function as the default export.
*/
interface CommandModule<FLAGS extends BaseFlags, ARGS extends BaseArgs, CONTEXT extends CommandContext> {
readonly default: CommandFunction<FLAGS, ARGS, CONTEXT>;
}
/**
* Asynchronously loads a function or a module containing a function to be executed by a command.
*/
type CommandFunctionLoader<FLAGS extends BaseFlags, ARGS extends BaseArgs, CONTEXT extends CommandContext> = () => Promise<CommandModule<FLAGS, ARGS, CONTEXT> | CommandFunction<FLAGS, ARGS, CONTEXT>>;
declare const CommandSymbol: unique symbol;
/**
* Parsed and validated command instance.
*/
interface Command<CONTEXT extends CommandContext> extends DocumentedTarget {
readonly kind: typeof CommandSymbol;
readonly loader: CommandFunctionLoader<BaseFlags, BaseArgs, CONTEXT>;
readonly parameters: CommandParameters;
readonly usesFlag: (flagName: string) => boolean;
}
declare const RouteMapSymbol: unique symbol;
interface RouteMapEntry<CONTEXT extends CommandContext> {
readonly name: Readonly<Record<DisplayCaseStyle, string>>;
readonly target: RoutingTarget<CONTEXT>;
readonly aliases: readonly string[];
readonly hidden: boolean;
}
/**
* Route map that stores multiple routes.
*/
interface RouteMap<CONTEXT extends CommandContext> extends DocumentedTarget {
readonly kind: typeof RouteMapSymbol;
readonly getRoutingTargetForInput: (input: string) => RoutingTarget<CONTEXT> | undefined;
readonly getDefaultCommand: () => Command<CONTEXT> | undefined;
readonly getOtherAliasesForInput: (input: string, caseStyle: ScannerCaseStyle) => Readonly<Record<DisplayCaseStyle, readonly string[]>>;
readonly getAllEntries: () => readonly RouteMapEntry<CONTEXT>[];
}
interface HelpFormattingArguments extends UsageFormattingArguments {
readonly text: DocumentationText;
readonly includeHelpAllFlag: boolean;
readonly includeVersionFlag: boolean;
readonly includeArgumentEscapeSequenceFlag: boolean;
readonly includeHidden: boolean;
readonly aliases?: readonly string[];
}
interface DocumentedTarget {
readonly brief: string;
readonly formatUsageLine: (args: UsageFormattingArguments) => string;
readonly formatHelp: (args: HelpFormattingArguments) => string;
}
type RoutingTarget<CONTEXT extends CommandContext> = Command<CONTEXT> | RouteMap<CONTEXT>;
interface RoutingTargetCompletion {
readonly kind: "routing-target:command" | "routing-target:route-map";
readonly completion: string;
readonly brief: string;
}
/**
* Interface for top-level command line application.
*/
interface Application<CONTEXT extends CommandContext> {
readonly root: RoutingTarget<CONTEXT>;
readonly config: ApplicationConfiguration;
readonly defaultText: ApplicationText;
}
/**
* Builds an application from a top-level route map and configuration.
*/
declare function buildApplication<CONTEXT extends CommandContext>(root: RouteMap<CONTEXT>, config: PartialApplicationConfiguration): Application<CONTEXT>;
/**
* Builds an application with a single, top-level command and configuration.
*/
declare function buildApplication<CONTEXT extends CommandContext>(command: Command<CONTEXT>, appConfig: PartialApplicationConfiguration): Application<CONTEXT>;
type DocumentedCommand = readonly [route: string, helpText: string];
/**
* Generate help text in the given locale for each command in this application.
* Return value is an array of tuples containing the route to that command and the help text.
*
* If no locale specified, uses the defaultLocale from the application configuration.
*/
declare function generateHelpTextForAllCommands({ root, defaultText, config }: Application<CommandContext>, locale?: string): readonly DocumentedCommand[];
declare class InternalError extends Error {
}
/**
* Abstract class that all internal argument scanner errors extend from.
*/
declare abstract class ArgumentScannerError extends InternalError {
private readonly _brand;
}
interface ArgumentScannerErrorType {
readonly AliasNotFoundError: AliasNotFoundError;
readonly ArgumentParseError: ArgumentParseError;
readonly EnumValidationError: EnumValidationError;
readonly FlagNotFoundError: FlagNotFoundError;
readonly InvalidNegatedFlagSyntaxError: InvalidNegatedFlagSyntaxError;
readonly UnexpectedFlagError: UnexpectedFlagError;
readonly UnexpectedPositionalError: UnexpectedPositionalError;
readonly UnsatisfiedFlagError: UnsatisfiedFlagError;
readonly UnsatisfiedPositionalError: UnsatisfiedPositionalError;
}
type ArgumentScannerErrorFormatter = {
readonly [T in keyof ArgumentScannerErrorType]: (error: ArgumentScannerErrorType[T]) => string;
};
/**
* Utility method for customizing message of argument scanner error
* @param error Error thrown by argument scanner
* @param formatter For all keys specified, controls message formatting for that specific subtype of error
*/
declare function formatMessageForArgumentScannerError(error: ArgumentScannerError, formatter: Partial<ArgumentScannerErrorFormatter>): string;
/**
* Thrown when input suggests an flag, but no flag with that name was found.
*/
declare class FlagNotFoundError extends ArgumentScannerError {
/**
* Command line input that triggered this error.
*/
readonly input: string;
/**
* Set of proposed suggestions that are similar to the input.
*/
readonly corrections: readonly string[];
/**
* Set if error was caused indirectly by an alias.
* This indicates that something is wrong with the command configuration itself.
*/
readonly aliasName?: string;
constructor(input: string, corrections: readonly string[], aliasName?: string);
}
/**
* Thrown when input suggests an alias, but no alias with that letter was found.
*/
declare class AliasNotFoundError extends ArgumentScannerError {
/**
* Command line input that triggered this error.
*/
readonly input: string;
constructor(input: string);
}
type Placeholder = string & {
readonly __Placeholder: unique symbol;
};
type ExternalFlagName = string & {
readonly __ExternalFlagName: unique symbol;
};
/**
* Thrown when underlying parameter parser throws an exception parsing some input.
*/
declare class ArgumentParseError extends ArgumentScannerError {
/**
* External name of flag or placeholder for positional argument that was parsing this input.
*/
readonly externalFlagNameOrPlaceholder: string;
/**
* Command line input that triggered this error.
*/
readonly input: string;
/**
* Raw exception thrown from parse function.
*/
readonly exception: unknown;
constructor(externalFlagNameOrPlaceholder: ExternalFlagName | Placeholder, input: string, exception: unknown);
}
/**
* Thrown when input fails to match the given values for an enum flag.
*/
declare class EnumValidationError extends ArgumentScannerError {
/**
* External name of flag that was parsing this input.
*/
readonly externalFlagName: string;
/**
* Command line input that triggered this error.
*/
readonly input: string;
/**
* All possible enum values.
*/
readonly values: readonly string[];
constructor(externalFlagName: ExternalFlagName, input: string, values: readonly string[], corrections: readonly string[]);
}
/**
* Thrown when flag was expecting input that was not provided.
*/
declare class UnsatisfiedFlagError extends ArgumentScannerError {
/**
* External name of flag that was active when this error was thrown.
*/
readonly externalFlagName: string;
/**
* External name of flag that interrupted the original flag.
*/
readonly nextFlagName?: string;
constructor(externalFlagName: ExternalFlagName, nextFlagName?: ExternalFlagName);
}
/**
* Thrown when too many positional arguments were encountered.
*/
declare class UnexpectedPositionalError extends ArgumentScannerError {
/**
* Expected (maximum) count of positional arguments.
*/
readonly expectedCount: number;
/**
* Command line input that triggered this error.
*/
readonly input: string;
constructor(expectedCount: number, input: string);
}
/**
* Thrown when positional parameter was expecting input that was not provided.
*/
declare class UnsatisfiedPositionalError extends ArgumentScannerError {
/**
* Placeholder for positional argument that was active when this error was thrown.
*/
readonly placeholder: string;
/**
* If specified, indicates the minimum number of arguments that are expected and the last argument count.
*/
readonly limit?: [minimum: number, count: number];
constructor(placeholder: Placeholder, limit?: [minimum: number, count: number]);
}
/**
* Thrown when a value is provided for a negated flag.
*/
declare class InvalidNegatedFlagSyntaxError extends ArgumentScannerError {
/**
* External name of flag that was active when this error was thrown.
*/
readonly externalFlagName: string;
/**
* Input text equivalent to right hand side of input
*/
readonly valueText: string;
constructor(externalFlagName: ExternalFlagName, valueText: string);
}
interface ArgumentCompletion {
readonly kind: "argument:flag" | "argument:value";
readonly completion: string;
readonly brief: string;
}
/**
* Thrown when single-valued flag encounters more than one value.
*/
declare class UnexpectedFlagError extends ArgumentScannerError {
/**
* External name of flag that was parsing this input.
*/
readonly externalFlagName: string;
/**
* Command line input that was previously encountered by this flag.
*/
readonly previousInput: string;
/**
* Command line input that triggered this error.
*/
readonly input: string;
constructor(externalFlagName: ExternalFlagName, previousInput: string, input: string);
}
type InputCompletion = ArgumentCompletion | RoutingTargetCompletion;
/**
* Propose possible completions for a partial input string.
*/
declare function proposeCompletionsForApplication<CONTEXT extends CommandContext>({ root, config, defaultText }: Application<CONTEXT>, rawInputs: readonly string[], context: StricliDynamicCommandContext<CONTEXT>): Promise<readonly InputCompletion[]>;
/**
* Enumeration of all possible exit codes returned by an application.
*/
declare const ExitCode: {
/**
* Unable to find a command in the application with the given command line arguments.
*/
readonly UnknownCommand: -5;
/**
* Unable to parse the specified arguments.
*/
readonly InvalidArgument: -4;
/**
* An error was thrown while loading the context for a command run.
*/
readonly ContextLoadError: -3;
/**
* Failed to load command module.
*/
readonly CommandLoadError: -2;
/**
* An unexpected error was thrown by or not caught by this library.
*/
readonly InternalError: -1;
/**
* Command executed successfully.
*/
readonly Success: 0;
/**
* Command module unexpectedly threw an error.
*/
readonly CommandRunError: 1;
};
/**
* Parses input strings as booleans.
* Transforms to lowercase and then checks against "true" and "false".
*/
declare const booleanParser: (input: string) => boolean;
/**
* Parses input strings as booleans (loosely).
* Transforms to lowercase and then checks against the following values:
* - `true`: `"true"`, `"t"`, `"yes"`, `"y"`, `"on"`, `"1"`
* - `false`: `"false"`, `"f"`, `"no"`, `"n"`, `"off"`, `"0"`
*/
declare const looseBooleanParser: (input: string) => boolean;
/**
* Creates an input parser that checks if the input string is found in a list of choices.
*/
declare function buildChoiceParser<T extends string>(choices: readonly T[]): InputParser<T>;
/**
* Parses input strings as numbers.
*/
declare const numberParser: (input: