Skip to content

Commit

Permalink
refactor: use concrete error types for node resolution (denoland#24470)
Browse files Browse the repository at this point in the history
This will help clean up some of the code in the CLI because we'll be
able to tell how the resolution failed (not part of this PR).
  • Loading branch information
dsherret authored Jul 9, 2024
1 parent 07613a6 commit 839caf6
Show file tree
Hide file tree
Showing 23 changed files with 1,007 additions and 585 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions cli/lsp/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ use deno_ast::MediaType;
use deno_cache_dir::HttpCache;
use deno_config::workspace::PackageJsonDepResolution;
use deno_config::workspace::WorkspaceResolver;
use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_graph::source::Resolver;
use deno_graph::GraphImport;
use deno_graph::ModuleSpecifier;
use deno_npm::NpmSystemInfo;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::errors::ClosestPkgJsonError;
use deno_runtime::deno_node::NodeResolution;
use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::deno_node::NodeResolver;
Expand Down Expand Up @@ -365,7 +365,7 @@ impl LspResolver {
pub fn get_closest_package_json(
&self,
referrer: &ModuleSpecifier,
) -> Result<Option<Arc<PackageJson>>, AnyError> {
) -> Result<Option<Arc<PackageJson>>, ClosestPkgJsonError> {
let resolver = self.get_scope_resolver(Some(referrer));
let Some(node_resolver) = resolver.node_resolver.as_ref() else {
return Ok(None);
Expand Down
2 changes: 1 addition & 1 deletion cli/module_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ impl<TGraphContainer: ModuleGraphContainer>
.resolve_package_sub_path_from_deno_module(
&package_folder,
module.nv_reference.sub_path(),
referrer,
Some(referrer),
NodeResolutionMode::Execution,
)
.with_context(|| {
Expand Down
60 changes: 35 additions & 25 deletions cli/npm/byonm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::errors::PackageFolderResolveError;
use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind;
use deno_runtime::deno_node::load_pkg_json;
use deno_runtime::deno_node::NodePermissions;
use deno_runtime::deno_node::NpmResolver;
Expand Down Expand Up @@ -168,42 +170,50 @@ impl NpmResolver for ByonmCliNpmResolver {
&self,
name: &str,
referrer: &ModuleSpecifier,
) -> Result<PathBuf, AnyError> {
) -> Result<PathBuf, PackageFolderResolveError> {
fn inner(
fs: &dyn FileSystem,
name: &str,
referrer: &ModuleSpecifier,
) -> Result<PathBuf, AnyError> {
let referrer_file = specifier_to_file_path(referrer)?;
let mut current_folder = referrer_file.parent().unwrap();
loop {
let node_modules_folder = if current_folder.ends_with("node_modules") {
Cow::Borrowed(current_folder)
} else {
Cow::Owned(current_folder.join("node_modules"))
};

let sub_dir = join_package_name(&node_modules_folder, name);
if fs.is_dir_sync(&sub_dir) {
return Ok(sub_dir);
}
) -> Result<PathBuf, PackageFolderResolveError> {
let maybe_referrer_file = specifier_to_file_path(referrer).ok();
let maybe_start_folder =
maybe_referrer_file.as_ref().and_then(|f| f.parent());
if let Some(start_folder) = maybe_start_folder {
for current_folder in start_folder.ancestors() {
let node_modules_folder = if current_folder.ends_with("node_modules")
{
Cow::Borrowed(current_folder)
} else {
Cow::Owned(current_folder.join("node_modules"))
};

if let Some(parent) = current_folder.parent() {
current_folder = parent;
} else {
break;
let sub_dir = join_package_name(&node_modules_folder, name);
if fs.is_dir_sync(&sub_dir) {
return Ok(sub_dir);
}
}
}

bail!(
"could not find package '{}' from referrer '{}'.",
name,
referrer
);
Err(
PackageFolderResolveErrorKind::NotFoundPackage {
package_name: name.to_string(),
referrer: referrer.clone(),
referrer_extra: None,
}
.into(),
)
}

let path = inner(&*self.fs, name, referrer)?;
Ok(self.fs.realpath_sync(&path)?)
self.fs.realpath_sync(&path).map_err(|err| {
PackageFolderResolveErrorKind::Io {
package_name: name.to_string(),
referrer: referrer.clone(),
source: err.into_io_error(),
}
.into()
})
}

fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
Expand Down
11 changes: 9 additions & 2 deletions cli/npm/managed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage;
use deno_npm::NpmSystemInfo;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::errors::PackageFolderResolveError;
use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind;
use deno_runtime::deno_node::NodePermissions;
use deno_runtime::deno_node::NpmResolver;
use deno_semver::package::PackageNv;
Expand Down Expand Up @@ -522,12 +524,17 @@ impl NpmResolver for ManagedCliNpmResolver {
&self,
name: &str,
referrer: &ModuleSpecifier,
) -> Result<PathBuf, AnyError> {
) -> Result<PathBuf, PackageFolderResolveError> {
let path = self
.fs_resolver
.resolve_package_folder_from_package(name, referrer)?;
let path =
canonicalize_path_maybe_not_exists_with_fs(&path, self.fs.as_ref())?;
canonicalize_path_maybe_not_exists_with_fs(&path, self.fs.as_ref())
.map_err(|err| PackageFolderResolveErrorKind::Io {
package_name: name.to_string(),
referrer: referrer.clone(),
source: err,
})?;
log::debug!("Resolved {} from {} to {}", name, referrer, path.display());
Ok(path)
}
Expand Down
14 changes: 12 additions & 2 deletions cli/npm/managed/resolvers/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::errors::PackageFolderResolveError;
use deno_runtime::deno_node::NodePermissions;

use crate::npm::managed::cache::TarballCache;
Expand All @@ -31,16 +32,25 @@ pub trait NpmPackageFsResolver: Send + Sync {
/// The local node_modules folder if it is applicable to the implementation.
fn node_modules_path(&self) -> Option<&PathBuf>;

fn maybe_package_folder(&self, package_id: &NpmPackageId) -> Option<PathBuf>;

fn package_folder(
&self,
package_id: &NpmPackageId,
) -> Result<PathBuf, AnyError>;
) -> Result<PathBuf, AnyError> {
self.maybe_package_folder(package_id).ok_or_else(|| {
deno_core::anyhow::anyhow!(
"Package folder not found for '{}'",
package_id.as_serialized()
)
})
}

fn resolve_package_folder_from_package(
&self,
name: &str,
referrer: &ModuleSpecifier,
) -> Result<PathBuf, AnyError>;
) -> Result<PathBuf, PackageFolderResolveError>;

fn resolve_package_cache_folder_id_from_specifier(
&self,
Expand Down
65 changes: 54 additions & 11 deletions cli/npm/managed/resolvers/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ use std::sync::Arc;

use async_trait::async_trait;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId;
use deno_npm::NpmSystemInfo;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::errors::PackageFolderResolveError;
use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind;
use deno_runtime::deno_node::NodePermissions;

use super::super::cache::NpmCache;
Expand Down Expand Up @@ -65,29 +66,71 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
None
}

fn package_folder(&self, id: &NpmPackageId) -> Result<PathBuf, AnyError> {
fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
let folder_id = self
.resolution
.resolve_pkg_cache_folder_id_from_pkg_id(id)
.unwrap();
Ok(self.cache.package_folder_for_id(&folder_id))
.resolve_pkg_cache_folder_id_from_pkg_id(id)?;
Some(self.cache.package_folder_for_id(&folder_id))
}

fn resolve_package_folder_from_package(
&self,
name: &str,
referrer: &ModuleSpecifier,
) -> Result<PathBuf, AnyError> {
let Some(referrer_pkg_id) = self
) -> Result<PathBuf, PackageFolderResolveError> {
use deno_npm::resolution::PackageNotFoundFromReferrerError;
let Some(referrer_cache_folder_id) = self
.cache
.resolve_package_folder_id_from_specifier(referrer)
else {
bail!("could not find npm package for '{}'", referrer);
return Err(
PackageFolderResolveErrorKind::NotFoundReferrer {
referrer: referrer.clone(),
referrer_extra: None,
}
.into(),
);
};
let pkg = self
let resolve_result = self
.resolution
.resolve_package_from_package(name, &referrer_pkg_id)?;
self.package_folder(&pkg.id)
.resolve_package_from_package(name, &referrer_cache_folder_id);
match resolve_result {
Ok(pkg) => match self.maybe_package_folder(&pkg.id) {
Some(folder) => Ok(folder),
None => Err(
PackageFolderResolveErrorKind::NotFoundPackage {
package_name: name.to_string(),
referrer: referrer.clone(),
referrer_extra: Some(format!(
"{} -> {}",
referrer_cache_folder_id,
pkg.id.as_serialized()
)),
}
.into(),
),
},
Err(err) => match *err {
PackageNotFoundFromReferrerError::Referrer(cache_folder_id) => Err(
PackageFolderResolveErrorKind::NotFoundReferrer {
referrer: referrer.clone(),
referrer_extra: Some(cache_folder_id.to_string()),
}
.into(),
),
PackageNotFoundFromReferrerError::Package {
name,
referrer: cache_folder_id_referrer,
} => Err(
PackageFolderResolveErrorKind::NotFoundPackage {
package_name: name,
referrer: referrer.clone(),
referrer_extra: Some(cache_folder_id_referrer.to_string()),
}
.into(),
),
},
}
}

fn resolve_package_cache_folder_id_from_specifier(
Expand Down
Loading

0 comments on commit 839caf6

Please sign in to comment.