Skip to content

fix(tsconfig): resolve rootDirs against the config that declared them#1150

Merged
Boshen merged 1 commit into
mainfrom
fix-root-dirs-extends
May 24, 2026
Merged

fix(tsconfig): resolve rootDirs against the config that declared them#1150
Boshen merged 1 commit into
mainfrom
fix-root-dirs-extends

Conversation

@Boshen

@Boshen Boshen commented May 24, 2026

Copy link
Copy Markdown
Member

Summary

Closes #1075.

rootDirs entries inherited via extends were being normalized against the caller tsconfig's directory at build() time, instead of against the directory of the config that actually declared them. This broke the SvelteKit pattern where tsconfig.json extends .svelte-kit/tsconfig.json and the latter declares rootDirs: ["..", "./types"] relative to itself.

Fix

Mirror the established paths_base pattern: normalize non-template rootDirs entries at parse time against each config's own canonical directory (canonical_path.parent()). The build() step keeps ${configDir} template substitution only, so templates still resolve against the root caller's directory as before.

After this change, extend_tsconfig's existing clone-from-parent is correct without further work — the parent's entries are already absolute by the time the child inherits them.

Verification

Cross-checked against TypeScript 6.0.3 via tsc --traceResolution:

  • SvelteKit case (no symlinks) — TS resolves rootDirs: ["..", "./types"] declared in .svelte-kit/tsconfig.json against .svelte-kit/, exactly matching the fixed behavior.
  • Symlinked extends (node_modules/shared-config → real-configs) — TS anchors inherited rootDirs at the canonical path of the parent config, matching the paths_base precedent landed in fix(tsconfig): resolve baseUrl / paths against the canonical tsconfig path #1148.

Verified against typescript-go source (internal/tsoptions/tsconfigparsing.go): rootDirs is declared IsFilePath: true and normalizeNonListOptionValue calls GetNormalizedAbsolutePath(value, basePath) at parse time per config; handleOptionConfigDirTemplateSubstitution runs once afterward against the root caller's directory.

New fixture fixtures/tsconfig/cases/root-dirs-extends/ mirrors the SvelteKit reproduction; new test test_root_dirs_via_extends fails on main (NotFound("./$types")) and passes after the fix.

Closes #1075.

`rootDirs` entries inherited via `extends` were being normalized against
the caller tsconfig's directory at `build()` time, instead of against the
directory of the config that actually declared them. This broke SvelteKit
projects where `tsconfig.json` extends `.svelte-kit/tsconfig.json` and
the latter declares `rootDirs: ["..", "./types"]` relative to itself.

Mirror the established `paths_base` pattern: normalize non-template
entries at parse time against each config's own canonical directory.
`build()` keeps `${configDir}` template substitution only. This also
matches TypeScript's behavior (verified via `tsc --traceResolution`).
@codecov

codecov Bot commented May 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.72727% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.14%. Comparing base (27a9864) to head (14962e2).

Files with missing lines Patch % Lines
src/tsconfig.rs 72.72% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1150      +/-   ##
==========================================
- Coverage   93.15%   93.14%   -0.01%     
==========================================
  Files          22       22              
  Lines        4150     4159       +9     
==========================================
+ Hits         3866     3874       +8     
- Misses        284      285       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq

codspeed-hq Bot commented May 24, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 4.78%

⚡ 1 improved benchmark
✅ 12 untouched benchmarks
⏩ 5 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
resolver_real[multi-thread] 405 µs 386.5 µs +4.78%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing fix-root-dirs-extends (14962e2) with main (27a9864)

Open in CodSpeed

Footnotes

  1. 5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Boshen Boshen merged commit 798cf49 into main May 24, 2026
18 checks passed
@Boshen Boshen deleted the fix-root-dirs-extends branch May 24, 2026 12:17
@oxc-guard oxc-guard Bot mentioned this pull request May 24, 2026
Boshen added a commit that referenced this pull request May 25, 2026
## 🤖 New release

* `oxc_resolver`: 11.19.1 -> 11.19.2
* `oxc_resolver_napi`: 11.19.1 -> 11.19.2

<details><summary><i><b>Changelog</b></i></summary><p>

## `oxc_resolver`

<blockquote>

##
[11.19.2](v11.19.1...v11.19.2)
- 2026-05-25

### <!-- 1 -->🐛 Bug Fixes

- *(tsconfig)* apply later-wins semantics for extends array
([#1156](#1156)) (by
@Boshen)
- *(tsconfig)* walk past a tsconfig that doesn't claim the file
([#1154](#1154)) (by
@Boshen)
- *(tsconfig)* let project references take priority over their parent
([#1151](#1151)) (by
@Boshen)
- *(tsconfig)* resolve `rootDirs` against the config that declared them
([#1150](#1150)) (by
@Boshen)
- *(tsconfig)* resolve `baseUrl` / `paths` against the canonical
tsconfig path
([#1148](#1148)) (by
@Boshen)
- strip query fragments when calling `find_tsconfig`
([#1147](#1147)) (by
@Boshen)
- avoid panic in resolve_file for parentless paths
([#1053](#1053)) (by
@Boshen)
- *(dts)* strip ./ prefix from package entry when matching typesVersions
([#1051](#1051)) (by
@Boshen)
- *(dts)* expand Declaration to TypeScript|Declaration for package entry
resolution
([#1050](#1050)) (by
@Boshen)
- *(dts)* prefer declaration extensions over JS in exports-resolved
paths ([#1047](#1047))
(by @Boshen)
- avoid wasm/wasi dead-code lint in NodePath
([#1043](#1043)) (by
@Boshen)
- *(napi)* replace panics with error returns to prevent WASM traps
([#1055](#1055)) (by
@Boshen)

### <!-- 2 -->🚜 Refactor

- remove clear_cache test that dynamically creates fixtures (by @Boshen)
- move resolve and misc fixtures into fixtures/integration (by @Boshen)
- replace ignored doctest with link to example (by @Boshen)
- consolidate fixture directories for better test file mapping (by
@Boshen)
- replace `url` crate with `percent-encoding`
([#1065](#1065)) (by
@Boshen)

### <!-- 4 -->⚡ Performance

- *(cache)* pack CachedPathImpl::meta into a CachedMeta byte
([#1144](#1144)) (by
@Boshen)
- *(cache)* store canonical path as Box<Path> instead of PathBuf
([#1143](#1143)) (by
@Boshen)
- *(alias)* fast-reject alias entries by cached first byte
([#1142](#1142)) (by
@Boshen)

### <!-- 6 -->🧪 Testing

- *(tsconfig)* port lookup scenarios from typescript-go
([#1155](#1155)) (by
@Boshen)
- add 28 tests to improve coverage (92% → 93%)
([#1082](#1082)) (by
@Boshen)

### Contributors

* @Boshen
* @renovate[bot]
</blockquote>



</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

Co-authored-by: oxc-guard[bot] <276638029+oxc-guard[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rootDirs paths incorrectly normalized when inherited via extends

1 participant