From 6802f9a869eaa241540854c5e6a7c8417596655f Mon Sep 17 00:00:00 2001 From: zhengbli Date: Tue, 23 Aug 2016 13:40:07 -0700 Subject: [PATCH] refactor again --- .../unittests/tsserverProjectSystem.ts | 25 ++-- src/server/builder.ts | 128 ++++++++---------- src/server/project.ts | 4 +- 3 files changed, 74 insertions(+), 83 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index b3a190e88632f..afe089f20d412 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -459,7 +459,6 @@ namespace ts { seq: 0, type: "request", command, - canCompressResponse: false, arguments: args }; return newRequest; @@ -1522,6 +1521,7 @@ namespace ts { // A compile on save affected file request using file1 let moduleFile1FileListRequest: server.protocol.Request; let host: TestServerHost; + let typingsInstaller: server.ITypingsInstaller; let session: server.Session; beforeEach(() => { @@ -1590,7 +1590,8 @@ namespace ts { moduleFile1FileListRequest = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path }); host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); - session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, Utils.byteLength, Utils.maxUncompressedMessageSize, Utils.compress, process.hrtime, nullLogger); + typingsInstaller = new TestTypingsInstaller("/a/data/", host); + session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger); }); it("should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", () => { @@ -1717,7 +1718,8 @@ namespace ts { }; host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]); - session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, Utils.byteLength, Utils.maxUncompressedMessageSize, Utils.compress, process.hrtime, nullLogger); + typingsInstaller = new TestTypingsInstaller("/a/data/", host); + session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger); openFilesForSession([moduleFile1, file1Consumer1], session); sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [moduleFile1, file1Consumer1]); @@ -1755,7 +1757,8 @@ namespace ts { }; host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]); - session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, Utils.byteLength, Utils.maxUncompressedMessageSize, Utils.compress, process.hrtime, nullLogger); + typingsInstaller = new TestTypingsInstaller("/a/data/", host); + session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger); openFilesForSession([moduleFile1], session); sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, []); }); @@ -1772,7 +1775,8 @@ namespace ts { }; host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]); - session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, Utils.byteLength, Utils.maxUncompressedMessageSize, Utils.compress, process.hrtime, nullLogger); + typingsInstaller = new TestTypingsInstaller("/a/data/", host); + session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger); openFilesForSession([moduleFile1], session); const file1ChangeShapeRequest = makeSessionRequest(server.CommandNames.Change, { @@ -1800,7 +1804,8 @@ namespace ts { }; host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]); - session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, Utils.byteLength, Utils.maxUncompressedMessageSize, Utils.compress, process.hrtime, nullLogger); + typingsInstaller = new TestTypingsInstaller("/a/data/", host); + session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger); openFilesForSession([moduleFile1], session); const file1ChangeShapeRequest = makeSessionRequest(server.CommandNames.Change, { @@ -1821,7 +1826,8 @@ namespace ts { content: `import {y} from "./file1Consumer1";` }; host = createServerHost([moduleFile1, file1Consumer1, file1Consumer1Consumer1, globalFile3, configFile, libFile]); - session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, Utils.byteLength, Utils.maxUncompressedMessageSize, Utils.compress, process.hrtime, nullLogger); + typingsInstaller = new TestTypingsInstaller("/a/data/", host); + session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger); openFilesForSession([moduleFile1, file1Consumer1], session); sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [moduleFile1, file1Consumer1, file1Consumer1Consumer1]); @@ -1856,7 +1862,8 @@ namespace ts { content: `{}` }; const host = createServerHost([file1, file2, config, libFile]); - const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, Utils.byteLength, Utils.maxUncompressedMessageSize, Utils.compress, process.hrtime, nullLogger); + const typingsInstaller = new TestTypingsInstaller("/a/data/", host); + const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger); openFilesForSession([file1, file2], session); const compileFileRequest = makeSessionRequest(server.CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: config.path }); @@ -1867,7 +1874,7 @@ namespace ts { assert.equal(host.readFile(expectedEmittedFileName), `"use strict";\r\nfunction Foo() { return 10; }\r\nexports.Foo = Foo;\r\n`); }); }); - + describe("typings installer", () => { it("configured projects (tsd installed) 1", () => { const file1 = { diff --git a/src/server/builder.ts b/src/server/builder.ts index 345941b08c098..2462a93c024ea 100644 --- a/src/server/builder.ts +++ b/src/server/builder.ts @@ -89,7 +89,7 @@ namespace ts.server { private fileInfos = createFileMap(); - constructor(public readonly project: Project, private ctor: { new(scriptInfo: ScriptInfo, project: Project): T }) { + constructor(public readonly project: Project, private ctor: { new (scriptInfo: ScriptInfo, project: Project): T }) { } protected getFileInfo(path: Path): T { @@ -146,7 +146,7 @@ namespace ts.server { class NonModuleBuilder extends AbstractBuilder { - constructor(public project: Project) { + constructor(public readonly project: Project) { super(project, BuilderFileInfo); } @@ -160,22 +160,16 @@ namespace ts.server { */ getFilesAffectedBy(scriptInfo: ScriptInfo): string[] { const info = this.getOrCreateFileInfo(scriptInfo.path); - let result: string[]; if (info.updateShapeSignature()) { const options = this.project.getCompilerOptions(); // If `--out` or `--outFile` is specified, any new emit will result in re-emitting the entire project, // so returning the file itself is good enough. if (options && (options.out || options.outFile)) { - result = [scriptInfo.fileName]; + return [scriptInfo.fileName]; } - else { - result = this.project.getFileNamesWithoutDefaultLib(); - } - } - else { - result = [scriptInfo.fileName]; + return this.project.getFileNamesWithoutDefaultLib(); } - return result; + return [scriptInfo.fileName]; } } @@ -184,10 +178,6 @@ namespace ts.server { referencedBy: ModuleBuilderFileInfo[] = []; scriptVersionForReferences: string; - getReferencedByFileNames() { - return map(this.referencedBy, info => info.scriptInfo.fileName); - } - static compareFileInfos(lf: ModuleBuilderFileInfo, rf: ModuleBuilderFileInfo): number { const l = lf.scriptInfo.fileName; const r = rf.scriptInfo.fileName; @@ -197,12 +187,12 @@ namespace ts.server { static addToReferenceList(array: ModuleBuilderFileInfo[], fileInfo: ModuleBuilderFileInfo) { if (array.length === 0) { array.push(fileInfo); + return; } - else { - const insertIndex = binarySearch(array, fileInfo, ModuleBuilderFileInfo.compareFileInfos); - if (insertIndex < 0) { - array.splice(~insertIndex, 0, fileInfo); - } + + const insertIndex = binarySearch(array, fileInfo, ModuleBuilderFileInfo.compareFileInfos); + if (insertIndex < 0) { + array.splice(~insertIndex, 0, fileInfo); } } @@ -211,7 +201,7 @@ namespace ts.server { return; } - if (array.length === 1 && array[0] === fileInfo) { + if (array[0] === fileInfo) { array.splice(0, 1); return; } @@ -229,11 +219,18 @@ namespace ts.server { removeReferencedBy(fileInfo: ModuleBuilderFileInfo): void { ModuleBuilderFileInfo.removeFromReferenceList(this.referencedBy, fileInfo); } + + removeFileReferences() { + for (const reference of this.references) { + reference.removeReferencedBy(this); + } + this.references = []; + } } class ModuleBuilder extends AbstractBuilder { - constructor(public project: Project) { + constructor(public readonly project: Project) { super(project, ModuleBuilderFileInfo); } @@ -245,7 +242,7 @@ namespace ts.server { } const referencedFilePaths = this.project.getReferencedFiles(fileInfo.scriptInfo.path); - if (referencedFilePaths && referencedFilePaths.length > 0) { + if (referencedFilePaths.length > 0) { return map(referencedFilePaths, f => this.getFileInfo(f)).sort(ModuleBuilderFileInfo.compareFileInfos); } return []; @@ -265,7 +262,7 @@ namespace ts.server { this.forEachFileInfo(fileInfo => { if (!this.project.containsScriptInfo(fileInfo.scriptInfo)) { // This file was deleted from this project - this.removeFileReferences(fileInfo); + fileInfo.removeFileReferences(); this.removeFileInfo(fileInfo.scriptInfo.path); } }); @@ -319,66 +316,53 @@ namespace ts.server { fileInfo.scriptVersionForReferences = fileInfo.scriptInfo.getLatestVersion(); } - private removeFileReferences(fileInfo: ModuleBuilderFileInfo) { - for (const reference of fileInfo.references) { - reference.removeReferencedBy(fileInfo); - } - fileInfo.references = []; - } - getFilesAffectedBy(scriptInfo: ScriptInfo): string[] { this.ensureProjectDependencyGraphUpToDate(); const fileInfo = this.getFileInfo(scriptInfo.path); - if (fileInfo && fileInfo.updateShapeSignature()) { - let result: string[]; - if (!fileInfo.isExternalModuleOrHasOnlyAmbientExternalModules()) { - result = this.project.getFileNamesWithoutDefaultLib(); - } - else { - const options = this.project.getCompilerOptions(); - if (options && (options.isolatedModules || options.out || options.outFile)) { - result = [scriptInfo.fileName]; - } - else { - // Now we need to if each file in the referencedBy list has a shape change as well. - // Because if so, its own referencedBy files need to be saved as well to make the - // emitting result consistent with files on disk. - - // Use slice to clone the array to avoid manipulating in place - const queue = fileInfo.referencedBy.slice(0); - const fileNameSet: Map = {}; - fileNameSet[scriptInfo.fileName] = true; - while (queue.length > 0) { - const processingFileInfo = queue.pop(); - if (processingFileInfo.updateShapeSignature() && processingFileInfo.referencedBy.length > 0) { - for (const potentialFileInfo of processingFileInfo.referencedBy) { - if (!fileNameSet[potentialFileInfo.scriptInfo.fileName]) { - queue.push(potentialFileInfo); - } - } - } - fileNameSet[processingFileInfo.scriptInfo.fileName] = true; + if (!fileInfo || !fileInfo.updateShapeSignature()) { + return [scriptInfo.fileName]; + } + + if (!fileInfo.isExternalModuleOrHasOnlyAmbientExternalModules()) { + return this.project.getFileNamesWithoutDefaultLib(); + } + + const options = this.project.getCompilerOptions(); + if (options && (options.isolatedModules || options.out || options.outFile)) { + return [scriptInfo.fileName]; + } + + // Now we need to if each file in the referencedBy list has a shape change as well. + // Because if so, its own referencedBy files need to be saved as well to make the + // emitting result consistent with files on disk. + + // Use slice to clone the array to avoid manipulating in place + const queue = fileInfo.referencedBy.slice(0); + const fileNameSet = createMap(); + fileNameSet[scriptInfo.fileName] = true; + while (queue.length > 0) { + const processingFileInfo = queue.pop(); + if (processingFileInfo.updateShapeSignature() && processingFileInfo.referencedBy.length > 0) { + for (const potentialFileInfo of processingFileInfo.referencedBy) { + if (!fileNameSet[potentialFileInfo.scriptInfo.fileName]) { + queue.push(potentialFileInfo); } - result = getKeys(fileNameSet); } } - return result; + fileNameSet[processingFileInfo.scriptInfo.fileName] = true; } - return [scriptInfo.fileName]; + return Object.keys(fileNameSet); } } export function createBuilder(project: Project): Builder { - if (project.projectKind === ProjectKind.Configured || project.projectKind === ProjectKind.External) { - const moduleKind = project.getCompilerOptions().module; - switch (moduleKind) { - case ModuleKind.None: - return new NonModuleBuilder(project); - default: - return new ModuleBuilder(project); - } + const moduleKind = project.getCompilerOptions().module; + switch (moduleKind) { + case ModuleKind.None: + return new NonModuleBuilder(project); + default: + return new ModuleBuilder(project); } - return new NonModuleBuilder(project); } } \ No newline at end of file diff --git a/src/server/project.ts b/src/server/project.ts index e1efdfcfa4dcd..3a05130a4d9ba 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -422,7 +422,7 @@ namespace ts.server { // We need to use a set here since the code can contain the same import twice, // but that will only be one dependency. // To avoid invernal conversion, the key of the referencedFiles map must be of type Path - const referencedFiles: Map = {}; + const referencedFiles = createMap(); if (sourceFile.imports) { const checker: TypeChecker = this.program.getTypeChecker(); for (const importName of sourceFile.imports) { @@ -455,7 +455,7 @@ namespace ts.server { } } - return map(getKeys(referencedFiles), key => key); + return map(Object.keys(referencedFiles), key => key); } // remove a root file from project