Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/harness/harnessLanguageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ namespace Harness.LanguageService {
const snapshot = this.getScriptSnapshot(path);
return snapshot.getText(0, snapshot.getLength());
}
getTypeRootsVersion() {
return 0;
}


log(s: string): void { }
Expand Down
12 changes: 12 additions & 0 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,15 @@ namespace ts.server {
this.printProjects();
}

private onTypeRootFileChanged(project: ConfiguredProject, fileName: string) {
this.logger.info(`Type root file ${fileName} changed`);
this.throttledOperations.schedule(project.configFileName + " * type root", /*delay*/ 250, () => {
project.updateTypes();
this.updateConfiguredProject(project); // TODO: Figure out why this is needed (should be redundant?)
this.refreshInferredProjects();
});
}

/**
* This is the callback function when a watched directory has added or removed source code files.
* @param project the project that associates with this directory watcher
Expand Down Expand Up @@ -395,6 +404,8 @@ namespace ts.server {
// For configured projects, the change is made outside the tsconfig file, and
// it is not likely to affect the project for other files opened by the client. We can
// just update the current project.

this.logger.info("Updating configured project");
this.updateConfiguredProject(project);

// Call refreshInferredProjects to clean up inferred projects we may have
Expand Down Expand Up @@ -771,6 +782,7 @@ namespace ts.server {
this.watchConfigDirectoryForProject(project, projectOptions);
}
project.watchWildcards((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
project.watchTypeRoots((project, path) => this.onTypeRootFileChanged(project, path));

this.configuredProjects.push(project);
return project;
Expand Down
4 changes: 4 additions & 0 deletions src/server/lsHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ namespace ts.server {
return this.project.getRootFilesLSHost();
}

getTypeRootsVersion() {
return this.project.typesVersion;
}

getScriptKind(fileName: string) {
const info = this.project.getScriptInfoLSHost(fileName);
return info && info.scriptKind;
Expand Down
30 changes: 30 additions & 0 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ namespace ts.server {

protected projectErrors: Diagnostic[];

public typesVersion = 0;

public isJsOnlyProject() {
this.updateGraph();
return allFilesAreJsOrDts(this);
Expand Down Expand Up @@ -153,6 +155,12 @@ namespace ts.server {
return this.program.getSourceFileByPath(path);
}

updateTypes() {
this.typesVersion++;
this.markAsDirty();
this.updateGraph();
}

close() {
if (this.program) {
// if we have a program - release all files that are enlisted in program
Expand Down Expand Up @@ -569,6 +577,7 @@ namespace ts.server {
private projectFileWatcher: FileWatcher;
private directoryWatcher: FileWatcher;
private directoriesWatchedForWildcards: Map<FileWatcher>;
private typeRootsWatchers: FileWatcher[];

/** Used for configured projects which may have multiple open roots */
openRefCount = 0;
Expand Down Expand Up @@ -608,6 +617,16 @@ namespace ts.server {
this.projectFileWatcher = this.projectService.host.watchFile(this.configFileName, _ => callback(this));
}

watchTypeRoots(callback: (project: ConfiguredProject, path: string) => void) {
const roots = this.getEffectiveTypeRoots();
const watchers: FileWatcher[] = [];
for (const root of roots) {
this.projectService.logger.info(`Add type root watcher for: ${root}`);
watchers.push(this.projectService.host.watchDirectory(root, path => callback(this, path), /*recursive*/ false));
}
this.typeRootsWatchers = watchers;
}

watchConfigDirectory(callback: (project: ConfiguredProject, path: string) => void) {
if (this.directoryWatcher) {
return;
Expand Down Expand Up @@ -651,6 +670,13 @@ namespace ts.server {
this.projectFileWatcher.close();
}

if (this.typeRootsWatchers) {
for (const watcher of this.typeRootsWatchers) {
watcher.close();
}
this.typeRootsWatchers = undefined;
}

for (const id in this.directoriesWatchedForWildcards) {
this.directoriesWatchedForWildcards[id].close();
}
Expand All @@ -667,6 +693,10 @@ namespace ts.server {
this.openRefCount--;
return this.openRefCount;
}

getEffectiveTypeRoots() {
return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host) || [];
}
}

export class ExternalProject extends Project {
Expand Down
13 changes: 13 additions & 0 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,11 @@ namespace ts {
readFile?(path: string, encoding?: string): string;
fileExists?(path: string): boolean;

/*
* LS host can optionally implement these methods to support automatic updating when new type libraries are installed
*/
getTypeRootsVersion?(): number;

/*
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
Expand Down Expand Up @@ -3099,6 +3104,7 @@ namespace ts {
let ruleProvider: formatting.RulesProvider;
let program: Program;
let lastProjectVersion: string;
let lastTypesRootVersion = 0;

const useCaseSensitivefileNames = host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames();
const cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
Expand Down Expand Up @@ -3215,6 +3221,13 @@ namespace ts {
};
}

const typeRootsVersion = host.getTypeRootsVersion ? host.getTypeRootsVersion() : 0;
if (lastTypesRootVersion !== typeRootsVersion) {
log("TypeRoots version has changed; provide new program");
program = undefined;
lastTypesRootVersion = typeRootsVersion;
}

const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
const newProgram = createProgram(hostCache.getRootFileNames(), newSettings, compilerHost, program);

Expand Down
8 changes: 8 additions & 0 deletions src/services/shims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ namespace ts {
getProjectVersion?(): string;
useCaseSensitiveFileNames?(): boolean;

getTypeRootsVersion?(): number;
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
readFile(path: string, encoding?: string): string;
fileExists(path: string): boolean;
Expand Down Expand Up @@ -358,6 +359,13 @@ namespace ts {
return this.shimHost.getProjectVersion();
}

public getTypeRootsVersion(): number {
if (!this.shimHost.getTypeRootsVersion) {
return 0;
}
return this.shimHost.getTypeRootsVersion();
}

public useCaseSensitiveFileNames(): boolean {
return this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false;
}
Expand Down