@@ -817,6 +817,8 @@ namespace ts {
817817 let resolvedProjectReferences : readonly ( ResolvedProjectReference | undefined ) [ ] | undefined ;
818818 let projectReferenceRedirects : Map < ResolvedProjectReference | false > | undefined ;
819819 let mapFromFileToProjectReferenceRedirects : Map < Path > | undefined ;
820+ let mapFromToProjectReferenceRedirectSource : Map < SourceOfProjectReferenceRedirect > | undefined ;
821+ const useSourceOfProjectReferenceRedirect = ! ! host . useSourceOfProjectReferenceRedirect && host . useSourceOfProjectReferenceRedirect ( ) ;
820822
821823 const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles ( oldProgram , options ) ;
822824 // We set `structuralIsReused` to `undefined` because `tryReuseStructureFromOldProgram` calls `tryReuseStructureFromOldProgram` which checks
@@ -831,17 +833,32 @@ namespace ts {
831833 if ( ! resolvedProjectReferences ) {
832834 resolvedProjectReferences = projectReferences . map ( parseProjectReferenceConfigFile ) ;
833835 }
836+ if ( host . setResolvedProjectReferenceCallbacks ) {
837+ host . setResolvedProjectReferenceCallbacks ( {
838+ getSourceOfProjectReferenceRedirect,
839+ forEachResolvedProjectReference
840+ } ) ;
841+ }
834842 if ( rootNames . length ) {
835843 for ( const parsedRef of resolvedProjectReferences ) {
836844 if ( ! parsedRef ) continue ;
837845 const out = parsedRef . commandLine . options . outFile || parsedRef . commandLine . options . out ;
838- if ( out ) {
839- processSourceFile ( changeExtension ( out , ".d.ts" ) , /*isDefaultLib*/ false , /*ignoreNoDefaultLib*/ false , /*packageId*/ undefined ) ;
846+ if ( useSourceOfProjectReferenceRedirect ) {
847+ if ( out || getEmitModuleKind ( parsedRef . commandLine . options ) === ModuleKind . None ) {
848+ for ( const fileName of parsedRef . commandLine . fileNames ) {
849+ processSourceFile ( fileName , /*isDefaultLib*/ false , /*ignoreNoDefaultLib*/ false , /*packageId*/ undefined ) ;
850+ }
851+ }
840852 }
841- else if ( getEmitModuleKind ( parsedRef . commandLine . options ) === ModuleKind . None ) {
842- for ( const fileName of parsedRef . commandLine . fileNames ) {
843- if ( ! fileExtensionIs ( fileName , Extension . Dts ) && hasTSFileExtension ( fileName ) ) {
844- processSourceFile ( getOutputDeclarationFileName ( fileName , parsedRef . commandLine , ! host . useCaseSensitiveFileNames ( ) ) , /*isDefaultLib*/ false , /*ignoreNoDefaultLib*/ false , /*packageId*/ undefined ) ;
853+ else {
854+ if ( out ) {
855+ processSourceFile ( changeExtension ( out , ".d.ts" ) , /*isDefaultLib*/ false , /*ignoreNoDefaultLib*/ false , /*packageId*/ undefined ) ;
856+ }
857+ else if ( getEmitModuleKind ( parsedRef . commandLine . options ) === ModuleKind . None ) {
858+ for ( const fileName of parsedRef . commandLine . fileNames ) {
859+ if ( ! fileExtensionIs ( fileName , Extension . Dts ) && hasTSFileExtension ( fileName ) ) {
860+ processSourceFile ( getOutputDeclarationFileName ( fileName , parsedRef . commandLine , ! host . useCaseSensitiveFileNames ( ) ) , /*isDefaultLib*/ false , /*ignoreNoDefaultLib*/ false , /*packageId*/ undefined ) ;
861+ }
845862 }
846863 }
847864 }
@@ -955,6 +972,7 @@ namespace ts {
955972 getResolvedProjectReferenceToRedirect,
956973 getResolvedProjectReferenceByPath,
957974 forEachResolvedProjectReference,
975+ isSourceOfProjectReferenceRedirect,
958976 emitBuildInfo
959977 } ;
960978
@@ -987,9 +1005,15 @@ namespace ts {
9871005 return ts . toPath ( fileName , currentDirectory , getCanonicalFileName ) ;
9881006 }
9891007
1008+ function isValidSourceFileForEmit ( file : SourceFile ) {
1009+ // source file is allowed to be emitted and its not source of project reference redirect
1010+ return sourceFileMayBeEmitted ( file , options , isSourceFileFromExternalLibrary , getResolvedProjectReferenceToRedirect ) &&
1011+ ! isSourceOfProjectReferenceRedirect ( file . fileName ) ;
1012+ }
1013+
9901014 function getCommonSourceDirectory ( ) {
9911015 if ( commonSourceDirectory === undefined ) {
992- const emittedFiles = filter ( files , file => sourceFileMayBeEmitted ( file , options , isSourceFileFromExternalLibrary , getResolvedProjectReferenceToRedirect ) ) ;
1016+ const emittedFiles = filter ( files , file => isValidSourceFileForEmit ( file ) ) ;
9931017 if ( options . rootDir && checkSourceFilesBelongToPath ( emittedFiles , options . rootDir ) ) {
9941018 // If a rootDir is specified use it as the commonSourceDirectory
9951019 commonSourceDirectory = getNormalizedAbsolutePath ( options . rootDir , currentDirectory ) ;
@@ -1220,6 +1244,12 @@ namespace ts {
12201244 }
12211245 if ( projectReferences ) {
12221246 resolvedProjectReferences = projectReferences . map ( parseProjectReferenceConfigFile ) ;
1247+ if ( host . setResolvedProjectReferenceCallbacks ) {
1248+ host . setResolvedProjectReferenceCallbacks ( {
1249+ getSourceOfProjectReferenceRedirect,
1250+ forEachResolvedProjectReference
1251+ } ) ;
1252+ }
12231253 }
12241254
12251255 // check if program source files has changed in the way that can affect structure of the program
@@ -1403,6 +1433,13 @@ namespace ts {
14031433 for ( const newSourceFile of newSourceFiles ) {
14041434 const filePath = newSourceFile . path ;
14051435 addFileToFilesByName ( newSourceFile , filePath , newSourceFile . resolvedPath ) ;
1436+ if ( useSourceOfProjectReferenceRedirect ) {
1437+ const redirectProject = getProjectReferenceRedirectProject ( newSourceFile . fileName ) ;
1438+ if ( redirectProject && ! ( redirectProject . commandLine . options . outFile || redirectProject . commandLine . options . out ) ) {
1439+ const redirect = getProjectReferenceOutputName ( redirectProject , newSourceFile . fileName ) ;
1440+ addFileToFilesByName ( newSourceFile , toPath ( redirect ) , /*redirectedPath*/ undefined ) ;
1441+ }
1442+ }
14061443 // Set the file as found during node modules search if it was found that way in old progra,
14071444 if ( oldProgram . isSourceFileFromExternalLibrary ( oldProgram . getSourceFileByPath ( newSourceFile . resolvedPath ) ! ) ) {
14081445 sourceFilesFoundSearchingNodeModules . set ( filePath , true ) ;
@@ -1682,7 +1719,7 @@ namespace ts {
16821719
16831720 function getSemanticDiagnosticsForFileNoCache ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] | undefined {
16841721 return runWithCancellationToken ( ( ) => {
1685- if ( skipTypeChecking ( sourceFile , options ) ) {
1722+ if ( skipTypeChecking ( sourceFile , options , program ) ) {
16861723 return emptyArray ;
16871724 }
16881725
@@ -2234,6 +2271,16 @@ namespace ts {
22342271
22352272 // Get source file from normalized fileName
22362273 function findSourceFile ( fileName : string , path : Path , isDefaultLib : boolean , ignoreNoDefaultLib : boolean , refFile : RefFile | undefined , packageId : PackageId | undefined ) : SourceFile | undefined {
2274+ if ( useSourceOfProjectReferenceRedirect ) {
2275+ const source = getSourceOfProjectReferenceRedirect ( fileName ) ;
2276+ if ( source ) {
2277+ const file = isString ( source ) ?
2278+ findSourceFile ( source , toPath ( source ) , isDefaultLib , ignoreNoDefaultLib , refFile , packageId ) :
2279+ undefined ;
2280+ if ( file ) addFileToFilesByName ( file , path , /*redirectedPath*/ undefined ) ;
2281+ return file ;
2282+ }
2283+ }
22372284 const originalFileName = fileName ;
22382285 if ( filesByName . has ( path ) ) {
22392286 const file = filesByName . get ( path ) ;
@@ -2282,7 +2329,7 @@ namespace ts {
22822329 }
22832330
22842331 let redirectedPath : Path | undefined ;
2285- if ( refFile ) {
2332+ if ( refFile && ! useSourceOfProjectReferenceRedirect ) {
22862333 const redirectProject = getProjectReferenceRedirectProject ( fileName ) ;
22872334 if ( redirectProject ) {
22882335 if ( redirectProject . commandLine . options . outFile || redirectProject . commandLine . options . out ) {
@@ -2451,6 +2498,36 @@ namespace ts {
24512498 } ) ;
24522499 }
24532500
2501+ function getSourceOfProjectReferenceRedirect ( file : string ) {
2502+ if ( ! isDeclarationFileName ( file ) ) return undefined ;
2503+ if ( mapFromToProjectReferenceRedirectSource === undefined ) {
2504+ mapFromToProjectReferenceRedirectSource = createMap ( ) ;
2505+ forEachResolvedProjectReference ( resolvedRef => {
2506+ if ( resolvedRef ) {
2507+ const out = resolvedRef . commandLine . options . outFile || resolvedRef . commandLine . options . out ;
2508+ if ( out ) {
2509+ // Dont know which source file it means so return true?
2510+ const outputDts = changeExtension ( out , Extension . Dts ) ;
2511+ mapFromToProjectReferenceRedirectSource ! . set ( toPath ( outputDts ) , true ) ;
2512+ }
2513+ else {
2514+ forEach ( resolvedRef . commandLine . fileNames , fileName => {
2515+ if ( ! fileExtensionIs ( fileName , Extension . Dts ) && hasTSFileExtension ( fileName ) ) {
2516+ const outputDts = getOutputDeclarationFileName ( fileName , resolvedRef . commandLine , host . useCaseSensitiveFileNames ( ) ) ;
2517+ mapFromToProjectReferenceRedirectSource ! . set ( toPath ( outputDts ) , fileName ) ;
2518+ }
2519+ } ) ;
2520+ }
2521+ }
2522+ } ) ;
2523+ }
2524+ return mapFromToProjectReferenceRedirectSource . get ( toPath ( file ) ) ;
2525+ }
2526+
2527+ function isSourceOfProjectReferenceRedirect ( fileName : string ) {
2528+ return useSourceOfProjectReferenceRedirect && ! ! getResolvedProjectReferenceToRedirect ( fileName ) ;
2529+ }
2530+
24542531 function forEachProjectReference < T > (
24552532 projectReferences : readonly ProjectReference [ ] | undefined ,
24562533 resolvedProjectReferences : readonly ( ResolvedProjectReference | undefined ) [ ] | undefined ,
@@ -2858,8 +2935,7 @@ namespace ts {
28582935 const rootPaths = arrayToSet ( rootNames , toPath ) ;
28592936 for ( const file of files ) {
28602937 // Ignore file that is not emitted
2861- if ( ! sourceFileMayBeEmitted ( file , options , isSourceFileFromExternalLibrary , getResolvedProjectReferenceToRedirect ) ) continue ;
2862- if ( ! rootPaths . has ( file . path ) ) {
2938+ if ( isValidSourceFileForEmit ( file ) && ! rootPaths . has ( file . path ) ) {
28632939 addProgramDiagnosticAtRefPath (
28642940 file ,
28652941 rootPaths ,
0 commit comments