Repository: oxc-project/oxc-resolver (rust)

Issue:
The result resolved by 7.0.0 no longer includes package.json.
It breaks oxc-node: https://github.com/oxc-project/oxc-node/pull/116

In 6.0.0, the [`compiled.js`](https://github.com/oxc-project/oxc-node/blob/main/packages/integrate-module/src/index.ts#L14) was resolved: `Resolution { path: "/Users/brooklyn/workspace/github/oxc-node/packages/integrate-module-bundler/src/compiled.js", query: None, fragment: None, package_json: Some("/Users/brooklyn/workspace/github/oxc-node/packages/integrate-module-bundler/package.json") }`

In 7.0.0, the result is: `Resolution { path: "/Users/brooklyn/workspace/github/oxc-node/packages/integrate-module/src/compiled.js", query: None, fragment: None, package_json: None }`

Without a package.json, I can't determine whether a .js file is CommonJS or ESM.

Pull request:
fix: fix incorrect return of package.json when a workspace module has `node_modules`
fixes #481

Patch:
diff --git a/fixtures/misc/package.json b/fixtures/misc/package.json
new file mode 100644
index 0000000..b9d8af1
--- /dev/null
+++ b/fixtures/misc/package.json
@@ -0,0 +1,3 @@
+{
+  "name": "misc"
+}
diff --git a/src/lib.rs b/src/lib.rs
index 01d4ca2..7ecf2c9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -287,12 +287,13 @@ impl<C: Cache> ResolverGeneric<C> {
         // Algorithm:
         // Find `node_modules/package/package.json`
         // or the first package.json if the path is not inside node_modules.
+        // TODO(perf): cache whether a directory is inside `node_modules`?
         let inside_node_modules = iter::successors(Some(cached_path), |cp| cp.parent())
-            .any(|cp| cp.node_modules().is_some());
+            .any(|cp| cp.path().ends_with("node_modules"));
         if inside_node_modules {
             let mut last = None;
             for cp in iter::successors(Some(cached_path), |cp| cp.parent()) {
-                if cp.node_modules().is_some() {
+                if cp.path().ends_with("node_modules") {
                     break;
                 }
                 if self.cache.is_dir(cp, ctx) {


Test patch:
diff --git a/src/tests/dependencies.rs b/src/tests/dependencies.rs
index 5584a1b..9f1b6da 100644
--- a/src/tests/dependencies.rs
+++ b/src/tests/dependencies.rs
@@ -52,7 +52,6 @@ mod windows {
                     // "/a/b/c/package.json",
                     "/a/b/package.json",
                     "/a/package.json",
-                    "/a/node_modules/package.json",
                     "/package.json",
                     // missing modules directories
                     "/a/b/c",
diff --git a/src/tests/package_json.rs b/src/tests/package_json.rs
index 8575763..1e41775 100644
--- a/src/tests/package_json.rs
+++ b/src/tests/package_json.rs
@@ -26,3 +26,23 @@ fn test() {
         assert_eq!(package_json_name, Some("package-json-nested"), "{path:?} {request}");
     }
 }
+
+#[test]
+fn adjacent_to_node_modules() {
+    let f = super::fixture_root().join("misc");
+
+    let resolver = Resolver::default();
+
+    // populate cache
+    let _ = resolver.resolve(&f, "package-json-nested");
+
+    let path = f.join("dir-with-index");
+    let request = "./index.js";
+    let resolved_package_json_path = f.join("package.json");
+
+    let package_json = resolver.resolve(&path, request).unwrap().package_json().cloned();
+    let package_json_path = package_json.as_ref().map(|p| &p.path);
+    let package_json_name = package_json.as_ref().and_then(|p| p.name.as_deref());
+    assert_eq!(package_json_path, Some(&resolved_package_json_path));
+    assert_eq!(package_json_name, Some("misc"));
+}