@@ -95,7 +95,7 @@ namespace ts {
9595 currentDirectory = host . getCurrentDirectory ( ) ;
9696 }
9797
98- return currentDirectory && getDefaultTypeRoots ( currentDirectory , host ) ;
98+ return currentDirectory !== undefined && getDefaultTypeRoots ( currentDirectory , host ) ;
9999 }
100100
101101 /**
@@ -675,23 +675,33 @@ namespace ts {
675675
676676 /* @internal */
677677 export function loadModuleFromNodeModules ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState , checkOneLevel : boolean ) : string {
678+ return loadModuleFromNodeModulesWorker ( moduleName , directory , failedLookupLocations , state , checkOneLevel , /*typesOnly*/ false ) ;
679+ }
680+
681+ function loadModuleFromNodeModulesAtTypes ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : string {
682+ return loadModuleFromNodeModulesWorker ( moduleName , directory , failedLookupLocations , state , /*checkOneLevel*/ false , /*typesOnly*/ true ) ;
683+ }
684+
685+ function loadModuleFromNodeModulesWorker ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState , checkOneLevel : boolean , typesOnly : boolean ) : string {
678686 directory = normalizeSlashes ( directory ) ;
679687 while ( true ) {
680688 const baseName = getBaseFileName ( directory ) ;
681689 if ( baseName !== "node_modules" ) {
682- // Try to load source from the package
683- const packageResult = loadModuleFromNodeModulesFolder ( moduleName , directory , failedLookupLocations , state ) ;
684- if ( packageResult && hasTypeScriptFileExtension ( packageResult ) ) {
685- // Always prefer a TypeScript (.ts, .tsx, .d.ts) file shipped with the package
686- return packageResult ;
687- }
688- else {
689- // Else prefer a types package over non-TypeScript results (e.g. JavaScript files)
690- const typesResult = loadModuleFromNodeModulesFolder ( combinePaths ( "@types" , moduleName ) , directory , failedLookupLocations , state ) ;
691- if ( typesResult || packageResult ) {
692- return typesResult || packageResult ;
690+ let packageResult : string | undefined ;
691+ if ( ! typesOnly ) {
692+ // Try to load source from the package
693+ packageResult = loadModuleFromNodeModulesFolder ( moduleName , directory , failedLookupLocations , state ) ;
694+ if ( packageResult && hasTypeScriptFileExtension ( packageResult ) ) {
695+ // Always prefer a TypeScript (.ts, .tsx, .d.ts) file shipped with the package
696+ return packageResult ;
693697 }
694698 }
699+
700+ // Else prefer a types package over non-TypeScript results (e.g. JavaScript files)
701+ const typesResult = loadModuleFromNodeModulesFolder ( combinePaths ( "@types" , moduleName ) , directory , failedLookupLocations , state ) ;
702+ if ( typesResult || packageResult ) {
703+ return typesResult || packageResult ;
704+ }
695705 }
696706
697707 const parentPath = getDirectoryPath ( directory ) ;
@@ -709,7 +719,7 @@ namespace ts {
709719 const state = { compilerOptions, host, traceEnabled, skipTsx : ! compilerOptions . jsx } ;
710720 const failedLookupLocations : string [ ] = [ ] ;
711721 const supportedExtensions = getSupportedExtensions ( compilerOptions ) ;
712- let containingDirectory = getDirectoryPath ( containingFile ) ;
722+ const containingDirectory = getDirectoryPath ( containingFile ) ;
713723
714724 const resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings ( moduleName , containingDirectory , loadModuleFromFile , failedLookupLocations , supportedExtensions , state ) ;
715725 if ( resolvedFileName ) {
@@ -718,18 +728,9 @@ namespace ts {
718728
719729 let referencedSourceFile : string ;
720730 if ( moduleHasNonRelativeName ( moduleName ) ) {
721- while ( true ) {
722- const searchName = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
723- referencedSourceFile = loadModuleFromFile ( searchName , supportedExtensions , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
724- if ( referencedSourceFile ) {
725- break ;
726- }
727- const parentPath = getDirectoryPath ( containingDirectory ) ;
728- if ( parentPath === containingDirectory ) {
729- break ;
730- }
731- containingDirectory = parentPath ;
732- }
731+ referencedSourceFile = referencedSourceFile = loadModuleFromAncestorDirectories ( moduleName , containingDirectory , supportedExtensions , failedLookupLocations , state ) ||
732+ // If we didn't find the file normally, look it up in @types.
733+ loadModuleFromNodeModulesAtTypes ( moduleName , containingDirectory , failedLookupLocations , state ) ;
733734 }
734735 else {
735736 const candidate = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
@@ -741,4 +742,20 @@ namespace ts {
741742 ? { resolvedModule : { resolvedFileName : referencedSourceFile } , failedLookupLocations }
742743 : { resolvedModule : undefined , failedLookupLocations } ;
743744 }
745+
746+ /** Climb up parent directories looking for a module. */
747+ function loadModuleFromAncestorDirectories ( moduleName : string , containingDirectory : string , supportedExtensions : string [ ] , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : string | undefined {
748+ while ( true ) {
749+ const searchName = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
750+ const referencedSourceFile = loadModuleFromFile ( searchName , supportedExtensions , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
751+ if ( referencedSourceFile ) {
752+ return referencedSourceFile ;
753+ }
754+ const parentPath = getDirectoryPath ( containingDirectory ) ;
755+ if ( parentPath === containingDirectory ) {
756+ return undefined ;
757+ }
758+ containingDirectory = parentPath ;
759+ }
760+ }
744761}
0 commit comments