Skip to content

Commit b7f78c3

Browse files
authored
fix: don't panic when resolving / with roots (#310)
1 parent 57fcd6e commit b7f78c3

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

fixtures/misc/dir-with-index/index.js

Whitespace-only changes.

src/lib.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
355355
return Ok(path);
356356
}
357357
}
358-
if let Some(path) = self.load_roots(specifier, ctx) {
358+
if let Some(path) = self.load_roots(cached_path, specifier, ctx) {
359359
return Ok(path);
360360
}
361361
// 2. If X begins with '/'
@@ -1086,15 +1086,28 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
10861086
/// defaults to context configuration option.
10871087
///
10881088
/// On non-Windows systems these requests are resolved as an absolute path first.
1089-
fn load_roots(&self, specifier: &str, ctx: &mut Ctx) -> Option<CachedPath> {
1089+
fn load_roots(
1090+
&self,
1091+
cached_path: &CachedPath,
1092+
specifier: &str,
1093+
ctx: &mut Ctx,
1094+
) -> Option<CachedPath> {
10901095
if self.options.roots.is_empty() {
10911096
return None;
10921097
}
10931098
if let Some(specifier) = specifier.strip_prefix(SLASH_START) {
1094-
for root in &self.options.roots {
1095-
let cached_path = self.cache.value(root);
1096-
if let Ok(path) = self.require_relative(&cached_path, specifier, ctx) {
1097-
return Some(path);
1099+
if specifier.is_empty() {
1100+
if self.options.roots.iter().any(|root| root.as_path() == cached_path.path()) {
1101+
if let Ok(path) = self.require_relative(cached_path, "./", ctx) {
1102+
return Some(path);
1103+
}
1104+
}
1105+
} else {
1106+
for root in &self.options.roots {
1107+
let cached_path = self.cache.value(root);
1108+
if let Ok(path) = self.require_relative(&cached_path, specifier, ctx) {
1109+
return Some(path);
1110+
}
10981111
}
10991112
}
11001113
}

src/tests/roots.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,34 @@ fn roots_fall_through() {
9090
Ok(absolute_path)
9191
);
9292
}
93+
94+
#[test]
95+
fn should_resolve_slash() {
96+
let f = super::fixture();
97+
let dir_with_index = super::fixture_root().join("./misc/dir-with-index");
98+
99+
#[rustfmt::skip]
100+
let pass = [
101+
("should resolve if importer is root", vec![dir_with_index.clone()], &dir_with_index, dir_with_index.join("index.js")),
102+
];
103+
104+
for (comment, roots, directory, expected) in pass {
105+
let resolver =
106+
Resolver::new(ResolveOptions { roots: roots.clone(), ..ResolveOptions::default() });
107+
let resolved_path = resolver.resolve(directory, "/").map(|r| r.full_path());
108+
assert_eq!(resolved_path, Ok(expected), "{comment} {roots:?}");
109+
}
110+
111+
#[rustfmt::skip]
112+
let fail = [
113+
("should not resolve if not found", vec![f.clone()], &f),
114+
("should not resolve if importer is not root", vec![dir_with_index], &f)
115+
];
116+
117+
for (comment, roots, directory) in fail {
118+
let resolver =
119+
Resolver::new(ResolveOptions { roots: roots.clone(), ..ResolveOptions::default() });
120+
let resolution = resolver.resolve(directory, "/");
121+
assert_eq!(resolution, Err(ResolveError::NotFound("/".into())), "{comment} {roots:?}");
122+
}
123+
}

0 commit comments

Comments
 (0)