@@ -15,8 +15,8 @@ namespace ts {
15
15
}
16
16
17
17
/* @internal */
18
- export function createResolvedModule ( resolvedFileName : string , isExternalLibraryImport : boolean , failedLookupLocations : string [ ] ) : ResolvedModuleWithFailedLookupLocations {
19
- return { resolvedModule : resolvedFileName ? { resolvedFileName, isExternalLibraryImport } : undefined , failedLookupLocations } ;
18
+ export function createResolvedModule ( resolvedFileName : string , isExternalLibraryImport : boolean , isUntyped : boolean , failedLookupLocations : string [ ] ) : ResolvedModuleWithFailedLookupLocations {
19
+ return { resolvedModule : resolvedFileName ? { resolvedFileName, isExternalLibraryImport, isUntyped } : undefined , failedLookupLocations } ;
20
20
}
21
21
22
22
function moduleHasNonRelativeName ( moduleName : string ) : boolean {
@@ -172,7 +172,7 @@ namespace ts {
172
172
for ( const typeRoot of primarySearchPaths ) {
173
173
const candidate = combinePaths ( typeRoot , typeReferenceDirectiveName ) ;
174
174
const candidateDirectory = getDirectoryPath ( candidate ) ;
175
- const resolvedFile = loadNodeModuleFromDirectory ( typeReferenceExtensions , candidate , failedLookupLocations ,
175
+ const resolvedFile = loadNodeModuleFromDirectoryNoPackageJson ( typeReferenceExtensions , candidate , failedLookupLocations ,
176
176
! directoryProbablyExists ( candidateDirectory , host ) , moduleResolutionState ) ;
177
177
178
178
if ( resolvedFile ) {
@@ -203,7 +203,7 @@ namespace ts {
203
203
if ( traceEnabled ) {
204
204
trace ( host , Diagnostics . Looking_up_in_node_modules_folder_initial_location_0 , initialLocationForSecondaryLookup ) ;
205
205
}
206
- resolvedFile = loadModuleFromNodeModules ( typeReferenceDirectiveName , initialLocationForSecondaryLookup , failedLookupLocations , moduleResolutionState , /*checkOneLevel*/ false ) ;
206
+ resolvedFile = loadTypedModuleFromNodeModules ( typeReferenceDirectiveName , initialLocationForSecondaryLookup , failedLookupLocations , moduleResolutionState , /*checkOneLevel*/ false ) ;
207
207
if ( traceEnabled ) {
208
208
if ( resolvedFile ) {
209
209
trace ( host , Diagnostics . Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2 , typeReferenceDirectiveName , resolvedFile , false ) ;
@@ -523,13 +523,18 @@ namespace ts {
523
523
failedLookupLocations , supportedExtensions , state ) ;
524
524
525
525
let isExternalLibraryImport = false ;
526
+ let isUntyped = false ;
526
527
if ( ! resolvedFileName ) {
527
528
if ( moduleHasNonRelativeName ( moduleName ) ) {
528
529
if ( traceEnabled ) {
529
530
trace ( host , Diagnostics . Loading_module_0_from_node_modules_folder , moduleName ) ;
530
531
}
531
- resolvedFileName = loadModuleFromNodeModules ( moduleName , containingDirectory , failedLookupLocations , state , /*checkOneLevel*/ false ) ;
532
- isExternalLibraryImport = resolvedFileName !== undefined ;
532
+ const result = loadModuleFromNodeModules ( moduleName , containingDirectory , failedLookupLocations , state , /*checkOneLevel*/ false , /*allowUntyped*/ ! compilerOptions . noImplicitAny ) ;
533
+ isExternalLibraryImport = result !== undefined ;
534
+ if ( isExternalLibraryImport ) {
535
+ resolvedFileName = result . path ;
536
+ isUntyped = result . isUntyped ;
537
+ }
533
538
}
534
539
else {
535
540
const candidate = normalizePath ( combinePaths ( containingDirectory , moduleName ) ) ;
@@ -541,11 +546,12 @@ namespace ts {
541
546
const originalFileName = resolvedFileName ;
542
547
resolvedFileName = normalizePath ( host . realpath ( resolvedFileName ) ) ;
543
548
if ( traceEnabled ) {
544
- trace ( host , Diagnostics . Resolving_real_path_for_0_result_1 , originalFileName , resolvedFileName ) ;
549
+ const diagnostic = isUntyped ? Diagnostics . Resolving_real_path_for_0_result_is_untyped_package_1 : Diagnostics . Resolving_real_path_for_0_result_1 ;
550
+ trace ( host , diagnostic , originalFileName , resolvedFileName ) ;
545
551
}
546
552
}
547
553
548
- return createResolvedModule ( resolvedFileName , isExternalLibraryImport , failedLookupLocations ) ;
554
+ return createResolvedModule ( resolvedFileName , isExternalLibraryImport , isUntyped , failedLookupLocations ) ;
549
555
}
550
556
551
557
function nodeLoadModuleByRelativeName ( candidate : string , supportedExtensions : string [ ] , failedLookupLocations : string [ ] ,
@@ -557,7 +563,7 @@ namespace ts {
557
563
558
564
const resolvedFileName = ! pathEndsWithDirectorySeparator ( candidate ) && loadModuleFromFile ( candidate , supportedExtensions , failedLookupLocations , onlyRecordFailures , state ) ;
559
565
560
- return resolvedFileName || loadNodeModuleFromDirectory ( supportedExtensions , candidate , failedLookupLocations , onlyRecordFailures , state ) ;
566
+ return resolvedFileName || loadNodeModuleFromDirectoryNoPackageJson ( supportedExtensions , candidate , failedLookupLocations , onlyRecordFailures , state ) ;
561
567
}
562
568
563
569
/* @internal */
@@ -619,10 +625,15 @@ namespace ts {
619
625
}
620
626
}
621
627
622
- function loadNodeModuleFromDirectory ( extensions : string [ ] , candidate : string , failedLookupLocation : string [ ] , onlyRecordFailures : boolean , state : ModuleResolutionState ) : string {
628
+ function loadNodeModuleFromDirectoryNoPackageJson ( extensions : string [ ] , candidate : string , failedLookupLocation : string [ ] , onlyRecordFailures : boolean , state : ModuleResolutionState ) : string {
629
+ return discardUntypedResults ( loadNodeModuleFromDirectory ( extensions , candidate , failedLookupLocation , onlyRecordFailures , state ) ) ;
630
+ }
631
+
632
+ function loadNodeModuleFromDirectory ( extensions : string [ ] , candidate : string , failedLookupLocation : string [ ] , onlyRecordFailures : boolean , state : ModuleResolutionState ) : ResolutionResult {
623
633
const packageJsonPath = pathToPackageJson ( candidate ) ;
624
634
const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( candidate , state . host ) ;
625
- if ( directoryExists && state . host . fileExists ( packageJsonPath ) ) {
635
+ const packageJsonExists = directoryExists && state . host . fileExists ( packageJsonPath ) ;
636
+ if ( packageJsonExists ) {
626
637
if ( state . traceEnabled ) {
627
638
trace ( state . host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
628
639
}
@@ -633,7 +644,7 @@ namespace ts {
633
644
const result = tryFile ( typesFile , failedLookupLocation , onlyRecordFailures , state ) ||
634
645
tryAddingExtensions ( typesFile , extensions , failedLookupLocation , onlyRecordFailures , state ) ;
635
646
if ( result ) {
636
- return result ;
647
+ return { isUntyped : false , path : result } ;
637
648
}
638
649
}
639
650
else {
@@ -650,57 +661,92 @@ namespace ts {
650
661
failedLookupLocation . push ( packageJsonPath ) ;
651
662
}
652
663
653
- return loadModuleFromFile ( combinePaths ( candidate , "index" ) , extensions , failedLookupLocation , ! directoryExists , state ) ;
664
+ const file = loadModuleFromFile ( combinePaths ( candidate , "index" ) , extensions , failedLookupLocation , ! directoryExists , state ) ;
665
+ return file
666
+ ? { isUntyped : false , path : file }
667
+ : packageJsonExists
668
+ ? { isUntyped : true , path : packageJsonPath }
669
+ : undefined ;
654
670
}
655
671
656
672
function pathToPackageJson ( directory : string ) : string {
657
673
return combinePaths ( directory , "package.json" ) ;
658
674
}
659
675
660
- function loadModuleFromNodeModulesFolder ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : string {
676
+ /** 3 cases: We may have found nothing, found a typed module (this includes `--allowJs`), or only found a package.json (so it's untyped). */
677
+ export type ResolutionResult = undefined | { isUntyped : boolean , path : string } ;
678
+
679
+ /** Gets only a typed resolution result. */
680
+ function discardUntypedResults ( result : ResolutionResult ) : string | undefined {
681
+ return result && ! result . isUntyped ? result . path : undefined ;
682
+ }
683
+
684
+ function loadTypedModuleFromNodeModulesFolder ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : string | undefined {
685
+ return discardUntypedResults ( loadModuleFromNodeModulesFolder ( moduleName , directory , failedLookupLocations , state ) ) ;
686
+ }
687
+
688
+ function loadModuleFromNodeModulesFolder ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : ResolutionResult {
661
689
const nodeModulesFolder = combinePaths ( directory , "node_modules" ) ;
662
690
const nodeModulesFolderExists = directoryProbablyExists ( nodeModulesFolder , state . host ) ;
663
691
const candidate = normalizePath ( combinePaths ( nodeModulesFolder , moduleName ) ) ;
664
692
const supportedExtensions = getSupportedExtensions ( state . compilerOptions ) ;
665
693
666
- let result = loadModuleFromFile ( candidate , supportedExtensions , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
667
- if ( result ) {
668
- return result ;
669
- }
670
- result = loadNodeModuleFromDirectory ( supportedExtensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
671
- if ( result ) {
672
- return result ;
673
- }
694
+ const file = loadModuleFromFile ( candidate , supportedExtensions , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
695
+ return file
696
+ ? { isUntyped : false , path : file }
697
+ : loadNodeModuleFromDirectory ( supportedExtensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
698
+ }
699
+
700
+ function loadTypedModuleFromNodeModules ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState , checkOneLevel : boolean ) : string | undefined {
701
+ return discardUntypedResults ( loadModuleFromNodeModules ( moduleName , directory , failedLookupLocations , state , checkOneLevel , /*allowUntyped*/ false ) ) ;
674
702
}
675
703
676
704
/* @internal */
677
- export function loadModuleFromNodeModules ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState , checkOneLevel : boolean ) : string {
678
- return loadModuleFromNodeModulesWorker ( moduleName , directory , failedLookupLocations , state , checkOneLevel , /*typesOnly*/ false ) ;
705
+ export function loadModuleFromNodeModules ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState , checkOneLevel : boolean , allowUntyped : boolean ) : ResolutionResult {
706
+ return loadModuleFromNodeModulesWorker ( moduleName , directory , failedLookupLocations , state , checkOneLevel , /*typesOnly*/ false , allowUntyped ) ;
679
707
}
680
708
681
- function loadModuleFromNodeModulesAtTypes ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : string {
682
- return loadModuleFromNodeModulesWorker ( moduleName , directory , failedLookupLocations , state , /*checkOneLevel*/ false , /*typesOnly*/ true ) ;
709
+ function loadModuleFromNodeModulesAtTypes ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : string | undefined {
710
+ return discardUntypedResults ( loadModuleFromNodeModulesWorker ( moduleName , directory , failedLookupLocations , state , /*checkOneLevel*/ false , /*typesOnly*/ true , /*allowUntyped*/ false ) ) ;
683
711
}
684
712
685
- function loadModuleFromNodeModulesWorker ( moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState , checkOneLevel : boolean , typesOnly : boolean ) : string {
713
+ function loadModuleFromNodeModulesWorker (
714
+ moduleName : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState , checkOneLevel : boolean , typesOnly : boolean , allowUntyped : boolean ) : ResolutionResult {
686
715
directory = normalizeSlashes ( directory ) ;
716
+ /**
717
+ * Remembers the path to a package.json for the package.
718
+ * If we have `/foo/node_modules/bar/package.json` and `/node_modules/@types/bar/index.d.ts` we want to return the latter,
719
+ * so we don't immediately return package.json results; we want to keep climbing to look for a typed package.
720
+ */
721
+ let packageJson : string | undefined ;
687
722
while ( true ) {
688
723
const baseName = getBaseFileName ( directory ) ;
689
724
if ( baseName !== "node_modules" ) {
690
- let packageResult : string | undefined ;
725
+ let packageResult : ResolutionResult ;
691
726
if ( ! typesOnly ) {
692
727
// Try to load source from the package
693
728
packageResult = loadModuleFromNodeModulesFolder ( moduleName , directory , failedLookupLocations , state ) ;
694
- if ( packageResult && hasTypeScriptFileExtension ( packageResult ) ) {
729
+ if ( packageResult && ! packageResult . isUntyped && hasTypeScriptFileExtension ( packageResult . path ) ) {
695
730
// Always prefer a TypeScript (.ts, .tsx, .d.ts) file shipped with the package
696
731
return packageResult ;
697
732
}
698
733
}
699
734
700
735
// 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 ;
736
+ const typesResult = loadTypedModuleFromNodeModulesFolder ( combinePaths ( "@types" , moduleName ) , directory , failedLookupLocations , state ) ;
737
+ if ( typesResult ) {
738
+ return { isUntyped : false , path : typesResult } ;
739
+ }
740
+
741
+ if ( packageResult ) {
742
+ if ( packageResult . isUntyped ) {
743
+ if ( allowUntyped ) {
744
+ packageJson = packageResult . path ;
745
+ }
746
+ }
747
+ else {
748
+ return packageResult ;
749
+ }
704
750
}
705
751
}
706
752
@@ -711,7 +757,8 @@ namespace ts {
711
757
712
758
directory = parentPath ;
713
759
}
714
- return undefined ;
760
+
761
+ return packageJson && { isUntyped : true , path : packageJson } ;
715
762
}
716
763
717
764
export function classicNameResolver ( moduleName : string , containingFile : string , compilerOptions : CompilerOptions , host : ModuleResolutionHost ) : ResolvedModuleWithFailedLookupLocations {
@@ -723,7 +770,7 @@ namespace ts {
723
770
724
771
const resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings ( moduleName , containingDirectory , loadModuleFromFile , failedLookupLocations , supportedExtensions , state ) ;
725
772
if ( resolvedFileName ) {
726
- return createResolvedModule ( resolvedFileName , /*isExternalLibraryImport*/ false , failedLookupLocations ) ;
773
+ return createResolvedModule ( resolvedFileName , /*isExternalLibraryImport*/ false , /*isUntyped*/ false , failedLookupLocations ) ;
727
774
}
728
775
729
776
let referencedSourceFile : string ;
@@ -737,7 +784,6 @@ namespace ts {
737
784
referencedSourceFile = loadModuleFromFile ( candidate , supportedExtensions , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
738
785
}
739
786
740
-
741
787
return referencedSourceFile
742
788
? { resolvedModule : { resolvedFileName : referencedSourceFile } , failedLookupLocations }
743
789
: { resolvedModule : undefined , failedLookupLocations } ;
0 commit comments