@@ -1289,8 +1289,7 @@ namespace ts.server {
12891289 }
12901290
12911291 const configFilePath = project instanceof server . ConfiguredProject && project . getConfigFilePath ( ) ;
1292- const base = getBaseFileName ( configFilePath ) ;
1293- return base === "tsconfig.json" || base === "jsconfig.json" ? base : "other" ;
1292+ return getBaseConfigFileName ( configFilePath ) || "other" ;
12941293 }
12951294
12961295 function convertTypeAcquisition ( { enable, include, exclude } : TypeAcquisition ) : ProjectInfoTypeAcquisitionData {
@@ -1344,13 +1343,14 @@ namespace ts.server {
13441343
13451344 private updateNonInferredProjectFiles < T > ( project : ExternalProject | ConfiguredProject , newUncheckedFiles : T [ ] , propertyReader : FilePropertyReader < T > , clientFileName ?: string ) {
13461345 const projectRootFilesMap = project . getRootFilesMap ( ) ;
1347- const newRootScriptInfoMap : Map < ProjectRoot > = createMap < ProjectRoot > ( ) ;
1346+ const newRootScriptInfoMap = createMap < ProjectRoot > ( ) ;
13481347
13491348 for ( const f of newUncheckedFiles ) {
13501349 const newRootFile = propertyReader . getFileName ( f ) ;
13511350 const normalizedPath = toNormalizedPath ( newRootFile ) ;
13521351 let scriptInfo : ScriptInfo | NormalizedPath ;
13531352 let path : Path ;
1353+ // Use the project's lsHost so that it can use caching instead of reaching to disk for the query
13541354 if ( ! project . lsHost . fileExists ( newRootFile ) ) {
13551355 path = normalizedPathToPath ( normalizedPath , this . currentDirectory , this . toCanonicalFileName ) ;
13561356 const existingValue = projectRootFilesMap . get ( path ) ;
@@ -1378,7 +1378,7 @@ namespace ts.server {
13781378 newRootScriptInfoMap . set ( path , scriptInfo ) ;
13791379 }
13801380
1381- // project's root file map size is always going to be larger than new roots map
1381+ // project's root file map size is always going to be same or larger than new roots map
13821382 // as we have already all the new files to the project
13831383 if ( projectRootFilesMap . size > newRootScriptInfoMap . size ) {
13841384 projectRootFilesMap . forEach ( ( value , path ) => {
@@ -1388,12 +1388,14 @@ namespace ts.server {
13881388 }
13891389 else {
13901390 projectRootFilesMap . delete ( path ) ;
1391- project . markAsDirty ( ) ;
13921391 }
13931392 }
13941393 } ) ;
13951394 }
1396- project . markAsDirty ( ) ; // Just to ensure that even if root files dont change, the changes to the non root file are picked up
1395+
1396+ // Just to ensure that even if root files dont change, the changes to the non root file are picked up,
1397+ // mark the project as dirty unconditionally
1398+ project . markAsDirty ( ) ;
13971399 }
13981400
13991401 private updateNonInferredProject < T > ( project : ExternalProject | ConfiguredProject , newUncheckedFiles : T [ ] , propertyReader : FilePropertyReader < T > , newOptions : CompilerOptions , newTypeAcquisition : TypeAcquisition , compileOnSave : boolean , configFileErrors : Diagnostic [ ] ) {
@@ -1408,38 +1410,22 @@ namespace ts.server {
14081410
14091411 /**
14101412 * Read the config file of the project again and update the project
1411- * @param project
14121413 */
14131414 /* @internal */
14141415 reloadConfiguredProject ( project : ConfiguredProject ) {
14151416 // At this point, there is no reason to not have configFile in the host
1416-
1417- // note: the returned "success" is true does not mean the "configFileErrors" is empty.
1418- // because we might have tolerated the errors and kept going. So always return the configFileErrors
1419- // regardless the "success" here is true or not.
14201417 const host = project . getCachedServerHost ( ) ;
1418+
1419+ // Clear the cache since we are reloading the project from disk
14211420 host . clearCache ( ) ;
14221421 const configFileName = project . getConfigFilePath ( ) ;
14231422 this . logger . info ( `Reloading configured project ${ configFileName } ` ) ;
1424- const { projectOptions, configFileErrors, configFileSpecs } = this . convertConfigFileContentToProjectOptions ( configFileName , host ) ;
1425- project . configFileSpecs = configFileSpecs ;
1426- this . updateConfiguredProject ( project , projectOptions , configFileErrors ) ;
1427-
1428- if ( ! this . eventHandler ) {
1429- return ;
1430- }
14311423
1432- this . eventHandler ( < ConfigFileDiagEvent > {
1433- eventName : ConfigFileDiagEvent ,
1434- data : { configFileName, diagnostics : project . getGlobalProjectErrors ( ) || [ ] , triggerFile : configFileName }
1435- } ) ;
1436- }
1424+ // Read updated contents from disk
1425+ const { projectOptions, configFileErrors, configFileSpecs } = this . convertConfigFileContentToProjectOptions ( configFileName , host ) ;
14371426
1438- /**
1439- * Updates the configured project with updated config file contents
1440- * @param project
1441- */
1442- private updateConfiguredProject ( project : ConfiguredProject , projectOptions : ProjectOptions , configFileErrors : Diagnostic [ ] ) {
1427+ // Update the project
1428+ project . configFileSpecs = configFileSpecs ;
14431429 if ( this . exceededTotalSizeLimitForNonTsFiles ( project . canonicalConfigFilePath , projectOptions . compilerOptions , projectOptions . files , fileNamePropertyReader ) ) {
14441430 project . disableLanguageService ( ) ;
14451431 project . stopWatchingWildCards ( WatcherCloseReason . ProjectReloadHitMaxSize ) ;
@@ -1451,6 +1437,15 @@ namespace ts.server {
14511437 project . watchTypeRoots ( ) ;
14521438 }
14531439 this . updateNonInferredProject ( project , projectOptions . files , fileNamePropertyReader , projectOptions . compilerOptions , projectOptions . typeAcquisition , projectOptions . compileOnSave , configFileErrors ) ;
1440+
1441+ if ( ! this . eventHandler ) {
1442+ return ;
1443+ }
1444+
1445+ this . eventHandler ( < ConfigFileDiagEvent > {
1446+ eventName : ConfigFileDiagEvent ,
1447+ data : { configFileName, diagnostics : project . getGlobalProjectErrors ( ) || [ ] , triggerFile : configFileName }
1448+ } ) ;
14541449 }
14551450
14561451 /*@internal */
@@ -1587,8 +1582,8 @@ namespace ts.server {
15871582 }
15881583 if ( args . extraFileExtensions ) {
15891584 this . hostConfiguration . extraFileExtensions = args . extraFileExtensions ;
1590- // We need to update the projects because of we might interprete more/less files
1591- // depending on whether extra files extenstions are either added or removed
1585+ // We need to update the project structures again as it is possible that existing
1586+ // project structure could have more or less files depending on extensions permitted
15921587 this . reloadProjects ( ) ;
15931588 this . logger . info ( "Host file extension mappings updated" ) ;
15941589 }
@@ -1664,7 +1659,7 @@ namespace ts.server {
16641659 * If the there is no existing project it just opens the configured project for the config file
16651660 */
16661661 private reloadConfiguredsProjectForFiles ( openFiles : ScriptInfo [ ] , delayReload : boolean ) {
1667- const mapUpdatedProjects = createMap < true > ( ) ;
1662+ const updatedProjects = createMap < true > ( ) ;
16681663 // try to reload config file for all open files
16691664 for ( const info of openFiles ) {
16701665 // This tries to search for a tsconfig.json for the given file. If we found it,
@@ -1673,32 +1668,35 @@ namespace ts.server {
16731668 // otherwise we create a new one.
16741669 const configFileName = this . getConfigFileNameForFile ( info ) ;
16751670 if ( configFileName ) {
1676- let project = this . findConfiguredProjectByProjectName ( configFileName ) ;
1671+ const project = this . findConfiguredProjectByProjectName ( configFileName ) ;
16771672 if ( ! project ) {
1678- project = this . createConfiguredProject ( configFileName , info . fileName ) ;
1679- mapUpdatedProjects . set ( configFileName , true ) ;
1673+ this . createConfiguredProject ( configFileName , info . fileName ) ;
1674+ updatedProjects . set ( configFileName , true ) ;
16801675 }
1681- else if ( ! mapUpdatedProjects . has ( configFileName ) ) {
1676+ else if ( ! updatedProjects . has ( configFileName ) ) {
16821677 if ( delayReload ) {
16831678 project . pendingReload = true ;
16841679 this . delayUpdateProjectGraph ( project ) ;
16851680 }
16861681 else {
16871682 this . reloadConfiguredProject ( project ) ;
16881683 }
1689- mapUpdatedProjects . set ( configFileName , true ) ;
1684+ updatedProjects . set ( configFileName , true ) ;
16901685 }
16911686 }
16921687 }
16931688 }
16941689
16951690 /**
1696- * - script info can be never migrate to state - root file in inferred project, this is only a starting point
1697- * - if script info has more that one containing projects - it is not a root file in inferred project because:
1698- * - references in inferred project supercede the root part
1699- * - root/reference in non-inferred project beats root in inferred project
1691+ * Remove the root of inferred project if script info is part of another project
17001692 */
17011693 private removeRootOfInferredProjectIfNowPartOfOtherProject ( info : ScriptInfo ) {
1694+ // If the script info is root of inferred project, it could only be first containing project
1695+ // since info is added to inferred project and made root only when there are no other projects containing it
1696+ // So even if it is root of the inferred project and after project structure updates its now part
1697+ // of multiple project it needs to be removed from that inferred project because:
1698+ // - references in inferred project supercede the root part
1699+ // - root / reference in non - inferred project beats root in inferred project
17021700 if ( info . containingProjects . length > 1 &&
17031701 info . containingProjects [ 0 ] . projectKind === ProjectKind . Inferred &&
17041702 info . containingProjects [ 0 ] . isRoot ( info ) ) {
@@ -1728,8 +1726,8 @@ namespace ts.server {
17281726 if ( info . containingProjects . length === 0 ) {
17291727 this . assignScriptInfoToInferredProject ( info ) ;
17301728 }
1731- // Or remove the root of inferred project if is referenced in more than one projects
17321729 else {
1730+ // Or remove the root of inferred project if is referenced in more than one projects
17331731 this . removeRootOfInferredProjectIfNowPartOfOtherProject ( info ) ;
17341732 }
17351733 }
@@ -1848,7 +1846,7 @@ namespace ts.server {
18481846 if ( ! this . changedFiles ) {
18491847 this . changedFiles = [ scriptInfo ] ;
18501848 }
1851- else if ( this . changedFiles . indexOf ( scriptInfo ) < 0 ) {
1849+ else if ( ! contains ( this . changedFiles , scriptInfo ) ) {
18521850 this . changedFiles . push ( scriptInfo ) ;
18531851 }
18541852 }
@@ -2023,8 +2021,7 @@ namespace ts.server {
20232021 const rootFiles : protocol . ExternalFile [ ] = [ ] ;
20242022 for ( const file of proj . rootFiles ) {
20252023 const normalized = toNormalizedPath ( file . fileName ) ;
2026- const baseFileName = getBaseFileName ( normalized ) ;
2027- if ( baseFileName === "tsconfig.json" || baseFileName === "jsconfig.json" ) {
2024+ if ( getBaseConfigFileName ( normalized ) ) {
20282025 if ( this . host . fileExists ( normalized ) ) {
20292026 ( tsConfigFiles || ( tsConfigFiles = [ ] ) ) . push ( normalized ) ;
20302027 }
0 commit comments