Skip to content

fix(tsconfig): honor explicit non-TS extensions in include#1213

Merged
Boshen merged 2 commits into
oxc-project:mainfrom
shulaoda:06-16-fix_tsconfig_honor_explicit_non-ts_extensions_in
Jun 17, 2026
Merged

fix(tsconfig): honor explicit non-TS extensions in include#1213
Boshen merged 2 commits into
oxc-project:mainfrom
shulaoda:06-16-fix_tsconfig_honor_explicit_non-ts_extensions_in

Conversation

@shulaoda

Copy link
Copy Markdown
Contributor

Related to #1212

Summary

is_file_included_in_tsconfig checked a file's extension before evaluating the include globs, rejecting any non-TS/JS extension up front — so a file with a non-TS extension that is explicitly listed in include (e.g. src/**/*.vue) was never matched.

In a solution-style layout (a root tsconfig.json with "files": [] + references, and paths declared in a referenced tsconfig.app.json whose include lists src/**/*.vue), a .vue / .svelte importer therefore could not select the project that owns it. The empty solution root (no paths) was chosen instead, so @/*-style aliases never resolved.

Why

This is the default create-vite Vue + TS layout, and it blocks migrating from the vite-tsconfig-paths plugin to Vite's built-in resolve.tsconfigPaths (Vite 8 / rolldown-vite, which resolves through oxc-resolver): import Foo from '@/components/Foo.vue' inside a .vue file fails in both dev and build. Downstream report: vitejs/vite#22047.

Closes #.

Change

  • Drop the blanket extension pre-gate in is_file_included_in_tsconfig.
  • Apply the TS/JS restriction in the default **/* (GlobPattern::All) branch instead, so a bare/omitted include still matches only TS/JS while an explicitly-named extension matches verbatim.

Extension filtering is now consistently per-pattern: the gate in is_glob_match already restricts only wildcard-terminated (*) patterns, so src/**/*.vue matches .vue once it is actually reached. This mirrors TypeScript (getSubPatternFromSpec / isImplicitGlob) and tsconfck's isGlobMatch — no hardcoded per-framework list, and no dependency on allowJs.

Tests

Adds solution_style_non_ts_extensions with a fixture mirroring the create-vite Vue scaffold: .vue / .svelte importers resolve a referenced project's paths, .ts importers keep working, and an extension not listed in any include (here .css) is still left to the solution root. The test fails on main and passes with this change.

Out of scope

claims_ownership_of still routes a non-TS importer to the nearest tsconfig. In nested layouts (a child tsconfig that doesn't include the file, with an ancestor solution project that does) the child still intercepts it. That needs a separate change to the discovery walk and is left as a follow-up.

@codspeed-hq

codspeed-hq Bot commented Jun 16, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 3 improved benchmarks
❌ 2 regressed benchmarks
✅ 16 untouched benchmarks
⏩ 5 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
pm/pnpm-hoisted 1 ms 1.1 ms -5.32%
resolver_real[multi-thread] 384.8 µs 404.6 µs -4.9%
pm/pnpm-isolated 1.1 ms 1 ms +5.57%
pm/yarn-flat 1,013.1 µs 960.4 µs +5.49%
pm/yarn-isolated 1.1 ms 1 ms +3.73%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing shulaoda:06-16-fix_tsconfig_honor_explicit_non-ts_extensions_in (2564324) with main (c4349da)

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 self-assigned this Jun 17, 2026
@Boshen Boshen merged commit c55a3e1 into oxc-project:main Jun 17, 2026
15 checks passed
@oxc-guard oxc-guard Bot mentioned this pull request Jun 17, 2026
Boshen pushed a commit that referenced this pull request Jun 17, 2026
…1216)

## Summary

Follow-up to #1213. When auto-discovering a `tsconfig.json` for an
importer, `claims_ownership_of` treated *any* file the tsconfig doesn't
compile as "owned by the nearest tsconfig" and stopped the upward walk.
That blanket shortcut intercepted files that an ancestor project
genuinely owns.

## The problem

The guard was:

```rust
if !self.is_file_extension_allowed_in_tsconfig(path) {
    return true; // claimed by the nearest tsconfig
}
```

`is_file_extension_allowed_in_tsconfig` is true only for TS extensions
(and JS when `allowJs` is on), so the negation claimed **non-TS files**
(`.vue`, `.css`), **extensionless paths**, and **`allowJs`-off `.js`**
alike. Two concrete failures:

1. **Non-TS files don't reach their solution project.** A child
`tsconfig.json` including only `**/*.ts` would claim a sibling
`App.vue`. Auto-discovery stopped at the child, so a solution root that
references a config with `include: ["src/**/*.vue"]` and a `@/*` alias
never owned the file and the alias didn't resolve.
2. **`allowJs`-off `.js` leaks a referenced project's `paths`.** A
referenced project with `allowJs` off but `include: ["src/**/*.js"]`
would still route a `.js` importer through itself, applying its `@lib/*`
paths to a file TypeScript excludes from the program.

## The fix

- **`claims_ownership_of`** — narrow the early `return true` to
`path.extension().is_none()`. A directory (extensionless importer) isn't
a file, so `files`/`include` ownership doesn't apply and the nearest
enclosing tsconfig governs it (many discovery cases rely on its
`paths`/`baseUrl`/`extends`). A genuine file — including an
`allowJs`-off `.js` this config won't compile — is claimed only when
actually owned, otherwise the walk continues up.
- **`is_file_included_in_tsconfig`** — reject non-program inputs (an
`allowJs`-off `.js`, even when a glob names `.js`; or an extensionless
path) before consulting `include`, so `resolve_tsconfig_solution` won't
route such files to a referenced project.
- Extracted `is_extensionless_or_uncompiled_js` to share that predicate.

Directory importers are unchanged: they still resolve against their
nearest tsconfig (verified by the existing `tsconfig_discovery` cases).

## Tests

- `solution_style_nested_non_ts_walks_up` (new) — a child config
including only `**/*.ts` no longer intercepts `App.vue`; the walk
reaches the solution project that owns `@/*`. A `.ts` the child includes
stays on the child; an `allowJs`-off `legacy.js` walks up like the
`.vue`.
- `referenced_config_drops_js_when_allow_js_off` (new) — a `.ts`
importer resolves `@lib/*`; a `.js` importer does not (dropped because
`allowJs` is off).
- `solution_style_non_ts_extensions` (updated) — a `.css` matched by no
`include` walks past the solution root to the outermost ancestor, and
the `@/*` alias does not leak into it.

New fixtures under `fixtures/tsconfig/cases/referenced-allow-js-off/`
and `fixtures/tsconfig/cases/solution-style-non-ts/src/feature/`.
Boshen pushed a commit that referenced this pull request Jun 17, 2026
## 🤖 New release

* `oxc_resolver`: 11.21.0 -> 11.21.1
* `oxc_resolver_napi`: 11.21.0 -> 11.21.1

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

## `oxc_resolver`

<blockquote>

##
[11.21.1](v11.21.0...v11.21.1)
- 2026-06-17

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

- *(tsconfig)* walk up for non-TS and `allowJs`-off `.js` importers
([#1216](#1216)) (by
@shulaoda)
- *(tsconfig)* honor explicit non-TS extensions in `include`
([#1213](#1213)) (by
@shulaoda)

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

- *(cache)* replace papaya with dashmap
([#1214](#1214)) (by
@Boshen)

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

- verify node_modules canonicalization across layouts
([#1200](#1200)) (by
@Boshen)

### Contributors

* @shulaoda
* @Boshen
</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>
@oxc-guard oxc-guard Bot mentioned this pull request Jun 17, 2026
shulaoda added a commit to rolldown/rolldown that referenced this pull request Jun 18, 2026
…9845)

Related to #9841

## What

Updates the `tsconfig` auto-discovery documentation (`packages/rolldown/src/options/docs/tsconfig.md`, injected into the `tsconfig` option's JSDoc) to reflect two oxc-resolver fixes that already ship in the version Rolldown uses (`11.21.3`).

## Why

The docs still described oxc-resolver's previous behavior, which no longer matches what the resolver does.

### 1. Fallback for unowned files (oxc-project/oxc-resolver#1220)

Previously, when no `tsconfig.json` owned a file, the resolver fell back to the outermost (topmost) ancestor `tsconfig.json`, leaking its `paths`/`baseUrl` to unrelated files. It now applies no config in that case (an inferred project with no path mapping), matching TypeScript and typescript-go.

Doc change:

> If no `tsconfig.json` owns the file, no config is applied (no `paths`/`baseUrl`), matching TypeScript.

### 2. Explicit non-TS extensions in `include` (oxc-project/oxc-resolver#1213)

The extension filter used to reject any non-TS/JS file up front, so an explicitly listed extension such as `src/**/*.vue` never matched. The filter now applies only to the default `**/*`-style globs: a bare/omitted `include` still matches only TS/JS, while an entry naming an explicit extension matches verbatim. This lets a `.vue` (or other non-TS) file pick up the project's `paths`/`baseUrl`.

This file-matching rule is general (it applies to both the root tsconfig and referenced projects), so it is now documented as a standalone paragraph instead of being buried in the `references` section:

> Whether a `files`/`include` entry matches a file depends on its extension: by default only TypeScript files (`.ts`/`.tsx`/`.mts`/`.cts`) match, plus `.js`/`.jsx`/`.mjs`/`.cjs` when `allowJs` is enabled. An entry that names an explicit extension (for example `src/**/*.vue`) matches that extension verbatim, so a non-TS file can be owned by the project and pick up its `paths`/`baseUrl`.
shulaoda added a commit to rolldown/rolldown that referenced this pull request Jun 18, 2026
## [1.1.2] - 2026-06-18

### 📝 Notable tsconfig behavior changes

These ship via the `oxc_resolver` 11.21.3 bump (#9841) and affect `resolve.tsconfigPaths` (Vite 8 resolves through oxc-resolver):

- **Honor explicit non-TS extensions in `include`** (oxc-project/oxc-resolver#1213). `compilerOptions.paths` now resolve for importers whose extension is explicitly listed in a tsconfig's `include` (e.g. `src/**/*.vue`, `src/**/*.svelte`). Previously oxc-resolver filtered importers by extension before evaluating the `include` globs, so a `.vue`/`.svelte` file listed in `include` never matched its project and its `paths` were skipped. This unblocks the default create-vite Vue + TS layout (a solution-style root plus a referenced `tsconfig.app.json` that declares `paths` and `include: ["src/**/*.ts", "src/**/*.vue"]`). Matches vue-tsc and svelte-check, which register these extensions via TypeScript's `extraFileExtensions`.
- **No fallback to the outermost tsconfig in auto-discovery** (oxc-project/oxc-resolver#1220). Auto-discovery no longer attaches the topmost ancestor `tsconfig.json` to a file that no project actually owns (via `files` / `include` / project references). Previously such a file inherited the outermost ancestor's `paths` / `baseUrl`, leaking aliases into files that project does not own. oxc-resolver now returns no config in that case, matching tsserver / typescript-go, which route such files to an inferred project with no aliases.

### 🚀 Features

- add option named for invalid return type errors for more places (#9846) by @shulaoda
- add option names for invalid return type errors (#9821) by @sapphi-red
- transform: infer decorator strictNullChecks from tsconfig (#9590) by @kylecannon
- expose React Compiler options for rolldown and Vite users (#9801) by @Boshen
- tracing: gate chrome-json trace layer behind `chrome-tracing` feature (#9773) by @hyf0
- dev: align test-dev-server with Vite dev server (#9668) by @h-a-n-a

### 🐛 Bug Fixes

- plugin_timings: point doc link to existing checks reference page (#9837) by @hyf0
- generator: correct contradictory panic message in cjs cross-chunk symbol lookup (#9836) by @hyf0
- esm: preserve with clause on export * from external (#9796) by @hyf0
- Make external_import_binding_merger deterministic (#9755) by @naruaway
- surface invalid `manualCodeSplitting` group `test` regex as an error (#9792) by @shulaoda
- avoid panic on `output.file` without a file name (#9789) by @shulaoda
- avoid O(N^2) rendering of high-volume diagnostics (#9748) (#9749) by @IWANABETHATGUY
- avoid panic on JSON numbers outside f64 range (#9788) by @shulaoda
- deps: bump mimalloc-safe to 0.1.63 to fix worker_threads segfault (#9785) by @shulaoda
- cache ESM evaluation errors (#9784) by @sapphi-red
- wrap node require helper in pure IIFE (#9783) by @kb019
- lazy-barrel: load locally-used imports on a re-exported record (#9757) by @shulaoda
- avoid dangling wrapped-ESM init call across chunks (#9502) (#9717) by @IWANABETHATGUY
- dev: detect same-second rewrites in CI poll watcher (#9736) by @h-a-n-a
- dev: force rebuild after HMR errors (#9686) by @h-a-n-a
- dev: print build errors on browser refresh after a failed build (#9652) by @h-a-n-a

### 🚜 Refactor

- single-source the chunk $N symbol-naming algorithm (#9831) by @Dunqing
- simplify common_dir helper (#9857) by @IWANABETHATGUY
- drop commondir crate in favor of in-house helper (#9849) by @Boshen
- binding: extract helpers from normalize_binding_options (#9842) by @Boshen
- move rolldown_filter_analyzer to tasks and scope oxc cfg feature (#9839) by @Boshen
- options: merge manualCodeSplitting into codeSplitting object form (#9805) by @IWANABETHATGUY
- options: support codeSplitting object form in CodeSplittingMode (#9804) by @IWANABETHATGUY
- diagnostic: reuse ByteLocator for per-source line lookup (#9762) by @IWANABETHATGUY
- remove redundant Arc around tracing spans (#9778) by @camc314
- remove unnecessary `Arc` around sourcemap sender (#9777) by @camc314
- rolldown_plugin_vite_wasm_fallback: remove the plugin (#9775) by @sapphi-red
- binding: remove infer-able `napi(ts_type)` (#9737) by @sapphi-red
- remove preprocessor span dedup (#9734) by @hyf0
- identify AST nodes by NodeId instead of Span/Address (#9609) by @IWANABETHATGUY

### 📚 Documentation

- tsconfig: align auto-discovery docs with oxc-resolver behavior (#9845) by @shulaoda
- relocate meta/design to internal-docs, split design from implementation (#9826) by @h-a-n-a
- meta: add options normalization design doc (#9818) by @IWANABETHATGUY
- document why the napi tracing feature is enabled (#9766) by @Boshen
- dev: move test-dev-server test guidance into the testing docs (#9809) by @h-a-n-a

### ⚡ Performance

- drop unused regex unicode property tables from the binding (#9848) by @Boshen
- drop urlencoding crate in favor of percent-encoding (#9851) by @Boshen
- drop owo-colors supports-colors feature in vite reporter (#9824) by @Boshen
- skip enum member value extraction for non-TypeScript modules (#9840) by @shulaoda
- rolldown: use unstable sort for itertools sorted_by at unique-key sites (#9827) by @Boshen
- cheaper deterministic ordering in external import binding merger (#9810) by @IWANABETHATGUY
- disable idna's ICU backend by pinning idna_adapter to 1.0.0 (-129 KB) (#9811) by @Boshen
- size: use unstable sort where stability is unneeded (#9803) by @Boshen
- remove num-format dependency from vite reporter (#9795) by @Boshen
- reduce js callback error size (#9776) by @Boshen
- rolldown_error: remove Debug supertrait from BuildEvent (#9798) by @Boshen
- reduce plugin hook order code size (#9761) by @Boshen
- deps: disable `infer` default features to reduce binary size (#9765) by @Boshen
- reduce pluginable monomorphization size (#9771) by @Boshen
- avoid rebuilding replace plugin values (#9764) by @Boshen
- defer link-stage-output drop to rayon workers after output is produced (#9733) by @Brooooooklyn
- tree-shaking: hoist already-included guard to call sites in inclusion DFS (#9738) by @Brooooooklyn
- renamer: dedup before allocating the owned name in add_symbol_in_root_scope (#9740) by @Brooooooklyn

### 🧪 Testing

- allocs: track allocation counts for rolldown_sourcemap (#9835) by @hyf0
- bench: add CodSpeed micro-benchmarks for rolldown_sourcemap (#9834) by @hyf0
- add cjs named export mutation test (#9823) by @sapphi-red
- dev: restore shared-page reliability conventions in AGENTS.md (#9786) by @h-a-n-a
- dev: add `AGENTS.md` test guidance for agents (#9763) by @h-a-n-a
- dev: split out initial-build-error into its own playground (#9772) by @h-a-n-a
- dev: align e2e suite with Vite and parallelize playgrounds (#9759) by @h-a-n-a
- remove unnecessary module namespace object JSON serializations in tests (#9725) by @sapphi-red
- use `assert.deepStrictEqual` instead of `assert.deepEqual` by using `assert/strict` instead of `assert` (#9724) by @sapphi-red
- hmr: add test case for #5301 (#5302) by @sapphi-red
- dev: add tests for dev-engine principles (#9720) by @h-a-n-a
- dev: align dev-engine test harness with Vite (#9684) by @h-a-n-a

### ⚙️ Miscellaneous Tasks

- deps: update napi to 3.9.3 (#9862) by @shulaoda
- deps: update oxc to 0.137.0 (#9856) by @Boshen
- re-enable default lld linker on x86_64-unknown-linux-gnu (#9855) by @Boshen
- deps: bump vite-plus to 0.2.1 (#9850) by @Boshen
- skills: translate _config.json when encoding rolldown REPL links (#9847) by @IWANABETHATGUY
- deps: update oxc_resolver and oxc_resolver_napi to 11.21.3 (#9841) by @Boshen
- pin vite-plus (vp) CLI to 0.1.24 in setup-vp (#9830) by @Boshen
- add crate/package-level CODEOWNERS (#9819) by @IWANABETHATGUY
- drop unused derive_more display feature from rolldown_plugin (#9820) by @Boshen
- remove auto-assign PR workflow (#9807) by @IWANABETHATGUY
- deps: update rollup submodule for tests to v4.62.0 (#9780) by @rolldown-guard[bot]
- deps: update esbuild for tests to 0.28.1 (#9779) by @rolldown-guard[bot]
- deps: update test262 submodule for tests (#9781) by @rolldown-guard[bot]
- deps: update oxc to 0.136.0 (#9770) by @Boshen
- add pull request template (#9756) by @sapphi-red
- clarify `rolldown_plugin_vite_*` is compatible for the same minor (#9774) by @sapphi-red
- deps: update github actions (#9745) by @renovate[bot]
- deps: update rust crates (#9747) by @renovate[bot]
- deps: update napi to v3.9.2 (#9744) by @renovate[bot]
- deps: update npm packages (#9746) by @renovate[bot]
- deps: update @napi-rs/cli and emnapi deps (#9741) by @Brooooooklyn
- generator: fix `vp fmt` on Windows (#9727) by @sapphi-red
- ban importing from `assert` and recommend `assert/strict` (#9726) by @sapphi-red

### ❤️ New Contributors

* @naruaway made their first contribution in [#9755](#9755)
* @kb019 made their first contribution in [#9783](#9783)

Co-authored-by: shulaoda <165626830+shulaoda@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.

2 participants