/// <reference types="node" />
/// <reference types="node" />
import { Readable, Writable } from 'stream';
import { CommandBuilder } from '../core';
import { ColorFormat } from '../format';
import { CommandClass, Command, Definition } from './Command';
import { CommandOption } from './options/utils';
declare type MakeOptional<T, Keys extends keyof T> = Omit<T, Keys> & Partial<Pick<T, Keys>>;
declare type VoidIfEmpty<T> = keyof T extends never ? void : never;
/**
 * The base context of the CLI.
 *
 * All Contexts have to extend it.
 */
export declare type BaseContext = {
    /**
     * Environment variables.
     *
     * @default
     * process.env
     */
    env: Record<string, string | undefined>;
    /**
     * The input stream of the CLI.
     *
     * @default
     * process.stdin
     */
    stdin: Readable;
    /**
     * The output stream of the CLI.
     *
     * @default
     * process.stdout
     */
    stdout: Writable;
    /**
     * The error stream of the CLI.
     *
     * @default
     * process.stderr
     */
    stderr: Writable;
    /**
     * Whether colors should be enabled.
     */
    colorDepth: number;
};
export declare type CliContext<Context extends BaseContext> = {
    commandClass: CommandClass<Context>;
};
export declare type UserContextKeys<Context extends BaseContext> = Exclude<keyof Context, keyof BaseContext>;
export declare type UserContext<Context extends BaseContext> = Pick<Context, UserContextKeys<Context>>;
export declare type PartialContext<Context extends BaseContext> = UserContextKeys<Context> extends never ? Partial<Pick<Context, keyof BaseContext>> | undefined | void : Partial<Pick<Context, keyof BaseContext>> & UserContext<Context>;
export declare type RunContext<Context extends BaseContext = BaseContext> = Partial<Pick<Context, keyof BaseContext>> & UserContext<Context>;
export declare type RunCommand<Context extends BaseContext = BaseContext> = Array<CommandClass<Context>> | CommandClass<Context>;
export declare type RunCommandNoContext<Context extends BaseContext = BaseContext> = UserContextKeys<Context> extends never ? RunCommand<Context> : never;
export declare type CliOptions = Readonly<{
    /**
     * The label of the binary.
     *
     * Shown at the top of the usage information.
     */
    binaryLabel?: string;
    /**
     * The name of the binary.
     *
     * Included in the path and the examples of the definitions.
     */
    binaryName: string;
    /**
     * The version of the binary.
     *
     * Shown at the top of the usage information.
     */
    binaryVersion?: string;
    /**
     * If `true`, the Cli will hook into the process standard streams to catch
     * the output produced by console.log and redirect them into the context
     * streams. Note: stdin isn't captured at the moment.
     *
     * @default
     * false
     */
    enableCapture: boolean;
    /**
     * If `true`, the Cli will use colors in the output. If `false`, it won't.
     * If `undefined`, Clipanion will infer the correct value from the env.
     */
    enableColors?: boolean;
}>;
export declare type MiniCli<Context extends BaseContext> = CliOptions & {
    /**
     * Returns an Array representing the definitions of all registered commands.
     */
    definitions(): Array<Definition>;
    /**
     * Formats errors using colors.
     *
     * @param error The error to format. If `error.name` is `'Error'`, it is replaced with `'Internal Error'`.
     * @param opts.command The command whose usage will be included in the formatted error.
     */
    error(error: Error, opts?: {
        command?: Command<Context> | null;
    }): string;
    /**
     * Returns a rich color format if colors are enabled, or a plain text format otherwise.
     *
     * @param colored Forcefully enable or disable colors.
     */
    format(colored?: boolean): ColorFormat;
    /**
     * Compiles a command and its arguments using the `CommandBuilder`.
     *
     * @param input An array containing the name of the command and its arguments
     *
     * @returns The compiled `Command`, with its properties populated with the arguments.
     */
    process(input: Array<string>, context?: Partial<Context>): Command<Context>;
    /**
     * Runs a command.
     *
     * @param input An array containing the name of the command and its arguments
     * @param context Overrides the Context of the main `Cli` instance
     *
     * @returns The exit code of the command
     */
    run(input: Array<string>, context?: Partial<Context>): Promise<number>;
    /**
     * Returns the usage of a command.
     *
     * @param command The `Command` whose usage will be returned or `null` to return the usage of all commands.
     * @param opts.detailed If `true`, the usage of a command will also include its description, details, and examples. Doesn't have any effect if `command` is `null` or doesn't have a `usage` property.
     * @param opts.prefix The prefix displayed before each command. Defaults to `$`.
     */
    usage(command?: CommandClass<Context> | Command<Context> | null, opts?: {
        detailed?: boolean;
        prefix?: string;
    }): string;
};
/**
 * An all-in-one helper that simultaneously instantiate a CLI and immediately
 * executes it. All parameters are optional except the command classes and
 * will be filled by sensible values for the current environment (for example
 * the argv argument will default to `process.argv`, etc).
 *
 * Just like `Cli#runExit`, this function will set the `process.exitCode` value
 * before returning.
 */
export declare function runExit<Context extends BaseContext = BaseContext>(commandClasses: RunCommandNoContext<Context>): Promise<void>;
export declare function runExit<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, context: RunContext<Context>): Promise<void>;
export declare function runExit<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommandNoContext<Context>): Promise<void>;
export declare function runExit<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommand<Context>, context: RunContext<Context>): Promise<void>;
export declare function runExit<Context extends BaseContext = BaseContext>(commandClasses: RunCommandNoContext<Context>, argv: Array<string>): Promise<void>;
export declare function runExit<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, argv: Array<string>, context: RunContext<Context>): Promise<void>;
export declare function runExit<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommandNoContext<Context>, argv: Array<string>): Promise<void>;
export declare function runExit<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommand<Context>, argv: Array<string>, context: RunContext<Context>): Promise<void>;
/**
 * An all-in-one helper that simultaneously instantiate a CLI and immediately
 * executes it. All parameters are optional except the command classes and
 * will be filled by sensible values for the current environment (for example
 * the argv argument will default to `process.argv`, etc).
 *
 * Unlike `runExit`, this function won't set the `process.exitCode` value
 * before returning.
 */
export declare function run<Context extends BaseContext = BaseContext>(commandClasses: RunCommandNoContext<Context>): Promise<number>;
export declare function run<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, context: RunContext<Context>): Promise<number>;
export declare function run<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommandNoContext<Context>): Promise<number>;
export declare function run<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommand<Context>, context: RunContext<Context>): Promise<number>;
export declare function run<Context extends BaseContext = BaseContext>(commandClasses: RunCommandNoContext<Context>, argv: Array<string>): Promise<number>;
export declare function run<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, argv: Array<string>, context: RunContext<Context>): Promise<number>;
export declare function run<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommandNoContext<Context>, argv: Array<string>): Promise<number>;
export declare function run<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommand<Context>, argv: Array<string>, context: RunContext<Context>): Promise<number>;
/**
 * @template Context The context shared by all commands. Contexts are a set of values, defined when calling the `run`/`runExit` functions from the CLI instance, that will be made available to the commands via `this.context`.
 */
export declare class Cli<Context extends BaseContext = BaseContext> implements Omit<MiniCli<Context>, `process` | `run`> {
    /**
     * The default context of the CLI.
     *
     * Contains the stdio of the current `process`.
     */
    static defaultContext: {
        env: NodeJS.ProcessEnv;
        stdin: NodeJS.ReadStream & {
            fd: 0;
        };
        stdout: NodeJS.WriteStream & {
            fd: 1;
        };
        stderr: NodeJS.WriteStream & {
            fd: 2;
        };
        colorDepth: number;
    };
    private readonly builder;
    protected readonly registrations: Map<CommandClass<Context>, {
        index: number;
        builder: CommandBuilder<CliContext<Context>>;
        specs: Map<string, CommandOption<unknown>>;
    }>;
    readonly binaryLabel?: string;
    readonly binaryName: string;
    readonly binaryVersion?: string;
    readonly enableCapture: boolean;
    readonly enableColors?: boolean;
    /**
     * Creates a new Cli and registers all commands passed as parameters.
     *
     * @param commandClasses The Commands to register
     * @returns The created `Cli` instance
     */
    static from<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, options?: Partial<CliOptions>): Cli<Context>;
    constructor({ binaryLabel, binaryName: binaryNameOpt, binaryVersion, enableCapture, enableColors }?: Partial<CliOptions>);
    /**
     * Registers a command inside the CLI.
     */
    register(commandClass: CommandClass<Context>): void;
    process(input: Array<string>, context: VoidIfEmpty<Omit<Context, keyof BaseContext>>): Command<Context>;
    process(input: Array<string>, context: MakeOptional<Context, keyof BaseContext>): Command<Context>;
    run(input: Command<Context> | Array<string>, context: VoidIfEmpty<Omit<Context, keyof BaseContext>>): Promise<number>;
    run(input: Command<Context> | Array<string>, context: MakeOptional<Context, keyof BaseContext>): Promise<number>;
    /**
     * Runs a command and exits the current `process` with the exit code returned by the command.
     *
     * @param input An array containing the name of the command and its arguments.
     *
     * @example
     * cli.runExit(process.argv.slice(2))
     */
    runExit(input: Command<Context> | Array<string>, context: VoidIfEmpty<Omit<Context, keyof BaseContext>>): Promise<void>;
    runExit(input: Command<Context> | Array<string>, context: MakeOptional<Context, keyof BaseContext>): Promise<void>;
    suggest(input: Array<string>, partial: boolean): string[][];
    definitions({ colored }?: {
        colored?: boolean;
    }): Array<Definition>;
    usage(command?: CommandClass<Context> | Command<Context> | null, { colored, detailed, prefix }?: {
        colored?: boolean;
        detailed?: boolean;
        prefix?: string;
    }): string;
    error(error: Error | any, { colored, command }?: {
        colored?: boolean;
        command?: Command<Context> | null;
    }): string;
    format(colored?: boolean): ColorFormat;
    protected getUsageByRegistration(klass: CommandClass<Context>, opts?: {
        detailed?: boolean;
        inlineOptions?: boolean;
    }): {
        usage: string;
        options: {
            definition: string;
            description: string;
            required: boolean;
        }[];
    };
    protected getUsageByIndex(n: number, opts?: {
        detailed?: boolean;
        inlineOptions?: boolean;
    }): {
        usage: string;
        options: {
            definition: string;
            description: string;
            required: boolean;
        }[];
    };
}
export {};
