Skip to content

feat(tsconfig): support package.json imports field in extends#1199

Merged
graphite-app[bot] merged 1 commit into
mainfrom
feat/tsconfig-extends-imports
Jun 3, 2026
Merged

feat(tsconfig): support package.json imports field in extends#1199
graphite-app[bot] merged 1 commit into
mainfrom
feat/tsconfig-extends-imports

Conversation

@Boshen

@Boshen Boshen commented Jun 3, 2026

Copy link
Copy Markdown
Member

What

Resolve #-prefixed Node.js subpath imports in tsconfig extends through the nearest package.json imports field:

// package.json
{ "imports": { "#base": "./common.tsconfig.json" } }
// tsconfig.json
{ "extends": "#base" }

Previously this failed with TsconfigNotFound: get_extended_tsconfig_path only handled /, ./.., and bare package specifiers (the last via exports/node_modules, which never consults imports).

Why

TypeScript supports this — it's used in monorepos to avoid brittle ../../../tsconfig.json paths. Verified against typescript-go: tsgo --showConfig resolves the fixture to the same targets this PR asserts (#string → es2020, #conditional node-branch → es6).

Reported in rolldown/rolldown#9611 (labeled bug: upstream).

How

  • New Some(b'#') arm in get_extended_tsconfig_path that routes through load_package_imports — the same wrapper the resolver uses for require("#x"), so it gets the correct package-scope lookup (LOOKUP_PACKAGE_SCOPE) and result verification (resolve_esm_match).
  • Extracted tsconfig_extends_resolver so the # (imports) and bare-package (exports/node_modules) arms share one lookup config (conditions ["node", "import"]) — extends: "pkg" and extends: "#pkg" now agree on which condition wins.
  • An undefined #import (or a missing target) is reported as TsconfigNotFound, consistent with how a missing bare-package or relative extends target is reported — and with tsgo, which emits File '#missing' not found.

Tests

One fixture (fixtures/tsconfig/cases/extends-imports/) and one test (test_extend_imports) covering, via its package.json imports map:

  • #string → string target → target: ES2020
  • #conditional{ node, default } object → node wins over defaulttarget: ES2015
  • extends: "#missing" (not in imports) → TsconfigNotFound

All cross-checked against tsgo (es2020 / es6 / File '#missing' not found).

🤖 Generated with Claude Code

@codecov

codecov Bot commented Jun 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.15385% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.77%. Comparing base (86b3d0f) to head (4a9f78c).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
src/tsconfig_resolver.rs 96.15% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1199      +/-   ##
==========================================
- Coverage   93.77%   93.77%   -0.01%     
==========================================
  Files          22       22              
  Lines        4212     4227      +15     
==========================================
+ Hits         3950     3964      +14     
- Misses        262      263       +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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04a4896cb8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/tsconfig_resolver.rs
@Boshen Boshen force-pushed the feat/tsconfig-extends-imports branch from 04a4896 to ebe4f3c Compare June 3, 2026 08:33

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebe4f3c81a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/tsconfig_resolver.rs
@codspeed-hq

codspeed-hq Bot commented Jun 3, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚡ 1 improved benchmark
❌ 3 regressed benchmarks
✅ 17 untouched benchmarks
⏩ 5 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
resolver_real[multi-thread] 393.7 µs 413.6 µs -4.8%
pm/yarn-isolated 1.1 ms 1.1 ms -4.66%
pm/bun-flat 962.7 µs 993 µs -3.05%
pm/bun-isolated 1.2 ms 1.1 ms +6.11%

Tip

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


Comparing feat/tsconfig-extends-imports (4a9f78c) with main (1975bb5)2

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.

  2. No successful run was found on main (4a9f78c) during the generation of this report, so 1975bb5 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@Boshen Boshen force-pushed the feat/tsconfig-extends-imports branch 2 times, most recently from 5746f35 to cd1f0f2 Compare June 3, 2026 08:54
@Boshen Boshen added the merge label Jun 3, 2026

Boshen commented Jun 3, 2026

Copy link
Copy Markdown
Member Author

Merge activity

## What

Resolve `#`-prefixed Node.js subpath imports in tsconfig `extends` through the nearest `package.json` `imports` field:

```jsonc
// package.json
{ "imports": { "#base": "./common.tsconfig.json" } }
// tsconfig.json
{ "extends": "#base" }
```

Previously this failed with `TsconfigNotFound`: `get_extended_tsconfig_path` only handled `/`, `.`/`..`, and bare package specifiers (the last via `exports`/`node_modules`, which never consults `imports`).

## Why

TypeScript supports this — it's used in monorepos to avoid brittle `../../../tsconfig.json` paths. Verified against `typescript-go`: `tsgo --showConfig` resolves the fixture to the same targets this PR asserts (`#string` → es2020, `#conditional` node-branch → es6).

Reported in rolldown/rolldown#9611 (labeled `bug: upstream`).

## How

- New `Some(b'#')` arm in `get_extended_tsconfig_path` that routes through `load_package_imports` — the same wrapper the resolver uses for `require("#x")`, so it gets the correct package-scope lookup (`LOOKUP_PACKAGE_SCOPE`) and result verification (`resolve_esm_match`).
- Extracted `tsconfig_extends_resolver` so the `#` (imports) and bare-package (`exports`/`node_modules`) arms share one lookup config (conditions `["node", "import"]`) — `extends: "pkg"` and `extends: "#pkg"` now agree on which condition wins.
- An undefined `#import` (or a missing target) is reported as `TsconfigNotFound`, consistent with how a missing bare-package or relative `extends` target is reported — and with `tsgo`, which emits `File '#missing' not found`.

## Tests

One fixture (`fixtures/tsconfig/cases/extends-imports/`) and one test (`test_extend_imports`) covering, via its `package.json` `imports` map:

- `#string` → string target → `target: ES2020`
- `#conditional` → `{ node, default }` object → `node` wins over `default` → `target: ES2015`
- `extends: "#missing"` (not in `imports`) → `TsconfigNotFound`

All cross-checked against `tsgo` (es2020 / es6 / `File '#missing' not found`).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@graphite-app graphite-app Bot force-pushed the feat/tsconfig-extends-imports branch from cd1f0f2 to 4a9f78c Compare June 3, 2026 09:11
@graphite-app graphite-app Bot merged commit 4a9f78c into main Jun 3, 2026
18 checks passed
@graphite-app graphite-app Bot removed the merge label Jun 3, 2026
@graphite-app graphite-app Bot deleted the feat/tsconfig-extends-imports branch June 3, 2026 09:15
@oxc-guard oxc-guard Bot mentioned this pull request Jun 3, 2026
Boshen pushed a commit that referenced this pull request Jun 3, 2026
## 🤖 New release

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

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

## `oxc_resolver`

<blockquote>

##
[11.21.0](v11.20.0...v11.21.0)
- 2026-06-03

### <!-- 0 -->🚀 Features

- *(tsconfig)* support package.json imports field in extends
([#1199](#1199)) (by
@Boshen)

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

- *(tsconfig)* apply each referenced project's own `allowJs`
([#1198](#1198)) (by
@shulaoda)
- make symlink_metadata VPath-aware for Yarn PnP
([#1183](#1183)) (by
@Boshen)

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

- borrow relative main field instead of allocating a "./" prefix
([#1187](#1187)) (by
@Boshen)
- *(cache)* move package.json path into parse instead of cloning
([#1186](#1186)) (by
@Boshen)
- eliminate symlink stat syscalls by reusing canonicalization
([#1184](#1184)) (by
@Boshen)
- reduce resolution syscalls by unifying stat and lstat
([#1182](#1182)) (by
@Boshen)

### <!-- 9 -->💼 Other

- add baselines for each package manager x node_modules layout
([#1176](#1176)) (by
@Boshen)

### Contributors

* @shulaoda
* @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.

1 participant