4
4
AmbientModuleDeclaration ,
5
5
append ,
6
6
arrayFrom ,
7
+ changeFullExtension ,
7
8
CharacterCodes ,
8
9
combinePaths ,
9
10
compareBooleans ,
@@ -59,6 +60,7 @@ import {
59
60
getSupportedExtensions ,
60
61
getTemporaryModuleResolutionState ,
61
62
getTextOfIdentifierOrLiteral ,
63
+ hasImplementationTSFileExtension ,
62
64
hasJSFileExtension ,
63
65
hasTSFileExtension ,
64
66
hostGetCanonicalFileName ,
@@ -599,7 +601,16 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt
599
601
return pathsOnly ? undefined : relativePath ;
600
602
}
601
603
602
- const fromPackageJsonImports = pathsOnly ? undefined : tryGetModuleNameFromPackageJsonImports ( moduleFileName , sourceDirectory , compilerOptions , host , importMode ) ;
604
+ const fromPackageJsonImports = pathsOnly
605
+ ? undefined
606
+ : tryGetModuleNameFromPackageJsonImports (
607
+ moduleFileName ,
608
+ sourceDirectory ,
609
+ compilerOptions ,
610
+ host ,
611
+ importMode ,
612
+ prefersTsExtension ( allowedEndings ) ,
613
+ ) ;
603
614
604
615
const fromPaths = pathsOnly || fromPackageJsonImports === undefined ? paths && tryGetModuleNameFromPaths ( relativeToBaseUrl , paths , allowedEndings , host , compilerOptions ) : undefined ;
605
616
if ( pathsOnly ) {
@@ -997,7 +1008,18 @@ const enum MatchingMode {
997
1008
Pattern ,
998
1009
}
999
1010
1000
- function tryGetModuleNameFromExportsOrImports ( options : CompilerOptions , host : ModuleSpecifierResolutionHost , targetFilePath : string , packageDirectory : string , packageName : string , exports : unknown , conditions : string [ ] , mode : MatchingMode , isImports : boolean ) : { moduleFileToTry : string ; } | undefined {
1011
+ function tryGetModuleNameFromExportsOrImports (
1012
+ options : CompilerOptions ,
1013
+ host : ModuleSpecifierResolutionHost ,
1014
+ targetFilePath : string ,
1015
+ packageDirectory : string ,
1016
+ packageName : string ,
1017
+ exports : unknown ,
1018
+ conditions : string [ ] ,
1019
+ mode : MatchingMode ,
1020
+ isImports : boolean ,
1021
+ preferTsExtension : boolean ,
1022
+ ) : { moduleFileToTry : string ; } | undefined {
1001
1023
if ( typeof exports === "string" ) {
1002
1024
const ignoreCase = ! hostUsesCaseSensitiveFileNames ( host ) ;
1003
1025
const getCommonSourceDirectory = ( ) => host . getCommonSourceDirectory ( ) ;
@@ -1006,6 +1028,7 @@ function tryGetModuleNameFromExportsOrImports(options: CompilerOptions, host: Mo
1006
1028
1007
1029
const pathOrPattern = getNormalizedAbsolutePath ( combinePaths ( packageDirectory , exports ) , /*currentDirectory*/ undefined ) ;
1008
1030
const extensionSwappedTarget = hasTSFileExtension ( targetFilePath ) ? removeFileExtension ( targetFilePath ) + tryGetJSExtensionForFile ( targetFilePath , options ) : undefined ;
1031
+ const canTryTsExtension = preferTsExtension && hasImplementationTSFileExtension ( targetFilePath ) ;
1009
1032
1010
1033
switch ( mode ) {
1011
1034
case MatchingMode . Exact :
@@ -1019,11 +1042,15 @@ function tryGetModuleNameFromExportsOrImports(options: CompilerOptions, host: Mo
1019
1042
}
1020
1043
break ;
1021
1044
case MatchingMode . Directory :
1045
+ if ( canTryTsExtension && containsPath ( targetFilePath , pathOrPattern , ignoreCase ) ) {
1046
+ const fragment = getRelativePathFromDirectory ( pathOrPattern , targetFilePath , /*ignoreCase*/ false ) ;
1047
+ return { moduleFileToTry : getNormalizedAbsolutePath ( combinePaths ( combinePaths ( packageName , exports ) , fragment ) , /*currentDirectory*/ undefined ) } ;
1048
+ }
1022
1049
if ( extensionSwappedTarget && containsPath ( pathOrPattern , extensionSwappedTarget , ignoreCase ) ) {
1023
1050
const fragment = getRelativePathFromDirectory ( pathOrPattern , extensionSwappedTarget , /*ignoreCase*/ false ) ;
1024
1051
return { moduleFileToTry : getNormalizedAbsolutePath ( combinePaths ( combinePaths ( packageName , exports ) , fragment ) , /*currentDirectory*/ undefined ) } ;
1025
1052
}
1026
- if ( containsPath ( pathOrPattern , targetFilePath , ignoreCase ) ) {
1053
+ if ( ! canTryTsExtension && containsPath ( pathOrPattern , targetFilePath , ignoreCase ) ) {
1027
1054
const fragment = getRelativePathFromDirectory ( pathOrPattern , targetFilePath , /*ignoreCase*/ false ) ;
1028
1055
return { moduleFileToTry : getNormalizedAbsolutePath ( combinePaths ( combinePaths ( packageName , exports ) , fragment ) , /*currentDirectory*/ undefined ) } ;
1029
1056
}
@@ -1032,19 +1059,23 @@ function tryGetModuleNameFromExportsOrImports(options: CompilerOptions, host: Mo
1032
1059
return { moduleFileToTry : combinePaths ( packageName , fragment ) } ;
1033
1060
}
1034
1061
if ( declarationFile && containsPath ( pathOrPattern , declarationFile , ignoreCase ) ) {
1035
- const fragment = getRelativePathFromDirectory ( pathOrPattern , declarationFile , /*ignoreCase*/ false ) ;
1062
+ const fragment = changeFullExtension ( getRelativePathFromDirectory ( pathOrPattern , declarationFile , /*ignoreCase*/ false ) , getJSExtensionForFile ( declarationFile , options ) ) ;
1036
1063
return { moduleFileToTry : combinePaths ( packageName , fragment ) } ;
1037
1064
}
1038
1065
break ;
1039
1066
case MatchingMode . Pattern :
1040
1067
const starPos = pathOrPattern . indexOf ( "*" ) ;
1041
1068
const leadingSlice = pathOrPattern . slice ( 0 , starPos ) ;
1042
1069
const trailingSlice = pathOrPattern . slice ( starPos + 1 ) ;
1070
+ if ( canTryTsExtension && startsWith ( targetFilePath , leadingSlice , ignoreCase ) && endsWith ( targetFilePath , trailingSlice , ignoreCase ) ) {
1071
+ const starReplacement = targetFilePath . slice ( leadingSlice . length , targetFilePath . length - trailingSlice . length ) ;
1072
+ return { moduleFileToTry : replaceFirstStar ( packageName , starReplacement ) } ;
1073
+ }
1043
1074
if ( extensionSwappedTarget && startsWith ( extensionSwappedTarget , leadingSlice , ignoreCase ) && endsWith ( extensionSwappedTarget , trailingSlice , ignoreCase ) ) {
1044
1075
const starReplacement = extensionSwappedTarget . slice ( leadingSlice . length , extensionSwappedTarget . length - trailingSlice . length ) ;
1045
1076
return { moduleFileToTry : replaceFirstStar ( packageName , starReplacement ) } ;
1046
1077
}
1047
- if ( startsWith ( targetFilePath , leadingSlice , ignoreCase ) && endsWith ( targetFilePath , trailingSlice , ignoreCase ) ) {
1078
+ if ( ! canTryTsExtension && startsWith ( targetFilePath , leadingSlice , ignoreCase ) && endsWith ( targetFilePath , trailingSlice , ignoreCase ) ) {
1048
1079
const starReplacement = targetFilePath . slice ( leadingSlice . length , targetFilePath . length - trailingSlice . length ) ;
1049
1080
return { moduleFileToTry : replaceFirstStar ( packageName , starReplacement ) } ;
1050
1081
}
@@ -1054,20 +1085,22 @@ function tryGetModuleNameFromExportsOrImports(options: CompilerOptions, host: Mo
1054
1085
}
1055
1086
if ( declarationFile && startsWith ( declarationFile , leadingSlice , ignoreCase ) && endsWith ( declarationFile , trailingSlice , ignoreCase ) ) {
1056
1087
const starReplacement = declarationFile . slice ( leadingSlice . length , declarationFile . length - trailingSlice . length ) ;
1057
- return { moduleFileToTry : replaceFirstStar ( packageName , starReplacement ) } ;
1088
+ const substituted = replaceFirstStar ( packageName , starReplacement ) ;
1089
+ const jsExtension = tryGetJSExtensionForFile ( declarationFile , options ) ;
1090
+ return jsExtension ? { moduleFileToTry : changeFullExtension ( substituted , jsExtension ) } : undefined ;
1058
1091
}
1059
1092
break ;
1060
1093
}
1061
1094
}
1062
1095
else if ( Array . isArray ( exports ) ) {
1063
- return forEach ( exports , e => tryGetModuleNameFromExportsOrImports ( options , host , targetFilePath , packageDirectory , packageName , e , conditions , mode , isImports ) ) ;
1096
+ return forEach ( exports , e => tryGetModuleNameFromExportsOrImports ( options , host , targetFilePath , packageDirectory , packageName , e , conditions , mode , isImports , preferTsExtension ) ) ;
1064
1097
}
1065
1098
else if ( typeof exports === "object" && exports !== null ) { // eslint-disable-line no-restricted-syntax
1066
1099
// conditional mapping
1067
1100
for ( const key of getOwnKeys ( exports as MapLike < unknown > ) ) {
1068
1101
if ( key === "default" || conditions . indexOf ( key ) >= 0 || isApplicableVersionedTypesKey ( conditions , key ) ) {
1069
1102
const subTarget = ( exports as MapLike < unknown > ) [ key ] ;
1070
- const result = tryGetModuleNameFromExportsOrImports ( options , host , targetFilePath , packageDirectory , packageName , subTarget , conditions , mode , isImports ) ;
1103
+ const result = tryGetModuleNameFromExportsOrImports ( options , host , targetFilePath , packageDirectory , packageName , subTarget , conditions , mode , isImports , preferTsExtension ) ;
1071
1104
if ( result ) {
1072
1105
return result ;
1073
1106
}
@@ -1089,13 +1122,13 @@ function tryGetModuleNameFromExports(options: CompilerOptions, host: ModuleSpeci
1089
1122
const mode = endsWith ( k , "/" ) ? MatchingMode . Directory
1090
1123
: k . includes ( "*" ) ? MatchingMode . Pattern
1091
1124
: MatchingMode . Exact ;
1092
- return tryGetModuleNameFromExportsOrImports ( options , host , targetFilePath , packageDirectory , subPackageName , ( exports as MapLike < unknown > ) [ k ] , conditions , mode , /*isImports*/ false ) ;
1125
+ return tryGetModuleNameFromExportsOrImports ( options , host , targetFilePath , packageDirectory , subPackageName , ( exports as MapLike < unknown > ) [ k ] , conditions , mode , /*isImports*/ false , /*preferTsExtension*/ false ) ;
1093
1126
} ) ;
1094
1127
}
1095
- return tryGetModuleNameFromExportsOrImports ( options , host , targetFilePath , packageDirectory , packageName , exports , conditions , MatchingMode . Exact , /*isImports*/ false ) ;
1128
+ return tryGetModuleNameFromExportsOrImports ( options , host , targetFilePath , packageDirectory , packageName , exports , conditions , MatchingMode . Exact , /*isImports*/ false , /*preferTsExtension*/ false ) ;
1096
1129
}
1097
1130
1098
- function tryGetModuleNameFromPackageJsonImports ( moduleFileName : string , sourceDirectory : string , options : CompilerOptions , host : ModuleSpecifierResolutionHost , importMode : ResolutionMode ) {
1131
+ function tryGetModuleNameFromPackageJsonImports ( moduleFileName : string , sourceDirectory : string , options : CompilerOptions , host : ModuleSpecifierResolutionHost , importMode : ResolutionMode , preferTsExtension : boolean ) {
1099
1132
if ( ! host . readFile || ! getResolvePackageJsonImports ( options ) ) {
1100
1133
return undefined ;
1101
1134
}
@@ -1120,7 +1153,7 @@ function tryGetModuleNameFromPackageJsonImports(moduleFileName: string, sourceDi
1120
1153
const mode = endsWith ( k , "/" ) ? MatchingMode . Directory
1121
1154
: k . includes ( "*" ) ? MatchingMode . Pattern
1122
1155
: MatchingMode . Exact ;
1123
- return tryGetModuleNameFromExportsOrImports ( options , host , moduleFileName , ancestorDirectoryWithPackageJson , k , ( imports as MapLike < unknown > ) [ k ] , conditions , mode , /*isImports*/ true ) ;
1156
+ return tryGetModuleNameFromExportsOrImports ( options , host , moduleFileName , ancestorDirectoryWithPackageJson , k , ( imports as MapLike < unknown > ) [ k ] , conditions , mode , /*isImports*/ true , preferTsExtension ) ;
1124
1157
} ) ?. moduleFileToTry ;
1125
1158
}
1126
1159
@@ -1221,7 +1254,15 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
1221
1254
const packageName = getPackageNameFromTypesPackageName ( nodeModulesDirectoryName ) ;
1222
1255
const conditions = getConditions ( options , importMode ) ;
1223
1256
const fromExports = packageJsonContent ?. exports
1224
- ? tryGetModuleNameFromExports ( options , host , path , packageRootPath , packageName , packageJsonContent . exports , conditions )
1257
+ ? tryGetModuleNameFromExports (
1258
+ options ,
1259
+ host ,
1260
+ path ,
1261
+ packageRootPath ,
1262
+ packageName ,
1263
+ packageJsonContent . exports ,
1264
+ conditions ,
1265
+ )
1225
1266
: undefined ;
1226
1267
if ( fromExports ) {
1227
1268
return { ...fromExports , verbatimFromExports : true } ;
@@ -1411,3 +1452,8 @@ function isPathRelativeToParent(path: string): boolean {
1411
1452
function getDefaultResolutionModeForFile ( file : Pick < SourceFile , "fileName" | "impliedNodeFormat" | "packageJsonScope" > , host : Pick < ModuleSpecifierResolutionHost , "getDefaultResolutionModeForFile" > , compilerOptions : CompilerOptions ) {
1412
1453
return isFullSourceFile ( file ) ? host . getDefaultResolutionModeForFile ( file ) : getDefaultResolutionModeForFileWorker ( file , compilerOptions ) ;
1413
1454
}
1455
+
1456
+ function prefersTsExtension ( allowedEndings : readonly ModuleSpecifierEnding [ ] ) {
1457
+ const tsPriority = allowedEndings . indexOf ( ModuleSpecifierEnding . TsExtension ) ;
1458
+ return tsPriority > - 1 && tsPriority < allowedEndings . indexOf ( ModuleSpecifierEnding . JsExtension ) ;
1459
+ }
0 commit comments