diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 34e92a81ea7..e6e4c8a5e7f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -87,7 +87,7 @@ namespace ts { return node.end - node.pos; } - export function arrayIsEqualTo(array1: T[], array2: T[], equaler?: (a: T, b: T) => boolean): boolean { + export function arrayIsEqualTo(array1: ReadonlyArray, array2: ReadonlyArray, equaler?: (a: T, b: T) => boolean): boolean { if (!array1 || !array2) { return array1 === array2; } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index d3e6849e3f9..394613bebe4 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -214,7 +214,6 @@ namespace ts.server { switch (response.kind) { case "set": this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typingOptions, response.typings); - project.setTypings(response.typings); project.updateGraph(); break; case "invalidate": diff --git a/src/server/project.ts b/src/server/project.ts index 492285ae364..e8293decdd3 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -47,7 +47,7 @@ namespace ts.server { */ private projectStateVersion = 0; - private typingFiles: string[]; + private typingFiles: TypingsArray; constructor( readonly projectKind: ProjectKind, @@ -226,18 +226,19 @@ namespace ts.server { if (!this.languageServiceEnabled) { return true; } - const hasChanges = this.updateGraphWorker(); + let hasChanges = this.updateGraphWorker(); + const cachedTypings = this.projectService.typingsCache.getTypingsForProject(this); + if (this.setTypings(cachedTypings)) { + hasChanges = this.updateGraphWorker() || hasChanges; + } if (hasChanges) { - if (this.setTypings(this.projectService.typingsCache.getTypingsForProject(this))) { - this.updateGraphWorker(); - } this.projectStructureVersion++; } return !hasChanges; } - setTypings(typings: string[]): boolean { - if (typings === this.typingFiles) { + private setTypings(typings: TypingsArray): boolean { + if (arrayIsEqualTo(this.typingFiles, typings)) { return false; } this.typingFiles = typings; diff --git a/src/server/typingsCache.ts b/src/server/typingsCache.ts index 4b5b2ceb9d4..2ab4f83b060 100644 --- a/src/server/typingsCache.ts +++ b/src/server/typingsCache.ts @@ -16,7 +16,7 @@ namespace ts.server { class TypingsCacheEntry { readonly typingOptions: TypingOptions; readonly compilerOptions: CompilerOptions; - readonly typings: string[]; + readonly typings: TypingsArray; } const emptyArray: any[] = []; @@ -43,9 +43,7 @@ namespace ts.server { if ((arr1 || emptyArray).length === 0 && (arr2 || emptyArray).length === 0) { return true; } -/* tslint:disable:no-null-keyword */ - const set: Map = Object.create(null); -/* tslint:enable:no-null-keyword */ + const set: Map = createMap(); let unique = 0; for (const v of arr1) { @@ -77,24 +75,33 @@ namespace ts.server { return opt1.allowJs != opt2.allowJs; } + export interface TypingsArray extends ReadonlyArray { + " __typingsArrayBrand": any; + } + + function toTypingsArray(arr: string[]): TypingsArray { + arr.sort(); + return arr; + } + export class TypingsCache { private readonly perProjectCache: Map = createMap(); constructor(private readonly installer: ITypingsInstaller) { } - getTypingsForProject(project: Project): Path[] { + getTypingsForProject(project: Project): TypingsArray { const typingOptions = getTypingOptionsForProjects(project); if (!typingOptions.enableAutoDiscovery) { - return emptyArray; + return emptyArray; } const entry = this.perProjectCache[project.getProjectName()]; if (!entry || typingOptionsChanged(typingOptions, entry.typingOptions) || compilerOptionsChanged(project.getCompilerOptions(), entry.compilerOptions)) { this.installer.enqueueInstallTypingsRequest(project, typingOptions); } - return entry ? entry.typings : emptyArray; + return entry ? entry.typings : emptyArray; } invalidateCachedTypingsForProject(project: Project) { @@ -109,7 +116,7 @@ namespace ts.server { this.perProjectCache[projectName] = { compilerOptions, typingOptions, - typings: newTypings + typings: toTypingsArray(newTypings) }; }