import { CommandContext, ProvidersFromChain } from "./context.mjs"; import { CompletionCallback, OptionCompletionCallback } from "./completion-types.mjs"; import { PromptOptionConfig, PromptProvider } from "./prompt-types.mjs"; import { InternalCLI } from "./internal-cli.mjs"; import { ArrayOptionConfig, BooleanOptionConfig, ConfigurationFiles, EnvOptionConfig, Expand, LocalizationDictionary, LocalizationFunction, MakeUndefinedPropertiesOptional, NumberOptionConfig, ObjectOptionConfig, OneOfOptionConfig, OptionConfig, OptionConfigToType, ParsedArgs, ResolveProperties, StringOptionConfig, WithOptional } from "@cli-forge/parser"; //#region src/lib/public-api.d.ts interface ProviderConfig { factory: (args: TArgs) => T; lifetime?: 'executionScope'; } interface GlobalProviderConfig { factory: () => T; lifetime: 'global'; } /** * Extracts the command name from a Command type. * Works with both CLI instances and command config objects. */ type ExtractCommandName = T extends CLI ? T extends InternalCLI ? string : string : T extends { name: infer N; } ? N extends string ? N : string : string; /** * Extracts the args type from a Command. * Works with both CLI instances and command config objects. */ type ExtractCommandArgs = T extends CLI ? A : T extends CLICommandOptions ? A : ParsedArgs; /** * Extracts the handler return type from a Command. */ type ExtractCommandHandlerReturn = T extends CLI ? R : T extends CLICommandOptions ? R : void; /** * Extracts the registered providers from a Command. * Works with both CLI instances (uses the 5th generic directly) and command * config objects (infers the builder's return type's provider map). */ type ExtractCommandProviders = T extends CLI ? P : T extends CLICommandOptions ? P : {}; /** * Converts a Command to its child CLI entry for TChildren tracking. * TParentCLI is the parent CLI type that will be set as the child's TParent. */ type CommandToChildEntry = { [K in ExtractCommandName]: CLI, ExtractCommandHandlerReturn, {}, TParentCLI, ExtractCommandProviders> }; /** * The interface for a CLI application or subcommands. * * {@link cli} is provided as a small helper function to create a new CLI instance. * * @example * ```ts * import { cli } from 'cli-forge'; * * cli('basic-cli').command('hello', { * builder: (args) => * args.option('name', { * type: 'string', * }), * handler: (args) => { * console.log(`Hello, ${args.name}!`); * }).forge(); * ``` */ interface CLI { command, TCommandArgs extends TArgs = (ExtractCommandArgs extends TArgs ? ExtractCommandArgs : TArgs), TCmdName extends string = ExtractCommandName, TChildHandlerReturn = ExtractCommandHandlerReturn>(cmd: TCommand): CLI, ExtractCommandProviders> }, TParent, TProviders>; /** * Registers a new command with the CLI. * @param key What should the new command be called? * @param options Settings for the new command. See {@link CLICommandOptions}. * @returns Updated CLI instance with the new command registered. */ command(key: TKey, options: CLICommandOptions, TChildChildren, TChildProviders>): CLI, TChildProviders> }, TParent, TProviders>; /** * Registers multiple subcommands with the CLI. * @param commands Several commands to register. Can be the result of a call to {@link cli} or a configuration object. * @returns Updated CLI instance with the commands registered and their types tracked in TChildren. */ commands(c1: C1): CLI>, TParent, TProviders>; commands(c1: C1, c2: C2): CLI> & CommandToChildEntry>, TParent, TProviders>; commands(c1: C1, c2: C2, c3: C3): CLI> & CommandToChildEntry> & CommandToChildEntry>, TParent, TProviders>; commands(c1: C1, c2: C2, c3: C3, c4: C4): CLI> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry>, TParent, TProviders>; commands(c1: C1, c2: C2, c3: C3, c4: C4, c5: C5): CLI> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry>, TParent, TProviders>; commands(c1: C1, c2: C2, c3: C3, c4: C4, c5: C5, c6: C6): CLI> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry>, TParent, TProviders>; commands(c1: C1, c2: C2, c3: C3, c4: C4, c5: C5, c6: C6, c7: C7): CLI> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry>, TParent, TProviders>; commands(c1: C1, c2: C2, c3: C3, c4: C4, c5: C5, c6: C6, c7: C7, c8: C8): CLI> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry>, TParent, TProviders>; commands(c1: C1, c2: C2, c3: C3, c4: C4, c5: C5, c6: C6, c7: C7, c8: C8, c9: C9): CLI> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry>, TParent, TProviders>; commands(c1: C1, c2: C2, c3: C3, c4: C4, c5: C5, c6: C6, c7: C7, c8: C8, c9: C9, c10: C10): CLI> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry> & CommandToChildEntry>, TParent, TProviders>; commands(commands: Command[]): CLI; commands(...commands: Command[]): CLI; /** * Register's a configuration provider for the CLI. See {@link ConfigurationProviders} for built-in providers. * * @param provider Provider to register. */ config(provider: ConfigurationFiles.AnyConfigProvider): CLI; /** * Updates configuration by routing each key to its owning provider. * * @param values Partial configuration to write. */ updateConfig(values: Partial): Promise; /** * Updates configuration via an updater function. The current merged * configuration is passed via a proxy that tracks which properties are set. * Only properties set during the callback are written back. * * @param updater Function that receives the current config and mutates it. */ updateConfig(updater: ConfigurationFiles.ConfigUpdater): Promise; /** * Enables the ability to run CLI commands that contain subcommands as an interactive shell. * This presents as a small shell that only knows the current command and its subcommands. * Any flags already consumed by the command will be passed to every subcommand invocation. */ enableInteractiveShell(): CLI; /** * Registers a custom global error handler for the CLI. This handler will be called when an error is thrown * during the execution of the CLI and not otherwise handled. Error handlers should re-throw the error if they * cannot handle it, s.t. the next error handler can attempt to handle it. * * @param handler Typically called with an Error object, but you should be prepared to handle any type of error. * @param actions Actions that can be taken by the error handler. Prefer using these over process.exit for better support of interactive shells. */ errorHandler(handler: ErrorHandler): CLI; /** * Registers a prompt provider for interactive option fulfillment. * Multiple providers can be registered. Filtered providers are checked first * (in registration order), then fallback providers (no filter). * * @param provider The prompt provider to register. */ withPromptProvider(provider: PromptProvider): CLI; /** * Registers a new option for the CLI command. This option will be accessible * within the command handler, as well as any subcommands. * * @param name The name of the option. * @param config Configuration for the option. See {@link UnknownOptionConfig}. * @returns Updated CLI instance with the new option registered. */ option>(name: TOption, config: ObjectOptionConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI : TCoerce, ObjectOptionConfig> }>>, THandlerReturn, TChildren, TParent, TProviders>; option>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; option>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; option>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; option>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; option>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; option>(name: TOption, config: TOptionConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; /** * Registers a new positional argument for the CLI command. This argument will be accessible * within the command handler, as well as any subcommands. * @param name The name of the positional argument. * @param config Configuration for the positional argument. See {@link UnknownOptionConfig}. * @returns Updated CLI instance with the new positional argument registered. */ positional>(name: TOption, config: ObjectOptionConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI : TCoerce, ObjectOptionConfig> }>>, THandlerReturn, TChildren, TParent, TProviders>; positional>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; positional>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; positional>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; positional>(name: TOption, config: TConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; positional>(name: TOption, config: TOptionConfig & { prompt?: PromptOptionConfig; completion?: OptionCompletionCallback; }): CLI }>>, THandlerReturn, TChildren, TParent, TProviders>; /** * Adds support for reading CLI options from environment variables. * @param prefix The prefix to use when looking up environment variables. Defaults to the command name. */ env(prefix?: string): CLI; env(options: EnvOptionConfig): CLI; /** * Sets up localization for option keys and other text. * When localization is enabled, option keys will be displayed in the specified locale in help text and documentation, * and both the default and localized keys will be accepted when parsing arguments. * * @param dictionary The localization dictionary mapping keys to their translations * @param locale The target locale (defaults to system locale if not provided) * @returns Updated CLI instance for chaining * * @example * ```ts * cli('myapp') * .localize({ * name: { default: 'name', 'es-ES': 'nombre' }, * port: { default: 'port', 'es-ES': 'puerto' } * }, 'es-ES') * .option('name', { type: 'string' }) * .option('port', { type: 'number' }); * ``` */ localize(dictionary: LocalizationDictionary, locale?: string): CLI; /** * Sets up localization using a custom function for translating keys. * This allows integration with existing localization libraries like i18next. * * @param fn A function that takes a key and returns its localized value * @returns Updated CLI instance for chaining * * @example * ```ts * import i18next from 'i18next'; * * cli('myapp') * .localize((key) => i18next.t(key)) * .option('name', { type: 'string' }) * .option('port', { type: 'number' }); * ``` */ localize(fn: LocalizationFunction): CLI; /** * Sets a group of options as mutually exclusive. If more than one option is provided, there will be a validation error. * @param options The options that should be mutually exclusive. */ conflicts(...options: [string, string, ...string[]]): CLI; /** * Sets a group of options as mutually inclusive. If one option is provided, all other options must also be provided. * @param option The option that implies the other options. * @param impliedOptions The options which become required when the option is provided. */ implies(option: string, ...impliedOptions: string[]): CLI; /** * Requires a command to be provided when executing the CLI. Useful if your parent command * cannot be executed on its own. * @returns Updated CLI instance. */ demandCommand(): CLI; /** * Enables or disables strict mode. When strict mode is enabled, the parser throws a validation error * when unmatched arguments are encountered. Unmatched arguments are those that don't match any * configured option or positional argument. * @param enable Whether to enable strict mode. Defaults to true. * @returns Updated CLI instance. */ strict(enable?: boolean): CLI; /** * Sets the usage text for the CLI. This text will be displayed in place of the default usage text * @param usageText Text displayed in place of the default usage text for `--help` and in generated docs. */ usage(usageText: string): CLI; /** * Marks this command as hidden so it is omitted from help output, generated documentation, * and shell completion suggestions. Useful when composing reusable builders that need to * register internal or experimental commands without exposing them to end users. * @param hidden Whether the command should be hidden. Defaults to `true`. */ hidden(hidden?: boolean): CLI; /** * Sets the description for the CLI. This text will be displayed in the help text and generated docs. * @param examples Examples to display in the help text and generated docs. */ examples(...examples: string[]): CLI; /** * Allows overriding the version displayed when passing `--version`. Defaults to crawling * the file system to get the package.json of the currently executing command. * @param override */ version(override?: string): CLI; /** * Prints help text to stdout. */ printHelp(): void; group({ label, keys, sortOrder }: { label: string; keys: (keyof TArgs)[]; sortOrder?: number; }): CLI; group(label: string, keys: (keyof TArgs)[]): CLI; middleware(callback: MiddlewareFunction): CLI, THandlerReturn, TChildren, TParent, TProviders>; /** * Registers a handler for this command. Fluent alternative to passing * `handler` in the command configuration object. * * @param fn Handler function receiving parsed args and command context. * @returns Updated CLI instance with the handler return type updated. * * @example * ```ts * cli('serve') * .option('port', { type: 'number', default: 3000 }) * .handler((args) => { * console.log(`Listening on port ${args.port}`); * }) * .forge(); * ``` */ handler(fn: (args: TArgs, context: CLIHandlerContext) => R): CLI; /** * Registers a dependency injection provider under a unique key. * The value (or factory result) is accessible via `inject()` within command handlers. * * Three forms are supported: * - **Eager value**: `provide('key', value)` — stored as-is. * - **ExecutionScope factory**: `provide('key', { factory: (args) => value })` — called per invocation with parsed args. * - **Global factory**: `provide('key', { factory: () => value, lifetime: 'global' })` — called once and cached. * * Duplicate keys on the same command instance throw an error. */ provide(key: TName & (TName extends keyof TProviders ? never : TName), config: GlobalProviderConfig): CLI; provide(key: TName & (TName extends keyof TProviders ? never : TName), config: ProviderConfig): CLI; provide(key: TName & (TName extends keyof TProviders ? never : TName), value: T): CLI; /** * Registers an init hook that runs before command resolution. * Init hooks receive partially-parsed args (from currently-registered options) * and can modify the CLI (register commands, options, middleware) before the * full parse runs. This enables plugin loading from config files. * * @param callback Async function receiving (args, cli). Mutate cli to add commands/options. */ init(callback: (cli: CLI, args: TArgs) => Promise | void): CLI; /** * Enables shell completion for this CLI. * When called at the root level (no parent), also registers: * - A hidden `--get-completions` flag for runtime completion * - A `completion` subcommand for installing shell scripts * * At any level, stores the optional callback for custom completion suggestions. * * @param callback Optional custom completion callback for this command level. */ completion(callback?: CompletionCallback): CLI; /** * Parses argv and executes the CLI * @param args argv. Defaults to process.argv.slice(2) * @returns Promise that resolves when the handler completes. */ forge(args?: string[]): Promise; /** * Returns the typed children commands registered with this CLI. * The return type depends on the commands registered via `command()` or `commands()`. * * @example * ```ts * const app = cli('app') * .command('init', { ... }) * .command('build', { ... }); * * const children = app.getChildren(); * // children.init and children.build are typed CLI instances * const initHandler = children.init.getHandler(); * ``` */ getChildren(): TChildren; /** * Returns the parent CLI instance, if this command was registered as a subcommand. * Returns undefined for root-level CLI instances. * * @example * ```ts * const build = cli('build', { * handler: (args, ctx) => { * const parent = ctx.command.getParent(); * const siblings = parent?.getChildren(); * // Access sibling commands * } * }); * ``` */ getParent(): TParent; /** * Returns the {@link CommandContext} for the currently executing command, * inferred from this CLI instance. * * This is a shorthand for `getCommandContext(this)` — it avoids the * separate `import { getCommandContext } from 'cli-forge'` when you * already have a reference to the CLI. Both forms are equivalent in * type inference and runtime safety: the CLI instance is validated * against the active command chain, so passing a CLI that isn't * running (a sibling, an unrelated app) throws. * * Must be called from within a command handler — not during builders * or middleware. * * @example * ```ts * const app = cli('app') * .provide('db', { factory: () => connectDb() }) * .command('migrate', { * handler: () => { * const db = app.getContext().inject('db'); * return db.runMigrations(); * }, * }); * ``` */ getContext(): CommandContext, TChildren>; /** * Returns a programmatic SDK for invoking this CLI and its subcommands. * The SDK provides typed function calls instead of argv parsing. * * @example * ```ts * const myCLI = cli('my-app') * .option('verbose', { type: 'boolean' }) * .command('build', { * builder: (cmd) => cmd.option('watch', { type: 'boolean' }), * handler: (args) => ({ success: true, files: ['a.js'] }) * }); * * const sdk = myCLI.sdk(); * * // Invoke root command (if it has a handler) * await sdk({ verbose: true }); * * // Invoke subcommand with typed args * const result = await sdk.build({ watch: true }); * console.log(result.files); // ['a.js'] * console.log(result.$args.watch); // true * * // Use CLI-style args for -- support * await sdk.build(['--watch', '--', 'extra-arg']); * ``` * * @returns An SDK object that is callable (if this command has a handler) * and has properties for each subcommand. */ sdk(): SDKCommand; /** * Returns the builder function for this command as a composable builder. * The returned function can be used with `chain` to compose multiple builders. * * @example * ```ts * const siblings = args.getParent().getChildren(); * const withBuildArgs = siblings.build.getBuilder()!; * const withServeArgs = siblings.serve.getBuilder()!; * return chain(args, withBuildArgs, withServeArgs); * ``` */ getBuilder(): ((parser: CLI) => CLI) | undefined; getHandler(): ((args: Omit) => THandlerReturn) | undefined; } interface CLIHandlerContext { command: CLI; } /** * Extracts the TChildren type parameter from a CLI type. */ type ExtractCLIChildren = T extends CLI ? C : {}; /** * Represents the configuration needed to create a CLI command. */ interface CLICommandOptions< /** * The type of the arguments that are already registered before `builder` is invoked. */ TInitial extends ParsedArgs, /** * The type of the arguments that are registered after `builder` is invoked, and the type that is passed to the handler. */ TArgs extends TInitial = TInitial, THandlerReturn = void | Promise, /** * The children commands that exist before the builder runs. */ TInitialChildren = {}, TParent = any, /** * The children commands after the builder runs (includes TInitialChildren plus any added by builder). */ TChildren = {}, /** * The providers registered inside the builder via `.provide()`. Inferred * from the builder's return type so that child-overrides-parent semantics * are visible in `getCommandContext(child).inject()`. */ TChildProviders = {}> { /** * If set the command will be registered under the provided name and any aliases. * * This can be useful if a command should be executed under more than one name, e.g. `npx my-cli` and `npx my-cli hello`. */ alias?: string[]; /** * The command description. This will be displayed in the help text and generated docs. */ description?: string; /** * The command builder. This function is called before the command is executed, and is used to register options and positional parameters. * @param parser The parser instance to register options and positionals with. */ builder?: (parser: CLI) => CLI; /** * The command handler. This function is called when the command is executed. * @param args The parsed arguments. * @param context Context for the handler. Contains the command instance. */ handler?: (args: NoInfer, context: CLIHandlerContext, TParent>) => THandlerReturn; /** * The usage text for the command. This text will be displayed in place of the default usage text in the help text and generated docs. */ usage?: string; /** * Examples to display in the help text and generated docs. */ examples?: string[]; /** * Hides the command from the help text and generated docs. Useful primarily for experimental or internal commands. */ hidden?: boolean; /** * The epilogue text for the command. This text will be displayed at the end of the help text and generated docs. */ epilogue?: string; } type Command = ({ name: TCommandName; } & CLICommandOptions) | CLI; /** * Error Handler for CLI applications. Error handlers should re-throw the error if they cannot handle it. * * @param e The error that was thrown. * @param actions Actions that can be taken by the error handler. Prefer using these over process.exit for better support of interactive shells. */ type ErrorHandler = (e: unknown, actions: { /** * Exits the process immediately. * @param code */ exit: (code?: number) => void; }) => void; /** Type alias for a CLI instance with any type parameters. Use in value positions where you need to accept any CLI. */ type AnyCLI = CLI; /** * Base CLI constraint for generic functions. Uses `ParsedArgs` instead of `any` * for `TArgs` so that method return types (like `.option()`) compute correctly * through `chain()`. Use this as the bound in ``. * * @example * ```ts * function withVerbose(cli: T) { * return cli.option('verbose', { type: 'boolean' }); * } * ``` */ type UnknownCLI = CLI; type MiddlewareFunction = (args: TArgs) => TArgs2 | Promise; /** * Result type that conditionally includes $args. * Only attaches $args when result is an object type. * Uses `Awaited` to handle async handlers that return `Promise`. */ type SDKResult = Awaited extends object ? Awaited & { $args: TArgs; } : Awaited; /** * The callable signature for a command with a handler. * Supports both object-style args (typed, skips validation) and * string array args (CLI-style, full validation pipeline). */ type SDKInvokable = { /** * Invoke the command with typed object args. * Skips validation (TypeScript handles it), applies defaults, runs middleware. */ (args?: Partial>): Promise>; /** * Invoke the command with CLI-style string args. * Runs full pipeline: parse → validate → middleware → handler. * Use this when you need to pass `--` extra args. */ (args: string[]): Promise>; }; /** * Recursively builds SDK type from TChildren. * Each child command becomes a property on the SDK object. */ type SDKChildren = { [K in keyof TChildren]: TChildren[K] extends CLI ? SDKCommand : never }; /** * A single SDK command - callable if it has a handler, with nested children as properties. * Container commands (no handler) are not callable but still provide access to children. */ type SDKCommand = SDKInvokable & SDKChildren; /** * Constructs a CLI instance. See {@link CLI} for more information. * @param name Name for the top level CLI * @param rootCommandConfiguration Configuration used when running the bare CLI. e.g. npx my-cli, rather than npx my-cli [cmd] * @returns A {@link CLI} instance. */ declare function cli(name: TName, rootCommandConfiguration?: CLICommandOptions): CLI; //#endregion export { AnyCLI, CLI, CLICommandOptions, CLIHandlerContext, Command, CommandToChildEntry, ErrorHandler, ExtractCLIChildren, ExtractCommandArgs, ExtractCommandHandlerReturn, ExtractCommandName, ExtractCommandProviders, GlobalProviderConfig, MiddlewareFunction, ProviderConfig, SDKChildren, SDKCommand, SDKInvokable, SDKResult, UnknownCLI, cli, cli as default }; //# sourceMappingURL=public-api.d.mts.map