perf(node_resolver): reduce url to/from path conversions (#27839)

Extracted out of https://github.com/denoland/deno/pull/27838/files

Reduces some allocations by accepting either a pathbuf or url for the
referrer for resolution and returning either a pathbuf or url at the
end, which the caller can then convert into to their preferred state.

This is about 4% faster when still converting the final result to a url
and 6% faster when keeping the result as a path in a benchmark I ran.
This commit is contained in:
David Sherret 2025-01-27 15:23:20 -05:00 committed by Bartek Iwańczuk
parent 690da479dd
commit 55b19e3e7a
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
28 changed files with 679 additions and 417 deletions

1
Cargo.lock generated
View file

@ -5260,6 +5260,7 @@ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
"boxed_error", "boxed_error",
"dashmap",
"deno_error", "deno_error",
"deno_package_json", "deno_package_json",
"deno_path_util", "deno_path_util",

View file

@ -7,6 +7,8 @@ use std::sync::Arc;
use deno_core::error::JsError; use deno_core::error::JsError;
use deno_node::NodeRequireLoaderRc; use deno_node::NodeRequireLoaderRc;
use deno_path_util::url_from_file_path;
use deno_path_util::url_to_file_path;
use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmResolver; use deno_resolver::npm::NpmResolver;
use deno_runtime::colors; use deno_runtime::colors;
@ -44,6 +46,7 @@ use deno_runtime::WorkerExecutionMode;
use deno_runtime::WorkerLogLevel; use deno_runtime::WorkerLogLevel;
use deno_runtime::UNSTABLE_GRANULAR_FLAGS; use deno_runtime::UNSTABLE_GRANULAR_FLAGS;
use node_resolver::errors::ResolvePkgJsonBinExportError; use node_resolver::errors::ResolvePkgJsonBinExportError;
use node_resolver::UrlOrPath;
use url::Url; use url::Url;
use crate::args::has_trace_permissions_enabled; use crate::args::has_trace_permissions_enabled;
@ -135,6 +138,9 @@ pub fn create_isolate_create_params() -> Option<v8::CreateParams> {
#[derive(Debug, thiserror::Error, deno_error::JsError)] #[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum ResolveNpmBinaryEntrypointError { pub enum ResolveNpmBinaryEntrypointError {
#[class(inherit)]
#[error(transparent)]
PathToUrl(#[from] deno_path_util::PathToUrlError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
ResolvePkgJsonBinExport(ResolvePkgJsonBinExportError), ResolvePkgJsonBinExport(ResolvePkgJsonBinExportError),
@ -153,7 +159,7 @@ pub enum ResolveNpmBinaryEntrypointFallbackError {
PackageSubpathResolve(node_resolver::errors::PackageSubpathResolveError), PackageSubpathResolve(node_resolver::errors::PackageSubpathResolveError),
#[class(generic)] #[class(generic)]
#[error("Cannot find module '{0}'")] #[error("Cannot find module '{0}'")]
ModuleNotFound(Url), ModuleNotFound(UrlOrPath),
} }
pub struct LibMainWorkerOptions { pub struct LibMainWorkerOptions {
@ -525,13 +531,13 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
.node_resolver .node_resolver
.resolve_binary_export(package_folder, sub_path) .resolve_binary_export(package_folder, sub_path)
{ {
Ok(specifier) => Ok(specifier), Ok(path) => Ok(url_from_file_path(&path)?),
Err(original_err) => { Err(original_err) => {
// if the binary entrypoint was not found, fallback to regular node resolution // if the binary entrypoint was not found, fallback to regular node resolution
let result = let result =
self.resolve_binary_entrypoint_fallback(package_folder, sub_path); self.resolve_binary_entrypoint_fallback(package_folder, sub_path);
match result { match result {
Ok(Some(specifier)) => Ok(specifier), Ok(Some(path)) => Ok(url_from_file_path(&path)?),
Ok(None) => { Ok(None) => {
Err(ResolveNpmBinaryEntrypointError::ResolvePkgJsonBinExport( Err(ResolveNpmBinaryEntrypointError::ResolvePkgJsonBinExport(
original_err, original_err,
@ -551,7 +557,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
&self, &self,
package_folder: &Path, package_folder: &Path,
sub_path: Option<&str>, sub_path: Option<&str>,
) -> Result<Option<Url>, ResolveNpmBinaryEntrypointFallbackError> { ) -> Result<Option<PathBuf>, ResolveNpmBinaryEntrypointFallbackError> {
// only fallback if the user specified a sub path // only fallback if the user specified a sub path
if sub_path.is_none() { if sub_path.is_none() {
// it's confusing to users if the package doesn't have any binary // it's confusing to users if the package doesn't have any binary
@ -573,14 +579,22 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
.map_err( .map_err(
ResolveNpmBinaryEntrypointFallbackError::PackageSubpathResolve, ResolveNpmBinaryEntrypointFallbackError::PackageSubpathResolve,
)?; )?;
if deno_path_util::url_to_file_path(&specifier) let path = match specifier {
.map(|p| self.shared.sys.fs_exists_no_err(p)) UrlOrPath::Url(ref url) => match url_to_file_path(url) {
.unwrap_or(false) Ok(path) => path,
{ Err(_) => {
Ok(Some(specifier)) return Err(ResolveNpmBinaryEntrypointFallbackError::ModuleNotFound(
specifier,
));
}
},
UrlOrPath::Path(path) => path,
};
if self.shared.sys.fs_exists_no_err(&path) {
Ok(Some(path))
} else { } else {
Err(ResolveNpmBinaryEntrypointFallbackError::ModuleNotFound( Err(ResolveNpmBinaryEntrypointFallbackError::ModuleNotFound(
specifier, UrlOrPath::Path(path),
)) ))
} }
} }

View file

@ -449,9 +449,7 @@ impl<'a> TsResponseImportMapper<'a> {
.pkg_json_resolver(specifier) .pkg_json_resolver(specifier)
// the specifier might have a closer package.json, but we // the specifier might have a closer package.json, but we
// want the root of the package's package.json // want the root of the package's package.json
.get_closest_package_json_from_file_path( .get_closest_package_json(&package_root_folder.join("package.json"))
&package_root_folder.join("package.json"),
)
.ok() .ok()
.flatten()?; .flatten()?;
let root_folder = package_json.path.parent()?; let root_folder = package_json.path.parent()?;

View file

@ -207,6 +207,8 @@ impl LspScopeResolver {
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
) )
}) })
.ok()?
.into_url()
.ok()?, .ok()?,
)) ))
.0; .0;
@ -257,7 +259,7 @@ impl LspScopeResolver {
root_node_modules_dir: byonm_npm_resolver root_node_modules_dir: byonm_npm_resolver
.root_node_modules_path() .root_node_modules_path()
.map(|p| p.to_path_buf()), .map(|p| p.to_path_buf()),
sys: CliSys::default(), sys: factory.sys.clone(),
pkg_json_resolver: self.pkg_json_resolver.clone(), pkg_json_resolver: self.pkg_json_resolver.clone(),
}, },
) )
@ -522,6 +524,8 @@ impl LspResolver {
resolution_mode, resolution_mode,
NodeResolutionKind::Types, NodeResolutionKind::Types,
) )
.ok()?
.into_url()
.ok()?, .ok()?,
))) )))
} }
@ -702,7 +706,7 @@ impl<'a> ResolverFactory<'a> {
let sys = CliSys::default(); let sys = CliSys::default();
let options = if enable_byonm { let options = if enable_byonm {
CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions { CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions {
sys, sys: self.sys.clone(),
pkg_json_resolver: self.pkg_json_resolver.clone(), pkg_json_resolver: self.pkg_json_resolver.clone(),
root_node_modules_dir: self.config_data.and_then(|config_data| { root_node_modules_dir: self.config_data.and_then(|config_data| {
config_data.node_modules_dir.clone().or_else(|| { config_data.node_modules_dir.clone().or_else(|| {

View file

@ -667,7 +667,12 @@ impl<TGraphContainer: ModuleGraphContainer>
ResolutionMode::Import, ResolutionMode::Import,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
) )
.map_err(|e| JsErrorBox::from_err(e).into()); .map_err(|e| JsErrorBox::from_err(e).into())
.and_then(|url_or_path| {
url_or_path
.into_url()
.map_err(|e| JsErrorBox::from_err(e).into())
});
} }
} }
@ -696,6 +701,8 @@ impl<TGraphContainer: ModuleGraphContainer>
source, source,
}) })
})? })?
.into_url()
.map_err(JsErrorBox::from_err)?
} }
Some(Module::Node(module)) => module.specifier.clone(), Some(Module::Node(module)) => module.specifier.clone(),
Some(Module::Js(module)) => module.specifier.clone(), Some(Module::Js(module)) => module.specifier.clone(),

View file

@ -2,6 +2,7 @@
//! Code for local node_modules resolution. //! Code for local node_modules resolution.
use std::borrow::Cow;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -312,7 +313,7 @@ async fn sync_resolution_with_fs(
); );
let sub_node_modules = folder_path.join("node_modules"); let sub_node_modules = folder_path.join("node_modules");
let package_path = let package_path =
join_package_name(&sub_node_modules, &package.id.nv.name); join_package_name(Cow::Owned(sub_node_modules), &package.id.nv.name);
let cache_folder = cache.package_folder_for_nv(&package.id.nv); let cache_folder = cache.package_folder_for_nv(&package.id.nv);
deno_core::unsync::spawn_blocking({ deno_core::unsync::spawn_blocking({
@ -350,7 +351,7 @@ async fn sync_resolution_with_fs(
let sub_node_modules = folder_path.join("node_modules"); let sub_node_modules = folder_path.join("node_modules");
let package_path = let package_path =
join_package_name(&sub_node_modules, &package.id.nv.name); join_package_name(Cow::Owned(sub_node_modules), &package.id.nv.name);
lifecycle_scripts.add(package, package_path.into()); lifecycle_scripts.add(package, package_path.into());
} }
@ -367,14 +368,16 @@ async fn sync_resolution_with_fs(
if !initialized_file.exists() { if !initialized_file.exists() {
let sub_node_modules = destination_path.join("node_modules"); let sub_node_modules = destination_path.join("node_modules");
let package_path = let package_path =
join_package_name(&sub_node_modules, &package.id.nv.name); join_package_name(Cow::Owned(sub_node_modules), &package.id.nv.name);
let source_path = join_package_name( let source_path = join_package_name(
&deno_local_registry_dir Cow::Owned(
.join(get_package_folder_id_folder_name( deno_local_registry_dir
&package_cache_folder_id.with_no_count(), .join(get_package_folder_id_folder_name(
)) &package_cache_folder_id.with_no_count(),
.join("node_modules"), ))
.join("node_modules"),
),
&package.id.nv.name, &package.id.nv.name,
); );
@ -407,14 +410,16 @@ async fn sync_resolution_with_fs(
get_package_folder_id_folder_name(&dep_cache_folder_id); get_package_folder_id_folder_name(&dep_cache_folder_id);
if dep_setup_cache.insert(name, &dep_folder_name) { if dep_setup_cache.insert(name, &dep_folder_name) {
let dep_folder_path = join_package_name( let dep_folder_path = join_package_name(
&deno_local_registry_dir Cow::Owned(
.join(dep_folder_name) deno_local_registry_dir
.join("node_modules"), .join(dep_folder_name)
.join("node_modules"),
),
&dep_id.nv.name, &dep_id.nv.name,
); );
symlink_package_dir( symlink_package_dir(
&dep_folder_path, &dep_folder_path,
&join_package_name(&sub_node_modules, name), &join_package_name(Cow::Borrowed(&sub_node_modules), name),
)?; )?;
} }
} }
@ -468,9 +473,11 @@ async fn sync_resolution_with_fs(
&remote_pkg.get_package_cache_folder_id(), &remote_pkg.get_package_cache_folder_id(),
); );
let local_registry_package_path = join_package_name( let local_registry_package_path = join_package_name(
&deno_local_registry_dir Cow::Owned(
.join(&target_folder_name) deno_local_registry_dir
.join("node_modules"), .join(&target_folder_name)
.join("node_modules"),
),
&remote_pkg.id.nv.name, &remote_pkg.id.nv.name,
); );
if install_in_child { if install_in_child {
@ -496,7 +503,10 @@ async fn sync_resolution_with_fs(
{ {
symlink_package_dir( symlink_package_dir(
&local_registry_package_path, &local_registry_package_path,
&join_package_name(root_node_modules_dir_path, remote_alias), &join_package_name(
Cow::Borrowed(root_node_modules_dir_path),
remote_alias,
),
)?; )?;
} }
} }
@ -526,15 +536,20 @@ async fn sync_resolution_with_fs(
get_package_folder_id_folder_name(&package.get_package_cache_folder_id()); get_package_folder_id_folder_name(&package.get_package_cache_folder_id());
if setup_cache.insert_root_symlink(&id.nv.name, &target_folder_name) { if setup_cache.insert_root_symlink(&id.nv.name, &target_folder_name) {
let local_registry_package_path = join_package_name( let local_registry_package_path = join_package_name(
&deno_local_registry_dir Cow::Owned(
.join(target_folder_name) deno_local_registry_dir
.join("node_modules"), .join(target_folder_name)
.join("node_modules"),
),
&id.nv.name, &id.nv.name,
); );
symlink_package_dir( symlink_package_dir(
&local_registry_package_path, &local_registry_package_path,
&join_package_name(root_node_modules_dir_path, &id.nv.name), &join_package_name(
Cow::Borrowed(root_node_modules_dir_path),
&id.nv.name,
),
)?; )?;
} }
} }
@ -556,15 +571,20 @@ async fn sync_resolution_with_fs(
if setup_cache.insert_deno_symlink(&package.id.nv.name, &target_folder_name) if setup_cache.insert_deno_symlink(&package.id.nv.name, &target_folder_name)
{ {
let local_registry_package_path = join_package_name( let local_registry_package_path = join_package_name(
&deno_local_registry_dir Cow::Owned(
.join(target_folder_name) deno_local_registry_dir
.join("node_modules"), .join(target_folder_name)
.join("node_modules"),
),
&package.id.nv.name, &package.id.nv.name,
); );
symlink_package_dir( symlink_package_dir(
&local_registry_package_path, &local_registry_package_path,
&join_package_name(&deno_node_modules_dir, &package.id.nv.name), &join_package_name(
Cow::Borrowed(&deno_node_modules_dir),
&package.id.nv.name,
),
)?; )?;
} }
} }
@ -986,13 +1006,17 @@ fn junction_or_symlink_dir(
} }
} }
fn join_package_name(path: &Path, package_name: &str) -> PathBuf { fn join_package_name(mut path: Cow<Path>, package_name: &str) -> PathBuf {
let mut path = path.to_path_buf();
// ensure backslashes are used on windows // ensure backslashes are used on windows
for part in package_name.split('/') { for part in package_name.split('/') {
path = path.join(part); match path {
Cow::Borrowed(inner) => path = Cow::Owned(inner.join(part)),
Cow::Owned(ref mut path) => {
path.push(part);
}
}
} }
path path.into_owned()
} }
#[cfg(test)] #[cfg(test)]

View file

@ -196,8 +196,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
referrer_kind, referrer_kind,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
) )
.map_err(JsErrorBox::from_err)? .and_then(|res| res.into_url())
.into_url(), .map_err(JsErrorBox::from_err)?,
); );
} }
@ -225,7 +225,10 @@ impl ModuleLoader for EmbeddedModuleLoader {
referrer_kind, referrer_kind,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
) )
.map_err(JsErrorBox::from_err)?, .map_err(JsErrorBox::from_err)
.and_then(|url_or_path| {
url_or_path.into_url().map_err(JsErrorBox::from_err)
})?,
), ),
Ok(MappedResolution::PackageJson { Ok(MappedResolution::PackageJson {
dep_result, dep_result,
@ -236,17 +239,22 @@ impl ModuleLoader for EmbeddedModuleLoader {
.as_ref() .as_ref()
.map_err(|e| JsErrorBox::from_err(e.clone()))? .map_err(|e| JsErrorBox::from_err(e.clone()))?
{ {
PackageJsonDepValue::Req(req) => self PackageJsonDepValue::Req(req) => Ok(
.shared self
.npm_req_resolver .shared
.resolve_req_with_sub_path( .npm_req_resolver
req, .resolve_req_with_sub_path(
sub_path.as_deref(), req,
&referrer, sub_path.as_deref(),
referrer_kind, &referrer,
NodeResolutionKind::Execution, referrer_kind,
) NodeResolutionKind::Execution,
.map_err(|e| JsErrorBox::from_err(e).into()), )
.map_err(JsErrorBox::from_err)
.and_then(|url_or_path| {
url_or_path.into_url().map_err(JsErrorBox::from_err)
})?,
),
PackageJsonDepValue::Workspace(version_req) => { PackageJsonDepValue::Workspace(version_req) => {
let pkg_folder = self let pkg_folder = self
.shared .shared
@ -267,7 +275,10 @@ impl ModuleLoader for EmbeddedModuleLoader {
referrer_kind, referrer_kind,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
) )
.map_err(JsErrorBox::from_err)?, .map_err(JsErrorBox::from_err)
.and_then(|url_or_path| {
url_or_path.into_url().map_err(JsErrorBox::from_err)
})?,
) )
} }
}, },
@ -286,7 +297,10 @@ impl ModuleLoader for EmbeddedModuleLoader {
referrer_kind, referrer_kind,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
) )
.map_err(JsErrorBox::from_err)?, .map_err(JsErrorBox::from_err)
.and_then(|url_or_path| {
url_or_path.into_url().map_err(JsErrorBox::from_err)
})?,
); );
} }
@ -323,7 +337,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
) )
.map_err(JsErrorBox::from_err)?; .map_err(JsErrorBox::from_err)?;
if let Some(res) = maybe_res { if let Some(res) = maybe_res {
return Ok(res.into_url()); return Ok(res.into_url().map_err(JsErrorBox::from_err)?);
} }
Err(JsErrorBox::from_err(err).into()) Err(JsErrorBox::from_err(err).into())
} }

View file

@ -667,7 +667,7 @@ fn resolve_npm_nv_ref(
node_resolver::NodeResolutionKind::Types, node_resolver::NodeResolutionKind::Types,
) )
.ok()?; .ok()?;
Some(resolved) resolved.into_url().ok()
} }
/// Matches the `@ts-check` pragma. /// Matches the `@ts-check` pragma.

View file

@ -75,13 +75,17 @@ pub async fn info(
target_pkg_json, target_pkg_json,
sub_path, sub_path,
.. ..
} => Some(node_resolver.resolve_package_subpath_from_deno_module( } => Some(
target_pkg_json.clone().dir_path(), node_resolver
sub_path.as_deref(), .resolve_package_subpath_from_deno_module(
Some(&cwd_url), target_pkg_json.clone().dir_path(),
node_resolver::ResolutionMode::Import, sub_path.as_deref(),
node_resolver::NodeResolutionKind::Execution, Some(&cwd_url),
)?), node_resolver::ResolutionMode::Import,
node_resolver::NodeResolutionKind::Execution,
)?
.into_url()?,
),
deno_config::workspace::MappedResolution::PackageJson { deno_config::workspace::MappedResolution::PackageJson {
alias, alias,
sub_path, sub_path,
@ -94,13 +98,17 @@ pub async fn info(
alias, alias,
version_req, version_req,
)?; )?;
Some(node_resolver.resolve_package_subpath_from_deno_module( Some(
pkg_folder, node_resolver
sub_path.as_deref(), .resolve_package_subpath_from_deno_module(
Some(&cwd_url), pkg_folder,
node_resolver::ResolutionMode::Import, sub_path.as_deref(),
node_resolver::NodeResolutionKind::Execution, Some(&cwd_url),
)?) node_resolver::ResolutionMode::Import,
node_resolver::NodeResolutionKind::Execution,
)?
.into_url()?,
)
} }
deno_package_json::PackageJsonDepValue::Req(req) => { deno_package_json::PackageJsonDepValue::Req(req) => {
Some(ModuleSpecifier::parse(&format!( Some(ModuleSpecifier::parse(&format!(

View file

@ -709,6 +709,9 @@ pub enum ResolveError {
)] )]
ModuleResolution(#[from] deno_core::ModuleResolutionError), ModuleResolution(#[from] deno_core::ModuleResolutionError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)]
FilePathToUrl(#[from] deno_path_util::PathToUrlError),
#[class(inherit)]
#[error("{0}")] #[error("{0}")]
PackageSubpathResolve(PackageSubpathResolveError), PackageSubpathResolve(PackageSubpathResolveError),
#[class(inherit)] #[class(inherit)]
@ -943,7 +946,7 @@ fn resolve_graph_specifier_types(
NodeResolutionKind::Types, NodeResolutionKind::Types,
); );
let maybe_url = match res_result { let maybe_url = match res_result {
Ok(url) => Some(url), Ok(path_or_url) => Some(path_or_url.into_url()?),
Err(err) => match err.code() { Err(err) => match err.code() {
NodeJsErrorCode::ERR_TYPES_NOT_FOUND NodeJsErrorCode::ERR_TYPES_NOT_FOUND
| NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None, | NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None,
@ -971,6 +974,9 @@ fn resolve_graph_specifier_types(
#[derive(Debug, Error, deno_error::JsError)] #[derive(Debug, Error, deno_error::JsError)]
pub enum ResolveNonGraphSpecifierTypesError { pub enum ResolveNonGraphSpecifierTypesError {
#[class(inherit)]
#[error(transparent)]
FilePathToUrl(#[from] deno_path_util::PathToUrlError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError), ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError),
@ -1003,8 +1009,8 @@ fn resolve_non_graph_specifier_types(
resolution_mode, resolution_mode,
NodeResolutionKind::Types, NodeResolutionKind::Types,
) )
.ok() .and_then(|res| res.into_url())
.map(|res| res.into_url()), .ok(),
))) )))
} else if let Ok(npm_req_ref) = } else if let Ok(npm_req_ref) =
NpmPackageReqReference::from_str(raw_specifier) NpmPackageReqReference::from_str(raw_specifier)
@ -1025,7 +1031,7 @@ fn resolve_non_graph_specifier_types(
NodeResolutionKind::Types, NodeResolutionKind::Types,
); );
let maybe_url = match res_result { let maybe_url = match res_result {
Ok(url) => Some(url), Ok(url_or_path) => Some(url_or_path.into_url()?),
Err(err) => match err.code() { Err(err) => match err.code() {
NodeJsErrorCode::ERR_TYPES_NOT_FOUND NodeJsErrorCode::ERR_TYPES_NOT_FOUND
| NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None, | NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None,

View file

@ -23,6 +23,8 @@ use node_resolver::InNpmPackageChecker;
use node_resolver::NodeResolutionKind; use node_resolver::NodeResolutionKind;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use node_resolver::ResolutionMode; use node_resolver::ResolutionMode;
use node_resolver::UrlOrPath;
use node_resolver::UrlOrPathRef;
use node_resolver::REQUIRE_CONDITIONS; use node_resolver::REQUIRE_CONDITIONS;
use sys_traits::FsCanonicalize; use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata; use sys_traits::FsMetadata;
@ -277,11 +279,12 @@ pub fn op_require_resolve_deno_dir<
TSys, TSys,
>>(); >>();
let path = PathBuf::from(parent_filename);
Ok( Ok(
resolver resolver
.resolve_package_folder_from_package( .resolve_package_folder_from_package(
&request, &request,
&url_from_file_path(&PathBuf::from(parent_filename))?, &UrlOrPathRef::from_path(&path),
) )
.ok() .ok()
.map(|p| p.to_string_lossy().into_owned()), .map(|p| p.to_string_lossy().into_owned()),
@ -487,9 +490,7 @@ pub fn op_require_try_self<
let pkg_json_resolver = state.borrow::<PackageJsonResolverRc<TSys>>(); let pkg_json_resolver = state.borrow::<PackageJsonResolverRc<TSys>>();
let pkg = pkg_json_resolver let pkg = pkg_json_resolver
.get_closest_package_json_from_file_path(&PathBuf::from( .get_closest_package_json(&PathBuf::from(parent_path.unwrap()))
parent_path.unwrap(),
))
.ok() .ok()
.flatten(); .flatten();
if pkg.is_none() { if pkg.is_none() {
@ -515,13 +516,13 @@ pub fn op_require_try_self<
return Ok(None); return Ok(None);
} }
let referrer = deno_core::url::Url::from_file_path(&pkg.path).unwrap();
if let Some(exports) = &pkg.exports { if let Some(exports) = &pkg.exports {
let node_resolver = state.borrow::<NodeResolverRc< let node_resolver = state.borrow::<NodeResolverRc<
TInNpmPackageChecker, TInNpmPackageChecker,
TNpmPackageFolderResolver, TNpmPackageFolderResolver,
TSys, TSys,
>>(); >>();
let referrer = UrlOrPathRef::from_path(&pkg.path);
let r = node_resolver.package_exports_resolve( let r = node_resolver.package_exports_resolve(
&pkg.path, &pkg.path,
&expansion, &expansion,
@ -531,11 +532,7 @@ pub fn op_require_try_self<
REQUIRE_CONDITIONS, REQUIRE_CONDITIONS,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
)?; )?;
Ok(Some(if r.scheme() == "file" { Ok(Some(url_or_path_to_string(r)?))
url_to_file_path_string(&r)?
} else {
r.to_string()
}))
} else { } else {
Ok(None) Ok(None)
} }
@ -627,22 +624,21 @@ pub fn op_require_resolve_exports<
let referrer = if parent_path.is_empty() { let referrer = if parent_path.is_empty() {
None None
} else { } else {
Some(Url::from_file_path(parent_path).unwrap()) Some(PathBuf::from(parent_path))
}; };
let r = node_resolver.package_exports_resolve( let r = node_resolver.package_exports_resolve(
&pkg.path, &pkg.path,
&format!(".{expansion}"), &format!(".{expansion}"),
exports, exports,
referrer.as_ref(), referrer
.as_ref()
.map(|r| UrlOrPathRef::from_path(r))
.as_ref(),
ResolutionMode::Require, ResolutionMode::Require,
REQUIRE_CONDITIONS, REQUIRE_CONDITIONS,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
)?; )?;
Ok(Some(if r.scheme() == "file" { Ok(Some(url_or_path_to_string(r)?))
url_to_file_path_string(&r)?
} else {
r.to_string()
}))
} }
deno_error::js_error_wrapper!( deno_error::js_error_wrapper!(
@ -701,8 +697,7 @@ pub fn op_require_package_imports_resolve<
let referrer_path = ensure_read_permission::<P>(state, &referrer_path) let referrer_path = ensure_read_permission::<P>(state, &referrer_path)
.map_err(RequireErrorKind::Permission)?; .map_err(RequireErrorKind::Permission)?;
let pkg_json_resolver = state.borrow::<PackageJsonResolverRc<TSys>>(); let pkg_json_resolver = state.borrow::<PackageJsonResolverRc<TSys>>();
let Some(pkg) = pkg_json_resolver let Some(pkg) = pkg_json_resolver.get_closest_package_json(&referrer_path)?
.get_closest_package_json_from_file_path(&referrer_path)?
else { else {
return Ok(None); return Ok(None);
}; };
@ -713,16 +708,15 @@ pub fn op_require_package_imports_resolve<
TNpmPackageFolderResolver, TNpmPackageFolderResolver,
TSys, TSys,
>>(); >>();
let referrer_url = Url::from_file_path(&referrer_filename).unwrap();
let url = node_resolver.package_imports_resolve( let url = node_resolver.package_imports_resolve(
&request, &request,
Some(&referrer_url), Some(&UrlOrPathRef::from_path(&referrer_path)),
ResolutionMode::Require, ResolutionMode::Require,
Some(&pkg), Some(&pkg),
REQUIRE_CONDITIONS, REQUIRE_CONDITIONS,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
)?; )?;
Ok(Some(url_to_file_path_string(&url)?)) Ok(Some(url_or_path_to_string(url)?))
} else { } else {
Ok(None) Ok(None)
} }
@ -738,11 +732,6 @@ pub fn op_require_break_on_next_statement(state: Rc<RefCell<OpState>>) {
inspector.wait_for_session_and_break_on_next_statement() inspector.wait_for_session_and_break_on_next_statement()
} }
fn url_to_file_path_string(url: &Url) -> Result<String, RequireError> {
let file_path = url_to_file_path(url)?;
Ok(file_path.to_string_lossy().into_owned())
}
#[op2(fast)] #[op2(fast)]
pub fn op_require_can_parse_as_esm( pub fn op_require_can_parse_as_esm(
scope: &mut v8::HandleScope, scope: &mut v8::HandleScope,
@ -768,3 +757,13 @@ pub fn op_require_can_parse_as_esm(
let mut source = v8::script_compiler::Source::new(source, Some(&origin)); let mut source = v8::script_compiler::Source::new(source, Some(&origin));
v8::script_compiler::compile_module(scope, &mut source).is_some() v8::script_compiler::compile_module(scope, &mut source).is_some()
} }
fn url_or_path_to_string(
url: UrlOrPath,
) -> Result<String, deno_path_util::UrlToFilePathError> {
if url.is_file() {
Ok(url.into_path()?.to_string_lossy().to_string())
} else {
Ok(url.to_string_lossy().to_string())
}
}

View file

@ -267,8 +267,11 @@ impl<TInNpmPackageChecker: InNpmPackageChecker, TSys: FsRead>
specifier: &Url, specifier: &Url,
) -> Result<ResolutionMode, ClosestPkgJsonError> { ) -> Result<ResolutionMode, ClosestPkgJsonError> {
if self.in_npm_pkg_checker.in_npm_package(specifier) { if self.in_npm_pkg_checker.in_npm_package(specifier) {
let Ok(path) = deno_path_util::url_to_file_path(specifier) else {
return Ok(ResolutionMode::Require);
};
if let Some(pkg_json) = if let Some(pkg_json) =
self.pkg_json_resolver.get_closest_package_json(specifier)? self.pkg_json_resolver.get_closest_package_json(&path)?
{ {
let is_file_location_cjs = pkg_json.typ != "module"; let is_file_location_cjs = pkg_json.typ != "module";
Ok(if is_file_location_cjs { Ok(if is_file_location_cjs {
@ -280,8 +283,11 @@ impl<TInNpmPackageChecker: InNpmPackageChecker, TSys: FsRead>
Ok(ResolutionMode::Require) Ok(ResolutionMode::Require)
} }
} else if self.mode != IsCjsResolutionMode::Disabled { } else if self.mode != IsCjsResolutionMode::Disabled {
let Ok(path) = deno_path_util::url_to_file_path(specifier) else {
return Ok(ResolutionMode::Import);
};
if let Some(pkg_json) = if let Some(pkg_json) =
self.pkg_json_resolver.get_closest_package_json(specifier)? self.pkg_json_resolver.get_closest_package_json(&path)?
{ {
let is_cjs_type = pkg_json.typ == "commonjs" let is_cjs_type = pkg_json.typ == "commonjs"
|| self.mode == IsCjsResolutionMode::ImplicitTypeCommonJs || self.mode == IsCjsResolutionMode::ImplicitTypeCommonJs

View file

@ -639,7 +639,6 @@ impl<
options: ResolverFactoryOptions, options: ResolverFactoryOptions,
) -> Self { ) -> Self {
Self { Self {
options,
deno_resolver: Default::default(), deno_resolver: Default::default(),
in_npm_package_checker: Default::default(), in_npm_package_checker: Default::default(),
node_resolver: Default::default(), node_resolver: Default::default(),
@ -650,6 +649,7 @@ impl<
sloppy_imports_resolver: Default::default(), sloppy_imports_resolver: Default::default(),
workspace_factory, workspace_factory,
workspace_resolver: Default::default(), workspace_resolver: Default::default(),
options,
} }
} }

View file

@ -92,6 +92,9 @@ pub enum DenoResolveErrorKind {
PackageSubpathResolve(#[from] PackageSubpathResolveError), PackageSubpathResolve(#[from] PackageSubpathResolveError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
PathToUrl(#[from] deno_path_util::PathToUrlError),
#[class(inherit)]
#[error(transparent)]
ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError), ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
@ -252,10 +255,12 @@ impl<
{ {
return node_resolver return node_resolver
.resolve(raw_specifier, referrer, resolution_mode, resolution_kind) .resolve(raw_specifier, referrer, resolution_mode, resolution_kind)
.map(|res| DenoResolution { .and_then(|res| {
url: res.into_url(), Ok(DenoResolution {
found_package_json_dep, url: res.into_url()?,
maybe_diagnostic, found_package_json_dep,
maybe_diagnostic,
})
}) })
.map_err(|e| e.into()); .map_err(|e| e.into());
} }
@ -318,7 +323,8 @@ impl<
resolution_mode, resolution_mode,
resolution_kind, resolution_kind,
) )
.map_err(|e| e.into()), .map_err(DenoResolveError::from)
.and_then(|r| Ok(r.into_url()?)),
MappedResolution::PackageJson { MappedResolution::PackageJson {
dep_result, dep_result,
alias, alias,
@ -372,7 +378,8 @@ impl<
.map_err(|e| { .map_err(|e| {
DenoResolveErrorKind::PackageSubpathResolve(e).into_box() DenoResolveErrorKind::PackageSubpathResolve(e).into_box()
}) })
}), })
.and_then(|r| Ok(r.into_url()?)),
}) })
} }
}, },
@ -425,12 +432,14 @@ impl<
resolution_mode, resolution_mode,
resolution_kind, resolution_kind,
) )
.map(|url| DenoResolution { .map_err(DenoResolveError::from)
url, .and_then(|url_or_path| {
maybe_diagnostic, Ok(DenoResolution {
found_package_json_dep, url: url_or_path.into_url()?,
}) maybe_diagnostic,
.map_err(|e| e.into()); found_package_json_dep,
})
});
} }
// do npm resolution for byonm // do npm resolution for byonm
@ -442,11 +451,6 @@ impl<
resolution_mode, resolution_mode,
resolution_kind, resolution_kind,
) )
.map(|url| DenoResolution {
url,
maybe_diagnostic,
found_package_json_dep,
})
.map_err(|err| { .map_err(|err| {
match err.into_kind() { match err.into_kind() {
ResolveReqWithSubPathErrorKind::MissingPackageNodeModulesFolder( ResolveReqWithSubPathErrorKind::MissingPackageNodeModulesFolder(
@ -459,7 +463,12 @@ impl<
err.into() err.into()
} }
} }
}); })
.and_then(|url_or_path| Ok(DenoResolution {
url: url_or_path.into_url()?,
maybe_diagnostic,
found_package_json_dep,
}));
} }
} }
@ -491,9 +500,9 @@ impl<
})?; })?;
if let Some(res) = maybe_resolution { if let Some(res) = maybe_resolution {
match res { match res {
NodeResolution::Module(url) => { NodeResolution::Module(ref _url) => {
return Ok(DenoResolution { return Ok(DenoResolution {
url, url: res.into_url()?,
maybe_diagnostic, maybe_diagnostic,
found_package_json_dep, found_package_json_dep,
}) })

View file

@ -18,6 +18,7 @@ use node_resolver::errors::PackageNotFoundError;
use node_resolver::InNpmPackageChecker; use node_resolver::InNpmPackageChecker;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use node_resolver::PackageJsonResolverRc; use node_resolver::PackageJsonResolverRc;
use node_resolver::UrlOrPathRef;
use sys_traits::FsCanonicalize; use sys_traits::FsCanonicalize;
use sys_traits::FsDirEntry; use sys_traits::FsDirEntry;
use sys_traits::FsMetadata; use sys_traits::FsMetadata;
@ -141,7 +142,7 @@ impl<TSys: FsCanonicalize + FsRead + FsMetadata + FsReadDir>
) -> std::io::Result<Option<PathBuf>> { ) -> std::io::Result<Option<PathBuf>> {
for ancestor in start_dir.ancestors() { for ancestor in start_dir.ancestors() {
let node_modules_folder = ancestor.join("node_modules"); let node_modules_folder = ancestor.join("node_modules");
let sub_dir = join_package_name(&node_modules_folder, alias); let sub_dir = join_package_name(Cow::Owned(node_modules_folder), alias);
if sys.fs_is_dir_no_err(&sub_dir) { if sys.fs_is_dir_no_err(&sub_dir) {
return Ok(Some( return Ok(Some(
deno_path_util::fs::canonicalize_path_maybe_not_exists( deno_path_util::fs::canonicalize_path_maybe_not_exists(
@ -368,7 +369,7 @@ impl<TSys: FsCanonicalize + FsRead + FsMetadata + FsReadDir>
best_version.map(|(_version, entry_name)| { best_version.map(|(_version, entry_name)| {
join_package_name( join_package_name(
&node_modules_deno_dir.join(entry_name).join("node_modules"), Cow::Owned(node_modules_deno_dir.join(entry_name).join("node_modules")),
&req.name, &req.name,
) )
}) })
@ -381,14 +382,14 @@ impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
fn resolve_package_folder_from_package( fn resolve_package_folder_from_package(
&self, &self,
name: &str, name: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, PackageFolderResolveError> { ) -> Result<PathBuf, PackageFolderResolveError> {
fn inner<TSys: FsMetadata>( fn inner<TSys: FsMetadata>(
sys: &TSys, sys: &TSys,
name: &str, name: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, PackageFolderResolveError> { ) -> Result<PathBuf, PackageFolderResolveError> {
let maybe_referrer_file = url_to_file_path(referrer).ok(); let maybe_referrer_file = referrer.path().ok();
let maybe_start_folder = let maybe_start_folder =
maybe_referrer_file.as_ref().and_then(|f| f.parent()); maybe_referrer_file.as_ref().and_then(|f| f.parent());
if let Some(start_folder) = maybe_start_folder { if let Some(start_folder) = maybe_start_folder {
@ -400,7 +401,7 @@ impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
Cow::Owned(current_folder.join("node_modules")) Cow::Owned(current_folder.join("node_modules"))
}; };
let sub_dir = join_package_name(&node_modules_folder, name); let sub_dir = join_package_name(node_modules_folder, name);
if sys.fs_is_dir_no_err(&sub_dir) { if sys.fs_is_dir_no_err(&sub_dir) {
return Ok(sub_dir); return Ok(sub_dir);
} }
@ -410,7 +411,7 @@ impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
Err( Err(
PackageNotFoundError { PackageNotFoundError {
package_name: name.to_string(), package_name: name.to_string(),
referrer: referrer.clone(), referrer: referrer.display(),
referrer_extra: None, referrer_extra: None,
} }
.into(), .into(),
@ -421,7 +422,7 @@ impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
self.sys.fs_canonicalize(&path).map_err(|err| { self.sys.fs_canonicalize(&path).map_err(|err| {
PackageFolderResolveIoError { PackageFolderResolveIoError {
package_name: name.to_string(), package_name: name.to_string(),
referrer: referrer.clone(), referrer: referrer.display(),
source: err, source: err,
} }
.into() .into()
@ -442,11 +443,15 @@ impl InNpmPackageChecker for ByonmInNpmPackageChecker {
} }
} }
fn join_package_name(path: &Path, package_name: &str) -> PathBuf { fn join_package_name(mut path: Cow<Path>, package_name: &str) -> PathBuf {
let mut path = path.to_path_buf();
// ensure backslashes are used on windows // ensure backslashes are used on windows
for part in package_name.split('/') { for part in package_name.split('/') {
path = path.join(part); match path {
Cow::Borrowed(inner) => path = Cow::Owned(inner.join(part)),
Cow::Owned(ref mut path) => {
path.push(part);
}
}
} }
path path.into_owned()
} }

View file

@ -6,6 +6,7 @@ use std::path::PathBuf;
use deno_npm::NpmPackageCacheFolderId; use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId; use deno_npm::NpmPackageId;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use node_resolver::UrlOrPathRef;
use sys_traits::FsCanonicalize; use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata; use sys_traits::FsMetadata;
use url::Url; use url::Url;
@ -60,7 +61,7 @@ impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
fn resolve_package_folder_from_package( fn resolve_package_folder_from_package(
&self, &self,
specifier: &str, specifier: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, node_resolver::errors::PackageFolderResolveError> { ) -> Result<PathBuf, node_resolver::errors::PackageFolderResolveError> {
match self { match self {
NpmPackageFsResolver::Local(r) => { NpmPackageFsResolver::Local(r) => {

View file

@ -13,6 +13,7 @@ use node_resolver::errors::PackageFolderResolveError;
use node_resolver::errors::PackageNotFoundError; use node_resolver::errors::PackageNotFoundError;
use node_resolver::errors::ReferrerNotFoundError; use node_resolver::errors::ReferrerNotFoundError;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use node_resolver::UrlOrPathRef;
use url::Url; use url::Url;
use super::resolution::NpmResolutionCellRc; use super::resolution::NpmResolutionCellRc;
@ -83,15 +84,15 @@ impl NpmPackageFolderResolver for GlobalNpmPackageResolver {
fn resolve_package_folder_from_package( fn resolve_package_folder_from_package(
&self, &self,
name: &str, name: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, PackageFolderResolveError> { ) -> Result<PathBuf, PackageFolderResolveError> {
use deno_npm::resolution::PackageNotFoundFromReferrerError; use deno_npm::resolution::PackageNotFoundFromReferrerError;
let Some(referrer_cache_folder_id) = let Some(referrer_cache_folder_id) = self
self.resolve_package_cache_folder_id_from_specifier_inner(referrer) .resolve_package_cache_folder_id_from_specifier_inner(referrer.url()?)
else { else {
return Err( return Err(
ReferrerNotFoundError { ReferrerNotFoundError {
referrer: referrer.clone(), referrer: referrer.display(),
referrer_extra: None, referrer_extra: None,
} }
.into(), .into(),
@ -106,7 +107,7 @@ impl NpmPackageFolderResolver for GlobalNpmPackageResolver {
None => Err( None => Err(
PackageNotFoundError { PackageNotFoundError {
package_name: name.to_string(), package_name: name.to_string(),
referrer: referrer.clone(), referrer: referrer.display(),
referrer_extra: Some(format!( referrer_extra: Some(format!(
"{} -> {}", "{} -> {}",
referrer_cache_folder_id, referrer_cache_folder_id,
@ -119,7 +120,7 @@ impl NpmPackageFolderResolver for GlobalNpmPackageResolver {
Err(err) => match *err { Err(err) => match *err {
PackageNotFoundFromReferrerError::Referrer(cache_folder_id) => Err( PackageNotFoundFromReferrerError::Referrer(cache_folder_id) => Err(
ReferrerNotFoundError { ReferrerNotFoundError {
referrer: referrer.clone(), referrer: referrer.display(),
referrer_extra: Some(cache_folder_id.to_string()), referrer_extra: Some(cache_folder_id.to_string()),
} }
.into(), .into(),
@ -130,7 +131,7 @@ impl NpmPackageFolderResolver for GlobalNpmPackageResolver {
} => Err( } => Err(
PackageNotFoundError { PackageNotFoundError {
package_name: name, package_name: name,
referrer: referrer.clone(), referrer: referrer.display(),
referrer_extra: Some(cache_folder_id_referrer.to_string()), referrer_extra: Some(cache_folder_id_referrer.to_string()),
} }
.into(), .into(),

View file

@ -15,6 +15,7 @@ use node_resolver::errors::PackageFolderResolveIoError;
use node_resolver::errors::PackageNotFoundError; use node_resolver::errors::PackageNotFoundError;
use node_resolver::errors::ReferrerNotFoundError; use node_resolver::errors::ReferrerNotFoundError;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use node_resolver::UrlOrPathRef;
use sys_traits::FsCanonicalize; use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata; use sys_traits::FsMetadata;
use url::Url; use url::Url;
@ -149,19 +150,19 @@ impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
fn resolve_package_folder_from_package( fn resolve_package_folder_from_package(
&self, &self,
name: &str, name: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, PackageFolderResolveError> { ) -> Result<PathBuf, PackageFolderResolveError> {
let maybe_local_path = self let maybe_local_path = self
.resolve_folder_for_specifier(referrer) .resolve_folder_for_specifier(referrer.url()?)
.map_err(|err| PackageFolderResolveIoError { .map_err(|err| PackageFolderResolveIoError {
package_name: name.to_string(), package_name: name.to_string(),
referrer: referrer.clone(), referrer: referrer.display(),
source: err, source: err,
})?; })?;
let Some(local_path) = maybe_local_path else { let Some(local_path) = maybe_local_path else {
return Err( return Err(
ReferrerNotFoundError { ReferrerNotFoundError {
referrer: referrer.clone(), referrer: referrer.display(),
referrer_extra: None, referrer_extra: None,
} }
.into(), .into(),
@ -182,7 +183,7 @@ impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
return Ok(self.sys.fs_canonicalize(&sub_dir).map_err(|err| { return Ok(self.sys.fs_canonicalize(&sub_dir).map_err(|err| {
PackageFolderResolveIoError { PackageFolderResolveIoError {
package_name: name.to_string(), package_name: name.to_string(),
referrer: referrer.clone(), referrer: referrer.display(),
source: err, source: err,
} }
})?); })?);
@ -196,7 +197,7 @@ impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
Err( Err(
PackageNotFoundError { PackageNotFoundError {
package_name: name.to_string(), package_name: name.to_string(),
referrer: referrer.clone(), referrer: referrer.display(),
referrer_extra: None, referrer_extra: None,
} }
.into(), .into(),

View file

@ -19,6 +19,7 @@ use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use node_resolver::InNpmPackageChecker; use node_resolver::InNpmPackageChecker;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use node_resolver::UrlOrPathRef;
use sys_traits::FsCanonicalize; use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata; use sys_traits::FsMetadata;
use url::Url; use url::Url;
@ -242,7 +243,7 @@ impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
fn resolve_package_folder_from_package( fn resolve_package_folder_from_package(
&self, &self,
specifier: &str, specifier: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, node_resolver::errors::PackageFolderResolveError> { ) -> Result<PathBuf, node_resolver::errors::PackageFolderResolveError> {
let path = self let path = self
.fs_resolver .fs_resolver
@ -250,7 +251,7 @@ impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
log::debug!( log::debug!(
"Resolved {} from {} to {}", "Resolved {} from {} to {}",
specifier, specifier,
referrer, referrer.display(),
path.display() path.display()
); );
Ok(path) Ok(path)

View file

@ -22,6 +22,8 @@ use node_resolver::NodeResolutionKind;
use node_resolver::NodeResolverRc; use node_resolver::NodeResolverRc;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use node_resolver::ResolutionMode; use node_resolver::ResolutionMode;
use node_resolver::UrlOrPath;
use node_resolver::UrlOrPathRef;
use sys_traits::FsCanonicalize; use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata; use sys_traits::FsMetadata;
use sys_traits::FsRead; use sys_traits::FsRead;
@ -234,7 +236,7 @@ impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
fn resolve_package_folder_from_package( fn resolve_package_folder_from_package(
&self, &self,
specifier: &str, specifier: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, node_resolver::errors::PackageFolderResolveError> { ) -> Result<PathBuf, node_resolver::errors::PackageFolderResolveError> {
match self { match self {
NpmResolver::Byonm(byonm_resolver) => { NpmResolver::Byonm(byonm_resolver) => {
@ -331,7 +333,7 @@ impl<
referrer: &Url, referrer: &Url,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, ResolveReqWithSubPathError> { ) -> Result<UrlOrPath, ResolveReqWithSubPathError> {
self.resolve_req_with_sub_path( self.resolve_req_with_sub_path(
req_ref.req(), req_ref.req(),
req_ref.sub_path(), req_ref.sub_path(),
@ -348,7 +350,7 @@ impl<
referrer: &Url, referrer: &Url,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, ResolveReqWithSubPathError> { ) -> Result<UrlOrPath, ResolveReqWithSubPathError> {
let package_folder = self let package_folder = self
.npm_resolver .npm_resolver
.resolve_pkg_folder_from_deno_module_req(req, referrer)?; .resolve_pkg_folder_from_deno_module_req(req, referrer)?;
@ -398,6 +400,8 @@ impl<
| NodeResolveErrorKind::PackageImportsResolve(_) | NodeResolveErrorKind::PackageImportsResolve(_)
| NodeResolveErrorKind::UnsupportedEsmUrlScheme(_) | NodeResolveErrorKind::UnsupportedEsmUrlScheme(_)
| NodeResolveErrorKind::DataUrlReferrer(_) | NodeResolveErrorKind::DataUrlReferrer(_)
| NodeResolveErrorKind::PathToUrl(_)
| NodeResolveErrorKind::UrlToFilePath(_)
| NodeResolveErrorKind::TypesNotFound(_) | NodeResolveErrorKind::TypesNotFound(_)
| NodeResolveErrorKind::FinalizeResolution(_) => Err( | NodeResolveErrorKind::FinalizeResolution(_) => Err(
ResolveIfForNpmPackageErrorKind::NodeResolve(err.into()).into_box(), ResolveIfForNpmPackageErrorKind::NodeResolve(err.into()).into_box(),
@ -405,6 +409,12 @@ impl<
NodeResolveErrorKind::PackageResolve(err) => { NodeResolveErrorKind::PackageResolve(err) => {
let err = err.into_kind(); let err = err.into_kind();
match err { match err {
PackageResolveErrorKind::UrlToFilePath(err) => Err(
ResolveIfForNpmPackageErrorKind::NodeResolve(
NodeResolveErrorKind::UrlToFilePath(err).into_box(),
)
.into_box(),
),
PackageResolveErrorKind::ClosestPkgJson(_) PackageResolveErrorKind::ClosestPkgJson(_)
| PackageResolveErrorKind::InvalidModuleSpecifier(_) | PackageResolveErrorKind::InvalidModuleSpecifier(_)
| PackageResolveErrorKind::ExportsResolve(_) | PackageResolveErrorKind::ExportsResolve(_)
@ -416,6 +426,12 @@ impl<
), ),
PackageResolveErrorKind::PackageFolderResolve(err) => { PackageResolveErrorKind::PackageFolderResolve(err) => {
match err.as_kind() { match err.as_kind() {
PackageFolderResolveErrorKind::PathToUrl(err) => Err(
ResolveIfForNpmPackageErrorKind::NodeResolve(
NodeResolveErrorKind::PathToUrl(err.clone()).into_box(),
)
.into_box(),
),
PackageFolderResolveErrorKind::Io( PackageFolderResolveErrorKind::Io(
PackageFolderResolveIoError { package_name, .. }, PackageFolderResolveIoError { package_name, .. },
) )

View file

@ -20,6 +20,7 @@ sync = ["deno_package_json/sync"]
anyhow.workspace = true anyhow.workspace = true
async-trait.workspace = true async-trait.workspace = true
boxed_error.workspace = true boxed_error.workspace = true
dashmap.workspace = true
deno_error.workspace = true deno_error.workspace = true
deno_package_json.workspace = true deno_package_json.workspace = true
deno_path_util.workspace = true deno_path_util.workspace = true

View file

@ -7,7 +7,6 @@ use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use deno_error::JsErrorBox; use deno_error::JsErrorBox;
use deno_path_util::url_from_file_path;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use futures::future::LocalBoxFuture; use futures::future::LocalBoxFuture;
use futures::stream::FuturesUnordered; use futures::stream::FuturesUnordered;
@ -29,6 +28,8 @@ use crate::NpmPackageFolderResolver;
use crate::PackageJsonResolverRc; use crate::PackageJsonResolverRc;
use crate::PathClean; use crate::PathClean;
use crate::ResolutionMode; use crate::ResolutionMode;
use crate::UrlOrPath;
use crate::UrlOrPathRef;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum CjsAnalysis<'a> { pub enum CjsAnalysis<'a> {
@ -253,14 +254,21 @@ impl<
errors: &mut Vec<JsErrorBox>| { errors: &mut Vec<JsErrorBox>| {
// 1. Resolve the re-exports and start a future to analyze each one // 1. Resolve the re-exports and start a future to analyze each one
for reexport in reexports { for reexport in reexports {
let result = self.resolve( let result = self
&reexport, .resolve(
&referrer, &reexport,
// FIXME(bartlomieju): check if these conditions are okay, probably &referrer,
// should be `deno-require`, because `deno` is already used in `esm_resolver.rs` // FIXME(bartlomieju): check if these conditions are okay, probably
&["deno", "node", "require", "default"], // should be `deno-require`, because `deno` is already used in `esm_resolver.rs`
NodeResolutionKind::Execution, &["deno", "node", "require", "default"],
); NodeResolutionKind::Execution,
)
.and_then(|value| {
value
.map(|url_or_path| url_or_path.into_url())
.transpose()
.map_err(JsErrorBox::from_err)
});
let reexport_specifier = match result { let reexport_specifier = match result {
Ok(Some(specifier)) => specifier, Ok(Some(specifier)) => specifier,
Ok(None) => continue, Ok(None) => continue,
@ -355,18 +363,18 @@ impl<
referrer: &Url, referrer: &Url,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Option<Url>, JsErrorBox> { ) -> Result<Option<UrlOrPath>, JsErrorBox> {
if specifier.starts_with('/') { if specifier.starts_with('/') {
todo!(); todo!();
} }
let referrer_path = url_to_file_path(referrer).unwrap(); let referrer = UrlOrPathRef::from_url(referrer);
let referrer_path = referrer.path().unwrap();
if specifier.starts_with("./") || specifier.starts_with("../") { if specifier.starts_with("./") || specifier.starts_with("../") {
if let Some(parent) = referrer_path.parent() { if let Some(parent) = referrer_path.parent() {
return self return self
.file_extension_probe(parent.join(specifier), &referrer_path) .file_extension_probe(parent.join(specifier), referrer_path)
.and_then(|p| url_from_file_path(&p).map_err(JsErrorBox::from_err)) .map(|p| Some(UrlOrPath::Path(p)));
.map(Some);
} else { } else {
todo!(); todo!();
} }
@ -376,20 +384,21 @@ impl<
let (package_specifier, package_subpath) = let (package_specifier, package_subpath) =
parse_specifier(specifier).unwrap(); parse_specifier(specifier).unwrap();
let module_dir = match self let module_dir =
.npm_resolver match self.npm_resolver.resolve_package_folder_from_package(
.resolve_package_folder_from_package(package_specifier.as_str(), referrer) package_specifier.as_str(),
{ &referrer,
Err(err) ) {
if matches!( Err(err)
err.as_kind(), if matches!(
crate::errors::PackageFolderResolveErrorKind::PackageNotFound(..) err.as_kind(),
) => crate::errors::PackageFolderResolveErrorKind::PackageNotFound(..)
{ ) =>
return Ok(None); {
} return Ok(None);
other => other.map_err(JsErrorBox::from_err)?, }
}; other => other.map_err(JsErrorBox::from_err)?,
};
let package_json_path = module_dir.join("package.json"); let package_json_path = module_dir.join("package.json");
let maybe_package_json = self let maybe_package_json = self
@ -405,7 +414,7 @@ impl<
&package_json_path, &package_json_path,
&package_subpath, &package_subpath,
exports, exports,
Some(referrer), Some(&referrer),
ResolutionMode::Import, ResolutionMode::Import,
conditions, conditions,
resolution_kind, resolution_kind,
@ -429,39 +438,26 @@ impl<
if let Some(main) = if let Some(main) =
package_json.main(deno_package_json::NodeModuleKind::Cjs) package_json.main(deno_package_json::NodeModuleKind::Cjs)
{ {
return Ok(Some( return Ok(Some(UrlOrPath::Path(d.join(main).clean())));
url_from_file_path(&d.join(main).clean())
.map_err(JsErrorBox::from_err)?,
));
} }
} }
return Ok(Some( return Ok(Some(UrlOrPath::Path(d.join("index.js").clean())));
url_from_file_path(&d.join("index.js").clean())
.map_err(JsErrorBox::from_err)?,
));
} }
return self return self
.file_extension_probe(d, &referrer_path) .file_extension_probe(d, referrer_path)
.and_then(|p| url_from_file_path(&p).map_err(JsErrorBox::from_err)) .map(|p| Some(UrlOrPath::Path(p)));
.map(Some);
} else if let Some(main) = } else if let Some(main) =
package_json.main(deno_package_json::NodeModuleKind::Cjs) package_json.main(deno_package_json::NodeModuleKind::Cjs)
{ {
return Ok(Some( return Ok(Some(UrlOrPath::Path(module_dir.join(main).clean())));
url_from_file_path(&module_dir.join(main).clean())
.map_err(JsErrorBox::from_err)?,
));
} else { } else {
return Ok(Some( return Ok(Some(UrlOrPath::Path(module_dir.join("index.js").clean())));
url_from_file_path(&module_dir.join("index.js").clean())
.map_err(JsErrorBox::from_err)?,
));
} }
} }
// as a fallback, attempt to resolve it via the ancestor directories // as a fallback, attempt to resolve it via the ancestor directories
let mut last = referrer_path.as_path(); let mut last = referrer_path;
while let Some(parent) = last.parent() { while let Some(parent) = last.parent() {
if !self.in_npm_pkg_checker.in_npm_package_at_dir_path(parent) { if !self.in_npm_pkg_checker.in_npm_package_at_dir_path(parent) {
break; break;
@ -471,15 +467,13 @@ impl<
} else { } else {
parent.join("node_modules").join(specifier) parent.join("node_modules").join(specifier)
}; };
if let Ok(path) = self.file_extension_probe(path, &referrer_path) { if let Ok(path) = self.file_extension_probe(path, referrer_path) {
return Ok(Some( return Ok(Some(UrlOrPath::Path(path)));
url_from_file_path(&path).map_err(JsErrorBox::from_err)?,
));
} }
last = parent; last = parent;
} }
Err(not_found(specifier, &referrer_path)) Err(not_found(specifier, referrer_path))
} }
fn file_extension_probe( fn file_extension_probe(

View file

@ -6,9 +6,11 @@ use std::path::PathBuf;
use boxed_error::Boxed; use boxed_error::Boxed;
use deno_error::JsError; use deno_error::JsError;
use deno_path_util::UrlToFilePathError;
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
use crate::path::UrlOrPath;
use crate::NodeResolutionKind; use crate::NodeResolutionKind;
use crate::ResolutionMode; use crate::ResolutionMode;
@ -24,6 +26,7 @@ pub enum NodeJsErrorCode {
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,
ERR_INVALID_FILE_URL_PATH,
/// Deno specific since Node doesn't support TypeScript. /// Deno specific since Node doesn't support TypeScript.
ERR_TYPES_NOT_FOUND, ERR_TYPES_NOT_FOUND,
} }
@ -48,6 +51,7 @@ impl NodeJsErrorCode {
ERR_UNSUPPORTED_DIR_IMPORT => "ERR_UNSUPPORTED_DIR_IMPORT", ERR_UNSUPPORTED_DIR_IMPORT => "ERR_UNSUPPORTED_DIR_IMPORT",
ERR_UNSUPPORTED_ESM_URL_SCHEME => "ERR_UNSUPPORTED_ESM_URL_SCHEME", ERR_UNSUPPORTED_ESM_URL_SCHEME => "ERR_UNSUPPORTED_ESM_URL_SCHEME",
ERR_TYPES_NOT_FOUND => "ERR_TYPES_NOT_FOUND", ERR_TYPES_NOT_FOUND => "ERR_TYPES_NOT_FOUND",
ERR_INVALID_FILE_URL_PATH => "ERR_INVALID_FILE_URL_PATH",
} }
} }
} }
@ -109,7 +113,7 @@ impl NodeJsErrorCoded for LegacyResolveError {
#[class(generic)] #[class(generic)]
pub struct PackageNotFoundError { pub struct PackageNotFoundError {
pub package_name: String, pub package_name: String,
pub referrer: Url, pub referrer: UrlOrPath,
/// Extra information about the referrer. /// Extra information about the referrer.
pub referrer_extra: Option<String>, pub referrer_extra: Option<String>,
} }
@ -128,7 +132,7 @@ impl NodeJsErrorCoded for PackageNotFoundError {
)] )]
#[class(generic)] #[class(generic)]
pub struct ReferrerNotFoundError { pub struct ReferrerNotFoundError {
pub referrer: Url, pub referrer: UrlOrPath,
/// Extra information about the referrer. /// Extra information about the referrer.
pub referrer_extra: Option<String>, pub referrer_extra: Option<String>,
} }
@ -144,7 +148,7 @@ impl NodeJsErrorCoded for ReferrerNotFoundError {
#[error("Failed resolving '{package_name}' from referrer '{referrer}'.")] #[error("Failed resolving '{package_name}' from referrer '{referrer}'.")]
pub struct PackageFolderResolveIoError { pub struct PackageFolderResolveIoError {
pub package_name: String, pub package_name: String,
pub referrer: Url, pub referrer: UrlOrPath,
#[source] #[source]
#[inherit] #[inherit]
pub source: std::io::Error, pub source: std::io::Error,
@ -162,6 +166,9 @@ impl NodeJsErrorCoded for PackageFolderResolveError {
PackageFolderResolveErrorKind::PackageNotFound(e) => e.code(), PackageFolderResolveErrorKind::PackageNotFound(e) => e.code(),
PackageFolderResolveErrorKind::ReferrerNotFound(e) => e.code(), PackageFolderResolveErrorKind::ReferrerNotFound(e) => e.code(),
PackageFolderResolveErrorKind::Io(e) => e.code(), PackageFolderResolveErrorKind::Io(e) => e.code(),
PackageFolderResolveErrorKind::PathToUrl(_) => {
NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
}
} }
} }
} }
@ -180,6 +187,9 @@ pub enum PackageFolderResolveErrorKind {
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
Io(#[from] PackageFolderResolveIoError), Io(#[from] PackageFolderResolveIoError),
#[class(inherit)]
#[error(transparent)]
PathToUrl(#[from] deno_path_util::PathToUrlError),
} }
impl NodeJsErrorCoded for PackageSubpathResolveError { impl NodeJsErrorCoded for PackageSubpathResolveError {
@ -232,7 +242,7 @@ pub enum PackageSubpathResolveErrorKind {
pub struct PackageTargetNotFoundError { pub struct PackageTargetNotFoundError {
pub pkg_json_path: PathBuf, pub pkg_json_path: PathBuf,
pub target: String, pub target: String,
pub maybe_referrer: Option<Url>, pub maybe_referrer: Option<UrlOrPath>,
pub resolution_mode: ResolutionMode, pub resolution_mode: ResolutionMode,
pub resolution_kind: NodeResolutionKind, pub resolution_kind: NodeResolutionKind,
} }
@ -251,6 +261,9 @@ impl NodeJsErrorCoded for PackageTargetResolveError {
PackageTargetResolveErrorKind::InvalidModuleSpecifier(e) => e.code(), PackageTargetResolveErrorKind::InvalidModuleSpecifier(e) => e.code(),
PackageTargetResolveErrorKind::PackageResolve(e) => e.code(), PackageTargetResolveErrorKind::PackageResolve(e) => e.code(),
PackageTargetResolveErrorKind::TypesNotFound(e) => e.code(), PackageTargetResolveErrorKind::TypesNotFound(e) => e.code(),
PackageTargetResolveErrorKind::UrlToFilePath(_) => {
NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
}
} }
} }
} }
@ -275,6 +288,9 @@ pub enum PackageTargetResolveErrorKind {
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
TypesNotFound(#[from] TypesNotFoundError), TypesNotFound(#[from] TypesNotFoundError),
#[class(inherit)]
#[error(transparent)]
UrlToFilePath(#[from] deno_path_util::UrlToFilePathError),
} }
impl NodeJsErrorCoded for PackageExportsResolveError { impl NodeJsErrorCoded for PackageExportsResolveError {
@ -311,8 +327,8 @@ pub struct TypesNotFoundError(pub Box<TypesNotFoundErrorData>);
#[derive(Debug)] #[derive(Debug)]
pub struct TypesNotFoundErrorData { pub struct TypesNotFoundErrorData {
pub code_specifier: Url, pub code_specifier: UrlOrPath,
pub maybe_referrer: Option<Url>, pub maybe_referrer: Option<UrlOrPath>,
} }
impl NodeJsErrorCoded for TypesNotFoundError { impl NodeJsErrorCoded for TypesNotFoundError {
@ -369,7 +385,7 @@ pub enum ClosestPkgJsonErrorKind {
pub struct PackageImportNotDefinedError { pub struct PackageImportNotDefinedError {
pub name: String, pub name: String,
pub package_json_path: Option<PathBuf>, pub package_json_path: Option<PathBuf>,
pub maybe_referrer: Option<Url>, pub maybe_referrer: Option<UrlOrPath>,
} }
impl NodeJsErrorCoded for PackageImportNotDefinedError { impl NodeJsErrorCoded for PackageImportNotDefinedError {
@ -416,6 +432,9 @@ impl NodeJsErrorCoded for PackageResolveError {
PackageResolveErrorKind::PackageFolderResolve(e) => e.code(), PackageResolveErrorKind::PackageFolderResolve(e) => e.code(),
PackageResolveErrorKind::ExportsResolve(e) => e.code(), PackageResolveErrorKind::ExportsResolve(e) => e.code(),
PackageResolveErrorKind::SubpathResolve(e) => e.code(), PackageResolveErrorKind::SubpathResolve(e) => e.code(),
PackageResolveErrorKind::UrlToFilePath(_) => {
NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
}
} }
} }
} }
@ -440,6 +459,9 @@ pub enum PackageResolveErrorKind {
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
SubpathResolve(#[from] PackageSubpathResolveError), SubpathResolve(#[from] PackageSubpathResolveError),
#[class(inherit)]
#[error(transparent)]
UrlToFilePath(#[from] UrlToFilePathError),
} }
#[derive(Debug, Error, JsError)] #[derive(Debug, Error, JsError)]
@ -470,6 +492,12 @@ pub enum NodeResolveErrorKind {
RelativeJoin(#[from] NodeResolveRelativeJoinError), RelativeJoin(#[from] NodeResolveRelativeJoinError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
PathToUrl(#[from] deno_path_util::PathToUrlError),
#[class(inherit)]
#[error(transparent)]
UrlToFilePath(#[from] deno_path_util::UrlToFilePathError),
#[class(inherit)]
#[error(transparent)]
PackageImportsResolve(#[from] PackageImportsResolveError), PackageImportsResolve(#[from] PackageImportsResolveError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
@ -502,6 +530,9 @@ pub enum FinalizeResolutionErrorKind {
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
UnsupportedDirImport(#[from] UnsupportedDirImportError), UnsupportedDirImport(#[from] UnsupportedDirImportError),
#[class(inherit)]
#[error(transparent)]
UrlToFilePath(#[from] deno_path_util::UrlToFilePathError),
} }
impl NodeJsErrorCoded for FinalizeResolutionError { impl NodeJsErrorCoded for FinalizeResolutionError {
@ -510,6 +541,9 @@ impl NodeJsErrorCoded for FinalizeResolutionError {
FinalizeResolutionErrorKind::InvalidModuleSpecifierError(e) => e.code(), FinalizeResolutionErrorKind::InvalidModuleSpecifierError(e) => e.code(),
FinalizeResolutionErrorKind::ModuleNotFound(e) => e.code(), FinalizeResolutionErrorKind::ModuleNotFound(e) => e.code(),
FinalizeResolutionErrorKind::UnsupportedDirImport(e) => e.code(), FinalizeResolutionErrorKind::UnsupportedDirImport(e) => e.code(),
FinalizeResolutionErrorKind::UrlToFilePath(_) => {
NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
}
} }
} }
} }
@ -524,8 +558,8 @@ impl NodeJsErrorCoded for FinalizeResolutionError {
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()
)] )]
pub struct ModuleNotFoundError { pub struct ModuleNotFoundError {
pub specifier: Url, pub specifier: UrlOrPath,
pub maybe_referrer: Option<Url>, pub maybe_referrer: Option<UrlOrPath>,
pub typ: &'static str, pub typ: &'static str,
} }
@ -544,8 +578,8 @@ impl NodeJsErrorCoded for ModuleNotFoundError {
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(),
)] )]
pub struct UnsupportedDirImportError { pub struct UnsupportedDirImportError {
pub dir_url: Url, pub dir_url: UrlOrPath,
pub maybe_referrer: Option<Url>, pub maybe_referrer: Option<UrlOrPath>,
} }
impl NodeJsErrorCoded for UnsupportedDirImportError { impl NodeJsErrorCoded for UnsupportedDirImportError {
@ -561,7 +595,7 @@ pub struct InvalidPackageTargetError {
pub sub_path: String, pub sub_path: String,
pub target: String, pub target: String,
pub is_import: bool, pub is_import: bool,
pub maybe_referrer: Option<Url>, pub maybe_referrer: Option<UrlOrPath>,
} }
impl std::error::Error for InvalidPackageTargetError {} impl std::error::Error for InvalidPackageTargetError {}
@ -616,7 +650,7 @@ impl NodeJsErrorCoded for InvalidPackageTargetError {
pub struct PackagePathNotExportedError { pub struct PackagePathNotExportedError {
pub pkg_json_path: PathBuf, pub pkg_json_path: PathBuf,
pub subpath: String, pub subpath: String,
pub maybe_referrer: Option<Url>, pub maybe_referrer: Option<UrlOrPath>,
pub resolution_kind: NodeResolutionKind, pub resolution_kind: NodeResolutionKind,
} }

View file

@ -24,6 +24,8 @@ pub use package_json::PackageJsonResolver;
pub use package_json::PackageJsonResolverRc; pub use package_json::PackageJsonResolverRc;
pub use package_json::PackageJsonThreadLocalCache; pub use package_json::PackageJsonThreadLocalCache;
pub use path::PathClean; pub use path::PathClean;
pub use path::UrlOrPath;
pub use path::UrlOrPathRef;
pub use resolution::parse_npm_pkg_name; pub use resolution::parse_npm_pkg_name;
pub use resolution::resolve_specifier_into_node_modules; pub use resolution::resolve_specifier_into_node_modules;
pub use resolution::ConditionsFromResolutionMode; pub use resolution::ConditionsFromResolutionMode;

View file

@ -9,13 +9,14 @@ use url::Url;
use crate::errors; use crate::errors;
use crate::path::PathClean; use crate::path::PathClean;
use crate::path::UrlOrPathRef;
pub trait NpmPackageFolderResolver { pub trait NpmPackageFolderResolver {
/// Resolves an npm package folder path from the specified referrer. /// Resolves an npm package folder path from the specified referrer.
fn resolve_package_folder_from_package( fn resolve_package_folder_from_package(
&self, &self,
specifier: &str, specifier: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, errors::PackageFolderResolveError>; ) -> Result<PathBuf, errors::PackageFolderResolveError>;
} }

View file

@ -9,7 +9,6 @@ use std::path::PathBuf;
use deno_package_json::PackageJson; use deno_package_json::PackageJson;
use deno_package_json::PackageJsonRc; use deno_package_json::PackageJsonRc;
use sys_traits::FsRead; use sys_traits::FsRead;
use url::Url;
use crate::errors::ClosestPkgJsonError; use crate::errors::ClosestPkgJsonError;
use crate::errors::PackageJsonLoadError; use crate::errors::PackageJsonLoadError;
@ -51,17 +50,17 @@ pub struct PackageJsonThreadLocalCache;
impl PackageJsonThreadLocalCache { impl PackageJsonThreadLocalCache {
pub fn clear() { pub fn clear() {
CACHE.with(|cache| cache.borrow_mut().clear()); CACHE.with_borrow_mut(|cache| cache.clear());
} }
} }
impl deno_package_json::PackageJsonCache for PackageJsonThreadLocalCache { impl deno_package_json::PackageJsonCache for PackageJsonThreadLocalCache {
fn get(&self, path: &Path) -> Option<PackageJsonRc> { fn get(&self, path: &Path) -> Option<PackageJsonRc> {
CACHE.with(|cache| cache.borrow().get(path).cloned()) CACHE.with_borrow(|cache| cache.get(path).cloned())
} }
fn set(&self, path: PathBuf, package_json: PackageJsonRc) { fn set(&self, path: PathBuf, package_json: PackageJsonRc) {
CACHE.with(|cache| cache.borrow_mut().insert(path, package_json)); CACHE.with_borrow_mut(|cache| cache.insert(path, package_json));
} }
} }
@ -81,20 +80,12 @@ impl<TSys: FsRead> PackageJsonResolver<TSys> {
} }
pub fn get_closest_package_json( pub fn get_closest_package_json(
&self,
url: &Url,
) -> Result<Option<PackageJsonRc>, ClosestPkgJsonError> {
let Ok(file_path) = deno_path_util::url_to_file_path(url) else {
return Ok(None);
};
self.get_closest_package_json_from_file_path(&file_path)
}
pub fn get_closest_package_json_from_file_path(
&self, &self,
file_path: &Path, file_path: &Path,
) -> Result<Option<PackageJsonRc>, ClosestPkgJsonError> { ) -> Result<Option<PackageJsonRc>, ClosestPkgJsonError> {
let parent_dir = file_path.parent().unwrap(); let Some(parent_dir) = file_path.parent() else {
return Ok(None);
};
for current_dir in parent_dir.ancestors() { for current_dir in parent_dir.ancestors() {
let package_json_path = current_dir.join("package.json"); let package_json_path = current_dir.join("package.json");
if let Some(pkg_json) = self.load_package_json(&package_json_path)? { if let Some(pkg_json) = self.load_package_json(&package_json_path)? {

View file

@ -1,9 +1,125 @@
// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2018-2025 the Deno authors. MIT license.
use std::borrow::Cow;
use std::path::Component; use std::path::Component;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use url::Url;
#[derive(Debug, Clone)]
pub enum UrlOrPath {
Url(Url),
Path(PathBuf),
}
impl UrlOrPath {
pub fn is_file(&self) -> bool {
match self {
UrlOrPath::Url(url) => url.scheme() == "file",
UrlOrPath::Path(_) => true,
}
}
pub fn is_node_url(&self) -> bool {
match self {
UrlOrPath::Url(url) => url.scheme() == "node",
UrlOrPath::Path(_) => false,
}
}
pub fn into_path(
self,
) -> Result<PathBuf, deno_path_util::UrlToFilePathError> {
match self {
UrlOrPath::Url(url) => deno_path_util::url_to_file_path(&url),
UrlOrPath::Path(path) => Ok(path),
}
}
pub fn into_url(self) -> Result<Url, deno_path_util::PathToUrlError> {
match self {
UrlOrPath::Url(url) => Ok(url),
UrlOrPath::Path(path) => deno_path_util::url_from_file_path(&path),
}
}
pub fn to_string_lossy(&self) -> Cow<str> {
match self {
UrlOrPath::Url(url) => Cow::Borrowed(url.as_str()),
UrlOrPath::Path(path) => path.to_string_lossy(),
}
}
}
impl std::fmt::Display for UrlOrPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UrlOrPath::Url(url) => url.fmt(f),
UrlOrPath::Path(path) => {
// prefer displaying a url
match deno_path_util::url_from_file_path(path) {
Ok(url) => url.fmt(f),
Err(_) => {
write!(f, "{}", path.display())
}
}
}
}
}
}
pub struct UrlOrPathRef<'a> {
url: once_cell::unsync::OnceCell<Cow<'a, Url>>,
path: once_cell::unsync::OnceCell<Cow<'a, Path>>,
}
impl<'a> UrlOrPathRef<'a> {
pub fn from_path(path: &'a Path) -> Self {
Self {
url: Default::default(),
path: once_cell::unsync::OnceCell::with_value(Cow::Borrowed(path)),
}
}
pub fn from_url(url: &'a Url) -> Self {
Self {
path: Default::default(),
url: once_cell::unsync::OnceCell::with_value(Cow::Borrowed(url)),
}
}
pub fn url(&self) -> Result<&Url, deno_path_util::PathToUrlError> {
self
.url
.get_or_try_init(|| {
deno_path_util::url_from_file_path(self.path.get().unwrap())
.map(Cow::Owned)
})
.map(|v| v.as_ref())
}
pub fn path(&self) -> Result<&Path, deno_path_util::UrlToFilePathError> {
self
.path
.get_or_try_init(|| {
deno_path_util::url_to_file_path(self.url.get().unwrap())
.map(Cow::Owned)
})
.map(|v| v.as_ref())
}
pub fn display(&self) -> UrlOrPath {
// prefer url
if let Ok(url) = self.url() {
UrlOrPath::Url(url.clone())
} else {
// this will always be set if url is None
UrlOrPath::Path(self.path.get().unwrap().to_path_buf())
}
}
}
/// Extension to path_clean::PathClean /// Extension to path_clean::PathClean
pub trait PathClean<T> { pub trait PathClean<T> {
fn clean(&self) -> T; fn clean(&self) -> T;

View file

@ -8,7 +8,6 @@ use std::path::PathBuf;
use anyhow::bail; use anyhow::bail;
use anyhow::Error as AnyError; use anyhow::Error as AnyError;
use deno_package_json::PackageJson; use deno_package_json::PackageJson;
use deno_path_util::url_from_file_path;
use serde_json::Map; use serde_json::Map;
use serde_json::Value; use serde_json::Value;
use sys_traits::FileType; use sys_traits::FileType;
@ -46,6 +45,8 @@ use crate::errors::TypesNotFoundError;
use crate::errors::TypesNotFoundErrorData; use crate::errors::TypesNotFoundErrorData;
use crate::errors::UnsupportedDirImportError; use crate::errors::UnsupportedDirImportError;
use crate::errors::UnsupportedEsmUrlSchemeError; use crate::errors::UnsupportedEsmUrlSchemeError;
use crate::path::UrlOrPath;
use crate::path::UrlOrPathRef;
use crate::InNpmPackageChecker; use crate::InNpmPackageChecker;
use crate::IsBuiltInNodeModuleChecker; use crate::IsBuiltInNodeModuleChecker;
use crate::NpmPackageFolderResolver; use crate::NpmPackageFolderResolver;
@ -115,21 +116,19 @@ impl NodeResolutionKind {
#[derive(Debug)] #[derive(Debug)]
pub enum NodeResolution { pub enum NodeResolution {
Module(Url), Module(UrlOrPath),
BuiltIn(String), BuiltIn(String),
} }
impl NodeResolution { impl NodeResolution {
pub fn into_url(self) -> Url { pub fn into_url(self) -> Result<Url, NodeResolveError> {
match self { match self {
Self::Module(u) => u, Self::Module(u) => Ok(u.into_url()?),
Self::BuiltIn(specifier) => { Self::BuiltIn(specifier) => Ok(if specifier.starts_with("node:") {
if specifier.starts_with("node:") { Url::parse(&specifier).unwrap()
Url::parse(&specifier).unwrap() } else {
} else { Url::parse(&format!("node:{specifier}")).unwrap()
Url::parse(&format!("node:{specifier}")).unwrap() }),
}
}
} }
} }
} }
@ -220,7 +219,7 @@ impl<
if let Ok(url) = Url::parse(specifier) { if let Ok(url) = Url::parse(specifier) {
if url.scheme() == "data" { if url.scheme() == "data" {
return Ok(NodeResolution::Module(url)); return Ok(NodeResolution::Module(UrlOrPath::Url(url)));
} }
if let Some(module_name) = if let Some(module_name) =
@ -245,26 +244,27 @@ impl<
let url = referrer let url = referrer
.join(specifier) .join(specifier)
.map_err(|source| DataUrlReferrerError { source })?; .map_err(|source| DataUrlReferrerError { source })?;
return Ok(NodeResolution::Module(url)); return Ok(NodeResolution::Module(UrlOrPath::Url(url)));
} }
} }
let conditions = self let conditions = self
.conditions_from_resolution_mode .conditions_from_resolution_mode
.resolve(resolution_mode); .resolve(resolution_mode);
let referrer = UrlOrPathRef::from_url(referrer);
let url = self.module_resolve( let url = self.module_resolve(
specifier, specifier,
referrer, &referrer,
resolution_mode, resolution_mode,
conditions, conditions,
resolution_kind, resolution_kind,
)?; )?;
let url = if resolution_kind.is_types() { let url = if resolution_kind.is_types() && url.is_file() {
let file_path = to_file_path(&url); let file_path = url.into_path()?;
self.path_to_declaration_url( self.path_to_declaration_path(
&file_path, file_path,
Some(referrer), Some(&referrer),
resolution_mode, resolution_mode,
conditions, conditions,
)? )?
@ -272,8 +272,8 @@ impl<
url url
}; };
let url = self.finalize_resolution(url, Some(referrer))?; let url_or_path = self.finalize_resolution(url, Some(&referrer))?;
let resolve_response = NodeResolution::Module(url); let resolve_response = NodeResolution::Module(url_or_path);
// TODO(bartlomieju): skipped checking errors for commonJS resolution and // TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options. // "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(resolve_response) Ok(resolve_response)
@ -282,23 +282,26 @@ impl<
fn module_resolve( fn module_resolve(
&self, &self,
specifier: &str, specifier: &str,
referrer: &Url, referrer: &UrlOrPathRef,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, NodeResolveError> { ) -> Result<UrlOrPath, NodeResolveError> {
if should_be_treated_as_relative_or_absolute_path(specifier) { if should_be_treated_as_relative_or_absolute_path(specifier) {
Ok(node_join_url(referrer, specifier).map_err(|err| { let referrer_url = referrer.url()?;
NodeResolveRelativeJoinError { Ok(UrlOrPath::Url(
path: specifier.to_string(), node_join_url(referrer_url, specifier).map_err(|err| {
base: referrer.clone(), NodeResolveRelativeJoinError {
source: err, path: specifier.to_string(),
} base: referrer_url.clone(),
})?) source: err,
}
})?,
))
} else if specifier.starts_with('#') { } else if specifier.starts_with('#') {
let pkg_config = self let pkg_config = self
.pkg_json_resolver .pkg_json_resolver
.get_closest_package_json(referrer) .get_closest_package_json(referrer.path()?)
.map_err(PackageImportsResolveErrorKind::ClosestPkgJson) .map_err(PackageImportsResolveErrorKind::ClosestPkgJson)
.map_err(|err| PackageImportsResolveError(Box::new(err)))?; .map_err(|err| PackageImportsResolveError(Box::new(err)))?;
Ok(self.package_imports_resolve( Ok(self.package_imports_resolve(
@ -310,7 +313,7 @@ impl<
resolution_kind, resolution_kind,
)?) )?)
} else if let Ok(resolved) = Url::parse(specifier) { } else if let Ok(resolved) = Url::parse(specifier) {
Ok(resolved) Ok(UrlOrPath::Url(resolved))
} else { } else {
Ok(self.package_resolve( Ok(self.package_resolve(
specifier, specifier,
@ -324,29 +327,37 @@ impl<
fn finalize_resolution( fn finalize_resolution(
&self, &self,
resolved: Url, resolved: UrlOrPath,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
) -> Result<Url, FinalizeResolutionError> { ) -> Result<UrlOrPath, FinalizeResolutionError> {
let encoded_sep_re = lazy_regex::regex!(r"%2F|%2C"); let encoded_sep_re = lazy_regex::regex!(r"%2F|%2C");
if encoded_sep_re.is_match(resolved.path()) { let text = match &resolved {
UrlOrPath::Url(url) => Cow::Borrowed(url.as_str()),
UrlOrPath::Path(path_buf) => path_buf.to_string_lossy(),
};
if encoded_sep_re.is_match(&text) {
return Err( return Err(
errors::InvalidModuleSpecifierError { errors::InvalidModuleSpecifierError {
request: resolved.to_string(), request: resolved.to_string(),
reason: Cow::Borrowed( reason: Cow::Borrowed(
"must not include encoded \"/\" or \"\\\\\" characters", "must not include encoded \"/\" or \"\\\\\" characters",
), ),
maybe_referrer: maybe_referrer.map(to_file_path_string), maybe_referrer: maybe_referrer.map(|r| match r.path() {
// in this case, prefer showing the path string
Ok(path) => path.display().to_string(),
Err(_) => r.display().to_string(),
}),
} }
.into(), .into(),
); );
} }
if resolved.scheme() == "node" { if resolved.is_node_url() {
return Ok(resolved); return Ok(resolved);
} }
let path = to_file_path(&resolved); let path = resolved.into_path()?;
// TODO(bartlomieju): currently not supported // TODO(bartlomieju): currently not supported
// if (getOptionValue('--experimental-specifier-resolution') === 'node') { // if (getOptionValue('--experimental-specifier-resolution') === 'node') {
@ -354,26 +365,27 @@ impl<
// } // }
let p_str = path.to_str().unwrap(); let p_str = path.to_str().unwrap();
let p = if p_str.ends_with('/') { let path = if p_str.ends_with('/') {
p_str[p_str.len() - 1..].to_string() // todo(dsherret): don't allocate a new string here
PathBuf::from(p_str[p_str.len() - 1..].to_string())
} else { } else {
p_str.to_string() path
}; };
let maybe_file_type = self.sys.fs_metadata(p).map(|m| m.file_type()); let maybe_file_type = self.sys.fs_metadata(&path).map(|m| m.file_type());
match maybe_file_type { match maybe_file_type {
Ok(FileType::Dir) => Err( Ok(FileType::Dir) => Err(
UnsupportedDirImportError { UnsupportedDirImportError {
dir_url: resolved.clone(), dir_url: UrlOrPath::Path(path),
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
} }
.into(), .into(),
), ),
Ok(FileType::File) => Ok(resolved), Ok(FileType::File) => Ok(UrlOrPath::Path(path)),
_ => Err( _ => Err(
ModuleNotFoundError { ModuleNotFoundError {
specifier: resolved, specifier: UrlOrPath::Path(path),
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
typ: "module", typ: "module",
} }
.into(), .into(),
@ -388,16 +400,17 @@ impl<
maybe_referrer: Option<&Url>, maybe_referrer: Option<&Url>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageSubpathResolveError> { ) -> Result<UrlOrPath, PackageSubpathResolveError> {
// todo(dsherret): don't allocate a string here (maybe use an // todo(dsherret): don't allocate a string here (maybe use an
// enum that says the subpath is not prefixed with a ./) // enum that says the subpath is not prefixed with a ./)
let package_subpath = package_subpath let package_subpath = package_subpath
.map(|s| format!("./{s}")) .map(|s| format!("./{s}"))
.unwrap_or_else(|| ".".to_string()); .unwrap_or_else(|| ".".to_string());
let maybe_referrer = maybe_referrer.map(UrlOrPathRef::from_url);
let resolved_url = self.resolve_package_dir_subpath( let resolved_url = self.resolve_package_dir_subpath(
package_dir, package_dir,
&package_subpath, &package_subpath,
maybe_referrer, maybe_referrer.as_ref(),
resolution_mode, resolution_mode,
self self
.conditions_from_resolution_mode .conditions_from_resolution_mode
@ -441,7 +454,7 @@ impl<
&self, &self,
package_folder: &Path, package_folder: &Path,
sub_path: Option<&str>, sub_path: Option<&str>,
) -> Result<Url, ResolvePkgJsonBinExportError> { ) -> Result<PathBuf, ResolvePkgJsonBinExportError> {
let pkg_json_path = package_folder.join("package.json"); let pkg_json_path = package_folder.join("package.json");
let Some(package_json) = let Some(package_json) =
self.pkg_json_resolver.load_package_json(&pkg_json_path)? self.pkg_json_resolver.load_package_json(&pkg_json_path)?
@ -456,18 +469,16 @@ impl<
message: err.to_string(), message: err.to_string(),
} }
})?; })?;
let url = url_from_file_path(&package_folder.join(bin_entry)).unwrap();
// TODO(bartlomieju): skipped checking errors for commonJS resolution and // TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options. // "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(url) Ok(package_folder.join(bin_entry))
} }
/// Resolves an npm package folder path from the specified referrer. /// Resolves an npm package folder path from the specified referrer.
pub fn resolve_package_folder_from_package( pub fn resolve_package_folder_from_package(
&self, &self,
specifier: &str, specifier: &str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<PathBuf, errors::PackageFolderResolveError> { ) -> Result<PathBuf, errors::PackageFolderResolveError> {
self self
.npm_pkg_folder_resolver .npm_pkg_folder_resolver
@ -475,13 +486,13 @@ impl<
} }
/// 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_path(
&self, &self,
path: &Path, path: PathBuf,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
) -> Result<Url, TypesNotFoundError> { ) -> Result<UrlOrPath, TypesNotFoundError> {
fn probe_extensions<TSys: FsMetadata>( fn probe_extensions<TSys: FsMetadata>(
sys: &TSys, sys: &TSys,
path: &Path, path: &Path,
@ -492,20 +503,20 @@ impl<
let mut searched_for_d_cts = false; let mut searched_for_d_cts = false;
if lowercase_path.ends_with(".mjs") { if lowercase_path.ends_with(".mjs") {
let d_mts_path = with_known_extension(path, "d.mts"); let d_mts_path = with_known_extension(path, "d.mts");
if sys.fs_exists_no_err(&d_mts_path) { if sys.fs_is_file_no_err(&d_mts_path) {
return Some(d_mts_path); return Some(d_mts_path);
} }
searched_for_d_mts = true; searched_for_d_mts = true;
} else if lowercase_path.ends_with(".cjs") { } else if lowercase_path.ends_with(".cjs") {
let d_cts_path = with_known_extension(path, "d.cts"); let d_cts_path = with_known_extension(path, "d.cts");
if sys.fs_exists_no_err(&d_cts_path) { if sys.fs_is_file_no_err(&d_cts_path) {
return Some(d_cts_path); return Some(d_cts_path);
} }
searched_for_d_cts = true; searched_for_d_cts = true;
} }
let dts_path = with_known_extension(path, "d.ts"); let dts_path = with_known_extension(path, "d.ts");
if sys.fs_exists_no_err(&dts_path) { if sys.fs_is_file_no_err(&dts_path) {
return Some(dts_path); return Some(dts_path);
} }
@ -519,7 +530,7 @@ impl<
_ => None, // already searched above _ => None, // already searched above
}; };
if let Some(specific_dts_path) = specific_dts_path { if let Some(specific_dts_path) = specific_dts_path {
if sys.fs_exists_no_err(&specific_dts_path) { if sys.fs_is_file_no_err(&specific_dts_path) {
return Some(specific_dts_path); return Some(specific_dts_path);
} }
} }
@ -531,16 +542,16 @@ impl<
|| 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(url_from_file_path(path).unwrap()); return Ok(UrlOrPath::Path(path));
} }
if let Some(path) = if let Some(path) =
probe_extensions(&self.sys, path, &lowercase_path, resolution_mode) probe_extensions(&self.sys, &path, &lowercase_path, resolution_mode)
{ {
return Ok(url_from_file_path(&path).unwrap()); return Ok(UrlOrPath::Path(path));
} }
if self.sys.fs_is_dir_no_err(path) { if self.sys.fs_is_dir_no_err(&path) {
let resolution_result = self.resolve_package_dir_subpath( let resolution_result = self.resolve_package_dir_subpath(
path, &path,
/* sub path */ ".", /* sub path */ ".",
maybe_referrer, maybe_referrer,
resolution_mode, resolution_mode,
@ -557,16 +568,16 @@ impl<
&index_path.to_string_lossy().to_lowercase(), &index_path.to_string_lossy().to_lowercase(),
resolution_mode, resolution_mode,
) { ) {
return Ok(url_from_file_path(&path).unwrap()); return Ok(UrlOrPath::Path(path));
} }
} }
// 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(url_from_file_path(path).unwrap()); return Ok(UrlOrPath::Path(path));
} }
Err(TypesNotFoundError(Box::new(TypesNotFoundErrorData { Err(TypesNotFoundError(Box::new(TypesNotFoundErrorData {
code_specifier: url_from_file_path(path).unwrap(), code_specifier: UrlOrPathRef::from_path(&path).display(),
maybe_referrer: maybe_referrer.cloned(), maybe_referrer: maybe_referrer.map(|r| r.display()),
}))) })))
} }
@ -574,12 +585,12 @@ impl<
pub fn package_imports_resolve( pub fn package_imports_resolve(
&self, &self,
name: &str, name: &str,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
referrer_pkg_json: Option<&PackageJson>, referrer_pkg_json: Option<&PackageJson>,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageImportsResolveError> { ) -> Result<UrlOrPath, PackageImportsResolveError> {
if name == "#" || name.starts_with("#/") || name.ends_with('/') { if name == "#" || name.starts_with("#/") || name.ends_with('/') {
let reason = "is not a valid internal imports specifier name"; let reason = "is not a valid internal imports specifier name";
return Err( return Err(
@ -662,7 +673,7 @@ impl<
PackageImportNotDefinedError { PackageImportNotDefinedError {
name: name.to_string(), name: name.to_string(),
package_json_path, package_json_path,
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
} }
.into(), .into(),
) )
@ -675,13 +686,13 @@ impl<
subpath: &str, subpath: &str,
match_: &str, match_: &str,
package_json_path: &Path, package_json_path: &Path,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
pattern: bool, pattern: bool,
internal: bool, internal: bool,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageTargetResolveError> { ) -> Result<UrlOrPath, PackageTargetResolveError> {
if !subpath.is_empty() && !pattern && !target.ends_with('/') { if !subpath.is_empty() && !pattern && !target.ends_with('/') {
return Err( return Err(
InvalidPackageTargetError { InvalidPackageTargetError {
@ -689,7 +700,7 @@ impl<
sub_path: match_.to_string(), sub_path: match_.to_string(),
target: target.to_string(), target: target.to_string(),
is_import: internal, is_import: internal,
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
} }
.into(), .into(),
); );
@ -705,7 +716,7 @@ impl<
if get_module_name_from_builtin_node_module_specifier(&url) if get_module_name_from_builtin_node_module_specifier(&url)
.is_some() .is_some()
{ {
return Ok(url); return Ok(UrlOrPath::Url(url));
} }
} }
Err(_) => { Err(_) => {
@ -716,18 +727,17 @@ impl<
} else { } else {
format!("{target}{subpath}") format!("{target}{subpath}")
}; };
let package_json_url =
url_from_file_path(package_json_path).unwrap();
let result = match self.package_resolve( let result = match self.package_resolve(
&export_target, &export_target,
&package_json_url, &UrlOrPathRef::from_path(package_json_path),
resolution_mode, resolution_mode,
conditions, conditions,
resolution_kind, resolution_kind,
) { ) {
Ok(url) => Ok(url), Ok(url) => Ok(url),
Err(err) => match err.code() { Err(err) => match err.code() {
NodeJsErrorCode::ERR_INVALID_MODULE_SPECIFIER NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
| NodeJsErrorCode::ERR_INVALID_MODULE_SPECIFIER
| NodeJsErrorCode::ERR_INVALID_PACKAGE_CONFIG | NodeJsErrorCode::ERR_INVALID_PACKAGE_CONFIG
| NodeJsErrorCode::ERR_INVALID_PACKAGE_TARGET | NodeJsErrorCode::ERR_INVALID_PACKAGE_TARGET
| NodeJsErrorCode::ERR_PACKAGE_IMPORT_NOT_DEFINED | NodeJsErrorCode::ERR_PACKAGE_IMPORT_NOT_DEFINED
@ -743,7 +753,7 @@ impl<
PackageTargetNotFoundError { PackageTargetNotFoundError {
pkg_json_path: package_json_path.to_path_buf(), pkg_json_path: package_json_path.to_path_buf(),
target: export_target.to_string(), target: export_target.to_string(),
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
resolution_mode, resolution_mode,
resolution_kind, resolution_kind,
}, },
@ -760,7 +770,9 @@ impl<
.is_built_in_node_module_checker .is_built_in_node_module_checker
.is_builtin_node_module(target) .is_builtin_node_module(target)
{ {
Ok(Url::parse(&format!("node:{}", target)).unwrap()) Ok(UrlOrPath::Url(
Url::parse(&format!("node:{}", target)).unwrap(),
))
} else { } else {
Err(err) Err(err)
} }
@ -775,7 +787,7 @@ impl<
sub_path: match_.to_string(), sub_path: match_.to_string(),
target: target.to_string(), target: target.to_string(),
is_import: internal, is_import: internal,
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
} }
.into(), .into(),
); );
@ -787,7 +799,7 @@ impl<
sub_path: match_.to_string(), sub_path: match_.to_string(),
target: target.to_string(), target: target.to_string(),
is_import: internal, is_import: internal,
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
} }
.into(), .into(),
); );
@ -801,13 +813,13 @@ impl<
sub_path: match_.to_string(), sub_path: match_.to_string(),
target: target.to_string(), target: target.to_string(),
is_import: internal, is_import: internal,
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
} }
.into(), .into(),
); );
} }
if subpath.is_empty() { if subpath.is_empty() {
return Ok(url_from_file_path(&resolved_path).unwrap()); return Ok(UrlOrPath::Path(resolved_path));
} }
if invalid_segment_re.is_match(subpath) { if invalid_segment_re.is_match(subpath) {
let request = if pattern { let request = if pattern {
@ -829,11 +841,9 @@ impl<
let resolved_path_str = resolved_path.to_string_lossy(); let resolved_path_str = resolved_path.to_string_lossy();
let replaced = pattern_re let replaced = pattern_re
.replace(&resolved_path_str, |_caps: &regex::Captures| subpath); .replace(&resolved_path_str, |_caps: &regex::Captures| subpath);
return Ok( return Ok(UrlOrPath::Path(PathBuf::from(replaced.to_string())));
url_from_file_path(&PathBuf::from(replaced.to_string())).unwrap(),
);
} }
Ok(url_from_file_path(&resolved_path.join(subpath).clean()).unwrap()) Ok(UrlOrPath::Path(resolved_path.join(subpath).clean()))
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@ -843,13 +853,13 @@ impl<
target: &Value, target: &Value,
subpath: &str, subpath: &str,
package_subpath: &str, package_subpath: &str,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
pattern: bool, pattern: bool,
internal: bool, internal: bool,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Option<Url>, PackageTargetResolveError> { ) -> Result<Option<UrlOrPath>, PackageTargetResolveError> {
let result = self.resolve_package_target_inner( let result = self.resolve_package_target_inner(
package_json_path, package_json_path,
target, target,
@ -899,15 +909,15 @@ impl<
target: &Value, target: &Value,
subpath: &str, subpath: &str,
package_subpath: &str, package_subpath: &str,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
pattern: bool, pattern: bool,
internal: bool, internal: bool,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Option<Url>, PackageTargetResolveError> { ) -> Result<Option<UrlOrPath>, PackageTargetResolveError> {
if let Some(target) = target.as_str() { if let Some(target) = target.as_str() {
let url = self.resolve_package_target_string( let url_or_path = self.resolve_package_target_string(
target, target,
subpath, subpath,
package_subpath, package_subpath,
@ -919,16 +929,16 @@ impl<
conditions, conditions,
resolution_kind, resolution_kind,
)?; )?;
if resolution_kind.is_types() && url.scheme() == "file" { if resolution_kind.is_types() && url_or_path.is_file() {
let path = deno_path_util::url_to_file_path(&url).unwrap(); let path = url_or_path.into_path()?;
return Ok(Some(self.path_to_declaration_url( return Ok(Some(self.path_to_declaration_path(
&path, path,
maybe_referrer, maybe_referrer,
resolution_mode, resolution_mode,
conditions, conditions,
)?)); )?));
} else { } else {
return Ok(Some(url)); return Ok(Some(url_or_path));
} }
} else if let Some(target_arr) = target.as_array() { } else if let Some(target_arr) = target.as_array() {
if target_arr.is_empty() { if target_arr.is_empty() {
@ -1013,7 +1023,7 @@ impl<
sub_path: package_subpath.to_string(), sub_path: package_subpath.to_string(),
target: target.to_string(), target: target.to_string(),
is_import: internal, is_import: internal,
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
} }
.into(), .into(),
) )
@ -1025,11 +1035,11 @@ impl<
package_json_path: &Path, package_json_path: &Path,
package_subpath: &str, package_subpath: &str,
package_exports: &Map<String, Value>, package_exports: &Map<String, Value>,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageExportsResolveError> { ) -> Result<UrlOrPath, PackageExportsResolveError> {
if let Some(target) = package_exports.get(package_subpath) { if let Some(target) = package_exports.get(package_subpath) {
if package_subpath.find('*').is_none() && !package_subpath.ends_with('/') if package_subpath.find('*').is_none() && !package_subpath.ends_with('/')
{ {
@ -1051,7 +1061,7 @@ impl<
PackagePathNotExportedError { PackagePathNotExportedError {
pkg_json_path: package_json_path.to_path_buf(), pkg_json_path: package_json_path.to_path_buf(),
subpath: package_subpath.to_string(), subpath: package_subpath.to_string(),
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
resolution_kind, resolution_kind,
} }
.into(), .into(),
@ -1116,7 +1126,7 @@ impl<
PackagePathNotExportedError { PackagePathNotExportedError {
pkg_json_path: package_json_path.to_path_buf(), pkg_json_path: package_json_path.to_path_buf(),
subpath: package_subpath.to_string(), subpath: package_subpath.to_string(),
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
resolution_kind, resolution_kind,
} }
.into(), .into(),
@ -1128,7 +1138,7 @@ impl<
PackagePathNotExportedError { PackagePathNotExportedError {
pkg_json_path: package_json_path.to_path_buf(), pkg_json_path: package_json_path.to_path_buf(),
subpath: package_subpath.to_string(), subpath: package_subpath.to_string(),
maybe_referrer: maybe_referrer.map(ToOwned::to_owned), maybe_referrer: maybe_referrer.map(|r| r.display()),
resolution_kind, resolution_kind,
} }
.into(), .into(),
@ -1138,16 +1148,17 @@ impl<
pub(super) fn package_resolve( pub(super) fn package_resolve(
&self, &self,
specifier: &str, specifier: &str,
referrer: &Url, referrer: &UrlOrPathRef,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageResolveError> { ) -> Result<UrlOrPath, PackageResolveError> {
let (package_name, package_subpath, _is_scoped) = let (package_name, package_subpath, _is_scoped) =
parse_npm_pkg_name(specifier, referrer)?; parse_npm_pkg_name(specifier, referrer)?;
if let Some(package_config) = if let Some(package_config) = self
self.pkg_json_resolver.get_closest_package_json(referrer)? .pkg_json_resolver
.get_closest_package_json(referrer.path()?)?
{ {
// ResolveSelf // ResolveSelf
if package_config.name.as_deref() == Some(package_name) { if package_config.name.as_deref() == Some(package_name) {
@ -1182,11 +1193,11 @@ impl<
&self, &self,
package_name: &str, package_name: &str,
package_subpath: &str, package_subpath: &str,
referrer: &Url, referrer: &UrlOrPathRef,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageResolveError> { ) -> Result<UrlOrPath, PackageResolveError> {
let result = self.resolve_package_subpath_for_package_inner( let result = self.resolve_package_subpath_for_package_inner(
package_name, package_name,
package_subpath, package_subpath,
@ -1195,7 +1206,7 @@ impl<
conditions, conditions,
resolution_kind, resolution_kind,
); );
if resolution_kind.is_types() && !matches!(result, Ok(Url { .. })) { if resolution_kind.is_types() && result.is_err() {
// try to resolve with the @types package // try to resolve with the @types package
let package_name = types_package_name(package_name); let package_name = types_package_name(package_name);
if let Ok(result) = self.resolve_package_subpath_for_package_inner( if let Ok(result) = self.resolve_package_subpath_for_package_inner(
@ -1217,11 +1228,11 @@ impl<
&self, &self,
package_name: &str, package_name: &str,
package_subpath: &str, package_subpath: &str,
referrer: &Url, referrer: &UrlOrPathRef,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageResolveError> { ) -> Result<UrlOrPath, PackageResolveError> {
let package_dir_path = self let package_dir_path = self
.npm_pkg_folder_resolver .npm_pkg_folder_resolver
.resolve_package_folder_from_package(package_name, referrer)?; .resolve_package_folder_from_package(package_name, referrer)?;
@ -1257,11 +1268,11 @@ impl<
&self, &self,
package_dir_path: &Path, package_dir_path: &Path,
package_subpath: &str, package_subpath: &str,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageSubpathResolveError> { ) -> Result<UrlOrPath, PackageSubpathResolveError> {
let package_json_path = package_dir_path.join("package.json"); let package_json_path = package_dir_path.join("package.json");
match self match self
.pkg_json_resolver .pkg_json_resolver
@ -1295,11 +1306,11 @@ impl<
&self, &self,
package_json: &PackageJson, package_json: &PackageJson,
package_subpath: &str, package_subpath: &str,
referrer: Option<&Url>, referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, PackageSubpathResolveError> { ) -> Result<UrlOrPath, PackageSubpathResolveError> {
if let Some(exports) = &package_json.exports { if let Some(exports) = &package_json.exports {
let result = self.package_exports_resolve( let result = self.package_exports_resolve(
&package_json.path, &package_json.path,
@ -1365,22 +1376,22 @@ impl<
&self, &self,
directory: &Path, directory: &Path,
package_subpath: &str, package_subpath: &str,
referrer: Option<&Url>, referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, TypesNotFoundError> { ) -> Result<UrlOrPath, TypesNotFoundError> {
assert_ne!(package_subpath, "."); assert_ne!(package_subpath, ".");
let file_path = directory.join(package_subpath); let file_path = directory.join(package_subpath);
if resolution_kind.is_types() { if resolution_kind.is_types() {
Ok(self.path_to_declaration_url( Ok(self.path_to_declaration_path(
&file_path, file_path,
referrer, referrer,
resolution_mode, resolution_mode,
conditions, conditions,
)?) )?)
} else { } else {
Ok(url_from_file_path(&file_path).unwrap()) Ok(UrlOrPath::Path(file_path))
} }
} }
@ -1388,18 +1399,20 @@ impl<
&self, &self,
directory: &Path, directory: &Path,
package_subpath: &str, package_subpath: &str,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, LegacyResolveError> { ) -> Result<UrlOrPath, LegacyResolveError> {
if package_subpath == "." { if package_subpath == "." {
self.legacy_index_resolve( self
directory, .legacy_index_resolve(
maybe_referrer, directory,
resolution_mode, maybe_referrer,
resolution_kind, resolution_mode,
) resolution_kind,
)
.map(UrlOrPath::Path)
} else { } else {
self self
.resolve_subpath_exact( .resolve_subpath_exact(
@ -1417,11 +1430,11 @@ impl<
pub(super) fn legacy_main_resolve( pub(super) fn legacy_main_resolve(
&self, &self,
package_json: &PackageJson, package_json: &PackageJson,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
conditions: &[&str], conditions: &[&str],
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, LegacyResolveError> { ) -> Result<UrlOrPath, LegacyResolveError> {
let pkg_json_kind = match resolution_mode { let pkg_json_kind = match resolution_mode {
ResolutionMode::Require => deno_package_json::NodeModuleKind::Cjs, ResolutionMode::Require => deno_package_json::NodeModuleKind::Cjs,
ResolutionMode::Import => deno_package_json::NodeModuleKind::Esm, ResolutionMode::Import => deno_package_json::NodeModuleKind::Esm,
@ -1434,15 +1447,15 @@ impl<
// a corresponding declaration file // a corresponding declaration file
if let Some(main) = package_json.main(pkg_json_kind) { if let Some(main) = package_json.main(pkg_json_kind) {
let main = package_json.path.parent().unwrap().join(main).clean(); let main = package_json.path.parent().unwrap().join(main).clean();
let decl_url_result = self.path_to_declaration_url( let decl_path_result = self.path_to_declaration_path(
&main, main,
maybe_referrer, maybe_referrer,
resolution_mode, resolution_mode,
conditions, conditions,
); );
// don't surface errors, fallback to checking the index now // don't surface errors, fallback to checking the index now
if let Ok(url) = decl_url_result { if let Ok(url_or_path) = decl_path_result {
return Ok(url); return Ok(url_or_path);
} }
} }
None None
@ -1455,7 +1468,7 @@ impl<
if let Some(main) = maybe_main { if let Some(main) = maybe_main {
let guess = package_json.path.parent().unwrap().join(main).clean(); let guess = package_json.path.parent().unwrap().join(main).clean();
if self.sys.fs_is_file_no_err(&guess) { if self.sys.fs_is_file_no_err(&guess) {
return Ok(url_from_file_path(&guess).unwrap()); return Ok(UrlOrPath::Path(guess));
} }
// todo(dsherret): investigate exactly how node and typescript handles this // todo(dsherret): investigate exactly how node and typescript handles this
@ -1485,26 +1498,28 @@ impl<
.clean(); .clean();
if self.sys.fs_is_file_no_err(&guess) { if self.sys.fs_is_file_no_err(&guess) {
// TODO(bartlomieju): emitLegacyIndexDeprecation() // TODO(bartlomieju): emitLegacyIndexDeprecation()
return Ok(url_from_file_path(&guess).unwrap()); return Ok(UrlOrPath::Path(guess));
} }
} }
} }
self.legacy_index_resolve( self
package_json.path.parent().unwrap(), .legacy_index_resolve(
maybe_referrer, package_json.path.parent().unwrap(),
resolution_mode, maybe_referrer,
resolution_kind, resolution_mode,
) resolution_kind,
)
.map(UrlOrPath::Path)
} }
fn legacy_index_resolve( fn legacy_index_resolve(
&self, &self,
directory: &Path, directory: &Path,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<Url, LegacyResolveError> { ) -> Result<PathBuf, LegacyResolveError> {
let index_file_names = if resolution_kind.is_types() { let index_file_names = if resolution_kind.is_types() {
// todo(dsherret): investigate exactly how typescript does this // todo(dsherret): investigate exactly how typescript does this
match resolution_mode { match resolution_mode {
@ -1520,25 +1535,25 @@ impl<
let guess = directory.join(index_file_name).clean(); let guess = directory.join(index_file_name).clean();
if self.sys.fs_is_file_no_err(&guess) { if self.sys.fs_is_file_no_err(&guess) {
// TODO(bartlomieju): emitLegacyIndexDeprecation() // TODO(bartlomieju): emitLegacyIndexDeprecation()
return Ok(url_from_file_path(&guess).unwrap()); return Ok(guess);
} }
} }
if resolution_kind.is_types() { if resolution_kind.is_types() {
Err( Err(
TypesNotFoundError(Box::new(TypesNotFoundErrorData { TypesNotFoundError(Box::new(TypesNotFoundErrorData {
code_specifier: url_from_file_path(&directory.join("index.js")) code_specifier: UrlOrPathRef::from_path(&directory.join("index.js"))
.unwrap(), .display(),
maybe_referrer: maybe_referrer.cloned(), maybe_referrer: maybe_referrer.map(|r| r.display()),
})) }))
.into(), .into(),
) )
} else { } else {
Err( Err(
ModuleNotFoundError { ModuleNotFoundError {
specifier: url_from_file_path(&directory.join("index.js")).unwrap(), specifier: UrlOrPath::Path(directory.join("index.js")),
typ: "module", typ: "module",
maybe_referrer: maybe_referrer.cloned(), maybe_referrer: maybe_referrer.map(|r| r.display()),
} }
.into(), .into(),
) )
@ -1652,14 +1667,6 @@ fn resolve_bin_entry_value<'a>(
} }
} }
fn to_file_path(url: &Url) -> PathBuf {
deno_path_util::url_to_file_path(url).unwrap()
}
fn to_file_path_string(url: &Url) -> String {
to_file_path(url).display().to_string()
}
fn should_be_treated_as_relative_or_absolute_path(specifier: &str) -> bool { fn should_be_treated_as_relative_or_absolute_path(specifier: &str) -> bool {
if specifier.is_empty() { if specifier.is_empty() {
return false; return false;
@ -1731,11 +1738,11 @@ fn with_known_extension(path: &Path, ext: &str) -> PathBuf {
path.with_file_name(format!("{file_name}.{ext}")) path.with_file_name(format!("{file_name}.{ext}"))
} }
fn to_specifier_display_string(url: &Url) -> String { fn to_specifier_display_string(url: &UrlOrPathRef) -> String {
if let Ok(path) = deno_path_util::url_to_file_path(url) { if let Ok(path) = url.path() {
path.display().to_string() path.display().to_string()
} else { } else {
url.to_string() url.display().to_string()
} }
} }
@ -1743,7 +1750,7 @@ fn throw_invalid_subpath(
subpath: String, subpath: String,
package_json_path: &Path, package_json_path: &Path,
internal: bool, internal: bool,
maybe_referrer: Option<&Url>, maybe_referrer: Option<&UrlOrPathRef>,
) -> InvalidModuleSpecifierError { ) -> InvalidModuleSpecifierError {
let ie = if internal { "imports" } else { "exports" }; let ie = if internal { "imports" } else { "exports" };
let reason = format!( let reason = format!(
@ -1760,7 +1767,7 @@ fn throw_invalid_subpath(
pub fn parse_npm_pkg_name<'a>( pub fn parse_npm_pkg_name<'a>(
specifier: &'a str, specifier: &'a str,
referrer: &Url, referrer: &UrlOrPathRef,
) -> Result<(&'a str, Cow<'static, str>, bool), InvalidModuleSpecifierError> { ) -> Result<(&'a str, Cow<'static, str>, bool), InvalidModuleSpecifierError> {
let mut separator_index = specifier.find('/'); let mut separator_index = specifier.find('/');
let mut valid_package_name = true; let mut valid_package_name = true;
@ -2045,6 +2052,7 @@ mod tests {
#[test] #[test]
fn test_parse_package_name() { fn test_parse_package_name() {
let dummy_referrer = Url::parse("http://example.com").unwrap(); let dummy_referrer = Url::parse("http://example.com").unwrap();
let dummy_referrer = UrlOrPathRef::from_url(&dummy_referrer);
assert_eq!( assert_eq!(
parse_npm_pkg_name("fetch-blob", &dummy_referrer).unwrap(), parse_npm_pkg_name("fetch-blob", &dummy_referrer).unwrap(),