Repository: oxc-project/oxc-resolver
Pull request #251 (2024-09-25 07:00:51)

feat: show tried extension aliases in `ResolveError::ExtensionAlias`
It is now displayed as `Cannot resolve 'index.mjs' with extension aliases 'index.mts' in ...`

Boshen: * **#251** <a href="https://app.graphite.dev/github/pr/oxc-project/oxc-resolver/251?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a> 👈
* `main`

This stack of pull requests is managed by Graphite. <a href="https://stacking.dev/?utm_source=stack-comment">Learn more about stacking.</a>
<h2></h2>

 Join @Boshen and the rest of your teammates on <a href="https://graphite.dev?utm-source=stack-comment"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="11px" height="11px"/> <b>Graphite</b></a>
  <!-- Current dependencies on/for this PR: -->
codspeed-hq[bot]: ## [CodSpeed Performance Report](https://codspeed.io/oxc-project/oxc-resolver/branches/09-25-feat_show_tried_extension_aliases_in_resolveerror_extensionalias_)

### Merging #251 will **not alter performance**

<sub>Comparing <code>09-25-feat_show_tried_extension_aliases_in_resolveerror_extensionalias_</code> (eea58f6) with <code>main</code> (aaace86)</sub>



### Summary

`✅ 3` untouched benchmarks





codecov[bot]: ## [Codecov](https://app.codecov.io/gh/oxc-project/oxc-resolver/pull/251?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oxc-project) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 96.99%. Comparing base [(`aaace86`)](https://app.codecov.io/gh/oxc-project/oxc-resolver/commit/aaace869ac109b0c153cafbafa2419e912c3b6a6?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oxc-project) to head [(`eea58f6`)](https://app.codecov.io/gh/oxc-project/oxc-resolver/commit/eea58f6bc9ca5f0e373b12cdde6d1f99b45e31ba?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oxc-project).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #251      +/-   ##
==========================================
+ Coverage   96.98%   96.99%   +0.01%     
==========================================
  Files          11       11              
  Lines        2355     2364       +9     
==========================================
+ Hits         2284     2293       +9     
  Misses         71       71              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/oxc-project/oxc-resolver/pull/251?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oxc-project).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=oxc-project).


Patch:
diff --git a/src/error.rs b/src/error.rs
index b00a0ba..ce46f4b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -47,8 +47,14 @@ pub enum ResolveError {
     Builtin(String),
 
     /// All of the aliased extension are not found
-    #[error("All of the aliased extensions are not found for {0}")]
-    ExtensionAlias(PathBuf),
+    ///
+    /// Displays `Cannot resolve 'index.mjs' with extension aliases 'index.mts' in ...`
+    #[error("Cannot resolve '{0}' for extension aliases '{1}' in '{2}'")]
+    ExtensionAlias(
+        /* File name */ String,
+        /* Tried file names */ String,
+        /* Path to dir */ PathBuf,
+    ),
 
     /// The provided path specifier cannot be parsed
     #[error("{0}")]
diff --git a/src/lib.rs b/src/lib.rs
index e6cb224..cacabba 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1047,11 +1047,12 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
         else {
             return Ok(None);
         };
-        let path = cached_path.path().with_extension("");
-        let path = path.as_os_str();
+        let path = cached_path.path();
+        let Some(filename) = path.file_name() else { return Ok(None) };
+        let path_without_extension = path.with_extension("");
         ctx.with_fully_specified(true);
         for extension in extensions {
-            let mut path_with_extension = path.to_os_string();
+            let mut path_with_extension = path_without_extension.clone().into_os_string();
             path_with_extension.reserve_exact(extension.len());
             path_with_extension.push(extension);
             let cached_path = self.cache.value(Path::new(&path_with_extension));
@@ -1065,7 +1066,16 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
                 return Ok(Some(path));
             }
         }
-        Err(ResolveError::ExtensionAlias(cached_path.to_path_buf()))
+        // Create a meaningful error message.
+        let dir = path.parent().unwrap().to_path_buf();
+        let filename_without_extension = Path::new(filename).with_extension("");
+        let filename_without_extension = filename_without_extension.to_string_lossy();
+        let files = extensions
+            .iter()
+            .map(|ext| format!("{filename_without_extension}{ext}"))
+            .collect::<Vec<_>>()
+            .join(",");
+        Err(ResolveError::ExtensionAlias(filename.to_string_lossy().to_string(), files, dir))
     }
 
     /// enhanced-resolve: RootsPlugin


Test patch:
diff --git a/src/tests/exports_field.rs b/src/tests/exports_field.rs
index 7ca73fb..8f3cb4d 100644
--- a/src/tests/exports_field.rs
+++ b/src/tests/exports_field.rs
@@ -269,7 +269,7 @@ fn extension_alias_throw_error() {
     let fail = [
         // enhanced-resolve has two test cases that are exactly the same here
         // https://github.com/webpack/enhanced-resolve/blob/a998c7d218b7a9ec2461fc4fddd1ad5dd7687485/test/exportsField.test.js#L2976-L3024
-        ("should throw error with the `extensionAlias` option", f.clone(), "pkg/string.js", ResolveError::ExtensionAlias(f.join("node_modules/pkg/dist/string.js"))),
+        ("should throw error with the `extensionAlias` option", f.clone(), "pkg/string.js", ResolveError::ExtensionAlias("string.js".into(), "string.ts".into(), f.join("node_modules/pkg/dist"))),
         // TODO: The error is PackagePathNotExported in enhanced-resolve
         // ("should throw error with the `extensionAlias` option", f.clone(), "pkg/string.js", ResolveError::PackagePathNotExported("node_modules/pkg/dist/string.ts".to_string())),
     ];
diff --git a/src/tests/extension_alias.rs b/src/tests/extension_alias.rs
index cc6a906..cf4fd36 100644
--- a/src/tests/extension_alias.rs
+++ b/src/tests/extension_alias.rs
@@ -29,19 +29,10 @@ fn extension_alias() {
         assert_eq!(resolved_path, Ok(expected), "{comment} {path:?} {request}");
     }
 
-    #[rustfmt::skip]
-    let fail = [
-        ("should not allow to fallback to the original extension or add extensions", f.clone(), "./index.mjs"),
-    ];
-
-    for (comment, path, request) in fail {
-        let resolution = resolver.resolve(&path, request);
-        assert_eq!(
-            resolution,
-            Err(ResolveError::ExtensionAlias(f.join(request))),
-            "{comment} {path:?} {request}"
-        );
-    }
+    // should not allow to fallback to the original extension or add extensions
+    let resolution = resolver.resolve(&f, "./index.mjs").unwrap_err();
+    let expected = ResolveError::ExtensionAlias("index.mjs".into(), "index.mts".into(), f);
+    assert_eq!(resolution, expected);
 }
 
 // should not apply extension alias to extensions or mainFiles field