@@ -77,16 +77,20 @@ namespace ts {
7777 traceEnabled : boolean ;
7878 }
7979
80- interface PackageJson {
81- name ?: string ;
82- version ?: string ;
80+ /** Just the fields that we use for module resolution. */
81+ interface PackageJsonPathFields {
8382 typings ?: string ;
8483 types ?: string ;
8584 main ?: string ;
8685 }
8786
87+ interface PackageJson extends PackageJsonPathFields {
88+ name ?: string ;
89+ version ?: string ;
90+ }
91+
8892 /** Reads from "main" or "types"/"typings" depending on `extensions`. */
89- function tryReadPackageJsonFields ( readTypes : boolean , jsonContent : PackageJson , baseDirectory : string , state : ModuleResolutionState ) : string | undefined {
93+ function tryReadPackageJsonFields ( readTypes : boolean , jsonContent : PackageJsonPathFields , baseDirectory : string , state : ModuleResolutionState ) : string | undefined {
9094 return readTypes ? tryReadFromField ( "typings" ) || tryReadFromField ( "types" ) : tryReadFromField ( "main" ) ;
9195
9296 function tryReadFromField ( fieldName : "typings" | "types" | "main" ) : string | undefined {
@@ -886,7 +890,7 @@ namespace ts {
886890 return withPackageId ( packageId , loadNodeModuleFromDirectoryWorker ( extensions , candidate , failedLookupLocations , onlyRecordFailures , state , packageJsonContent ) ) ;
887891 }
888892
889- function loadNodeModuleFromDirectoryWorker ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState , packageJsonContent : PackageJson | undefined ) : PathAndExtension | undefined {
893+ function loadNodeModuleFromDirectoryWorker ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState , packageJsonContent : PackageJsonPathFields | undefined ) : PathAndExtension | undefined {
890894 const fromPackageJson = packageJsonContent && loadModuleFromPackageJson ( packageJsonContent , extensions , candidate , failedLookupLocations , state ) ;
891895 if ( fromPackageJson ) {
892896 return fromPackageJson ;
@@ -901,7 +905,7 @@ namespace ts {
901905 failedLookupLocations : Push < string > ,
902906 onlyRecordFailures : boolean ,
903907 { host, traceEnabled } : ModuleResolutionState ,
904- ) : { packageJsonContent : PackageJson | undefined , packageId : PackageId | undefined } {
908+ ) : { found : boolean , packageJsonContent : PackageJsonPathFields | undefined , packageId : PackageId | undefined } {
905909 const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( nodeModuleDirectory , host ) ;
906910 const packageJsonPath = pathToPackageJson ( nodeModuleDirectory ) ;
907911 if ( directoryExists && host . fileExists ( packageJsonPath ) ) {
@@ -912,19 +916,19 @@ namespace ts {
912916 const packageId : PackageId = typeof packageJsonContent . name === "string" && typeof packageJsonContent . version === "string"
913917 ? { name : packageJsonContent . name , subModuleName, version : packageJsonContent . version }
914918 : undefined ;
915- return { packageJsonContent, packageId } ;
919+ return { found : true , packageJsonContent, packageId } ;
916920 }
917921 else {
918922 if ( directoryExists && traceEnabled ) {
919923 trace ( host , Diagnostics . File_0_does_not_exist , packageJsonPath ) ;
920924 }
921925 // record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
922926 failedLookupLocations . push ( packageJsonPath ) ;
923- return { packageJsonContent : undefined , packageId : undefined } ;
927+ return { found : false , packageJsonContent : undefined , packageId : undefined } ;
924928 }
925929 }
926930
927- function loadModuleFromPackageJson ( jsonContent : PackageJson , extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : PathAndExtension | undefined {
931+ function loadModuleFromPackageJson ( jsonContent : PackageJsonPathFields , extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : PathAndExtension | undefined {
928932 const file = tryReadPackageJsonFields ( extensions !== Extensions . JavaScript , jsonContent , candidate , state ) ;
929933 if ( ! file ) {
930934 return undefined ;
@@ -976,10 +980,22 @@ namespace ts {
976980 }
977981
978982 function loadModuleFromNodeModulesFolder ( extensions : Extensions , moduleName : string , nodeModulesFolder : string , nodeModulesFolderExists : boolean , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : Resolved | undefined {
979- const { packageName, rest } = getPackageName ( moduleName ) ;
980- const packageRootPath = combinePaths ( nodeModulesFolder , packageName ) ;
981- const { packageJsonContent, packageId } = getPackageJsonInfo ( packageRootPath , rest , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
982983 const candidate = normalizePath ( combinePaths ( nodeModulesFolder , moduleName ) ) ;
984+ // First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
985+ let packageJsonContent : PackageJsonPathFields | undefined ;
986+ let packageId : PackageId | undefined ;
987+ const packageInfo = getPackageJsonInfo ( candidate , "" , failedLookupLocations , /*onlyRecordFailures*/ ! nodeModulesFolderExists , state ) ;
988+ if ( packageInfo . found ) {
989+ ( { packageJsonContent, packageId } = packageInfo ) ;
990+ }
991+ else {
992+ const { packageName, rest } = getPackageName ( moduleName ) ;
993+ if ( rest !== "" ) { // If "rest" is empty, we just did this search above.
994+ const packageRootPath = combinePaths ( nodeModulesFolder , packageName ) ;
995+ // Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId.
996+ packageId = getPackageJsonInfo ( packageRootPath , rest , failedLookupLocations , ! nodeModulesFolderExists , state ) . packageId ;
997+ }
998+ }
983999 const pathAndExtension = loadModuleFromFile ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ||
9841000 loadNodeModuleFromDirectoryWorker ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state , packageJsonContent ) ;
9851001 return withPackageId ( packageId , pathAndExtension ) ;
0 commit comments