fix(tsconfig): walk past a tsconfig that doesn't claim the file#1154
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1154 +/- ##
==========================================
+ Coverage 93.14% 93.17% +0.03%
==========================================
Files 22 22
Lines 4158 4177 +19
==========================================
+ Hits 3873 3892 +19
Misses 285 285 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Merge activity
|
## Summary
`find_tsconfig_auto` previously returned the nearest `tsconfig.json` unconditionally. If that nearest tsconfig had narrow `files` / `include` / `exclude` that didn't cover the file under resolution, its `compilerOptions.paths` were still applied — leaking the project's aliases into files the project doesn't actually own.
The fix: after finding a `tsconfig.json`, check `claims_ownership_of` (does its `files`/`include`/`exclude` cover the file, or does any matching reference?). If no, remember it as a fallback and walk up to the next ancestor. Mirrors TypeScript 6.0 tsserver and typescript-go's `findDefaultConfiguredProjectWorker`.
## Concrete repros (now fixed)
```
fixtures/tsconfig/cases/project-references-walk-up/
├── files-misses/ pkg-a has files: ["src/foo.ts"] + paths: { "@/*": [...] }
│ → import "@/foo" from pkg-a/src/bar.ts no longer resolves
│ via pkg-a's paths (bar.ts isn't in pkg-a's program)
└── exclude-pattern/ pkg-a has include + exclude that removes src/excluded/bar.ts
→ same fix
```
## Alignment with TypeScript 6.0
Verified all 15 hand-crafted probe scenarios against `tsserver` from TypeScript 6.0.3 — **15 / 15 match**, including:
- solution-style root with matching / non-matching reference
- multi-ref priority (first declared wins)
- nested / cross-directory `include`
- `files` / `include` + `exclude` permutations
## Known divergences from typescript-go (out of scope here)
- **Transitive references** — typescript-go does BFS through the full reference graph; we only check direct `references_resolved`. Triggers only with deep nested references claiming cross-directory files; not observed in real projects.
- **Fallback in the no-claim-anywhere case** — typescript-go returns `nil` (inferred project); we return the topmost ancestor tsconfig. This matches TypeScript 6.0 tsserver but not typescript-go.
5335546 to
120a369
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
## 🤖 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>
…#9714) ## What Corrects the `tsconfig` auto-discovery documentation to match how Rolldown actually resolves `tsconfig.json` since v1.1.0. ## Why The v1.1.0 release notes covered the in-config reference changes (oxc-resolver #1151 reference priority, #1198 allowJs) but omitted [oxc-resolver #1154](oxc-project/oxc-resolver#1154) ("walk past a tsconfig that doesn't claim the file"), which shipped in oxc_resolver v11.19.2 and is part of the 11.19.1 -> 11.21.0 upgrade. As a result the docs still described the old behavior: - "find the nearest tsconfig.json" - "if no referenced project includes the file, fall back to the root tsconfig" Both are inaccurate now. `find_tsconfig_auto` walks up ancestor directories, uses the first tsconfig that owns the file (its `files`/`include`/`exclude`, or a matching `references` entry), and falls back to the outermost (topmost) tsconfig when nothing claims it. This matches TypeScript 6.0 tsserver. A solution-style root (`files: []` plus only `references`) never claims files on its own, so resolution continues upward unless one of its references matches. ## Changes - Rewrite the auto-discovery paragraph: upward, ownership-based search with topmost fallback instead of "nearest". - Fix the references paragraph: root's own `include` vs. a solution-style root, first matching reference wins, per-project `allowJs`. - Drop the "(similar to Vite)" qualifier; the semantics follow TypeScript, not Vite. - Add a `::: warning` callout flagging the v1.1.0 behavior change.
Summary
find_tsconfig_autopreviously returned the nearesttsconfig.jsonunconditionally. If that nearest tsconfig had narrowfiles/include/excludethat didn't cover the file under resolution, itscompilerOptions.pathswere still applied — leaking the project's aliases into files the project doesn't actually own.The fix: after finding a
tsconfig.json, checkclaims_ownership_of(does itsfiles/include/excludecover the file, or does any matching reference?). If no, remember it as a fallback and walk up to the next ancestor. Mirrors TypeScript 6.0 tsserver and typescript-go'sfindDefaultConfiguredProjectWorker.Concrete repros (now fixed)
Alignment with TypeScript 6.0
Verified all 15 hand-crafted probe scenarios against
tsserverfrom TypeScript 6.0.3 — 15 / 15 match, including:includefiles/include+excludepermutationsKnown divergences from typescript-go (out of scope here)
references_resolved. Triggers only with deep nested references claiming cross-directory files; not observed in real projects.nil(inferred project); we return the topmost ancestor tsconfig. This matches TypeScript 6.0 tsserver but not typescript-go.