Skip to content

Commit ae90321

Browse files
committed
fix(cli): show friendly "No package.json found." for pm subcommands
When running `vp pm`, `vp outdated`, `vp why`, and other package manager commands in a directory without package.json, the error was verbose and unfriendly. Now shows a clean "No package.json found." message without the "Error: " prefix by introducing an Error::UserMessage variant.
1 parent 52ded45 commit ae90321

15 files changed

Lines changed: 76 additions & 65 deletions

File tree

crates/vite_global_cli/src/commands/dedupe.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::process::ExitStatus;
22

3-
use vite_install::{commands::dedupe::DedupeCommandOptions, package_manager::PackageManager};
3+
use vite_install::commands::dedupe::DedupeCommandOptions;
44
use vite_path::AbsolutePathBuf;
55

6-
use super::prepend_js_runtime_to_path_env;
6+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
77
use crate::error::Error;
88

99
/// Dedupe command for deduplicating dependencies by removing older versions.
@@ -26,8 +26,7 @@ impl DedupeCommand {
2626
) -> Result<ExitStatus, Error> {
2727
prepend_js_runtime_to_path_env(&self.cwd).await?;
2828

29-
// Detect package manager
30-
let package_manager = PackageManager::builder(&self.cwd).build_with_default().await?;
29+
let package_manager = build_package_manager(&self.cwd).await?;
3130

3231
let dedupe_command_options = DedupeCommandOptions { check, pass_through_args };
3332
Ok(package_manager.run_dedupe_command(&dedupe_command_options, &self.cwd).await?)

crates/vite_global_cli/src/commands/dlx.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::process::ExitStatus;
22

3-
use vite_install::{commands::dlx::DlxCommandOptions, package_manager::PackageManager};
3+
use vite_install::commands::dlx::DlxCommandOptions;
44
use vite_path::AbsolutePathBuf;
55

6-
use super::prepend_js_runtime_to_path_env;
6+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
77
use crate::error::Error;
88

99
/// Dlx command for executing packages without installing them as dependencies.
@@ -40,8 +40,7 @@ impl DlxCommand {
4040
let package_spec = &args[0];
4141
let command_args: Vec<String> = args[1..].to_vec();
4242

43-
// Detect package manager
44-
let package_manager = PackageManager::builder(&self.cwd).build_with_default().await?;
43+
let package_manager = build_package_manager(&self.cwd).await?;
4544

4645
let dlx_command_options = DlxCommandOptions {
4746
packages: &packages,

crates/vite_global_cli/src/commands/link.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::process::ExitStatus;
22

3-
use vite_install::{commands::link::LinkCommandOptions, package_manager::PackageManager};
3+
use vite_install::commands::link::LinkCommandOptions;
44
use vite_path::AbsolutePathBuf;
55

6-
use super::prepend_js_runtime_to_path_env;
6+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
77
use crate::error::Error;
88

99
/// Link command for local package development.
@@ -26,8 +26,7 @@ impl LinkCommand {
2626
) -> Result<ExitStatus, Error> {
2727
prepend_js_runtime_to_path_env(&self.cwd).await?;
2828

29-
// Detect package manager
30-
let package_manager = PackageManager::builder(&self.cwd).build_with_default().await?;
29+
let package_manager = build_package_manager(&self.cwd).await?;
3130

3231
let link_command_options = LinkCommandOptions { package, pass_through_args };
3332
Ok(package_manager.run_link_command(&link_command_options, &self.cwd).await?)

crates/vite_global_cli/src/commands/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
//! Category C - Local CLI Delegation:
2424
//! - `delegate`: Local CLI delegation
2525
26+
use vite_install::package_manager::PackageManager;
2627
use vite_path::AbsolutePath;
2728
use vite_shared::{PrependOptions, prepend_to_path_env};
2829

@@ -68,6 +69,17 @@ pub async fn prepend_js_runtime_to_path_env(project_path: &AbsolutePath) -> Resu
6869
Ok(())
6970
}
7071

72+
/// Build a PackageManager, converting PackageJsonNotFound into a friendly error message.
73+
pub async fn build_package_manager(cwd: &AbsolutePath) -> Result<PackageManager, Error> {
74+
match PackageManager::builder(cwd).build_with_default().await {
75+
Ok(pm) => Ok(pm),
76+
Err(vite_error::Error::WorkspaceError(vite_workspace::Error::PackageJsonNotFound(_))) => {
77+
Err(Error::UserMessage("No package.json found.".into()))
78+
}
79+
Err(e) => Err(e.into()),
80+
}
81+
}
82+
7183
// Category A: Package manager commands
7284
pub mod add;
7385
pub mod dedupe;

crates/vite_global_cli/src/commands/outdated.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
use std::process::ExitStatus;
22

3-
use vite_install::{
4-
commands::outdated::{Format, OutdatedCommandOptions},
5-
package_manager::PackageManager,
6-
};
3+
use vite_install::commands::outdated::{Format, OutdatedCommandOptions};
74
use vite_path::AbsolutePathBuf;
85

9-
use super::prepend_js_runtime_to_path_env;
6+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
107
use crate::error::Error;
118

129
/// Outdated command for checking outdated packages.
@@ -41,8 +38,7 @@ impl OutdatedCommand {
4138
) -> Result<ExitStatus, Error> {
4239
prepend_js_runtime_to_path_env(&self.cwd).await?;
4340

44-
// Detect package manager
45-
let package_manager = PackageManager::builder(&self.cwd).build_with_default().await?;
41+
let package_manager = build_package_manager(&self.cwd).await?;
4642

4743
let outdated_command_options = OutdatedCommandOptions {
4844
packages,

crates/vite_global_cli/src/commands/pm.rs

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,14 @@
66
77
use std::process::ExitStatus;
88

9-
use vite_install::{
10-
PackageManager,
11-
commands::{
12-
cache::CacheCommandOptions, config::ConfigCommandOptions, list::ListCommandOptions,
13-
owner::OwnerSubcommand, pack::PackCommandOptions, prune::PruneCommandOptions,
14-
publish::PublishCommandOptions, view::ViewCommandOptions,
15-
},
9+
use vite_install::commands::{
10+
cache::CacheCommandOptions, config::ConfigCommandOptions, list::ListCommandOptions,
11+
owner::OwnerSubcommand, pack::PackCommandOptions, prune::PruneCommandOptions,
12+
publish::PublishCommandOptions, view::ViewCommandOptions,
1613
};
1714
use vite_path::AbsolutePathBuf;
1815

19-
use super::prepend_js_runtime_to_path_env;
16+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
2017
use crate::{
2118
cli::{ConfigCommands, OwnerCommands, PmCommands},
2219
error::Error,
@@ -32,7 +29,7 @@ pub async fn execute_info(
3229
) -> Result<ExitStatus, Error> {
3330
prepend_js_runtime_to_path_env(&cwd).await?;
3431

35-
let package_manager = PackageManager::builder(&cwd).build_with_default().await?;
32+
let package_manager = build_package_manager(&cwd).await?;
3633

3734
let options = ViewCommandOptions { package, field, json, pass_through_args };
3835

@@ -51,24 +48,7 @@ pub async fn execute_pm_subcommand(
5148

5249
prepend_js_runtime_to_path_env(&cwd).await?;
5350

54-
let package_manager = match PackageManager::builder(&cwd).build_with_default().await {
55-
Ok(pm) => pm,
56-
Err(e) => {
57-
// For `list` command, silently succeed when no workspace is found
58-
// (matches `pnpm list` behavior in dirs without package.json)
59-
if matches!(&command, PmCommands::List { .. })
60-
&& matches!(
61-
&e,
62-
vite_error::Error::WorkspaceError(vite_workspace::Error::PackageJsonNotFound(
63-
_
64-
))
65-
)
66-
{
67-
return Ok(ExitStatus::default());
68-
}
69-
return Err(e.into());
70-
}
71-
};
51+
let package_manager = build_package_manager(&cwd).await?;
7252

7353
match command {
7454
PmCommands::Prune { prod, no_optional, pass_through_args } => {

crates/vite_global_cli/src/commands/remove.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::process::ExitStatus;
22

3-
use vite_install::{commands::remove::RemoveCommandOptions, package_manager::PackageManager};
3+
use vite_install::commands::remove::RemoveCommandOptions;
44
use vite_path::AbsolutePathBuf;
55

6-
use super::prepend_js_runtime_to_path_env;
6+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
77
use crate::error::Error;
88

99
/// Remove command for removing packages from dependencies.
@@ -33,8 +33,7 @@ impl RemoveCommand {
3333
) -> Result<ExitStatus, Error> {
3434
prepend_js_runtime_to_path_env(&self.cwd).await?;
3535

36-
// Detect package manager
37-
let package_manager = PackageManager::builder(&self.cwd).build_with_default().await?;
36+
let package_manager = build_package_manager(&self.cwd).await?;
3837

3938
let remove_command_options = RemoveCommandOptions {
4039
packages,

crates/vite_global_cli/src/commands/unlink.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::process::ExitStatus;
22

3-
use vite_install::{commands::unlink::UnlinkCommandOptions, package_manager::PackageManager};
3+
use vite_install::commands::unlink::UnlinkCommandOptions;
44
use vite_path::AbsolutePathBuf;
55

6-
use super::prepend_js_runtime_to_path_env;
6+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
77
use crate::error::Error;
88

99
/// Unlink command for removing package links.
@@ -27,8 +27,7 @@ impl UnlinkCommand {
2727
) -> Result<ExitStatus, Error> {
2828
prepend_js_runtime_to_path_env(&self.cwd).await?;
2929

30-
// Detect package manager
31-
let package_manager = PackageManager::builder(&self.cwd).build_with_default().await?;
30+
let package_manager = build_package_manager(&self.cwd).await?;
3231

3332
let unlink_command_options = UnlinkCommandOptions { package, recursive, pass_through_args };
3433
Ok(package_manager.run_unlink_command(&unlink_command_options, &self.cwd).await?)

crates/vite_global_cli/src/commands/update.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::process::ExitStatus;
22

3-
use vite_install::{commands::update::UpdateCommandOptions, package_manager::PackageManager};
3+
use vite_install::commands::update::UpdateCommandOptions;
44
use vite_path::AbsolutePathBuf;
55

6-
use super::prepend_js_runtime_to_path_env;
6+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
77
use crate::error::Error;
88

99
/// Update command for updating packages to their latest versions.
@@ -38,8 +38,7 @@ impl UpdateCommand {
3838
) -> Result<ExitStatus, Error> {
3939
prepend_js_runtime_to_path_env(&self.cwd).await?;
4040

41-
// Detect package manager
42-
let package_manager = PackageManager::builder(&self.cwd).build_with_default().await?;
41+
let package_manager = build_package_manager(&self.cwd).await?;
4342

4443
let update_command_options = UpdateCommandOptions {
4544
packages,

crates/vite_global_cli/src/commands/why.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::process::ExitStatus;
22

3-
use vite_install::{commands::why::WhyCommandOptions, package_manager::PackageManager};
3+
use vite_install::commands::why::WhyCommandOptions;
44
use vite_path::AbsolutePathBuf;
55

6-
use super::prepend_js_runtime_to_path_env;
6+
use super::{build_package_manager, prepend_js_runtime_to_path_env};
77
use crate::error::Error;
88

99
/// Why command for showing why a package is installed.
@@ -40,8 +40,7 @@ impl WhyCommand {
4040
) -> Result<ExitStatus, Error> {
4141
prepend_js_runtime_to_path_env(&self.cwd).await?;
4242

43-
// Detect package manager
44-
let package_manager = PackageManager::builder(&self.cwd).build_with_default().await?;
43+
let package_manager = build_package_manager(&self.cwd).await?;
4544

4645
let why_command_options = WhyCommandOptions {
4746
packages,

0 commit comments

Comments
 (0)