zhorton34 stubscli .cursorrules file for TypeScript (stars: 1)

We're creating a command line tool to help speed up the developer workflows. 

We're using cliffy.

```ts
// deno-lint-ignore-file no-explicit-any
import {
  parseFlags,
  type ParseFlagsContext,
  UnknownTypeError,
  ValidationError as FlagsValidationError,
} from "jsr:@cliffy/flags@1.0.0-rc.7";
import { bold, brightBlue, red } from "jsr:/@std/fmt@~1.0.2/colors";
import type {
  MapTypes,
  MapValue,
  MergeOptions,
  TypedArguments,
  TypedCommandArguments,
  TypedEnv,
  TypedOption,
  TypedType,
} from "./_argument_types.ts";
import {
  CommandNotFoundError,
  DefaultCommandNotFoundError,
  DuplicateCommandAliasError,
  DuplicateCommandNameError,
  DuplicateCompletionError,
  DuplicateEnvVarError,
  DuplicateExampleError,
  DuplicateOptionNameError,
  DuplicateTypeError,
  MissingArgumentError,
  MissingArgumentsError,
  MissingCommandNameError,
  MissingRequiredEnvVarError,
  NoArgumentsAllowedError,
  TooManyArgumentsError,
  TooManyEnvVarValuesError,
  UnexpectedOptionalEnvVarValueError,
  UnexpectedVariadicEnvVarValueError,
  UnknownCommandError,
  ValidationError,
} from "./_errors.ts";
import { exit } from "jsr:@cliffy/internal@1.0.0-rc.7/runtime/exit";
import { getArgs } from "jsr:@cliffy/internal@1.0.0-rc.7/runtime/get-args";
import { getEnv } from "jsr:@cliffy/internal@1.0.0-rc.7/runtime/get-env";
import type { Merge, OneOf, ValueOf } from "./_type_utils.ts";
import {
  getDescription,
  parseArgumentsDefinition,
  splitArguments,
  underscoreToCamelCase,
} from "./_utils.ts";
import { HelpGenerator, type HelpOptions } from "./help/_help_generator.ts";
import { Type } from "./type.ts";
import type {
  ActionHandler,
  Argument,
  ArgumentValue,
  CommandResult,
  CompleteHandler,
  CompleteOptions,
  Completion,
  DefaultValue,
  Description,
  EnvVar,
  EnvVarOptions,
  EnvVarValueHandler,
  ErrorHandler,
  Example,
  GlobalEnvVarOptions,
  GlobalOptionOptions,
  HelpHandler,
  Option,
  OptionOptions,
  OptionValueHandler,
  TypeDef,
  TypeOptions,
  TypeOrTypeHandler,
  VersionHandler,
} from "./types.ts";
import { BooleanType } from "./types/boolean.ts";
import { FileType } from "./types/file.ts";
import { IntegerType } from "./types/integer.ts";
import { NumberType } from "./types/number.ts";
import { StringType } from "./types/string.ts";
import { checkVersion } from "./upgrade/_check_version.ts";

/**
 * Chainable command factory class.
 *
 * ```ts
 * import { Command } from "./mod.ts";
 *
 * export const cli = new Command()
 *   .name("todo")
 *   .description("Example command description")
 *   .globalOption("--verbose", "Enable verbose output.")
 *   .globalEnv("VERBOSE=<value>", "Enable verbose output.")
 *   .command("add <todo>", "Add todo.")
 *   .action(({ verbose }, todo: string) => {
 *     if (verbose) {
 *       console.log("Add todo '%s'.", todo);
 *     }
 *   })
 *   .command("delete <id>", "Delete todo.")
 *   .action(({ verbose }, id: string) => {
 *     if (verbose) {
 *       console.log("Delete todo with id '%s'.", id);
 *     }
 *   });
 *
 * if (import.meta.main) {
 *   await cli.parse();
 * }
 * ```
 */
export class Command<
  TParentCommandGlobals extends Record<string, unknown> | void = void,
  TParentCommandTypes extends Record<string, unknown> | void =
    TParentCommandGlobals extends number ? any : void,
  TCommandOptions extends Record<string, unknown> | void =
    TParentCommandGlobals extends number ? any : void,
  TCommandArguments extends Array<unknown> = TParentCommandGlobals extends
    number ? any : [],
  TCommandGlobals extends Record<string, unknown> | void =
    TParentCommandGlobals extends number ? any : void,
  TCommandTypes extends Record<string, unknown> | void =
    TParentCommandGlobals extends number ? any : {
      number: number;
      integer: number;
      string: string;
      boolean: boolean;
      file: string;
    },
  TCommandGlobalTypes extends Record<string, unknown> | void =
    TParentCommandGlobals extends number ? any : void,
  TParentCommand extends Command<any> | undefined =
    TParentCommandGlobals extends number ? any : undefined,
> {
  private types: Map<string, TypeDef> = new Map();
  private rawArgs: Array<string> = [];
  private literalArgs: Array<string> = [];
  private _name = "COMMAND";
  private _parent?: TParentCommand;
  private _globalParent?: Command<any>;
  private ver?: VersionHandler;
  private desc: Description = "";
  private _usage?: string;
  private actionHandler?: ActionHandler;
  private globalActionHandler?: ActionHandler;
  private options: Array<Option> = [];
  private commands = new Map<string, Command<any>>();
  private examples: Array<Example> = [];
  private envVars: Array<EnvVar> = [];
  private aliases: Array<string> = [];
  private completions = new Map<string, Completion>();
  private cmd: Command<any> = this;
  private argsDefinition?: string;
  private throwOnError = false;
  private _allowEmpty = false;
  private _stopEarly = false;
  private defaultCommand?: string;
  private _useRawArgs = false;
  private args: Array<Argument> = [];
  private isHidden = false;
  private isGlobal = false;
  private hasDefaults = false;
  private _versionOptions?: DefaultOption | false;
  private _helpOptions?: DefaultOption | false;
  private _versionOption?: Option;
  private _helpOption?: Option;
  private _help?: HelpHandler;
  private _shouldExit?: boolean;
  private _meta: Record<string, string> = {};
  private _groupName: string | null = null;
  private _noGlobals = false;
  private errorHandler?: ErrorHandler;

  /** Disable version option. */
  public versionOption(enable: false): this;

  /**
   * Set global version option.
   *
   * @param flags The flags of the version option.
   * @param desc  The description of the version option.
   * @param opts  Version option options.
   */
  public versionOption(
    flags: string,
    desc?: string,
    opts?:
      & OptionOptions<
        Partial<TCommandOptions>,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
      & {
        global: true;
      },
  ): this;

  /**
   * Set version option.
   *
   * @param flags The flags of the version option.
   * @param desc  The description of the version option.
   * @param opts  Version option options.
   */
  public versionOption(
    flags: string,
    desc?: string,
    opts?: OptionOptions<
      TCommandOptions,
      TCommandArguments,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      TParentCommand
    >,
  ): this;

  /**
   * Set version option.
   *
   * @param flags The flags of the version option.
   * @param desc  The description of the version option.
   * @param opts  The action of the version option.
   */
  public versionOption(
    flags: string,
    desc?: string,
    opts?: ActionHandler<
      TCommandOptions,
      TCommandArguments,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      TParentCommand
    >,
  ): this;

  public versionOption(
    flags: string | false,
    desc?: string,
    opts?:
      | ActionHandler<
        TCommandOptions,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
      | OptionOptions<
        TCommandOptions,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
      | OptionOptions<
        Partial<TCommandOptions>,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
        & {
          global: true;
        },
  ): this {
    this._versionOptions = flags === false ? flags : {
      flags,
      desc,
      opts: typeof opts === "function" ? { action: opts } : opts,
    };
    return this;
  }

  /** Disable help option. */
  public helpOption(enable: false): this;

  /**
   * Set global help option.
   *
   * @param flags The flags of the help option.
   * @param desc  The description of the help option.
   * @param opts  Help option options.
   */
  public helpOption(
    flags: string,
    desc?: string,
    opts?:
      & OptionOptions<
        Partial<TCommandOptions>,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
      & {
        global: true;
      },
  ): this;

  /**
   * Set help option.
   *
   * @param flags The flags of the help option.
   * @param desc  The description of the help option.
   * @param opts  Help option options.
   */
  public helpOption(
    flags: string,
    desc?: string,
    opts?: OptionOptions<
      TCommandOptions,
      TCommandArguments,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      TParentCommand
    >,
  ): this;

  /**
   * Set help option.
   *
   * @param flags The flags of the help option.
   * @param desc  The description of the help option.
   * @param opts  The action of the help option.
   */
  public helpOption(
    flags: string,
    desc?: string,
    opts?: ActionHandler<
      TCommandOptions,
      TCommandArguments,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      TParentCommand
    >,
  ): this;

  public helpOption(
    flags: string | false,
    desc?: string,
    opts?:
      | ActionHandler<
        TCommandOptions,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
      | OptionOptions<
        TCommandOptions,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
      | OptionOptions<
        Partial<TCommandOptions>,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
        & {
          global: true;
        },
  ): this {
    this._helpOptions = flags === false ? flags : {
      flags,
      desc,
      opts: typeof opts === "function" ? { action: opts } : opts,
    };
    return this;
  }

  /**
   * Add new sub-command.
   *
   * @param name      Command definition. E.g: `my-command <input-file:string> <output-file:string>`
   * @param cmd       The new child command to register.
   * @param override  Override existing child command.
   */
  public command<
    TCommand extends Command<
      (TGlobalOptions & Record<string, unknown>) | void | undefined,
      TGlobalTypes | void | undefined,
      Record<string, unknown> | void,
      Array<unknown>,
      Record<string, unknown> | void,
      Record<string, unknown> | void,
      Record<string, unknown> | void,
      Command<
        TGlobalOptions | void | undefined,
        TGlobalTypes | void | undefined,
        Record<string, unknown> | void,
        Array<unknown>,
        Record<string, unknown> | void,
        Record<string, unknown> | void,
        Record<string, unknown> | void,
        undefined
      >
    >,
    TGlobalOptions
      extends (TParentCommand extends Command<any> ? TParentCommandGlobals
        : Merge<TParentCommandGlobals, TCommandGlobals>),
    TGlobalTypes
      extends (TParentCommand extends Command<any> ? TParentCommandTypes
        : Merge<TParentCommandTypes, TCommandTypes>),
  >(
    name: string,
    cmd: TCommand,
    override?: boolean,
  ): ReturnType<TCommand["reset"]> extends Command<
    Record<string, unknown> | void,
    Record<string, unknown> | void,
    infer Options,
    infer Arguments,
    infer GlobalOptions,
    infer Types,
    infer GlobalTypes,
    undefined
  > ? Command<
      TGlobalOptions,
      TGlobalTypes,
      Options,
      Arguments,
      GlobalOptions,
      Types,
      GlobalTypes,
      OneOf<TParentCommand, this>
    >
    : never;

  /**
   * Add new sub-command.
   *
   * @param name      Command definition. E.g: `my-command <input-file:string> <output-file:string>`
   * @param cmd       The new child command to register.
   * @param override  Override existing child command.
   */
  public command<
    TCommand extends Command<
      TGlobalOptions | void | undefined,
      TGlobalTypes | void | undefined,
      Record<string, unknown> | void,
      Array<unknown>,
      Record<string, unknown> | void,
      Record<string, unknown> | void,
      Record<string, unknown> | void,
      OneOf<TParentCommand, this> | undefined
    >,
    TGlobalOptions
      extends (TParentCommand extends Command<any> ? TParentCommandGlobals
        : Merge<TParentCommandGlobals, TCommandGlobals>),
    TGlobalTypes
      extends (TParentCommand extends Command<any> ? TParentCommandTypes
        : Merge<TParentCommandTypes, TCommandTypes>),
  >(
    name: string,
    cmd: TCommand,
    override?: boolean,
  ): TCommand extends Command<
    Record<string, unknown> | void,
    Record<string, unknown> | void,
    infer Options,
    infer Arguments,
    infer GlobalOptions,
    infer Types,
    infer GlobalTypes,
    OneOf<TParentCommand, this> | undefined
  > ? Command<
      TGlobalOptions,
      TGlobalTypes,
      Options,
      Arguments,
      GlobalOptions,
      Types,
      GlobalTypes,
      OneOf<TParentCommand, this>
    >
    : never;

  /**
   * Add new sub-command.
   *
   * @param nameAndArguments  Command definition. E.g: `my-command <input-file:string> <output-file:string>`
   * @param desc              The description of the new child command.
   * @param override          Override existing child command.
   */
  public command<
    TNameAndArguments extends string,
    TArguments extends TypedCommandArguments<
      TNameAndArguments,
      TParentCommand extends Command<any> ? TParentCommandTypes
        : Merge<TParentCommandTypes, TCommandGlobalTypes>
    >,
  >(
    nameAndArguments: TNameAndArguments,
    desc?: string,
    override?: boolean,
  ): TParentCommandGlobals extends number ? Command<any> : Command<
    TParentCommand extends Command<any> ? TParentCommandGlobals
      : Merge<TParentCommandGlobals, TCommandGlobals>,
    TParentCommand extends Command<any> ? TParentCommandTypes
      : Merge<TParentCommandTypes, TCommandGlobalTypes>,
    void,
    TArguments,
    void,
    void,
    void,
    OneOf<TParentCommand, this>
  >;

  /**
   * Add new sub-command.
   * @param nameAndArguments  Command definition. E.g: `my-command <input-file:string> <output-file:string>`
   * @param cmdOrDescription  The description of the new child command.
   * @param override          Override existing child command.
   */
  command(
    nameAndArguments: string,
    cmdOrDescription?: Command<any> | string,
    override?: boolean,
  ): Command<any> {
    this.reset();

    const result = splitArguments(nameAndArguments);

    const name: string | undefined = result.flags.shift();
    const aliases: string[] = result.flags;

    if (!name) {
      throw new MissingCommandNameError();
    }

    if (this.getBaseCommand(name, true)) {
      if (!override) {
        throw new DuplicateCommandNameError(name);
      }
      this.removeCommand(name);
    }

    let description: string | undefined;
    let cmd: Command<any>;

    if (typeof cmdOrDescription === "string") {
      description = cmdOrDescription;
    }

    if (cmdOrDescription instanceof Command) {
      cmd = cmdOrDescription.reset();
    } else {
      cmd = new Command();
    }

    cmd._name = name;
    cmd._parent = this;

    if (description) {
      cmd.description(description);
    }

    if (result.typeDefinition) {
      cmd.arguments(result.typeDefinition);
    }

    aliases.forEach((alias: string) => cmd.alias(alias));

    this.commands.set(name, cmd);

    this.select(name);

    return this;
  }

  /**
   * Add new command alias.
   *
   * @param alias Tha name of the alias.
   */
  public alias(alias: string): this {
    if (this.cmd._name === alias || this.cmd.aliases.includes(alias)) {
      throw new DuplicateCommandAliasError(alias);
    }

    this.cmd.aliases.push(alias);

    return this;
  }

  /** Reset internal command reference to main command. */
  public reset(): OneOf<TParentCommand, this> {
    this._groupName = null;
    this.cmd = this;
    return this as OneOf<TParentCommand, this>;
  }

  /**
   * Set internal command pointer to child command with given name.
   * @param name The name of the command to select.
   */
  public select<
    TOptions extends Record<string, unknown> | void = any,
    TArguments extends Array<unknown> = any,
    TGlobalOptions extends Record<string, unknown> | void = any,
  >(
    name: string,
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    TOptions,
    TArguments,
    TGlobalOptions,
    TCommandTypes,
    TCommandGlobalTypes,
    TParentCommand
  > {
    const cmd = this.getBaseCommand(name, true);

    if (!cmd) {
      throw new CommandNotFoundError(name, this.getBaseCommands(true));
    }

    this.cmd = cmd;

    return this as Command<any>;
  }

  /*****************************************************************************
   **** SUB HANDLER ************************************************************
   *****************************************************************************/

  /** Set command name. Used in auto generated help and shell completions */
  public name(name: string): this {
    this.cmd._name = name;
    return this;
  }

  /**
   * Set command version.
   *
   * @param version Semantic version string string or method that returns the version string.
   */
  public version(
    version:
      | string
      | VersionHandler<
        Partial<TCommandOptions>,
        Partial<TCommandArguments>,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >,
  ): this {
    if (typeof version === "string") {
      this.cmd.ver = () => version;
    } else if (typeof version === "function") {
      this.cmd.ver = version;
    }
    return this;
  }

  /**
   * Add meta data. Will be displayed in the auto generated help and in the
   * output of the long version.
   *
   * @param name  The name/label of the metadata.
   * @param value The value of the metadata.
   */
  public meta(name: string, value: string): this {
    this.cmd._meta[name] = value;
    return this;
  }

  /** Returns an object of metadata. */
  public getMeta(): Record<string, string>;

  /** Get metadata value by name. */
  public getMeta(name: string): string;

  public getMeta(name?: string): Record<string, string> | string {
    return typeof name === "undefined" ? this._meta : this._meta[name];
  }

  /**
   * Set command help.
   *
   * @param help Help string, method, or config for generator that returns the help string.
   */
  public help(
    help:
      | string
      | HelpHandler<
        Partial<TCommandOptions>,
        Partial<TCommandArguments>,
        TCommandGlobals,
        TParentCommandGlobals
      >
      | HelpOptions,
  ): this {
    if (typeof help === "string") {
      this.cmd._help = () => help;
    } else if (typeof help === "function") {
      this.cmd._help = help;
    } else {
      this.cmd._help = (cmd: Command, options: HelpOptions): string =>
        HelpGenerator.generate(cmd, { ...help, ...options });
    }
    return this;
  }

  /**
   * Set the long command description.
   *
   * @param description The command description.
   */
  public description(
    description: Description<
      TCommandOptions,
      TCommandArguments,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      TParentCommand
    >,
  ): this {
    this.cmd.desc = description;
    return this;
  }

  /**
   * Set the command usage. Defaults to arguments.
   *
   * @param usage The command usage.
   */
  public usage(usage: string): this {
    this.cmd._usage = usage;
    return this;
  }

  /** Hide command from help, completions, etc. */
  public hidden(): this {
    this.cmd.isHidden = true;
    return this;
  }

  /** Make command globally available. */
  public global(): this {
    this.cmd.isGlobal = true;
    return this;
  }

  /**
   * Set command arguments.
   *
   * Syntax: `<requiredArg:string> [optionalArg: number] [...restArgs:string]`
   */
  public arguments<
    TArguments extends TypedArguments<
      TArgs,
      Merge<TParentCommandTypes, Merge<TCommandGlobalTypes, TCommandTypes>>
    >,
    TArgs extends string = string,
  >(
    args: TArgs,
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    TCommandOptions,
    TArguments,
    TCommandGlobals,
    TCommandTypes,
    TCommandGlobalTypes,
    TParentCommand
  > {
    this.cmd.argsDefinition = args;
    return this as Command<any>;
  }

  /**
   * Set command callback method.
   *
   * @param fn Command action handler.
   */
  public action(
    fn: ActionHandler<
      TCommandOptions,
      TCommandArguments,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      TParentCommand
    >,
  ): this {
    this.cmd.actionHandler = fn;
    return this;
  }

  /**
   * Set command callback method.
   *
   * @param fn Command action handler.
   */
  public globalAction(
    fn: ActionHandler<
      Partial<TCommandOptions>,
      Array<unknown>,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      TParentCommand
    >,
  ): this {
    this.cmd.globalActionHandler = fn;
    return this;
  }

  /**
   * Don't throw an error if the command was called without arguments.
   *
   * @param allowEmpty Enable/disable allow empty.
   */
  public allowEmpty<TAllowEmpty extends boolean | undefined = undefined>(
    allowEmpty?: TAllowEmpty,
  ): false extends TAllowEmpty ? this
    : Command<
      Partial<TParentCommandGlobals>,
      TParentCommandTypes,
      Partial<TCommandOptions>,
      TCommandArguments,
      TCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommand
    > {
    this.cmd._allowEmpty = allowEmpty !== false;
    return this as false extends TAllowEmpty ? this
      : Command<
        Partial<TParentCommandGlobals>,
        TParentCommandTypes,
        Partial<TCommandOptions>,
        TCommandArguments,
        TCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommand
      >;
  }

  /**
   * Enable stop early. If enabled, all arguments starting from the first non
   * option argument will be passed as arguments with type string to the command
   * action handler.
   *
   * For example:
   *     `command --debug-level warning server --port 80`
   *
   * Will result in:
   *     - options: `{ debugLevel: 'warning' }`
   *     - args: `['server', '--port', '80']`
   *
   * @param stopEarly Enable/disable stop early.
   */
  public stopEarly(stopEarly = true): this {
    this.cmd._stopEarly = stopEarly;
    return this;
  }

  /**
   * Disable parsing arguments. If enabled the raw arguments will be passed to
   * the action handler. This has no effect for parent or child commands. Only
   * for the command on which this method was called.
   *
   * @param useRawArgs Enable/disable raw arguments.
   */
  public useRawArgs(
    useRawArgs = true,
  ): Command<
    void,
    void,
    void,
    Array<string>,
    void,
    void,
    void,
    TParentCommand
  > {
    this.cmd._useRawArgs = useRawArgs;
    return this as Command<any>;
  }

  /**
   * Set default command. The default command is executed when the program
   * was called without any argument and if no action handler is registered.
   *
   * @param name Name of the default command.
   */
  public default(name: string): this {
    this.cmd.defaultCommand = name;
    return this;
  }

  public globalType<
    THandler extends TypeOrTypeHandler<unknown>,
    TName extends string = string,
  >(
    name: TName,
    handler: THandler,
    options?: Omit<TypeOptions, "global">,
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    TCommandOptions,
    TCommandArguments,
    TCommandGlobals,
    TCommandTypes,
    Merge<TCommandGlobalTypes, TypedType<TName, THandler>>,
    TParentCommand
  > {
    return this.type(name, handler, { ...options, global: true });
  }

  /**
   * Register custom type.
   *
   * @param name    The name of the type.
   * @param handler The callback method to parse the type.
   * @param options Type options.
   */
  public type<
    THandler extends TypeOrTypeHandler<unknown>,
    TName extends string = string,
  >(
    name: TName,
    handler: THandler,
    options?: TypeOptions,
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    TCommandOptions,
    TCommandArguments,
    TCommandGlobals,
    Merge<TCommandTypes, TypedType<TName, THandler>>,
    TCommandGlobalTypes,
    TParentCommand
  > {
    if (this.cmd.types.get(name) && !options?.override) {
      throw new DuplicateTypeError(name);
    }

    this.cmd.types.set(name, {
      ...options,
      name,
      handler: handler as TypeOrTypeHandler<unknown>,
    });

    if (
      handler instanceof Type &&
      (typeof handler.complete !== "undefined" ||
        typeof handler.values !== "undefined")
    ) {
      const completeHandler: CompleteHandler = (
        cmd: Command,
        parent?: Command,
      ) => handler.complete?.(cmd, parent) || [];
      this.complete(name, completeHandler, options);
    }

    return this as Command<any>;
  }

  /**
   * Register global complete handler.
   *
   * @param name      The name of the completion.
   * @param complete  The callback method to complete the type.
   * @param options   Complete options.
   */
  public globalComplete(
    name: string,
    complete: CompleteHandler,
    options?: Omit<CompleteOptions, "global">,
  ): this {
    return this.complete(name, complete, { ...options, global: true });
  }

  /**
   * Register global complete handler.
   *
   * @param name      The name of the completion.
   * @param complete  The callback method to complete the type.
   * @param options   Complete options.
   */
  public complete(
    name: string,
    complete: CompleteHandler<
      Partial<TCommandOptions>,
      Partial<TCommandArguments>,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      any
    >,
    options: CompleteOptions & { global: boolean },
  ): this;

  /**
   * Register complete handler.
   *
   * @param name      The name of the completion.
   * @param complete  The callback method to complete the type.
   * @param options   Complete options.
   */
  public complete(
    name: string,
    complete: CompleteHandler<
      TCommandOptions,
      TCommandArguments,
      TCommandGlobals,
      TParentCommandGlobals,
      TCommandTypes,
      TCommandGlobalTypes,
      TParentCommandTypes,
      TParentCommand
    >,
    options?: CompleteOptions,
  ): this;

  public complete(
    name: string,
    complete:
      | CompleteHandler<
        TCommandOptions,
        TCommandArguments,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
      | CompleteHandler<
        Partial<TCommandOptions>,
        Partial<TCommandArguments>,
        TCommandGlobals,
        TParentCommandGlobals,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        any
      >,
    options?: CompleteOptions,
  ): this {
    if (this.cmd.completions.has(name) && !options?.override) {
      throw new DuplicateCompletionError(name);
    }

    this.cmd.completions.set(name, {
      name,
      complete,
      ...options,
    });

    return this;
  }

  /**
   * Throw validation errors instead of calling `exit()` to handle
   * validation errors manually.
   *
   * A validation error is thrown when the command is wrongly used by the user.
   * For example: If the user passes some invalid options or arguments to the
   * command.
   *
   * This has no effect for parent commands. Only for the command on which this
   * method was called and all child commands.
   *
   * **Example:**
   *
   * ```ts
   * import { Command, ValidationError } from "./mod.ts";
   *
   * const cmd = new Command();
   * // ...
   *
   * try {
   *   cmd.parse();
   * } catch(error) {
   *   if (error instanceof ValidationError) {
   *     cmd.showHelp();
   *     Deno.exit(1);
   *   }
   *   throw error;
   * }
   * ```
   *
   * @see ValidationError
   */
  public throwErrors(): this {
    this.cmd.throwOnError = true;
    return this;
  }

  /**
   * Set custom error handler.
   *
   * @param handler Error handler callback function.
   */
  public error(handler: ErrorHandler): this {
    this.cmd.errorHandler = handler;
    return this;
  }

  /** Get error handler callback function. */
  private getErrorHandler(): ErrorHandler | undefined {
    return this.errorHandler ?? this._parent?.errorHandler;
  }

  /**
   * Same as `.throwErrors()` but also prevents calling `exit()` after
   * printing help or version with the --help and --version option.
   */
  public noExit(): this {
    this.cmd._shouldExit = false;
    this.throwErrors();
    return this;
  }

  /**
   * Disable inheriting global commands, options and environment variables from
   * parent commands.
   */
  public noGlobals(): this {
    this.cmd._noGlobals = true;
    return this;
  }

  /** Check whether the command should throw errors or exit. */
  protected shouldThrowErrors(): boolean {
    return this.throwOnError || !!this._parent?.shouldThrowErrors();
  }

  /** Check whether the command should exit after printing help or version. */
  protected shouldExit(): boolean {
    return this._shouldExit ?? this._parent?.shouldExit() ?? true;
  }

  /**
   * Enable grouping of options and set the name of the group.
   * All option which are added after calling the `.group()` method will be
   * grouped in the help output. If the `.group()` method can be use multiple
   * times to create more groups.
   *
   * @param name The name of the option group.
   */
  public group(name: string | null): this {
    this.cmd._groupName = name;
    return this;
  }

  /**
   * Register a global option.
   *
   * @param flags Flags string e.g: -h, --help, --manual <requiredArg:string> [optionalArg:number] [...restArgs:string]
   * @param desc Flag description.
   * @param opts Flag options or custom handler for processing flag value.
   */
  public globalOption<
    TFlags extends string,
    TGlobalOptions extends TypedOption<
      TFlags,
      TCommandOptions,
      Merge<TParentCommandTypes, Merge<TCommandGlobalTypes, TCommandTypes>>,
      undefined extends TConflicts ? TRequired : false,
      TDefaultValue
    >,
    TMappedGlobalOptions extends MapValue<
      TGlobalOptions,
      TMappedValue,
      TCollect
    >,
    TRequired extends OptionOptions["required"] = undefined,
    TCollect extends OptionOptions["collect"] = undefined,
    TConflicts extends OptionOptions["conflicts"] = undefined,
    const TDefaultValue = undefined,
    TMappedValue = undefined,
  >(
    flags: TFlags,
    desc: string,
    opts?:
      | Omit<
        GlobalOptionOptions<
          Partial<TCommandOptions>,
          TCommandArguments,
          MergeOptions<TFlags, TCommandGlobals, TGlobalOptions>,
          TParentCommandGlobals,
          TCommandTypes,
          TCommandGlobalTypes,
          TParentCommandTypes,
          TParentCommand
        >,
        "value"
      >
        & {
          default?: DefaultValue<TDefaultValue>;
          required?: TRequired;
          collect?: TCollect;
          value?: OptionValueHandler<
            MapTypes<ValueOf<TGlobalOptions>>,
            TMappedValue
          >;
        }
      | OptionValueHandler<MapTypes<ValueOf<TGlobalOptions>>, TMappedValue>,
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    TCommandOptions,
    TCommandArguments,
    MergeOptions<TFlags, TCommandGlobals, TMappedGlobalOptions>,
    TCommandTypes,
    TCommandGlobalTypes,
    TParentCommand
  > {
    if (typeof opts === "function") {
      return this.option(
        flags,
        desc,
        { value: opts, global: true } as OptionOptions,
      ) as Command<any>;
    }
    return this.option(
      flags,
      desc,
      { ...opts, global: true } as OptionOptions,
    ) as Command<any>;
  }

  /**
   * Add a global option.
   *
   * @param flags Flags string e.g: -h, --help, --manual <requiredArg:string> [optionalArg:number] [...restArgs:string]
   * @param desc Flag description.
   * @param opts Flag options or custom handler for processing flag value.
   */
  public option<
    TFlags extends string,
    TGlobalOptions extends TypedOption<
      TFlags,
      TCommandOptions,
      Merge<TParentCommandTypes, Merge<TCommandGlobalTypes, TCommandTypes>>,
      undefined extends TConflicts ? TRequired : false,
      TDefaultValue
    >,
    TMappedGlobalOptions extends MapValue<
      TGlobalOptions,
      TMappedValue,
      TCollect
    >,
    TRequired extends OptionOptions["required"] = undefined,
    TCollect extends OptionOptions["collect"] = undefined,
    TConflicts extends OptionOptions["conflicts"] = undefined,
    const TDefaultValue = undefined,
    TMappedValue = undefined,
  >(
    flags: TFlags,
    desc: string,
    opts:
      | Omit<
        OptionOptions<
          Partial<TCommandOptions>,
          TCommandArguments,
          MergeOptions<TFlags, TCommandGlobals, TGlobalOptions>,
          TParentCommandGlobals,
          TCommandTypes,
          TCommandGlobalTypes,
          TParentCommandTypes,
          TParentCommand
        >,
        "value"
      >
        & {
          global: true;
          default?: DefaultValue<TDefaultValue>;
          required?: TRequired;
          collect?: TCollect;
          value?: OptionValueHandler<
            MapTypes<ValueOf<TGlobalOptions>>,
            TMappedValue
          >;
        }
      | OptionValueHandler<MapTypes<ValueOf<TGlobalOptions>>, TMappedValue>,
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    TCommandOptions,
    TCommandArguments,
    MergeOptions<TFlags, TCommandGlobals, TMappedGlobalOptions>,
    TCommandTypes,
    TCommandGlobalTypes,
    TParentCommand
  >;

  /**
   * Register an option.
   *
   * @param flags Flags string e.g: -h, --help, --manual <requiredArg:string> [optionalArg:number] [...restArgs:string]
   * @param desc Flag description.
   * @param opts Flag options or custom handler for processing flag value.
   */
  public option<
    TFlags extends string,
    TOptions extends TypedOption<
      TFlags,
      TCommandOptions,
      Merge<TParentCommandTypes, Merge<TCommandGlobalTypes, TCommandTypes>>,
      undefined extends TConflicts ? TRequired : false,
      TDefaultValue
    >,
    TMappedOptions extends MapValue<TOptions, TMappedValue, TCollect>,
    TRequired extends OptionOptions["required"] = undefined,
    TCollect extends OptionOptions["collect"] = undefined,
    TConflicts extends OptionOptions["conflicts"] = undefined,
    const TDefaultValue = undefined,
    TMappedValue = undefined,
  >(
    flags: TFlags,
    desc: string,
    opts?:
      | Omit<
        OptionOptions<
          MergeOptions<TFlags, TCommandOptions, TMappedOptions>,
          TCommandArguments,
          TCommandGlobals,
          TParentCommandGlobals,
          TCommandTypes,
          TCommandGlobalTypes,
          TParentCommandTypes,
          TParentCommand
        >,
        "value"
      >
        & {
          default?: DefaultValue<TDefaultValue>;
          required?: TRequired;
          collect?: TCollect;
          conflicts?: TConflicts;
          value?: OptionValueHandler<MapTypes<ValueOf<TOptions>>, TMappedValue>;
        }
      | OptionValueHandler<MapTypes<ValueOf<TOptions>>, TMappedValue>,
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    MergeOptions<TFlags, TCommandOptions, TMappedOptions>,
    TCommandArguments,
    TCommandGlobals,
    TCommandTypes,
    TCommandGlobalTypes,
    TParentCommand
  >;

  public option(
    flags: string,
    desc: string,
    opts?: OptionOptions | OptionValueHandler,
  ): Command<any> {
    if (typeof opts === "function") {
      opts = { value: opts };
    }

    const result = splitArguments(flags);

    const args: Argument[] = result.typeDefinition
      ? parseArgumentsDefinition(result.typeDefinition)
      : [];

    const option: Option = {
      ...opts,
      name: "",
      description: desc,
      args,
      flags: result.flags,
      equalsSign: result.equalsSign,
      typeDefinition: result.typeDefinition,
      groupName: this._groupName ?? undefined,
    };

    if (option.separator) {
      for (const arg of args) {
        if (arg.list) {
          arg.separator = option.separator;
        }
      }
    }

    for (const part of option.flags) {
      const arg = part.trim();
      const isLong = /^--/.test(arg);
      const name = isLong ? arg.slice(2) : arg.slice(1);

      if (this.cmd.getBaseOption(name, true)) {
        if (opts?.override) {
          this.removeOption(name);
        } else {
          throw new DuplicateOptionNameError(name, this.getPath());
        }
      }

      if (!option.name && isLong) {
        option.name = name;
      } else if (!option.aliases) {
        option.aliases = [name];
      } else {
        option.aliases.push(name);
      }
    }

    if (option.prepend) {
      this.cmd.options.unshift(option);
    } else {
      this.cmd.options.push(option);
    }

    return this;
  }

  /**
   * Register command example.
   *
   * @param name          Name of the example.
   * @param description   The content of the example.
   */
  public example(name: string, description: string): this {
    if (this.cmd.hasExample(name)) {
      throw new DuplicateExampleError(name);
    }

    this.cmd.examples.push({ name, description });

    return this;
  }

  /**
   * @param flags Flags string e.g: -h, --help, --manual <requiredArg:string> [optionalArg:number] [...restArgs:string]
   * @param desc Flag description.
   * @param opts Flag options or custom handler for processing flag value.
   */

  /**
   * Register a global environment variable.
   *
   * @param name        Name of the environment variable.
   * @param description The description of the environment variable.
   * @param options     Environment variable options.
   */
  public globalEnv<
    TNameAndValue extends string,
    TGlobalEnvVars extends TypedEnv<
      TNameAndValue,
      TPrefix,
      TCommandOptions,
      Merge<TParentCommandTypes, Merge<TCommandGlobalTypes, TCommandTypes>>,
      TRequired
    >,
    TMappedGlobalEnvVars extends MapValue<TGlobalEnvVars, TMappedValue>,
    TRequired extends EnvVarOptions["required"] = undefined,
    TPrefix extends EnvVarOptions["prefix"] = undefined,
    TMappedValue = undefined,
  >(
    name: TNameAndValue,
    description: string,
    options?: Omit<GlobalEnvVarOptions, "value"> & {
      required?: TRequired;
      prefix?: TPrefix;
      value?: EnvVarValueHandler<
        MapTypes<ValueOf<TGlobalEnvVars>>,
        TMappedValue
      >;
    },
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    TCommandOptions,
    TCommandArguments,
    Merge<TCommandGlobals, TMappedGlobalEnvVars>,
    TCommandTypes,
    TCommandGlobalTypes,
    TParentCommand
  > {
    return this.env(
      name,
      description,
      { ...options, global: true } as EnvVarOptions,
    ) as Command<any>;
  }

  /**
   * Register a global environment variable.
   *
   * @param name        Name of the environment variable.
   * @param description The description of the environment variable.
   * @param options     Environment variable options.
   */
  public env<
    N extends string,
    G extends TypedEnv<
      N,
      P,
      TCommandOptions,
      Merge<TParentCommandTypes, Merge<TCommandGlobalTypes, TCommandTypes>>,
      R
    >,
    MG extends MapValue<G, V>,
    R extends EnvVarOptions["required"] = undefined,
    P extends EnvVarOptions["prefix"] = undefined,
    V = undefined,
  >(
    name: N,
    description: string,
    options: Omit<EnvVarOptions, "value"> & {
      global: true;
      required?: R;
      prefix?: P;
      value?: EnvVarValueHandler<MapTypes<ValueOf<G>>, V>;
    },
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    TCommandOptions,
    TCommandArguments,
    Merge<TCommandGlobals, MG>,
    TCommandTypes,
    TCommandGlobalTypes,
    TParentCommand
  >;

  /**
   * Register an environment variable.
   *
   * @param name        Name of the environment variable.
   * @param description The description of the environment variable.
   * @param options     Environment variable options.
   */
  public env<
    TNameAndValue extends string,
    TEnvVar extends TypedEnv<
      TNameAndValue,
      TPrefix,
      TCommandOptions,
      Merge<TParentCommandTypes, Merge<TCommandGlobalTypes, TCommandTypes>>,
      TRequired
    >,
    TMappedEnvVar extends MapValue<TEnvVar, TMappedValue>,
    TRequired extends EnvVarOptions["required"] = undefined,
    TPrefix extends EnvVarOptions["prefix"] = undefined,
    TMappedValue = undefined,
  >(
    name: TNameAndValue,
    description: string,
    options?: Omit<EnvVarOptions, "value"> & {
      required?: TRequired;
      prefix?: TPrefix;
      value?: EnvVarValueHandler<MapTypes<ValueOf<TEnvVar>>, TMappedValue>;
    },
  ): Command<
    TParentCommandGlobals,
    TParentCommandTypes,
    Merge<TCommandOptions, TMappedEnvVar>,
    TCommandArguments,
    TCommandGlobals,
    TCommandTypes,
    TCommandGlobalTypes,
    TParentCommand
  >;

  public env(
    name: string,
    description: string,
    options?: EnvVarOptions,
  ): Command<any> {
    const result = splitArguments(name);

    if (!result.typeDefinition) {
      result.typeDefinition = "<value:boolean>";
    }

    if (result.flags.some((envName) => this.cmd.getBaseEnvVar(envName, true))) {
      throw new DuplicateEnvVarError(name);
    }

    const details: Argument[] = parseArgumentsDefinition(
      result.typeDefinition,
    );

    if (details.length > 1) {
      throw new TooManyEnvVarValuesError(name);
    } else if (details.length && details[0].optional) {
      throw new UnexpectedOptionalEnvVarValueError(name);
    } else if (details.length && details[0].variadic) {
      throw new UnexpectedVariadicEnvVarValueError(name);
    }

    this.cmd.envVars.push({
      name: result.flags[0],
      names: result.flags,
      description,
      type: details[0].type,
      details: details.shift() as Argument,
      ...options,
    });

    return this;
  }

  /*****************************************************************************
   **** MAIN HANDLER ***********************************************************
   *****************************************************************************/

  /**
   * Parse command line arguments and execute matched command.
   *
   * @param args Command line args to parse. Ex: `cmd.parse( Deno.args )`
   */
  public parse(
    args: string[] = getArgs(),
  ): Promise<
    TParentCommand extends Command<any> ? CommandResult<
        Record<string, unknown>,
        Array<unknown>,
        Record<string, unknown>,
        Record<string, unknown>,
        Record<string, unknown>,
        Record<string, unknown>,
        Record<string, unknown>,
        undefined
      >
      : CommandResult<
        MapTypes<TCommandOptions>,
        MapTypes<TCommandArguments>,
        MapTypes<TCommandGlobals>,
        MapTypes<TParentCommandGlobals>,
        TCommandTypes,
        TCommandGlobalTypes,
        TParentCommandTypes,
        TParentCommand
      >
  > {
    const ctx: ParseContext = {
      unknown: args.slice(),
      flags: {},
      env: {},
      literal: [],
      stopEarly: false,
      stopOnUnknown: false,
      defaults: {},
      actions: [],
    };
    return this.parseCommand(ctx) as any;
  }

  private async parseCommand(ctx: ParseContext): Promise<CommandResult> {
    try {
      this.reset();
      this.registerDefaults();
      this.rawArgs = ctx.unknown.slice();

      if (this._useRawArgs) {
        await this.parseEnvVars(ctx, this.envVars);
        return await this.execute(ctx.env, ctx.unknown);
      }

      let preParseGlobals = false;
      let subCommand: Command<any> | undefined;

      // Pre parse globals to support: cmd --global-option sub-command --option
      if (ctx.unknown.length > 0) {
        // Detect sub command.
        subCommand = this.getSubCommand(ctx);

        if (!subCommand) {
          // Only pre parse globals if first arg ist a global option.
          const optionName = ctx.unknown[0].replace(/^-+/, "");
          const option = this.getOption(optionName, true);

          if (option?.global) {
            preParseGlobals = true;
            await this.parseGlobalOptionsAndEnvVars(ctx);
          }
        }
      }

      if (subCommand || ctx.unknown.length > 0) {
        subCommand ??= this.getSubCommand(ctx);

        if (subCommand) {
          subCommand._globalParent = this;
          return subCommand.parseCommand(ctx);
        }
      }

      // Parse rest options & env vars.
      await this.parseOptionsAndEnvVars(ctx, preParseGlobals);
      const options = { ...ctx.env, ...ctx.flags };
      const args = this.parseArguments(ctx, options);
      this.literalArgs = ctx.literal;

      // Execute option action.
      if (ctx.actions.length) {
        await Promise.all(
          ctx.actions.map((action) => action.call(this, options, ...args)),
        );

        if (ctx.standalone) {
          return {
            options,
            args,
            cmd: this,
            literal: this.literalArgs,
          };
        }
      }

      return await this.execute(options, args);
    } catch (error: unknown) {
      this.handleError(error);
    }
  }

  private getSubCommand(ctx: ParseContext) {
    const subCommand = this.getCommand(ctx.unknown[0], true);

    if (subCommand) {
      ctx.unknown.shift();
    }

    return subCommand;
  }

  private async parseGlobalOptionsAndEnvVars(
    ctx: ParseContext,
  ): Promise<void> {
    const isHelpOption = this.getHelpOption()?.flags.includes(ctx.unknown[0]);

    // Parse global env vars.
    const envVars = [
      ...this.envVars.filter((envVar) => envVar.global),
      ...this.getGlobalEnvVars(true),
    ];

    await this.parseEnvVars(ctx, envVars, !isHelpOption);

    // Parse global options.
    const options = [
      ...this.options.filter((option) => option.global),
      ...this.getGlobalOptions(true),
    ];

    this.parseOptions(ctx, options, {
      stopEarly: true,
      stopOnUnknown: true,
      dotted: false,
    });
  }

  private async parseOptionsAndEnvVars(
    ctx: ParseContext,
    preParseGlobals: boolean,
  ): Promise<void> {
    const helpOption = this.getHelpOption();
    const isVersionOption = this._versionOption?.flags.includes(ctx.unknown[0]);
    const isHelpOption = helpOption && ctx.flags?.[helpOption.name] === true;

    // Parse env vars.
    const envVars = preParseGlobals
      ? this.envVars.filter((envVar) => !envVar.global)
      : this.getEnvVars(true);

    await this.parseEnvVars(
      ctx,
      envVars,
      !isHelpOption && !isVersionOption,
    );

    // Parse options.
    const options = this.getOptions(true);

    this.parseOptions(ctx, options);
  }

  /** Register default options like `--version` and `--help`. */
  private registerDefaults(): this {
    if (this.hasDefaults || this.getParent()) {
      return this;
    }
    this.hasDefaults = true;

    this.reset();

    !this.types.has("string") &&
      this.type("string", new StringType(), { global: true });
    !this.types.has("number") &&
      this.type("number", new NumberType(), { global: true });
    !this.types.has("integer") &&
      this.type("integer", new IntegerType(), { global: true });
    !this.types.has("boolean") &&
      this.type("boolean", new BooleanType(), { global: true });
    !this.types.has("file") &&
      this.type("file", new FileType(), { global: true });

    if (!this._help) {
      this.help({});
    }

    if (this._versionOptions !== false && (this._versionOptions || this.ver)) {
      this.option(
        this._versionOptions?.flags || "-V, --version",
        this._versionOptions?.desc ||
          "Show the version number for this program.",
        {
          standalone: true,
          prepend: true,
          action: async function () {
            const long = this.getRawArgs().includes(
              `--${this._versionOption?.name}`,
            );
            if (long) {
              await checkVersion(this);
              this.showLongVersion();
            } else {
              this.showVersion();
            }
            this.exit();
          },
          ...(this._versionOptions?.opts ?? {}),
        },
      );
      this._versionOption = this.options[0];
    }

    if (this._helpOptions !== false) {
      this.option(
        this._helpOptions?.flags || "-h, --help",
        this._helpOptions?.desc || "Show this help.",
        {
          standalone: true,
          global: true,
          prepend: true,
          action: async function () {
            const long = this.getRawArgs().includes(
              `--${this.getHelpOption()?.name}`,
            );
            await checkVersion(this);
            this.showHelp({ long });
            this.exit();
          },
          ...(this._helpOptions?.opts ?? {}),
        },
      );
      this._helpOption = this.options[0];
    }

    return this;
  }

  /**
   * Execute command.
   * @param options A map of options.
   * @param args Command arguments.
   */
  private async execute(
    options: Record<string, unknown>,
    args: Array<unknown>,
  ): Promise<CommandResult> {
    if (this.defaultCommand) {
      const cmd = this.getCommand(this.defaultCommand, true);

      if (!cmd) {
        throw new DefaultCommandNotFoundError(
          this.defaultCommand,
          this.getCommands(),
        );
      }
      cmd._globalParent = this;

      return cmd.execute(options, args);
    }

    await this.executeGlobalAction(options, args);

    if (this.actionHandler) {
      await this.actionHandler(options, ...args);
    }

    return {
      options,
      args,
      cmd: this,
      literal: this.literalArgs,
    };
  }

  private async executeGlobalAction(
    options: Record<string, unknown>,
    args: Array<unknown>,
  ) {
    if (!this._noGlobals) {
      await this._parent?.executeGlobalAction(options, args);
    }
    await this.globalActionHandler?.(options, ...args);
  }

  /** Parse raw command line arguments. */
  protected parseOptions(
    ctx: ParseContext,
    options: Option[],
    {
      stopEarly = this._stopEarly,
      stopOnUnknown = false,
      dotted = true,
    }: ParseOptionsOptions = {},
  ): void {
    parseFlags(ctx, {
      stopEarly,
      stopOnUnknown,
      dotted,
      allowEmpty: this._allowEmpty,
      flags: options,
      ignoreDefaults: ctx.env,
      parse: (type: ArgumentValue) => this.parseType(type),
      option: (option: Option) => {
        if (option.action) {
          ctx.actions.push(option.action);
        }
      },
    });
  }

  /** Parse argument type. */
  protected parseType(type: ArgumentValue): unknown {
    const typeSettings: TypeDef | undefined = this.getType(type.type);

    if (!typeSettings) {
      throw new UnknownTypeError(
        type.type,
        this.getTypes().map((type) => type.name),
      );
    }

    return typeSettings.handler instanceof Type
      ? typeSettings.handler.parse(type)
      : typeSettings.handler(type);
  }

  /**
   * Read and validate environment variables.
   * @param ctx Parse context.
   * @param envVars env vars defined by the command.
   * @param validate when true, throws an error if a required env var is missing.
   */
  protected async parseEnvVars(
    ctx: ParseContext,
    envVars: Array<EnvVar>,
    validate = true,
  ): Promise<void> {
    for (const envVar of envVars) {
      const env = await this.findEnvVar(envVar.names);

      if (env) {
        const parseType = (value: string) => {
          return this.parseType({
            label: "Environment variable",
            type: envVar.type,
            name: env.name,
            value,
          });
        };

        const propertyName = underscoreToCamelCase(
          envVar.prefix
            ? envVar.names[0].replace(new RegExp(`^${envVar.prefix}`), "")
            : envVar.names[0],
        );

        if (envVar.details.list) {
          ctx.env[propertyName] = env.value
            .split(envVar.details.separator ?? ",")
            .map(parseType);
        } else {
          ctx.env[propertyName] = parseType(env.value);
        }

        if (envVar.value && typeof ctx.env[propertyName] !== "undefined") {
          ctx.env[propertyName] = envVar.value(ctx.env[propertyName]);
        }
      } else if (envVar.required && validate) {
        throw new MissingRequiredEnvVarError(envVar);
      }
    }
  }

  protected async findEnvVar(
    names: readonly string[],
  ): Promise<{ name: string; value: string } | undefined> {
    for (const name of names) {
      const status = await (globalThis as any).Deno?.permissions.query({
        name: "env",
        variable: name,
      });

      if (!status || status.state === "granted") {
        const value = getEnv(name);

        if (value) {
          return { name, value };
        }
      }
    }

    return undefined;
  }

  /**
   * Parse command-line arguments.
   * @param ctx     Parse context.
   * @param options Parsed command line options.
   */
  protected parseArguments(
    ctx: ParseContext,
    options: Record<string, unknown>,
  ): TCommandArguments {
    const params: Array<unknown> = [];
    const args = ctx.unknown.slice();

    if (!this.hasArguments()) {
      if (args.length) {
        if (this.hasCommands(true)) {
          if (this.hasCommand(args[0], true)) {
            // e.g: command --global-foo --foo sub-command
            throw new TooManyArgumentsError(args);
          } else {
            throw new UnknownCommandError(args[0], this.getCommands());
          }
        } else {
          throw new NoArgumentsAllowedError(this.getPath());
        }
      }
    } else {
      if (!args.length) {
        const required = this.getArguments()
          .filter((expectedArg) => !expectedArg.optional)
          .map((expectedArg) => expectedArg.name);

        if (required.length) {
          const optionNames: string[] = Object.keys(options);
          const hasStandaloneOption = !!optionNames.find((name) =>
            this.getOption(name, true)?.standalone
          );

          if (!hasStandaloneOption) {
            throw new MissingArgumentsError(required);
          }
        }
      } else {
        for (const expectedArg of this.getArguments()) {
          if (!args.length) {
            if (expectedArg.optional) {
              break;
            }
            throw new MissingArgumentError(expectedArg.name);
          }

          let arg: unknown;

          const parseArgValue = (value: string) => {
            return expectedArg.list
              ? value.split(",").map((value) => parseArgType(value))
              : parseArgType(value);
          };

          const parseArgType = (value: string) => {
            return this.parseType({
              label: "Argument",
              type: expectedArg.type,
              name: expectedArg.name,
              value,
            });
          };

          if (expectedArg.variadic) {
            arg = args.splice(0, args.length).map((value) =>
              parseArgValue(value)
            );
          } else {
            arg = parseArgValue(args.shift() as string);
          }

          if (expectedArg.variadic && Array.isArray(arg)) {
            params.push(...arg);
          } else if (typeof arg !== "undefined") {
            params.push(arg);
          }
        }

        if (args.length) {
          throw new TooManyArgumentsError(args);
        }
      }
    }

    return params as TCommandArguments;
  }

  private handleError(error: unknown): never {
    this.throw(
      error instanceof FlagsValidationError
        ? new ValidationError(error.message)
        : error instanceof Error
        ? error
        : new Error(`[non-error-thrown] ${error}`),
    );
  }

  /**
   * Handle error. If `throwErrors` is enabled the error will be thrown,
   * otherwise a formatted error message will be printed and `exit(1)`
   * will be called. This will also trigger registered error handlers.
   *
   * @param error The error to handle.
   */
  public throw(error: Error): never {
    if (error instanceof ValidationError) {
      error.cmd = this as unknown as Command;
    }
    this.getErrorHandler()?.(error, this as unknown as Command);

    if (this.shouldThrowErrors() || !(error instanceof ValidationError)) {
      throw error;
    }
    this.showHelp();

    console.error(red(`  ${bold("error")}: ${error.message}\n`));

    exit(error instanceof ValidationError ? error.exitCode : 1);
  }

  /*****************************************************************************
   **** GETTER *****************************************************************
   *****************************************************************************/

  /** Get command name. */
  public getName(): string {
    return this._name;
  }

  /** Get parent command. */
  public getParent(): TParentCommand {
    return this._parent as TParentCommand;
  }

  /**
   * Get parent command from global executed command.
   * Be sure, to call this method only inside an action handler. Unless this or any child command was executed,
   * this method returns always undefined.
   */
  public getGlobalParent(): Command<any> | undefined {
    return this._globalParent;
  }

  /** Get main command. */
  public getMainCommand(): Command<any> {
    return this._parent?.getMainCommand() ?? this;
  }

  /** Get command name aliases. */
  public getAliases(): string[] {
    return this.aliases;
  }

  /**
   * Get full command path.
   *
   * @param name Override the main command name.
   */
  public getPath(name?: string): string {
    return this._parent
      ? this._parent.getPath(name) + " " + this._name
      : name || this._name;
  }

  /** Get arguments definition. E.g: <input-file:string> <output-file:string> */
  public getArgsDefinition(): string | undefined {
    return this.argsDefinition;
  }

  /**
   * Get argument by name.
   *
   * @param name Name of the argument.
   */
  public getArgument(name: string): Argument | undefined {
    return this.getArguments().find((arg) => arg.name === name);
  }

  /** Get arguments. */
  public getArguments(): Argument[] {
    if (!this.args.length && this.argsDefinition) {
      this.args = parseArgumentsDefinition(this.argsDefinition);
    }

    return this.args;
  }

  /** Check if command has arguments. */
  public hasArguments(): boolean {
    return !!this.argsDefinition;
  }

  /** Get command version. */
  public getVersion(): string | undefined {
    return this.getVersionHandler()?.call(this, this);
  }

  /** Get help handler method. */
  private getVersionHandler(): VersionHandler | undefined {
    return this.ver ?? this._parent?.getVersionHandler();
  }

  /** Get command description. */
  public getDescription(): string {
    // call description method only once
    return typeof this.desc === "function"
      ? this.desc = this.desc()
      : this.desc;
  }

  /** Get auto generated command usage. */
  public getUsage(): string {
    return this._usage ??
      [this.getArgsDefinition(), this.getRequiredOptionsDefinition()]
        .join(" ")
        .trim();
  }

  private getRequiredOptionsDefinition() {
    return this.getOptions()
      .filter((option) => option.required)
      .map((option) =>
        [findFlag(option.flags), option.typeDefinition].filter((v) => v)
          .join(" ")
          .trim()
      )
      .join(" ");
  }

  /** Get short command description. This is the first line of the description. */
  public getShortDescription(): string {
    return getDescription(this.getDescription(), true);
  }

  /** Get original command-line arguments. */
  public getRawArgs(): string[] {
    return this.rawArgs;
  }

  /** Get all arguments defined after the double dash. */
  public getLiteralArgs(): string[] {
    return this.literalArgs;
  }

  /** Output generated help without exiting. */
  public showVersion(): void {
    console.log(this.getVersion());
  }

  /** Returns command name, version and meta data. */
  public getLongVersion(): string {
    return `${bold(this.getMainCommand().getName())} ${
      brightBlue(this.getVersion() ?? "")
    }` +
      Object.entries(this.getMeta()).map(
        ([k, v]) => `\n${bold(k)} ${brightBlue(v)}`,
      ).join("");
  }

  /** Outputs command name, version and meta data. */
  public showLongVersion(): void {
    console.log(this.getLongVersion());
  }

  /** Output generated help without exiting. */
  public showHelp(options?: HelpOptions): void {
    console.log(this.getHelp(options));
  }

  /** Get generated help. */
  public getHelp(options?: HelpOptions): string {
    this.registerDefaults();
    return this.getHelpHandler().call(this, this, options ?? {});
  }

  /** Get help handler method. */
  private getHelpHandler(): HelpHandler {
    return this._help ?? this._parent?.getHelpHandler() as HelpHandler;
  }

  private exit(code = 0) {
    if (this.shouldExit()) {
      exit(code);
    }
  }

  /*****************************************************************************
   **** Options GETTER *********************************************************
   *****************************************************************************/

  /**
   * Checks whether the command has options or not.
   *
   * @param hidden Include hidden options.
   */
  public hasOptions(hidden?: boolean): boolean {
    return this.getOptions(hidden).length > 0;
  }

  /**
   * Get options.
   *
   * @param hidden Include hidden options.
   */
  public getOptions(hidden?: boolean): Option[] {
    return this.getGlobalOptions(hidden).concat(this.getBaseOptions(hidden));
  }

  /**
   * Get base options.
   *
   * @param hidden Include hidden options.
   */
  public getBaseOptions(hidden?: boolean): Option[] {
    if (!this.options.length) {
      return [];
    }

    return hidden
      ? this.options.slice(0)
      : this.options.filter((opt) => !opt.hidden);
  }

  /**
   * Get global options.
   *
   * @param hidden Include hidden options.
   */
  public getGlobalOptions(hidden?: boolean): Option[] {
    const helpOption = this.getHelpOption();
    const getGlobals = (
      cmd: Command<any>,
      noGlobals: boolean,
      options: Option[] = [],
      names: string[] = [],
    ): Option[] => {
      if (cmd.options.length) {
        for (const option of cmd.options) {
          if (
            option.global &&
            !this.options.find((opt) => opt.name === option.name) &&
            names.indexOf(option.name) === -1 &&
            (hidden || !option.hidden)
          ) {
            if (noGlobals && option !== helpOption) {
              continue;
            }

            names.push(option.name);
            options.push(option);
          }
        }
      }

      return cmd._parent
        ? getGlobals(
          cmd._parent,
          noGlobals || cmd._noGlobals,
          options,
          names,
        )
        : options;
    };

    return this._parent ? getGlobals(this._parent, this._noGlobals) : [];
  }

  /**
   * Checks whether the command has an option with given name or not.
   *
   * @param name Name of the option. Must be in param-case.
   * @param hidden Include hidden options.
   */
  public hasOption(name: string, hidden?: boolean): boolean {
    return !!this.getOption(name, hidden);
  }

  /**
   * Get option by name.
   *
   * @param name Name of the option. Must be in param-case.
   * @param hidden Include hidden options.
   */
  public getOption(name: string, hidden?: boolean): Option | undefined {
    return this.getBaseOption(name, hidden) ??
      this.getGlobalOption(name, hidden);
  }

  /**
   * Get base option by name.
   *
   * @param name Name of the option. Must be in param-case.
   * @param hidden Include hidden options.
   */
  public getBaseOption(name: string, hidden?: boolean): Option | undefined {
    const option = this.options.find((option) =>
      option.name === name || option.aliases?.includes(name)
    );

    return option && (hidden || !option.hidden) ? option : undefined;
  }

  /**
   * Get global option from parent commands by name.
   *
   * @param name Name of the option. Must be in param-case.
   * @param hidden Include hidden options.
   */
  public getGlobalOption(name: string, hidden?: boolean): Option | undefined {
    const helpOption = this.getHelpOption();
    const getGlobalOption = (
      parent: Command,
      noGlobals: boolean,
    ): Option | undefined => {
      const option: Option | undefined = parent.getBaseOption(
        name,
        hidden,
      );

      if (!option?.global) {
        return parent._parent && getGlobalOption(
          parent._parent,
          noGlobals || parent._noGlobals,
        );
      }
      if (noGlobals && option !== helpOption) {
        return;
      }

      return option;
    };

    return this._parent && getGlobalOption(
      this._parent,
      this._noGlobals,
    );
  }

  /**
   * Remove option by name.
   *
   * @param name Name of the option. Must be in param-case.
   */
  public removeOption(name: string): Option | undefined {
    const index = this.options.findIndex((option) => option.name === name);

    if (index === -1) {
      return;
    }

    return this.options.splice(index, 1)[0];
  }

  /**
   * Checks whether the command has sub-commands or not.
   *
   * @param hidden Include hidden commands.
   */
  public hasCommands(hidden?: boolean): boolean {
    return this.getCommands(hidden).length > 0;
  }

  /**
   * Get commands.
   *
   * @param hidden Include hidden commands.
   */
  public getCommands(hidden?: boolean): Array<Command<any>> {
    return this.getGlobalCommands(hidden).concat(this.getBaseCommands(hidden));
  }

  /**
   * Get base commands.
   *
   * @param hidden Include hidden commands.
   */
  public getBaseCommands(hidden?: boolean): Array<Command<any>> {
    const commands = Array.from(this.commands.values());
    return hidden ? commands : commands.filter((cmd) => !cmd.isHidden);
  }

  /**
   * Get global commands.
   *
   * @param hidden Include hidden commands.
   */
  public getGlobalCommands(hidden?: boolean): Array<Command<any>> {
    const getCommands = (
      command: Command<any>,
      noGlobals: boolean,
      commands: Array<Command<any>> = [],
      names: string[] = [],
    ): Array<Command<any>> => {
      if (command.commands.size) {
        for (const [_, cmd] of command.commands) {
          if (
            cmd.isGlobal &&
            this !== cmd &&
            !this.commands.has(cmd._name) &&
            names.indexOf(cmd._name) === -1 &&
            (hidden || !cmd.isHidden)
          ) {
            if (noGlobals && cmd?.getName() !== "help") {
              continue;
            }

            names.push(cmd._name);
            commands.push(cmd);
          }
        }
      }

      return command._parent
        ? getCommands(
          command._parent,
          noGlobals || command._noGlobals,
          commands,
          names,
        )
        : commands;
    };

    return this._parent ? getCommands(this._parent, this._noGlobals) : [];
  }

  /**
   * Checks whether a child command exists by given name or alias.
   *
   * @param name Name or alias of the command.
   * @param hidden Include hidden commands.
   */
  public hasCommand(name: string, hidden?: boolean): boolean {
    return !!this.getCommand(name, hidden);
  }

  /**
   * Get command by name or alias.
   *
   * @param name Name or alias of the command.
   * @param hidden Include hidden commands.
   */
  public getCommand<TCommand extends Command<any>>(
    name: string,
    hidden?: boolean,
  ): TCommand | undefined {
    return this.getBaseCommand(name, hidden) ??
      this.getGlobalCommand(name, hidden);
  }

  /**
   * Get base command by name or alias.
   *
   * @param name Name or alias of the command.
   * @param hidden Include hidden commands.
   */
  public getBaseCommand<TCommand extends Command<any>>(
    name: string,
    hidden?: boolean,
  ): TCommand | undefined {
    for (const cmd of this.commands.values()) {
      if (cmd._name === name || cmd.aliases.includes(name)) {
        return (cmd && (hidden || !cmd.isHidden) ? cmd : undefined) as
          | TCommand
          | undefined;
      }
    }
  }

  /**
   * Get global command by name or alias.
   *
   * @param name Name or alias of the command.
   * @param hidden Include hidden commands.
   */
  public getGlobalCommand<TCommand extends Command<any>>(
    name: string,
    hidden?: boolean,
  ): TCommand | undefined {
    const getGlobalCommand = (
      parent: Command,
      noGlobals: boolean,
    ): Command | undefined => {
      const cmd: Command | undefined = parent.getBaseCommand(name, hidden);

      if (!cmd?.isGlobal) {
        return parent._parent &&
          getGlobalCommand(parent._parent, noGlobals || parent._noGlobals);
      }
      if (noGlobals && cmd.getName() !== "help") {
        return;
      }

      return cmd;
    };

    return this._parent &&
      getGlobalCommand(this._parent, this._noGlobals) as TCommand;
  }

  /**
   * Remove sub-command by name or alias.
   *
   * @param name Name or alias of the command.
   */
  public removeCommand(name: string): Command<any> | undefined {
    const command = this.getBaseCommand(name, true);

    if (command) {
      this.commands.delete(command._name);
    }

    return command;
  }

  /** Get types. */
  public getTypes(): Array<TypeDef> {
    return this.getGlobalTypes().concat(this.getBaseTypes());
  }

  /** Get base types. */
  public getBaseTypes(): Array<TypeDef> {
    return Array.from(this.types.values());
  }

  /** Get global types. */
  public getGlobalTypes(): Array<TypeDef> {
    const getTypes = (
      cmd: Command<any> | undefined,
      types: Array<TypeDef> = [],
      names: Array<string> = [],
    ): Array<TypeDef> => {
      if (cmd) {
        if (cmd.types.size) {
          cmd.types.forEach((type: TypeDef) => {
            if (
              type.global &&
              !this.types.has(type.name) &&
              names.indexOf(type.name) === -1
            ) {
              names.push(type.name);
              types.push(type);
            }
          });
        }

        return getTypes(cmd._parent, types, names);
      }

      return types;
    };

    return getTypes(this._parent);
  }

  /**
   * Get type by name.
   *
   * @param name Name of the type.
   */
  public getType(name: string): TypeDef | undefined {
    return this.getBaseType(name) ?? this.getGlobalType(name);
  }

  /**
   * Get base type by name.
   *
   * @param name Name of the type.
   */
  public getBaseType(name: string): TypeDef | undefined {
    return this.types.get(name);
  }

  /**
   * Get global type by name.
   *
   * @param name Name of the type.
   */
  public getGlobalType(name: string): TypeDef | undefined {
    if (!this._parent) {
      return;
    }

    const cmd: TypeDef | undefined = this._parent.getBaseType(name);

    if (!cmd?.global) {
      return this._parent.getGlobalType(name);
    }

    return cmd;
  }

  /** Get completions. */
  public getCompletions(): Completion<
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >[] {
    return this.getGlobalCompletions().concat(this.getBaseCompletions());
  }

  /** Get base completions. */
  public getBaseCompletions(): Completion[] {
    return Array.from(this.completions.values());
  }

  /** Get global completions. */
  public getGlobalCompletions(): Completion[] {
    const getCompletions = (
      cmd: Command<any> | undefined,
      completions: Completion[] = [],
      names: string[] = [],
    ): Completion[] => {
      if (cmd) {
        if (cmd.completions.size) {
          cmd.completions.forEach((completion: Completion) => {
            if (
              completion.global &&
              !this.completions.has(completion.name) &&
              names.indexOf(completion.name) === -1
            ) {
              names.push(completion.name);
              completions.push(completion);
            }
          });
        }

        return getCompletions(cmd._parent, completions, names);
      }

      return completions;
    };

    return getCompletions(this._parent);
  }

  /**
   * Get completion by name.
   *
   * @param name Name of the completion.
   */
  public getCompletion(name: string): Completion | undefined {
    return this.getBaseCompletion(name) ?? this.getGlobalCompletion(name);
  }

  /**
   * Get base completion by name.
   *
   * @param name Name of the completion.
   */
  public getBaseCompletion(name: string): Completion | undefined {
    return this.completions.get(name);
  }

  /**
   * Get global completions by name.
   *
   * @param name Name of the completion.
   */
  public getGlobalCompletion(name: string): Completion | undefined {
    if (!this._parent) {
      return;
    }

    const completion: Completion | undefined = this._parent.getBaseCompletion(
      name,
    );

    if (!completion?.global) {
      return this._parent.getGlobalCompletion(name);
    }

    return completion;
  }

  /**
   * Checks whether the command has environment variables or not.
   *
   * @param hidden Include hidden environment variable.
   */
  public hasEnvVars(hidden?: boolean): boolean {
    return this.getEnvVars(hidden).length > 0;
  }

  /**
   * Get environment variables.
   *
   * @param hidden Include hidden environment variable.
   */
  public getEnvVars(hidden?: boolean): EnvVar[] {
    return this.getGlobalEnvVars(hidden).concat(this.getBaseEnvVars(hidden));
  }

  /**
   * Get base environment variables.
   *
   * @param hidden Include hidden environment variable.
   */
  public getBaseEnvVars(hidden?: boolean): EnvVar[] {
    if (!this.envVars.length) {
      return [];
    }

    return hidden
      ? this.envVars.slice(0)
      : this.envVars.filter((env) => !env.hidden);
  }

  /**
   * Get global environment variables.
   *
   * @param hidden Include hidden environment variable.
   */
  public getGlobalEnvVars(hidden?: boolean): EnvVar[] {
    if (this._noGlobals) {
      return [];
    }

    const getEnvVars = (
      cmd: Command<any> | undefined,
      envVars: EnvVar[] = [],
      names: string[] = [],
    ): EnvVar[] => {
      if (cmd) {
        if (cmd.envVars.length) {
          cmd.envVars.forEach((envVar: EnvVar) => {
            if (
              envVar.global &&
              !this.envVars.find((env) => env.names[0] === envVar.names[0]) &&
              names.indexOf(envVar.names[0]) === -1 &&
              (hidden || !envVar.hidden)
            ) {
              names.push(envVar.names[0]);
              envVars.push(envVar);
            }
          });
        }

        return getEnvVars(cmd._parent, envVars, names);
      }

      return envVars;
    };

    return getEnvVars(this._parent);
  }

  /**
   * Checks whether the command has an environment variable with given name or not.
   *
   * @param name Name of the environment variable.
   * @param hidden Include hidden environment variable.
   */
  public hasEnvVar(name: string, hidden?: boolean): boolean {
    return !!this.getEnvVar(name, hidden);
  }

  /**
   * Get environment variable by name.
   *
   * @param name Name of the environment variable.
   * @param hidden Include hidden environment variable.
   */
  public getEnvVar(name: string, hidden?: boolean): EnvVar | undefined {
    return this.getBaseEnvVar(name, hidden) ??
      this.getGlobalEnvVar(name, hidden);
  }

  /**
   * Get base environment variable by name.
   *
   * @param name Name of the environment variable.
   * @param hidden Include hidden environment variable.
   */
  public getBaseEnvVar(name: string, hidden?: boolean): EnvVar | undefined {
    const envVar: EnvVar | undefined = this.envVars.find((env) =>
      env.names.indexOf(name) !== -1
    );

    return envVar && (hidden || !envVar.hidden) ? envVar : undefined;
  }

  /**
   * Get global environment variable by name.
   *
   * @param name Name of the environment variable.
   * @param hidden Include hidden environment variable.
   */
  public getGlobalEnvVar(name: string, hidden?: boolean): EnvVar | undefined {
    if (!this._parent || this._noGlobals) {
      return;
    }

    const envVar: EnvVar | undefined = this._parent.getBaseEnvVar(
      name,
      hidden,
    );

    if (!envVar?.global) {
      return this._parent.getGlobalEnvVar(name, hidden);
    }

    return envVar;
  }

  /** Checks whether the command has examples or not. */
  public hasExamples(): boolean {
    return this.examples.length > 0;
  }

  /** Get all examples. */
  public getExamples(): Example[] {
    return this.examples;
  }

  /** Checks whether the command has an example with given name or not. */
  public hasExample(name: string): boolean {
    return !!this.getExample(name);
  }

  /** Get example with given name. */
  public getExample(name: string): Example | undefined {
    return this.examples.find((example) => example.name === name);
  }

  private getHelpOption(): Option | undefined {
    return this._helpOption ?? this._parent?.getHelpOption();
  }
}

function findFlag(flags: Array<string>): string {
  for (const flag of flags) {
    if (flag.startsWith("--")) {
      return flag;
    }
  }
  return flags[0];
}

interface DefaultOption {
  flags: string;
  desc?: string;
  opts?: OptionOptions;
}

interface ParseContext extends ParseFlagsContext<Record<string, unknown>> {
  actions: Array<ActionHandler>;
  env: Record<string, unknown>;
}

interface ParseOptionsOptions {
  stopEarly?: boolean;
  stopOnUnknown?: boolean;
  dotted?: boolean;
}
```
less
rest-api
typescript

First Time Repository

TypeScript

Languages:

TypeScript: 16.8KB
Created: 10/5/2024
Updated: 10/5/2024

All Repositories (1)