@@ -13,13 +13,32 @@ namespace ts {
1313 return compilerOptions . traceResolution && host . trace !== undefined ;
1414 }
1515
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. */
2031 interface Resolved {
2132 path : string ;
2233 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 ;
2342 }
2443
2544 /**
@@ -43,7 +62,7 @@ namespace ts {
4362
4463 function createResolvedModuleWithFailedLookupLocations ( resolved : Resolved | undefined , isExternalLibraryImport : boolean , failedLookupLocations : string [ ] ) : ResolvedModuleWithFailedLookupLocations {
4564 return {
46- resolvedModule : resolved && { resolvedFileName : resolved . path , extension : resolved . extension , isExternalLibraryImport } ,
65+ resolvedModule : resolved && { resolvedFileName : resolved . path , extension : resolved . extension , isExternalLibraryImport, packageId : resolved . packageId } ,
4766 failedLookupLocations
4867 } ;
4968 }
@@ -54,9 +73,16 @@ namespace ts {
5473 traceEnabled : boolean ;
5574 }
5675
76+ interface PackageJson {
77+ name ?: string ;
78+ version ?: string ;
79+ typings ?: string ;
80+ types ?: string ;
81+ main ?: string ;
82+ }
83+
5784 /** 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 {
6086 return readTypes ? tryReadFromField ( "typings" ) || tryReadFromField ( "types" ) : tryReadFromField ( "main" ) ;
6187
6288 function tryReadFromField ( fieldName : "typings" | "types" | "main" ) : string | undefined {
@@ -83,7 +109,7 @@ namespace ts {
83109 }
84110 }
85111
86- function readJson ( path : string , host : ModuleResolutionHost ) : { typings ?: string , types ?: string , main ?: string } {
112+ function readJson ( path : string , host : ModuleResolutionHost ) : PackageJson {
87113 try {
88114 const jsonText = host . readFile ( path ) ;
89115 return jsonText ? JSON . parse ( jsonText ) : { } ;
@@ -646,7 +672,7 @@ namespace ts {
646672 if ( extension !== undefined ) {
647673 const path = tryFile ( candidate , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
648674 if ( path !== undefined ) {
649- return { path, extension } ;
675+ return { path, extension, packageId : undefined } ;
650676 }
651677 }
652678
@@ -709,7 +735,7 @@ namespace ts {
709735 }
710736 const resolved = loadModuleFromNodeModules ( extensions , moduleName , containingDirectory , failedLookupLocations , state , cache ) ;
711737 // 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 } } ;
713739 }
714740 else {
715741 const candidate = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
@@ -747,7 +773,7 @@ namespace ts {
747773 }
748774 const resolvedFromFile = loadModuleFromFile ( extensions , candidate , failedLookupLocations , onlyRecordFailures , state ) ;
749775 if ( resolvedFromFile ) {
750- return resolvedFromFile ;
776+ return noPackageId ( resolvedFromFile ) ;
751777 }
752778 }
753779 if ( ! onlyRecordFailures ) {
@@ -768,11 +794,15 @@ namespace ts {
768794 return ! host . directoryExists || host . directoryExists ( directoryName ) ;
769795 }
770796
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+
771801 /**
772802 * @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
773803 * 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.
774804 */
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 {
776806 // First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
777807 const resolvedByAddingExtension = tryAddingExtensions ( candidate , extensions , failedLookupLocations , onlyRecordFailures , state ) ;
778808 if ( resolvedByAddingExtension ) {
@@ -792,7 +822,7 @@ namespace ts {
792822 }
793823
794824 /** 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 {
796826 if ( ! onlyRecordFailures ) {
797827 // check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
798828 const directory = getDirectoryPath ( candidate ) ;
@@ -810,9 +840,9 @@ namespace ts {
810840 return tryExtension ( Extension . Js ) || tryExtension ( Extension . Jsx ) ;
811841 }
812842
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 } ;
816846 }
817847 }
818848
@@ -838,12 +868,23 @@ namespace ts {
838868 function loadNodeModuleFromDirectory ( extensions : Extensions , candidate : string , failedLookupLocations : Push < string > , onlyRecordFailures : boolean , state : ModuleResolutionState , considerPackageJson = true ) : Resolved | undefined {
839869 const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( candidate , state . host ) ;
840870
871+ let packageId : PackageId | undefined ;
872+
841873 if ( considerPackageJson ) {
842874 const packageJsonPath = pathToPackageJson ( candidate ) ;
843875 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 ) ;
845886 if ( fromPackageJson ) {
846- return fromPackageJson ;
887+ return withPackageId ( packageId , fromPackageJson ) ;
847888 }
848889 }
849890 else {
@@ -855,15 +896,11 @@ namespace ts {
855896 }
856897 }
857898
858- return loadModuleFromFile ( extensions , combinePaths ( candidate , "index" ) , failedLookupLocations , ! directoryExists , state ) ;
899+ return withPackageId ( packageId , loadModuleFromFile ( extensions , combinePaths ( candidate , "index" ) , failedLookupLocations , ! directoryExists , state ) ) ;
859900 }
860901
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 ) ;
867904 if ( ! file ) {
868905 return undefined ;
869906 }
@@ -883,13 +920,18 @@ namespace ts {
883920 // Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
884921 const nextExtensions = extensions === Extensions . DtsOnly ? Extensions . TypeScript : extensions ;
885922 // 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+ }
887929 }
888930
889931 /** 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 ;
893935 }
894936
895937 /** True if `extension` is one of the supported `extensions`. */
@@ -911,7 +953,7 @@ namespace ts {
911953 function loadModuleFromNodeModulesFolder ( extensions : Extensions , moduleName : string , nodeModulesFolder : string , nodeModulesFolderExists : boolean , failedLookupLocations : Push < string > , state : ModuleResolutionState ) : Resolved | undefined {
912954 const candidate = normalizePath ( combinePaths ( nodeModulesFolder , moduleName ) ) ;
913955
914- return loadModuleFromFile ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ||
956+ return loadModuleFromFileNoPackageId ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ||
915957 loadNodeModuleFromDirectory ( extensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
916958 }
917959
@@ -996,7 +1038,7 @@ namespace ts {
9961038 if ( traceEnabled ) {
9971039 trace ( host , Diagnostics . Resolution_for_module_0_was_found_in_cache , moduleName ) ;
9981040 }
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 } } ;
10001042 }
10011043 }
10021044
@@ -1010,7 +1052,7 @@ namespace ts {
10101052 return createResolvedModuleWithFailedLookupLocations ( resolved && resolved . value , /*isExternalLibraryImport*/ false , failedLookupLocations ) ;
10111053
10121054 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 ) ;
10141056 if ( resolvedUsingSettings ) {
10151057 return { value : resolvedUsingSettings } ;
10161058 }
@@ -1024,7 +1066,7 @@ namespace ts {
10241066 return resolutionFromCache ;
10251067 }
10261068 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 ) ) ;
10281070 } ) ;
10291071 if ( resolved ) {
10301072 return resolved ;
@@ -1036,7 +1078,7 @@ namespace ts {
10361078 }
10371079 else {
10381080 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 ) ) ;
10401082 }
10411083 }
10421084 }
0 commit comments