@@ -19,13 +19,26 @@ namespace ts {
19
19
push ( value : T ) : void ;
20
20
}
21
21
22
- /**
23
- * Result of trying to resolve a module.
24
- * At least one of `ts` and `js` should be defined, or the whole thing should be `undefined`.
25
- */
22
+ function withPackageId ( packageId : PackageId | undefined , r : PathAndExtension | undefined ) : Resolved {
23
+ return r && { path : r . path , extension : r . ext , packageId } ;
24
+ }
25
+
26
+ function noPackageId ( r : PathAndExtension | undefined ) : Resolved {
27
+ return withPackageId ( /*packageId*/ undefined , r ) ;
28
+ }
29
+
30
+ /** Result of trying to resolve a module. */
26
31
interface Resolved {
27
32
path : string ;
28
33
extension : Extension ;
34
+ packageId : PackageId | undefined ;
35
+ }
36
+
37
+ /** Result of trying to resolve a module at a file. Needs to have 'packageId' added later. */
38
+ interface PathAndExtension {
39
+ path : string ;
40
+ // (Use a different name than `extension` to make sure Resolved isn't assignable to PathAndExtension.)
41
+ ext : Extension ;
29
42
}
30
43
31
44
/**
@@ -49,7 +62,7 @@ namespace ts {
49
62
50
63
function createResolvedModuleWithFailedLookupLocations ( resolved : Resolved | undefined , isExternalLibraryImport : boolean , failedLookupLocations : string [ ] ) : ResolvedModuleWithFailedLookupLocations {
51
64
return {
52
- resolvedModule : resolved && { resolvedFileName : resolved . path , extension : resolved . extension , isExternalLibraryImport } ,
65
+ resolvedModule : resolved && { resolvedFileName : resolved . path , extension : resolved . extension , isExternalLibraryImport, packageId : resolved . packageId } ,
53
66
failedLookupLocations
54
67
} ;
55
68
}
@@ -65,8 +78,7 @@ namespace ts {
65
78
}
66
79
67
80
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
68
- function tryReadPackageJsonFields ( readTypes : boolean , packageJsonPath : string , baseDirectory : string , state : ModuleResolutionState ) : string | undefined {
69
- const jsonContent = readJson ( packageJsonPath , state . host ) ;
81
+ function tryReadPackageJsonFields ( readTypes : boolean , jsonContent : PackageJson , baseDirectory : string , state : ModuleResolutionState ) : string | undefined {
70
82
return readTypes ? tryReadFromField ( "typings" ) || tryReadFromField ( "types" ) : tryReadFromField ( "main" ) ;
71
83
72
84
function tryReadFromField ( fieldName : "typings" | "types" | "main" ) : string | undefined {
@@ -93,7 +105,8 @@ namespace ts {
93
105
}
94
106
}
95
107
96
- function readJson ( path : string , host : ModuleResolutionHost ) : { typings ?: string , types ?: string , main ?: string } {
108
+ interface PackageJson { name ?: string ; version ?: string ; typings ?: string ; types ?: string ; main ?: string ; }
109
+ function readJson ( path : string , host : ModuleResolutionHost ) : PackageJson {
97
110
try {
98
111
const jsonText = host . readFile ( path ) ;
99
112
return jsonText ? JSON . parse ( jsonText ) : { } ;
@@ -658,7 +671,7 @@ namespace ts {
658
671
if ( extension !== undefined ) {
659
672
const path = tryFile ( candidate , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
660
673
if ( path !== undefined ) {
661
- return { path, extension } ;
674
+ return { path, extension, packageId : undefined } ;
662
675
}
663
676
}
664
677
@@ -721,7 +734,7 @@ namespace ts {
721
734
}
722
735
const resolved = loadModuleFromNodeModules ( extensions , moduleName , containingDirectory , failedLookupLocations , state , cache ) ;
723
736
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
724
- return resolved && { value : resolved . value && { resolved : { path : realpath ( resolved . value . path , host , traceEnabled ) , extension : resolved . value . extension } , isExternalLibraryImport : true } } ;
737
+ return resolved && { value : resolved . value && { resolved : { ... resolved . value , path : realpath ( resolved . value . path , host , traceEnabled ) } , isExternalLibraryImport : true } } ;
725
738
}
726
739
else {
727
740
const candidate = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
@@ -759,7 +772,7 @@ namespace ts {
759
772
}
760
773
const resolvedFromFile = loadModuleFromFile ( extensions , candidate , failedLookupLocations , onlyRecordFailures , state ) ;
761
774
if ( resolvedFromFile ) {
762
- return resolvedFromFile ;
775
+ return noPackageId ( resolvedFromFile ) ;
763
776
}
764
777
}
765
778
if ( ! onlyRecordFailures ) {
@@ -780,11 +793,15 @@ namespace ts {
780
793
return ! host . directoryExists || host . directoryExists ( directoryName ) ;
781
794
}
782
795
796
+ function loadModuleFromFileNoPackageId ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : Resolved {
797
+ return noPackageId ( loadModuleFromFile ( extensions , candidate , failedLookupLocations , onlyRecordFailures , state ) ) ;
798
+ }
799
+
783
800
/**
784
801
* @param {boolean } onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
785
802
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
786
803
*/
787
- function loadModuleFromFile ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : Resolved | undefined {
804
+ function loadModuleFromFile ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : PathAndExtension | undefined {
788
805
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
789
806
const resolvedByAddingExtension = tryAddingExtensions ( candidate , extensions , failedLookupLocations , onlyRecordFailures , state ) ;
790
807
if ( resolvedByAddingExtension ) {
@@ -804,7 +821,7 @@ namespace ts {
804
821
}
805
822
806
823
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
807
- function tryAddingExtensions ( candidate : string , extensions : Extensions , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : Resolved | undefined {
824
+ function tryAddingExtensions ( candidate : string , extensions : Extensions , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : PathAndExtension | undefined {
808
825
if ( ! onlyRecordFailures ) {
809
826
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
810
827
const directory = getDirectoryPath ( candidate ) ;
@@ -815,16 +832,16 @@ namespace ts {
815
832
816
833
switch ( extensions ) {
817
834
case Extensions . DtsOnly :
818
- return tryExtension ( ".d.ts" , Extension . Dts ) ;
835
+ return tryExtension ( Extension . Dts ) ;
819
836
case Extensions . TypeScript :
820
- return tryExtension ( ".ts" , Extension . Ts ) || tryExtension ( ".tsx" , Extension . Tsx ) || tryExtension ( ".d.ts" , Extension . Dts ) ;
837
+ return tryExtension ( Extension . Ts ) || tryExtension ( Extension . Tsx ) || tryExtension ( Extension . Dts ) ;
821
838
case Extensions . JavaScript :
822
- return tryExtension ( ".js" , Extension . Js ) || tryExtension ( ".jsx" , Extension . Jsx ) ;
839
+ return tryExtension ( Extension . Js ) || tryExtension ( Extension . Jsx ) ;
823
840
}
824
841
825
- function tryExtension ( ext : string , extension : Extension ) : Resolved | undefined {
826
- const path = tryFile ( candidate + ext , failedLookupLocations , onlyRecordFailures , state ) ;
827
- return path && { path, extension } ;
842
+ function tryExtension ( ext : Extension ) : PathAndExtension | undefined {
843
+ const path = tryFile ( candidate + extensionText ( ext ) , failedLookupLocations , onlyRecordFailures , state ) ;
844
+ return path && { path, ext } ;
828
845
}
829
846
}
830
847
@@ -850,12 +867,23 @@ namespace ts {
850
867
function loadNodeModuleFromDirectory ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState , considerPackageJson = true ) : Resolved | undefined {
851
868
const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( candidate , state . host ) ;
852
869
870
+ let packageId : PackageId | undefined ;
871
+
853
872
if ( considerPackageJson ) {
854
873
const packageJsonPath = pathToPackageJson ( candidate ) ;
855
874
if ( directoryExists && state . host . fileExists ( packageJsonPath ) ) {
856
- const fromPackageJson = loadModuleFromPackageJson ( packageJsonPath , extensions , candidate , failedLookupLocations , state ) ;
875
+ if ( state . traceEnabled ) {
876
+ trace ( state . host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
877
+ }
878
+ const jsonContent = readJson ( packageJsonPath , state . host ) ;
879
+
880
+ if ( typeof jsonContent . name === "string" && typeof jsonContent . version === "string" ) {
881
+ packageId = { name : jsonContent . name , version : jsonContent . version } ;
882
+ }
883
+
884
+ const fromPackageJson = loadModuleFromPackageJson ( jsonContent , extensions , candidate , failedLookupLocations , state ) ;
857
885
if ( fromPackageJson ) {
858
- return fromPackageJson ;
886
+ return withPackageId ( packageId , fromPackageJson ) ;
859
887
}
860
888
}
861
889
else {
@@ -867,15 +895,11 @@ namespace ts {
867
895
}
868
896
}
869
897
870
- return loadModuleFromFile ( extensions , combinePaths ( candidate , "index" ) , failedLookupLocations , ! directoryExists , state ) ;
898
+ return withPackageId ( packageId , loadModuleFromFile ( extensions , combinePaths ( candidate , "index" ) , failedLookupLocations , ! directoryExists , state ) ) ;
871
899
}
872
900
873
- function loadModuleFromPackageJson ( packageJsonPath : string , extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : Resolved | undefined {
874
- if ( state . traceEnabled ) {
875
- trace ( state . host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
876
- }
877
-
878
- const file = tryReadPackageJsonFields ( extensions !== Extensions . JavaScript , packageJsonPath , candidate , state ) ;
901
+ function loadModuleFromPackageJson ( jsonContent : PackageJson , extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : PathAndExtension | undefined {
902
+ const file = tryReadPackageJsonFields ( extensions !== Extensions . JavaScript , jsonContent , candidate , state ) ;
879
903
if ( ! file ) {
880
904
return undefined ;
881
905
}
@@ -895,13 +919,18 @@ namespace ts {
895
919
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
896
920
const nextExtensions = extensions === Extensions . DtsOnly ? Extensions . TypeScript : extensions ;
897
921
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
898
- return nodeLoadModuleByRelativeName ( nextExtensions , file , failedLookupLocations , onlyRecordFailures , state , /*considerPackageJson*/ false ) ;
922
+ const result = nodeLoadModuleByRelativeName ( nextExtensions , file , failedLookupLocations , onlyRecordFailures , state , /*considerPackageJson*/ false ) ;
923
+ if ( result ) {
924
+ // It won't have a `packageId` set, because we disabled `considerPackageJson`.
925
+ Debug . assert ( result . packageId === undefined ) ;
926
+ return { path : result . path , ext : result . extension } ;
927
+ }
899
928
}
900
929
901
930
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
902
- function resolvedIfExtensionMatches ( extensions : Extensions , path : string ) : Resolved | undefined {
903
- const extension = tryGetExtensionFromPath ( path ) ;
904
- return extension !== undefined && extensionIsOk ( extensions , extension ) ? { path, extension } : undefined ;
931
+ function resolvedIfExtensionMatches ( extensions : Extensions , path : string ) : PathAndExtension | undefined {
932
+ const ext = tryGetExtensionFromPath ( path ) ;
933
+ return ext !== undefined && extensionIsOk ( extensions , ext ) ? { path, ext } : undefined ;
905
934
}
906
935
907
936
/** True if `extension` is one of the supported `extensions`. */
@@ -923,7 +952,7 @@ namespace ts {
923
952
function loadModuleFromNodeModulesFolder ( extensions : Extensions , moduleName : string , nodeModulesFolder : string , nodeModulesFolderExists : boolean , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : Resolved | undefined {
924
953
const candidate = normalizePath ( combinePaths ( nodeModulesFolder , moduleName ) ) ;
925
954
926
- return loadModuleFromFile ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ||
955
+ return loadModuleFromFileNoPackageId ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ||
927
956
loadNodeModuleFromDirectory ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
928
957
}
929
958
@@ -1008,7 +1037,7 @@ namespace ts {
1008
1037
if ( traceEnabled ) {
1009
1038
trace ( host , Diagnostics . Resolution_for_module_0_was_found_in_cache , moduleName ) ;
1010
1039
}
1011
- return { value : result . resolvedModule && { path : result . resolvedModule . resolvedFileName , extension : result . resolvedModule . extension } } ;
1040
+ return { value : result . resolvedModule && { path : result . resolvedModule . resolvedFileName , extension : result . resolvedModule . extension , packageId : result . resolvedModule . packageId } } ;
1012
1041
}
1013
1042
}
1014
1043
@@ -1022,7 +1051,7 @@ namespace ts {
1022
1051
return createResolvedModuleWithFailedLookupLocations ( resolved && resolved . value , /*isExternalLibraryImport*/ false , failedLookupLocations ) ;
1023
1052
1024
1053
function tryResolve ( extensions : Extensions ) : SearchResult < Resolved > {
1025
- const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings ( extensions , moduleName , containingDirectory , loadModuleFromFile , failedLookupLocations , state ) ;
1054
+ const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings ( extensions , moduleName , containingDirectory , loadModuleFromFileNoPackageId , failedLookupLocations , state ) ;
1026
1055
if ( resolvedUsingSettings ) {
1027
1056
return { value : resolvedUsingSettings } ;
1028
1057
}
@@ -1036,7 +1065,7 @@ namespace ts {
1036
1065
return resolutionFromCache ;
1037
1066
}
1038
1067
const searchName = normalizePath ( combinePaths ( directory , moduleName ) ) ;
1039
- return toSearchResult ( loadModuleFromFile ( extensions , searchName , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ) ;
1068
+ return toSearchResult ( loadModuleFromFileNoPackageId ( extensions , searchName , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ) ;
1040
1069
} ) ;
1041
1070
if ( resolved ) {
1042
1071
return resolved ;
@@ -1048,7 +1077,7 @@ namespace ts {
1048
1077
}
1049
1078
else {
1050
1079
const candidate = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
1051
- return toSearchResult ( loadModuleFromFile ( extensions , candidate , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ) ;
1080
+ return toSearchResult ( loadModuleFromFileNoPackageId ( extensions , candidate , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ) ;
1052
1081
}
1053
1082
}
1054
1083
}
0 commit comments