Skip to content

Commit 1a17ccd

Browse files
authored
chore: CLI improvements. (#668)
1 parent 84ebcd8 commit 1a17ccd

81 files changed

Lines changed: 1959 additions & 1018 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/vite_global_cli/src/cli.rs

Lines changed: 53 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{
1717
RemoveCommand, UnlinkCommand, UpdateCommand, WhyCommand,
1818
},
1919
error::Error,
20+
help,
2021
};
2122

2223
/// Vite+ Global CLI
@@ -1793,25 +1794,65 @@ pub async fn run_command(cwd: AbsolutePathBuf, args: Args) -> Result<ExitStatus,
17931794
Commands::Migrate { args } => commands::migrate::execute(cwd, &args).await,
17941795

17951796
// Category C: Local CLI Delegation (stubs)
1796-
Commands::Dev { args } => commands::delegate::execute(cwd, "dev", &args).await,
1797+
Commands::Dev { args } => {
1798+
if help::maybe_print_unified_delegate_help("dev", &args) {
1799+
return Ok(ExitStatus::default());
1800+
}
1801+
commands::delegate::execute(cwd, "dev", &args).await
1802+
}
17971803

1798-
Commands::Build { args } => commands::delegate::execute(cwd, "build", &args).await,
1804+
Commands::Build { args } => {
1805+
if help::maybe_print_unified_delegate_help("build", &args) {
1806+
return Ok(ExitStatus::default());
1807+
}
1808+
commands::delegate::execute(cwd, "build", &args).await
1809+
}
17991810

1800-
Commands::Test { args } => commands::delegate::execute(cwd, "test", &args).await,
1811+
Commands::Test { args } => {
1812+
if help::maybe_print_unified_delegate_help("test", &args) {
1813+
return Ok(ExitStatus::default());
1814+
}
1815+
commands::delegate::execute(cwd, "test", &args).await
1816+
}
18011817

1802-
Commands::Lint { args } => commands::delegate::execute(cwd, "lint", &args).await,
1818+
Commands::Lint { args } => {
1819+
if help::maybe_print_unified_delegate_help("lint", &args) {
1820+
return Ok(ExitStatus::default());
1821+
}
1822+
commands::delegate::execute(cwd, "lint", &args).await
1823+
}
18031824

1804-
Commands::Fmt { args } => commands::delegate::execute(cwd, "fmt", &args).await,
1825+
Commands::Fmt { args } => {
1826+
if help::maybe_print_unified_delegate_help("fmt", &args) {
1827+
return Ok(ExitStatus::default());
1828+
}
1829+
commands::delegate::execute(cwd, "fmt", &args).await
1830+
}
18051831

1806-
Commands::Check { args } => commands::delegate::execute(cwd, "check", &args).await,
1832+
Commands::Check { args } => {
1833+
if help::maybe_print_unified_delegate_help("check", &args) {
1834+
return Ok(ExitStatus::default());
1835+
}
1836+
commands::delegate::execute(cwd, "check", &args).await
1837+
}
18071838

1808-
Commands::Pack { args } => commands::delegate::execute(cwd, "pack", &args).await,
1839+
Commands::Pack { args } => {
1840+
if help::maybe_print_unified_delegate_help("pack", &args) {
1841+
return Ok(ExitStatus::default());
1842+
}
1843+
commands::delegate::execute(cwd, "pack", &args).await
1844+
}
18091845

18101846
Commands::Run { args } => commands::run_or_delegate::execute(cwd, &args).await,
18111847

18121848
Commands::Exec { args } => commands::delegate::execute(cwd, "exec", &args).await,
18131849

1814-
Commands::Preview { args } => commands::delegate::execute(cwd, "preview", &args).await,
1850+
Commands::Preview { args } => {
1851+
if help::maybe_print_unified_delegate_help("preview", &args) {
1852+
return Ok(ExitStatus::default());
1853+
}
1854+
commands::delegate::execute(cwd, "preview", &args).await
1855+
}
18151856

18161857
Commands::Cache { args } => commands::delegate::execute(cwd, "cache", &args).await,
18171858

@@ -1854,52 +1895,12 @@ pub fn command_with_help() -> clap::Command {
18541895

18551896
/// Apply custom help formatting to a clap Command to match the JS CLI output.
18561897
fn apply_custom_help(cmd: clap::Command) -> clap::Command {
1857-
let bold = "\x1b[1m";
1858-
let bold_underline = "\x1b[1;4m";
1859-
let reset = "\x1b[0m";
18601898
let version = env!("CARGO_PKG_VERSION");
1861-
1862-
let after_help = format!(
1863-
"{bold_underline}Core Commands:{reset}
1864-
{bold}create{reset} Create a new project from a template
1865-
{bold}dev{reset} Run the development server
1866-
{bold}build{reset} Build for production
1867-
{bold}test{reset} Run tests
1868-
{bold}lint{reset} Lint code
1869-
{bold}fmt{reset} Format code
1870-
{bold}check{reset} Run format, lint, and type checks
1871-
{bold}pack{reset} Build library
1872-
{bold}run{reset} Run tasks
1873-
{bold}exec{reset} Execute a command from local node_modules/.bin
1874-
{bold}preview{reset} Preview production build
1875-
{bold}env{reset} Manage Node.js versions
1876-
{bold}migrate{reset} Migrate an existing project to Vite+
1877-
{bold}cache{reset} Manage the task cache
1878-
1879-
{bold_underline}Package Manager Commands:{reset}
1880-
{bold}install, i{reset} Install all dependencies, or add packages if package names are provided
1881-
{bold}add{reset} Add packages to dependencies
1882-
{bold}remove, rm, un, uninstall{reset} Remove packages from dependencies
1883-
{bold}dedupe{reset} Deduplicate dependencies by removing older versions
1884-
{bold}dlx{reset} Execute a package binary without installing it as a dependency
1885-
{bold}info, view, show{reset} View package information from the registry
1886-
{bold}link, ln{reset} Link packages for local development
1887-
{bold}list, ls{reset} List installed packages
1888-
{bold}outdated{reset} Check for outdated packages
1889-
{bold}pm{reset} Forward a command to the package manager
1890-
{bold}unlink{reset} Unlink packages
1891-
{bold}update, up{reset} Update packages to their latest versions
1892-
{bold}why, explain{reset} Show why a package is installed
1893-
1894-
{bold_underline}Maintenance Commands:{reset}
1895-
{bold}upgrade{reset} Update vp itself to the latest version
1896-
"
1897-
);
1899+
let after_help = help::render_help_doc(&help::top_level_help_doc());
18981900
let help_template = format!(
1899-
"Vite+/{version}
1900-
1901-
{{usage-heading}} {{usage}}{{after-help}}
1902-
{bold_underline}Options:{reset}
1901+
"Vite+/{version}\
1902+
{{after-help}}
1903+
Options:
19031904
{{options}}
19041905
"
19051906
);

crates/vite_global_cli/src/commands/env/exec.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub async fn execute(
2727
npm_version: Option<&str>,
2828
command: &[String],
2929
) -> Result<ExitStatus, Error> {
30+
let command = normalize_wrapper_command(command);
31+
3032
if command.is_empty() {
3133
eprintln!("vp env exec: missing command to execute");
3234
eprintln!("Usage: vp env exec [--node <version>] <command> [args...]");
@@ -35,7 +37,7 @@ pub async fn execute(
3537

3638
// If --node is provided, use explicit version mode (existing behavior)
3739
if let Some(version) = node_version {
38-
return execute_with_version(version, npm_version, command).await;
40+
return execute_with_version(version, npm_version, &command).await;
3941
}
4042

4143
// No --node provided - check if first command is a shim tool
@@ -77,6 +79,34 @@ pub async fn execute(
7779
Ok(exit_status(1))
7880
}
7981

82+
/// Normalize arguments when invoked via Windows shim wrappers.
83+
///
84+
/// Wrappers insert `--` after the tool name so flags like `--help` aren't
85+
/// consumed by clap while parsing `vp env exec`. Remove only that inserted
86+
/// separator before forwarding args to the target tool.
87+
fn normalize_wrapper_command(command: &[String]) -> Vec<String> {
88+
let from_wrapper = std::env::var_os(env_vars::VITE_PLUS_SHIM_WRAPPER).is_some();
89+
let normalized = normalize_wrapper_command_inner(command, from_wrapper);
90+
91+
if from_wrapper {
92+
// SAFETY: We're in a short-lived CLI process and clearing a wrapper-only
93+
// marker before tool execution avoids leaking it to child processes.
94+
unsafe {
95+
std::env::remove_var(env_vars::VITE_PLUS_SHIM_WRAPPER);
96+
}
97+
}
98+
99+
normalized
100+
}
101+
102+
fn normalize_wrapper_command_inner(command: &[String], from_wrapper: bool) -> Vec<String> {
103+
let mut normalized = command.to_vec();
104+
if from_wrapper && normalized.len() >= 2 && normalized[1] == "--" {
105+
normalized.remove(1);
106+
}
107+
normalized
108+
}
109+
80110
/// Execute a command with an explicitly specified Node.js version.
81111
async fn execute_with_version(
82112
node_version: &str,
@@ -238,4 +268,18 @@ mod tests {
238268
// Should fail because python is not a shim tool and --node was not provided
239269
assert!(!status.success(), "Non-shim command without --node should fail");
240270
}
271+
272+
#[test]
273+
fn test_normalize_wrapper_command_strips_only_wrapper_separator() {
274+
let command = vec!["node".to_string(), "--".to_string(), "--version".to_string()];
275+
let normalized = normalize_wrapper_command_inner(&command, true);
276+
assert_eq!(normalized, vec!["node", "--version"]);
277+
}
278+
279+
#[test]
280+
fn test_normalize_wrapper_command_no_wrapper_keeps_separator() {
281+
let command = vec!["node".to_string(), "--".to_string(), "--version".to_string()];
282+
let normalized = normalize_wrapper_command_inner(&command, false);
283+
assert_eq!(normalized, command);
284+
}
241285
}

crates/vite_global_cli/src/commands/env/global_install.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,11 +405,13 @@ async fn create_package_shim(
405405
return Ok(());
406406
}
407407

408-
// Create .cmd wrapper that calls vp env exec <bin_name>
408+
// Create .cmd wrapper that calls vp env exec <bin_name>.
409+
// Use `--` so args like `--help` are forwarded to the package binary,
410+
// not consumed by clap while parsing `vp env exec`.
409411
// Set VITE_PLUS_HOME using %~dp0.. which resolves to the parent of bin/
410412
// This ensures the vp binary knows its home directory
411413
let wrapper_content = format!(
412-
"@echo off\r\nset VITE_PLUS_HOME=%~dp0..\r\n\"%VITE_PLUS_HOME%\\current\\bin\\vp.exe\" env exec {} %*\r\nexit /b %ERRORLEVEL%\r\n",
414+
"@echo off\r\nset VITE_PLUS_HOME=%~dp0..\r\nset VITE_PLUS_SHIM_WRAPPER=1\r\n\"%VITE_PLUS_HOME%\\current\\bin\\vp.exe\" env exec {} -- %*\r\nexit /b %ERRORLEVEL%\r\n",
413415
bin_name
414416
);
415417
tokio::fs::write(&cmd_path, wrapper_content).await?;
@@ -422,7 +424,8 @@ async fn create_package_shim(
422424
r#"#!/bin/sh
423425
VITE_PLUS_HOME="$(dirname "$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")")")"
424426
export VITE_PLUS_HOME
425-
exec "$VITE_PLUS_HOME/current/bin/vp.exe" env exec {} "$@"
427+
export VITE_PLUS_SHIM_WRAPPER=1
428+
exec "$VITE_PLUS_HOME/current/bin/vp.exe" env exec {} -- "$@"
426429
"#,
427430
bin_name
428431
);

crates/vite_global_cli/src/commands/env/setup.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,14 @@ async fn create_windows_shim(
233233
) -> Result<(), Error> {
234234
let cmd_path = bin_dir.join(format!("{tool}.cmd"));
235235

236-
// Create .cmd wrapper that calls vp env exec <tool>
236+
// Create .cmd wrapper that calls vp env exec <tool>.
237+
// Use `--` so tool args like `--help` are forwarded to the tool,
238+
// not consumed by clap while parsing `vp env exec`.
237239
// Use a for loop to canonicalize VITE_PLUS_HOME path.
238240
// %~dp0.. would produce paths like C:\Users\x\.vite-plus\bin\..
239241
// The for loop resolves this to a clean C:\Users\x\.vite-plus
240242
let cmd_content = format!(
241-
"@echo off\r\nfor %%I in (\"%~dp0..\") do set VITE_PLUS_HOME=%%~fI\r\n\"%VITE_PLUS_HOME%\\current\\bin\\vp.exe\" env exec {} %*\r\nexit /b %ERRORLEVEL%\r\n",
243+
"@echo off\r\nfor %%I in (\"%~dp0..\") do set VITE_PLUS_HOME=%%~fI\r\nset VITE_PLUS_SHIM_WRAPPER=1\r\n\"%VITE_PLUS_HOME%\\current\\bin\\vp.exe\" env exec {} -- %*\r\nexit /b %ERRORLEVEL%\r\n",
242244
tool
243245
);
244246

@@ -252,7 +254,8 @@ async fn create_windows_shim(
252254
r#"#!/bin/sh
253255
VITE_PLUS_HOME="$(dirname "$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")")")"
254256
export VITE_PLUS_HOME
255-
exec "$VITE_PLUS_HOME/current/bin/vp.exe" env exec {} "$@"
257+
export VITE_PLUS_SHIM_WRAPPER=1
258+
exec "$VITE_PLUS_HOME/current/bin/vp.exe" env exec {} -- "$@"
256259
"#,
257260
tool
258261
);

0 commit comments

Comments
 (0)