1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-29 16:30:56 -05:00

refactor(node): internally add .code() to node resolution errors (#24610)

This makes it easier to tell what kind of error something is (even for
deeply nested errors) and will help in the future once we add error
codes to the JS errors this returns.
This commit is contained in:
David Sherret 2024-07-16 18:32:41 -04:00 committed by Bartek Iwańczuk
parent 6e6c5ab51a
commit 35cbe2937d
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
4 changed files with 313 additions and 98 deletions

View file

@ -24,6 +24,8 @@ use deno_npm::resolution::NpmResolutionError;
use deno_runtime::deno_fs; use deno_runtime::deno_fs;
use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::errors::ClosestPkgJsonError; use deno_runtime::deno_node::errors::ClosestPkgJsonError;
use deno_runtime::deno_node::errors::NodeResolveError;
use deno_runtime::deno_node::errors::ResolvePkgSubpathFromDenoModuleError;
use deno_runtime::deno_node::errors::UrlToNodeResolutionError; use deno_runtime::deno_node::errors::UrlToNodeResolutionError;
use deno_runtime::deno_node::is_builtin_node_module; use deno_runtime::deno_node::is_builtin_node_module;
use deno_runtime::deno_node::parse_npm_pkg_name; use deno_runtime::deno_node::parse_npm_pkg_name;
@ -105,7 +107,7 @@ impl CliNodeResolver {
specifier: &str, specifier: &str,
referrer: &ModuleSpecifier, referrer: &ModuleSpecifier,
mode: NodeResolutionMode, mode: NodeResolutionMode,
) -> Option<Result<Option<NodeResolution>, AnyError>> { ) -> Option<Result<Option<NodeResolution>, NodeResolveError>> {
if self.in_npm_package(referrer) { if self.in_npm_package(referrer) {
// we're in an npm package, so use node resolution // we're in an npm package, so use node resolution
Some(self.resolve(specifier, referrer, mode)) Some(self.resolve(specifier, referrer, mode))
@ -119,19 +121,18 @@ impl CliNodeResolver {
specifier: &str, specifier: &str,
referrer: &ModuleSpecifier, referrer: &ModuleSpecifier,
mode: NodeResolutionMode, mode: NodeResolutionMode,
) -> Result<Option<NodeResolution>, AnyError> { ) -> Result<Option<NodeResolution>, NodeResolveError> {
let referrer_kind = if self.cjs_resolutions.contains(referrer) { let referrer_kind = if self.cjs_resolutions.contains(referrer) {
NodeModuleKind::Cjs NodeModuleKind::Cjs
} else { } else {
NodeModuleKind::Esm NodeModuleKind::Esm
}; };
self.handle_node_resolve_result( let maybe_res =
self self
.node_resolver .node_resolver
.resolve(specifier, referrer, referrer_kind, mode) .resolve(specifier, referrer, referrer_kind, mode)?;
.map_err(AnyError::from), Ok(self.handle_node_resolution(maybe_res))
)
} }
pub fn resolve_req_reference( pub fn resolve_req_reference(
@ -218,18 +219,16 @@ impl CliNodeResolver {
sub_path: Option<&str>, sub_path: Option<&str>,
maybe_referrer: Option<&ModuleSpecifier>, maybe_referrer: Option<&ModuleSpecifier>,
mode: NodeResolutionMode, mode: NodeResolutionMode,
) -> Result<Option<NodeResolution>, AnyError> { ) -> Result<Option<NodeResolution>, ResolvePkgSubpathFromDenoModuleError> {
self.handle_node_resolve_result( let maybe_res = self
self .node_resolver
.node_resolver .resolve_package_subpath_from_deno_module(
.resolve_package_subpath_from_deno_module( package_folder,
package_folder, sub_path,
sub_path, maybe_referrer,
maybe_referrer, mode,
mode, )?;
) Ok(self.handle_node_resolution(maybe_res))
.map_err(AnyError::from),
)
} }
pub fn handle_if_in_node_modules( pub fn handle_if_in_node_modules(
@ -266,20 +265,15 @@ impl CliNodeResolver {
self.node_resolver.url_to_node_resolution(specifier) self.node_resolver.url_to_node_resolution(specifier)
} }
fn handle_node_resolve_result( fn handle_node_resolution(
&self, &self,
result: Result<Option<NodeResolution>, AnyError>, maybe_resolution: Option<NodeResolution>,
) -> Result<Option<NodeResolution>, AnyError> { ) -> Option<NodeResolution> {
match result? { if let Some(NodeResolution::CommonJs(specifier)) = &maybe_resolution {
Some(response) => { // remember that this was a common js resolution
if let NodeResolution::CommonJs(specifier) = &response { self.cjs_resolutions.insert(specifier.clone());
// remember that this was a common js resolution
self.cjs_resolutions.insert(specifier.clone());
}
Ok(Some(response))
}
None => Ok(None),
} }
maybe_resolution
} }
} }
@ -465,7 +459,7 @@ impl CliGraphResolver {
} }
} }
// todo(dsherret): if we returned structured errors from the NodeResolver we wouldn't need this // todo(dsherret): update this and the surrounding code to handle the structured errors from NodeResolver
fn check_surface_byonm_node_error( fn check_surface_byonm_node_error(
&self, &self,
specifier: &str, specifier: &str,
@ -681,7 +675,10 @@ impl Resolver for CliGraphResolver {
Err(err) => { Err(err) => {
self self
.check_surface_byonm_node_error( .check_surface_byonm_node_error(
specifier, referrer, err, resolver, specifier,
referrer,
err.into(),
resolver,
) )
.map_err(ResolveError::Other)?; .map_err(ResolveError::Other)?;
} }

View file

@ -1,10 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::Write;
use std::path::PathBuf; use std::path::PathBuf;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use thiserror::Error; use thiserror::Error;
@ -38,11 +37,62 @@ macro_rules! kinded_err {
}; };
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types)]
pub enum NodeJsErrorCode {
ERR_INVALID_MODULE_SPECIFIER,
ERR_INVALID_PACKAGE_CONFIG,
ERR_INVALID_PACKAGE_TARGET,
ERR_MODULE_NOT_FOUND,
ERR_PACKAGE_IMPORT_NOT_DEFINED,
ERR_PACKAGE_PATH_NOT_EXPORTED,
ERR_UNKNOWN_FILE_EXTENSION,
ERR_UNSUPPORTED_DIR_IMPORT,
ERR_UNSUPPORTED_ESM_URL_SCHEME,
}
impl std::fmt::Display for NodeJsErrorCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl NodeJsErrorCode {
pub fn as_str(&self) -> &'static str {
use NodeJsErrorCode::*;
match self {
ERR_INVALID_MODULE_SPECIFIER => "ERR_INVALID_MODULE_SPECIFIER",
ERR_INVALID_PACKAGE_CONFIG => "ERR_INVALID_PACKAGE_CONFIG",
ERR_INVALID_PACKAGE_TARGET => "ERR_INVALID_PACKAGE_TARGET",
ERR_MODULE_NOT_FOUND => "ERR_MODULE_NOT_FOUND",
ERR_PACKAGE_IMPORT_NOT_DEFINED => "ERR_PACKAGE_IMPORT_NOT_DEFINED",
ERR_PACKAGE_PATH_NOT_EXPORTED => "ERR_PACKAGE_PATH_NOT_EXPORTED",
ERR_UNKNOWN_FILE_EXTENSION => "ERR_UNKNOWN_FILE_EXTENSION",
ERR_UNSUPPORTED_DIR_IMPORT => "ERR_UNSUPPORTED_DIR_IMPORT",
ERR_UNSUPPORTED_ESM_URL_SCHEME => "ERR_UNSUPPORTED_ESM_URL_SCHEME",
}
}
}
pub trait NodeJsErrorCoded {
fn code(&self) -> NodeJsErrorCode;
}
kinded_err!( kinded_err!(
ResolvePkgSubpathFromDenoModuleError, ResolvePkgSubpathFromDenoModuleError,
ResolvePkgSubpathFromDenoModuleErrorKind ResolvePkgSubpathFromDenoModuleErrorKind
); );
impl NodeJsErrorCoded for ResolvePkgSubpathFromDenoModuleError {
fn code(&self) -> NodeJsErrorCode {
use ResolvePkgSubpathFromDenoModuleErrorKind::*;
match self.as_kind() {
PackageSubpathResolve(e) => e.code(),
UrlToNodeResolution(e) => e.code(),
}
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ResolvePkgSubpathFromDenoModuleErrorKind { pub enum ResolvePkgSubpathFromDenoModuleErrorKind {
#[error(transparent)] #[error(transparent)]
@ -54,7 +104,8 @@ pub enum ResolvePkgSubpathFromDenoModuleErrorKind {
// todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError // todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError
#[derive(Debug, Clone, Error)] #[derive(Debug, Clone, Error)]
#[error( #[error(
"[ERR_INVALID_MODULE_SPECIFIER] Invalid module '{}' {}{}", "[{}] Invalid module '{}' {}{}",
self.code(),
request, request,
reason, reason,
maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default() maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default()
@ -65,14 +116,40 @@ pub struct InvalidModuleSpecifierError {
pub maybe_referrer: Option<String>, pub maybe_referrer: Option<String>,
} }
impl NodeJsErrorCoded for InvalidModuleSpecifierError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_INVALID_MODULE_SPECIFIER
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum LegacyMainResolveError { pub enum LegacyMainResolveError {
#[error(transparent)] #[error(transparent)]
PathToDeclarationUrl(PathToDeclarationUrlError), PathToDeclarationUrl(PathToDeclarationUrlError),
} }
impl NodeJsErrorCoded for LegacyMainResolveError {
fn code(&self) -> NodeJsErrorCode {
match self {
Self::PathToDeclarationUrl(e) => e.code(),
}
}
}
kinded_err!(PackageFolderResolveError, PackageFolderResolveErrorKind); kinded_err!(PackageFolderResolveError, PackageFolderResolveErrorKind);
impl NodeJsErrorCoded for PackageFolderResolveError {
fn code(&self) -> NodeJsErrorCode {
match self.as_kind() {
PackageFolderResolveErrorKind::NotFoundPackage { .. }
| PackageFolderResolveErrorKind::NotFoundReferrer { .. }
| PackageFolderResolveErrorKind::Io { .. } => {
NodeJsErrorCode::ERR_MODULE_NOT_FOUND
}
}
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum PackageFolderResolveErrorKind { pub enum PackageFolderResolveErrorKind {
#[error( #[error(
@ -108,15 +185,25 @@ pub enum PackageFolderResolveErrorKind {
kinded_err!(PackageSubpathResolveError, PackageSubpathResolveErrorKind); kinded_err!(PackageSubpathResolveError, PackageSubpathResolveErrorKind);
impl NodeJsErrorCoded for PackageSubpathResolveError {
fn code(&self) -> NodeJsErrorCode {
match self.as_kind() {
PackageSubpathResolveErrorKind::PkgJsonLoad(e) => e.code(),
PackageSubpathResolveErrorKind::PackageFolderResolve(e) => e.code(),
PackageSubpathResolveErrorKind::Exports(e) => e.code(),
PackageSubpathResolveErrorKind::LegacyMain(e) => e.code(),
PackageSubpathResolveErrorKind::LegacyExact(e) => e.code(),
}
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum PackageSubpathResolveErrorKind { pub enum PackageSubpathResolveErrorKind {
#[error(transparent)] #[error(transparent)]
PkgJsonLoad(#[from] deno_config::package_json::PackageJsonLoadError), PkgJsonLoad(#[from] PackageJsonLoadError),
#[error(transparent)] #[error(transparent)]
PackageFolderResolve(#[from] PackageFolderResolveError), PackageFolderResolve(#[from] PackageFolderResolveError),
#[error(transparent)] #[error(transparent)]
DirNotFound(AnyError),
#[error(transparent)]
Exports(PackageExportsResolveError), Exports(PackageExportsResolveError),
#[error(transparent)] #[error(transparent)]
LegacyMain(LegacyMainResolveError), LegacyMain(LegacyMainResolveError),
@ -152,8 +239,26 @@ pub struct PackageTargetNotFoundError {
pub mode: NodeResolutionMode, pub mode: NodeResolutionMode,
} }
impl NodeJsErrorCoded for PackageTargetNotFoundError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_MODULE_NOT_FOUND
}
}
kinded_err!(PackageTargetResolveError, PackageTargetResolveErrorKind); kinded_err!(PackageTargetResolveError, PackageTargetResolveErrorKind);
impl NodeJsErrorCoded for PackageTargetResolveError {
fn code(&self) -> NodeJsErrorCode {
match self.as_kind() {
PackageTargetResolveErrorKind::NotFound(e) => e.code(),
PackageTargetResolveErrorKind::InvalidPackageTarget(e) => e.code(),
PackageTargetResolveErrorKind::InvalidModuleSpecifier(e) => e.code(),
PackageTargetResolveErrorKind::PackageResolve(e) => e.code(),
PackageTargetResolveErrorKind::PathToDeclarationUrl(e) => e.code(),
}
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum PackageTargetResolveErrorKind { pub enum PackageTargetResolveErrorKind {
#[error(transparent)] #[error(transparent)]
@ -170,6 +275,15 @@ pub enum PackageTargetResolveErrorKind {
kinded_err!(PackageExportsResolveError, PackageExportsResolveErrorKind); kinded_err!(PackageExportsResolveError, PackageExportsResolveErrorKind);
impl NodeJsErrorCoded for PackageExportsResolveError {
fn code(&self) -> NodeJsErrorCode {
match self.as_kind() {
PackageExportsResolveErrorKind::PackagePathNotExported(e) => e.code(),
PackageExportsResolveErrorKind::PackageTargetResolve(e) => e.code(),
}
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum PackageExportsResolveErrorKind { pub enum PackageExportsResolveErrorKind {
#[error(transparent)] #[error(transparent)]
@ -184,18 +298,63 @@ pub enum PathToDeclarationUrlError {
SubPath(#[from] PackageSubpathResolveError), SubPath(#[from] PackageSubpathResolveError),
} }
impl NodeJsErrorCoded for PathToDeclarationUrlError {
fn code(&self) -> NodeJsErrorCode {
match self {
PathToDeclarationUrlError::SubPath(e) => e.code(),
}
}
}
#[derive(Debug, Error)]
#[error(
"[{}] Invalid package config. {}",
self.code(),
self.0
)]
pub struct PackageJsonLoadError(
#[source]
#[from]
pub deno_config::package_json::PackageJsonLoadError,
);
impl NodeJsErrorCoded for PackageJsonLoadError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_INVALID_PACKAGE_CONFIG
}
}
kinded_err!(ClosestPkgJsonError, ClosestPkgJsonErrorKind); kinded_err!(ClosestPkgJsonError, ClosestPkgJsonErrorKind);
impl NodeJsErrorCoded for ClosestPkgJsonError {
fn code(&self) -> NodeJsErrorCode {
match self.as_kind() {
ClosestPkgJsonErrorKind::CanonicalizingDir(e) => e.code(),
ClosestPkgJsonErrorKind::Load(e) => e.code(),
}
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ClosestPkgJsonErrorKind { pub enum ClosestPkgJsonErrorKind {
#[error("Failed canonicalizing package.json directory '{dir_path}'.")]
CanonicalizingDir {
dir_path: PathBuf,
#[source]
source: std::io::Error,
},
#[error(transparent)] #[error(transparent)]
Load(#[from] deno_config::package_json::PackageJsonLoadError), CanonicalizingDir(#[from] CanonicalizingPkgJsonDirError),
#[error(transparent)]
Load(#[from] PackageJsonLoadError),
}
#[derive(Debug, Error)]
#[error("[{}] Failed canonicalizing package.json directory '{}'.", self.code(), dir_path.display())]
pub struct CanonicalizingPkgJsonDirError {
pub dir_path: PathBuf,
#[source]
pub source: std::io::Error,
}
impl NodeJsErrorCoded for CanonicalizingPkgJsonDirError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_MODULE_NOT_FOUND
}
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -204,8 +363,23 @@ pub struct TypeScriptNotSupportedInNpmError {
pub specifier: ModuleSpecifier, pub specifier: ModuleSpecifier,
} }
impl NodeJsErrorCoded for TypeScriptNotSupportedInNpmError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_UNKNOWN_FILE_EXTENSION
}
}
kinded_err!(UrlToNodeResolutionError, UrlToNodeResolutionErrorKind); kinded_err!(UrlToNodeResolutionError, UrlToNodeResolutionErrorKind);
impl NodeJsErrorCoded for UrlToNodeResolutionError {
fn code(&self) -> NodeJsErrorCode {
match self.as_kind() {
UrlToNodeResolutionErrorKind::TypeScriptNotSupported(e) => e.code(),
UrlToNodeResolutionErrorKind::ClosestPkgJson(e) => e.code(),
}
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum UrlToNodeResolutionErrorKind { pub enum UrlToNodeResolutionErrorKind {
#[error(transparent)] #[error(transparent)]
@ -217,7 +391,8 @@ pub enum UrlToNodeResolutionErrorKind {
// todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError // todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[error( #[error(
"[ERR_PACKAGE_IMPORT_NOT_DEFINED] Package import specifier \"{}\" is not defined{}{}", "[{}] Package import specifier \"{}\" is not defined{}{}",
self.code(),
name, name,
package_json_path.as_ref().map(|p| format!(" in package {}", p.display())).unwrap_or_default(), package_json_path.as_ref().map(|p| format!(" in package {}", p.display())).unwrap_or_default(),
maybe_referrer.as_ref().map(|r| format!(" imported from '{}'", r)).unwrap_or_default(), maybe_referrer.as_ref().map(|r| format!(" imported from '{}'", r)).unwrap_or_default(),
@ -228,6 +403,12 @@ pub struct PackageImportNotDefinedError {
pub maybe_referrer: Option<ModuleSpecifier>, pub maybe_referrer: Option<ModuleSpecifier>,
} }
impl NodeJsErrorCoded for PackageImportNotDefinedError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_PACKAGE_IMPORT_NOT_DEFINED
}
}
kinded_err!(PackageImportsResolveError, PackageImportsResolveErrorKind); kinded_err!(PackageImportsResolveError, PackageImportsResolveErrorKind);
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -242,8 +423,30 @@ pub enum PackageImportsResolveErrorKind {
Target(#[from] PackageTargetResolveError), Target(#[from] PackageTargetResolveError),
} }
impl NodeJsErrorCoded for PackageImportsResolveErrorKind {
fn code(&self) -> NodeJsErrorCode {
match self {
Self::ClosestPkgJson(e) => e.code(),
Self::InvalidModuleSpecifier(e) => e.code(),
Self::NotDefined(e) => e.code(),
Self::Target(e) => e.code(),
}
}
}
kinded_err!(PackageResolveError, PackageResolveErrorKind); kinded_err!(PackageResolveError, PackageResolveErrorKind);
impl NodeJsErrorCoded for PackageResolveError {
fn code(&self) -> NodeJsErrorCode {
match self.as_kind() {
PackageResolveErrorKind::ClosestPkgJson(e) => e.code(),
PackageResolveErrorKind::InvalidModuleSpecifier(e) => e.code(),
PackageResolveErrorKind::ExportsResolve(e) => e.code(),
PackageResolveErrorKind::SubpathResolve(e) => e.code(),
}
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum PackageResolveErrorKind { pub enum PackageResolveErrorKind {
#[error(transparent)] #[error(transparent)]
@ -298,7 +501,8 @@ pub enum FinalizeResolutionErrorKind {
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[error( #[error(
"[ERR_MODULE_NOT_FOUND] Cannot find {} '{}'{}", "[{}] Cannot find {} '{}'{}",
self.code(),
typ, typ,
specifier, specifier,
maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default() maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default()
@ -309,9 +513,16 @@ pub struct ModuleNotFoundError {
pub typ: &'static str, pub typ: &'static str,
} }
impl ModuleNotFoundError {
pub fn code(&self) -> &'static str {
"ERR_MODULE_NOT_FOUND"
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[error( #[error(
"[ERR_UNSUPPORTED_DIR_IMPORT] Directory import '{}' is not supported resolving ES modules{}", "[{}] Directory import '{}' is not supported resolving ES modules{}",
self.code(),
dir_url, dir_url,
maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default(), maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default(),
)] )]
@ -320,6 +531,12 @@ pub struct UnsupportedDirImportError {
pub maybe_referrer: Option<ModuleSpecifier>, pub maybe_referrer: Option<ModuleSpecifier>,
} }
impl NodeJsErrorCoded for UnsupportedDirImportError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_UNSUPPORTED_DIR_IMPORT
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct InvalidPackageTargetError { pub struct InvalidPackageTargetError {
pub pkg_json_path: PathBuf, pub pkg_json_path: PathBuf,
@ -336,7 +553,9 @@ impl std::fmt::Display for InvalidPackageTargetError {
let rel_error = !self.is_import let rel_error = !self.is_import
&& !self.target.is_empty() && !self.target.is_empty()
&& !self.target.starts_with("./"); && !self.target.starts_with("./");
f.write_str("[ERR_INVALID_PACKAGE_TARGET]")?; f.write_char('[')?;
f.write_str(self.code().as_str())?;
f.write_char(']')?;
if self.sub_path == "." { if self.sub_path == "." {
assert!(!self.is_import); assert!(!self.is_import);
@ -368,6 +587,12 @@ impl std::fmt::Display for InvalidPackageTargetError {
} }
} }
impl NodeJsErrorCoded for InvalidPackageTargetError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_INVALID_PACKAGE_TARGET
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct PackagePathNotExportedError { pub struct PackagePathNotExportedError {
pub pkg_json_path: PathBuf, pub pkg_json_path: PathBuf,
@ -376,11 +601,19 @@ pub struct PackagePathNotExportedError {
pub mode: NodeResolutionMode, pub mode: NodeResolutionMode,
} }
impl NodeJsErrorCoded for PackagePathNotExportedError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_PACKAGE_PATH_NOT_EXPORTED
}
}
impl std::error::Error for PackagePathNotExportedError {} impl std::error::Error for PackagePathNotExportedError {}
impl std::fmt::Display for PackagePathNotExportedError { impl std::fmt::Display for PackagePathNotExportedError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("[ERR_PACKAGE_PATH_NOT_EXPORTED]")?; f.write_char('[')?;
f.write_str(self.code().as_str())?;
f.write_char(']')?;
let types_msg = match self.mode { let types_msg = match self.mode {
NodeResolutionMode::Execution => String::new(), NodeResolutionMode::Execution => String::new(),
@ -412,7 +645,8 @@ impl std::fmt::Display for PackagePathNotExportedError {
#[derive(Debug, Clone, Error)] #[derive(Debug, Clone, Error)]
#[error( #[error(
"[ERR_UNSUPPORTED_ESM_URL_SCHEME] Only file and data URLS are supported by the default ESM loader.{} Received protocol '{}'", "[{}] Only file and data URLs are supported by the default ESM loader.{} Received protocol '{}'",
self.code(),
if cfg!(windows) && url_scheme.len() == 2 { " On Windows, absolute path must be valid file:// URLS."} else { "" }, if cfg!(windows) && url_scheme.len() == 2 { " On Windows, absolute path must be valid file:// URLS."} else { "" },
url_scheme url_scheme
)] )]
@ -420,10 +654,16 @@ pub struct UnsupportedEsmUrlSchemeError {
pub url_scheme: String, pub url_scheme: String,
} }
impl NodeJsErrorCoded for UnsupportedEsmUrlSchemeError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_UNSUPPORTED_ESM_URL_SCHEME
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ResolvePkgJsonBinExportError { pub enum ResolvePkgJsonBinExportError {
#[error(transparent)] #[error(transparent)]
PkgJsonLoad(#[from] deno_config::package_json::PackageJsonLoadError), PkgJsonLoad(#[from] PackageJsonLoadError),
#[error("Failed resolving binary export. '{}' did not exist", pkg_json_path.display())] #[error("Failed resolving binary export. '{}' did not exist", pkg_json_path.display())]
MissingPkgJson { pkg_json_path: PathBuf }, MissingPkgJson { pkg_json_path: PathBuf },
#[error("Failed resolving binary export. {message}")] #[error("Failed resolving binary export. {message}")]
@ -435,31 +675,11 @@ pub enum ResolvePkgJsonBinExportError {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ResolveBinaryCommandsError { pub enum ResolveBinaryCommandsError {
#[error(transparent)] #[error(transparent)]
PkgJsonLoad(#[from] deno_config::package_json::PackageJsonLoadError), PkgJsonLoad(#[from] PackageJsonLoadError),
#[error("'{}' did not have a name", pkg_json_path.display())] #[error("'{}' did not have a name", pkg_json_path.display())]
MissingPkgJsonName { pkg_json_path: PathBuf }, MissingPkgJsonName { pkg_json_path: PathBuf },
} }
#[allow(unused)]
pub fn err_invalid_package_config(
path: &str,
maybe_base: Option<String>,
maybe_message: Option<String>,
) -> AnyError {
let mut msg =
format!("[ERR_INVALID_PACKAGE_CONFIG] Invalid package config {path}");
if let Some(base) = maybe_base {
msg = format!("{msg} while importing {base}");
}
if let Some(message) = maybe_message {
msg = format!("{msg}. {message}");
}
generic_error(msg)
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View file

@ -1,7 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_config::package_json::PackageJson; use deno_config::package_json::PackageJson;
use deno_config::package_json::PackageJsonLoadError;
use deno_config::package_json::PackageJsonRc; use deno_config::package_json::PackageJsonRc;
use deno_fs::DenoConfigFsAdapter; use deno_fs::DenoConfigFsAdapter;
use std::cell::RefCell; use std::cell::RefCell;
@ -10,6 +9,8 @@ use std::io::ErrorKind;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use crate::errors::PackageJsonLoadError;
// use a thread local cache so that workers have their own distinct cache // use a thread local cache so that workers have their own distinct cache
thread_local! { thread_local! {
static CACHE: RefCell<HashMap<PathBuf, PackageJsonRc>> = RefCell::new(HashMap::new()); static CACHE: RefCell<HashMap<PathBuf, PackageJsonRc>> = RefCell::new(HashMap::new());
@ -48,11 +49,9 @@ pub fn load_pkg_json(
); );
match result { match result {
Ok(pkg_json) => Ok(Some(pkg_json)), Ok(pkg_json) => Ok(Some(pkg_json)),
Err(PackageJsonLoadError::Io { source, .. }) Err(deno_config::package_json::PackageJsonLoadError::Io {
if source.kind() == ErrorKind::NotFound => source, ..
{ }) if source.kind() == ErrorKind::NotFound => Ok(None),
Ok(None) Err(err) => Err(PackageJsonLoadError(err)),
}
Err(err) => Err(err),
} }
} }

View file

@ -16,18 +16,21 @@ use deno_fs::FileSystemRc;
use deno_media_type::MediaType; use deno_media_type::MediaType;
use crate::errors; use crate::errors;
use crate::errors::CanonicalizingPkgJsonDirError;
use crate::errors::ClosestPkgJsonError; use crate::errors::ClosestPkgJsonError;
use crate::errors::ClosestPkgJsonErrorKind;
use crate::errors::FinalizeResolutionError; use crate::errors::FinalizeResolutionError;
use crate::errors::InvalidModuleSpecifierError; use crate::errors::InvalidModuleSpecifierError;
use crate::errors::InvalidPackageTargetError; use crate::errors::InvalidPackageTargetError;
use crate::errors::LegacyMainResolveError; use crate::errors::LegacyMainResolveError;
use crate::errors::ModuleNotFoundError; use crate::errors::ModuleNotFoundError;
use crate::errors::NodeJsErrorCode;
use crate::errors::NodeJsErrorCoded;
use crate::errors::NodeResolveError; use crate::errors::NodeResolveError;
use crate::errors::PackageExportsResolveError; use crate::errors::PackageExportsResolveError;
use crate::errors::PackageImportNotDefinedError; use crate::errors::PackageImportNotDefinedError;
use crate::errors::PackageImportsResolveError; use crate::errors::PackageImportsResolveError;
use crate::errors::PackageImportsResolveErrorKind; use crate::errors::PackageImportsResolveErrorKind;
use crate::errors::PackageJsonLoadError;
use crate::errors::PackagePathNotExportedError; use crate::errors::PackagePathNotExportedError;
use crate::errors::PackageResolveError; use crate::errors::PackageResolveError;
use crate::errors::PackageSubpathResolveError; use crate::errors::PackageSubpathResolveError;
@ -283,7 +286,7 @@ impl NodeResolver {
let maybe_url = if mode.is_types() { let maybe_url = if mode.is_types() {
let file_path = to_file_path(&url); let file_path = to_file_path(&url);
self.path_to_declaration_url(file_path, Some(referrer), referrer_kind)? self.path_to_declaration_url(&file_path, Some(referrer), referrer_kind)?
} else { } else {
Some(url) Some(url)
}; };
@ -469,7 +472,7 @@ impl NodeResolver {
/// Checks if the resolved file has a corresponding declaration file. /// Checks if the resolved file has a corresponding declaration file.
fn path_to_declaration_url( fn path_to_declaration_url(
&self, &self,
path: PathBuf, path: &Path,
maybe_referrer: Option<&ModuleSpecifier>, maybe_referrer: Option<&ModuleSpecifier>,
referrer_kind: NodeModuleKind, referrer_kind: NodeModuleKind,
) -> Result<Option<ModuleSpecifier>, PathToDeclarationUrlError> { ) -> Result<Option<ModuleSpecifier>, PathToDeclarationUrlError> {
@ -522,16 +525,16 @@ impl NodeResolver {
|| lowercase_path.ends_with(".d.cts") || lowercase_path.ends_with(".d.cts")
|| lowercase_path.ends_with(".d.mts") || lowercase_path.ends_with(".d.mts")
{ {
return Ok(Some(to_file_specifier(&path))); return Ok(Some(to_file_specifier(path)));
} }
if let Some(path) = if let Some(path) =
probe_extensions(&*self.fs, &path, &lowercase_path, referrer_kind) probe_extensions(&*self.fs, path, &lowercase_path, referrer_kind)
{ {
return Ok(Some(to_file_specifier(&path))); return Ok(Some(to_file_specifier(&path)));
} }
if self.fs.is_dir_sync(&path) { if self.fs.is_dir_sync(path) {
let maybe_resolution = self.resolve_package_dir_subpath( let maybe_resolution = self.resolve_package_dir_subpath(
&path, path,
/* sub path */ ".", /* sub path */ ".",
maybe_referrer, maybe_referrer,
referrer_kind, referrer_kind,
@ -556,7 +559,7 @@ impl NodeResolver {
} }
// allow resolving .css files for types resolution // allow resolving .css files for types resolution
if lowercase_path.ends_with(".css") { if lowercase_path.ends_with(".css") {
return Ok(Some(to_file_specifier(&path))); return Ok(Some(to_file_specifier(path)));
} }
Ok(None) Ok(None)
} }
@ -845,7 +848,7 @@ impl NodeResolver {
if mode.is_types() && url.scheme() == "file" { if mode.is_types() && url.scheme() == "file" {
let path = url.to_file_path().unwrap(); let path = url.to_file_path().unwrap();
return Ok(self.path_to_declaration_url( return Ok(self.path_to_declaration_url(
path, &path,
maybe_referrer, maybe_referrer,
referrer_kind, referrer_kind,
)?); )?);
@ -879,8 +882,7 @@ impl NodeResolver {
continue; continue;
} }
Err(e) => { Err(e) => {
// todo(dsherret): add codes to each error and match on that instead if e.code() == NodeJsErrorCode::ERR_INVALID_PACKAGE_TARGET {
if e.to_string().starts_with("[ERR_INVALID_PACKAGE_TARGET]") {
last_error = Some(e); last_error = Some(e);
continue; continue;
} else { } else {
@ -1274,7 +1276,7 @@ impl NodeResolver {
assert_ne!(package_subpath, "."); assert_ne!(package_subpath, ".");
let file_path = directory.join(package_subpath); let file_path = directory.join(package_subpath);
if mode.is_types() { if mode.is_types() {
Ok(self.path_to_declaration_url(file_path, referrer, referrer_kind)?) Ok(self.path_to_declaration_url(&file_path, referrer, referrer_kind)?)
} else { } else {
Ok(Some(to_file_specifier(&file_path))) Ok(Some(to_file_specifier(&file_path)))
} }
@ -1318,7 +1320,7 @@ impl NodeResolver {
let parent_dir = file_path.parent().unwrap(); let parent_dir = file_path.parent().unwrap();
let current_dir = let current_dir =
deno_core::strip_unc_prefix(self.fs.realpath_sync(parent_dir).map_err( deno_core::strip_unc_prefix(self.fs.realpath_sync(parent_dir).map_err(
|source| ClosestPkgJsonErrorKind::CanonicalizingDir { |source| CanonicalizingPkgJsonDirError {
dir_path: parent_dir.to_path_buf(), dir_path: parent_dir.to_path_buf(),
source: source.into_io_error(), source: source.into_io_error(),
}, },
@ -1336,10 +1338,7 @@ impl NodeResolver {
pub(super) fn load_package_json( pub(super) fn load_package_json(
&self, &self,
package_json_path: &Path, package_json_path: &Path,
) -> Result< ) -> Result<Option<PackageJsonRc>, PackageJsonLoadError> {
Option<PackageJsonRc>,
deno_config::package_json::PackageJsonLoadError,
> {
crate::package_json::load_pkg_json(&*self.fs, package_json_path) crate::package_json::load_pkg_json(&*self.fs, package_json_path)
} }
@ -1359,7 +1358,7 @@ impl NodeResolver {
if let Some(main) = package_json.main(referrer_kind) { if let Some(main) = package_json.main(referrer_kind) {
let main = package_json.path.parent().unwrap().join(main).clean(); let main = package_json.path.parent().unwrap().join(main).clean();
let maybe_decl_url = self let maybe_decl_url = self
.path_to_declaration_url(main, maybe_referrer, referrer_kind) .path_to_declaration_url(&main, maybe_referrer, referrer_kind)
.map_err(LegacyMainResolveError::PathToDeclarationUrl)?; .map_err(LegacyMainResolveError::PathToDeclarationUrl)?;
if let Some(path) = maybe_decl_url { if let Some(path) = maybe_decl_url {
return Ok(Some(path)); return Ok(Some(path));