Skip to content

Commit 6244ef9

Browse files
committed
fix: resolve module ipaddr.js correctly when extensionAlias is provided
closes #227
1 parent 312d612 commit 6244ef9

File tree

8 files changed

+77
-21
lines changed

8 files changed

+77
-21
lines changed

examples/resolver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn main() {
1818
alias_fields: vec![vec!["browser".into()]],
1919
alias: vec![("asdf".into(), vec![AliasValue::from("./test.js")])],
2020
extensions: vec![".js".into(), ".ts".into()],
21-
extension_alias: vec![(".js".into(), vec![".ts".into()])],
21+
extension_alias: vec![(".js".into(), vec![".ts".into(), ".js".into()])],
2222
..ResolveOptions::default()
2323
};
2424

fixtures/pnpm/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"private": true,
55
"devDependencies": {
66
"axios": "1.6.2",
7-
"styled-components": "6.1.1",
8-
"postcss": "8.4.33"
7+
"ipaddr.js": "2.2.0",
8+
"postcss": "8.4.33",
9+
"styled-components": "6.1.1"
910
}
1011
}

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ pub enum ResolveError {
4343
Builtin(String),
4444

4545
/// All of the aliased extension are not found
46-
#[error("All of the aliased extension are not found")]
47-
ExtensionAlias,
46+
#[error("All of the aliased extensions are not found for {0}")]
47+
ExtensionAlias(PathBuf),
4848

4949
/// The provided path specifier cannot be parsed
5050
#[error("{0}")]

src/lib.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
510510
// 2. If X.js is a file, load X.js as JavaScript text. STOP
511511
// 3. If X.json is a file, parse X.json to a JavaScript Object. STOP
512512
// 4. If X.node is a file, load X.node as binary addon. STOP
513-
if let Some(path) =
514-
self.load_extensions(cached_path.path(), &self.options.extensions, ctx)?
515-
{
513+
if let Some(path) = self.load_extensions(cached_path, &self.options.extensions, ctx)? {
516514
return Ok(Some(path));
517515
}
518516
Ok(None)
@@ -571,11 +569,16 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
571569
Ok(None)
572570
}
573571

574-
fn load_extensions(&self, path: &Path, extensions: &[String], ctx: &mut Ctx) -> ResolveResult {
572+
fn load_extensions(
573+
&self,
574+
path: &CachedPath,
575+
extensions: &[String],
576+
ctx: &mut Ctx,
577+
) -> ResolveResult {
575578
if ctx.fully_specified {
576579
return Ok(None);
577580
}
578-
let path = path.as_os_str();
581+
let path = path.path().as_os_str();
579582
for extension in extensions {
580583
let mut path_with_extension = path.to_os_string();
581584
path_with_extension.reserve_exact(extension.len());
@@ -637,9 +640,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
637640
// 1. If X/index.js is a file, load X/index.js as JavaScript text. STOP
638641
// 2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
639642
// 3. If X/index.node is a file, load X/index.node as binary addon. STOP
640-
if let Some(path) =
641-
self.load_extensions(cached_path.path(), &self.options.extensions, ctx)?
642-
{
643+
if let Some(path) = self.load_extensions(&cached_path, &self.options.extensions, ctx)? {
643644
return Ok(Some(path));
644645
}
645646
}
@@ -972,7 +973,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
972973
Ok(None)
973974
}
974975

975-
/// Given an extension alias map `{".js": [".ts", "js"]}`,
976+
/// Given an extension alias map `{".js": [".ts", ".js"]}`,
976977
/// load the mapping instead of the provided extension
977978
///
978979
/// This is an enhanced-resolve feature
@@ -996,11 +997,24 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
996997
return Ok(None);
997998
};
998999
let path = cached_path.path().with_extension("");
999-
ctx.with_fully_specified(false);
1000-
if let Some(path) = self.load_extensions(&path, extensions, ctx)? {
1001-
return Ok(Some(path));
1000+
let path = path.as_os_str();
1001+
ctx.with_fully_specified(true);
1002+
for extension in extensions {
1003+
let mut path_with_extension = path.to_os_string();
1004+
path_with_extension.reserve_exact(extension.len());
1005+
path_with_extension.push(extension);
1006+
let cached_path = self.cache.value(Path::new(&path_with_extension));
1007+
// Bail if path is module directory such as `ipaddr.js`
1008+
if cached_path.is_dir(&self.cache.fs, ctx) {
1009+
ctx.with_fully_specified(false);
1010+
return Ok(None);
1011+
}
1012+
if let Some(path) = self.load_alias_or_file(&cached_path, ctx)? {
1013+
ctx.with_fully_specified(false);
1014+
return Ok(Some(path));
1015+
}
10021016
}
1003-
Err(ResolveError::ExtensionAlias)
1017+
Err(ResolveError::ExtensionAlias(cached_path.to_path_buf()))
10041018
}
10051019

10061020
/// enhanced-resolve: RootsPlugin

src/tests/exports_field.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ fn extension_alias_throw_error() {
269269
let fail = [
270270
// enhanced-resolve has two test cases that are exactly the same here
271271
// https://github.com/webpack/enhanced-resolve/blob/a998c7d218b7a9ec2461fc4fddd1ad5dd7687485/test/exportsField.test.js#L2976-L3024
272-
("should throw error with the `extensionAlias` option", f, "pkg/string.js", ResolveError::ExtensionAlias),
272+
("should throw error with the `extensionAlias` option", f.clone(), "pkg/string.js", ResolveError::ExtensionAlias(f.join("node_modules/pkg/dist/string.js"))),
273273
// TODO: The error is PackagePathNotExported in enhanced-resolve
274274
// ("should throw error with the `extensionAlias` option", f.clone(), "pkg/string.js", ResolveError::PackagePathNotExported("node_modules/pkg/dist/string.ts".to_string())),
275275
];

src/tests/extension_alias.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ fn extension_alias() {
3131

3232
#[rustfmt::skip]
3333
let fail = [
34-
("should not allow to fallback to the original extension or add extensions", f, "./index.mjs"),
34+
("should not allow to fallback to the original extension or add extensions", f.clone(), "./index.mjs"),
3535
];
3636

3737
for (comment, path, request) in fail {
3838
let resolution = resolver.resolve(&path, request);
39-
assert_eq!(resolution, Err(ResolveError::ExtensionAlias), "{comment} {path:?} {request}");
39+
assert_eq!(
40+
resolution,
41+
Err(ResolveError::ExtensionAlias(f.join(request))),
42+
"{comment} {path:?} {request}"
43+
);
4044
}
4145
}
4246

tests/resolve_test.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,31 @@ fn postcss() {
102102
let resolution = resolver.resolve(&module_path, "./lib/terminal-highlight");
103103
assert_eq!(resolution, Err(ResolveError::Ignored(module_path.join("lib/terminal-highlight"))));
104104
}
105+
106+
#[test]
107+
fn ipaddr_js() {
108+
let dir = dir();
109+
let path = dir.join("fixtures/pnpm");
110+
let module_path =
111+
dir.join("node_modules/.pnpm/ipaddr.js@2.2.0/node_modules/ipaddr.js/lib/ipaddr.js");
112+
113+
let resolvers = [
114+
// with `extension_alias`
115+
Resolver::new(ResolveOptions {
116+
extension_alias: vec![(".js".into(), vec![".js".into(), ".ts".into(), ".tsx".into()])],
117+
..ResolveOptions::default()
118+
}),
119+
// with `extensions` should still resolve to module main
120+
Resolver::new(ResolveOptions {
121+
extensions: vec![(".ts".into())],
122+
..ResolveOptions::default()
123+
}),
124+
// default
125+
Resolver::default(),
126+
];
127+
128+
for resolver in resolvers {
129+
let resolution = resolver.resolve(&path, "ipaddr.js").map(|r| r.full_path());
130+
assert_eq!(resolution, Ok(module_path.clone()));
131+
}
132+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy