diff --git a/crates/vite_global_cli/src/cli.rs b/crates/vite_global_cli/src/cli.rs index 93d363ff82..f214bef15b 100644 --- a/crates/vite_global_cli/src/cli.rs +++ b/crates/vite_global_cli/src/cli.rs @@ -816,9 +816,7 @@ async fn managed_update( } async fn get_current_node_version() -> Result { - let cwd = vite_path::current_dir().map_err(|error| { - Error::ConfigError(format!("Cannot get current directory: {error}").into()) - })?; + let cwd = vite_path::current_dir()?; Ok(resolve_version(&cwd).await?.version) } diff --git a/crates/vite_global_cli/src/commands/env/list.rs b/crates/vite_global_cli/src/commands/env/list.rs index 2f086a30a8..db4fc81dbe 100644 --- a/crates/vite_global_cli/src/commands/env/list.rs +++ b/crates/vite_global_cli/src/commands/env/list.rs @@ -52,8 +52,7 @@ fn compare_versions(a: &str, b: &str) -> Ordering { /// Execute the list command (local installed versions). pub async fn execute(cwd: AbsolutePathBuf, json_output: bool) -> Result { - let home_dir = - vite_shared::get_vp_home().map_err(|e| Error::ConfigError(format!("{e}").into()))?; + let home_dir = vite_shared::get_vp_home()?; let node_dir = home_dir.join("js_runtime").join("node"); let versions = list_installed_versions(node_dir.as_path()); diff --git a/crates/vite_global_cli/src/commands/env/mod.rs b/crates/vite_global_cli/src/commands/env/mod.rs index 063fa31f9b..b59f9ada7d 100644 --- a/crates/vite_global_cli/src/commands/env/mod.rs +++ b/crates/vite_global_cli/src/commands/env/mod.rs @@ -80,15 +80,14 @@ pub async fn execute(cwd: AbsolutePathBuf, args: EnvArgs) -> Result { let provider = vite_js_runtime::NodeProvider::new(); let resolved = config::resolve_version_alias(&version, &provider).await?; - let home_dir = vite_shared::get_vp_home() - .map_err(|e| crate::error::Error::ConfigError(format!("{e}").into()))?; + let home_dir = vite_shared::get_vp_home()?; let version_dir = home_dir.join("js_runtime").join("node").join(&resolved); if !version_dir.as_path().exists() { eprintln!("Node.js v{} is not installed", resolved); return Ok(exit_status(1)); } tokio::fs::remove_dir_all(version_dir.as_path()).await.map_err(|e| { - crate::error::Error::ConfigError( + crate::error::Error::Other( format!("Failed to remove Node.js v{}: {}", resolved, e).into(), ) })?; diff --git a/crates/vite_global_cli/src/commands/env/package_metadata.rs b/crates/vite_global_cli/src/commands/env/package_metadata.rs index c1a665b640..374735cd4d 100644 --- a/crates/vite_global_cli/src/commands/env/package_metadata.rs +++ b/crates/vite_global_cli/src/commands/env/package_metadata.rs @@ -86,9 +86,7 @@ impl PackageMetadata { return Ok(None); } let content = tokio::fs::read_to_string(&path).await?; - let metadata: Self = serde_json::from_str(&content).map_err(|e| { - Error::ConfigError(format!("Failed to parse package metadata: {e}").into()) - })?; + let metadata: Self = serde_json::from_str(&content).map_err(Error::JsonError)?; Ok(Some(metadata)) } @@ -100,9 +98,7 @@ impl PackageMetadata { tokio::fs::create_dir_all(parent).await?; } - let content = serde_json::to_string_pretty(self).map_err(|e| { - Error::ConfigError(format!("Failed to serialize package metadata: {e}").into()) - })?; + let content = serde_json::to_string_pretty(self).map_err(Error::JsonError)?; tokio::fs::write(&path, content).await?; Ok(()) } diff --git a/crates/vite_global_cli/src/commands/env/pin.rs b/crates/vite_global_cli/src/commands/env/pin.rs index 6726bd39f5..5f67440423 100644 --- a/crates/vite_global_cli/src/commands/env/pin.rs +++ b/crates/vite_global_cli/src/commands/env/pin.rs @@ -155,7 +155,7 @@ async fn do_pin( } PinTarget::DevEngines => { if !package_json_exists { - return Err(Error::ConfigError( + return Err(Error::Other( format!( "cannot pin to devEngines: no {} in {}", PACKAGE_JSON_FILE, @@ -398,7 +398,7 @@ async fn write_dev_engines_node_version(cwd: &AbsolutePathBuf, version: &str) -> let updated = vite_shared::edit_json_object(&content, |obj| { set_dev_engines_runtime_node(obj, version); }) - .map_err(|e| Error::ConfigError(format!("failed to update package.json: {e}").into()))?; + .map_err(|e| Error::Other(format!("failed to update package.json: {e}").into()))?; tokio::fs::write(&package_json_path, updated).await?; Ok(()) } @@ -493,7 +493,7 @@ async fn remove_dev_engines_runtime_node(cwd: &AbsolutePathBuf) -> Result Result tokio::fs::create_dir_all(&bin_dir).await?; // Get the current executable path (for shims) - let current_exe = std::env::current_exe() - .map_err(|e| Error::ConfigError(format!("Cannot find current executable: {e}").into()))?; + let current_exe = std::env::current_exe()?; // Create wrapper script in bin/ setup_vp_wrapper(¤t_exe, &bin_dir, refresh).await?; @@ -328,7 +327,7 @@ async fn create_unix_shim( tool: &str, ) -> Result<(), Error> { let bin_dir = shim_path.parent().ok_or_else(|| { - Error::ConfigError(format!("Cannot find parent directory for {tool} shim").into()) + Error::Other(format!("Cannot find parent directory for {tool} shim").into()) })?; let target = resolve_unix_vp_shim_target(source, bin_dir).await?; tokio::fs::symlink(&target, shim_path).await?; @@ -414,19 +413,18 @@ pub(crate) fn get_trampoline_path() -> Result let path = std::path::PathBuf::from(override_path); if path.exists() { return vite_path::AbsolutePathBuf::new(path) - .ok_or_else(|| Error::ConfigError("Invalid trampoline override path".into())); + .ok_or_else(|| Error::Other("Invalid trampoline override path".into())); } } - let current_exe = std::env::current_exe() - .map_err(|e| Error::ConfigError(format!("Cannot find current executable: {e}").into()))?; + let current_exe = std::env::current_exe()?; let bin_dir = current_exe .parent() - .ok_or_else(|| Error::ConfigError("Cannot find parent directory of vp.exe".into()))?; + .ok_or_else(|| Error::Other("Cannot find parent directory of vp.exe".into()))?; let trampoline = bin_dir.join("vp-shim.exe"); if !trampoline.exists() { - return Err(Error::ConfigError( + return Err(Error::Other( format!( "Trampoline binary not found at {}. Re-install vite-plus to fix this.", trampoline.display() @@ -436,7 +434,7 @@ pub(crate) fn get_trampoline_path() -> Result } vite_path::AbsolutePathBuf::new(trampoline) - .ok_or_else(|| Error::ConfigError("Invalid trampoline path".into())) + .ok_or_else(|| Error::Other("Invalid trampoline path".into())) } /// Try to delete an `.exe` file; if deletion fails (e.g., file is locked by a diff --git a/crates/vite_global_cli/src/commands/env/use.rs b/crates/vite_global_cli/src/commands/env/use.rs index 57e0e7d572..e3a8848569 100644 --- a/crates/vite_global_cli/src/commands/env/use.rs +++ b/crates/vite_global_cli/src/commands/env/use.rs @@ -137,11 +137,8 @@ pub async fn execute( // Ensure version is installed (unless --no-install) if !no_install { - let home_dir = vite_shared::get_vp_home() - .map_err(|e| Error::ConfigError(format!("{e}").into()))? - .join("js_runtime") - .join("node") - .join(&resolved_version); + let home_dir = + vite_shared::get_vp_home()?.join("js_runtime").join("node").join(&resolved_version); #[cfg(windows)] let binary_path = home_dir.join("node.exe"); diff --git a/crates/vite_global_cli/src/commands/env/which.rs b/crates/vite_global_cli/src/commands/env/which.rs index 9601a7e34e..6e13afb2cb 100644 --- a/crates/vite_global_cli/src/commands/env/which.rs +++ b/crates/vite_global_cli/src/commands/env/which.rs @@ -229,13 +229,13 @@ fn locate_package_binary(package_name: &str, binary_name: &str) -> Result { @@ -245,7 +245,7 @@ fn locate_package_binary(package_name: &str, binary_name: &str) -> Result Result { - return Err(Error::ConfigError( + return Err(Error::Other( format!("No bin field in package.json for {}", package_name).into(), )); } diff --git a/crates/vite_global_cli/src/commands/global/install.rs b/crates/vite_global_cli/src/commands/global/install.rs index da7816f08d..4dd9179bdb 100644 --- a/crates/vite_global_cli/src/commands/global/install.rs +++ b/crates/vite_global_cli/src/commands/global/install.rs @@ -129,11 +129,7 @@ pub async fn install( // Resolve from current directory let cwd = match current_dir() { Ok(cwd) => cwd, - Err(error) => { - let error = - Error::ConfigError(format!("Cannot get current directory: {}", error).into()); - return Err((None, error)); - } + Err(error) => return Err((None, error.into())), }; let resolution = match resolve_version(&cwd).await { Ok(resolution) => resolution, @@ -535,7 +531,7 @@ async fn install_one( } let _ = std::io::stderr().write_all(&output.stderr); cleanup_failed_install(package_name, backup).await?; - return Err(Error::ConfigError( + return Err(Error::Other( format!("npm install failed with exit code: {:?}", output.status.code()).into(), )); } @@ -545,7 +541,7 @@ async fn install_one( if !tokio::fs::try_exists(&package_json_path).await.unwrap_or(false) { cleanup_failed_install(package_name, backup).await?; - return Err(Error::ConfigError( + return Err(Error::Other( format!( "Package was not installed correctly, package.json not found at {}", package_json_path.as_path().display() @@ -565,9 +561,7 @@ async fn install_one( Ok(package_json) => package_json, Err(error) => { cleanup_failed_install(package_name, backup).await?; - return Err(Error::ConfigError( - format!("Failed to parse package.json: {error}").into(), - )); + return Err(Error::Other(format!("Failed to parse package.json: {error}").into())); } }; @@ -648,7 +642,7 @@ fn unique_backup_dir(package_name: &str) -> Result { backup_path.set_file_name(backup_name); AbsolutePathBuf::new(backup_path) - .ok_or_else(|| Error::ConfigError("Invalid global package backup path".into())) + .ok_or_else(|| Error::Other("Invalid global package backup path".into())) } async fn cleanup_failed_install( @@ -723,7 +717,7 @@ async fn stale_bin_names_for_package( pub async fn uninstall(package_name: &str, dry_run: bool) -> Result<(), Error> { if is_local_package_spec(package_name) { // We can't resolve local packages for uninstall, follow npm's behavior - return Err(Error::ConfigError( + return Err(Error::Other( format!( "Local path {} can't be resolved, please enter a package name instead", package_name @@ -741,9 +735,7 @@ pub async fn uninstall(package_name: &str, dry_run: bool) -> Result<(), Error> { // Phase 2: Fallback - scan BinConfig files for orphaned binaries let orphan_bins = BinConfig::find_by_package(&package_name).await?; if orphan_bins.is_empty() { - return Err(Error::ConfigError( - format!("Package {} is not installed", package_name).into(), - )); + return Err(Error::Other(format!("Package {} is not installed", package_name).into())); } orphan_bins }; diff --git a/crates/vite_global_cli/src/commands/global/mod.rs b/crates/vite_global_cli/src/commands/global/mod.rs index 5d9234c131..57530e8ae5 100644 --- a/crates/vite_global_cli/src/commands/global/mod.rs +++ b/crates/vite_global_cli/src/commands/global/mod.rs @@ -38,9 +38,7 @@ struct NpmRegistry { impl NpmRegistry { async fn resolve() -> Result { - let cwd = current_dir().map_err(|error| { - Error::ConfigError(format!("Cannot get current directory: {error}").into()) - })?; + let cwd = current_dir()?; let resolution = resolve_version(&cwd).await?; let runtime = vite_js_runtime::download_runtime( vite_js_runtime::JsRuntimeType::Node, @@ -78,9 +76,7 @@ async fn npm_view( if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); - return Err(Error::ConfigError( - format!("npm view failed for {package_spec}: {stderr}").into(), - )); + return Err(Error::Other(format!("npm view failed for {package_spec}: {stderr}").into())); } Ok(output.stdout) @@ -159,7 +155,7 @@ pub(crate) fn parse_package_spec(spec: &str) -> Result<(String, Option), if is_local_package_spec(spec) { let package_json = read_local_package_json(spec)?; let Some(package_name) = package_json.get("name").and_then(|name| name.as_str()) else { - return Err(Error::ConfigError( + return Err(Error::Other( format!("Local package {spec} must have a string name in package.json").into(), )); }; @@ -187,13 +183,9 @@ fn resolve_local_package_path(spec: &str) -> Result { let path = std::path::Path::new(path_spec); if path.is_absolute() { AbsolutePathBuf::new(path.to_path_buf()) - .ok_or_else(|| Error::ConfigError(format!("Invalid local package path {spec}").into())) + .ok_or_else(|| Error::Other(format!("Invalid local package path {spec}").into())) } else { - Ok(current_dir() - .map_err(|error| { - Error::ConfigError(format!("Cannot get current directory: {error}").into()) - })? - .join(path)) + Ok(current_dir()?.join(path)) } } @@ -206,7 +198,7 @@ fn read_local_package_json(spec: &str) -> Result { let package_json_path = package_path.join("package.json"); let package_json_content = std::fs::read_to_string(package_json_path.as_path()).map_err(|error| { - Error::ConfigError( + Error::Other( format!( "Failed to read package.json for local package {spec} at {}: {error}", package_json_path.as_path().display() @@ -227,7 +219,7 @@ fn read_package_json_from_tarball( package_path: &AbsolutePathBuf, ) -> Result { let file = File::open(package_path.as_path()).map_err(|error| { - Error::ConfigError( + Error::Other( format!( "Failed to read package tarball {spec} at {}: {error}", package_path.as_path().display() @@ -239,13 +231,13 @@ fn read_package_json_from_tarball( let mut archive = Archive::new(decoder); for entry in archive.entries().map_err(|error| { - Error::ConfigError(format!("Failed to read package tarball {spec}: {error}").into()) + Error::Other(format!("Failed to read package tarball {spec}: {error}").into()) })? { let mut entry = entry.map_err(|error| { - Error::ConfigError(format!("Failed to read package tarball {spec}: {error}").into()) + Error::Other(format!("Failed to read package tarball {spec}: {error}").into()) })?; let path = entry.path().map_err(|error| { - Error::ConfigError(format!("Failed to read package tarball {spec}: {error}").into()) + Error::Other(format!("Failed to read package tarball {spec}: {error}").into()) })?; if path.as_ref() != std::path::Path::new("package/package.json") { continue; @@ -253,30 +245,28 @@ fn read_package_json_from_tarball( let mut package_json_content = String::new(); entry.read_to_string(&mut package_json_content).map_err(|error| { - Error::ConfigError( + Error::Other( format!("Failed to read package.json from package tarball {spec}: {error}").into(), ) })?; return serde_json::from_str(&package_json_content).map_err(Error::JsonError); } - Err(Error::ConfigError( - format!("Package tarball {spec} must contain package/package.json").into(), - )) + Err(Error::Other(format!("Package tarball {spec} must contain package/package.json").into())) } fn parse_npm_view_version(stdout: &[u8]) -> Result { let raw = String::from_utf8_lossy(stdout); let trimmed = raw.trim(); if trimmed.is_empty() { - return Err(Error::ConfigError("npm view returned an empty version".into())); + return Err(Error::Other("npm view returned an empty version".into())); } match serde_json::from_str::(trimmed) { Ok(serde_json::Value::String(version)) => Ok(version), Ok(serde_json::Value::Array(versions)) => { let Some(version) = versions.iter().rev().find_map(|version| version.as_str()) else { - return Err(Error::ConfigError("npm view returned an empty version list".into())); + return Err(Error::Other("npm view returned an empty version list".into())); }; Ok(version.to_string()) } diff --git a/crates/vite_global_cli/src/commands/global/packages.rs b/crates/vite_global_cli/src/commands/global/packages.rs index 916585c162..149d96cda2 100644 --- a/crates/vite_global_cli/src/commands/global/packages.rs +++ b/crates/vite_global_cli/src/commands/global/packages.rs @@ -33,8 +33,7 @@ pub async fn execute(json: bool, pattern: Option<&str>) -> Result/.npm/_logs/