diff --git a/cli/module_loader.rs b/cli/module_loader.rs index 4254375e5733cf..2e047d36d3820b 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -446,15 +446,14 @@ impl specifier: &str, referrer: &ModuleSpecifier, ) -> Result { - if let Some(result) = self.shared.node_resolver.resolve_if_in_npm_package( - specifier, - referrer, - NodeResolutionMode::Execution, - ) { - return match result? { - Some(res) => Ok(res.into_url()), - None => Err(generic_error("not found")), - }; + if self.shared.node_resolver.in_npm_package(referrer) { + return Ok( + self + .shared + .node_resolver + .resolve(specifier, referrer, NodeResolutionMode::Execution)? + .into_url(), + ); } let graph = self.graph_container.graph(); diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index f776b79c1994bb..d10bb6b2aba6c4 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -12,7 +12,8 @@ use deno_core::serde_json; use deno_package_json::PackageJsonDepValue; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node::errors::PackageFolderResolveError; -use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind; +use deno_runtime::deno_node::errors::PackageFolderResolveIoError; +use deno_runtime::deno_node::errors::PackageNotFoundError; use deno_runtime::deno_node::load_pkg_json; use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NpmResolver; @@ -198,7 +199,7 @@ impl NpmResolver for ByonmCliNpmResolver { } Err( - PackageFolderResolveErrorKind::NotFoundPackage { + PackageNotFoundError { package_name: name.to_string(), referrer: referrer.clone(), referrer_extra: None, @@ -209,7 +210,7 @@ impl NpmResolver for ByonmCliNpmResolver { let path = inner(&*self.fs, name, referrer)?; self.fs.realpath_sync(&path).map_err(|err| { - PackageFolderResolveErrorKind::Io { + PackageFolderResolveIoError { package_name: name.to_string(), referrer: referrer.clone(), source: err.into_io_error(), diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs index a18ad4d7f19cfa..602733cabdb9c6 100644 --- a/cli/npm/managed/mod.rs +++ b/cli/npm/managed/mod.rs @@ -21,7 +21,7 @@ use deno_npm::NpmResolutionPackage; use deno_npm::NpmSystemInfo; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node::errors::PackageFolderResolveError; -use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind; +use deno_runtime::deno_node::errors::PackageFolderResolveIoError; use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NpmResolver; use deno_semver::package::PackageNv; @@ -549,7 +549,7 @@ impl NpmResolver for ManagedCliNpmResolver { .resolve_package_folder_from_package(name, referrer)?; let path = canonicalize_path_maybe_not_exists_with_fs(&path, self.fs.as_ref()) - .map_err(|err| PackageFolderResolveErrorKind::Io { + .map_err(|err| PackageFolderResolveIoError { package_name: name.to_string(), referrer: referrer.clone(), source: err, diff --git a/cli/npm/managed/resolvers/global.rs b/cli/npm/managed/resolvers/global.rs index d16fe7cd0d9e67..e7a57fc23f26fc 100644 --- a/cli/npm/managed/resolvers/global.rs +++ b/cli/npm/managed/resolvers/global.rs @@ -15,7 +15,8 @@ use deno_npm::NpmPackageId; use deno_npm::NpmSystemInfo; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node::errors::PackageFolderResolveError; -use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind; +use deno_runtime::deno_node::errors::PackageNotFoundError; +use deno_runtime::deno_node::errors::ReferrerNotFoundError; use deno_runtime::deno_node::NodePermissions; use super::super::cache::NpmCache; @@ -84,7 +85,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver { .resolve_package_folder_id_from_specifier(referrer) else { return Err( - PackageFolderResolveErrorKind::NotFoundReferrer { + ReferrerNotFoundError { referrer: referrer.clone(), referrer_extra: None, } @@ -98,7 +99,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver { Ok(pkg) => match self.maybe_package_folder(&pkg.id) { Some(folder) => Ok(folder), None => Err( - PackageFolderResolveErrorKind::NotFoundPackage { + PackageNotFoundError { package_name: name.to_string(), referrer: referrer.clone(), referrer_extra: Some(format!( @@ -112,7 +113,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver { }, Err(err) => match *err { PackageNotFoundFromReferrerError::Referrer(cache_folder_id) => Err( - PackageFolderResolveErrorKind::NotFoundReferrer { + ReferrerNotFoundError { referrer: referrer.clone(), referrer_extra: Some(cache_folder_id.to_string()), } @@ -122,7 +123,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver { name, referrer: cache_folder_id_referrer, } => Err( - PackageFolderResolveErrorKind::NotFoundPackage { + PackageNotFoundError { package_name: name, referrer: referrer.clone(), referrer_extra: Some(cache_folder_id_referrer.to_string()), diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs index 90a17b15727880..cda78548b2f3b0 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/managed/resolvers/local.rs @@ -33,7 +33,9 @@ use deno_npm::NpmResolutionPackage; use deno_npm::NpmSystemInfo; use deno_runtime::deno_fs; use deno_runtime::deno_node::errors::PackageFolderResolveError; -use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind; +use deno_runtime::deno_node::errors::PackageFolderResolveIoError; +use deno_runtime::deno_node::errors::PackageNotFoundError; +use deno_runtime::deno_node::errors::ReferrerNotFoundError; use deno_runtime::deno_node::NodePermissions; use deno_semver::package::PackageNv; use serde::Deserialize; @@ -185,14 +187,14 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver { ) -> Result { let maybe_local_path = self .resolve_folder_for_specifier(referrer) - .map_err(|err| PackageFolderResolveErrorKind::Io { + .map_err(|err| PackageFolderResolveIoError { package_name: name.to_string(), referrer: referrer.clone(), source: err, })?; let Some(local_path) = maybe_local_path else { return Err( - PackageFolderResolveErrorKind::NotFoundReferrer { + ReferrerNotFoundError { referrer: referrer.clone(), referrer_extra: None, } @@ -220,7 +222,7 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver { } Err( - PackageFolderResolveErrorKind::NotFoundPackage { + PackageNotFoundError { package_name: name.to_string(), referrer: referrer.clone(), referrer_extra: None, diff --git a/cli/resolver.rs b/cli/resolver.rs index c332878a23b616..c1bb8a0a571113 100644 --- a/cli/resolver.rs +++ b/cli/resolver.rs @@ -25,15 +25,17 @@ use deno_runtime::deno_fs; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node::errors::ClosestPkgJsonError; use deno_runtime::deno_node::errors::NodeResolveError; -use deno_runtime::deno_node::errors::ResolvePkgSubpathFromDenoModuleError; +use deno_runtime::deno_node::errors::NodeResolveErrorKind; +use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind; +use deno_runtime::deno_node::errors::PackageFolderResolveIoError; +use deno_runtime::deno_node::errors::PackageNotFoundError; +use deno_runtime::deno_node::errors::PackageResolveErrorKind; use deno_runtime::deno_node::errors::UrlToNodeResolutionError; use deno_runtime::deno_node::is_builtin_node_module; -use deno_runtime::deno_node::parse_npm_pkg_name; use deno_runtime::deno_node::NodeModuleKind; use deno_runtime::deno_node::NodeResolution; use deno_runtime::deno_node::NodeResolutionMode; use deno_runtime::deno_node::NodeResolver; -use deno_runtime::deno_node::NpmResolver as DenoNodeNpmResolver; use deno_runtime::deno_node::PackageJson; use deno_runtime::fs_util::specifier_to_file_path; use deno_semver::npm::NpmPackageReqReference; @@ -47,7 +49,6 @@ use crate::args::JsxImportSourceConfig; use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS; use crate::colors; use crate::node::CliNodeCodeTranslator; -use crate::npm::ByonmCliNpmResolver; use crate::npm::CliNpmResolver; use crate::npm::InnerCliNpmResolverRef; use crate::util::sync::AtomicFlag; @@ -102,17 +103,77 @@ impl CliNodeResolver { self.node_resolver.get_closest_package_json(referrer) } - pub fn resolve_if_in_npm_package( + pub fn resolve_if_for_npm_pkg( &self, specifier: &str, referrer: &ModuleSpecifier, mode: NodeResolutionMode, - ) -> Option, NodeResolveError>> { - if self.in_npm_package(referrer) { - // we're in an npm package, so use node resolution - Some(self.resolve(specifier, referrer, mode)) - } else { - None + ) -> Result, AnyError> { + let resolution_result = self.resolve(specifier, referrer, mode); + match resolution_result { + Ok(res) => Ok(Some(res)), + Err(err) => { + let err = err.into_kind(); + match err { + NodeResolveErrorKind::RelativeJoin(_) + | NodeResolveErrorKind::PackageImportsResolve(_) + | NodeResolveErrorKind::UnsupportedEsmUrlScheme(_) + | NodeResolveErrorKind::DataUrlReferrer(_) + | NodeResolveErrorKind::TypesNotFound(_) + | NodeResolveErrorKind::FinalizeResolution(_) + | NodeResolveErrorKind::UrlToNodeResolution(_) => Err(err.into()), + NodeResolveErrorKind::PackageResolve(err) => { + let err = err.into_kind(); + match err { + PackageResolveErrorKind::ClosestPkgJson(_) + | PackageResolveErrorKind::InvalidModuleSpecifier(_) + | PackageResolveErrorKind::ExportsResolve(_) + | PackageResolveErrorKind::SubpathResolve(_) => Err(err.into()), + PackageResolveErrorKind::PackageFolderResolve(err) => { + match err.as_kind() { + PackageFolderResolveErrorKind::Io( + PackageFolderResolveIoError { package_name, .. }, + ) + | PackageFolderResolveErrorKind::PackageNotFound( + PackageNotFoundError { package_name, .. }, + ) => { + if self.in_npm_package(referrer) { + return Err(err.into()); + } + if let Some(byonm_npm_resolver) = + self.npm_resolver.as_byonm() + { + if byonm_npm_resolver + .find_ancestor_package_json_with_dep( + package_name, + referrer, + ) + .is_some() + { + return Err(anyhow!( + concat!( + "Could not resolve \"{}\", but found it in a package.json. ", + "Deno expects the node_modules/ directory to be up to date. ", + "Did you forget to run `npm install`?" + ), + specifier + )); + } + } + Ok(None) + } + PackageFolderResolveErrorKind::ReferrerNotFound(_) => { + if self.in_npm_package(referrer) { + return Err(err.into()); + } + Ok(None) + } + } + } + } + } + } + } } } @@ -121,18 +182,18 @@ impl CliNodeResolver { specifier: &str, referrer: &ModuleSpecifier, mode: NodeResolutionMode, - ) -> Result, NodeResolveError> { + ) -> Result { let referrer_kind = if self.cjs_resolutions.contains(referrer) { NodeModuleKind::Cjs } else { NodeModuleKind::Esm }; - let maybe_res = + let res = self .node_resolver .resolve(specifier, referrer, referrer_kind, mode)?; - Ok(self.handle_node_resolution(maybe_res)) + Ok(self.handle_node_resolution(res)) } pub fn resolve_req_reference( @@ -159,16 +220,15 @@ impl CliNodeResolver { let package_folder = self .npm_resolver .resolve_pkg_folder_from_deno_module_req(req, referrer)?; - let maybe_resolution = self - .maybe_resolve_package_sub_path_from_deno_module( - &package_folder, - sub_path, - Some(referrer), - mode, - )?; - match maybe_resolution { - Some(resolution) => Ok(resolution), - None => { + let resolution_result = self.resolve_package_sub_path_from_deno_module( + &package_folder, + sub_path, + Some(referrer), + mode, + ); + match resolution_result { + Ok(resolution) => Ok(resolution), + Err(err) => { if self.npm_resolver.as_byonm().is_some() { let package_json_path = package_folder.join("package.json"); if !self.fs.exists_sync(&package_json_path) { @@ -178,12 +238,7 @@ impl CliNodeResolver { )); } } - Err(anyhow!( - "Failed resolving '{}{}' in '{}'.", - req, - sub_path.map(|s| format!("/{}", s)).unwrap_or_default(), - package_folder.display() - )) + Err(err) } } } @@ -195,32 +250,7 @@ impl CliNodeResolver { maybe_referrer: Option<&ModuleSpecifier>, mode: NodeResolutionMode, ) -> Result { - self - .maybe_resolve_package_sub_path_from_deno_module( - package_folder, - sub_path, - maybe_referrer, - mode, - )? - .ok_or_else(|| { - anyhow!( - "Failed resolving '{}' in '{}'.", - sub_path - .map(|s| format!("/{}", s)) - .unwrap_or_else(|| ".".to_string()), - package_folder.display(), - ) - }) - } - - pub fn maybe_resolve_package_sub_path_from_deno_module( - &self, - package_folder: &Path, - sub_path: Option<&str>, - maybe_referrer: Option<&ModuleSpecifier>, - mode: NodeResolutionMode, - ) -> Result, ResolvePkgSubpathFromDenoModuleError> { - let maybe_res = self + let res = self .node_resolver .resolve_package_subpath_from_deno_module( package_folder, @@ -228,7 +258,7 @@ impl CliNodeResolver { maybe_referrer, mode, )?; - Ok(self.handle_node_resolution(maybe_res)) + Ok(self.handle_node_resolution(res)) } pub fn handle_if_in_node_modules( @@ -267,13 +297,13 @@ impl CliNodeResolver { fn handle_node_resolution( &self, - maybe_resolution: Option, - ) -> Option { - if let Some(NodeResolution::CommonJs(specifier)) = &maybe_resolution { + resolution: NodeResolution, + ) -> NodeResolution { + if let NodeResolution::CommonJs(specifier) = &resolution { // remember that this was a common js resolution self.cjs_resolutions.insert(specifier.clone()); } - maybe_resolution + resolution } } @@ -458,39 +488,6 @@ impl CliGraphResolver { bare_node_builtins_enabled: self.bare_node_builtins_enabled, } } - - // todo(dsherret): update this and the surrounding code to handle the structured errors from NodeResolver - fn check_surface_byonm_node_error( - &self, - specifier: &str, - referrer: &ModuleSpecifier, - original_err: AnyError, - resolver: &ByonmCliNpmResolver, - ) -> Result<(), AnyError> { - if let Ok((pkg_name, _, _)) = parse_npm_pkg_name(specifier, referrer) { - match resolver.resolve_package_folder_from_package(&pkg_name, referrer) { - Ok(_) => { - return Err(original_err); - } - Err(_) => { - if resolver - .find_ancestor_package_json_with_dep(&pkg_name, referrer) - .is_some() - { - return Err(anyhow!( - concat!( - "Could not resolve \"{}\", but found it in a package.json. ", - "Deno expects the node_modules/ directory to be up to date. ", - "Did you forget to run `npm install`?" - ), - specifier - )); - } - } - } - } - Ok(()) - } } impl Resolver for CliGraphResolver { @@ -523,6 +520,18 @@ impl Resolver for CliGraphResolver { } let referrer = &referrer_range.specifier; + + // Use node resolution if we're in an npm package + if let Some(node_resolver) = self.node_resolver.as_ref() { + if referrer.scheme() == "file" && node_resolver.in_npm_package(referrer) { + return node_resolver + .resolve(specifier, referrer, to_node_mode(mode)) + .map(|res| res.into_url()) + .map_err(|e| ResolveError::Other(e.into())); + } + } + + // Attempt to resolve with the workspace resolver let result: Result<_, ResolveError> = self .workspace_resolver .resolve(specifier, referrer) @@ -535,7 +544,19 @@ impl Resolver for CliGraphResolver { let result = match result { Ok(resolution) => match resolution { MappedResolution::Normal(specifier) - | MappedResolution::ImportMap(specifier) => Ok(specifier), + | MappedResolution::ImportMap(specifier) => { + // do sloppy imports resolution if enabled + if let Some(sloppy_imports_resolver) = &self.sloppy_imports_resolver { + Ok(sloppy_imports_resolve( + sloppy_imports_resolver, + specifier, + referrer_range, + mode, + )) + } else { + Ok(specifier) + } + } MappedResolution::WorkspaceNpmPackage { target_pkg_json: pkg_json, sub_path, @@ -552,8 +573,6 @@ impl Resolver for CliGraphResolver { ) .map_err(ResolveError::Other) .map(|res| res.into_url()), - // todo(dsherret): for byonm it should do resolution solely based on - // the referrer and not the package.json MappedResolution::PackageJson { dep_result, alias, @@ -604,127 +623,75 @@ impl Resolver for CliGraphResolver { Err(err) => Err(err), }; - // check if it's an npm specifier that resolves to a workspace member - if let Some(node_resolver) = &self.node_resolver { + // When the user is vendoring, don't allow them to import directly from the vendor/ directory + // as it might cause them confusion or duplicate dependencies. Additionally, this folder has + // special treatment in the language server so it will definitely cause issues/confusion there + // if they do this. + if let Some(vendor_specifier) = &self.maybe_vendor_specifier { if let Ok(specifier) = &result { - if let Ok(req_ref) = NpmPackageReqReference::from_specifier(specifier) { + if specifier.as_str().starts_with(vendor_specifier.as_str()) { + return Err(ResolveError::Other(anyhow!("Importing from the vendor directory is not permitted. Use a remote specifier instead or disable vendoring."))); + } + } + } + + let Some(node_resolver) = &self.node_resolver else { + return result; + }; + + let is_byonm = self + .npm_resolver + .as_ref() + .is_some_and(|r| r.as_byonm().is_some()); + match result { + Ok(specifier) => { + if let Ok(npm_req_ref) = + NpmPackageReqReference::from_specifier(&specifier) + { + // check if the npm specifier resolves to a workspace member if let Some(pkg_folder) = self .workspace_resolver - .resolve_workspace_pkg_json_folder_for_npm_specifier(req_ref.req()) + .resolve_workspace_pkg_json_folder_for_npm_specifier( + npm_req_ref.req(), + ) { return Ok( node_resolver .resolve_package_sub_path_from_deno_module( pkg_folder, - req_ref.sub_path(), + npm_req_ref.sub_path(), Some(referrer), to_node_mode(mode), )? .into_url(), ); } - } - } - } - - // do sloppy imports resolution if enabled - let result = - if let Some(sloppy_imports_resolver) = &self.sloppy_imports_resolver { - result.map(|specifier| { - sloppy_imports_resolve( - sloppy_imports_resolver, - specifier, - referrer_range, - mode, - ) - }) - } else { - result - }; - - // When the user is vendoring, don't allow them to import directly from the vendor/ directory - // as it might cause them confusion or duplicate dependencies. Additionally, this folder has - // special treatment in the language server so it will definitely cause issues/confusion there - // if they do this. - if let Some(vendor_specifier) = &self.maybe_vendor_specifier { - if let Ok(specifier) = &result { - if specifier.as_str().starts_with(vendor_specifier.as_str()) { - return Err(ResolveError::Other(anyhow!("Importing from the vendor directory is not permitted. Use a remote specifier instead or disable vendoring."))); - } - } - } - if let Some(resolver) = - self.npm_resolver.as_ref().and_then(|r| r.as_byonm()) - { - match &result { - Ok(specifier) => { - if let Ok(npm_req_ref) = - NpmPackageReqReference::from_specifier(specifier) - { - let node_resolver = self.node_resolver.as_ref().unwrap(); + // do npm resolution for byonm + if is_byonm { return node_resolver .resolve_req_reference(&npm_req_ref, referrer, to_node_mode(mode)) .map(|res| res.into_url()) .map_err(|err| err.into()); } } - Err(_) => { - if referrer.scheme() == "file" { - if let Some(node_resolver) = &self.node_resolver { - let node_result = - node_resolver.resolve(specifier, referrer, to_node_mode(mode)); - match node_result { - Ok(Some(res)) => { - return Ok(res.into_url()); - } - Ok(None) => { - self - .check_surface_byonm_node_error( - specifier, - referrer, - anyhow!("Cannot find \"{}\"", specifier), - resolver, - ) - .map_err(ResolveError::Other)?; - } - Err(err) => { - self - .check_surface_byonm_node_error( - specifier, - referrer, - err.into(), - resolver, - ) - .map_err(ResolveError::Other)?; - } - } - } + + Ok(node_resolver.handle_if_in_node_modules(specifier)?) + } + Err(err) => { + // If byonm, check if the bare specifier resolves to an npm package + if is_byonm && referrer.scheme() == "file" { + let maybe_resolution = node_resolver + .resolve_if_for_npm_pkg(specifier, referrer, to_node_mode(mode)) + .map_err(ResolveError::Other)?; + if let Some(res) = maybe_resolution { + return Ok(res.into_url()); } } - } - } - if referrer.scheme() == "file" { - if let Some(node_resolver) = &self.node_resolver { - let node_result = node_resolver.resolve_if_in_npm_package( - specifier, - referrer, - to_node_mode(mode), - ); - if let Some(Ok(Some(res))) = node_result { - return Ok(res.into_url()); - } + Err(err) } } - - let specifier = result?; - match &self.node_resolver { - Some(node_resolver) => node_resolver - .handle_if_in_node_modules(specifier) - .map_err(|e| e.into()), - None => Ok(specifier), - } } } diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index 74586c1be01f5e..561c99c983a50b 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -151,15 +151,14 @@ impl ModuleLoader for EmbeddedModuleLoader { })? }; - if let Some(result) = self.shared.node_resolver.resolve_if_in_npm_package( - specifier, - &referrer, - NodeResolutionMode::Execution, - ) { - return match result? { - Some(res) => Ok(res.into_url()), - None => Err(generic_error("not found")), - }; + if self.shared.node_resolver.in_npm_package(&referrer) { + return Ok( + self + .shared + .node_resolver + .resolve(specifier, &referrer, NodeResolutionMode::Execution)? + .into_url(), + ); } let mapped_resolution = @@ -250,14 +249,12 @@ impl ModuleLoader for EmbeddedModuleLoader { Err(err) if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" => { - // todo(dsherret): return a better error from node resolution so that - // we can more easily tell whether to surface it or not - let node_result = self.shared.node_resolver.resolve( + let maybe_res = self.shared.node_resolver.resolve_if_for_npm_pkg( specifier, &referrer, NodeResolutionMode::Execution, - ); - if let Ok(Some(res)) = node_result { + )?; + if let Some(res) = maybe_res { return Ok(res.into_url()); } Err(err.into()) diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index f6440266e284b9..424b5c3d3141db 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -30,6 +30,8 @@ use deno_graph::GraphKind; use deno_graph::Module; use deno_graph::ModuleGraph; use deno_graph::ResolutionResolved; +use deno_runtime::deno_node::errors::NodeJsErrorCode; +use deno_runtime::deno_node::errors::NodeJsErrorCoded; use deno_runtime::deno_node::NodeModuleKind; use deno_runtime::deno_node::NodeResolution; use deno_runtime::deno_node::NodeResolutionMode; @@ -756,13 +758,21 @@ fn resolve_graph_specifier_types( .as_managed() .unwrap() // should never be byonm because it won't create Module::Npm .resolve_pkg_folder_from_deno_module(module.nv_reference.nv())?; - let maybe_resolution = + let res_result = npm.node_resolver.resolve_package_subpath_from_deno_module( &package_folder, module.nv_reference.sub_path(), Some(referrer), NodeResolutionMode::Types, - )?; + ); + let maybe_resolution = match res_result { + Ok(res) => Some(res), + Err(err) => match err.code() { + NodeJsErrorCode::ERR_TYPES_NOT_FOUND + | NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None, + _ => return Err(err.into()), + }, + }; Ok(Some(NodeResolution::into_specifier_and_media_type( maybe_resolution, ))) @@ -805,8 +815,7 @@ fn resolve_non_graph_specifier_types( referrer_kind, NodeResolutionMode::Types, ) - .ok() - .flatten(), + .ok(), ))) } else if let Ok(npm_req_ref) = NpmPackageReqReference::from_str(specifier) { debug_assert_eq!(referrer_kind, NodeModuleKind::Esm); @@ -817,13 +826,20 @@ fn resolve_non_graph_specifier_types( let package_folder = npm .npm_resolver .resolve_pkg_folder_from_deno_module_req(npm_req_ref.req(), referrer)?; - let maybe_resolution = node_resolver - .resolve_package_subpath_from_deno_module( - &package_folder, - npm_req_ref.sub_path(), - Some(referrer), - NodeResolutionMode::Types, - )?; + let res_result = node_resolver.resolve_package_subpath_from_deno_module( + &package_folder, + npm_req_ref.sub_path(), + Some(referrer), + NodeResolutionMode::Types, + ); + let maybe_resolution = match res_result { + Ok(res) => Some(res), + Err(err) => match err.code() { + NodeJsErrorCode::ERR_TYPES_NOT_FOUND + | NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None, + _ => return Err(err.into()), + }, + }; Ok(Some(NodeResolution::into_specifier_and_media_type( maybe_resolution, ))) diff --git a/cli/worker.rs b/cli/worker.rs index a639dae4107db2..0d7e61c50eb79e 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -687,7 +687,7 @@ impl CliMainWorkerFactory { return Ok(None); } - let Some(resolution) = self + let resolution = self .shared .node_resolver .resolve_package_subpath_from_deno_module( @@ -695,10 +695,7 @@ impl CliMainWorkerFactory { sub_path, /* referrer */ None, NodeResolutionMode::Execution, - )? - else { - return Ok(None); - }; + )?; match &resolution { NodeResolution::BuiltIn(_) => Ok(None), NodeResolution::CommonJs(specifier) | NodeResolution::Esm(specifier) => { diff --git a/ext/node/errors.rs b/ext/node/errors.rs index 11bb011f812570..64625d32f440b4 100644 --- a/ext/node/errors.rs +++ b/ext/node/errors.rs @@ -49,6 +49,8 @@ pub enum NodeJsErrorCode { ERR_UNKNOWN_FILE_EXTENSION, ERR_UNSUPPORTED_DIR_IMPORT, ERR_UNSUPPORTED_ESM_URL_SCHEME, + /// Deno specific since Node doesn't support TypeScript. + ERR_TYPES_NOT_FOUND, } impl std::fmt::Display for NodeJsErrorCode { @@ -70,6 +72,7 @@ impl 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_TYPES_NOT_FOUND => "ERR_TYPES_NOT_FOUND", } } } @@ -122,65 +125,98 @@ impl NodeJsErrorCoded for InvalidModuleSpecifierError { } } +kinded_err!(LegacyResolveError, LegacyResolveErrorKind); + #[derive(Debug, Error)] -pub enum LegacyMainResolveError { +pub enum LegacyResolveErrorKind { + #[error(transparent)] + TypesNotFound(#[from] TypesNotFoundError), #[error(transparent)] - PathToDeclarationUrl(PathToDeclarationUrlError), + ModuleNotFound(#[from] ModuleNotFoundError), } -impl NodeJsErrorCoded for LegacyMainResolveError { +impl NodeJsErrorCoded for LegacyResolveError { fn code(&self) -> NodeJsErrorCode { - match self { - Self::PathToDeclarationUrl(e) => e.code(), + match self.as_kind() { + LegacyResolveErrorKind::TypesNotFound(e) => e.code(), + LegacyResolveErrorKind::ModuleNotFound(e) => e.code(), } } } kinded_err!(PackageFolderResolveError, PackageFolderResolveErrorKind); +#[derive(Debug, Error)] +#[error( + "Could not find package '{}' from referrer '{}'{}.", + package_name, + referrer, + referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default() +)] +pub struct PackageNotFoundError { + pub package_name: String, + pub referrer: ModuleSpecifier, + /// Extra information about the referrer. + pub referrer_extra: Option, +} + +impl NodeJsErrorCoded for PackageNotFoundError { + fn code(&self) -> NodeJsErrorCode { + NodeJsErrorCode::ERR_MODULE_NOT_FOUND + } +} + +#[derive(Debug, Error)] +#[error( + "Could not find referrer npm package '{}'{}.", + referrer, + referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default() +)] +pub struct ReferrerNotFoundError { + pub referrer: ModuleSpecifier, + /// Extra information about the referrer. + pub referrer_extra: Option, +} + +impl NodeJsErrorCoded for ReferrerNotFoundError { + fn code(&self) -> NodeJsErrorCode { + NodeJsErrorCode::ERR_MODULE_NOT_FOUND + } +} + +#[derive(Debug, Error)] +#[error("Failed resolving '{package_name}' from referrer '{referrer}'.")] +pub struct PackageFolderResolveIoError { + pub package_name: String, + pub referrer: ModuleSpecifier, + #[source] + pub source: std::io::Error, +} + +impl NodeJsErrorCoded for PackageFolderResolveIoError { + fn code(&self) -> NodeJsErrorCode { + NodeJsErrorCode::ERR_MODULE_NOT_FOUND + } +} + impl NodeJsErrorCoded for PackageFolderResolveError { fn code(&self) -> NodeJsErrorCode { match self.as_kind() { - PackageFolderResolveErrorKind::NotFoundPackage { .. } - | PackageFolderResolveErrorKind::NotFoundReferrer { .. } - | PackageFolderResolveErrorKind::Io { .. } => { - NodeJsErrorCode::ERR_MODULE_NOT_FOUND - } + PackageFolderResolveErrorKind::PackageNotFound(e) => e.code(), + PackageFolderResolveErrorKind::ReferrerNotFound(e) => e.code(), + PackageFolderResolveErrorKind::Io(e) => e.code(), } } } #[derive(Debug, Error)] pub enum PackageFolderResolveErrorKind { - #[error( - "Could not find package '{}' from referrer '{}'{}.", - package_name, - referrer, - referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default() - )] - NotFoundPackage { - package_name: String, - referrer: ModuleSpecifier, - /// Extra information about the referrer. - referrer_extra: Option, - }, - #[error( - "Could not find referrer npm package '{}'{}.", - referrer, - referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default() - )] - NotFoundReferrer { - referrer: ModuleSpecifier, - /// Extra information about the referrer. - referrer_extra: Option, - }, - #[error("Failed resolving '{package_name}' from referrer '{referrer}'.")] - Io { - package_name: String, - referrer: ModuleSpecifier, - #[source] - source: std::io::Error, - }, + #[error(transparent)] + PackageNotFound(#[from] PackageNotFoundError), + #[error(transparent)] + ReferrerNotFound(#[from] ReferrerNotFoundError), + #[error(transparent)] + Io(#[from] PackageFolderResolveIoError), } kinded_err!(PackageSubpathResolveError, PackageSubpathResolveErrorKind); @@ -189,10 +225,8 @@ impl NodeJsErrorCoded for PackageSubpathResolveError { fn code(&self) -> NodeJsErrorCode { match self.as_kind() { PackageSubpathResolveErrorKind::PkgJsonLoad(e) => e.code(), - PackageSubpathResolveErrorKind::PackageFolderResolve(e) => e.code(), PackageSubpathResolveErrorKind::Exports(e) => e.code(), - PackageSubpathResolveErrorKind::LegacyMain(e) => e.code(), - PackageSubpathResolveErrorKind::LegacyExact(e) => e.code(), + PackageSubpathResolveErrorKind::LegacyResolve(e) => e.code(), } } } @@ -202,13 +236,9 @@ pub enum PackageSubpathResolveErrorKind { #[error(transparent)] PkgJsonLoad(#[from] PackageJsonLoadError), #[error(transparent)] - PackageFolderResolve(#[from] PackageFolderResolveError), - #[error(transparent)] Exports(PackageExportsResolveError), #[error(transparent)] - LegacyMain(LegacyMainResolveError), - #[error(transparent)] - LegacyExact(PathToDeclarationUrlError), + LegacyResolve(LegacyResolveError), } #[derive(Debug, Error)] @@ -254,7 +284,7 @@ impl NodeJsErrorCoded for PackageTargetResolveError { PackageTargetResolveErrorKind::InvalidPackageTarget(e) => e.code(), PackageTargetResolveErrorKind::InvalidModuleSpecifier(e) => e.code(), PackageTargetResolveErrorKind::PackageResolve(e) => e.code(), - PackageTargetResolveErrorKind::PathToDeclarationUrl(e) => e.code(), + PackageTargetResolveErrorKind::TypesNotFound(e) => e.code(), } } } @@ -270,7 +300,7 @@ pub enum PackageTargetResolveErrorKind { #[error(transparent)] PackageResolve(#[from] PackageResolveError), #[error(transparent)] - PathToDeclarationUrl(#[from] PathToDeclarationUrlError), + TypesNotFound(#[from] TypesNotFoundError), } kinded_err!(PackageExportsResolveError, PackageExportsResolveErrorKind); @@ -293,16 +323,23 @@ pub enum PackageExportsResolveErrorKind { } #[derive(Debug, Error)] -pub enum PathToDeclarationUrlError { - #[error(transparent)] - SubPath(#[from] PackageSubpathResolveError), +#[error( + "[{}] Could not find types for '{}'{}", + self.code(), + self.0.code_specifier, + self.0.maybe_referrer.as_ref().map(|r| format!(" imported from '{}'", r)).unwrap_or_default(), + )] +pub struct TypesNotFoundError(pub Box); + +#[derive(Debug)] +pub struct TypesNotFoundErrorData { + pub code_specifier: ModuleSpecifier, + pub maybe_referrer: Option, } -impl NodeJsErrorCoded for PathToDeclarationUrlError { +impl NodeJsErrorCoded for TypesNotFoundError { fn code(&self) -> NodeJsErrorCode { - match self { - PathToDeclarationUrlError::SubPath(e) => e.code(), - } + NodeJsErrorCode::ERR_TYPES_NOT_FOUND } } @@ -441,6 +478,7 @@ impl NodeJsErrorCoded for PackageResolveError { match self.as_kind() { PackageResolveErrorKind::ClosestPkgJson(e) => e.code(), PackageResolveErrorKind::InvalidModuleSpecifier(e) => e.code(), + PackageResolveErrorKind::PackageFolderResolve(e) => e.code(), PackageResolveErrorKind::ExportsResolve(e) => e.code(), PackageResolveErrorKind::SubpathResolve(e) => e.code(), } @@ -454,37 +492,49 @@ pub enum PackageResolveErrorKind { #[error(transparent)] InvalidModuleSpecifier(#[from] InvalidModuleSpecifierError), #[error(transparent)] + PackageFolderResolve(#[from] PackageFolderResolveError), + #[error(transparent)] ExportsResolve(#[from] PackageExportsResolveError), #[error(transparent)] SubpathResolve(#[from] PackageSubpathResolveError), } #[derive(Debug, Error)] -pub enum NodeResolveError { - #[error("Failed joining '{path}' from '{base}'.")] - RelativeJoinError { - path: String, - base: ModuleSpecifier, - #[source] - source: url::ParseError, - }, +#[error("Failed joining '{path}' from '{base}'.")] +pub struct NodeResolveRelativeJoinError { + pub path: String, + pub base: ModuleSpecifier, + #[source] + pub source: url::ParseError, +} + +#[derive(Debug, Error)] +#[error("Failed resolving specifier from data url referrer.")] +pub struct DataUrlReferrerError { + #[source] + pub source: url::ParseError, +} + +kinded_err!(NodeResolveError, NodeResolveErrorKind); + +#[derive(Debug, Error)] +pub enum NodeResolveErrorKind { + #[error(transparent)] + RelativeJoin(#[from] NodeResolveRelativeJoinError), #[error(transparent)] PackageImportsResolve(#[from] PackageImportsResolveError), #[error(transparent)] UnsupportedEsmUrlScheme(#[from] UnsupportedEsmUrlSchemeError), - #[error("Failed resolving specifier from data url referrer.")] - DataUrlReferrerFailed { - #[source] - source: url::ParseError, - }, + #[error(transparent)] + DataUrlReferrer(#[from] DataUrlReferrerError), #[error(transparent)] PackageResolve(#[from] PackageResolveError), #[error(transparent)] - PathToDeclarationUrl(#[from] PathToDeclarationUrlError), - #[error(transparent)] - UrlToNodeResolution(#[from] UrlToNodeResolutionError), + TypesNotFound(#[from] TypesNotFoundError), #[error(transparent)] FinalizeResolution(#[from] FinalizeResolutionError), + #[error(transparent)] + UrlToNodeResolution(#[from] UrlToNodeResolutionError), } kinded_err!(FinalizeResolutionError, FinalizeResolutionErrorKind); @@ -499,6 +549,16 @@ pub enum FinalizeResolutionErrorKind { UnsupportedDirImport(#[from] UnsupportedDirImportError), } +impl NodeJsErrorCoded for FinalizeResolutionError { + fn code(&self) -> NodeJsErrorCode { + match self.as_kind() { + FinalizeResolutionErrorKind::InvalidModuleSpecifierError(e) => e.code(), + FinalizeResolutionErrorKind::ModuleNotFound(e) => e.code(), + FinalizeResolutionErrorKind::UnsupportedDirImport(e) => e.code(), + } + } +} + #[derive(Debug, Error)] #[error( "[{}] Cannot find {} '{}'{}", @@ -513,9 +573,9 @@ pub struct ModuleNotFoundError { pub typ: &'static str, } -impl ModuleNotFoundError { - pub fn code(&self) -> &'static str { - "ERR_MODULE_NOT_FOUND" +impl NodeJsErrorCoded for ModuleNotFoundError { + fn code(&self) -> NodeJsErrorCode { + NodeJsErrorCode::ERR_MODULE_NOT_FOUND } } diff --git a/ext/node/lib.rs b/ext/node/lib.rs index 6f71851488c13a..21af5a094f5d74 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -46,7 +46,6 @@ pub use path::PathClean; pub use polyfill::is_builtin_node_module; pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES; pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX; -pub use resolution::parse_npm_pkg_name; pub use resolution::NodeModuleKind; pub use resolution::NodeResolution; pub use resolution::NodeResolutionMode; diff --git a/ext/node/resolution.rs b/ext/node/resolution.rs index 476b4f59c4f96d..6417835a28bd7e 100644 --- a/ext/node/resolution.rs +++ b/ext/node/resolution.rs @@ -18,14 +18,16 @@ use deno_package_json::PackageJsonRc; use crate::errors; use crate::errors::CanonicalizingPkgJsonDirError; use crate::errors::ClosestPkgJsonError; +use crate::errors::DataUrlReferrerError; use crate::errors::FinalizeResolutionError; use crate::errors::InvalidModuleSpecifierError; use crate::errors::InvalidPackageTargetError; -use crate::errors::LegacyMainResolveError; +use crate::errors::LegacyResolveError; use crate::errors::ModuleNotFoundError; use crate::errors::NodeJsErrorCode; use crate::errors::NodeJsErrorCoded; use crate::errors::NodeResolveError; +use crate::errors::NodeResolveRelativeJoinError; use crate::errors::PackageExportsResolveError; use crate::errors::PackageImportNotDefinedError; use crate::errors::PackageImportsResolveError; @@ -38,11 +40,12 @@ use crate::errors::PackageSubpathResolveErrorKind; use crate::errors::PackageTargetNotFoundError; use crate::errors::PackageTargetResolveError; use crate::errors::PackageTargetResolveErrorKind; -use crate::errors::PathToDeclarationUrlError; use crate::errors::ResolveBinaryCommandsError; use crate::errors::ResolvePkgJsonBinExportError; use crate::errors::ResolvePkgSubpathFromDenoModuleError; use crate::errors::TypeScriptNotSupportedInNpmError; +use crate::errors::TypesNotFoundError; +use crate::errors::TypesNotFoundErrorData; use crate::errors::UnsupportedDirImportError; use crate::errors::UnsupportedEsmUrlSchemeError; use crate::errors::UrlToNodeResolutionError; @@ -55,6 +58,7 @@ use crate::PathClean; pub static DEFAULT_CONDITIONS: &[&str] = &["deno", "node", "import"]; pub static REQUIRE_CONDITIONS: &[&str] = &["require", "node"]; +static TYPES_ONLY_CONDITIONS: &[&str] = &["types"]; pub type NodeModuleKind = deno_package_json::NodeModuleKind; @@ -177,23 +181,23 @@ impl NodeResolver { referrer: &ModuleSpecifier, referrer_kind: NodeModuleKind, mode: NodeResolutionMode, - ) -> Result, NodeResolveError> { + ) -> Result { // Note: if we are here, then the referrer is an esm module // TODO(bartlomieju): skipped "policy" part as we don't plan to support it if crate::is_builtin_node_module(specifier) { - return Ok(Some(NodeResolution::BuiltIn(specifier.to_string()))); + return Ok(NodeResolution::BuiltIn(specifier.to_string())); } if let Ok(url) = Url::parse(specifier) { if url.scheme() == "data" { - return Ok(Some(NodeResolution::Esm(url))); + return Ok(NodeResolution::Esm(url)); } if let Some(module_name) = get_module_name_from_builtin_node_module_specifier(&url) { - return Ok(Some(NodeResolution::BuiltIn(module_name.to_string()))); + return Ok(NodeResolution::BuiltIn(module_name.to_string())); } let protocol = url.scheme(); @@ -209,14 +213,14 @@ impl NodeResolver { // todo(dsherret): this seems wrong if referrer.scheme() == "data" { - let url = referrer.join(specifier).map_err(|source| { - NodeResolveError::DataUrlReferrerFailed { source } - })?; - return Ok(Some(NodeResolution::Esm(url))); + let url = referrer + .join(specifier) + .map_err(|source| DataUrlReferrerError { source })?; + return Ok(NodeResolution::Esm(url)); } } - let maybe_url = self.module_resolve( + let url = self.module_resolve( specifier, referrer, referrer_kind, @@ -226,15 +230,19 @@ impl NodeResolver { }, mode, )?; - let url = match maybe_url { - Some(url) => url, - None => return Ok(None), + + let url = if mode.is_types() { + let file_path = to_file_path(&url); + self.path_to_declaration_url(&file_path, Some(referrer), referrer_kind)? + } else { + url }; + let url = self.finalize_resolution(url, Some(referrer))?; let resolve_response = self.url_to_node_resolution(url)?; // TODO(bartlomieju): skipped checking errors for commonJS resolution and // "preserveSymlinksMain"/"preserveSymlinks" options. - Ok(Some(resolve_response)) + Ok(resolve_response) } fn module_resolve( @@ -244,12 +252,10 @@ impl NodeResolver { referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - ) -> Result, NodeResolveError> { - // note: if we're here, the referrer is an esm module - let maybe_url = if should_be_treated_as_relative_or_absolute_path(specifier) - { - Some(referrer.join(specifier).map_err(|err| { - NodeResolveError::RelativeJoinError { + ) -> Result { + if should_be_treated_as_relative_or_absolute_path(specifier) { + Ok(referrer.join(specifier).map_err(|err| { + NodeResolveRelativeJoinError { path: specifier.to_string(), base: referrer.clone(), source: err, @@ -260,7 +266,7 @@ impl NodeResolver { .get_closest_package_json(referrer) .map_err(PackageImportsResolveErrorKind::ClosestPkgJson) .map_err(|err| PackageImportsResolveError(Box::new(err)))?; - Some(self.package_imports_resolve( + Ok(self.package_imports_resolve( specifier, Some(referrer), referrer_kind, @@ -269,32 +275,16 @@ impl NodeResolver { mode, )?) } else if let Ok(resolved) = Url::parse(specifier) { - Some(resolved) + Ok(resolved) } else { - self.package_resolve( + Ok(self.package_resolve( specifier, referrer, referrer_kind, conditions, mode, - )? - }; - - let Some(url) = maybe_url else { - return Ok(None); - }; - - let maybe_url = if mode.is_types() { - let file_path = to_file_path(&url); - self.path_to_declaration_url(&file_path, Some(referrer), referrer_kind)? - } else { - Some(url) - }; - - Ok(match maybe_url { - Some(url) => Some(self.finalize_resolution(url, Some(referrer))?), - None => None, - }) + )?) + } } fn finalize_resolution( @@ -369,12 +359,12 @@ impl NodeResolver { package_subpath: Option<&str>, maybe_referrer: Option<&ModuleSpecifier>, mode: NodeResolutionMode, - ) -> Result, ResolvePkgSubpathFromDenoModuleError> { + ) -> Result { let node_module_kind = NodeModuleKind::Esm; let package_subpath = package_subpath .map(|s| format!("./{s}")) .unwrap_or_else(|| ".".to_string()); - let maybe_resolved_url = self.resolve_package_dir_subpath( + let resolved_url = self.resolve_package_dir_subpath( package_dir, &package_subpath, maybe_referrer, @@ -382,14 +372,10 @@ impl NodeResolver { DEFAULT_CONDITIONS, mode, )?; - let resolved_url = match maybe_resolved_url { - Some(resolved_url) => resolved_url, - None => return Ok(None), - }; let resolve_response = self.url_to_node_resolution(resolved_url)?; // TODO(bartlomieju): skipped checking errors for commonJS resolution and // "preserveSymlinksMain"/"preserveSymlinks" options. - Ok(Some(resolve_response)) + Ok(resolve_response) } pub fn resolve_binary_commands( @@ -475,7 +461,7 @@ impl NodeResolver { path: &Path, maybe_referrer: Option<&ModuleSpecifier>, referrer_kind: NodeModuleKind, - ) -> Result, PathToDeclarationUrlError> { + ) -> Result { fn probe_extensions( fs: &dyn deno_fs::FileSystem, path: &Path, @@ -525,15 +511,15 @@ impl NodeResolver { || lowercase_path.ends_with(".d.cts") || lowercase_path.ends_with(".d.mts") { - return Ok(Some(to_file_specifier(path))); + return Ok(to_file_specifier(path)); } if let Some(path) = probe_extensions(&*self.fs, path, &lowercase_path, referrer_kind) { - return Ok(Some(to_file_specifier(&path))); + return Ok(to_file_specifier(&path)); } if self.fs.is_dir_sync(path) { - let maybe_resolution = self.resolve_package_dir_subpath( + let resolution_result = self.resolve_package_dir_subpath( path, /* sub path */ ".", maybe_referrer, @@ -543,9 +529,9 @@ impl NodeResolver { NodeModuleKind::Cjs => REQUIRE_CONDITIONS, }, NodeResolutionMode::Types, - )?; - if let Some(resolution) = maybe_resolution { - return Ok(Some(resolution)); + ); + if let Ok(resolution) = resolution_result { + return Ok(resolution); } let index_path = path.join("index.js"); if let Some(path) = probe_extensions( @@ -554,14 +540,17 @@ impl NodeResolver { &index_path.to_string_lossy().to_lowercase(), referrer_kind, ) { - return Ok(Some(to_file_specifier(&path))); + return Ok(to_file_specifier(&path)); } } // allow resolving .css files for types resolution if lowercase_path.ends_with(".css") { - return Ok(Some(to_file_specifier(path))); + return Ok(to_file_specifier(path)); } - Ok(None) + Err(TypesNotFoundError(Box::new(TypesNotFoundErrorData { + code_specifier: to_file_specifier(path), + maybe_referrer: maybe_referrer.cloned(), + }))) } #[allow(clippy::too_many_arguments)] @@ -719,22 +708,32 @@ impl NodeResolver { conditions, mode, ) { - Ok(Some(url)) => Ok(url), - Ok(None) => Err( - PackageTargetResolveErrorKind::NotFound( - PackageTargetNotFoundError { - pkg_json_path: package_json_path.to_path_buf(), - target: export_target.to_string(), - maybe_referrer: maybe_referrer.map(ToOwned::to_owned), - referrer_kind, - mode, - }, - ) - .into(), - ), - Err(err) => { - Err(PackageTargetResolveErrorKind::PackageResolve(err).into()) - } + Ok(url) => Ok(url), + Err(err) => match err.code() { + NodeJsErrorCode::ERR_INVALID_MODULE_SPECIFIER + | NodeJsErrorCode::ERR_INVALID_PACKAGE_CONFIG + | NodeJsErrorCode::ERR_INVALID_PACKAGE_TARGET + | NodeJsErrorCode::ERR_PACKAGE_IMPORT_NOT_DEFINED + | NodeJsErrorCode::ERR_PACKAGE_PATH_NOT_EXPORTED + | NodeJsErrorCode::ERR_UNKNOWN_FILE_EXTENSION + | NodeJsErrorCode::ERR_UNSUPPORTED_DIR_IMPORT + | NodeJsErrorCode::ERR_UNSUPPORTED_ESM_URL_SCHEME + | NodeJsErrorCode::ERR_TYPES_NOT_FOUND => { + Err(PackageTargetResolveErrorKind::PackageResolve(err).into()) + } + NodeJsErrorCode::ERR_MODULE_NOT_FOUND => Err( + PackageTargetResolveErrorKind::NotFound( + PackageTargetNotFoundError { + pkg_json_path: package_json_path.to_path_buf(), + target: export_target.to_string(), + maybe_referrer: maybe_referrer.map(ToOwned::to_owned), + referrer_kind, + mode, + }, + ) + .into(), + ), + }, }; return match result { @@ -831,6 +830,62 @@ impl NodeResolver { internal: bool, conditions: &[&str], mode: NodeResolutionMode, + ) -> Result, PackageTargetResolveError> { + let result = self.resolve_package_target_inner( + package_json_path, + target, + subpath, + package_subpath, + maybe_referrer, + referrer_kind, + pattern, + internal, + conditions, + mode, + ); + match result { + Ok(maybe_resolved) => Ok(maybe_resolved), + Err(err) => { + if mode.is_types() + && err.code() == NodeJsErrorCode::ERR_TYPES_NOT_FOUND + && conditions != TYPES_ONLY_CONDITIONS + { + // try resolving with just "types" conditions for when someone misconfigures + // and puts the "types" condition in the wrong place + if let Ok(Some(resolved)) = self.resolve_package_target_inner( + package_json_path, + target, + subpath, + package_subpath, + maybe_referrer, + referrer_kind, + pattern, + internal, + TYPES_ONLY_CONDITIONS, + mode, + ) { + return Ok(Some(resolved)); + } + } + + Err(err) + } + } + } + + #[allow(clippy::too_many_arguments)] + fn resolve_package_target_inner( + &self, + package_json_path: &Path, + target: &Value, + subpath: &str, + package_subpath: &str, + maybe_referrer: Option<&ModuleSpecifier>, + referrer_kind: NodeModuleKind, + pattern: bool, + internal: bool, + conditions: &[&str], + mode: NodeResolutionMode, ) -> Result, PackageTargetResolveError> { if let Some(target) = target.as_str() { let url = self.resolve_package_target_string( @@ -847,11 +902,11 @@ impl NodeResolver { )?; if mode.is_types() && url.scheme() == "file" { let path = url.to_file_path().unwrap(); - return Ok(self.path_to_declaration_url( + return Ok(Some(self.path_to_declaration_url( &path, maybe_referrer, referrer_kind, - )?); + )?)); } else { return Ok(Some(url)); } @@ -1069,41 +1124,37 @@ impl NodeResolver { referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - ) -> Result, PackageResolveError> { + ) -> Result { let (package_name, package_subpath, _is_scoped) = parse_npm_pkg_name(specifier, referrer)?; - let Some(package_config) = self.get_closest_package_json(referrer)? else { - return Ok(None); - }; - // ResolveSelf - if package_config.name.as_ref() == Some(&package_name) { - if let Some(exports) = &package_config.exports { - return self - .package_exports_resolve( - &package_config.path, - &package_subpath, - exports, - Some(referrer), - referrer_kind, - conditions, - mode, - ) - .map(Some) - .map_err(|err| err.into()); + if let Some(package_config) = self.get_closest_package_json(referrer)? { + // ResolveSelf + if package_config.name.as_ref() == Some(&package_name) { + if let Some(exports) = &package_config.exports { + return self + .package_exports_resolve( + &package_config.path, + &package_subpath, + exports, + Some(referrer), + referrer_kind, + conditions, + mode, + ) + .map_err(|err| err.into()); + } } } - self - .resolve_package_subpath_for_package( - &package_name, - &package_subpath, - referrer, - referrer_kind, - conditions, - mode, - ) - .map_err(|err| err.into()) + self.resolve_package_subpath_for_package( + &package_name, + &package_subpath, + referrer, + referrer_kind, + conditions, + mode, + ) } #[allow(clippy::too_many_arguments)] @@ -1115,7 +1166,7 @@ impl NodeResolver { referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - ) -> Result, PackageSubpathResolveError> { + ) -> Result { let result = self.resolve_package_subpath_for_package_inner( package_name, package_subpath, @@ -1124,10 +1175,10 @@ impl NodeResolver { conditions, mode, ); - if mode.is_types() && !matches!(result, Ok(Some(_))) { + if mode.is_types() && !matches!(result, Ok(ModuleSpecifier { .. })) { // try to resolve with the @types package let package_name = types_package_name(package_name); - if let Ok(Some(result)) = self.resolve_package_subpath_for_package_inner( + if let Ok(result) = self.resolve_package_subpath_for_package_inner( &package_name, package_subpath, referrer, @@ -1135,7 +1186,7 @@ impl NodeResolver { conditions, mode, ) { - return Ok(Some(result)); + return Ok(result); } } result @@ -1150,7 +1201,7 @@ impl NodeResolver { referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - ) -> Result, PackageSubpathResolveError> { + ) -> Result { let package_dir_path = self .npm_resolver .resolve_package_folder_from_package(package_name, referrer)?; @@ -1169,14 +1220,16 @@ impl NodeResolver { // )) // Package match. - self.resolve_package_dir_subpath( - &package_dir_path, - package_subpath, - Some(referrer), - referrer_kind, - conditions, - mode, - ) + self + .resolve_package_dir_subpath( + &package_dir_path, + package_subpath, + Some(referrer), + referrer_kind, + conditions, + mode, + ) + .map_err(|err| err.into()) } #[allow(clippy::too_many_arguments)] @@ -1188,7 +1241,7 @@ impl NodeResolver { referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - ) -> Result, PackageSubpathResolveError> { + ) -> Result { let package_json_path = package_dir_path.join("package.json"); match self.load_package_json(&package_json_path)? { Some(pkg_json) => self.resolve_package_subpath( @@ -1207,7 +1260,9 @@ impl NodeResolver { referrer_kind, mode, ) - .map_err(|err| PackageSubpathResolveErrorKind::LegacyExact(err).into()), + .map_err(|err| { + PackageSubpathResolveErrorKind::LegacyResolve(err).into() + }), } } @@ -1220,7 +1275,7 @@ impl NodeResolver { referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - ) -> Result, PackageSubpathResolveError> { + ) -> Result { if let Some(exports) = &package_json.exports { let result = self.package_exports_resolve( &package_json.path, @@ -1232,13 +1287,13 @@ impl NodeResolver { mode, ); match result { - Ok(found) => return Ok(Some(found)), + Ok(found) => return Ok(found), Err(exports_err) => { if mode.is_types() && package_subpath == "." { return self .legacy_main_resolve(package_json, referrer, referrer_kind, mode) .map_err(|err| { - PackageSubpathResolveErrorKind::LegacyMain(err).into() + PackageSubpathResolveErrorKind::LegacyResolve(err).into() }); } return Err( @@ -1251,7 +1306,9 @@ impl NodeResolver { if package_subpath == "." { return self .legacy_main_resolve(package_json, referrer, referrer_kind, mode) - .map_err(|err| PackageSubpathResolveErrorKind::LegacyMain(err).into()); + .map_err(|err| { + PackageSubpathResolveErrorKind::LegacyResolve(err).into() + }); } self @@ -1262,7 +1319,9 @@ impl NodeResolver { referrer_kind, mode, ) - .map_err(|err| PackageSubpathResolveErrorKind::LegacyExact(err).into()) + .map_err(|err| { + PackageSubpathResolveErrorKind::LegacyResolve(err.into()).into() + }) } fn resolve_subpath_exact( @@ -1272,13 +1331,13 @@ impl NodeResolver { referrer: Option<&ModuleSpecifier>, referrer_kind: NodeModuleKind, mode: NodeResolutionMode, - ) -> Result, PathToDeclarationUrlError> { + ) -> Result { assert_ne!(package_subpath, "."); let file_path = directory.join(package_subpath); if mode.is_types() { Ok(self.path_to_declaration_url(&file_path, referrer, referrer_kind)?) } else { - Ok(Some(to_file_specifier(&file_path))) + Ok(to_file_specifier(&file_path)) } } @@ -1286,20 +1345,22 @@ impl NodeResolver { &self, directory: &Path, package_subpath: &str, - referrer: Option<&ModuleSpecifier>, + maybe_referrer: Option<&ModuleSpecifier>, referrer_kind: NodeModuleKind, mode: NodeResolutionMode, - ) -> Result, PathToDeclarationUrlError> { + ) -> Result { if package_subpath == "." { - Ok(self.legacy_index_resolve(directory, referrer_kind, mode)) + self.legacy_index_resolve(directory, maybe_referrer, referrer_kind, mode) } else { - self.resolve_subpath_exact( - directory, - package_subpath, - referrer, - referrer_kind, - mode, - ) + self + .resolve_subpath_exact( + directory, + package_subpath, + maybe_referrer, + referrer_kind, + mode, + ) + .map_err(|err| err.into()) } } @@ -1348,7 +1409,7 @@ impl NodeResolver { maybe_referrer: Option<&ModuleSpecifier>, referrer_kind: NodeModuleKind, mode: NodeResolutionMode, - ) -> Result, LegacyMainResolveError> { + ) -> Result { let maybe_main = if mode.is_types() { match package_json.types.as_ref() { Some(types) => Some(types.as_str()), @@ -1357,11 +1418,14 @@ impl NodeResolver { // a corresponding declaration file if let Some(main) = package_json.main(referrer_kind) { let main = package_json.path.parent().unwrap().join(main).clean(); - let maybe_decl_url = self - .path_to_declaration_url(&main, maybe_referrer, referrer_kind) - .map_err(LegacyMainResolveError::PathToDeclarationUrl)?; - if let Some(path) = maybe_decl_url { - return Ok(Some(path)); + let decl_url_result = self.path_to_declaration_url( + &main, + maybe_referrer, + referrer_kind, + ); + // don't surface errors, fallback to checking the index now + if let Ok(url) = decl_url_result { + return Ok(url); } } None @@ -1374,7 +1438,7 @@ impl NodeResolver { if let Some(main) = maybe_main { let guess = package_json.path.parent().unwrap().join(main).clean(); if self.fs.is_file_sync(&guess) { - return Ok(Some(to_file_specifier(&guess))); + return Ok(to_file_specifier(&guess)); } // todo(dsherret): investigate exactly how node and typescript handles this @@ -1404,24 +1468,26 @@ impl NodeResolver { .clean(); if self.fs.is_file_sync(&guess) { // TODO(bartlomieju): emitLegacyIndexDeprecation() - return Ok(Some(to_file_specifier(&guess))); + return Ok(to_file_specifier(&guess)); } } } - Ok(self.legacy_index_resolve( + self.legacy_index_resolve( package_json.path.parent().unwrap(), + maybe_referrer, referrer_kind, mode, - )) + ) } fn legacy_index_resolve( &self, directory: &Path, + maybe_referrer: Option<&ModuleSpecifier>, referrer_kind: NodeModuleKind, mode: NodeResolutionMode, - ) -> Option { + ) -> Result { let index_file_names = if mode.is_types() { // todo(dsherret): investigate exactly how typescript does this match referrer_kind { @@ -1435,11 +1501,28 @@ impl NodeResolver { let guess = directory.join(index_file_name).clean(); if self.fs.is_file_sync(&guess) { // TODO(bartlomieju): emitLegacyIndexDeprecation() - return Some(to_file_specifier(&guess)); + return Ok(to_file_specifier(&guess)); } } - None + if mode.is_types() { + Err( + TypesNotFoundError(Box::new(TypesNotFoundErrorData { + code_specifier: to_file_specifier(&directory.join("index.js")), + maybe_referrer: maybe_referrer.cloned(), + })) + .into(), + ) + } else { + Err( + ModuleNotFoundError { + specifier: to_file_specifier(&directory.join("index.js")), + typ: "module", + maybe_referrer: maybe_referrer.cloned(), + } + .into(), + ) + } } } @@ -1557,7 +1640,7 @@ fn should_be_treated_as_relative_or_absolute_path(specifier: &str) -> bool { // TODO(ry) We very likely have this utility function elsewhere in Deno. fn is_relative_specifier(specifier: &str) -> bool { let specifier_len = specifier.len(); - let specifier_chars: Vec<_> = specifier.chars().collect(); + let specifier_chars: Vec<_> = specifier.chars().take(3).collect(); if !specifier_chars.is_empty() && specifier_chars[0] == '.' { if specifier_len == 1 || specifier_chars[1] == '/' { diff --git a/tests/integration/npm_tests.rs b/tests/integration/npm_tests.rs index dba51908707fb0..e721633a630a4b 100644 --- a/tests/integration/npm_tests.rs +++ b/tests/integration/npm_tests.rs @@ -15,13 +15,6 @@ use util::TestContextBuilder; // NOTE: See how to make test npm packages at ./testdata/npm/README.md -itest!(esm_import_cjs_default { - args: "run --allow-read --allow-env --quiet --check=all npm/esm_import_cjs_default/main.ts", - output: "npm/esm_import_cjs_default/main.out", - envs: env_vars_for_npm_tests(), - http_server: true, -}); - itest!(cjs_with_deps { args: "run --allow-read --allow-env npm/cjs_with_deps/main.js", output: "npm/cjs_with_deps/main.out", @@ -324,14 +317,6 @@ itest!(check_local { exit_code: 1, }); -itest!(types_general { - args: "check --quiet npm/types/main.ts", - output: "npm/types/main.out", - envs: env_vars_for_npm_tests(), - http_server: true, - exit_code: 1, -}); - itest!(types_ambient_module { args: "check --quiet npm/types_ambient_module/main.ts", output: "npm/types_ambient_module/main.out", @@ -341,27 +326,11 @@ itest!(types_ambient_module { }); itest!(types_ambient_module_import_map { - args: "check --quiet --import-map=npm/types_ambient_module/import_map.json npm/types_ambient_module/main_import_map.ts", - output: "npm/types_ambient_module/main_import_map.out", - envs: env_vars_for_npm_tests(), - http_server: true, - exit_code: 1, - }); - -itest!(no_types_cjs { - args: "check --quiet npm/no_types_cjs/main.ts", - output_str: Some(""), - exit_code: 0, - envs: env_vars_for_npm_tests(), - http_server: true, -}); - -itest!(no_types_in_conditional_exports { - args: "run --check npm/no_types_in_conditional_exports/main.ts", - output: "npm/no_types_in_conditional_exports/main.out", - exit_code: 0, + args: "check --quiet --import-map=npm/types_ambient_module/import_map.json npm/types_ambient_module/main_import_map.ts", + output: "npm/types_ambient_module/main_import_map.out", envs: env_vars_for_npm_tests(), http_server: true, + exit_code: 1, }); itest!(types_entry_value_not_exists { diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/__test__.jsonc b/tests/specs/node/byonm_phantom_dep_res_failure/__test__.jsonc new file mode 100644 index 00000000000000..35e0a7686d688b --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/__test__.jsonc @@ -0,0 +1,13 @@ +{ + "tests": { + "bad_import": { + "args": "run bad_import.ts", + "output": "bad_import.out", + "exitCode": 1 + }, + "good_import": { + "args": "run good_import.ts", + "output": "good_import.out" + } + } +} diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/bad_import.out b/tests/specs/node/byonm_phantom_dep_res_failure/bad_import.out new file mode 100644 index 00000000000000..a524720e37239d --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/bad_import.out @@ -0,0 +1,2 @@ +error: [ERR_MODULE_NOT_FOUND] Cannot find module 'file:///[WILDLINE]/node_modules/package/index.js' imported from 'file:///[WILDLINE]/bad_import.ts' + at file:///[WILDLINE]/bad_import.ts:1:16 diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/bad_import.ts b/tests/specs/node/byonm_phantom_dep_res_failure/bad_import.ts new file mode 100644 index 00000000000000..e20fe1fcf129c0 --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/bad_import.ts @@ -0,0 +1,3 @@ +import hi from "package"; + +hi(); diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/deno.json b/tests/specs/node/byonm_phantom_dep_res_failure/deno.json new file mode 100644 index 00000000000000..6134d86d1c1156 --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/deno.json @@ -0,0 +1,3 @@ +{ + "unstable": ["byonm"] +} diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/good_import.out b/tests/specs/node/byonm_phantom_dep_res_failure/good_import.out new file mode 100644 index 00000000000000..45b983be36b73c --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/good_import.out @@ -0,0 +1 @@ +hi diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/good_import.ts b/tests/specs/node/byonm_phantom_dep_res_failure/good_import.ts new file mode 100644 index 00000000000000..2b17d3e3310681 --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/good_import.ts @@ -0,0 +1,3 @@ +import hi from "package/main.js"; + +hi(); diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/node_modules/package/main.js b/tests/specs/node/byonm_phantom_dep_res_failure/node_modules/package/main.js new file mode 100644 index 00000000000000..bc76b8e9ea536a --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/node_modules/package/main.js @@ -0,0 +1 @@ +module.exports = () => console.log('hi'); \ No newline at end of file diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/node_modules/package/package.json b/tests/specs/node/byonm_phantom_dep_res_failure/node_modules/package/package.json new file mode 100644 index 00000000000000..5723987e9f4279 --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/node_modules/package/package.json @@ -0,0 +1,4 @@ +{ + "name": "package", + "version": "1.0.0" +} \ No newline at end of file diff --git a/tests/specs/node/byonm_phantom_dep_res_failure/package.json b/tests/specs/node/byonm_phantom_dep_res_failure/package.json new file mode 100644 index 00000000000000..2c63c0851048d8 --- /dev/null +++ b/tests/specs/node/byonm_phantom_dep_res_failure/package.json @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/specs/npm/esm_import_cjs_default/__test__.jsonc b/tests/specs/npm/esm_import_cjs_default/__test__.jsonc new file mode 100644 index 00000000000000..b2a25914f8d52a --- /dev/null +++ b/tests/specs/npm/esm_import_cjs_default/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "run --allow-read --allow-env --check=all main.ts", + "output": "main.out" +} diff --git a/tests/testdata/npm/esm_import_cjs_default/main.out b/tests/specs/npm/esm_import_cjs_default/main.out similarity index 78% rename from tests/testdata/npm/esm_import_cjs_default/main.out rename to tests/specs/npm/esm_import_cjs_default/main.out index 0f6a61e349367c..ec7962e5a30652 100644 --- a/tests/testdata/npm/esm_import_cjs_default/main.out +++ b/tests/specs/npm/esm_import_cjs_default/main.out @@ -1,3 +1,10 @@ +[UNORDERED_START] +Download http://localhost:4260/@denotest/esm-import-cjs-default +Download http://localhost:4260/@denotest/cjs-default-export +Download http://localhost:4260/@denotest/cjs-default-export/1.0.0.tgz +Download http://localhost:4260/@denotest/esm-import-cjs-default/1.0.0.tgz +[UNORDERED_END] +Check file:///[WILDLINE]/main.ts Node esm importing node cjs =========================== { diff --git a/tests/testdata/npm/esm_import_cjs_default/main.ts b/tests/specs/npm/esm_import_cjs_default/main.ts similarity index 100% rename from tests/testdata/npm/esm_import_cjs_default/main.ts rename to tests/specs/npm/esm_import_cjs_default/main.ts diff --git a/tests/specs/npm/no_types_cjs/__test__.jsonc b/tests/specs/npm/no_types_cjs/__test__.jsonc new file mode 100644 index 00000000000000..de0339cfb4e739 --- /dev/null +++ b/tests/specs/npm/no_types_cjs/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "check main.ts", + "output": "main.out" +} diff --git a/tests/specs/npm/no_types_cjs/main.out b/tests/specs/npm/no_types_cjs/main.out new file mode 100644 index 00000000000000..4747a9a325c812 --- /dev/null +++ b/tests/specs/npm/no_types_cjs/main.out @@ -0,0 +1,3 @@ +Download http://localhost:4260/@denotest/no-types-cjs +Download http://localhost:4260/@denotest/no-types-cjs/1.0.0.tgz +Check file:///[WILDLINE]/no_types_cjs/main.ts diff --git a/tests/testdata/npm/no_types_cjs/main.ts b/tests/specs/npm/no_types_cjs/main.ts similarity index 100% rename from tests/testdata/npm/no_types_cjs/main.ts rename to tests/specs/npm/no_types_cjs/main.ts diff --git a/tests/specs/npm/no_types_in_conditional_exports/__test__.jsonc b/tests/specs/npm/no_types_in_conditional_exports/__test__.jsonc new file mode 100644 index 00000000000000..8955fcda2e5be0 --- /dev/null +++ b/tests/specs/npm/no_types_in_conditional_exports/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "run --check main.ts", + "output": "main.out" +} diff --git a/tests/testdata/npm/no_types_in_conditional_exports/main.out b/tests/specs/npm/no_types_in_conditional_exports/main.out similarity index 100% rename from tests/testdata/npm/no_types_in_conditional_exports/main.out rename to tests/specs/npm/no_types_in_conditional_exports/main.out diff --git a/tests/testdata/npm/no_types_in_conditional_exports/main.ts b/tests/specs/npm/no_types_in_conditional_exports/main.ts similarity index 100% rename from tests/testdata/npm/no_types_in_conditional_exports/main.ts rename to tests/specs/npm/no_types_in_conditional_exports/main.ts diff --git a/tests/specs/npm/types_general/__test__.jsonc b/tests/specs/npm/types_general/__test__.jsonc new file mode 100644 index 00000000000000..a991c6eed4f620 --- /dev/null +++ b/tests/specs/npm/types_general/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check main.ts", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/testdata/npm/types/main.out b/tests/specs/npm/types_general/main.out similarity index 70% rename from tests/testdata/npm/types/main.out rename to tests/specs/npm/types_general/main.out index de1f2c1455e2c2..ffba4f84dbf506 100644 --- a/tests/testdata/npm/types/main.out +++ b/tests/specs/npm/types_general/main.out @@ -1,7 +1,16 @@ +[UNORDERED_START] +Download http://localhost:4260/@denotest/types +Download http://localhost:4260/@denotest/types_imported +Download http://localhost:4260/@denotest/types-exports-subpaths +Download http://localhost:4260/@denotest/types_imported/1.0.0.tgz +Download http://localhost:4260/@denotest/types-exports-subpaths/1.0.0.tgz +Download http://localhost:4260/@denotest/types/1.0.0.tgz +[UNORDERED_END] +Check file:///[WILDLINE]/main.ts error: TS2322 [ERROR]: Type 'number' is not assignable to type 'string'. bar: 1, ~~~ - at [WILDCARD]/npm/types/main.ts:[WILDCARD] + at [WILDCARD]/main.ts:[WILDCARD] The expected type comes from property 'bar' which is declared here on type 'Foobar' bar: string; @@ -11,7 +20,7 @@ error: TS2322 [ERROR]: Type 'number' is not assignable to type 'string'. TS2322 [ERROR]: Type 'number' is not assignable to type 'string'. prop: 1, ~~~~ - at [WILDCARD]/npm/types/main.ts:[WILDCARD] + at [WILDCARD]/main.ts:[WILDCARD] The expected type comes from property 'prop' which is declared here on type 'SomeInterface' prop: string; @@ -21,7 +30,7 @@ TS2322 [ERROR]: Type 'number' is not assignable to type 'string'. TS2322 [ERROR]: Type 'string' is not assignable to type 'number'. prop2: "asdf", ~~~~~ - at [WILDCARD]/npm/types/main.ts:[WILDCARD] + at [WILDCARD]/main.ts:[WILDCARD] The expected type comes from property 'prop2' which is declared here on type 'SomeInterface' prop2: number; @@ -31,7 +40,7 @@ TS2322 [ERROR]: Type 'string' is not assignable to type 'number'. TS2322 [ERROR]: Type 'number' is not assignable to type 'string'. fizz: 1, ~~~~ - at [WILDCARD]/npm/types/main.ts:[WILDCARD] + at [WILDCARD]/main.ts:[WILDCARD] The expected type comes from property 'fizz' which is declared here on type 'Fizzbuzz' fizz: string; @@ -41,7 +50,7 @@ TS2322 [ERROR]: Type 'number' is not assignable to type 'string'. TS2322 [ERROR]: Type 'number' is not assignable to type 'string'. buzz: 2, ~~~~ - at [WILDCARD]/npm/types/main.ts:[WILDCARD] + at [WILDCARD]/main.ts:[WILDCARD] The expected type comes from property 'buzz' which is declared here on type 'Fizzbuzz' buzz: string; @@ -51,21 +60,21 @@ TS2322 [ERROR]: Type 'number' is not assignable to type 'string'. TS2322 [ERROR]: Type '5' is not assignable to type '"test1"'. const valueA: "test1" = getClient(); ~~~~~~ - at [WILDCARD]/npm/types/main.ts:[WILDCARD] + at [WILDCARD]/main.ts:[WILDCARD] TS2322 [ERROR]: Type '"import"' is not assignable to type '"test2"'. const valueB: "test2" = entryImport(); ~~~~~~ - at [WILDCARD]/types/main.ts:[WILDCARD] + at [WILDCARD]/main.ts:[WILDCARD] TS2322 [ERROR]: Type '12' is not assignable to type '"test3"'. const valueC: "test3" = entryA(); ~~~~~~ - at [WILDCARD]/types/main.ts:[WILDCARD] + at [WILDCARD]/main.ts:[WILDCARD] TS2322 [ERROR]: Type '"types"' is not assignable to type '"test4"'. const valueD: "test4" = entryTypes(); ~~~~~~ - at file:///[WILDCARD]/types/main.ts:[WILDCARD] + at file:///[WILDCARD]/main.ts:[WILDCARD] Found 9 errors. diff --git a/tests/testdata/npm/types/main.ts b/tests/specs/npm/types_general/main.ts similarity index 100% rename from tests/testdata/npm/types/main.ts rename to tests/specs/npm/types_general/main.ts diff --git a/tools/lint.js b/tools/lint.js index aeab48c1a48290..dad963160b70ef 100755 --- a/tools/lint.js +++ b/tools/lint.js @@ -218,7 +218,7 @@ async function ensureNoNewITests() { "lsp_tests.rs": 0, "node_compat_tests.rs": 4, "node_unit_tests.rs": 2, - "npm_tests.rs": 97, + "npm_tests.rs": 93, "pm_tests.rs": 0, "publish_tests.rs": 0, "repl_tests.rs": 0,