Skip to content

Commit

Permalink
Ensure that file updates are reflected
Browse files Browse the repository at this point in the history
  • Loading branch information
sheetalkamat committed Sep 4, 2020
1 parent 3bfa3d4 commit cd18da8
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 6 deletions.
18 changes: 17 additions & 1 deletion src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace ts.server {
export const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
export const ProjectInfoTelemetryEvent = "projectInfo";
export const OpenFileInfoTelemetryEvent = "openFileInfo";
const ensureProjectForOpenFileSchedule = "*ensureProjectForOpenFiles*";

export interface ProjectsUpdatedInBackgroundEvent {
eventName: typeof ProjectsUpdatedInBackgroundEvent;
Expand Down Expand Up @@ -878,7 +879,7 @@ namespace ts.server {
/*@internal*/
delayEnsureProjectForOpenFiles() {
this.pendingEnsureProjectForOpenFiles = true;
this.throttledOperations.schedule("*ensureProjectForOpenFiles*", /*delay*/ 2500, () => {
this.throttledOperations.schedule(ensureProjectForOpenFileSchedule, /*delay*/ 2500, () => {
if (this.pendingProjectUpdates.size !== 0) {
this.delayEnsureProjectForOpenFiles();
}
Expand Down Expand Up @@ -2796,6 +2797,21 @@ namespace ts.server {
// (and would separate out below reloading of projects to be called when immediate reload is needed)
// as there is no need to load contents of the files from the disk

// Reload script infos
this.filenameToScriptInfo.forEach(info => {
if (this.openFiles.has(info.path)) return; // Skip open files
if (!info.fileWatcher) return; // not watched file
// Handle as if file is changed or deleted
this.onSourceFileChanged(info, this.host.fileExists(info.fileName) ? FileWatcherEventKind.Changed : FileWatcherEventKind.Deleted);
});
// Cancel all project updates since we will be updating them now
this.pendingProjectUpdates.forEach((_project, projectName) => {
this.throttledOperations.cancel(projectName);
this.pendingProjectUpdates.delete(projectName);
});
this.throttledOperations.cancel(ensureProjectForOpenFileSchedule);
this.pendingEnsureProjectForOpenFiles = false;

// Reload Projects
this.reloadConfiguredProjectForFiles(this.openFiles as ESMap<Path, NormalizedPath | undefined>, /*clearSemanticCache*/ true, /*delayReload*/ false, returnTrue, "User requested reload projects");
this.externalProjects.forEach(project => {
Expand Down
40 changes: 35 additions & 5 deletions src/testRunner/unittests/tsserver/reloadProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,40 @@ namespace ts.projectSystem {
const file1: File = {
path: `${tscWatch.projectRoot}/file1.ts`,
content: `import { foo } from "module1";
foo();`
foo();
import { bar } from "./file2";
bar();`
};
const file2: File = {
path: `${tscWatch.projectRoot}/file2.ts`,
content: `${file1.content}
export function bar(){}`
content: `export function bar(){}`
};
const moduleFile: File = {
path: `${tscWatch.projectRoot}/node_modules/module1/index.d.ts`,
content: `export function foo(): string;`
};

function verifyFileUpdates(host: TestServerHost, service: TestProjectService, project: server.Project) {
// update file
const updatedText = `${file2.content}
bar();`;
host.writeFile(file2.path, updatedText);
host.checkTimeoutQueueLength(0);
service.reloadProjects();
assert.equal(project.getCurrentProgram()?.getSourceFile(file2.path)?.text, updatedText);

// delete file
host.deleteFile(file2.path);
host.checkTimeoutQueueLength(0);
service.reloadProjects();
assert.isUndefined(project.getCurrentProgram()?.getSourceFile(file2.path)?.text);
assert.isUndefined(service.getScriptInfo(file2.path));
}

it("configured project", () => {
const host = createServerHost([configFile, libFile, file1, file2]);
const service = createProjectService(host);
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
service.openClientFile(file1.path);
checkNumberOfProjects(service, { configuredProjects: 1 });
const project = service.configuredProjects.get(configFile.path)!;
Expand All @@ -37,18 +56,21 @@ namespace ts.projectSystem {
checkNumberOfProjects(service, { configuredProjects: 1 });
assert.strictEqual(service.configuredProjects.get(configFile.path), project);
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, configFile.path, moduleFile.path]);

verifyFileUpdates(host, service, project);
});

it("inferred project", () => {
const host = createServerHost([libFile, file1, file2]);
const service = createProjectService(host, /*parameters*/ undefined, { useInferredProjectPerProjectRoot: true, });
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
const timeoutId = host.getNextTimeoutId();
service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["node_modules"] }, tscWatch.projectRoot);
host.clearTimeout(timeoutId);
service.openClientFile(file1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, tscWatch.projectRoot);
checkNumberOfProjects(service, { inferredProjects: 1 });
const project = service.inferredProjects[0];
checkProjectActualFiles(project, [libFile.path, file1.path]);
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]);

// Install module1
host.ensureFileOrFolder(moduleFile);
Expand All @@ -57,12 +79,15 @@ namespace ts.projectSystem {
service.reloadProjects();
checkNumberOfProjects(service, { inferredProjects: 1 });
assert.strictEqual(service.inferredProjects[0], project);
checkProjectActualFiles(project, [libFile.path, file1.path, moduleFile.path]);
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, moduleFile.path]);

verifyFileUpdates(host, service, project);
});

it("external project", () => {
const host = createServerHost([libFile, file1, file2]);
const service = createProjectService(host);
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
service.openExternalProject({
projectFileName: `${tscWatch.projectRoot}/project.sln`,
options: { excludeDirectories: ["node_modules"] },
Expand All @@ -81,11 +106,14 @@ namespace ts.projectSystem {
checkNumberOfProjects(service, { externalProjects: 1 });
assert.strictEqual(service.externalProjects[0], project);
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, moduleFile.path]);

verifyFileUpdates(host, service, project);
});

it("external project with config file", () => {
const host = createServerHost([libFile, file1, file2, configFile]);
const service = createProjectService(host);
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
service.openExternalProject({
projectFileName: `${tscWatch.projectRoot}/project.sln`,
options: { excludeDirectories: ["node_modules"] },
Expand All @@ -104,6 +132,8 @@ namespace ts.projectSystem {
checkNumberOfProjects(service, { configuredProjects: 1 });
assert.strictEqual(service.configuredProjects.get(configFile.path), project);
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, configFile.path, moduleFile.path]);

verifyFileUpdates(host, service, project);
});
});
}

0 comments on commit cd18da8

Please sign in to comment.