Skip to content

Apply extensionAlias to imports-field resolutions#549

Merged
alexander-akait merged 3 commits intomainfrom
claude/review-issue-413-rygbg
Apr 22, 2026
Merged

Apply extensionAlias to imports-field resolutions#549
alexander-akait merged 3 commits intomainfrom
claude/review-issue-413-rygbg

Conversation

@alexander-akait
Copy link
Copy Markdown
Member

Summary

Closes part of #413 (the imports field half).

extensionAlias is tapped on raw-resolve and keys off request.request. When a request is resolved through the package.json imports field, ImportsFieldPlugin bypasses raw-resolve and hands off to the relative hook with request: undefined (only request.path is set), so TypeScript-style extension substitution (.js.ts) never fires for internal subpath imports like #foo. This made extensionAlias unusable together with the imports field — the exact setup eslint-import-resolver-typescript needs.

Unlike the exports field, the imports field is internal to the package, so applying the consumer's aliases does not expose files the package author never meant to expose (the concern raised in #355 / #413). For that reason this enables the behavior by default for imports only; the exports side can still be discussed as an opt-in later.

Before

// package.json: { "imports": { "#foo": "./foo.js" } }
// files: foo.ts, foo.js
resolve({ extensionAlias: { ".js": [".ts", ".js"] } }, dir, "#foo")
// -> foo.js  (extensionAlias ignored)

resolve({ extensionAlias: { ".js": [".ts", ".js"] } }, dir, "./foo.js")
// -> foo.ts  (works, asymmetric)

After

resolve({ extensionAlias: { ".js": [".ts", ".js"] } }, dir, "#foo")
// -> foo.ts  (consistent with ./foo.js)

Changes

  • ExtensionAliasPlugin: handle both the existing "request" mode (specifier-based) and a new "path" mode (when request.request === undefined, operate on request.path / request.relativePath).
  • ResolverFactory: introduce an imports-field-relative hook between ImportsFieldPlugin and relative, tap per-alias plugins there, and forward to relative by default via NextPlugin. ExportsFieldPlugin is left untouched.
  • Tests: 4 new cases in test/extension-alias.test.js covering the primary alias, fallback to later alternatives, strict (no-fallback) mapping, and single-string alias.

Test plan

  • npx jest — 996 passing (992 before + 4 new)
  • npx jest test/extension-alias.test.js — 12 passing
  • npx tsc — clean
  • npx eslint lib/ExtensionAliasPlugin.js lib/ResolverFactory.js test/extension-alias.test.js — clean
  • Manual check: exports-field resolution (self-ref/foofoo.js) unchanged

https://claude.ai/code/session_01JGjZtthJN27rDbRPUAPjQh


Generated by Claude Code

When a request goes through the package.json "imports" field (e.g.
`#foo` -> `./foo.js`), the resolver skipped `raw-resolve` where the
`extensionAlias` plugin is tapped, so TypeScript-style extension
substitution (`.js` -> `.ts`) never fired for internal subpath
imports. This made it impossible to use `extensionAlias` together
with the imports field, which is what TypeScript projects need
when their imports map to `.js` targets but the actual source is `.ts`.

The imports field is internal to the package, so applying the
consumer's aliases does not expose files the package author never
intended to expose -- unlike the exports field, where the same
change would cross a trust boundary (see issue #355 / #413).

Changes:
- Teach ExtensionAliasPlugin to also operate on `request.path` /
  `request.relativePath` when the specifier has already been joined
  (i.e. `request.request === undefined`).
- Introduce an `imports-field-relative` hook between
  ImportsFieldPlugin and the `relative` hook, tap per-alias plugins
  on it, and forward to `relative` by default.
- Leave the exports field untouched.

Fixes #413 for the imports-field case.
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented Apr 22, 2026

CLA Not Signed

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 22, 2026

🦋 Changeset detected

Latest commit: 418fd35

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
enhanced-resolve Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 22, 2026

Codecov Report

❌ Patch coverage is 95.23810% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 96.57%. Comparing base (ed92a94) to head (418fd35).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
lib/ExtensionAliasPlugin.js 94.11% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #549      +/-   ##
==========================================
- Coverage   96.58%   96.57%   -0.02%     
==========================================
  Files          50       50              
  Lines        2783     2800      +17     
  Branches      850      863      +13     
==========================================
+ Hits         2688     2704      +16     
- Misses         79       80       +1     
  Partials       16       16              
Flag Coverage Δ
integration 96.57% <95.23%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 22, 2026

Merging this PR will not alter performance

✅ 69 untouched benchmarks


Comparing claude/review-issue-413-rygbg (418fd35) with main (ed92a94)

Open in CodSpeed

claude and others added 2 commits April 22, 2026 19:14
Reflects the change that extensionAlias now applies to paths
resolved via the imports field:

- Note the behavior and the exports-field carve-out on the
  extensionAlias option docs.
- Update ExtensionAliasPlugin and ImportsFieldPlugin wiring lines.
- Add imports-field-relative to the pipeline hooks table.
- Extend the "internal import" flow diagram to show the
  relative-target branch through imports-field-relative.
@alexander-akait alexander-akait merged commit 8757f67 into main Apr 22, 2026
31 of 34 checks passed
@alexander-akait alexander-akait deleted the claude/review-issue-413-rygbg branch April 22, 2026 19:33
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