From 2612a74f633cd74fd0ed32cd1b5cfc813762dff0 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 19 Sep 2016 16:47:15 -0700 Subject: [PATCH 01/13] Working version --- src/server/editorServices.ts | 21 +++++++++++++++++++-- src/server/lsHost.ts | 11 +++++++++++ src/server/project.ts | 26 ++++++++++++++++++++++++++ src/server/utilities.ts | 4 ++++ src/services/services.ts | 13 +++++++++++++ src/services/shims.ts | 5 +++++ 6 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 34e438d37f..0596dffa68 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -363,6 +363,10 @@ namespace ts.server { this.printProjects(); } + private onTypeRootFileChanged(project: ConfiguredProject, fileName: string) { + this.onSourceFileInDirectoryChangedForConfiguredProject(project, fileName); + } + /** * 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 @@ -389,17 +393,29 @@ namespace ts.server { const newRootFiles = projectOptions.files.map((f => this.getCanonicalFileName(f))); const currentRootFiles = project.getRootFiles().map((f => this.getCanonicalFileName(f))); + const lastUpdateTypesRoot: number = Math.max.apply(Math, project.getEffectiveTypeRoots().map(root => { + this.logger.info('Compute for ' + root); + if (this.host.directoryExists(root)) { + return +this.host.getModifiedTime(root); + } + return 0; + })); + this.logger.info('Last type roots update = ' + lastUpdateTypesRoot + ', last was ' + project.lastUpdatedTypesRootTime); // We check if the project file list has changed. If so, we update the project. - if (!arrayIsEqualTo(currentRootFiles.sort(), newRootFiles.sort())) { + if (!arrayIsEqualTo(currentRootFiles.sort(), newRootFiles.sort()) || (lastUpdateTypesRoot > project.lastUpdatedTypesRootTime)) { // 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 // created for the new files this.refreshInferredProjects(); + + project.lastUpdatedTypesRootTime = lastUpdateTypesRoot; } } @@ -771,13 +787,14 @@ 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; } private watchConfigDirectoryForProject(project: ConfiguredProject, options: ProjectOptions): void { - if (!options.configHasFilesProperty) { + if (!options.configHasFilesProperty || (options.compilerOptions.types === undefined)) { project.watchConfigDirectory((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path)); } } diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index f6530953a5..e6fc699f23 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -145,6 +145,17 @@ namespace ts.server { return this.project.getRootFilesLSHost(); } + getTypeRootsVersion() { + const roots = ts.getEffectiveTypeRoots(this.project.getCompilerOptions(), this); + if (roots && roots.length > 0) { + return Math.max.apply(Math, roots.map(root => { + return +this.host.getModifiedTime(root); + })); + } else { + return 0; + } + } + getScriptKind(fileName: string) { const info = this.project.getScriptInfoLSHost(fileName); return info && info.scriptKind; diff --git a/src/server/project.ts b/src/server/project.ts index 9b4c7619fb..17d33b0413 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -569,9 +569,11 @@ namespace ts.server { private projectFileWatcher: FileWatcher; private directoryWatcher: FileWatcher; private directoriesWatchedForWildcards: Map; + private typeRootsWatchers: FileWatcher[]; /** Used for configured projects which may have multiple open roots */ openRefCount = 0; + lastUpdatedTypesRootTime = 0; constructor(readonly configFileName: NormalizedPath, projectService: ProjectService, @@ -608,6 +610,19 @@ namespace ts.server { this.projectFileWatcher = this.projectService.host.watchFile(this.configFileName, _ => callback(this)); } + watchTypeRoots(callback: (project: ConfiguredProject, path: string) => void) { + const roots = ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host); + this.projectService.logger.info(`Add type roots watchers for: ${roots}`); + const watchers: FileWatcher[] = []; + if (roots) { + 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), true)); + } + } + this.typeRootsWatchers = watchers; + } + watchConfigDirectory(callback: (project: ConfiguredProject, path: string) => void) { if (this.directoryWatcher) { return; @@ -651,6 +666,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(); } @@ -667,6 +689,10 @@ namespace ts.server { this.openRefCount--; return this.openRefCount; } + + getEffectiveTypeRoots() { + return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host); + } } export class ExternalProject extends Project { diff --git a/src/server/utilities.ts b/src/server/utilities.ts index a7a0160ea6..1814e5920e 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -216,6 +216,10 @@ namespace ts.server { * true if config file explicitly listed files **/ configHasFilesProperty?: boolean; + /** + * true if config file explicitly listed type names + **/ + configHasTypesProperty?: boolean; /** * these fields can be present in the project file **/ diff --git a/src/services/services.ts b/src/services/services.ts index 8c233c5698..e369aefa4b 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -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 @@ -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()); @@ -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); diff --git a/src/services/shims.ts b/src/services/shims.ts index f107809f3d..e564625451 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -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; @@ -358,6 +359,10 @@ namespace ts { return this.shimHost.getProjectVersion(); } + public getTypeRootsVersion(): number { + return this.shimHost.getTypeRootsVersion(); + } + public useCaseSensitiveFileNames(): boolean { return this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false; } From 6de3dc4f8b6e7c59d73b56f476d9eeb916da198c Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 19 Sep 2016 17:00:10 -0700 Subject: [PATCH 02/13] Cleanup --- src/server/editorServices.ts | 4 +--- src/server/project.ts | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 0596dffa68..05f6a38007 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -394,13 +394,11 @@ namespace ts.server { const newRootFiles = projectOptions.files.map((f => this.getCanonicalFileName(f))); const currentRootFiles = project.getRootFiles().map((f => this.getCanonicalFileName(f))); const lastUpdateTypesRoot: number = Math.max.apply(Math, project.getEffectiveTypeRoots().map(root => { - this.logger.info('Compute for ' + root); if (this.host.directoryExists(root)) { return +this.host.getModifiedTime(root); } return 0; })); - this.logger.info('Last type roots update = ' + lastUpdateTypesRoot + ', last was ' + project.lastUpdatedTypesRootTime); // We check if the project file list has changed. If so, we update the project. if (!arrayIsEqualTo(currentRootFiles.sort(), newRootFiles.sort()) || (lastUpdateTypesRoot > project.lastUpdatedTypesRootTime)) { @@ -794,7 +792,7 @@ namespace ts.server { } private watchConfigDirectoryForProject(project: ConfiguredProject, options: ProjectOptions): void { - if (!options.configHasFilesProperty || (options.compilerOptions.types === undefined)) { + if (!options.configHasFilesProperty) { project.watchConfigDirectory((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path)); } } diff --git a/src/server/project.ts b/src/server/project.ts index 17d33b0413..10782ed4bb 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -612,7 +612,6 @@ namespace ts.server { watchTypeRoots(callback: (project: ConfiguredProject, path: string) => void) { const roots = ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host); - this.projectService.logger.info(`Add type roots watchers for: ${roots}`); const watchers: FileWatcher[] = []; if (roots) { for (const root of roots) { From c1630e59d1855d009dcc8053e4d1fae346f189e5 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 19 Sep 2016 17:25:27 -0700 Subject: [PATCH 03/13] Fixup --- src/server/editorServices.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 05f6a38007..2ae3f812d4 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -364,7 +364,8 @@ namespace ts.server { } private onTypeRootFileChanged(project: ConfiguredProject, fileName: string) { - this.onSourceFileInDirectoryChangedForConfiguredProject(project, fileName); + this.updateConfiguredProject(project); + this.refreshInferredProjects(); } /** @@ -387,18 +388,27 @@ namespace ts.server { () => this.handleChangeInSourceFileForConfiguredProject(project)); } + getTypeRootsVersion(project: ConfiguredProject) { + const roots = project.getEffectiveTypeRoots(); + if (roots === undefined) { + return 0; + } + + return Math.max.apply(Math, project.getEffectiveTypeRoots().map(root => { + if (this.host.directoryExists(root)) { + return +this.host.getModifiedTime(root); + } + return 0; + })); + } + private handleChangeInSourceFileForConfiguredProject(project: ConfiguredProject) { const { projectOptions, configFileErrors } = this.convertConfigFileContentToProjectOptions(project.configFileName); this.reportConfigFileDiagnostics(project.getProjectName(), configFileErrors); const newRootFiles = projectOptions.files.map((f => this.getCanonicalFileName(f))); const currentRootFiles = project.getRootFiles().map((f => this.getCanonicalFileName(f))); - const lastUpdateTypesRoot: number = Math.max.apply(Math, project.getEffectiveTypeRoots().map(root => { - if (this.host.directoryExists(root)) { - return +this.host.getModifiedTime(root); - } - return 0; - })); + const lastUpdateTypesRoot: number = this.getTypeRootsVersion(project); // We check if the project file list has changed. If so, we update the project. if (!arrayIsEqualTo(currentRootFiles.sort(), newRootFiles.sort()) || (lastUpdateTypesRoot > project.lastUpdatedTypesRootTime)) { From 924a2bf03dfa8e052fbfa2a08f8c263179cb9bc6 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 19 Sep 2016 17:53:10 -0700 Subject: [PATCH 04/13] Remove unused --- src/harness/harness.ts | 2 +- src/harness/harnessLanguageService.ts | 5 ++++- src/server/editorServices.ts | 2 +- src/server/utilities.ts | 4 ---- src/services/services.ts | 4 ++-- src/services/shims.ts | 3 +++ 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 429a1aab80..b66d08bcb5 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1932,5 +1932,5 @@ namespace Harness { return { unitName: libFile, content: io.readFile(libFile) }; } - if (Error) (Error).stackTraceLimit = 1; + if (Error) (Error).stackTraceLimit = 25; } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index d73f1b6062..513c6be7ee 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -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 { } @@ -367,7 +370,7 @@ namespace Harness.LanguageService { function unwrapJSONCallResult(result: string): any { const parsedResult = JSON.parse(result); if (parsedResult.error) { - throw new Error("Language Service Shim Error: " + JSON.stringify(parsedResult.error)); + throw new Error("Language Service Shim Error: " + JSON.stringify(parsedResult)); } else if (parsedResult.canceled) { throw new ts.OperationCanceledException(); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 2ae3f812d4..4718fa36e4 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -416,7 +416,7 @@ namespace ts.server { // 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.logger.info("Updating configured project"); this.updateConfiguredProject(project); // Call refreshInferredProjects to clean up inferred projects we may have diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 1814e5920e..a7a0160ea6 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -216,10 +216,6 @@ namespace ts.server { * true if config file explicitly listed files **/ configHasFilesProperty?: boolean; - /** - * true if config file explicitly listed type names - **/ - configHasTypesProperty?: boolean; /** * these fields can be present in the project file **/ diff --git a/src/services/services.ts b/src/services/services.ts index e369aefa4b..7ef3a9b0ef 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1188,7 +1188,7 @@ namespace ts { /* * LS host can optionally implement these methods to support automatic updating when new type libraries are installed */ - getTypeRootsVersion?(): number; + getTypeRootsVersion(): number; /* * LS host can optionally implement this method if it wants to be completely in charge of module name resolution. @@ -3223,7 +3223,7 @@ namespace ts { const typeRootsVersion = host.getTypeRootsVersion ? host.getTypeRootsVersion() : 0; if (lastTypesRootVersion !== typeRootsVersion) { - log('TypeRoots version has changed; provide new program'); + log("TypeRoots version has changed; provide new program"); program = undefined; lastTypesRootVersion = typeRootsVersion; } diff --git a/src/services/shims.ts b/src/services/shims.ts index e564625451..f2ee5b4409 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -360,6 +360,9 @@ namespace ts { } public getTypeRootsVersion(): number { + if (!this.shimHost.getTypeRootsVersion) { + return 0; + } return this.shimHost.getTypeRootsVersion(); } From 46dfd68ef8bb4125b21e6bbc5b49b9da408370cd Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 19 Sep 2016 18:00:42 -0700 Subject: [PATCH 05/13] Always return [] --- src/server/project.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/project.ts b/src/server/project.ts index 10782ed4bb..e0b938a389 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -690,7 +690,7 @@ namespace ts.server { } getEffectiveTypeRoots() { - return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host); + return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host) || []; } } From c0806439ea0910e0cbdd93ec4a7df3a0cdd301a3 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 19 Sep 2016 18:20:50 -0700 Subject: [PATCH 06/13] Refactor --- src/harness/harness.ts | 2 +- src/harness/harnessLanguageService.ts | 2 +- src/server/editorServices.ts | 12 +----------- src/server/lsHost.ts | 8 +------- src/server/utilities.ts | 15 +++++++++++++++ src/services/services.ts | 2 +- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index b66d08bcb5..429a1aab80 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1932,5 +1932,5 @@ namespace Harness { return { unitName: libFile, content: io.readFile(libFile) }; } - if (Error) (Error).stackTraceLimit = 25; + if (Error) (Error).stackTraceLimit = 1; } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 513c6be7ee..6e34c80a3c 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -370,7 +370,7 @@ namespace Harness.LanguageService { function unwrapJSONCallResult(result: string): any { const parsedResult = JSON.parse(result); if (parsedResult.error) { - throw new Error("Language Service Shim Error: " + JSON.stringify(parsedResult)); + throw new Error("Language Service Shim Error: " + JSON.stringify(parsedResult.error)); } else if (parsedResult.canceled) { throw new ts.OperationCanceledException(); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 4718fa36e4..71d1188046 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -389,17 +389,7 @@ namespace ts.server { } getTypeRootsVersion(project: ConfiguredProject) { - const roots = project.getEffectiveTypeRoots(); - if (roots === undefined) { - return 0; - } - - return Math.max.apply(Math, project.getEffectiveTypeRoots().map(root => { - if (this.host.directoryExists(root)) { - return +this.host.getModifiedTime(root); - } - return 0; - })); + return getLatestDirectoryChangeTime(project.getEffectiveTypeRoots(), this.host); } private handleChangeInSourceFileForConfiguredProject(project: ConfiguredProject) { diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index e6fc699f23..0ae358591d 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -147,13 +147,7 @@ namespace ts.server { getTypeRootsVersion() { const roots = ts.getEffectiveTypeRoots(this.project.getCompilerOptions(), this); - if (roots && roots.length > 0) { - return Math.max.apply(Math, roots.map(root => { - return +this.host.getModifiedTime(root); - })); - } else { - return 0; - } + return getLatestChangeTime(roots, this.host); } getScriptKind(fileName: string) { diff --git a/src/server/utilities.ts b/src/server/utilities.ts index a7a0160ea6..cb7290711a 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -90,6 +90,21 @@ namespace ts.server { }; } + export function getLatestDirectoryChangeTime(paths: string[] | undefined, host: System) { + if (!host.getModifiedTime || !host.directoryExists || !paths) { + return 0; + } + + return Math.max.apply(Math, paths.map(path => { + if (host.directoryExists(path)) { + return host.getModifiedTime(path); + } + else { + return 0; + } + })); + } + export function mergeMaps(target: MapLike, source: MapLike ): void { for (const key in source) { if (hasProperty(source, key)) { diff --git a/src/services/services.ts b/src/services/services.ts index 7ef3a9b0ef..4b6e27e6c6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1188,7 +1188,7 @@ namespace ts { /* * LS host can optionally implement these methods to support automatic updating when new type libraries are installed */ - getTypeRootsVersion(): number; + getTypeRootsVersion?(): number; /* * LS host can optionally implement this method if it wants to be completely in charge of module name resolution. From 76f51ad37c1f6b79c3194467447f0832b6ddc4f9 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 19 Sep 2016 18:28:53 -0700 Subject: [PATCH 07/13] Cleanup --- src/server/editorServices.ts | 2 +- src/server/lsHost.ts | 2 +- src/server/utilities.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 71d1188046..45d67f4333 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -389,7 +389,7 @@ namespace ts.server { } getTypeRootsVersion(project: ConfiguredProject) { - return getLatestDirectoryChangeTime(project.getEffectiveTypeRoots(), this.host); + return server.getLatestDirectoryChangeTime(project.getEffectiveTypeRoots(), this.host); } private handleChangeInSourceFileForConfiguredProject(project: ConfiguredProject) { diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index 0ae358591d..bfd3fc0be2 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -147,7 +147,7 @@ namespace ts.server { getTypeRootsVersion() { const roots = ts.getEffectiveTypeRoots(this.project.getCompilerOptions(), this); - return getLatestChangeTime(roots, this.host); + return server.getLatestDirectoryChangeTime(roots, this.host); } getScriptKind(fileName: string) { diff --git a/src/server/utilities.ts b/src/server/utilities.ts index cb7290711a..300aa6e0e6 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -94,7 +94,7 @@ namespace ts.server { if (!host.getModifiedTime || !host.directoryExists || !paths) { return 0; } - + return Math.max.apply(Math, paths.map(path => { if (host.directoryExists(path)) { return host.getModifiedTime(path); From aa03a04c7fc069214a47f71f525201a59de52e89 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 20 Sep 2016 11:30:34 -0700 Subject: [PATCH 08/13] Use explicit coercion --- src/server/utilities.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 300aa6e0e6..9bc31704db 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -95,14 +95,14 @@ namespace ts.server { return 0; } - return Math.max.apply(Math, paths.map(path => { + return Math.max(...paths.map(path => { if (host.directoryExists(path)) { - return host.getModifiedTime(path); + return +host.getModifiedTime(path); } else { return 0; } - })); + }); } export function mergeMaps(target: MapLike, source: MapLike ): void { From 3c7b213a8cb93774960d1922f1366aded8e46d73 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 20 Sep 2016 12:07:52 -0700 Subject: [PATCH 09/13] PR updates --- src/server/editorServices.ts | 7 +++++-- src/server/project.ts | 10 ++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 45d67f4333..c48706f2e9 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -364,8 +364,11 @@ namespace ts.server { } private onTypeRootFileChanged(project: ConfiguredProject, fileName: string) { - this.updateConfiguredProject(project); - this.refreshInferredProjects(); + this.logger.info(`Type root file ${fileName} changed`); + this.throttledOperations.schedule(project.configFileName, /*delay*/ 250, () => { + this.updateConfiguredProject(project); + this.refreshInferredProjects(); + }); } /** diff --git a/src/server/project.ts b/src/server/project.ts index e0b938a389..a5c38fb188 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -611,13 +611,11 @@ namespace ts.server { } watchTypeRoots(callback: (project: ConfiguredProject, path: string) => void) { - const roots = ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.projectService.host); + const roots = this.getEffectiveTypeRoots(); const watchers: FileWatcher[] = []; - if (roots) { - 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), true)); - } + 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; } From 2dfcafe2b3702735eaaa788b98da81635cadddb4 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 20 Sep 2016 12:11:39 -0700 Subject: [PATCH 10/13] ) --- src/server/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 9bc31704db..4e444c3ce8 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -102,7 +102,7 @@ namespace ts.server { else { return 0; } - }); + })); } export function mergeMaps(target: MapLike, source: MapLike ): void { From 8c899a6c608e3fd850369a8a3e121613c3bfeed5 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 20 Sep 2016 16:52:34 -0700 Subject: [PATCH 11/13] An elegant weapon for a more civilized age --- src/server/editorServices.ts | 12 +++--------- src/server/lsHost.ts | 3 +-- src/server/project.ts | 9 ++++++++- src/server/utilities.ts | 15 --------------- 4 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index c48706f2e9..bb2e422152 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -365,7 +365,8 @@ namespace ts.server { private onTypeRootFileChanged(project: ConfiguredProject, fileName: string) { this.logger.info(`Type root file ${fileName} changed`); - this.throttledOperations.schedule(project.configFileName, /*delay*/ 250, () => { + this.throttledOperations.schedule(project.configFileName + ' * type root', /*delay*/ 250, () => { + project.updateTypes(); this.updateConfiguredProject(project); this.refreshInferredProjects(); }); @@ -391,20 +392,15 @@ namespace ts.server { () => this.handleChangeInSourceFileForConfiguredProject(project)); } - getTypeRootsVersion(project: ConfiguredProject) { - return server.getLatestDirectoryChangeTime(project.getEffectiveTypeRoots(), this.host); - } - private handleChangeInSourceFileForConfiguredProject(project: ConfiguredProject) { const { projectOptions, configFileErrors } = this.convertConfigFileContentToProjectOptions(project.configFileName); this.reportConfigFileDiagnostics(project.getProjectName(), configFileErrors); const newRootFiles = projectOptions.files.map((f => this.getCanonicalFileName(f))); const currentRootFiles = project.getRootFiles().map((f => this.getCanonicalFileName(f))); - const lastUpdateTypesRoot: number = this.getTypeRootsVersion(project); // We check if the project file list has changed. If so, we update the project. - if (!arrayIsEqualTo(currentRootFiles.sort(), newRootFiles.sort()) || (lastUpdateTypesRoot > project.lastUpdatedTypesRootTime)) { + if (!arrayIsEqualTo(currentRootFiles.sort(), newRootFiles.sort())) { // 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. @@ -415,8 +411,6 @@ namespace ts.server { // Call refreshInferredProjects to clean up inferred projects we may have // created for the new files this.refreshInferredProjects(); - - project.lastUpdatedTypesRootTime = lastUpdateTypesRoot; } } diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index bfd3fc0be2..5b33770ce2 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -146,8 +146,7 @@ namespace ts.server { } getTypeRootsVersion() { - const roots = ts.getEffectiveTypeRoots(this.project.getCompilerOptions(), this); - return server.getLatestDirectoryChangeTime(roots, this.host); + return this.project.typesVersion; } getScriptKind(fileName: string) { diff --git a/src/server/project.ts b/src/server/project.ts index a5c38fb188..01858b4cc6 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -69,6 +69,8 @@ namespace ts.server { protected projectErrors: Diagnostic[]; + public typesVersion = 0; + public isJsOnlyProject() { this.updateGraph(); return allFilesAreJsOrDts(this); @@ -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 @@ -573,7 +581,6 @@ namespace ts.server { /** Used for configured projects which may have multiple open roots */ openRefCount = 0; - lastUpdatedTypesRootTime = 0; constructor(readonly configFileName: NormalizedPath, projectService: ProjectService, diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 4e444c3ce8..a7a0160ea6 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -90,21 +90,6 @@ namespace ts.server { }; } - export function getLatestDirectoryChangeTime(paths: string[] | undefined, host: System) { - if (!host.getModifiedTime || !host.directoryExists || !paths) { - return 0; - } - - return Math.max(...paths.map(path => { - if (host.directoryExists(path)) { - return +host.getModifiedTime(path); - } - else { - return 0; - } - })); - } - export function mergeMaps(target: MapLike, source: MapLike ): void { for (const key in source) { if (hasProperty(source, key)) { From 6449e5c357ab43b2bf7a16c87b0a43354a34480a Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 20 Sep 2016 16:56:50 -0700 Subject: [PATCH 12/13] Lint --- src/server/editorServices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index bb2e422152..a1226a3d6f 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -365,7 +365,7 @@ namespace ts.server { private onTypeRootFileChanged(project: ConfiguredProject, fileName: string) { this.logger.info(`Type root file ${fileName} changed`); - this.throttledOperations.schedule(project.configFileName + ' * type root', /*delay*/ 250, () => { + this.throttledOperations.schedule(project.configFileName + " * type root", /*delay*/ 250, () => { project.updateTypes(); this.updateConfiguredProject(project); this.refreshInferredProjects(); From 52fddfa137a51921eb3184b69dcf7d5a2f29d38e Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 20 Sep 2016 17:12:07 -0700 Subject: [PATCH 13/13] Add TODO --- src/server/editorServices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index a1226a3d6f..3f0670edcc 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -367,7 +367,7 @@ namespace ts.server { this.logger.info(`Type root file ${fileName} changed`); this.throttledOperations.schedule(project.configFileName + " * type root", /*delay*/ 250, () => { project.updateTypes(); - this.updateConfiguredProject(project); + this.updateConfiguredProject(project); // TODO: Figure out why this is needed (should be redundant?) this.refreshInferredProjects(); }); }