@@ -13,13 +13,32 @@ namespace ts {
13
13
return compilerOptions . traceResolution && host . trace !== undefined ;
14
14
}
15
15
16
- /**
17
- * Result of trying to resolve a module.
18
- * At least one of `ts` and `js` should be defined, or the whole thing should be `undefined`.
19
- */
16
+ /** Array that is only intended to be pushed to, never read. */
17
+ /* @internal */
18
+ export interface Push < T > {
19
+ push ( value : T ) : void ;
20
+ }
21
+
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. */
20
31
interface Resolved {
21
32
path : string ;
22
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 ;
23
42
}
24
43
25
44
/**
@@ -43,7 +62,7 @@ namespace ts {
43
62
44
63
function createResolvedModuleWithFailedLookupLocations ( resolved : Resolved | undefined , isExternalLibraryImport : boolean , failedLookupLocations : string [ ] ) : ResolvedModuleWithFailedLookupLocations {
45
64
return {
46
- resolvedModule : resolved && { resolvedFileName : resolved . path , extension : resolved . extension , isExternalLibraryImport } ,
65
+ resolvedModule : resolved && { resolvedFileName : resolved . path , extension : resolved . extension , isExternalLibraryImport, packageId : resolved . packageId } ,
47
66
failedLookupLocations
48
67
} ;
49
68
}
@@ -54,9 +73,16 @@ namespace ts {
54
73
traceEnabled : boolean ;
55
74
}
56
75
76
+ interface PackageJson {
77
+ name ?: string ;
78
+ version ?: string ;
79
+ typings ?: string ;
80
+ types ?: string ;
81
+ main ?: string ;
82
+ }
83
+
57
84
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
58
- function tryReadPackageJsonFields ( readTypes : boolean , packageJsonPath : string , baseDirectory : string , state : ModuleResolutionState ) : string | undefined {
59
- const jsonContent = readJson ( packageJsonPath , state . host ) ;
85
+ function tryReadPackageJsonFields ( readTypes : boolean , jsonContent : PackageJson , baseDirectory : string , state : ModuleResolutionState ) : string | undefined {
60
86
return readTypes ? tryReadFromField ( "typings" ) || tryReadFromField ( "types" ) : tryReadFromField ( "main" ) ;
61
87
62
88
function tryReadFromField ( fieldName : "typings" | "types" | "main" ) : string | undefined {
@@ -83,7 +109,7 @@ namespace ts {
83
109
}
84
110
}
85
111
86
- function readJson ( path : string , host : ModuleResolutionHost ) : { typings ?: string , types ?: string , main ?: string } {
112
+ function readJson ( path : string , host : ModuleResolutionHost ) : PackageJson {
87
113
try {
88
114
const jsonText = host . readFile ( path ) ;
89
115
return jsonText ? JSON . parse ( jsonText ) : { } ;
@@ -646,7 +672,7 @@ namespace ts {
646
672
if ( extension !== undefined ) {
647
673
const path = tryFile ( candidate , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
648
674
if ( path !== undefined ) {
649
- return { path, extension } ;
675
+ return { path, extension, packageId : undefined } ;
650
676
}
651
677
}
652
678
@@ -709,7 +735,7 @@ namespace ts {
709
735
}
710
736
const resolved = loadModuleFromNodeModules ( extensions , moduleName , containingDirectory , failedLookupLocations , state , cache ) ;
711
737
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
712
- return resolved && { value : resolved . value && { resolved : { path : realpath ( resolved . value . path , host , traceEnabled ) , extension : resolved . value . extension } , isExternalLibraryImport : true } } ;
738
+ return resolved && { value : resolved . value && { resolved : { ... resolved . value , path : realpath ( resolved . value . path , host , traceEnabled ) } , isExternalLibraryImport : true } } ;
713
739
}
714
740
else {
715
741
const candidate = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
@@ -747,7 +773,7 @@ namespace ts {
747
773
}
748
774
const resolvedFromFile = loadModuleFromFile ( extensions , candidate , failedLookupLocations , onlyRecordFailures , state ) ;
749
775
if ( resolvedFromFile ) {
750
- return resolvedFromFile ;
776
+ return noPackageId ( resolvedFromFile ) ;
751
777
}
752
778
}
753
779
if ( ! onlyRecordFailures ) {
@@ -768,11 +794,15 @@ namespace ts {
768
794
return ! host . directoryExists || host . directoryExists ( directoryName ) ;
769
795
}
770
796
797
+ function loadModuleFromFileNoPackageId ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : Resolved {
798
+ return noPackageId ( loadModuleFromFile ( extensions , candidate , failedLookupLocations , onlyRecordFailures , state ) ) ;
799
+ }
800
+
771
801
/**
772
802
* @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
773
803
* 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.
774
804
*/
775
- function loadModuleFromFile ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : Resolved | undefined {
805
+ function loadModuleFromFile ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : PathAndExtension | undefined {
776
806
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
777
807
const resolvedByAddingExtension = tryAddingExtensions ( candidate , extensions , failedLookupLocations , onlyRecordFailures , state ) ;
778
808
if ( resolvedByAddingExtension ) {
@@ -792,7 +822,7 @@ namespace ts {
792
822
}
793
823
794
824
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
795
- function tryAddingExtensions ( candidate : string , extensions : Extensions , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : Resolved | undefined {
825
+ function tryAddingExtensions ( candidate : string , extensions : Extensions , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState ) : PathAndExtension | undefined {
796
826
if ( ! onlyRecordFailures ) {
797
827
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
798
828
const directory = getDirectoryPath ( candidate ) ;
@@ -810,9 +840,9 @@ namespace ts {
810
840
return tryExtension ( Extension . Js ) || tryExtension ( Extension . Jsx ) ;
811
841
}
812
842
813
- function tryExtension ( extension : Extension ) : Resolved | undefined {
814
- const path = tryFile ( candidate + extension , failedLookupLocations , onlyRecordFailures , state ) ;
815
- return path && { path, extension } ;
843
+ function tryExtension ( ext : Extension ) : PathAndExtension | undefined {
844
+ const path = tryFile ( candidate + ext , failedLookupLocations , onlyRecordFailures , state ) ;
845
+ return path && { path, ext } ;
816
846
}
817
847
}
818
848
@@ -838,12 +868,23 @@ namespace ts {
838
868
function loadNodeModuleFromDirectory ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState , considerPackageJson = true ) : Resolved | undefined {
839
869
const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( candidate , state . host ) ;
840
870
871
+ let packageId : PackageId | undefined ;
872
+
841
873
if ( considerPackageJson ) {
842
874
const packageJsonPath = pathToPackageJson ( candidate ) ;
843
875
if ( directoryExists && state . host . fileExists ( packageJsonPath ) ) {
844
- const fromPackageJson = loadModuleFromPackageJson ( packageJsonPath , extensions , candidate , failedLookupLocations , state ) ;
876
+ if ( state . traceEnabled ) {
877
+ trace ( state . host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
878
+ }
879
+ const jsonContent = readJson ( packageJsonPath , state . host ) ;
880
+
881
+ if ( typeof jsonContent . name === "string" && typeof jsonContent . version === "string" ) {
882
+ packageId = { name : jsonContent . name , version : jsonContent . version } ;
883
+ }
884
+
885
+ const fromPackageJson = loadModuleFromPackageJson ( jsonContent , extensions , candidate , failedLookupLocations , state ) ;
845
886
if ( fromPackageJson ) {
846
- return fromPackageJson ;
887
+ return withPackageId ( packageId , fromPackageJson ) ;
847
888
}
848
889
}
849
890
else {
@@ -855,15 +896,11 @@ namespace ts {
855
896
}
856
897
}
857
898
858
- return loadModuleFromFile ( extensions , combinePaths ( candidate , "index" ) , failedLookupLocations , ! directoryExists , state ) ;
899
+ return withPackageId ( packageId , loadModuleFromFile ( extensions , combinePaths ( candidate , "index" ) , failedLookupLocations , ! directoryExists , state ) ) ;
859
900
}
860
901
861
- function loadModuleFromPackageJson ( packageJsonPath : string , extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : Resolved | undefined {
862
- if ( state . traceEnabled ) {
863
- trace ( state . host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
864
- }
865
-
866
- const file = tryReadPackageJsonFields ( extensions !== Extensions . JavaScript , packageJsonPath , candidate , state ) ;
902
+ function loadModuleFromPackageJson ( jsonContent : PackageJson , extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : PathAndExtension | undefined {
903
+ const file = tryReadPackageJsonFields ( extensions !== Extensions . JavaScript , jsonContent , candidate , state ) ;
867
904
if ( ! file ) {
868
905
return undefined ;
869
906
}
@@ -883,13 +920,18 @@ namespace ts {
883
920
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
884
921
const nextExtensions = extensions === Extensions . DtsOnly ? Extensions . TypeScript : extensions ;
885
922
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
886
- return nodeLoadModuleByRelativeName ( nextExtensions , file , failedLookupLocations , onlyRecordFailures , state , /*considerPackageJson*/ false ) ;
923
+ const result = nodeLoadModuleByRelativeName ( nextExtensions , file , failedLookupLocations , onlyRecordFailures , state , /*considerPackageJson*/ false ) ;
924
+ if ( result ) {
925
+ // It won't have a `packageId` set, because we disabled `considerPackageJson`.
926
+ Debug . assert ( result . packageId === undefined ) ;
927
+ return { path : result . path , ext : result . extension } ;
928
+ }
887
929
}
888
930
889
931
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
890
- function resolvedIfExtensionMatches ( extensions : Extensions , path : string ) : Resolved | undefined {
891
- const extension = tryGetExtensionFromPath ( path ) ;
892
- return extension !== undefined && extensionIsOk ( extensions , extension ) ? { path, extension } : undefined ;
932
+ function resolvedIfExtensionMatches ( extensions : Extensions , path : string ) : PathAndExtension | undefined {
933
+ const ext = tryGetExtensionFromPath ( path ) ;
934
+ return ext !== undefined && extensionIsOk ( extensions , ext ) ? { path, ext } : undefined ;
893
935
}
894
936
895
937
/** True if `extension` is one of the supported `extensions`. */
@@ -911,7 +953,7 @@ namespace ts {
911
953
function loadModuleFromNodeModulesFolder ( extensions : Extensions , moduleName : string , nodeModulesFolder : string , nodeModulesFolderExists : boolean , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : Resolved | undefined {
912
954
const candidate = normalizePath ( combinePaths ( nodeModulesFolder , moduleName ) ) ;
913
955
914
- return loadModuleFromFile ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ||
956
+ return loadModuleFromFileNoPackageId ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ||
915
957
loadNodeModuleFromDirectory ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
916
958
}
917
959
@@ -996,7 +1038,7 @@ namespace ts {
996
1038
if ( traceEnabled ) {
997
1039
trace ( host , Diagnostics . Resolution_for_module_0_was_found_in_cache , moduleName ) ;
998
1040
}
999
- return { value : result . resolvedModule && { path : result . resolvedModule . resolvedFileName , extension : result . resolvedModule . extension } } ;
1041
+ return { value : result . resolvedModule && { path : result . resolvedModule . resolvedFileName , extension : result . resolvedModule . extension , packageId : result . resolvedModule . packageId } } ;
1000
1042
}
1001
1043
}
1002
1044
@@ -1010,7 +1052,7 @@ namespace ts {
1010
1052
return createResolvedModuleWithFailedLookupLocations ( resolved && resolved . value , /*isExternalLibraryImport*/ false , failedLookupLocations ) ;
1011
1053
1012
1054
function tryResolve ( extensions : Extensions ) : SearchResult < Resolved > {
1013
- const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings ( extensions , moduleName , containingDirectory , loadModuleFromFile , failedLookupLocations , state ) ;
1055
+ const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings ( extensions , moduleName , containingDirectory , loadModuleFromFileNoPackageId , failedLookupLocations , state ) ;
1014
1056
if ( resolvedUsingSettings ) {
1015
1057
return { value : resolvedUsingSettings } ;
1016
1058
}
@@ -1024,7 +1066,7 @@ namespace ts {
1024
1066
return resolutionFromCache ;
1025
1067
}
1026
1068
const searchName = normalizePath ( combinePaths ( directory , moduleName ) ) ;
1027
- return toSearchResult ( loadModuleFromFile ( extensions , searchName , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ) ;
1069
+ return toSearchResult ( loadModuleFromFileNoPackageId ( extensions , searchName , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ) ;
1028
1070
} ) ;
1029
1071
if ( resolved ) {
1030
1072
return resolved ;
@@ -1036,7 +1078,7 @@ namespace ts {
1036
1078
}
1037
1079
else {
1038
1080
const candidate = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
1039
- return toSearchResult ( loadModuleFromFile ( extensions , candidate , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ) ;
1081
+ return toSearchResult ( loadModuleFromFileNoPackageId ( extensions , candidate , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ) ;
1040
1082
}
1041
1083
}
1042
1084
}
0 commit comments