@@ -105,7 +105,7 @@ namespace ts.moduleSpecifiers {
105
105
const info = getInfo ( importingSourceFile . path , host ) ;
106
106
const modulePaths = getAllModulePaths ( importingSourceFile . path , nodeModulesFileName , host , preferences , options ) ;
107
107
return firstDefined ( modulePaths ,
108
- modulePath => tryGetModuleNameAsNodeModule ( modulePath , info , importingSourceFile , host , compilerOptions , /*packageNameOnly*/ true , options . overrideImportMode ) ) ;
108
+ modulePath => tryGetModuleNameAsNodeModule ( modulePath , info , importingSourceFile , host , compilerOptions , preferences , /*packageNameOnly*/ true , options . overrideImportMode ) ) ;
109
109
}
110
110
111
111
function getModuleSpecifierWorker (
@@ -120,7 +120,7 @@ namespace ts.moduleSpecifiers {
120
120
) : string {
121
121
const info = getInfo ( importingSourceFileName , host ) ;
122
122
const modulePaths = getAllModulePaths ( importingSourceFileName , toFileName , host , userPreferences , options ) ;
123
- return firstDefined ( modulePaths , modulePath => tryGetModuleNameAsNodeModule ( modulePath , info , importingSourceFile , host , compilerOptions , /*packageNameOnly*/ undefined , options . overrideImportMode ) ) ||
123
+ return firstDefined ( modulePaths , modulePath => tryGetModuleNameAsNodeModule ( modulePath , info , importingSourceFile , host , compilerOptions , userPreferences , /*packageNameOnly*/ undefined , options . overrideImportMode ) ) ||
124
124
getLocalModuleSpecifier ( toFileName , info , compilerOptions , host , preferences ) ;
125
125
}
126
126
@@ -248,7 +248,7 @@ namespace ts.moduleSpecifiers {
248
248
let pathsSpecifiers : string [ ] | undefined ;
249
249
let relativeSpecifiers : string [ ] | undefined ;
250
250
for ( const modulePath of modulePaths ) {
251
- const specifier = tryGetModuleNameAsNodeModule ( modulePath , info , importingSourceFile , host , compilerOptions , /*packageNameOnly*/ undefined , options . overrideImportMode ) ;
251
+ const specifier = tryGetModuleNameAsNodeModule ( modulePath , info , importingSourceFile , host , compilerOptions , userPreferences , /*packageNameOnly*/ undefined , options . overrideImportMode ) ;
252
252
nodeModulesSpecifiers = append ( nodeModulesSpecifiers , specifier ) ;
253
253
if ( specifier && modulePath . isRedirect ) {
254
254
// If we got a specifier for a redirect, it was a bare package specifier (e.g. "@foo/bar",
@@ -666,7 +666,7 @@ namespace ts.moduleSpecifiers {
666
666
: removeFileExtension ( relativePath ) ;
667
667
}
668
668
669
- function tryGetModuleNameAsNodeModule ( { path, isRedirect } : ModulePath , { getCanonicalFileName, sourceDirectory } : Info , importingSourceFile : SourceFile , host : ModuleSpecifierResolutionHost , options : CompilerOptions , packageNameOnly ?: boolean , overrideMode ?: ModuleKind . ESNext | ModuleKind . CommonJS ) : string | undefined {
669
+ function tryGetModuleNameAsNodeModule ( { path, isRedirect } : ModulePath , { getCanonicalFileName, sourceDirectory } : Info , importingSourceFile : SourceFile , host : ModuleSpecifierResolutionHost , options : CompilerOptions , userPreferences : UserPreferences , packageNameOnly ?: boolean , overrideMode ?: ModuleKind . ESNext | ModuleKind . CommonJS ) : string | undefined {
670
670
if ( ! host . fileExists || ! host . readFile ) {
671
671
return undefined ;
672
672
}
@@ -680,8 +680,9 @@ namespace ts.moduleSpecifiers {
680
680
let moduleSpecifier = path ;
681
681
let isPackageRootPath = false ;
682
682
if ( ! packageNameOnly ) {
683
+ const preferences = getPreferences ( host , userPreferences , options , importingSourceFile ) ;
683
684
let packageRootIndex = parts . packageRootIndex ;
684
- let moduleFileNameForExtensionless : string | undefined ;
685
+ let moduleFileName : string | undefined ;
685
686
while ( true ) {
686
687
// If the module could be imported by a directory name, use that directory's name
687
688
const { moduleFileToTry, packageRootPath, blockedByExports, verbatimFromExports } = tryDirectoryWithPackageJson ( packageRootIndex ) ;
@@ -698,12 +699,12 @@ namespace ts.moduleSpecifiers {
698
699
isPackageRootPath = true ;
699
700
break ;
700
701
}
701
- if ( ! moduleFileNameForExtensionless ) moduleFileNameForExtensionless = moduleFileToTry ;
702
+ if ( ! moduleFileName ) moduleFileName = moduleFileToTry ;
702
703
703
704
// try with next level of directory
704
705
packageRootIndex = path . indexOf ( directorySeparator , packageRootIndex + 1 ) ;
705
706
if ( packageRootIndex === - 1 ) {
706
- moduleSpecifier = getExtensionlessFileName ( moduleFileNameForExtensionless ) ;
707
+ moduleSpecifier = removeExtensionAndIndexPostFix ( moduleFileName , preferences . ending , options , host ) ;
707
708
break ;
708
709
}
709
710
}
@@ -768,28 +769,22 @@ namespace ts.moduleSpecifiers {
768
769
}
769
770
}
770
771
// If the file is the main module, it can be imported by the package name
771
- const mainFileRelative = packageJsonContent . typings || packageJsonContent . types || packageJsonContent . main ;
772
+ const mainFileRelative = packageJsonContent . typings || packageJsonContent . types || packageJsonContent . main || "index.js" ;
772
773
if ( isString ( mainFileRelative ) ) {
773
774
const mainExportFile = toPath ( mainFileRelative , packageRootPath , getCanonicalFileName ) ;
774
775
if ( removeFileExtension ( mainExportFile ) === removeFileExtension ( getCanonicalFileName ( moduleFileToTry ) ) ) {
775
776
return { packageRootPath, moduleFileToTry } ;
776
777
}
777
778
}
778
779
}
779
- return { moduleFileToTry } ;
780
- }
781
-
782
- function getExtensionlessFileName ( path : string ) : string {
783
- // We still have a file name - remove the extension
784
- const fullModulePathWithoutExtension = removeFileExtension ( path ) ;
785
-
786
- // If the file is /index, it can be imported by its directory name
787
- // IFF there is not _also_ a file by the same name
788
- if ( getCanonicalFileName ( fullModulePathWithoutExtension . substring ( parts . fileNameIndex ) ) === "/index" && ! tryGetAnyFileFromPath ( host , fullModulePathWithoutExtension . substring ( 0 , parts . fileNameIndex ) ) ) {
789
- return fullModulePathWithoutExtension . substring ( 0 , parts . fileNameIndex ) ;
780
+ else {
781
+ // No package.json exists; an index.js will still resolve as the package name
782
+ const fileName = getCanonicalFileName ( moduleFileToTry . substring ( parts . packageRootIndex + 1 ) ) ;
783
+ if ( fileName === "index.d.ts" || fileName === "index.js" || fileName === "index.ts" || fileName === "index.tsx" ) {
784
+ return { moduleFileToTry, packageRootPath } ;
785
+ }
790
786
}
791
-
792
- return fullModulePathWithoutExtension ;
787
+ return { moduleFileToTry } ;
793
788
}
794
789
}
795
790
@@ -812,13 +807,19 @@ namespace ts.moduleSpecifiers {
812
807
} ) ;
813
808
}
814
809
815
- function removeExtensionAndIndexPostFix ( fileName : string , ending : Ending , options : CompilerOptions ) : string {
810
+ function removeExtensionAndIndexPostFix ( fileName : string , ending : Ending , options : CompilerOptions , host ?: ModuleSpecifierResolutionHost ) : string {
816
811
if ( fileExtensionIsOneOf ( fileName , [ Extension . Json , Extension . Mjs , Extension . Cjs ] ) ) return fileName ;
817
812
const noExtension = removeFileExtension ( fileName ) ;
818
813
if ( fileExtensionIsOneOf ( fileName , [ Extension . Dmts , Extension . Mts , Extension . Dcts , Extension . Cts ] ) ) return noExtension + getJSExtensionForFile ( fileName , options ) ;
819
814
switch ( ending ) {
820
815
case Ending . Minimal :
821
- return removeSuffix ( noExtension , "/index" ) ;
816
+ const withoutIndex = removeSuffix ( noExtension , "/index" ) ;
817
+ if ( host && withoutIndex !== noExtension && tryGetAnyFileFromPath ( host , withoutIndex ) ) {
818
+ // Can't remove index if there's a file by the same name as the directory.
819
+ // Probably more callers should pass `host` so we can determine this?
820
+ return noExtension ;
821
+ }
822
+ return withoutIndex ;
822
823
case Ending . Index :
823
824
return noExtension ;
824
825
case Ending . JsExtension :
0 commit comments