diff options
Diffstat (limited to 'cli')
| -rw-r--r-- | cli/Cargo.toml | 2 | ||||
| -rw-r--r-- | cli/graph_util.rs | 9 | ||||
| -rw-r--r-- | cli/lsp/diagnostics.rs | 3 | ||||
| -rw-r--r-- | cli/lsp/documents.rs | 72 | ||||
| -rw-r--r-- | cli/resolver.rs | 205 | ||||
| -rw-r--r-- | cli/tools/registry/unfurl.rs | 2 |
6 files changed, 203 insertions, 90 deletions
diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0d71eae1e..18bafb77e 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -68,7 +68,7 @@ deno_config = "=0.12.0" deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_doc = { version = "=0.113.1", features = ["html"] } deno_emit = "=0.38.2" -deno_graph = { version = "=0.69.4", features = ["tokio_executor"] } +deno_graph = { version = "=0.69.5", features = ["tokio_executor"] } deno_lint = { version = "=0.57.1", features = ["docs"] } deno_lockfile.workspace = true deno_npm = "=0.17.0" diff --git a/cli/graph_util.rs b/cli/graph_util.rs index facff0af5..0ed591fb7 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -30,6 +30,7 @@ use deno_core::parking_lot::Mutex; use deno_core::parking_lot::RwLock; use deno_core::ModuleSpecifier; use deno_graph::source::Loader; +use deno_graph::source::ResolutionMode; use deno_graph::source::ResolveError; use deno_graph::GraphKind; use deno_graph::Module; @@ -694,8 +695,12 @@ pub fn enhanced_module_error_message( ) -> String { let additional_message = match error { ModuleError::Missing(specifier, _) => { - SloppyImportsResolver::resolve_with_fs(fs, specifier) - .as_suggestion_message() + SloppyImportsResolver::resolve_with_fs( + fs, + specifier, + ResolutionMode::Execution, + ) + .as_suggestion_message() } _ => None, }; diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index e3e206a52..25cfd94e2 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -35,6 +35,7 @@ use deno_core::unsync::spawn; use deno_core::unsync::spawn_blocking; use deno_core::unsync::JoinHandle; use deno_core::ModuleSpecifier; +use deno_graph::source::ResolutionMode; use deno_graph::Resolution; use deno_graph::ResolutionError; use deno_graph::SpecifierError; @@ -1240,7 +1241,7 @@ impl DenoDiagnostic { Self::NoCacheJsr(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing jsr package: {}", pkg_req), Some(json!({ "specifier": specifier }))), Self::NoCacheNpm(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing npm package: {}", pkg_req), Some(json!({ "specifier": specifier }))), Self::NoLocal(specifier) => { - let sloppy_resolution = SloppyImportsResolver::resolve_with_fs(&deno_fs::RealFs, specifier); + let sloppy_resolution = SloppyImportsResolver::resolve_with_fs(&deno_fs::RealFs, specifier, ResolutionMode::Execution); let data = sloppy_resolution.as_lsp_quick_fix_message().map(|message| { json!({ "specifier": specifier, diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index 66ebe5115..419d08d50 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -1101,24 +1101,28 @@ impl Documents { &self, specifier: &'a ModuleSpecifier, ) -> SloppyImportsResolution<'a> { - SloppyImportsResolver::resolve_with_stat_sync(specifier, |path| { - if let Ok(specifier) = ModuleSpecifier::from_file_path(path) { - if self.open_docs.contains_key(&specifier) - || self.cache.contains(&specifier) - { - return Some(SloppyImportsFsEntry::File); - } - } - path.metadata().ok().and_then(|m| { - if m.is_file() { - Some(SloppyImportsFsEntry::File) - } else if m.is_dir() { - Some(SloppyImportsFsEntry::Dir) - } else { - None + SloppyImportsResolver::resolve_with_stat_sync( + specifier, + ResolutionMode::Types, + |path| { + if let Ok(specifier) = ModuleSpecifier::from_file_path(path) { + if self.open_docs.contains_key(&specifier) + || self.cache.contains(&specifier) + { + return Some(SloppyImportsFsEntry::File); + } } - }) - }) + path.metadata().ok().and_then(|m| { + if m.is_file() { + Some(SloppyImportsFsEntry::File) + } else if m.is_dir() { + Some(SloppyImportsFsEntry::Dir) + } else { + None + } + }) + }, + ) } /// Return `true` if the specifier can be resolved to a document. @@ -1800,22 +1804,26 @@ impl<'a> OpenDocumentsGraphLoader<'a> { &self, specifier: &'b ModuleSpecifier, ) -> SloppyImportsResolution<'b> { - SloppyImportsResolver::resolve_with_stat_sync(specifier, |path| { - if let Ok(specifier) = ModuleSpecifier::from_file_path(path) { - if self.open_docs.contains_key(&specifier) { - return Some(SloppyImportsFsEntry::File); - } - } - path.metadata().ok().and_then(|m| { - if m.is_file() { - Some(SloppyImportsFsEntry::File) - } else if m.is_dir() { - Some(SloppyImportsFsEntry::Dir) - } else { - None + SloppyImportsResolver::resolve_with_stat_sync( + specifier, + ResolutionMode::Types, + |path| { + if let Ok(specifier) = ModuleSpecifier::from_file_path(path) { + if self.open_docs.contains_key(&specifier) { + return Some(SloppyImportsFsEntry::File); + } } - }) - }) + path.metadata().ok().and_then(|m| { + if m.is_file() { + Some(SloppyImportsFsEntry::File) + } else if m.is_dir() { + Some(SloppyImportsFsEntry::Dir) + } else { + None + } + }) + }, + ) } } diff --git a/cli/resolver.rs b/cli/resolver.rs index 5bb9e66d0..de85992a7 100644 --- a/cli/resolver.rs +++ b/cli/resolver.rs @@ -522,6 +522,7 @@ impl Resolver for CliGraphResolver { sloppy_imports_resolver, specifier, referrer_range, + mode, ) }) } else { @@ -646,12 +647,22 @@ fn sloppy_imports_resolve( resolver: &SloppyImportsResolver, specifier: ModuleSpecifier, referrer_range: &deno_graph::Range, + mode: ResolutionMode, ) -> ModuleSpecifier { - let resolution = resolver.resolve(&specifier); + let resolution = resolver.resolve(&specifier, mode); + if mode.is_types() { + // don't bother warning for types resolution because + // we already probably warned during execution resolution + match resolution { + SloppyImportsResolution::None(_) => return specifier, // avoid a clone + _ => return resolution.into_specifier().into_owned(), + } + } + let hint_message = match &resolution { SloppyImportsResolution::JsToTs(to_specifier) => { - let from_media_type = MediaType::from_specifier(&specifier); let to_media_type = MediaType::from_specifier(to_specifier); + let from_media_type = MediaType::from_specifier(&specifier); format!( "update {} extension to {}", from_media_type.as_ts_extension(), @@ -677,7 +688,7 @@ fn sloppy_imports_resolve( log::warn!( "{} Sloppy module resolution {}\n at {}", crate::colors::yellow("Warning"), - crate::colors::gray(format!("(hint: {})", hint_message)), + crate::colors::gray(format!("(hint: {})", hint_message)).to_string(), if referrer_range.end == deno_graph::Position::zeroed() { // not worth showing the range in this case crate::colors::cyan(referrer_range.specifier.as_str()).to_string() @@ -928,8 +939,9 @@ impl SloppyImportsResolver { pub fn resolve_with_fs<'a>( fs: &dyn FileSystem, specifier: &'a ModuleSpecifier, + mode: ResolutionMode, ) -> SloppyImportsResolution<'a> { - Self::resolve_with_stat_sync(specifier, |path| { + Self::resolve_with_stat_sync(specifier, mode, |path| { fs.stat_sync(path) .ok() .and_then(|stat| SloppyImportsFsEntry::from_fs_stat(&stat)) @@ -938,8 +950,38 @@ impl SloppyImportsResolver { pub fn resolve_with_stat_sync( specifier: &ModuleSpecifier, + mode: ResolutionMode, stat_sync: impl Fn(&Path) -> Option<SloppyImportsFsEntry>, ) -> SloppyImportsResolution { + fn path_without_ext( + path: &Path, + media_type: MediaType, + ) -> Option<Cow<str>> { + let old_path_str = path.to_string_lossy(); + match media_type { + MediaType::Unknown => Some(old_path_str), + _ => old_path_str + .strip_suffix(media_type.as_ts_extension()) + .map(|s| Cow::Owned(s.to_string())), + } + } + + fn media_types_to_paths( + path_no_ext: &str, + probe_media_type_types: Vec<MediaType>, + ) -> Vec<PathBuf> { + probe_media_type_types + .into_iter() + .map(|media_type| { + PathBuf::from(format!( + "{}{}", + path_no_ext, + media_type.as_ts_extension() + )) + }) + .collect::<Vec<_>>() + } + if specifier.scheme() != "file" { return SloppyImportsResolution::None(specifier); } @@ -951,27 +993,79 @@ impl SloppyImportsResolver { let mut is_no_ext_resolution = false; let probe_paths = match (stat_sync)(&path) { Some(SloppyImportsFsEntry::File) => { - return SloppyImportsResolution::None(specifier); + if mode.is_types() { + let media_type = MediaType::from_specifier(specifier); + // attempt to resolve the .d.ts file before the .js file + let probe_media_type_types = match media_type { + MediaType::JavaScript => { + vec![MediaType::Dts, MediaType::JavaScript] + } + MediaType::Mjs => { + vec![MediaType::Dmts, MediaType::Dts, MediaType::Mjs] + } + MediaType::Cjs => { + vec![MediaType::Dcts, MediaType::Dts, MediaType::Cjs] + } + _ => return SloppyImportsResolution::None(specifier), + }; + let Some(path_no_ext) = path_without_ext(&path, media_type) else { + return SloppyImportsResolution::None(specifier); + }; + media_types_to_paths(&path_no_ext, probe_media_type_types) + } else { + return SloppyImportsResolution::None(specifier); + } } Some(SloppyImportsFsEntry::Dir) => { is_dir_resolution = true; // try to resolve at the index file - vec![ - path.join("index.ts"), - path.join("index.js"), - path.join("index.mts"), - path.join("index.mjs"), - path.join("index.tsx"), - path.join("index.jsx"), - ] + if mode.is_types() { + vec![ + path.join("index.ts"), + path.join("index.mts"), + path.join("index.d.ts"), + path.join("index.d.mts"), + path.join("index.js"), + path.join("index.mjs"), + path.join("index.tsx"), + path.join("index.jsx"), + ] + } else { + vec![ + path.join("index.ts"), + path.join("index.mts"), + path.join("index.tsx"), + path.join("index.js"), + path.join("index.mjs"), + path.join("index.jsx"), + ] + } } None => { let media_type = MediaType::from_specifier(specifier); let probe_media_type_types = match media_type { - MediaType::JavaScript => vec![MediaType::TypeScript, MediaType::Tsx], + MediaType::JavaScript => { + if mode.is_types() { + vec![MediaType::TypeScript, MediaType::Tsx, MediaType::Dts] + } else { + vec![MediaType::TypeScript, MediaType::Tsx] + } + } MediaType::Jsx => vec![MediaType::Tsx], - MediaType::Mjs => vec![MediaType::Mts], - MediaType::Cjs => vec![MediaType::Cts], + MediaType::Mjs => { + if mode.is_types() { + vec![MediaType::Mts, MediaType::Dmts, MediaType::Dts] + } else { + vec![MediaType::Mts] + } + } + MediaType::Cjs => { + if mode.is_types() { + vec![MediaType::Cts, MediaType::Dcts, MediaType::Dts] + } else { + vec![MediaType::Cts] + } + } MediaType::TypeScript | MediaType::Mts | MediaType::Cts @@ -987,34 +1081,34 @@ impl SloppyImportsResolver { } MediaType::Unknown => { is_no_ext_resolution = true; - vec![ - MediaType::TypeScript, - MediaType::JavaScript, - MediaType::Tsx, - MediaType::Jsx, - MediaType::Mts, - MediaType::Mjs, - ] + if mode.is_types() { + vec![ + MediaType::TypeScript, + MediaType::Tsx, + MediaType::Mts, + MediaType::Dts, + MediaType::Dmts, + MediaType::Dcts, + MediaType::JavaScript, + MediaType::Jsx, + MediaType::Mjs, + ] + } else { + vec![ + MediaType::TypeScript, + MediaType::JavaScript, + MediaType::Tsx, + MediaType::Jsx, + MediaType::Mts, + MediaType::Mjs, + ] + } } }; - let old_path_str = path.to_string_lossy(); - let old_path_str = match media_type { - MediaType::Unknown => old_path_str, - _ => match old_path_str.strip_suffix(media_type.as_ts_extension()) { - Some(s) => Cow::Borrowed(s), - None => return SloppyImportsResolution::None(specifier), - }, + let Some(path_no_ext) = path_without_ext(&path, media_type) else { + return SloppyImportsResolution::None(specifier); }; - probe_media_type_types - .into_iter() - .map(|media_type| { - PathBuf::from(format!( - "{}{}", - old_path_str, - media_type.as_ts_extension() - )) - }) - .collect::<Vec<_>>() + media_types_to_paths(&path_no_ext, probe_media_type_types) } }; @@ -1038,8 +1132,9 @@ impl SloppyImportsResolver { pub fn resolve<'a>( &self, specifier: &'a ModuleSpecifier, + mode: ResolutionMode, ) -> SloppyImportsResolution<'a> { - Self::resolve_with_stat_sync(specifier, |path| { + Self::resolve_with_stat_sync(specifier, mode, |path| { self.stat_cache.stat_sync(path) }) } @@ -1117,17 +1212,21 @@ mod test { #[test] fn test_unstable_sloppy_imports() { fn resolve(specifier: &ModuleSpecifier) -> SloppyImportsResolution { - SloppyImportsResolver::resolve_with_stat_sync(specifier, |path| { - RealFs.stat_sync(path).ok().and_then(|stat| { - if stat.is_file { - Some(SloppyImportsFsEntry::File) - } else if stat.is_directory { - Some(SloppyImportsFsEntry::Dir) - } else { - None - } - }) - }) + SloppyImportsResolver::resolve_with_stat_sync( + specifier, + ResolutionMode::Execution, + |path| { + RealFs.stat_sync(path).ok().and_then(|stat| { + if stat.is_file { + Some(SloppyImportsFsEntry::File) + } else if stat.is_directory { + Some(SloppyImportsFsEntry::Dir) + } else { + None + } + }) + }, + ) } let context = TestContext::default(); diff --git a/cli/tools/registry/unfurl.rs b/cli/tools/registry/unfurl.rs index abea2bd0c..6ed8bf99b 100644 --- a/cli/tools/registry/unfurl.rs +++ b/cli/tools/registry/unfurl.rs @@ -151,7 +151,7 @@ impl<'a> SpecifierUnfurler<'a> { let resolved = if let Some(sloppy_imports_resolver) = self.sloppy_imports_resolver { sloppy_imports_resolver - .resolve(&resolved) + .resolve(&resolved, deno_graph::source::ResolutionMode::Execution) .as_specifier() .clone() } else { |
