Skip to content

Commit 7cfc5ac

Browse files
committed
fix(tsconfig): apply extends to project references before recursing
When a project reference uses `extends` to inherit its `baseUrl`/`paths` from a shared base config, those fields must be merged before the reference is consulted for resolution. The previous flow loaded each reference through `cache.tsconfig` and only ran the extends-merging logic on the entry tsconfig, so a transitively-referenced project whose aliases live in an extended base file would resolve as if it had no aliases at all. This was a pre-existing latent bug at depth 1 — direct references with `extends` did not inherit their aliases either — that the new transitive-references support made easier to hit. Changes: - Extract `merge_tsconfig_extends` from `load_tsconfig` and call it from `load_references`' inner callback after the self-reference check, before recursing into nested references. - Update the `references-transitive` fixture: `project_c` now reads its `paths` from a sibling `tsconfig.base.json` via `extends`. The existing `transitive_references` test fails before this fix (NotFound) and passes after. Detected via Codex review of #213.
1 parent 415504a commit 7cfc5ac

3 files changed

Lines changed: 56 additions & 33 deletions

File tree

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
{
2+
"extends": "../tsconfig.base.json",
23
"compilerOptions": {
34
"composite": true,
4-
"baseUrl": "./",
5-
"paths": {
6-
"@/*": ["./aliased/*"]
7-
}
5+
"baseUrl": "./"
86
}
97
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"paths": {
4+
"@/*": ["./aliased/*"]
5+
}
6+
}
7+
}

src/lib.rs

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,35 +1475,9 @@ impl<Fs: FileSystem + Send + Sync> ResolverGeneric<Fs> {
14751475
tracing::trace!(tsconfig = ?tsconfig, "load_tsconfig");
14761476

14771477
// Extend tsconfig
1478-
if let Some(extends) = &tsconfig.extends {
1479-
let extended_tsconfig_paths = match extends {
1480-
ExtendsField::Single(s) => {
1481-
vec![
1482-
self
1483-
.get_extended_tsconfig_path(&directory, &tsconfig, s)
1484-
.await?,
1485-
]
1486-
}
1487-
ExtendsField::Multiple(specifiers) => {
1488-
try_join_all(
1489-
specifiers
1490-
.iter()
1491-
.map(|s| self.get_extended_tsconfig_path(&directory, &tsconfig, s)),
1492-
)
1493-
.await?
1494-
}
1495-
};
1496-
for extended_tsconfig_path in extended_tsconfig_paths {
1497-
let extended_tsconfig = self
1498-
.load_tsconfig(
1499-
/* root */ false,
1500-
&extended_tsconfig_path,
1501-
&TsconfigReferences::Disabled,
1502-
)
1503-
.await?;
1504-
tsconfig.extend_tsconfig(&extended_tsconfig);
1505-
}
1506-
}
1478+
self
1479+
.merge_tsconfig_extends(&mut tsconfig, &directory)
1480+
.await?;
15071481

15081482
// Load project references
15091483
match references {
@@ -1562,6 +1536,12 @@ impl<Fs: FileSystem + Send + Sync> ResolverGeneric<Fs> {
15621536
reference_tsconfig.path.clone(),
15631537
));
15641538
}
1539+
// Apply `extends` so the reference inherits its base config's
1540+
// `baseUrl`/`paths` before its own references are walked.
1541+
let directory = self.cache.value(reference_tsconfig.directory());
1542+
self
1543+
.merge_tsconfig_extends(&mut reference_tsconfig, &directory)
1544+
.await?;
15651545
self.load_references(&mut reference_tsconfig).await?;
15661546
Ok(reference_tsconfig)
15671547
}
@@ -1577,6 +1557,44 @@ impl<Fs: FileSystem + Send + Sync> ResolverGeneric<Fs> {
15771557
})
15781558
}
15791559

1560+
async fn merge_tsconfig_extends(
1561+
&self,
1562+
tsconfig: &mut TsConfig,
1563+
directory: &CachedPath,
1564+
) -> Result<(), ResolveError> {
1565+
let Some(extends) = &tsconfig.extends else {
1566+
return Ok(());
1567+
};
1568+
let extended_tsconfig_paths = match extends {
1569+
ExtendsField::Single(s) => {
1570+
vec![
1571+
self
1572+
.get_extended_tsconfig_path(directory, tsconfig, s)
1573+
.await?,
1574+
]
1575+
}
1576+
ExtendsField::Multiple(specifiers) => {
1577+
try_join_all(
1578+
specifiers
1579+
.iter()
1580+
.map(|s| self.get_extended_tsconfig_path(directory, tsconfig, s)),
1581+
)
1582+
.await?
1583+
}
1584+
};
1585+
for extended_tsconfig_path in extended_tsconfig_paths {
1586+
let extended_tsconfig = self
1587+
.load_tsconfig(
1588+
/* root */ false,
1589+
&extended_tsconfig_path,
1590+
&TsconfigReferences::Disabled,
1591+
)
1592+
.await?;
1593+
tsconfig.extend_tsconfig(&extended_tsconfig);
1594+
}
1595+
Ok(())
1596+
}
1597+
15801598
async fn get_extended_tsconfig_path(
15811599
&self,
15821600
directory: &CachedPath,

0 commit comments

Comments
 (0)