mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(add): Better error message when missing npm specifier (#24970)
Before: <img width="278" alt="Screenshot 2024-08-09 at 3 15 01 PM" src="https://github.com/user-attachments/assets/91b0ada6-93ee-4be6-a996-078aef98c2a9"> After: <img width="888" alt="Screenshot 2024-08-09 at 3 52 15 PM" src="https://github.com/user-attachments/assets/3c88a0e8-c761-4f70-88bf-109355ac12f0">
This commit is contained in:
parent
4dc8fe2020
commit
218ee1b1ff
6 changed files with 86 additions and 7 deletions
|
@ -98,7 +98,7 @@ fn spawn_subcommand<F: Future<Output = T> + 'static, T: SubcommandOutput>(
|
||||||
async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
||||||
let handle = match flags.subcommand.clone() {
|
let handle = match flags.subcommand.clone() {
|
||||||
DenoSubcommand::Add(add_flags) => spawn_subcommand(async {
|
DenoSubcommand::Add(add_flags) => spawn_subcommand(async {
|
||||||
tools::registry::add(flags, add_flags).await
|
tools::registry::add(flags, add_flags, tools::registry::AddCommandName::Add).await
|
||||||
}),
|
}),
|
||||||
DenoSubcommand::Bench(bench_flags) => spawn_subcommand(async {
|
DenoSubcommand::Bench(bench_flags) => spawn_subcommand(async {
|
||||||
if bench_flags.watch.is_some() {
|
if bench_flags.watch.is_some() {
|
||||||
|
|
|
@ -266,7 +266,12 @@ async fn install_local(
|
||||||
maybe_add_flags: Option<AddFlags>,
|
maybe_add_flags: Option<AddFlags>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
if let Some(add_flags) = maybe_add_flags {
|
if let Some(add_flags) = maybe_add_flags {
|
||||||
return super::registry::add(flags, add_flags).await;
|
return super::registry::add(
|
||||||
|
flags,
|
||||||
|
add_flags,
|
||||||
|
super::registry::AddCommandName::Install,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let factory = CliFactory::from_flags(flags);
|
let factory = CliFactory::from_flags(flags);
|
||||||
|
|
|
@ -64,6 +64,7 @@ mod unfurl;
|
||||||
use auth::get_auth_method;
|
use auth::get_auth_method;
|
||||||
use auth::AuthMethod;
|
use auth::AuthMethod;
|
||||||
pub use pm::add;
|
pub use pm::add;
|
||||||
|
pub use pm::AddCommandName;
|
||||||
use publish_order::PublishOrderGraph;
|
use publish_order::PublishOrderGraph;
|
||||||
use unfurl::SpecifierUnfurler;
|
use unfurl::SpecifierUnfurler;
|
||||||
|
|
||||||
|
|
|
@ -175,9 +175,26 @@ fn package_json_dependency_entry(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
/// The name of the subcommand invoking the `add` operation.
|
||||||
|
pub enum AddCommandName {
|
||||||
|
Add,
|
||||||
|
Install,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for AddCommandName {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
AddCommandName::Add => write!(f, "add"),
|
||||||
|
AddCommandName::Install => write!(f, "install"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn add(
|
pub async fn add(
|
||||||
flags: Arc<Flags>,
|
flags: Arc<Flags>,
|
||||||
add_flags: AddFlags,
|
add_flags: AddFlags,
|
||||||
|
cmd_name: AddCommandName,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let (config_file, cli_factory) =
|
let (config_file, cli_factory) =
|
||||||
DenoOrPackageJson::from_flags(flags.clone())?;
|
DenoOrPackageJson::from_flags(flags.clone())?;
|
||||||
|
@ -234,8 +251,16 @@ pub async fn add(
|
||||||
let package_and_version = package_and_version_result?;
|
let package_and_version = package_and_version_result?;
|
||||||
|
|
||||||
match package_and_version {
|
match package_and_version {
|
||||||
PackageAndVersion::NotFound(package_name) => {
|
PackageAndVersion::NotFound {
|
||||||
bail!("{} was not found.", crate::colors::red(package_name));
|
package: package_name,
|
||||||
|
found_npm_package,
|
||||||
|
package_req,
|
||||||
|
} => {
|
||||||
|
if found_npm_package {
|
||||||
|
bail!("{} was not found, but a matching npm package exists. Did you mean `{}`?", crate::colors::red(package_name), crate::colors::yellow(format!("deno {cmd_name} npm:{package_req}")));
|
||||||
|
} else {
|
||||||
|
bail!("{} was not found.", crate::colors::red(package_name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PackageAndVersion::Selected(selected) => {
|
PackageAndVersion::Selected(selected) => {
|
||||||
selected_packages.push(selected);
|
selected_packages.push(selected);
|
||||||
|
@ -327,7 +352,11 @@ struct SelectedPackage {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PackageAndVersion {
|
enum PackageAndVersion {
|
||||||
NotFound(String),
|
NotFound {
|
||||||
|
package: String,
|
||||||
|
found_npm_package: bool,
|
||||||
|
package_req: PackageReq,
|
||||||
|
},
|
||||||
Selected(SelectedPackage),
|
Selected(SelectedPackage),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +369,19 @@ async fn find_package_and_select_version_for_req(
|
||||||
AddPackageReqValue::Jsr(req) => {
|
AddPackageReqValue::Jsr(req) => {
|
||||||
let jsr_prefixed_name = format!("jsr:{}", &req.name);
|
let jsr_prefixed_name = format!("jsr:{}", &req.name);
|
||||||
let Some(nv) = jsr_resolver.req_to_nv(&req).await else {
|
let Some(nv) = jsr_resolver.req_to_nv(&req).await else {
|
||||||
return Ok(PackageAndVersion::NotFound(jsr_prefixed_name));
|
if npm_resolver.req_to_nv(&req).await.is_some() {
|
||||||
|
return Ok(PackageAndVersion::NotFound {
|
||||||
|
package: jsr_prefixed_name,
|
||||||
|
found_npm_package: true,
|
||||||
|
package_req: req,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(PackageAndVersion::NotFound {
|
||||||
|
package: jsr_prefixed_name,
|
||||||
|
found_npm_package: false,
|
||||||
|
package_req: req,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
let range_symbol = if req.version_req.version_text().starts_with('~') {
|
let range_symbol = if req.version_req.version_text().starts_with('~') {
|
||||||
'~'
|
'~'
|
||||||
|
@ -357,7 +398,11 @@ async fn find_package_and_select_version_for_req(
|
||||||
AddPackageReqValue::Npm(req) => {
|
AddPackageReqValue::Npm(req) => {
|
||||||
let npm_prefixed_name = format!("npm:{}", &req.name);
|
let npm_prefixed_name = format!("npm:{}", &req.name);
|
||||||
let Some(nv) = npm_resolver.req_to_nv(&req).await else {
|
let Some(nv) = npm_resolver.req_to_nv(&req).await else {
|
||||||
return Ok(PackageAndVersion::NotFound(npm_prefixed_name));
|
return Ok(PackageAndVersion::NotFound {
|
||||||
|
package: npm_prefixed_name,
|
||||||
|
found_npm_package: false,
|
||||||
|
package_req: req,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
let range_symbol = if req.version_req.version_text().starts_with('~') {
|
let range_symbol = if req.version_req.version_text().starts_with('~') {
|
||||||
'~'
|
'~'
|
||||||
|
|
28
tests/specs/add/missing_npm_specifier/__test__.jsonc
Normal file
28
tests/specs/add/missing_npm_specifier/__test__.jsonc
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"tempDir": true,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"args": "add ajv@latest",
|
||||||
|
"output": "error: jsr:ajv was not found, but a matching npm package exists. Did you mean `deno add npm:ajv@latest`?\n",
|
||||||
|
"exitCode": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"args": "add ajv",
|
||||||
|
"output": "error: jsr:ajv was not found, but a matching npm package exists. Did you mean `deno add npm:ajv`?\n",
|
||||||
|
"exitCode": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"args": "add ajv@8.11.0",
|
||||||
|
"output": "error: jsr:ajv was not found, but a matching npm package exists. Did you mean `deno add npm:ajv@8.11.0`?\n",
|
||||||
|
"exitCode": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"envs": {
|
||||||
|
"DENO_FUTURE": "1"
|
||||||
|
},
|
||||||
|
"args": "install ajv@latest",
|
||||||
|
"output": "error: jsr:ajv was not found, but a matching npm package exists. Did you mean `deno install npm:ajv@latest`?\n",
|
||||||
|
"exitCode": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
0
tests/specs/add/missing_npm_specifier/deno.json
Normal file
0
tests/specs/add/missing_npm_specifier/deno.json
Normal file
Loading…
Reference in a new issue