@@ -70,8 +70,8 @@ pub use crate::{
7070 error:: { JSONError , ResolveError , SpecifierError } ,
7171 file_system:: { FileMetadata , FileSystem , FileSystemOs } ,
7272 options:: {
73- Alias , AliasValue , EnforceExtension , ResolveOptions , Restriction , TsconfigOptions ,
74- TsconfigReferences ,
73+ Alias , AliasValue , EnforceExtension , ResolveOptions , Restriction , TsconfigDiscovery ,
74+ TsconfigOptions , TsconfigReferences ,
7575 } ,
7676 package_json:: {
7777 ImportsExportsArray , ImportsExportsEntry , ImportsExportsKind , ImportsExportsMap ,
@@ -281,6 +281,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
281281 debug_assert ! ( path. starts_with( package_json. directory( ) ) ) ;
282282 }
283283 let module_type = self . esm_file_format ( & cached_path, ctx) ?;
284+
284285 Ok ( Resolution {
285286 path,
286287 query : ctx. query . take ( ) ,
@@ -1456,21 +1457,78 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
14561457 if cached_path. inside_node_modules ( ) {
14571458 return Ok ( None ) ;
14581459 }
1459- let Some ( tsconfig_options) = & self . options . tsconfig else {
1460- return Ok ( None ) ;
1460+ let tsconfig = match & self . options . tsconfig {
1461+ None => return Ok ( None ) ,
1462+ Some ( TsconfigDiscovery :: Manual ( tsconfig_options) ) => {
1463+ let tsconfig = self . load_tsconfig (
1464+ /* root */ true ,
1465+ & tsconfig_options. config_file ,
1466+ & tsconfig_options. references ,
1467+ & mut TsconfigResolveContext :: default ( ) ,
1468+ ) ?;
1469+ // Cache the loaded tsconfig in the path's directory
1470+ let tsconfig_dir = self . cache . value ( tsconfig. directory ( ) ) ;
1471+ _ = tsconfig_dir. tsconfig . get_or_init ( || Some ( Arc :: clone ( & tsconfig) ) ) ;
1472+ tsconfig
1473+ }
1474+ Some ( TsconfigDiscovery :: Auto ) => {
1475+ let Some ( tsconfig) = self . find_tsconfig ( cached_path, ctx) ? else {
1476+ return Ok ( None ) ;
1477+ } ;
1478+ tsconfig
1479+ }
14611480 } ;
1462- let tsconfig = self . load_tsconfig (
1463- /* root */ true ,
1464- & tsconfig_options. config_file ,
1465- & tsconfig_options. references ,
1466- & mut TsconfigResolveContext :: default ( ) ,
1467- ) ?;
1481+
14681482 let paths = tsconfig. resolve ( cached_path. path ( ) , specifier) ;
14691483 for path in paths {
1470- let cached_path = self . cache . value ( & path) ;
1471- if let Some ( path) = self . load_as_file_or_directory ( & cached_path, "." , ctx) ? {
1472- return Ok ( Some ( path) ) ;
1484+ let resolved_path = self . cache . value ( & path) ;
1485+ if let Some ( resolution) = self . load_as_file_or_directory ( & resolved_path, "." , ctx) ? {
1486+ // Cache the tsconfig in the resolved path
1487+ _ = resolved_path. tsconfig . get_or_init ( || Some ( Arc :: clone ( & tsconfig) ) ) ;
1488+ return Ok ( Some ( resolution) ) ;
1489+ }
1490+ }
1491+ Ok ( None )
1492+ }
1493+
1494+ /// Find tsconfig.json of a path by traversing parent directories.
1495+ ///
1496+ /// # Errors
1497+ ///
1498+ /// * [ResolveError::Json]
1499+ pub ( crate ) fn find_tsconfig (
1500+ & self ,
1501+ cached_path : & CachedPath ,
1502+ ctx : & mut Ctx ,
1503+ ) -> Result < Option < Arc < TsConfig > > , ResolveError > {
1504+ // Don't discover tsconfig for paths inside node_modules
1505+ if cached_path. inside_node_modules ( ) {
1506+ return Ok ( None ) ;
1507+ }
1508+
1509+ let mut cache_value = cached_path. clone ( ) ;
1510+ // Go up directories when the querying path is not a directory
1511+ while !self . cache . is_dir ( & cache_value, ctx) {
1512+ if let Some ( cv) = cache_value. parent ( ) {
1513+ cache_value = cv;
1514+ } else {
1515+ break ;
1516+ }
1517+ }
1518+ let mut cache_value = Some ( cache_value) ;
1519+ while let Some ( cv) = cache_value {
1520+ if let Some ( tsconfig) = cv. tsconfig . get_or_try_init ( || {
1521+ let tsconfig_path = cv. path . join ( "tsconfig.json" ) ;
1522+ let tsconfig_path = self . cache . value ( & tsconfig_path) ;
1523+ if self . cache . is_file ( & tsconfig_path, ctx) {
1524+ self . resolve_tsconfig ( tsconfig_path. path ( ) ) . map ( Some )
1525+ } else {
1526+ Ok ( None )
1527+ }
1528+ } ) ? {
1529+ return Ok ( Some ( Arc :: clone ( tsconfig) ) ) ;
14731530 }
1531+ cache_value = cv. parent ( ) ;
14741532 }
14751533 Ok ( None )
14761534 }
@@ -1487,6 +1545,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
14871545 Some ( b'.' ) => Ok ( tsconfig. directory ( ) . normalize_with ( specifier) ) ,
14881546 _ => self
14891547 . clone_with_options ( ResolveOptions {
1548+ tsconfig : None ,
14901549 extensions : vec ! [ ".json" . into( ) ] ,
14911550 main_files : vec ! [ "tsconfig.json" . into( ) ] ,
14921551 #[ cfg( feature = "yarn_pnp" ) ]
0 commit comments