@@ -103,22 +103,74 @@ impl<Fs: FileSystem> Cache<Fs> {
103103 )
104104 }
105105
106+ /// Get package.json of a path of `path`.
107+ ///
108+ /// # Errors
109+ ///
110+ /// * [ResolveError::Json]
106111 pub ( crate ) fn get_package_json (
107112 & self ,
108113 path : & CachedPath ,
109114 options : & ResolveOptions ,
110115 ctx : & mut Ctx ,
111116 ) -> Result < Option < Arc < PackageJson > > , ResolveError > {
117+ self . find_package_json ( path, options, ctx) . map ( |option_package_json| {
118+ option_package_json. filter ( |package_json| {
119+ package_json
120+ . path ( )
121+ . parent ( )
122+ . is_some_and ( |p| p. as_os_str ( ) == path. path ( ) . as_os_str ( ) )
123+ } )
124+ } )
125+ }
126+
127+ /// Find package.json of a path by traversing parent directories.
128+ ///
129+ /// # Errors
130+ ///
131+ /// * [ResolveError::Json]
132+ pub ( crate ) fn find_package_json (
133+ & self ,
134+ path : & CachedPath ,
135+ options : & ResolveOptions ,
136+ ctx : & mut Ctx ,
137+ ) -> Result < Option < Arc < PackageJson > > , ResolveError > {
138+ let mut path = path. clone ( ) ;
139+ // Go up directories when the querying path is not a directory
140+ while !self . is_dir ( & path, ctx) {
141+ if let Some ( cv) = path. parent ( ) {
142+ path = cv;
143+ } else {
144+ break ;
145+ }
146+ }
147+ self . find_package_json_impl ( & path, options, ctx) . map ( |option_index| {
148+ option_index. and_then ( |index| self . package_jsons . read ( ) . get ( index) . cloned ( ) )
149+ } )
150+ }
151+
152+ /// Find package.json of a path by traversing parent directories.
153+ ///
154+ /// # Errors
155+ ///
156+ /// * [ResolveError::Json]
157+ fn find_package_json_impl (
158+ & self ,
159+ path : & CachedPath ,
160+ options : & ResolveOptions ,
161+ ctx : & mut Ctx ,
162+ ) -> Result < Option < PackageJsonIndex > , ResolveError > {
112163 // Change to `std::sync::OnceLock::get_or_try_init` when it is stable.
113- let result = path
114- . package_json
164+ path. package_json
115165 . get_or_try_init ( || {
116166 let package_json_path = path. path . join ( "package.json" ) ;
117167 let Ok ( package_json_bytes) = self . fs . read ( & package_json_path) else {
118168 if let Some ( deps) = & mut ctx. missing_dependencies {
119169 deps. push ( package_json_path) ;
120170 }
121- return Ok ( None ) ;
171+ return path. parent ( ) . map_or ( Ok ( None ) , |parent| {
172+ self . find_package_json_impl ( & parent, options, ctx)
173+ } ) ;
122174 } ;
123175 let real_path = if options. symlinks {
124176 self . canonicalize ( path) ?. join ( "package.json" )
@@ -152,11 +204,7 @@ impl<Fs: FileSystem> Cache<Fs> {
152204 }
153205 } )
154206 } )
155- . cloned ( ) ;
156-
157- result. map ( |option_index| {
158- option_index. and_then ( |index| self . package_jsons . read ( ) . get ( index) . cloned ( ) )
159- } )
207+ . cloned ( )
160208 }
161209
162210 pub ( crate ) fn get_tsconfig < F : FnOnce ( & mut TsConfig ) -> Result < ( ) , ResolveError > > (
0 commit comments