Skip to content

feat: add DTS resolver matching TypeScript's bundler mode#997

Open
Boshen wants to merge 1 commit intomainfrom
feat/dts-resolver
Open

feat: add DTS resolver matching TypeScript's bundler mode#997
Boshen wants to merge 1 commit intomainfrom
feat/dts-resolver

Conversation

@Boshen
Copy link
Member

@Boshen Boshen commented Feb 6, 2026

Summary

  • Add resolve_dts() method to ResolverGeneric implementing TypeScript's ts.resolveModuleName with moduleResolution: "bundler" algorithm
  • Two-pass node_modules walk: all ancestors for TS/DTS + @types before trying JS — fixes the fundamental algorithmic difference that JS workarounds can't address
  • @types scoped name mangling (@babel/core@types/babel__core)
  • TypeScript extension substitution (.js.ts, .d.ts) following TS priority order
  • typesVersions package.json field support
  • exports field absolute priority (blocks types/typings/main when present)
  • NAPI bindings: resolveDtsSync / resolveDtsAsync
  • 20 test cases covering relative resolution, extension substitution/priority, directory modules, @types, exports, typesVersions, typings field, and name mangling

Closes #549

🤖 Generated with Claude Code

…ler"`

Add `resolve_dts()` method to `ResolverGeneric` that implements TypeScript's
`ts.resolveModuleName` algorithm for declaration file resolution. This replaces
the need for JS workarounds that configure enhanced-resolve with DTS-friendly
options but can't match TypeScript's actual resolution behavior.

Key features:
- Two-pass node_modules walk: TS/DTS + @types before JS
- @types scoped name mangling (@babel/core -> @types/babel__core)
- TypeScript extension substitution (.js -> .ts, .d.ts)
- typesVersions package.json field support
- exports field absolute priority (blocks types/typings/main)
- NAPI bindings: resolveDtsSync / resolveDtsAsync

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

❌ Patch coverage is 75.18797% with 132 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.62%. Comparing base (a644254) to head (9e682ba).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
src/dts_resolver.rs 74.11% 132 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #997      +/-   ##
==========================================
- Coverage   94.02%   91.62%   -2.41%     
==========================================
  Files          17       18       +1     
  Lines        3348     3880     +532     
==========================================
+ Hits         3148     3555     +407     
- Misses        200      325     +125     

☔ 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

codspeed-hq bot commented Feb 6, 2026

Merging this PR will not alter performance

✅ 12 untouched benchmarks
⏩ 5 skipped benchmarks1


Comparing feat/dts-resolver (9e682ba) with main (42b7ef4)

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 requested a review from Copilot February 6, 2026 09:42
@Boshen Boshen marked this pull request as ready for review February 6, 2026 09:42
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a DTS resolver that implements TypeScript's ts.resolveModuleName with moduleResolution: "bundler" algorithm. The implementation addresses a critical gap for tools like rolldown-plugin-dts that need to inline and bundle type declarations, and solves numerous edge cases that cannot be handled by workarounds using the existing JavaScript resolver.

Changes:

  • Implements a new resolve_dts() method with TypeScript-specific resolution logic including two-pass node_modules walk, @types scoped name mangling, TypeScript extension substitution, typesVersions support, and proper exports field handling
  • Adds package.json field accessors for types, typings, and typesVersions fields in both simd and serde implementations
  • Exposes resolveDtsSync and resolveDtsAsync methods through NAPI bindings with comprehensive documentation

Reviewed changes

Copilot reviewed 18 out of 41 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/dts_resolver.rs Core DTS resolution algorithm implementation with TypeScript-specific logic
src/tests/dts_resolver.rs Comprehensive test suite with 20 test cases covering relative resolution, extension priority, @types, exports, typesVersions, and name mangling
src/package_json/simd.rs Added types(), typings(), and types_versions() accessors for SIMD JSON parser
src/package_json/serde.rs Added types(), typings(), and types_versions() accessors for serde JSON parser
napi/src/lib.rs NAPI bindings for resolve_dts_sync and resolve_dts_async
napi/index.d.ts TypeScript type definitions for DTS resolution methods
src/tests/mod.rs Added dts_resolver test module
src/lib.rs Added dts_resolver module
fixtures/dts_resolver/* Test fixtures for DTS resolution scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

/// `specifier` is the module specifier string.
///
/// The resolver uses the existing `ResolveOptions` for:
/// - `condition_names` (used for `exports` resolution; `"types"` is always added)
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The documentation states that "types" is always added to condition_names, but this is not implemented in the code. Users must manually include "types" in their ResolveOptions.condition_names (as shown in the test at src/tests/dts_resolver.rs:13). Either update the documentation to reflect the actual behavior, or implement the automatic addition of "types" to condition_names when calling resolve_dts.

Copilot uses AI. Check for mistakes.
Comment on lines +390 to +432
let mut entry = if extensions.contains(Extensions::DECLARATION) {
pkg.typings().or_else(|| pkg.types())
} else {
None
};
if entry.is_none()
&& extensions.intersects(
Extensions::TYPESCRIPT
.union(Extensions::JAVASCRIPT)
.union(Extensions::DECLARATION),
)
{
entry = pkg.main_fields(&main_fields).next();
}

let vp_specifier = entry.unwrap_or("index");
if let Some(path) = self.dts_resolve_via_version_paths(
extensions,
vp_specifier,
candidate,
&version_paths,
ctx,
)? {
return Ok(Some(path));
}
}

// Determine entry file (types/typings/main)
if let Some(ref pkg) = pkg {
let mut entry = if extensions.contains(Extensions::DECLARATION) {
pkg.typings().or_else(|| pkg.types())
} else {
None
};
if entry.is_none()
&& extensions.intersects(
Extensions::TYPESCRIPT
.union(Extensions::JAVASCRIPT)
.union(Extensions::DECLARATION),
)
{
entry = pkg.main_fields(&main_fields).next();
}
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

There is duplicate logic for determining the entry field (types/typings/main). Lines 390-403 and 419-432 contain nearly identical code. Consider extracting this into a helper method to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
}
_ => {
// Unknown extensions like .vue, .svelte - return them for d.{ext}.ts handling
if !ext.is_empty() && ext.len() < 10 { Some(ext) } else { None }
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

Consider extracting the magic number 10 to a named constant like MAX_UNKNOWN_EXTENSION_LENGTH to improve code readability and make the intent clearer.

Copilot uses AI. Check for mistakes.
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.

DTS Resolver

1 participant