Skip to content

Commit 5644abb

Browse files
authored
fix: resolve module ipaddr.js correctly when extensionAlias is provided (#228)
closes #227
1 parent 312d612 commit 5644abb

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/[email protected]/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)