@@ -432,34 +432,55 @@ namespace ts.server {
432432 /*@internal */
433433 export function forEachResolvedProjectReferenceProject < T > (
434434 project : ConfiguredProject ,
435- cb : ( child : ConfiguredProject , configFileName : NormalizedPath ) => T | undefined ,
436- projectReferenceProjectLoadKind : ProjectReferenceProjectLoadKind . Find | ProjectReferenceProjectLoadKind . FindCreate
435+ cb : ( child : ConfiguredProject ) => T | undefined ,
436+ projectReferenceProjectLoadKind : ProjectReferenceProjectLoadKind . Find | ProjectReferenceProjectLoadKind . FindCreate ,
437437 ) : T | undefined ;
438438 /*@internal */
439439 export function forEachResolvedProjectReferenceProject < T > (
440440 project : ConfiguredProject ,
441- cb : ( child : ConfiguredProject , configFileName : NormalizedPath ) => T | undefined ,
442- projectReferenceProjectLoadKind : ProjectReferenceProjectLoadKind . FindCreateLoad ,
441+ cb : ( child : ConfiguredProject ) => T | undefined ,
442+ projectReferenceProjectLoadKind : ProjectReferenceProjectLoadKind ,
443443 reason : string
444444 ) : T | undefined ;
445445 export function forEachResolvedProjectReferenceProject < T > (
446446 project : ConfiguredProject ,
447- cb : ( child : ConfiguredProject , configFileName : NormalizedPath ) => T | undefined ,
447+ cb : ( child : ConfiguredProject ) => T | undefined ,
448448 projectReferenceProjectLoadKind : ProjectReferenceProjectLoadKind ,
449449 reason ?: string
450450 ) : T | undefined {
451- return forEachResolvedProjectReference ( project , ref => {
452- if ( ! ref ) return undefined ;
453- const configFileName = toNormalizedPath ( ref . sourceFile . fileName ) ;
454- const child = project . projectService . findConfiguredProjectByProjectName ( configFileName ) || (
455- projectReferenceProjectLoadKind === ProjectReferenceProjectLoadKind . FindCreate ?
456- project . projectService . createConfiguredProject ( configFileName ) :
457- projectReferenceProjectLoadKind === ProjectReferenceProjectLoadKind . FindCreateLoad ?
458- project . projectService . createAndLoadConfiguredProject ( configFileName , reason ! ) :
459- undefined
460- ) ;
461- return child && cb ( child , configFileName ) ;
462- } ) ;
451+ let seenResolvedRefs : ESMap < string , ProjectReferenceProjectLoadKind > | undefined ;
452+ return worker ( project . getCurrentProgram ( ) ?. getResolvedProjectReferences ( ) , project . getCompilerOptions ( ) ) ;
453+
454+ function worker ( resolvedProjectReferences : readonly ( ResolvedProjectReference | undefined ) [ ] | undefined , parentOptions : CompilerOptions ) : T | undefined {
455+ const loadKind = parentOptions . disableReferencedProjectLoad ? ProjectReferenceProjectLoadKind . Find : projectReferenceProjectLoadKind ;
456+ return forEach ( resolvedProjectReferences , ref => {
457+ if ( ! ref ) return undefined ;
458+
459+ const configFileName = toNormalizedPath ( ref . sourceFile . fileName ) ;
460+ const canonicalPath = project . projectService . toCanonicalFileName ( configFileName ) ;
461+ const seenValue = seenResolvedRefs ?. get ( canonicalPath ) ;
462+ if ( seenValue !== undefined && seenValue >= loadKind ) {
463+ return undefined ;
464+ }
465+ const child = project . projectService . findConfiguredProjectByProjectName ( configFileName ) || (
466+ loadKind === ProjectReferenceProjectLoadKind . Find ?
467+ undefined :
468+ loadKind === ProjectReferenceProjectLoadKind . FindCreate ?
469+ project . projectService . createConfiguredProject ( configFileName ) :
470+ loadKind === ProjectReferenceProjectLoadKind . FindCreateLoad ?
471+ project . projectService . createAndLoadConfiguredProject ( configFileName , reason ! ) :
472+ Debug . assertNever ( loadKind )
473+ ) ;
474+
475+ const result = child && cb ( child ) ;
476+ if ( result ) {
477+ return result ;
478+ }
479+
480+ ( seenResolvedRefs || ( seenResolvedRefs = new Map ( ) ) ) . set ( canonicalPath , loadKind ) ;
481+ return worker ( ref . references , ref . commandLine . options ) ;
482+ } ) ;
483+ }
463484 }
464485
465486 /*@internal */
@@ -2773,6 +2794,12 @@ namespace ts.server {
27732794 */
27742795 private reloadConfiguredProjectForFiles < T > ( openFiles : ESMap < Path , T > , delayReload : boolean , shouldReloadProjectFor : ( openFileValue : T ) => boolean , reason : string ) {
27752796 const updatedProjects = new Map < string , true > ( ) ;
2797+ const reloadChildProject = ( child : ConfiguredProject ) => {
2798+ if ( ! updatedProjects . has ( child . canonicalConfigFilePath ) ) {
2799+ updatedProjects . set ( child . canonicalConfigFilePath , true ) ;
2800+ this . reloadConfiguredProject ( child , reason ) ;
2801+ }
2802+ } ;
27762803 // try to reload config file for all open files
27772804 openFiles . forEach ( ( openFileValue , path ) => {
27782805 // Filter out the files that need to be ignored
@@ -2801,17 +2828,22 @@ namespace ts.server {
28012828 this . reloadConfiguredProject ( project , reason ) ;
28022829 // If this is solution, reload the project till the reloaded project contains the script info directly
28032830 if ( ! project . containsScriptInfo ( info ) && project . isSolution ( ) ) {
2804- forEachResolvedProjectReferenceProject (
2831+ const referencedProject = forEachResolvedProjectReferenceProject (
28052832 project ,
28062833 child => {
2807- if ( ! updatedProjects . has ( child . canonicalConfigFilePath ) ) {
2808- updatedProjects . set ( child . canonicalConfigFilePath , true ) ;
2809- this . reloadConfiguredProject ( child , reason ) ;
2810- }
2834+ reloadChildProject ( child ) ;
28112835 return projectContainsInfoDirectly ( child , info ) ;
28122836 } ,
28132837 ProjectReferenceProjectLoadKind . FindCreate
28142838 ) ;
2839+ if ( referencedProject ) {
2840+ // Reload the project's tree that is already present
2841+ forEachResolvedProjectReferenceProject (
2842+ project ,
2843+ reloadChildProject ,
2844+ ProjectReferenceProjectLoadKind . Find
2845+ ) ;
2846+ }
28152847 }
28162848 }
28172849 }
@@ -2913,7 +2945,7 @@ namespace ts.server {
29132945 const info = this . getScriptInfo ( fileName ) ;
29142946 return info && projectContainsInfoDirectly ( child , info ) ? child : undefined ;
29152947 } ,
2916- ProjectReferenceProjectLoadKind . FindCreateLoad ,
2948+ configuredProject . getCompilerOptions ( ) . disableReferencedProjectLoad ? ProjectReferenceProjectLoadKind . Find : ProjectReferenceProjectLoadKind . FindCreateLoad ,
29172949 `Creating project referenced in solution ${ configuredProject . projectName } to find possible configured project for original file: ${ originalFileInfo . fileName } ${ location !== originalLocation ? " for location: " + location . fileName : "" } `
29182950 ) ;
29192951 if ( ! configuredProject ) return undefined ;
@@ -2965,8 +2997,9 @@ namespace ts.server {
29652997 let configFileName : NormalizedPath | undefined ;
29662998 let configFileErrors : readonly Diagnostic [ ] | undefined ;
29672999 let project : ConfiguredProject | ExternalProject | undefined = this . findExternalProjectContainingOpenScriptInfo ( info ) ;
2968- let defaultConfigProject : ConfiguredProject | undefined ;
29693000 let retainProjects : ConfiguredProject [ ] | ConfiguredProject | undefined ;
3001+ let projectForConfigFileDiag : ConfiguredProject | undefined ;
3002+ let defaultConfigProjectIsCreated = false ;
29703003 if ( this . syntaxOnly ) {
29713004 // Invalidate resolutions in the file since this file is now open
29723005 info . containingProjects . forEach ( project => {
@@ -2981,30 +3014,22 @@ namespace ts.server {
29813014 project = this . findConfiguredProjectByProjectName ( configFileName ) ;
29823015 if ( ! project ) {
29833016 project = this . createLoadAndUpdateConfiguredProject ( configFileName , `Creating possible configured project for ${ info . fileName } to open` ) ;
2984- // Send the event only if the project got created as part of this open request and info is part of the project
2985- if ( ! project . containsScriptInfo ( info ) ) {
2986- // Since the file isnt part of configured project, do not send config file info
2987- configFileName = undefined ;
2988- }
2989- else {
2990- configFileErrors = project . getAllProjectErrors ( ) ;
2991- this . sendConfigFileDiagEvent ( project , info . fileName ) ;
2992- }
3017+ defaultConfigProjectIsCreated = true ;
29933018 }
29943019 else {
29953020 // Ensure project is ready to check if it contains opened script info
29963021 updateProjectIfDirty ( project ) ;
29973022 }
29983023
2999- defaultConfigProject = project ;
3000- retainProjects = defaultConfigProject ;
3024+ projectForConfigFileDiag = project . containsScriptInfo ( info ) ? project : undefined ;
3025+ retainProjects = project ;
30013026
30023027 // If this configured project doesnt contain script info but
30033028 // it is solution with project references, try those project references
3004- if ( ! project . containsScriptInfo ( info ) && project . isSolution ( ) ) {
3029+ if ( project . isSolution ( ) ) {
30053030 forEachResolvedProjectReferenceProject (
30063031 project ,
3007- ( child , childConfigFileName ) => {
3032+ child => {
30083033 updateProjectIfDirty ( child ) ;
30093034 // Retain these projects
30103035 if ( ! isArray ( retainProjects ) ) {
@@ -3016,20 +3041,35 @@ namespace ts.server {
30163041
30173042 // If script info belongs to this child project, use this as default config project
30183043 if ( projectContainsInfoDirectly ( child , info ) ) {
3019- configFileName = childConfigFileName ;
3020- configFileErrors = child . getAllProjectErrors ( ) ;
3021- this . sendConfigFileDiagEvent ( child , info . fileName ) ;
3044+ projectForConfigFileDiag = child ;
30223045 return child ;
30233046 }
3047+
3048+ // If this project uses the script info (even through project reference), if default project is not found, use this for configFileDiag
3049+ if ( ! projectForConfigFileDiag && child . containsScriptInfo ( info ) ) {
3050+ projectForConfigFileDiag = child ;
3051+ }
30243052 } ,
30253053 ProjectReferenceProjectLoadKind . FindCreateLoad ,
30263054 `Creating project referenced in solution ${ project . projectName } to find possible configured project for ${ info . fileName } to open`
30273055 ) ;
30283056 }
3057+
3058+ // Send the event only if the project got created as part of this open request and info is part of the project
3059+ if ( projectForConfigFileDiag ) {
3060+ configFileName = projectForConfigFileDiag . getConfigFilePath ( ) ;
3061+ if ( projectForConfigFileDiag !== project || defaultConfigProjectIsCreated ) {
3062+ configFileErrors = projectForConfigFileDiag . getAllProjectErrors ( ) ;
3063+ this . sendConfigFileDiagEvent ( projectForConfigFileDiag , info . fileName ) ;
3064+ }
3065+ }
30293066 else {
3030- // Create ancestor configured project
3031- this . createAncestorProjects ( info , defaultConfigProject || project ) ;
3067+ // Since the file isnt part of configured project, do not send config file info
3068+ configFileName = undefined ;
30323069 }
3070+
3071+ // Create ancestor configured project
3072+ this . createAncestorProjects ( info , project ) ;
30333073 }
30343074 }
30353075
0 commit comments