Skip to content

Commit

Permalink
refactor again
Browse files Browse the repository at this point in the history
  • Loading branch information
zhengbli committed Aug 23, 2016
1 parent 54f5c72 commit 6802f9a
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 83 deletions.
25 changes: 16 additions & 9 deletions src/harness/unittests/tsserverProjectSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,6 @@ namespace ts {
seq: 0,
type: "request",
command,
canCompressResponse: false,
arguments: args
};
return newRequest;
Expand Down Expand Up @@ -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(() => {
Expand Down Expand Up @@ -1590,7 +1590,8 @@ namespace ts {
moduleFile1FileListRequest = makeSessionRequest<server.protocol.FileRequestArgs>(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", () => {
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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, []);
});
Expand All @@ -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.protocol.ChangeRequestArgs>(server.CommandNames.Change, {
Expand Down Expand Up @@ -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.protocol.ChangeRequestArgs>(server.CommandNames.Change, {
Expand All @@ -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]);
Expand Down Expand Up @@ -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.protocol.CompileOnSaveEmitFileRequestArgs>(server.CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: config.path });
Expand All @@ -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 = {
Expand Down
128 changes: 56 additions & 72 deletions src/server/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ namespace ts.server {

private fileInfos = createFileMap<T>();

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 {
Expand Down Expand Up @@ -146,7 +146,7 @@ namespace ts.server {

class NonModuleBuilder extends AbstractBuilder<BuilderFileInfo> {

constructor(public project: Project) {
constructor(public readonly project: Project) {
super(project, BuilderFileInfo);
}

Expand All @@ -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];
}
}

Expand All @@ -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;
Expand All @@ -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);
}
}

Expand All @@ -211,7 +201,7 @@ namespace ts.server {
return;
}

if (array.length === 1 && array[0] === fileInfo) {
if (array[0] === fileInfo) {
array.splice(0, 1);
return;
}
Expand All @@ -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<ModuleBuilderFileInfo> {

constructor(public project: Project) {
constructor(public readonly project: Project) {
super(project, ModuleBuilderFileInfo);
}

Expand All @@ -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 [];
Expand All @@ -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);
}
});
Expand Down Expand Up @@ -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<boolean> = {};
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<boolean>();
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);
}
}
4 changes: 2 additions & 2 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<boolean> = {};
const referencedFiles = createMap<boolean>();
if (sourceFile.imports) {
const checker: TypeChecker = this.program.getTypeChecker();
for (const importName of sourceFile.imports) {
Expand Down Expand Up @@ -455,7 +455,7 @@ namespace ts.server {
}
}

return map(getKeys(referencedFiles), key => <Path>key);
return map(Object.keys(referencedFiles), key => <Path>key);
}

// remove a root file from project
Expand Down

0 comments on commit 6802f9a

Please sign in to comment.