@@ -9,6 +9,7 @@ use std::fs::File;
99use std:: io:: Read ;
1010use std:: io:: { self , BufRead } ;
1111use std:: path:: { Component , Path , PathBuf } ;
12+ use std:: sync:: { LazyLock , RwLock } ;
1213use std:: time:: { SystemTime , UNIX_EPOCH } ;
1314
1415pub type StdErr = String ;
@@ -31,6 +32,25 @@ pub mod emojis {
3132 pub static LINE_CLEAR : & str = "\x1b [2K\r " ;
3233}
3334
35+ // Cache existence checks for candidate node_modules paths during upward traversal.
36+ // Keyed by the absolute candidate path string; value is the existence boolean.
37+ static NODE_MODULES_EXIST_CACHE : LazyLock < RwLock < ahash:: AHashMap < String , bool > > > =
38+ LazyLock :: new ( || RwLock :: new ( ahash:: AHashMap :: new ( ) ) ) ;
39+
40+ fn cached_path_exists ( path : & Path ) -> bool {
41+ let key = path. to_string_lossy ( ) . to_string ( ) ;
42+ if let Ok ( cache) = NODE_MODULES_EXIST_CACHE . read ( ) {
43+ if let Some ( exists) = cache. get ( & key) {
44+ return * exists;
45+ }
46+ }
47+ let exists = path. exists ( ) ;
48+ if let Ok ( mut cache) = NODE_MODULES_EXIST_CACHE . write ( ) {
49+ cache. insert ( key, exists) ;
50+ }
51+ exists
52+ }
53+
3454/// This trait is used to strip the verbatim prefix from a Windows path.
3555/// On non-Windows systems, it simply returns the original path.
3656/// This is needed until the rescript compiler can handle such paths.
@@ -189,7 +209,7 @@ fn find_dep_in_upward_node_modules(start_dir: &Path, package_name: &str) -> anyh
189209 while let Some ( dir) = current {
190210 let candidate = package_path ( dir, package_name) ;
191211 log:: debug!( "try_package_path: checking '{}'" , candidate. to_string_lossy( ) ) ;
192- if candidate . exists ( ) {
212+ if cached_path_exists ( & candidate ) {
193213 log:: debug!(
194214 "try_package_path: found '{}' at '{}' via upward traversal" ,
195215 package_name,
0 commit comments