fix(unstable): sloppy imports should resolve .d.ts files during types resolution (#22602)

This commit is contained in:
David Sherret 2024-02-27 13:30:21 -05:00 committed by GitHub
parent 8d5c231349
commit e9fe71acb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 348 additions and 135 deletions

84
Cargo.lock generated
View file

@ -1124,9 +1124,9 @@ dependencies = [
[[package]]
name = "deno_ast"
version = "0.34.0"
version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b28da6d573c30a63e4a6b66b91fa32773ed2cf4c0f26aa19b91f6c542b1a57"
checksum = "a73fa2b215c93d44b55228a6c69aa92ffa200cfa683ebaf45202ecfbd749bf52"
dependencies = [
"anyhow",
"base64",
@ -1434,9 +1434,9 @@ dependencies = [
[[package]]
name = "deno_graph"
version = "0.69.4"
version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73c83b0538ee10854dcf0f24aa05ec79f62e308b358cefd65d30f9d0959a9dc3"
checksum = "d49d7cfd7eb14200f2d91b9ff3330b7bd86334060367d47248871c78374a2897"
dependencies = [
"anyhow",
"async-trait",
@ -2251,9 +2251,9 @@ dependencies = [
[[package]]
name = "dprint-swc-ext"
version = "0.15.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fcd02c378803dba687471a9f1f1b758c33e53f616333faaddbaeb8840d9b6dd"
checksum = "5bad772f9e49af3a613fcddf1671d1e2e877e0a6d94f2b7162bfea4ac8140bee"
dependencies = [
"allocator-api2",
"bumpalo",
@ -5945,9 +5945,9 @@ dependencies = [
[[package]]
name = "swc_bundler"
version = "0.225.6"
version = "0.225.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a10c82d574fd928182f90962e280967b23b692d7e21ec9484dc6cbdaa73bab"
checksum = "21736fd17b258d4324f576e1d151d997fd5370a04b68dcb59f3e5050828de33f"
dependencies = [
"anyhow",
"crc",
@ -5989,9 +5989,9 @@ dependencies = [
[[package]]
name = "swc_common"
version = "0.33.17"
version = "0.33.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "095c158fe55b36faeebb4274692643a6d7cdc5b7902e1d5968ddbe52b7de1d1c"
checksum = "c85e8b15d0fb87691e27c8f3cf953748db3ccd2a39e165d6d5275a48fb0d29e3"
dependencies = [
"ast_node",
"better_scoped_tls",
@ -6041,9 +6041,9 @@ dependencies = [
[[package]]
name = "swc_ecma_ast"
version = "0.112.2"
version = "0.112.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852a48a24a2533de88298c6b25355bc68fdee31ac21cb4fb8939b7001715353c"
checksum = "36226eb87bfd2f5620bde04f149a4b869ab34e78496d60cb0d8eb9da765d0732"
dependencies = [
"bitflags 2.4.1",
"is-macro",
@ -6059,9 +6059,9 @@ dependencies = [
[[package]]
name = "swc_ecma_codegen"
version = "0.148.3"
version = "0.148.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d79df3f8c5ed028fce5dc24acb83002c0854f8b9d7e893292aeee394a6b9eaf4"
checksum = "5ba8669ab28bb5d1e65c1e8690257c026745ac368e0101c2c6544d4a03afc95e"
dependencies = [
"memchr",
"num-bigint",
@ -6090,9 +6090,9 @@ dependencies = [
[[package]]
name = "swc_ecma_loader"
version = "0.45.19"
version = "0.45.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c16051bce5421992a1b49350735bf4d110f761fd68ae7098af17a64ad639b8d"
checksum = "d0058cf970880f5382effe43eb2b727a73ba09ae41922fa140c2c3fa6ca9b2d1"
dependencies = [
"anyhow",
"pathdiff",
@ -6104,9 +6104,9 @@ dependencies = [
[[package]]
name = "swc_ecma_parser"
version = "0.143.3"
version = "0.143.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ff55811ed5de14b05e9a2979bae2bce3c807582f559b4325948463265307d9"
checksum = "20823cac99a9adbd4c03fb5e126aaccbf92446afedad99252a0e1fc76e2ffc43"
dependencies = [
"either",
"new_debug_unreachable",
@ -6126,9 +6126,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_base"
version = "0.137.6"
version = "0.137.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9489f8f5c6c08e8291bd93eb354aa91903d4eba5eeb72e1b90adf43c8fe7a29"
checksum = "66539401f619730b26d380a120b91b499f80cbdd9bb15d00aa73bc3a4d4cc394"
dependencies = [
"better_scoped_tls",
"bitflags 2.4.1",
@ -6149,9 +6149,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_classes"
version = "0.126.6"
version = "0.126.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00fecbd333497362f75f475ca467beb486ae381968c9bd67315dddacc9ee67c"
checksum = "ebf9048e687b746d2bbe6149601c3eedd819fef08d7657e5fddcef99b22febba"
dependencies = [
"swc_atoms",
"swc_common",
@ -6175,9 +6175,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_optimization"
version = "0.198.6"
version = "0.198.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db73c718c737c58ed7265fea79aff38578012269398d856264ddc4e764dfb192"
checksum = "17889816334ce9d05ab0c292f93514fdd863b8537a35852dda609ebe3f48071d"
dependencies = [
"dashmap",
"indexmap",
@ -6199,9 +6199,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_proposal"
version = "0.171.6"
version = "0.171.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39920f44aa30ab997dd7cfdc364addd54e4a5fcc3807ae69a6fe283f306bc5a5"
checksum = "35f0a72ee781aa9208836046fd2c12e483f5515898858511b68863290cb97b45"
dependencies = [
"either",
"rustc-hash",
@ -6219,9 +6219,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_react"
version = "0.183.6"
version = "0.183.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d8d36fc8dbfd96dd1ef17f989175e60a291399c6168b20a74951085b0075df"
checksum = "f0ec75c1194365abe4d44d94e58f918ec853469ecd39733b381a089cfdcdee1a"
dependencies = [
"base64",
"dashmap",
@ -6243,9 +6243,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_typescript"
version = "0.188.6"
version = "0.188.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "432cf63b05d3ec435199bfbf7ba50793c6cb777bfcd8ad9f055f501aa9048d9c"
checksum = "fec5e95a9c840eb13562884123eaa627cb6e05e0461c94a2ce69ae7e70313010"
dependencies = [
"ryu-js",
"serde",
@ -6260,9 +6260,9 @@ dependencies = [
[[package]]
name = "swc_ecma_utils"
version = "0.127.5"
version = "0.127.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2de25ac5cc8c8375476985e854054f05d9e841886f3c290716a0eec32eedce3"
checksum = "14482e455df85486d68a51533a31645d511e56df93a35cadf0eabbe7abe96b98"
dependencies = [
"indexmap",
"num_cpus",
@ -6278,9 +6278,9 @@ dependencies = [
[[package]]
name = "swc_ecma_visit"
version = "0.98.2"
version = "0.98.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb71511a816c7c84ddc96e6939389be261caf20858486a5e76948551f110e1f"
checksum = "df0127694c36d656ea9eab5c170cdd8ab398246ae2a335de26961c913a4aca47"
dependencies = [
"num-bigint",
"swc_atoms",
@ -6303,9 +6303,9 @@ dependencies = [
[[package]]
name = "swc_fast_graph"
version = "0.21.17"
version = "0.21.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffd32eda2dd2c725f8d4448d0013c3b5466118e4ff5c30aff2c04f6750f7238b"
checksum = "91bea847755eb7b131edb83c1a437d353e9d25cabd92ac27655420dd13c7267b"
dependencies = [
"indexmap",
"petgraph",
@ -6315,9 +6315,9 @@ dependencies = [
[[package]]
name = "swc_graph_analyzer"
version = "0.22.19"
version = "0.22.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ae1172960aa3b0cdbe94a1d5edf3efa9f1199cbd8384f48dedd0c5bdb5d6bd"
checksum = "1f1469d9d6d5c6f3b469348262ab6bda2c8a9d8e3db7298d9f71f6d17986895d"
dependencies = [
"auto_impl",
"petgraph",
@ -6339,9 +6339,9 @@ dependencies = [
[[package]]
name = "swc_visit"
version = "0.5.8"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b27078d8571abe23aa52ef608dd1df89096a37d867cf691cbb4f4c392322b7c9"
checksum = "358e246dedeb4ae8efacebcce1360dc2f9b6c0b4c1ad8b737cc60f5b6633691a"
dependencies = [
"either",
"swc_visit_macros",
@ -6349,9 +6349,9 @@ dependencies = [
[[package]]
name = "swc_visit_macros"
version = "0.5.9"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa8bb05975506741555ea4d10c3a3bdb0e2357cd58e1a4a4332b8ebb4b44c34d"
checksum = "fbbbb9d77d5112f90ed7ea00477135b16c4370c872b93a0b63b766e8710650ad"
dependencies = [
"Inflector",
"pmutil",

View file

@ -42,7 +42,7 @@ license = "MIT"
repository = "https://github.com/denoland/deno"
[workspace.dependencies]
deno_ast = { version = "0.34.0", features = ["transpiling"] }
deno_ast = { version = "0.34.1", features = ["transpiling"] }
deno_core = { version = "0.265.0", features = ["snapshot_data_bincode"] }
deno_bench_util = { version = "0.133.0", path = "./bench_util" }

View file

@ -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"

View file

@ -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,
};

View file

@ -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,

View file

@ -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);
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
}
})
})
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);
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
}
})
})
path.metadata().ok().and_then(|m| {
if m.is_file() {
Some(SloppyImportsFsEntry::File)
} else if m.is_dir() {
Some(SloppyImportsFsEntry::Dir)
} else {
None
}
})
},
)
}
}

View file

@ -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();

View file

@ -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 {

View file

@ -418,3 +418,105 @@ fn npm_module_check_then_error() {
.assert_matches_text("Check [WILDCARD]main.ts\nerror: TS2305[WILDCARD]has no exported member 'oldName'[WILDCARD]")
.assert_exit_code(1);
}
#[test]
fn test_unstable_sloppy_imports_dts_files() {
let context = TestContextBuilder::new().use_temp_cwd().build();
let temp_dir = context.temp_dir();
temp_dir.write("a.ts", "export class A {}"); // resolves this
temp_dir.write("a.d.ts", "export class A2 {}");
temp_dir.write("b.js", "export class B {}");
temp_dir.write("b.d.ts", "export class B2 {}"); // this
temp_dir.write("c.mts", "export class C {}"); // this
temp_dir.write("c.d.mts", "export class C2 {}");
temp_dir.write("d.mjs", "export class D {}");
temp_dir.write("d.d.mts", "export class D2 {}"); // this
let temp_dir = temp_dir.path();
let dir = temp_dir.join("dir_ts");
dir.create_dir_all();
dir.join("index.ts").write("export class Dir {}"); // this
dir.join("index.d.ts").write("export class Dir2 {}");
let dir = temp_dir.join("dir_js");
dir.create_dir_all();
dir.join("index.js").write("export class Dir {}");
dir.join("index.d.ts").write("export class Dir2 {}"); // this
let dir = temp_dir.join("dir_mts");
dir.create_dir_all();
dir.join("index.mts").write("export class Dir {}"); // this
dir.join("index.d.ts").write("export class Dir2 {}");
let dir = temp_dir.join("dir_mjs");
dir.create_dir_all();
dir.join("index.mjs").write("export class Dir {}");
dir.join("index.d.ts").write("export class Dir2 {}"); // this
temp_dir.join("main.ts").write(
r#"import * as a from "./a.js";
import * as b from "./b.js";
import * as c from "./c.mjs";
import * as d from "./d.mjs";
console.log(a.A);
console.log(b.B2);
console.log(c.C);
console.log(d.D2);
import * as a2 from "./a";
import * as b2 from "./b";
import * as c2 from "./c";
import * as d2 from "./d";
console.log(a2.A);
console.log(b2.B2);
console.log(c2.C);
console.log(d2.D2);
import * as dirTs from "./dir_ts";
import * as dirJs from "./dir_js";
import * as dirMts from "./dir_mts";
import * as dirMjs from "./dir_mjs";
console.log(dirTs.Dir);
console.log(dirJs.Dir2);
console.log(dirMts.Dir);
console.log(dirMjs.Dir2);
"#,
);
context
.new_command()
.args("check --unstable-sloppy-imports main.ts")
.run()
.assert_matches_text(
r#"Warning Sloppy module resolution (hint: update .js extension to .ts)
at file:///[WILDCARD]/main.ts:1:20
Warning Sloppy module resolution (hint: update .mjs extension to .mts)
at file:///[WILDCARD]/main.ts:3:20
Warning Sloppy module resolution (hint: add .ts extension)
at file:///[WILDCARD]/main.ts:11:21
Warning Sloppy module resolution (hint: add .js extension)
at file:///[WILDCARD]/main.ts:12:21
Warning Sloppy module resolution (hint: add .mts extension)
at file:///[WILDCARD]/main.ts:13:21
Warning Sloppy module resolution (hint: add .mjs extension)
at file:///[WILDCARD]/main.ts:14:21
Warning Sloppy module resolution (hint: specify path to index.ts file in directory instead)
at file:///[WILDCARD]/main.ts:21:24
Warning Sloppy module resolution (hint: specify path to index.js file in directory instead)
at file:///[WILDCARD]/main.ts:22:24
Warning Sloppy module resolution (hint: specify path to index.mts file in directory instead)
at file:///[WILDCARD]/main.ts:23:25
Warning Sloppy module resolution (hint: specify path to index.mjs file in directory instead)
at file:///[WILDCARD]/main.ts:24:25
Check [WILDCARD]main.ts
"#,
)
.assert_exit_code(0);
}

View file

@ -1,5 +1,3 @@
Warning Sloppy module resolution (hint: specify path to index.ts file in directory instead)
at file:///[WILDCARD]/publish/sloppy_imports/mod.ts:1:20
Warning Sloppy module resolution (hint: specify path to index.ts file in directory instead)
at file:///[WILDCARD]/publish/sloppy_imports/mod.ts:1:20
Check file:///[WILDCARD]/publish/sloppy_imports/mod.ts