Skip to content

Commit a8118bc

Browse files
authored
fix: incorrect resolution when using shared resolvers with different main_fields (#134)
1 parent db051d5 commit a8118bc

File tree

3 files changed

+25
-30
lines changed

3 files changed

+25
-30
lines changed

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
515515
cached_path.package_json(&self.cache.fs, &self.options, ctx)?
516516
{
517517
// b. If "main" is a falsy value, GOTO 2.
518-
for main_field in &package_json.main_fields {
518+
for main_field in package_json.main_fields(&self.options.main_fields) {
519519
// c. let M = X + (json main field)
520520
let main_field_path = cached_path.path().normalize_with(main_field);
521521
// d. LOAD_AS_FILE(M)
@@ -1149,7 +1149,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
11491149
// 6. Otherwise, if packageSubpath is equal to ".", then
11501150
if subpath == "." {
11511151
// 1. If pjson.main is a string, then
1152-
for main_field in &package_json.main_fields {
1152+
for main_field in package_json.main_fields(&self.options.main_fields) {
11531153
// 1. Return the URL resolution of main in packageURL.
11541154
let path = cached_path.path().normalize_with(main_field);
11551155
let cached_path = self.cache.value(&path);

src/package_json.rs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,14 @@ pub struct PackageJson {
1818
/// Realpath to `package.json`. Contains the `package.json` filename.
1919
pub realpath: PathBuf,
2020

21-
#[cfg(feature = "package_json_raw_json_api")]
22-
pub(crate) raw_json: std::sync::Arc<serde_json::Value>,
21+
raw_json: std::sync::Arc<serde_json::Value>,
2322

2423
/// The "name" field defines your package's name.
2524
/// The "name" field can be used in addition to the "exports" field to self-reference a package using its name.
2625
///
2726
/// <https://nodejs.org/api/packages.html#name>
2827
pub name: Option<String>,
2928

30-
/// The "main" field defines the entry point of a package when imported by name via a node_modules lookup. Its value is a path.
31-
/// When a package has an "exports" field, this will take precedence over the "main" field when importing the package by name.
32-
///
33-
/// Values are dynamically added from [ResolveOptions::main_fields].
34-
///
35-
/// <https://nodejs.org/api/packages.html#main>
36-
pub main_fields: Vec<String>,
37-
3829
/// The "exports" field allows defining the entry points of a package when imported by name loaded either via a node_modules lookup or a self-reference to its own name.
3930
///
4031
/// <https://nodejs.org/api/packages.html#exports>
@@ -64,7 +55,6 @@ impl PackageJson {
6455
let mut raw_json: Value = serde_json::from_str(json)?;
6556
let mut package_json = Self::default();
6657

67-
package_json.main_fields.reserve_exact(options.main_fields.len());
6858
package_json.exports.reserve_exact(options.exports_fields.len());
6959
package_json.browser_fields.reserve_exact(options.alias_fields.len());
7060

@@ -92,15 +82,6 @@ impl PackageJson {
9282
.transpose()?
9383
.map(Box::new);
9484

95-
// Dynamically create `main_fields`.
96-
for main_field_key in &options.main_fields {
97-
// Using `get` + `clone` instead of remove here
98-
// because `main_fields` may contain `browser`, which is also used in `browser_fields.
99-
if let Some(serde_json::Value::String(value)) = json_object.get(main_field_key) {
100-
package_json.main_fields.push(value.clone());
101-
}
102-
}
103-
10485
// Dynamically create `browser_fields`.
10586
let dir = path.parent().unwrap();
10687
for object_path in &options.alias_fields {
@@ -138,10 +119,7 @@ impl PackageJson {
138119

139120
package_json.path = path;
140121
package_json.realpath = realpath;
141-
#[cfg(feature = "package_json_raw_json_api")]
142-
{
143-
package_json.raw_json = std::sync::Arc::new(raw_json);
144-
}
122+
package_json.raw_json = std::sync::Arc::new(raw_json);
145123
Ok(package_json)
146124
}
147125

@@ -189,6 +167,23 @@ impl PackageJson {
189167
self.realpath.parent().unwrap()
190168
}
191169

170+
/// The "main" field defines the entry point of a package when imported by name via a node_modules lookup. Its value is a path.
171+
///
172+
/// When a package has an "exports" field, this will take precedence over the "main" field when importing the package by name.
173+
///
174+
/// Values are dynamically retrieved from [ResolveOptions::main_fields].
175+
///
176+
/// <https://nodejs.org/api/packages.html#main>
177+
pub(crate) fn main_fields<'a>(
178+
&'a self,
179+
main_fields: &'a [String],
180+
) -> impl Iterator<Item = &'a str> + '_ {
181+
main_fields
182+
.iter()
183+
.filter_map(|main_field| self.raw_json.get(main_field))
184+
.filter_map(|value| value.as_str())
185+
}
186+
192187
/// Resolve the request string for this package.json by looking at the `browser` field.
193188
///
194189
/// # Errors

src/tests/main_field.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ use crate::{ResolveOptions, Resolver};
66
fn test() {
77
let f = super::fixture().join("restrictions");
88

9-
let resolver = Resolver::new(ResolveOptions {
9+
let resolver1 = Resolver::new(ResolveOptions {
1010
main_fields: vec!["style".into()],
1111
..ResolveOptions::default()
1212
});
1313

14-
let resolution = resolver.resolve(&f, "pck2").map(|r| r.full_path());
14+
let resolution = resolver1.resolve(&f, "pck2").map(|r| r.full_path());
1515
assert_eq!(resolution, Ok(f.join("node_modules/pck2/index.css")));
1616

17-
let resolver = Resolver::new(ResolveOptions {
17+
let resolver2 = resolver1.clone_with_options(ResolveOptions {
1818
main_fields: vec!["module".into(), "main".into()],
1919
..ResolveOptions::default()
2020
});
2121

22-
let resolution = resolver.resolve(&f, "pck2").map(|r| r.full_path());
22+
let resolution = resolver2.resolve(&f, "pck2").map(|r| r.full_path());
2323
assert_eq!(resolution, Ok(f.join("node_modules/pck2/module.js")));
2424
}

0 commit comments

Comments
 (0)