@@ -1053,7 +1053,7 @@ export class ProjectService {
1053
1053
/**
1054
1054
* Open files: with value being project root path, and key being Path of the file that is open
1055
1055
*/
1056
- readonly openFiles : Map < string , NormalizedPath | undefined > = new Map < Path , NormalizedPath | undefined > ( ) ;
1056
+ readonly openFiles : Map < Path , NormalizedPath | undefined > = new Map < Path , NormalizedPath | undefined > ( ) ;
1057
1057
/** @internal */
1058
1058
readonly configFileForOpenFiles = new Map < Path , NormalizedPath | false > ( ) ;
1059
1059
/**
@@ -1364,7 +1364,7 @@ export class ProjectService {
1364
1364
const event : ProjectsUpdatedInBackgroundEvent = {
1365
1365
eventName : ProjectsUpdatedInBackgroundEvent ,
1366
1366
data : {
1367
- openFiles : arrayFrom ( this . openFiles . keys ( ) , path => this . getScriptInfoForPath ( path as Path ) ! . fileName ) ,
1367
+ openFiles : arrayFrom ( this . openFiles . keys ( ) , path => this . getScriptInfoForPath ( path ) ! . fileName ) ,
1368
1368
} ,
1369
1369
} ;
1370
1370
this . eventHandler ( event ) ;
@@ -1797,10 +1797,8 @@ export class ProjectService {
1797
1797
// Otherwise, we scheduled the update on configured project graph,
1798
1798
// we would need to schedule the project reload for only the root of inferred projects
1799
1799
// Get open files to reload projects for
1800
- this . reloadConfiguredProjectForFiles (
1801
- configFileExistenceInfo . openFilesImpactedByConfigFile ,
1802
- /*clearSemanticCache*/ false ,
1803
- /*delayReload*/ true ,
1800
+ this . delayReloadConfiguredProjectsForFile (
1801
+ configFileExistenceInfo ,
1804
1802
eventKind !== FileWatcherEventKind . Deleted ?
1805
1803
identity : // Reload open files if they are root of inferred project
1806
1804
returnTrue , // Reload all the open files impacted by config file
@@ -1809,6 +1807,44 @@ export class ProjectService {
1809
1807
this . delayEnsureProjectForOpenFiles ( ) ;
1810
1808
}
1811
1809
1810
+ /**
1811
+ * This function goes through all the openFiles and tries to file the config file for them.
1812
+ * If the config file is found and it refers to existing project, it schedules the reload it for reload
1813
+ * If there is no existing project it just opens the configured project for the config file
1814
+ * shouldReloadProjectFor provides a way to filter out files to reload configured project for
1815
+ */
1816
+ private delayReloadConfiguredProjectsForFile (
1817
+ configFileExistenceInfo : ConfigFileExistenceInfo ,
1818
+ shouldReloadProjectFor : ( infoIsRootOfInferredProject : boolean ) => boolean ,
1819
+ reason : string ,
1820
+ ) {
1821
+ const updatedProjects = new Set < ConfiguredProject > ( ) ;
1822
+ // try to reload config file for all open files
1823
+ configFileExistenceInfo . openFilesImpactedByConfigFile ?. forEach ( ( infoIsRootOfInferredProject , path ) => {
1824
+ // Invalidate default config file name for open file
1825
+ this . configFileForOpenFiles . delete ( path ) ;
1826
+ // Filter out the files that need to be ignored
1827
+ if ( ! shouldReloadProjectFor ( infoIsRootOfInferredProject ) ) {
1828
+ return ;
1829
+ }
1830
+ const info = this . getScriptInfoForPath ( path ) ! ;
1831
+ Debug . assert ( info . isScriptOpen ( ) ) ;
1832
+ // This tries to search for a tsconfig.json for the given file. If we found it,
1833
+ // we first detect if there is already a configured project created for it: if so,
1834
+ // we re- read the tsconfig file content and update the project only if we havent already done so
1835
+ // otherwise we create a new one.
1836
+ const configFileName = this . getConfigFileNameForFile ( info ) ;
1837
+ if ( configFileName ) {
1838
+ const project = this . findConfiguredProjectByProjectName ( configFileName ) || this . createConfiguredProject ( configFileName ) ;
1839
+ if ( tryAddToSet ( updatedProjects , project ) ) {
1840
+ project . pendingUpdateLevel = ProgramUpdateLevel . Full ;
1841
+ project . pendingUpdateReason = reason ;
1842
+ this . delayUpdateProjectGraph ( project ) ;
1843
+ }
1844
+ }
1845
+ } ) ;
1846
+ }
1847
+
1812
1848
private removeProject ( project : Project ) {
1813
1849
this . logger . info ( "`remove Project::" ) ;
1814
1850
project . print ( /*writeProjectFileNames*/ true , /*writeFileExplaination*/ true , /*writeFileVersionAndText*/ false ) ;
@@ -1917,7 +1953,7 @@ export class ProjectService {
1917
1953
private assignOrphanScriptInfosToInferredProject ( ) {
1918
1954
// collect orphaned files and assign them to inferred project just like we treat open of a file
1919
1955
this . openFiles . forEach ( ( projectRootPath , path ) => {
1920
- const info = this . getScriptInfoForPath ( path as Path ) ! ;
1956
+ const info = this . getScriptInfoForPath ( path ) ! ;
1921
1957
// collect all orphaned script infos from open files
1922
1958
if ( info . isOrphan ( ) ) {
1923
1959
this . assignOrphanScriptInfoToInferredProject ( info , projectRootPath ) ;
@@ -2319,7 +2355,7 @@ export class ProjectService {
2319
2355
2320
2356
this . logger . info ( "Open files: " ) ;
2321
2357
this . openFiles . forEach ( ( projectRootPath , path ) => {
2322
- const info = this . getScriptInfoForPath ( path as Path ) ! ;
2358
+ const info = this . getScriptInfoForPath ( path ) ! ;
2323
2359
this . logger . info ( `\tFileName: ${ info . fileName } ProjectRootPath: ${ projectRootPath } ` ) ;
2324
2360
this . logger . info ( `\t\tProjects: ${ info . containingProjects . map ( p => p . getProjectName ( ) ) } ` ) ;
2325
2361
} ) ;
@@ -3510,7 +3546,7 @@ export class ProjectService {
3510
3546
} ) ;
3511
3547
3512
3548
// Reload Projects
3513
- this . reloadConfiguredProjectForFiles ( this . openFiles as Map < Path , NormalizedPath | undefined > , /*clearSemanticCache*/ true , /*delayReload*/ false , returnTrue , "User requested reload projects" ) ;
3549
+ this . reloadConfiguredProjectForFiles ( "User requested reload projects" ) ;
3514
3550
this . externalProjects . forEach ( project => {
3515
3551
this . clearSemanticCache ( project ) ;
3516
3552
project . updateGraph ( ) ;
@@ -3525,26 +3561,19 @@ export class ProjectService {
3525
3561
/**
3526
3562
* This function goes through all the openFiles and tries to file the config file for them.
3527
3563
* If the config file is found and it refers to existing project, it reloads it either immediately
3528
- * or schedules it for reload depending on delayReload option
3529
3564
* If there is no existing project it just opens the configured project for the config file
3530
- * reloadForInfo provides a way to filter out files to reload configured project for
3531
3565
*/
3532
- private reloadConfiguredProjectForFiles < T > ( openFiles : Map < Path , T > | undefined , clearSemanticCache : boolean , delayReload : boolean , shouldReloadProjectFor : ( openFileValue : T ) => boolean , reason : string ) {
3533
- const updatedProjects = new Map < string , true > ( ) ;
3566
+ private reloadConfiguredProjectForFiles ( reason : string ) {
3567
+ const updatedProjects = new Set < ConfiguredProject > ( ) ;
3534
3568
const reloadChildProject = ( child : ConfiguredProject ) => {
3535
- if ( ! updatedProjects . has ( child . canonicalConfigFilePath ) ) {
3536
- updatedProjects . set ( child . canonicalConfigFilePath , true ) ;
3537
- this . reloadConfiguredProject ( child , reason , /*isInitialLoad*/ false , clearSemanticCache ) ;
3569
+ if ( tryAddToSet ( updatedProjects , child ) ) {
3570
+ this . reloadConfiguredProject ( child , reason , /*isInitialLoad*/ false , /*clearSemanticCache*/ true ) ;
3538
3571
}
3539
3572
} ;
3540
3573
// try to reload config file for all open files
3541
- openFiles ?. forEach ( ( openFileValue , path ) => {
3574
+ this . openFiles ?. forEach ( ( _projectRoot , path ) => {
3542
3575
// Invalidate default config file name for open file
3543
3576
this . configFileForOpenFiles . delete ( path ) ;
3544
- // Filter out the files that need to be ignored
3545
- if ( ! shouldReloadProjectFor ( openFileValue ) ) {
3546
- return ;
3547
- }
3548
3577
3549
3578
const info = this . getScriptInfoForPath ( path ) ! ; // TODO: GH#18217
3550
3579
Debug . assert ( info . isScriptOpen ( ) ) ;
@@ -3555,37 +3584,28 @@ export class ProjectService {
3555
3584
const configFileName = this . getConfigFileNameForFile ( info ) ;
3556
3585
if ( configFileName ) {
3557
3586
const project = this . findConfiguredProjectByProjectName ( configFileName ) || this . createConfiguredProject ( configFileName ) ;
3558
- if ( ! updatedProjects . has ( project . canonicalConfigFilePath ) ) {
3559
- updatedProjects . set ( project . canonicalConfigFilePath , true ) ;
3560
- if ( delayReload ) {
3561
- project . pendingUpdateLevel = ProgramUpdateLevel . Full ;
3562
- project . pendingUpdateReason = reason ;
3563
- if ( clearSemanticCache ) this . clearSemanticCache ( project ) ;
3564
- this . delayUpdateProjectGraph ( project ) ;
3565
- }
3566
- else {
3567
- // reload from the disk
3568
- this . reloadConfiguredProject ( project , reason , /*isInitialLoad*/ false , clearSemanticCache ) ;
3569
- // If this project does not contain this file directly, reload the project till the reloaded project contains the script info directly
3570
- if ( ! projectContainsInfoDirectly ( project , info ) ) {
3571
- const referencedProject = forEachResolvedProjectReferenceProject (
3587
+ if ( tryAddToSet ( updatedProjects , project ) ) {
3588
+ // reload from the disk
3589
+ this . reloadConfiguredProject ( project , reason , /*isInitialLoad*/ false , /*clearSemanticCache*/ true ) ;
3590
+ // If this project does not contain this file directly, reload the project till the reloaded project contains the script info directly
3591
+ if ( ! projectContainsInfoDirectly ( project , info ) ) {
3592
+ const referencedProject = forEachResolvedProjectReferenceProject (
3593
+ project ,
3594
+ info . path ,
3595
+ child => {
3596
+ reloadChildProject ( child ) ;
3597
+ return projectContainsInfoDirectly ( child , info ) ;
3598
+ } ,
3599
+ ProjectReferenceProjectLoadKind . FindCreate ,
3600
+ ) ;
3601
+ if ( referencedProject ) {
3602
+ // Reload the project's tree that is already present
3603
+ forEachResolvedProjectReferenceProject (
3572
3604
project ,
3573
- info . path ,
3574
- child => {
3575
- reloadChildProject ( child ) ;
3576
- return projectContainsInfoDirectly ( child , info ) ;
3577
- } ,
3578
- ProjectReferenceProjectLoadKind . FindCreate ,
3605
+ /*fileName*/ undefined ,
3606
+ reloadChildProject ,
3607
+ ProjectReferenceProjectLoadKind . Find ,
3579
3608
) ;
3580
- if ( referencedProject ) {
3581
- // Reload the project's tree that is already present
3582
- forEachResolvedProjectReferenceProject (
3583
- project ,
3584
- /*fileName*/ undefined ,
3585
- reloadChildProject ,
3586
- ProjectReferenceProjectLoadKind . Find ,
3587
- ) ;
3588
- }
3589
3609
}
3590
3610
}
3591
3611
}
@@ -3636,7 +3656,7 @@ export class ProjectService {
3636
3656
this . printProjects ( ) ;
3637
3657
3638
3658
this . openFiles . forEach ( ( projectRootPath , path ) => {
3639
- const info = this . getScriptInfoForPath ( path as Path ) ! ;
3659
+ const info = this . getScriptInfoForPath ( path ) ! ;
3640
3660
// collect all orphaned script infos from open files
3641
3661
if ( info . isOrphan ( ) ) {
3642
3662
this . assignOrphanScriptInfoToInferredProject ( info , projectRootPath ) ;
0 commit comments