Skip to content

Commit 0ee2db3

Browse files
authored
Fix declaration emit in --moduleResolution bundler using wrong exports conditions (#56265)
1 parent 60ce788 commit 0ee2db3

File tree

5 files changed

+87
-18
lines changed

5 files changed

+87
-18
lines changed

Diff for: src/compiler/moduleNameResolver.ts

+10-15
Original file line numberDiff line numberDiff line change
@@ -585,10 +585,8 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string
585585
if (resolutionMode === ModuleKind.ESNext && (ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext)) {
586586
features |= NodeResolutionFeatures.EsmMode;
587587
}
588-
// true: "import" / false: "require" / undefined: default based on settings
589-
const useImportCondition = resolutionMode === ModuleKind.ESNext || (resolutionMode !== undefined ? false : undefined);
590588
const conditions = (features & NodeResolutionFeatures.Exports)
591-
? getConditions(options, useImportCondition)
589+
? getConditions(options, resolutionMode)
592590
: [];
593591
const diagnostics: Diagnostic[] = [];
594592
const moduleResolutionState: ModuleResolutionState = {
@@ -744,16 +742,13 @@ function getNodeResolutionFeatures(options: CompilerOptions) {
744742
return features;
745743
}
746744

747-
/**
748-
* @param overrideResolutionModeAttribute
749-
* @internal
750-
*/
751-
export function getConditions(options: CompilerOptions, esmMode?: boolean) {
745+
/** @internal */
746+
export function getConditions(options: CompilerOptions, resolutionMode?: ResolutionMode) {
752747
const moduleResolution = getEmitModuleResolutionKind(options);
753-
if (esmMode === undefined) {
748+
if (resolutionMode === undefined) {
754749
if (moduleResolution === ModuleResolutionKind.Bundler) {
755750
// bundler always uses `import` unless explicitly overridden
756-
esmMode ??= moduleResolution === ModuleResolutionKind.Bundler;
751+
resolutionMode = ModuleKind.ESNext;
757752
}
758753
else if (moduleResolution === ModuleResolutionKind.Node10) {
759754
// node10 does not support package.json imports/exports without
@@ -764,7 +759,7 @@ export function getConditions(options: CompilerOptions, esmMode?: boolean) {
764759
}
765760
// conditions are only used by the node16/nodenext/bundler resolvers - there's no priority order in the list,
766761
// it's essentially a set (priority is determined by object insertion order in the object we look at).
767-
const conditions = esmMode
762+
const conditions = resolutionMode === ModuleKind.ESNext
768763
? ["import"]
769764
: ["require"];
770765
if (!options.noDtsResolution) {
@@ -1439,13 +1434,13 @@ export function resolveModuleName(moduleName: string, containingFile: string, co
14391434
result = nodeNextModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode);
14401435
break;
14411436
case ModuleResolutionKind.Node10:
1442-
result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode ? getConditions(compilerOptions, resolutionMode === ModuleKind.ESNext) : undefined);
1437+
result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode ? getConditions(compilerOptions, resolutionMode) : undefined);
14431438
break;
14441439
case ModuleResolutionKind.Classic:
14451440
result = classicNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference);
14461441
break;
14471442
case ModuleResolutionKind.Bundler:
1448-
result = bundlerModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode ? getConditions(compilerOptions, resolutionMode === ModuleKind.ESNext) : undefined);
1443+
result = bundlerModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode ? getConditions(compilerOptions, resolutionMode) : undefined);
14491444
break;
14501445
default:
14511446
return Debug.fail(`Unexpected moduleResolution: ${moduleResolution}`);
@@ -1813,7 +1808,7 @@ function nodeModuleNameResolverWorker(
18131808
compilerOptions,
18141809
moduleResolution === ModuleResolutionKind.Bundler || moduleResolution === ModuleResolutionKind.Node10
18151810
? undefined
1816-
: !!(features & NodeResolutionFeatures.EsmMode),
1811+
: (features & NodeResolutionFeatures.EsmMode) ? ModuleKind.ESNext : ModuleKind.CommonJS,
18171812
);
18181813

18191814
const diagnostics: Diagnostic[] = [];
@@ -2225,7 +2220,7 @@ export function getEntrypointsFromPackageJsonInfo(
22252220

22262221
if (features & NodeResolutionFeatures.Exports && packageJsonInfo.contents.packageJsonContent.exports) {
22272222
const conditionSets = deduplicate(
2228-
[getConditions(options, /*esmMode*/ true), getConditions(options, /*esmMode*/ false)],
2223+
[getConditions(options, ModuleKind.ESNext), getConditions(options, ModuleKind.CommonJS)],
22292224
arrayIsEqualTo,
22302225
);
22312226
for (const conditions of conditionSets) {

Diff for: src/compiler/moduleSpecifiers.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
992992
// use the actual directory name, so don't look at `packageJsonContent.name` here.
993993
const nodeModulesDirectoryName = packageRootPath.substring(parts.topLevelPackageNameIndex + 1);
994994
const packageName = getPackageNameFromTypesPackageName(nodeModulesDirectoryName);
995-
const conditions = getConditions(options, importMode === ModuleKind.ESNext);
995+
const conditions = getConditions(options, importMode);
996996
const fromExports = packageJsonContent.exports
997997
? tryGetModuleNameFromExports(options, path, packageRootPath, packageName, packageJsonContent.exports, conditions)
998998
: undefined;

Diff for: src/services/stringCompletions.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ import {
9696
LiteralTypeNode,
9797
mapDefined,
9898
MapLike,
99-
ModuleKind,
10099
moduleResolutionUsesNodeModules,
101100
ModuleSpecifierEnding,
102101
moduleSpecifiers,
@@ -952,7 +951,7 @@ function getCompletionEntriesForNonRelativeModules(
952951
}
953952
const keys = getOwnKeys(exports);
954953
const fragmentSubpath = components.join("/") + (components.length && hasTrailingDirectorySeparator(fragment) ? "/" : "");
955-
const conditions = getConditions(compilerOptions, mode === ModuleKind.ESNext);
954+
const conditions = getConditions(compilerOptions, mode);
956955
addCompletionEntriesFromPathsOrExports(
957956
result,
958957
fragmentSubpath,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [tests/cases/compiler/declarationEmitBundlerConditions.ts] ////
2+
3+
//// [package.json]
4+
{
5+
"name": "pkg",
6+
"type": "module",
7+
"exports": {
8+
".": {
9+
"import": "./index.js",
10+
"require": "./index.cjs"
11+
}
12+
}
13+
}
14+
15+
//// [index.d.ts]
16+
export declare class C {
17+
private p;
18+
}
19+
20+
//// [index.d.cts]
21+
export {};
22+
23+
//// [makeC.ts]
24+
import { C } from "pkg";
25+
export function makeC() {
26+
return new C();
27+
}
28+
29+
//// [index.ts]
30+
import { makeC } from "./makeC";
31+
export const c = makeC();
32+
33+
34+
35+
36+
//// [makeC.d.ts]
37+
import { C } from "pkg";
38+
export declare function makeC(): C;
39+
//// [index.d.ts]
40+
export declare const c: import("pkg").C;
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// @module: esnext
2+
// @moduleResolution: bundler
3+
// @declaration: true
4+
// @emitDeclarationOnly: true
5+
// @noTypesAndSymbols: true
6+
7+
// @Filename: /node_modules/pkg/package.json
8+
{
9+
"name": "pkg",
10+
"type": "module",
11+
"exports": {
12+
".": {
13+
"import": "./index.js",
14+
"require": "./index.cjs"
15+
}
16+
}
17+
}
18+
19+
// @Filename: /node_modules/pkg/index.d.ts
20+
export declare class C {
21+
private p;
22+
}
23+
24+
// @Filename: /node_modules/pkg/index.d.cts
25+
export {};
26+
27+
// @Filename: /makeC.ts
28+
import { C } from "pkg";
29+
export function makeC() {
30+
return new C();
31+
}
32+
33+
// @Filename: /index.ts
34+
import { makeC } from "./makeC";
35+
export const c = makeC();

0 commit comments

Comments
 (0)