@@ -77,16 +77,20 @@ namespace ts {
77
77
traceEnabled : boolean ;
78
78
}
79
79
80
- interface PackageJson {
81
- name ?: string ;
82
- version ?: string ;
80
+ /** Just the fields that we use for module resolution. */
81
+ interface PackageJsonPathFields {
83
82
typings ?: string ;
84
83
types ?: string ;
85
84
main ?: string ;
86
85
}
87
86
87
+ interface PackageJson extends PackageJsonPathFields {
88
+ name ?: string ;
89
+ version ?: string ;
90
+ }
91
+
88
92
/** 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 {
90
94
return readTypes ? tryReadFromField ( "typings" ) || tryReadFromField ( "types" ) : tryReadFromField ( "main" ) ;
91
95
92
96
function tryReadFromField ( fieldName : "typings" | "types" | "main" ) : string | undefined {
@@ -886,7 +890,7 @@ namespace ts {
886
890
return withPackageId ( packageId , loadNodeModuleFromDirectoryWorker ( extensions , candidate , failedLookupLocations , onlyRecordFailures , state , packageJsonContent ) ) ;
887
891
}
888
892
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 {
890
894
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson ( packageJsonContent , extensions , candidate , failedLookupLocations , state ) ;
891
895
if ( fromPackageJson ) {
892
896
return fromPackageJson ;
@@ -901,7 +905,7 @@ namespace ts {
901
905
failedLookupLocations : Push < string > ,
902
906
onlyRecordFailures : boolean ,
903
907
{ host, traceEnabled } : ModuleResolutionState ,
904
- ) : { packageJsonContent : PackageJson | undefined , packageId : PackageId | undefined } {
908
+ ) : { found : boolean , packageJsonContent : PackageJsonPathFields | undefined , packageId : PackageId | undefined } {
905
909
const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( nodeModuleDirectory , host ) ;
906
910
const packageJsonPath = pathToPackageJson ( nodeModuleDirectory ) ;
907
911
if ( directoryExists && host . fileExists ( packageJsonPath ) ) {
@@ -912,19 +916,19 @@ namespace ts {
912
916
const packageId : PackageId = typeof packageJsonContent . name === "string" && typeof packageJsonContent . version === "string"
913
917
? { name : packageJsonContent . name , subModuleName, version : packageJsonContent . version }
914
918
: undefined ;
915
- return { packageJsonContent, packageId } ;
919
+ return { found : true , packageJsonContent, packageId } ;
916
920
}
917
921
else {
918
922
if ( directoryExists && traceEnabled ) {
919
923
trace ( host , Diagnostics . File_0_does_not_exist , packageJsonPath ) ;
920
924
}
921
925
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
922
926
failedLookupLocations . push ( packageJsonPath ) ;
923
- return { packageJsonContent : undefined , packageId : undefined } ;
927
+ return { found : false , packageJsonContent : undefined , packageId : undefined } ;
924
928
}
925
929
}
926
930
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 {
928
932
const file = tryReadPackageJsonFields ( extensions !== Extensions . JavaScript , jsonContent , candidate , state ) ;
929
933
if ( ! file ) {
930
934
return undefined ;
@@ -976,10 +980,22 @@ namespace ts {
976
980
}
977
981
978
982
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 ) ;
982
983
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
+ }
983
999
const pathAndExtension = loadModuleFromFile ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ||
984
1000
loadNodeModuleFromDirectoryWorker ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state , packageJsonContent ) ;
985
1001
return withPackageId ( packageId , pathAndExtension ) ;
0 commit comments