fix(check): npm resolution errors to tsc diagnostics (#28174)

Closes https://github.com/denoland/deno/issues/27188
This commit is contained in:
David Sherret 2025-02-18 16:44:49 -05:00 committed by GitHub
parent 3747d2759a
commit f62fc9e81f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 196 additions and 69 deletions

View file

@ -40,6 +40,7 @@ use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::package::PackageNv;
use deno_semver::SmallStackString;
use sys_traits::FsMetadata;
use crate::args::config_to_deno_graph_workspace_member;
use crate::args::deno_json::TsConfigResolver;
@ -151,6 +152,25 @@ pub fn graph_walk_errors<'a>(
roots: &'a [ModuleSpecifier],
options: GraphWalkErrorsOptions<'a>,
) -> impl Iterator<Item = JsErrorBox> + 'a {
fn should_ignore_error(
sys: &CliSys,
graph_kind: GraphKind,
error: &ModuleGraphError,
) -> bool {
if graph_kind == GraphKind::TypesOnly
&& matches!(
error,
ModuleGraphError::ModuleError(ModuleError::UnsupportedMediaType(..))
)
{
return true;
}
// surface these as typescript diagnostics instead
graph_kind.include_types()
&& has_module_graph_error_for_tsc_diagnostic(sys, error)
}
graph
.walk(
roots.iter(),
@ -163,6 +183,11 @@ pub fn graph_walk_errors<'a>(
)
.errors()
.flat_map(|error| {
if should_ignore_error(sys, graph.graph_kind(), &error) {
log::debug!("Ignoring: {}", error);
return None;
}
let is_root = match &error {
ModuleGraphError::ResolutionError(_)
| ModuleGraphError::TypesResolutionError(_) => false,
@ -180,32 +205,94 @@ pub fn graph_walk_errors<'a>(
},
);
if graph.graph_kind() == GraphKind::TypesOnly
&& matches!(
error,
ModuleGraphError::ModuleError(ModuleError::UnsupportedMediaType(..))
)
{
log::debug!("Ignoring: {}", message);
return None;
}
if graph.graph_kind().include_types()
&& (message.contains(RUN_WITH_SLOPPY_IMPORTS_MSG)
|| matches!(
error,
ModuleGraphError::ModuleError(ModuleError::Missing(..))
))
{
// ignore and let typescript surface this as a diagnostic instead
log::debug!("Ignoring: {}", message);
return None;
}
Some(JsErrorBox::new(error.get_class(), message))
})
}
fn has_module_graph_error_for_tsc_diagnostic(
sys: &CliSys,
error: &ModuleGraphError,
) -> bool {
match error {
ModuleGraphError::ModuleError(error) => {
module_error_for_tsc_diagnostic(sys, error).is_some()
}
ModuleGraphError::ResolutionError(error) => {
resolution_error_for_tsc_diagnostic(error).is_some()
}
ModuleGraphError::TypesResolutionError(error) => {
resolution_error_for_tsc_diagnostic(error).is_some()
}
}
}
pub struct ModuleNotFoundGraphErrorRef<'a> {
pub specifier: &'a ModuleSpecifier,
pub maybe_range: Option<&'a deno_graph::Range>,
}
pub fn module_error_for_tsc_diagnostic<'a>(
sys: &CliSys,
error: &'a ModuleError,
) -> Option<ModuleNotFoundGraphErrorRef<'a>> {
match error {
ModuleError::Missing(specifier, maybe_range) => {
Some(ModuleNotFoundGraphErrorRef {
specifier,
maybe_range: maybe_range.as_ref(),
})
}
ModuleError::LoadingErr(
specifier,
maybe_range,
ModuleLoadError::Loader(_),
) => {
if let Ok(path) = deno_path_util::url_to_file_path(specifier) {
if sys.fs_is_dir_no_err(path) {
return Some(ModuleNotFoundGraphErrorRef {
specifier,
maybe_range: maybe_range.as_ref(),
});
}
}
None
}
_ => None,
}
}
pub struct ModuleNotFoundNodeResolutionErrorRef<'a> {
pub specifier: &'a str,
pub maybe_range: Option<&'a deno_graph::Range>,
}
pub fn resolution_error_for_tsc_diagnostic(
error: &ResolutionError,
) -> Option<ModuleNotFoundNodeResolutionErrorRef> {
match error {
ResolutionError::ResolverError {
error,
specifier,
range,
} => match error.as_ref() {
ResolveError::Other(error) => {
// would be nice if there were an easier way of doing this
let text = error.to_string();
if text.contains("[ERR_MODULE_NOT_FOUND]") {
Some(ModuleNotFoundNodeResolutionErrorRef {
specifier,
maybe_range: Some(range),
})
} else {
None
}
}
_ => None,
},
_ => None,
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum EnhanceGraphErrorMode {
ShowRange,