@@ -385,7 +385,7 @@ namespace ts.server {
385
385
syntaxOnly ?: boolean ;
386
386
}
387
387
388
- interface OriginalFileInfo { fileName : NormalizedPath ; path : Path ; }
388
+ interface OriginalFileInfo { fileName : NormalizedPath ; path : Path ; openInfoPathForConfigFile ?: Path ; }
389
389
type OpenScriptInfoOrClosedFileInfo = ScriptInfo | OriginalFileInfo ;
390
390
391
391
function isOpenScriptInfo ( infoOrFileName : OpenScriptInfoOrClosedFileInfo ) : infoOrFileName is ScriptInfo {
@@ -1009,6 +1009,10 @@ namespace ts.server {
1009
1009
}
1010
1010
else {
1011
1011
this . logConfigFileWatchUpdate ( project . getConfigFilePath ( ) , project . canonicalConfigFilePath , configFileExistenceInfo , ConfigFileWatcherStatus . ReloadingInferredRootFiles ) ;
1012
+ if ( project . isInitialLoadPending ( ) ) {
1013
+ return ;
1014
+ }
1015
+
1012
1016
project . pendingReload = ConfigFileProgramReloadLevel . Full ;
1013
1017
project . pendingReloadReason = "Change in config file detected" ;
1014
1018
this . delayUpdateProjectGraph ( project ) ;
@@ -1416,32 +1420,38 @@ namespace ts.server {
1416
1420
}
1417
1421
1418
1422
Debug . assert ( ! isOpenScriptInfo ( info ) || this . openFiles . has ( info . path ) ) ;
1419
- const projectRootPath = this . openFiles . get ( info . path ) ;
1423
+ const openInfoPathForConfigFile = ! isOpenScriptInfo ( info ) ? info . openInfoPathForConfigFile : undefined ;
1424
+ const projectRootPath = this . openFiles . get ( openInfoPathForConfigFile || info . path ) ;
1420
1425
1421
1426
let searchPath = asNormalizedPath ( getDirectoryPath ( info . fileName ) ) ;
1422
1427
const isSearchPathInProjectRoot = ( ) => containsPath ( projectRootPath ! , searchPath , this . currentDirectory , ! this . host . useCaseSensitiveFileNames ) ;
1423
1428
1424
1429
// If projectRootPath doesn't contain info.path, then do normal search for config file
1425
1430
const anySearchPathOk = ! projectRootPath || ! isSearchPathInProjectRoot ( ) ;
1431
+ // For config files always ignore its directory since that would just result to same config file
1432
+ let ignoreDirectory = ! ! openInfoPathForConfigFile ;
1426
1433
do {
1427
- const canonicalSearchPath = normalizedPathToPath ( searchPath , this . currentDirectory , this . toCanonicalFileName ) ;
1428
- const tsconfigFileName = asNormalizedPath ( combinePaths ( searchPath , "tsconfig.json" ) ) ;
1429
- let result = action ( tsconfigFileName , combinePaths ( canonicalSearchPath , "tsconfig.json" ) ) ;
1430
- if ( result ) {
1431
- return tsconfigFileName ;
1432
- }
1434
+ if ( ! ignoreDirectory ) {
1435
+ const canonicalSearchPath = normalizedPathToPath ( searchPath , this . currentDirectory , this . toCanonicalFileName ) ;
1436
+ const tsconfigFileName = asNormalizedPath ( combinePaths ( searchPath , "tsconfig.json" ) ) ;
1437
+ let result = action ( tsconfigFileName , combinePaths ( canonicalSearchPath , "tsconfig.json" ) ) ;
1438
+ if ( result ) {
1439
+ return tsconfigFileName ;
1440
+ }
1433
1441
1434
- const jsconfigFileName = asNormalizedPath ( combinePaths ( searchPath , "jsconfig.json" ) ) ;
1435
- result = action ( jsconfigFileName , combinePaths ( canonicalSearchPath , "jsconfig.json" ) ) ;
1436
- if ( result ) {
1437
- return jsconfigFileName ;
1442
+ const jsconfigFileName = asNormalizedPath ( combinePaths ( searchPath , "jsconfig.json" ) ) ;
1443
+ result = action ( jsconfigFileName , combinePaths ( canonicalSearchPath , "jsconfig.json" ) ) ;
1444
+ if ( result ) {
1445
+ return jsconfigFileName ;
1446
+ }
1438
1447
}
1439
1448
1440
1449
const parentPath = asNormalizedPath ( getDirectoryPath ( searchPath ) ) ;
1441
1450
if ( parentPath === searchPath ) {
1442
1451
break ;
1443
1452
}
1444
1453
searchPath = parentPath ;
1454
+ ignoreDirectory = false ;
1445
1455
} while ( anySearchPathOk || isSearchPathInProjectRoot ( ) ) ;
1446
1456
1447
1457
return undefined ;
@@ -2431,7 +2441,7 @@ namespace ts.server {
2431
2441
if ( ! project ) {
2432
2442
project = this . createLoadAndUpdateConfiguredProject ( configFileName , `Creating possible configured project for ${ fileName } to open` ) ;
2433
2443
// Send the event only if the project got created as part of this open request and info is part of the project
2434
- if ( info . isOrphan ( ) ) {
2444
+ if ( ! project . containsScriptInfo ( info ) ) {
2435
2445
// Since the file isnt part of configured project, do not send config file info
2436
2446
configFileName = undefined ;
2437
2447
}
@@ -2444,6 +2454,8 @@ namespace ts.server {
2444
2454
// Ensure project is ready to check if it contains opened script info
2445
2455
updateProjectIfDirty ( project ) ;
2446
2456
}
2457
+ // Traverse till project Root and create those configured projects
2458
+ this . createAncestorConfiguredProjects ( info , project ) ;
2447
2459
}
2448
2460
}
2449
2461
@@ -2493,6 +2505,34 @@ namespace ts.server {
2493
2505
return { configFileName, configFileErrors } ;
2494
2506
}
2495
2507
2508
+ /**
2509
+ * Traverse till project Root and create those configured projects
2510
+ */
2511
+ private createAncestorConfiguredProjects ( info : ScriptInfo , project : ConfiguredProject ) {
2512
+ if ( ! project . containsScriptInfo ( info ) || ! project . getCompilerOptions ( ) . composite ) return ;
2513
+ const configPath = this . toPath ( project . canonicalConfigFilePath ) ;
2514
+ const configInfo : OriginalFileInfo = {
2515
+ fileName : project . getConfigFilePath ( ) ,
2516
+ path : configPath ,
2517
+ openInfoPathForConfigFile : info . path
2518
+ } ;
2519
+
2520
+ // Go create all configured projects till project root
2521
+ while ( true ) {
2522
+ const configFileName = this . getConfigFileNameForFile ( configInfo ) ;
2523
+ if ( ! configFileName ) return ;
2524
+
2525
+ // TODO: may be we should create only first project and then once its loaded,
2526
+ // do pending search if this is composite ?
2527
+ const ancestor = this . findConfiguredProjectByProjectName ( configFileName ) ||
2528
+ this . createConfiguredProjectWithDelayLoad ( configFileName , `Project possibly referencing default composite project ${ project . getProjectName ( ) } of open file ${ info . fileName } ` ) ;
2529
+ ancestor . setPotentialProjectRefence ( configPath ) ;
2530
+
2531
+ configInfo . fileName = configFileName ;
2532
+ configInfo . path = this . toPath ( configFileName ) ;
2533
+ }
2534
+ }
2535
+
2496
2536
private removeOrphanConfiguredProjects ( ) {
2497
2537
const toRemoveConfiguredProjects = cloneMap ( this . configuredProjects ) ;
2498
2538
@@ -2506,15 +2546,11 @@ namespace ts.server {
2506
2546
markOriginalProjectsAsUsed ( project ) ;
2507
2547
}
2508
2548
else {
2509
- // If the configured project for project reference has more than zero references, keep it alive
2510
- project . forEachResolvedProjectReference ( ref => {
2511
- if ( ref ) {
2512
- const refProject = this . configuredProjects . get ( ref . sourceFile . path ) ;
2513
- if ( refProject && refProject . hasOpenRef ( ) ) {
2514
- toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2515
- }
2516
- }
2517
- } ) ;
2549
+ project . forEachResolvedProjectReference (
2550
+ resolvedRef => markProjectAsUsedIfReferencedConfigWithOpenRef ( project , resolvedRef && this . configuredProjects . get ( resolvedRef . sourceFile . path ) ) ,
2551
+ projectRef => markProjectAsUsedIfReferencedConfigWithOpenRef ( project , this . configuredProjects . get ( this . toPath ( projectRef . path ) ) ) ,
2552
+ potentialProjectRef => markProjectAsUsedIfReferencedConfigWithOpenRef ( project , this . configuredProjects . get ( potentialProjectRef ) )
2553
+ ) ;
2518
2554
}
2519
2555
} ) ;
2520
2556
@@ -2526,6 +2562,13 @@ namespace ts.server {
2526
2562
project . originalConfiguredProjects . forEach ( ( _value , configuredProjectPath ) => toRemoveConfiguredProjects . delete ( configuredProjectPath ) ) ;
2527
2563
}
2528
2564
}
2565
+
2566
+ function markProjectAsUsedIfReferencedConfigWithOpenRef ( project : ConfiguredProject , refProject : ConfiguredProject | undefined ) {
2567
+ if ( refProject && refProject . hasOpenRef ( ) ) {
2568
+ toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2569
+ return true ;
2570
+ }
2571
+ }
2529
2572
}
2530
2573
2531
2574
private telemetryOnOpenFile ( scriptInfo : ScriptInfo ) : void {
0 commit comments