refactor(node): internally add .code() to node resolution errors (#24610)
Some checks are pending
ci / publish canary (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, test, windows, release, ${{ (!contains(github.event.pull_request.labels.*.name, 'ci-full') && (github.event_name == 'pull_request')) && 'ubuntu-22.04' || github.reposi… (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, test, windows, debug, windows-2022) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, test, macos, release, ${{ (!contains(github.event.pull_request.labels.*.name, 'ci-full') && (github.event_name == 'pull_request')) && 'ubuntu-22.04' || 'macos-13' }}, … (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, test, macos, debug, macos-13) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, test, linux, release, ${{ github.repository == 'denoland/deno' && 'ubuntu-22.04-xl' || 'ubuntu-22.04' }}, true, ${{ !startsWith(github.ref, 'refs/tags/') }}) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, test, linux, debug, ubuntu-22.04, true) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, lint, windows, debug, windows-2022) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, lint, macos, debug, macos-13) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, lint, linux, debug, ubuntu-22.04) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (x86_64, bench, linux, release, ${{ (!contains(github.event.pull_request.labels.*.name, 'ci-full') && (github.event_name == 'pull_request' && !contains(github.event.pull_reques… (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (aarch64, test, macos, release, ${{ (!contains(github.event.pull_request.labels.*.name, 'ci-full') && (github.event_name == 'pull_request')) && 'ubuntu-22.04' || 'macos-14' }},… (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (aarch64, test, macos, debug, macos-14) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (aarch64, test, linux, release, ubicloud-standard-16-arm, true) (push) Blocked by required conditions
ci / ${{ matrix.job }} ${{ matrix.profile }} ${{ matrix.os }}-${{ matrix.arch }} (aarch64, test, linux, debug, ubicloud-standard-16-arm) (push) Blocked by required conditions
ci / pre-build (push) Waiting to run

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 GitHub
parent c9da27e147
commit 568dd132fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
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::FileSystem;
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::is_builtin_node_module;
use deno_runtime::deno_node::parse_npm_pkg_name;
@ -105,7 +107,7 @@ impl CliNodeResolver {
specifier: &str,
referrer: &ModuleSpecifier,
mode: NodeResolutionMode,
) -> Option<Result<Option<NodeResolution>, AnyError>> {
) -> Option<Result<Option<NodeResolution>, NodeResolveError>> {
if self.in_npm_package(referrer) {
// we're in an npm package, so use node resolution
Some(self.resolve(specifier, referrer, mode))
@ -119,19 +121,18 @@ impl CliNodeResolver {
specifier: &str,
referrer: &ModuleSpecifier,
mode: NodeResolutionMode,
) -> Result<Option<NodeResolution>, AnyError> {
) -> Result<Option<NodeResolution>, NodeResolveError> {
let referrer_kind = if self.cjs_resolutions.contains(referrer) {
NodeModuleKind::Cjs
} else {
NodeModuleKind::Esm
};
self.handle_node_resolve_result(
let maybe_res =
self
.node_resolver
.resolve(specifier, referrer, referrer_kind, mode)
.map_err(AnyError::from),
)
.resolve(specifier, referrer, referrer_kind, mode)?;
Ok(self.handle_node_resolution(maybe_res))
}
pub fn resolve_req_reference(
@ -218,18 +219,16 @@ impl CliNodeResolver {
sub_path: Option<&str>,
maybe_referrer: Option<&ModuleSpecifier>,
mode: NodeResolutionMode,
) -> Result<Option<NodeResolution>, AnyError> {
self.handle_node_resolve_result(
self
.node_resolver
.resolve_package_subpath_from_deno_module(
package_folder,
sub_path,
maybe_referrer,
mode,
)
.map_err(AnyError::from),
)
) -> Result<Option<NodeResolution>, ResolvePkgSubpathFromDenoModuleError> {
let maybe_res = self
.node_resolver
.resolve_package_subpath_from_deno_module(
package_folder,
sub_path,
maybe_referrer,
mode,
)?;
Ok(self.handle_node_resolution(maybe_res))
}
pub fn handle_if_in_node_modules(
@ -266,20 +265,15 @@ impl CliNodeResolver {
self.node_resolver.url_to_node_resolution(specifier)
}
fn handle_node_resolve_result(
fn handle_node_resolution(
&self,
result: Result<Option<NodeResolution>, AnyError>,
) -> Result<Option<NodeResolution>, AnyError> {
match result? {
Some(response) => {
if let NodeResolution::CommonJs(specifier) = &response {
// remember that this was a common js resolution
self.cjs_resolutions.insert(specifier.clone());
}
Ok(Some(response))
}
None => Ok(None),
maybe_resolution: Option<NodeResolution>,
) -> Option<NodeResolution> {
if let Some(NodeResolution::CommonJs(specifier)) = &maybe_resolution {
// remember that this was a common js resolution
self.cjs_resolutions.insert(specifier.clone());
}
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(
&self,
specifier: &str,
@ -681,7 +675,10 @@ impl Resolver for CliGraphResolver {
Err(err) => {
self
.check_surface_byonm_node_error(
specifier, referrer, err, resolver,
specifier,
referrer,
err.into(),
resolver,
)
.map_err(ResolveError::Other)?;
}

View file

@ -1,10 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::borrow::Cow;
use std::fmt::Write;
use std::path::PathBuf;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::ModuleSpecifier;
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!(
ResolvePkgSubpathFromDenoModuleError,
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)]
pub enum ResolvePkgSubpathFromDenoModuleErrorKind {
#[error(transparent)]
@ -54,7 +104,8 @@ pub enum ResolvePkgSubpathFromDenoModuleErrorKind {
// todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError
#[derive(Debug, Clone, Error)]
#[error(
"[ERR_INVALID_MODULE_SPECIFIER] Invalid module '{}' {}{}",
"[{}] Invalid module '{}' {}{}",
self.code(),
request,
reason,
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>,
}
impl NodeJsErrorCoded for InvalidModuleSpecifierError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_INVALID_MODULE_SPECIFIER
}
}
#[derive(Debug, Error)]
pub enum LegacyMainResolveError {
#[error(transparent)]
PathToDeclarationUrl(PathToDeclarationUrlError),
}
impl NodeJsErrorCoded for LegacyMainResolveError {
fn code(&self) -> NodeJsErrorCode {
match self {
Self::PathToDeclarationUrl(e) => e.code(),
}
}
}
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)]
pub enum PackageFolderResolveErrorKind {
#[error(
@ -108,15 +185,25 @@ pub enum PackageFolderResolveErrorKind {
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)]
pub enum PackageSubpathResolveErrorKind {
#[error(transparent)]
PkgJsonLoad(#[from] deno_config::package_json::PackageJsonLoadError),
PkgJsonLoad(#[from] PackageJsonLoadError),
#[error(transparent)]
PackageFolderResolve(#[from] PackageFolderResolveError),
#[error(transparent)]
DirNotFound(AnyError),
#[error(transparent)]
Exports(PackageExportsResolveError),
#[error(transparent)]
LegacyMain(LegacyMainResolveError),
@ -152,8 +239,26 @@ pub struct PackageTargetNotFoundError {
pub mode: NodeResolutionMode,
}
impl NodeJsErrorCoded for PackageTargetNotFoundError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_MODULE_NOT_FOUND
}
}
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)]
pub enum PackageTargetResolveErrorKind {
#[error(transparent)]
@ -170,6 +275,15 @@ pub enum PackageTargetResolveErrorKind {
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)]
pub enum PackageExportsResolveErrorKind {
#[error(transparent)]
@ -184,18 +298,63 @@ pub enum PathToDeclarationUrlError {
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);
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)]
pub enum ClosestPkgJsonErrorKind {
#[error("Failed canonicalizing package.json directory '{dir_path}'.")]
CanonicalizingDir {
dir_path: PathBuf,
#[source]
source: std::io::Error,
},
#[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)]
@ -204,8 +363,23 @@ pub struct TypeScriptNotSupportedInNpmError {
pub specifier: ModuleSpecifier,
}
impl NodeJsErrorCoded for TypeScriptNotSupportedInNpmError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_UNKNOWN_FILE_EXTENSION
}
}
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)]
pub enum UrlToNodeResolutionErrorKind {
#[error(transparent)]
@ -217,7 +391,8 @@ pub enum UrlToNodeResolutionErrorKind {
// todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError
#[derive(Debug, Error)]
#[error(
"[ERR_PACKAGE_IMPORT_NOT_DEFINED] Package import specifier \"{}\" is not defined{}{}",
"[{}] Package import specifier \"{}\" is not defined{}{}",
self.code(),
name,
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(),
@ -228,6 +403,12 @@ pub struct PackageImportNotDefinedError {
pub maybe_referrer: Option<ModuleSpecifier>,
}
impl NodeJsErrorCoded for PackageImportNotDefinedError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_PACKAGE_IMPORT_NOT_DEFINED
}
}
kinded_err!(PackageImportsResolveError, PackageImportsResolveErrorKind);
#[derive(Debug, Error)]
@ -242,8 +423,30 @@ pub enum PackageImportsResolveErrorKind {
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);
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)]
pub enum PackageResolveErrorKind {
#[error(transparent)]
@ -298,7 +501,8 @@ pub enum FinalizeResolutionErrorKind {
#[derive(Debug, Error)]
#[error(
"[ERR_MODULE_NOT_FOUND] Cannot find {} '{}'{}",
"[{}] Cannot find {} '{}'{}",
self.code(),
typ,
specifier,
maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default()
@ -309,9 +513,16 @@ pub struct ModuleNotFoundError {
pub typ: &'static str,
}
impl ModuleNotFoundError {
pub fn code(&self) -> &'static str {
"ERR_MODULE_NOT_FOUND"
}
}
#[derive(Debug, 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,
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>,
}
impl NodeJsErrorCoded for UnsupportedDirImportError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_UNSUPPORTED_DIR_IMPORT
}
}
#[derive(Debug)]
pub struct InvalidPackageTargetError {
pub pkg_json_path: PathBuf,
@ -336,7 +553,9 @@ impl std::fmt::Display for InvalidPackageTargetError {
let rel_error = !self.is_import
&& !self.target.is_empty()
&& !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 == "." {
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)]
pub struct PackagePathNotExportedError {
pub pkg_json_path: PathBuf,
@ -376,11 +601,19 @@ pub struct PackagePathNotExportedError {
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::fmt::Display for PackagePathNotExportedError {
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 {
NodeResolutionMode::Execution => String::new(),
@ -412,7 +645,8 @@ impl std::fmt::Display for PackagePathNotExportedError {
#[derive(Debug, Clone, 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 { "" },
url_scheme
)]
@ -420,10 +654,16 @@ pub struct UnsupportedEsmUrlSchemeError {
pub url_scheme: String,
}
impl NodeJsErrorCoded for UnsupportedEsmUrlSchemeError {
fn code(&self) -> NodeJsErrorCode {
NodeJsErrorCode::ERR_UNSUPPORTED_ESM_URL_SCHEME
}
}
#[derive(Debug, Error)]
pub enum ResolvePkgJsonBinExportError {
#[error(transparent)]
PkgJsonLoad(#[from] deno_config::package_json::PackageJsonLoadError),
PkgJsonLoad(#[from] PackageJsonLoadError),
#[error("Failed resolving binary export. '{}' did not exist", pkg_json_path.display())]
MissingPkgJson { pkg_json_path: PathBuf },
#[error("Failed resolving binary export. {message}")]
@ -435,31 +675,11 @@ pub enum ResolvePkgJsonBinExportError {
#[derive(Debug, Error)]
pub enum ResolveBinaryCommandsError {
#[error(transparent)]
PkgJsonLoad(#[from] deno_config::package_json::PackageJsonLoadError),
PkgJsonLoad(#[from] PackageJsonLoadError),
#[error("'{}' did not have a name", pkg_json_path.display())]
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)]
mod test {
use super::*;

View file

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

View file

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