@@ -34,6 +34,10 @@ func continueSearching() *resolved {
34
34
return nil
35
35
}
36
36
37
+ func unresolved () * resolved {
38
+ return & resolved {}
39
+ }
40
+
37
41
type resolutionKindSpecificLoader = func (extensions extensions , candidate string , onlyRecordFailures bool ) * resolved
38
42
39
43
type resolutionState struct {
@@ -54,7 +58,7 @@ type resolutionState struct {
54
58
resolvedPackageDirectory bool
55
59
failedLookupLocations []string
56
60
affectingLocations []string
57
- diagnostics []ast.Diagnostic
61
+ diagnostics []* ast.Diagnostic
58
62
}
59
63
60
64
func newResolutionState (
@@ -748,10 +752,104 @@ func (r *resolutionState) loadModuleFromTargetExportOrImport(extensions extensio
748
752
}
749
753
750
754
func (r * resolutionState ) tryLoadInputFileForPath (finalPath string , entry string , packagePath string , isImports bool ) * resolved {
751
- // !!!
755
+ // Replace any references to outputs for files in the program with the input files to support package self-names used with outDir
756
+ if ! r .isConfigLookup &&
757
+ (r .compilerOptions .DeclarationDir != "" || r .compilerOptions .OutDir != "" ) &&
758
+ ! strings .Contains (finalPath , "/node_modules/" ) &&
759
+ (r .compilerOptions .ConfigFilePath == "" || tspath .ContainsPath (
760
+ tspath .GetDirectoryPath (packagePath ),
761
+ r .compilerOptions .ConfigFilePath ,
762
+ tspath.ComparePathsOptions {
763
+ UseCaseSensitiveFileNames : r .resolver .host .FS ().UseCaseSensitiveFileNames (),
764
+ CurrentDirectory : r .resolver .host .GetCurrentDirectory (),
765
+ },
766
+ )) {
767
+
768
+ // Note: this differs from Strada's tryLoadInputFileForPath in that it
769
+ // does not attempt to perform "guesses", instead requring a clear root indicator.
770
+
771
+ var rootDir string
772
+ if r .compilerOptions .RootDir != "" {
773
+ // A `rootDir` compiler option strongly indicates the root location
774
+ rootDir = r .compilerOptions .RootDir
775
+ } else if r .compilerOptions .Composite .IsTrue () && r .compilerOptions .ConfigFilePath != "" {
776
+ // A `composite` project is using project references and has it's common src dir set to `.`, so it shouldn't need to check any other locations
777
+ rootDir = r .compilerOptions .ConfigFilePath
778
+ } else {
779
+ diagnostic := ast .NewDiagnostic (
780
+ nil ,
781
+ core.TextRange {},
782
+ core .IfElse (isImports ,
783
+ diagnostics .The_project_root_is_ambiguous_but_is_required_to_resolve_import_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate ,
784
+ diagnostics .The_project_root_is_ambiguous_but_is_required_to_resolve_export_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate ,
785
+ ),
786
+ core .IfElse (entry == "" , "." , entry ), // replace empty string with `.` - the reverse of the operation done when entries are built - so main entrypoint errors don't look weird
787
+ packagePath ,
788
+ )
789
+ r .diagnostics = append (r .diagnostics , diagnostic )
790
+ return unresolved ()
791
+ }
792
+
793
+ candidateDirectories := r .getOutputDirectoriesForBaseDirectory (rootDir )
794
+ for _ , candidateDir := range candidateDirectories {
795
+ if tspath .ContainsPath (candidateDir , finalPath , tspath.ComparePathsOptions {
796
+ UseCaseSensitiveFileNames : r .resolver .host .FS ().UseCaseSensitiveFileNames (),
797
+ CurrentDirectory : r .resolver .host .GetCurrentDirectory (),
798
+ }) {
799
+ // The matched export is looking up something in either the out declaration or js dir, now map the written path back into the source dir and source extension
800
+ pathFragment := finalPath [len (candidateDir )+ 1 :] // +1 to also remove directory separator
801
+ possibleInputBase := tspath .CombinePaths (rootDir , pathFragment )
802
+ jsAndDtsExtensions := []string {tspath .ExtensionMjs , tspath .ExtensionCjs , tspath .ExtensionJs , tspath .ExtensionJson , tspath .ExtensionDmts , tspath .ExtensionDcts , tspath .ExtensionDts }
803
+ for _ , ext := range jsAndDtsExtensions {
804
+ if tspath .FileExtensionIs (possibleInputBase , ext ) {
805
+ inputExts := r .getPossibleOriginalInputExtensionForExtension (possibleInputBase )
806
+ for _ , possibleExt := range inputExts {
807
+ if ! extensionIsOk (r .extensions , possibleExt ) {
808
+ continue
809
+ }
810
+ possibleInputWithInputExtension := tspath .ChangeExtension (possibleInputBase , possibleExt )
811
+ if r .resolver .host .FS ().FileExists (possibleInputWithInputExtension ) {
812
+ resolved := r .loadFileNameFromPackageJSONField (r .extensions , possibleInputWithInputExtension , "" , false )
813
+ if ! resolved .shouldContinueSearching () {
814
+ return resolved
815
+ }
816
+ }
817
+ }
818
+ }
819
+ }
820
+ }
821
+ }
822
+ }
752
823
return continueSearching ()
753
824
}
754
825
826
+ func (r * resolutionState ) getOutputDirectoriesForBaseDirectory (commonSourceDirGuess string ) []string {
827
+ // Config file output paths are processed to be relative to the host's current directory, while
828
+ // otherwise the paths are resolved relative to the common source dir the compiler puts together
829
+ currentDir := core .IfElse (r .compilerOptions .ConfigFilePath != "" , r .resolver .host .GetCurrentDirectory (), commonSourceDirGuess )
830
+ var candidateDirectories []string
831
+ if r .compilerOptions .DeclarationDir != "" {
832
+ candidateDirectories = append (candidateDirectories , tspath .GetNormalizedAbsolutePath (tspath .CombinePaths (currentDir , r .compilerOptions .DeclarationDir ), r .resolver .host .GetCurrentDirectory ()))
833
+ }
834
+ if r .compilerOptions .OutDir != "" && r .compilerOptions .OutDir != r .compilerOptions .DeclarationDir {
835
+ candidateDirectories = append (candidateDirectories , tspath .GetNormalizedAbsolutePath (tspath .CombinePaths (currentDir , r .compilerOptions .OutDir ), r .resolver .host .GetCurrentDirectory ()))
836
+ }
837
+ return candidateDirectories
838
+ }
839
+
840
+ func (r * resolutionState ) getPossibleOriginalInputExtensionForExtension (path string ) []string {
841
+ if tspath .FileExtensionIsOneOf (path , []string {tspath .ExtensionDmts , tspath .ExtensionMjs , tspath .ExtensionMts }) {
842
+ return []string {tspath .ExtensionMts , tspath .ExtensionMjs }
843
+ }
844
+ if tspath .FileExtensionIsOneOf (path , []string {tspath .ExtensionDcts , tspath .ExtensionCjs , tspath .ExtensionCts }) {
845
+ return []string {tspath .ExtensionCts , tspath .ExtensionCjs }
846
+ }
847
+ if tspath .FileExtensionIs (path , ".d.json.ts" ) {
848
+ return []string {tspath .ExtensionJson }
849
+ }
850
+ return []string {tspath .ExtensionTsx , tspath .ExtensionTs , tspath .ExtensionJsx , tspath .ExtensionJs }
851
+ }
852
+
755
853
func (r * resolutionState ) loadModuleFromNearestNodeModulesDirectory (typesScopeOnly bool ) * resolved {
756
854
mode := core .ResolutionModeCommonJS
757
855
if r .esmMode || r .conditionMatches ("import" ) {
@@ -1377,7 +1475,7 @@ func (r *resolutionState) loadFileNameFromPackageJSONField(extensions extensions
1377
1475
return & resolved {
1378
1476
path : path ,
1379
1477
extension : extension ,
1380
- resolvedUsingTsExtension : ! strings .HasSuffix (packageJSONValue , extension ),
1478
+ resolvedUsingTsExtension : packageJSONValue != "" && ! strings .HasSuffix (packageJSONValue , extension ),
1381
1479
}
1382
1480
}
1383
1481
return continueSearching ()
0 commit comments