@@ -281,6 +281,7 @@ namespace ts.server {
281281 export class Project {
282282 compilerService : CompilerService ;
283283 projectFilename : string ;
284+ projectFileWatcher : FileWatcher ;
284285 program : ts . Program ;
285286 filenameToSourceFile : ts . Map < ts . SourceFile > = { } ;
286287 updateGraphSeq = 0 ;
@@ -453,6 +454,11 @@ namespace ts.server {
453454 }
454455 }
455456
457+ watchedConfigFileChanged ( configFileName : string ) {
458+ this . log ( "Config File Changed: " + configFileName ) ;
459+ this . updateConfigFile ( configFileName ) ;
460+ }
461+
456462 log ( msg : string , type = "Err" ) {
457463 this . psLogger . msg ( msg , type ) ;
458464 }
@@ -529,6 +535,18 @@ namespace ts.server {
529535 }
530536 this . configuredProjects = configuredProjects ;
531537 }
538+
539+ removeConfiguredProject ( configFilename : string ) {
540+ let matchedProjects = this . configuredProjects . filter ( project => project . projectFilename == configFilename ) ;
541+ if ( matchedProjects . length > 0 ) {
542+ let projectToRemove = matchedProjects [ 0 ] ;
543+ projectToRemove . projectFileWatcher . close ( ) ;
544+
545+ let filenames = projectToRemove . getFileNameList ( ) ;
546+ filenames . forEach ( filename => this . closeOpenFile ( this . getScriptInfo ( filename ) ) ) ;
547+ filenames . forEach ( filename => this . openClientFile ( filename ) ) ;
548+ }
549+ }
532550
533551 setConfiguredProjectRoot ( info : ScriptInfo ) {
534552 for ( var i = 0 , len = this . configuredProjects . length ; i < len ; i ++ ) {
@@ -583,7 +601,6 @@ namespace ts.server {
583601 /**
584602 * Remove this file from the set of open, non-configured files.
585603 * @param info The file that has been closed or newly configured
586- * @param openedByConfig True if info has become a root of a configured project
587604 */
588605 closeOpenFile ( info : ScriptInfo ) {
589606 var openFileRoots : ScriptInfo [ ] = [ ] ;
@@ -906,41 +923,75 @@ namespace ts.server {
906923 return false ;
907924 }
908925
909- openConfigFile ( configFilename : string , clientFileName ?: string ) : ProjectOpenResult {
926+ configFileToProjectOptions ( configFilename : string ) : { succeeded : boolean , projectOptions ?: ProjectOptions , error ? : ProjectOpenResult } {
910927 configFilename = ts . normalizePath ( configFilename ) ;
911928 // file references will be relative to dirPath (or absolute)
912929 var dirPath = ts . getDirectoryPath ( configFilename ) ;
913930 var rawConfig : { config ?: ProjectOptions ; error ?: Diagnostic ; } = ts . readConfigFile ( configFilename ) ;
914931 if ( rawConfig . error ) {
915- return rawConfig . error ;
932+ return { succeeded : false , error : rawConfig . error } ;
916933 }
917934 else {
918935 var parsedCommandLine = ts . parseConfigFile ( rawConfig . config , this . host , dirPath ) ;
919936 if ( parsedCommandLine . errors && ( parsedCommandLine . errors . length > 0 ) ) {
920- return { errorMsg : "tsconfig option errors" } ;
937+ return { succeeded : false , error : { errorMsg : "tsconfig option errors" } } ;
938+ }
939+ else if ( parsedCommandLine . fileNames == null ) {
940+ return { succeeded : false , error : { errorMsg : "no files found" } }
921941 }
922- else if ( parsedCommandLine . fileNames ) {
942+ else {
923943 var projectOptions : ProjectOptions = {
924944 files : parsedCommandLine . fileNames ,
925945 compilerOptions : parsedCommandLine . options
926946 } ;
927- var proj = this . createProject ( configFilename , projectOptions ) ;
928- for ( var i = 0 , len = parsedCommandLine . fileNames . length ; i < len ; i ++ ) {
929- var rootFilename = parsedCommandLine . fileNames [ i ] ;
930- if ( this . host . fileExists ( rootFilename ) ) {
931- var info = this . openFile ( rootFilename , clientFileName == rootFilename ) ;
932- proj . addRoot ( info ) ;
933- }
934- else {
935- return { errorMsg : "specified file " + rootFilename + " not found" } ;
936- }
947+ return { succeeded : true , projectOptions } ;
948+ }
949+ }
950+
951+ }
952+
953+ openConfigFile ( configFilename : string , clientFileName ?: string ) : ProjectOpenResult {
954+ let { succeeded, projectOptions, error } = this . configFileToProjectOptions ( configFilename ) ;
955+ if ( ! succeeded ) {
956+ return error ;
957+ }
958+ else {
959+ let proj = this . createProject ( configFilename , projectOptions ) ;
960+ for ( let i = 0 , len = projectOptions . files . length ; i < len ; i ++ ) {
961+ let rootFilename = projectOptions . files [ i ] ;
962+ if ( this . host . fileExists ( rootFilename ) ) {
963+ let info = this . openFile ( rootFilename , /*openedByClient*/ clientFileName == rootFilename ) ;
964+ proj . addRoot ( info ) ;
965+ }
966+ else {
967+ return { errorMsg : "specified file " + rootFilename + " not found" } ;
937968 }
938- proj . finishGraph ( ) ;
939- return { success : true , project : proj } ;
969+ }
970+ proj . finishGraph ( ) ;
971+ proj . projectFileWatcher = this . host . watchFile ( configFilename , _ => this . watchedConfigFileChanged ( configFilename ) ) ;
972+ return { success : true , project : proj } ;
973+ }
974+ }
975+
976+ updateConfigFile ( configFilename : string ) : ProjectOpenResult {
977+ let matchedProjects = this . configuredProjects . filter ( project => project . projectFilename == configFilename ) ;
978+ if ( matchedProjects !== null ) {
979+ let matchedProject = matchedProjects [ 0 ] ;
980+ // if the config file is deleted, remove the project and update project structure
981+ if ( ! this . host . fileExists ( configFilename ) ) {
982+ this . log ( "Config file deleted" ) ;
983+ this . removeConfiguredProject ( configFilename ) ;
940984 }
941985 else {
942- return { errorMsg : "no files found" } ;
986+ let { succeeded, projectOptions, error } = this . configFileToProjectOptions ( configFilename ) ;
987+ if ( ! succeeded ) {
988+ return error ;
989+ }
990+ else {
991+ matchedProject . setProjectOptions ( projectOptions ) ;
992+ }
943993 }
994+ this . updateProjectStructure ( ) ;
944995 }
945996 }
946997
0 commit comments