diff --git a/fixtures/dts_resolver/node_modules/exports-dts-for-mjs/dist/index.d.mts b/fixtures/dts_resolver/node_modules/exports-dts-for-mjs/dist/index.d.mts new file mode 100644 index 000000000..e69de29bb diff --git a/fixtures/dts_resolver/node_modules/exports-dts-for-mjs/dist/index.mjs b/fixtures/dts_resolver/node_modules/exports-dts-for-mjs/dist/index.mjs new file mode 100644 index 000000000..e69de29bb diff --git a/fixtures/dts_resolver/node_modules/exports-dts-for-mjs/package.json b/fixtures/dts_resolver/node_modules/exports-dts-for-mjs/package.json new file mode 100644 index 000000000..73b4eb685 --- /dev/null +++ b/fixtures/dts_resolver/node_modules/exports-dts-for-mjs/package.json @@ -0,0 +1,8 @@ +{ + "name": "exports-dts-for-mjs", + "exports": { + ".": { + "import": "./dist/index.mjs" + } + } +} diff --git a/fixtures/pnpm/package.json b/fixtures/pnpm/package.json index 43f842501..95bf810f7 100644 --- a/fixtures/pnpm/package.json +++ b/fixtures/pnpm/package.json @@ -7,6 +7,7 @@ "axios": "1.8.4", "decimal.js": "10.5.0", "ipaddr.js": "2.2.0", + "magic-string": "0.30.17", "mathjs": "14.4.0", "minimatch": "10.0.1", "postcss": "8.5.3", diff --git a/napi/tests/dts.test.mjs b/napi/tests/dts.test.mjs new file mode 100644 index 000000000..913677d6c --- /dev/null +++ b/napi/tests/dts.test.mjs @@ -0,0 +1,20 @@ +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { assert, test } from "vitest"; + +import { ResolverFactory } from "../index.js"; + +const currentDir = join(fileURLToPath(import.meta.url), ".."); +const rootDir = join(currentDir, "..", ".."); +const pnpmDir = join(rootDir, "fixtures", "pnpm"); + +const resolver = new ResolverFactory({ + conditionNames: ["import", "types"], +}); + +test("magic-string resolves to .d.mts", () => { + const containingFile = join(pnpmDir, "index.ts"); + const result = resolver.resolveDtsSync(containingFile, "magic-string"); + assert.isUndefined(result.error); + assert.match(result.path, /magic-string\.es\.d\.mts$/); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11bc0a758..b1838badc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: ipaddr.js: specifier: 2.2.0 version: 2.2.0 + magic-string: + specifier: 0.30.17 + version: 0.30.17 mathjs: specifier: 14.4.0 version: 14.4.0 @@ -1358,6 +1361,9 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -2573,6 +2579,10 @@ snapshots: dependencies: argparse: 2.0.1 + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 diff --git a/src/dts_resolver.rs b/src/dts_resolver.rs index 2fe303408..599b35e41 100644 --- a/src/dts_resolver.rs +++ b/src/dts_resolver.rs @@ -593,13 +593,16 @@ impl ResolverGeneric { } fn dts_resolve_esm_match(&self, cached_path: &CachedPath, ctx: &mut Ctx) -> Option { + // Try declaration/TS extension substitution first (e.g. .mjs -> .d.mts) + let extensions = Extensions::TYPESCRIPT.union(Extensions::DECLARATION); + if let Some(path) = self.dts_resolve_as_file(extensions, cached_path, ctx) { + return Some(path); + } + // Fall back to original file if it exists if self.cache.is_file(cached_path, ctx) { return Some(cached_path.clone()); } - // Try as file with TS extensions - let extensions = - Extensions::TYPESCRIPT.union(Extensions::DECLARATION).union(Extensions::JAVASCRIPT); - self.dts_resolve_as_file(extensions, cached_path, ctx) + None } // -------- @types name mangling -------- diff --git a/src/tests/dts_resolver.rs b/src/tests/dts_resolver.rs index 5b19d0c7f..f494dc43e 100644 --- a/src/tests/dts_resolver.rs +++ b/src/tests/dts_resolver.rs @@ -173,6 +173,19 @@ fn no_types_not_resolved() { assert_eq!(result.path(), dts_fixture().join("node_modules/no-types/index.js")); } +// -------- exports: ESM match finds declaration over JS -------- + +#[test] +fn exports_esm_match_finds_declaration() { + // When exports resolves to .mjs but .d.mts exists, prefer .d.mts + let r = resolver(); + let result = r.resolve_dts(containing_file(), "exports-dts-for-mjs").unwrap(); + assert_eq!( + result.path(), + dts_fixture().join("node_modules/exports-dts-for-mjs/dist/index.d.mts") + ); +} + // -------- @types name mangling -------- #[test]