import { ResultPromise, Options } from 'execa';
import { Project } from 'fixturify-project';

declare class BinTesterProject extends Project {
    private _dirChanged;
    /**
     * Constructs an instance of a BinTesterProject.
     * @param {string} name - The name of the project. Used within the package.json as the name property.
     * @param {string} version - The version of the project. Used within the package.json as the version property.
     * @param {Function} cb - An optional callback for additional setup steps after the project is constructed.
     */
    constructor(name?: string, version?: string, cb?: (project: Project) => void);
    /**
     * Runs `git init` inside a project.
     * @returns {*} {ResultPromise}
     */
    gitInit(): ResultPromise;
    /**
     * Writes the project files to disk.
     */
    write(): Promise<void>;
    /**
     * Changes a directory from inside the project.
     */
    chdir(): Promise<void>;
    /**
     * Correctly disposes of the project, observing when the directory has been changed.
     * @returns {void}
     */
    dispose(): void;
}

/**
 * Options for configuring the bin tester.
 */
interface BinTesterOptions<TProject> {
    /**
     * The absolute path to the bin to invoke
     */
    binPath: string | (<TProject extends BinTesterProject>(project: TProject) => string);
    /**
     * An array of static arguments that will be used every time when running the bin
     */
    staticArgs?: string[];
    /**
     * An optional function to use to create the project. Use this if you want to provide a custom implementation of a BinTesterProject.
     */
    createProject?: () => Promise<TProject>;
}
/**
 * Function signature for running the configured CLI binary.
 */
interface RunBin {
    /**
     * A runBin implementation that takes no parameters.
     * @returns {*}  {ResultPromise}
     */
    (): ResultPromise;
    /**
     * A runBin implementation that takes string varargs.
     * @param {...RunBinArgs} args
     * @returns {*}  {ResultPromise}
     */
    (...args: [...binArgs: string[]]): ResultPromise;
    /**
     * A runBin implementation that takes an Options object.
     * @param {...RunBinArgs} args
     * @returns {*}  {ResultPromise}
     */
    (...args: [execaOptions: Options]): ResultPromise;
    /**
     * A runBin implementation that takes string or an Options object varargs.
     * @param {...RunBinArgs} args
     * @returns {*}  {ResultPromise}
     */
    (...args: [...binArgs: string[], execaOptions: Options]): ResultPromise;
}
/**
 * The result returned by createBinTester.
 */
interface CreateBinTesterResult<TProject extends BinTesterProject> {
    /**
     * Runs the configured bin function via execa.
     */
    runBin: RunBin;
    /**
     * Sets up the specified project for use within tests.
     */
    setupProject: () => Promise<TProject>;
    /**
     * Sets up a tmp directory for use within tests.
     */
    setupTmpDir: () => Promise<string>;
    /**
     * Tears the project down, ensuring the tmp directory is removed.
     * When BIN_TESTER_DEBUG is set, fixtures are preserved for inspection.
     */
    teardownProject: () => void;
    /**
     * Runs the configured bin with Node inspector enabled in attach mode (--inspect).
     * Set BIN_TESTER_DEBUG=break to break on first line instead.
     */
    runBinDebug: RunBin;
}
/**
 * Creates the bin tester API functions to use within tests.
 * @param {BinTesterOptions<TProject>} options - An object of bin tester options
 * @returns {CreateBinTesterResult<TProject>} - A project instance.
 */
declare function createBinTester<TProject extends BinTesterProject>(options: BinTesterOptions<TProject>): CreateBinTesterResult<TProject>;

export { type BinTesterOptions, BinTesterProject, type CreateBinTesterResult, type RunBin, createBinTester };
