# How Vite+ Implements the `--no-*` Boolean Flag Pattern in Its CLI

> Discover how Vite+ implements --no-* boolean flags using Clap derive macros. Learn to conditionally skip tooling steps in your CLI commands for greater control.

- Repository: [VoidZero/vite-plus](https://github.com/voidzero-dev/vite-plus)
- Tags: internals
- Published: 2026-03-16

---

**Vite+ defines explicit negative flags (e.g., `--no-fmt`, `--no-lint`) using Clap's derive macros, parsing them into standard `bool` fields that command executors check to conditionally skip specific tooling steps.**

The Vite+ monorepo provides a unified CLI for formatting, linting, and type-checking. To give users granular control over which checks run, the toolkit implements a consistent negatable flag pattern across its Rust-based command structure. This approach leverages the **Clap** crate to declare `--no-*` variants explicitly, ensuring type-safe boolean parsing and automatic help generation without complex custom logic.

## Declaring Negatable Flags with Clap Derive Macros

Vite+ defines CLI arguments through Rust structs using Clap's derive API. For any feature that users might want to disable, the codebase declares an explicit negative flag using the `#[arg(long = "no-<name>")]` attribute. This creates a standard boolean field that defaults to `false` and flips to `true` only when the flag appears on the command line.

In [`packages/cli/binding/src/cli.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/cli.rs), the `Check` command variant demonstrates this pattern for disabling the formatter and linter:

```rust
/// Run format, lint, and type checks
Check {
    /// Auto-fix format and lint issues
    #[arg(long)]
    fix: bool,
    /// Skip format check
    #[arg(long = "no-fmt")]
    no_fmt: bool,
    /// Skip lint check
    #[arg(long = "no-lint")]
    no_lint: bool,
    /// File paths to check (passed through to fmt and lint)
    #[arg(trailing_var_arg = true)]
    paths: Vec<String>,
},

```

*Source:* [`packages/cli/binding/src/cli.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/cli.rs) (lines 112–119)【112†L112-L119】

By declaring `no_fmt` and `no_lint` as distinct boolean fields rather than using optional value parsing (e.g., `--fmt=false`), Vite+ ensures that the generated argument parser treats these as simple presence flags. This eliminates ambiguity and allows Clap to enforce correct usage automatically.

## Handling `--no-*` Flags in Command Execution

The command dispatcher reads these boolean fields to determine which subsystems to execute. In [`packages/cli/binding/src/cli.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/cli.rs), the `execute_direct_subcommand` function matches on the `Check` variant and implements validation logic to prevent users from disabling all available checks simultaneously.

```rust
SynthesizableSubcommand::Check { fix, no_fmt, no_lint, paths } => {
    if no_fmt && no_lint {
        output::error("No checks enabled");
        print_summary_line(
            "`vp check` did not run because both `--no-fmt` and `--no-lint` were set",
        );
        return Ok(ExitStatus(1));
    }

    // ... later in the function ...
    if !no_fmt {
        // run formatting step
    }

    if !no_lint {
        // run linting step
    }
}

```

*Source:* [`packages/cli/binding/src/cli.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/cli.rs) (lines 1010–1030)【1010†L1010-L1030】

This implementation pattern separates **argument parsing** from **business logic**. The Clap-generated code handles string-to-bool conversion and validation (e.g., rejecting unknown flags), while the executor function simply branches on the boolean state. When both `--no-fmt` and `--no-lint` are present, the function uses `output::error` from [`crates/vite_shared/src/output.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/crates/vite_shared/src/output.rs) to print a diagnostic message and returns `ExitStatus(1)` to signal failure.

## Help Output and User Interface

Because Clap derives the argument parser from struct definitions, it automatically generates help text entries for each `--no-*` flag. Vite+ augments this standard output with a unified help formatter located in [`crates/vite_global_cli/src/help.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/crates/vite_global_cli/src/help.rs), which ensures consistent styling across the CLI surface.

The generated help entries appear alongside other options:

```text
--no-fmt   Skip format check
--no-lint  Skip lint check

```

*Source:* [`crates/vite_global_cli/src/help.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/crates/vite_global_cli/src/help.rs) (row definition)【760†L760-L762】

This approach guarantees that documentation stays synchronized with code. When developers add new negatable flags to the struct, Clap updates the help output automatically, requiring no manual edits to string tables or markdown files.

## Summary

- **Explicit declaration**: Negatable flags use `#[arg(long = "no-*")]` attributes in Clap derive macros, creating clear, self-documenting argument names.
- **Boolean parsing**: Flags map directly to `bool` fields (true when present, false otherwise), avoiding complex value parsing logic.
- **Conditional execution**: Command executors in [`packages/cli/binding/src/cli.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/cli.rs) check these booleans to skip specific tooling steps.
- **Validation logic**: The implementation prevents invalid state combinations (e.g., disabling all checks) with early exits and descriptive error messages.
- **Automatic documentation**: Clap generates help text from struct definitions, ensuring flags appear correctly in `--help` output without manual maintenance.

## Frequently Asked Questions

### Why does Vite+ use `--no-*` flags instead of `--flag=false`?

Explicit negative flags provide unambiguous UX and avoid parsing edge cases. Clap handles `--no-fmt` as a simple boolean switch, whereas `--fmt=false` would require value parsing and potential type conversion errors. The `--no-*` pattern also aligns with conventions established by tools like Git and npm.

### Can multiple `--no-*` flags be combined in a single command?

Yes, users can combine flags (e.g., `vp check --no-fmt --no-lint`). However, the executor validates that at least one check remains enabled. If both formatting and linting are disabled, the CLI prints "`No checks enabled`" and exits with status code `1`, preventing no-op executions.

### How does Clap generate help text for these negatable flags?

Clap introspects the struct field names and `#[arg]` attributes to build the help table automatically. The `long = "no-fmt"` string becomes the documented flag name, while the doc comment above the field becomes the description. Custom formatting in [`crates/vite_global_cli/src/help.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/crates/vite_global_cli/src/help.rs) ensures consistent indentation and styling across all subcommands.

### Where is the validation logic for conflicting negatable flags?

The validation resides in the `execute_direct_subcommand` function within [`packages/cli/binding/src/cli.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/cli.rs). Specifically, the code checks `if no_fmt && no_lint` immediately after destructuring the command variant, returning an `ExitStatus(1)` before any tooling processes execute.