Skip to content

Commit 9b080fb

Browse files
committed
Add file watcher for tsconfig.json
1 parent 2c5ba08 commit 9b080fb

File tree

1 file changed

+69
-18
lines changed

1 file changed

+69
-18
lines changed

src/server/editorServices.ts

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)