add support for single inferred project

This commit is contained in:
Vladimir Matveev 2016-06-27 14:25:43 -07:00
parent 15f825b6b3
commit 96a867a52e
9 changed files with 183 additions and 89 deletions

View File

@ -681,6 +681,7 @@ namespace Harness.LanguageService {
const serverHost = new SessionServerHost(clientHost);
const server = new ts.server.Session(serverHost,
{ isCancellationRequested: () => false },
/*useOneInferredProject*/ false,
Buffer ? Buffer.byteLength : (string: string, encoding?: string) => string.length,
process.hrtime, serverHost);

View File

@ -137,26 +137,25 @@ namespace ts.server {
private readonly directoryWatchers: DirectoryWatchers;
private hostConfiguration: HostConfiguration;
private readonly hostConfiguration: HostConfiguration;
private timerForDetectingProjectFileListChanges: Map<any> = {};
constructor(public readonly host: ServerHost,
public readonly logger: Logger,
public readonly cancellationToken: HostCancellationToken,
private readonly useOneInferredProject: boolean,
private readonly eventHandler?: ProjectServiceEventHandler) {
this.directoryWatchers = new DirectoryWatchers(this);
// ts.disableIncrementalParsing = true;
this.setDefaultHostConfiguration();
this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames, host.getCurrentDirectory());
}
private setDefaultHostConfiguration() {
this.hostConfiguration = {
formatCodeOptions: getDefaultFormatCodeSettings(this.host),
hostInfo: "Unknown host"
};
this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames, host.getCurrentDirectory());
}
stopWatchingDirectory(directory: string) {
@ -378,31 +377,36 @@ namespace ts.server {
}
if (info.containingProjects.length === 0) {
// create new inferred project p with the newly opened file as root
const inferredProject = this.createAndAddInferredProject(info);
const openFileRoots: ScriptInfo[] = [];
// for each inferred project root r
for (const rootFile of this.openFileRoots) {
// if r referenced by the new project
if (inferredProject.containsScriptInfo(rootFile)) {
// remove inferred project that was initially created for rootFile
const defaultProject = rootFile.getDefaultProject();
if (defaultProject === inferredProject) {
continue;
}
Debug.assert(defaultProject.projectKind === ProjectKind.Inferred);
// or add root to existing inferred project if 'useOneInferredProject' is true
const inferredProject = this.addFileToInferredProject(info);
if (!this.useOneInferredProject) {
this.removeProject(defaultProject);
// put r in referenced open file list
this.openFilesReferenced.push(rootFile);
// set default project of r to the new project
rootFile.attachToProject(inferredProject);
}
else {
// otherwise, keep r as root of inferred project
openFileRoots.push(rootFile);
// if useOneInferredProject is not set then try to fixup ownership of open files
const openFileRoots: ScriptInfo[] = [];
// for each inferred project root r
for (const rootFile of this.openFileRoots) {
// if r referenced by the new project
if (inferredProject.containsScriptInfo(rootFile)) {
// remove inferred project that was initially created for rootFile
const defaultProject = rootFile.getDefaultProject();
if (defaultProject === inferredProject) {
continue;
}
Debug.assert(defaultProject.projectKind === ProjectKind.Inferred);
this.removeProject(defaultProject);
// put r in referenced open file list
this.openFilesReferenced.push(rootFile);
// set default project of r to the new project
rootFile.attachToProject(inferredProject);
}
else {
// otherwise, keep r as root of inferred project
openFileRoots.push(rootFile);
}
}
this.openFileRoots = openFileRoots;
}
this.openFileRoots = openFileRoots;
}
this.openFileRoots.push(info);
@ -736,6 +740,8 @@ namespace ts.server {
// delete inferred project
let toRemove: Project[];
// TODO: unify logic
for (const p of info.containingProjects) {
if (p.projectKind === ProjectKind.Inferred && p.isRoot(info)) {
(toRemove || (toRemove = [])).push(p);
@ -743,7 +749,10 @@ namespace ts.server {
}
if (toRemove) {
for (const p of toRemove) {
this.removeProject(p);
p.removeFile(info);
if (!p.hasRoots()) {
this.removeProject(p);
}
}
}
}
@ -792,8 +801,12 @@ namespace ts.server {
}
}
createAndAddInferredProject(root: ScriptInfo) {
const project = new InferredProject(this, this.documentRegistry, /*languageServiceEnabled*/ true);
addFileToInferredProject(root: ScriptInfo) {
const useExistingProject = this.useOneInferredProject && this.inferredProjects.length;
const project = useExistingProject
? this.inferredProjects[0]
: new InferredProject(this, this.documentRegistry, /*languageServiceEnabled*/ true);
project.addRoot(root);
this.directoryWatchers.startWatchingContainingDirectoriesForFile(
@ -802,7 +815,10 @@ namespace ts.server {
fileName => this.onConfigFileAddedForInferredProject(fileName));
project.updateGraph();
this.inferredProjects.push(project);
if (!useExistingProject) {
this.inferredProjects.push(project);
}
return project;
}
@ -966,7 +982,10 @@ namespace ts.server {
if (inConfiguredProject || inExternalProject) {
const inferredProjects = rootFile.containingProjects.filter(p => p.projectKind === ProjectKind.Inferred);
for (const p of inferredProjects) {
this.removeProject(p);
p.removeFile(rootFile, /*detachFromProject*/ true);
if (!p.hasRoots()) {
this.removeProject(p);
}
}
if (inConfiguredProject) {
this.openFileRootsConfigured.push(rootFile);
@ -1033,6 +1052,9 @@ namespace ts.server {
for (const f of unattachedOpenFiles) {
this.addOpenFile(f);
}
for (const p of this.inferredProjects) {
p.updateGraph();
}
this.printProjects();
}

View File

@ -108,6 +108,10 @@ namespace ts.server {
return this.compilerOptions;
}
hasRoots() {
return this.rootFiles.length > 0;
}
getRootFiles() {
return this.rootFiles.map(info => info.fileName);
}

View File

@ -606,6 +606,11 @@ declare namespace ts.server.protocol {
* The format options to use during formatting and other code editing features.
*/
formatOptions?: FormatOptions;
/**
* If set to true - then all loose files will land into one inferred project
*/
useOneInferredProject?: boolean;
}
/**

View File

@ -91,8 +91,8 @@ namespace ts.server {
}
class IOSession extends Session {
constructor(host: ServerHost, cancellationToken: HostCancellationToken, logger: ts.server.Logger) {
super(host, cancellationToken, Buffer.byteLength, process.hrtime, logger);
constructor(host: ServerHost, cancellationToken: HostCancellationToken, useOneInferredProject: boolean, logger: ts.server.Logger) {
super(host, cancellationToken, useOneInferredProject, Buffer.byteLength, process.hrtime, logger);
}
exit() {
@ -304,7 +304,8 @@ namespace ts.server {
};
};
const ioSession = new IOSession(sys, cancellationToken, logger);
const useOneInferredProject = sys.args.some(arg => arg === "--useOneInferredProject");
const ioSession = new IOSession(sys, cancellationToken, useOneInferredProject, logger);
process.on("uncaughtException", function(err: Error) {
ioSession.logError(err, "unknown");
});

View File

@ -178,12 +178,13 @@ namespace ts.server {
constructor(
private host: ServerHost,
private cancellationToken: HostCancellationToken,
cancellationToken: HostCancellationToken,
useOneInferredProject: boolean,
private byteLength: (buf: string, encoding?: string) => number,
private hrtime: (start?: number[]) => number[],
private logger: Logger) {
this.projectService =
new ProjectService(host, logger, cancellationToken, (eventName, project, fileName) => {
new ProjectService(host, logger, cancellationToken, useOneInferredProject, (eventName, project, fileName) => {
this.handleEvent(eventName, project, fileName);
});
}
@ -1380,10 +1381,10 @@ namespace ts.server {
this.cleanup();
return this.requiredResponse(true);
},
[CommandNames.SemanticDiagnosticsSync]: (request: protocol.FileRequest) => {
[CommandNames.SemanticDiagnosticsSync]: (request: protocol.SemanticDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSemanticDiagnosticsSync(request.arguments));
},
[CommandNames.SyntacticDiagnosticsSync]: (request: protocol.FileRequest) => {
[CommandNames.SyntacticDiagnosticsSync]: (request: protocol.SyntacticDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSyntacticDiagnosticsSync(request.arguments));
},
[CommandNames.Geterr]: (request: protocol.Request) => {
@ -1398,9 +1399,8 @@ namespace ts.server {
this.change(request.arguments);
return this.notRequired();
},
[CommandNames.Configure]: (request: protocol.Request) => {
const configureArgs = <protocol.ConfigureRequestArguments>request.arguments;
this.projectService.setHostConfiguration(configureArgs);
[CommandNames.Configure]: (request: protocol.ConfigureRequest) => {
this.projectService.setHostConfiguration(request.arguments);
this.output(undefined, CommandNames.Configure, request.seq);
return this.notRequired();
},

View File

@ -79,9 +79,9 @@ namespace ts {
msg: (s: string, type?: string) => { }
};
const projectService = new server.ProjectService(serverHost, logger, { isCancellationRequested: () => false });
const projectService = new server.ProjectService(serverHost, logger, { isCancellationRequested: () => false }, /*useOneInferredProject*/ false);
const rootScriptInfo = projectService.getOrCreateScriptInfo(rootFile, /* openedByClient */true, /*containingProject*/ undefined);
const project = projectService.createAndAddInferredProject(rootScriptInfo);
const project = projectService.addFileToInferredProject(rootScriptInfo);
project.setCompilerOptions({ module: ts.ModuleKind.AMD } );
return {
project,

View File

@ -40,7 +40,7 @@ namespace ts.server {
let lastSent: protocol.Message;
beforeEach(() => {
session = new Session(mockHost, nullCancellationToken, Utils.byteLength, process.hrtime, mockLogger);
session = new Session(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, Utils.byteLength, process.hrtime, mockLogger);
session.send = (msg: protocol.Message) => {
lastSent = msg;
};
@ -265,7 +265,7 @@ namespace ts.server {
lastSent: protocol.Message;
customHandler = "testhandler";
constructor() {
super(mockHost, nullCancellationToken, Utils.byteLength, process.hrtime, mockLogger);
super(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, Utils.byteLength, process.hrtime, mockLogger);
this.addProtocolHandler(this.customHandler, () => {
return { response: undefined, responseRequired: true };
});
@ -323,7 +323,7 @@ namespace ts.server {
class InProcSession extends Session {
private queue: protocol.Request[] = [];
constructor(private client: InProcClient) {
super(mockHost, nullCancellationToken, Utils.byteLength, process.hrtime, mockLogger);
super(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, Utils.byteLength, process.hrtime, mockLogger);
this.addProtocolHandler("echo", (req: protocol.Request) => ({
response: req.arguments,
responseRequired: true

View File

@ -26,6 +26,22 @@ namespace ts {
return combinePaths(getDirectoryPath(libFile.path), "tsc.js");
}
interface TestServerHostCreationParameters {
fileOrFolderList: FileOrFolder[];
useCaseSensitiveFileNames?: boolean;
executingFilePath?: string;
libFile?: FileOrFolder;
currentDirectory?: string;
}
function createServerHost(params: TestServerHostCreationParameters): TestServerHost {
return new TestServerHost(
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
params.executingFilePath || getExecutingFilePathFromLibFile(params.libFile),
params.currentDirectory || "/",
params.fileOrFolderList);
}
interface FileOrFolder {
path: string;
content?: string;
@ -112,12 +128,12 @@ namespace ts {
checkMapKeys("watchedDirectories", host.watchedDirectories, expectedDirectories);
}
function checkConfiguredProjectActualFiles(project: server.Project, expectedFiles: string[]) {
checkFileNames("configuredProjects project, actualFileNames", project.getFileNames(), expectedFiles);
function checkProjectActualFiles(project: server.Project, expectedFiles: string[]) {
checkFileNames(`${server.ProjectKind[project.projectKind]} project, actual files`, project.getFileNames(), expectedFiles);
}
function checkConfiguredProjectRootFiles(project: server.Project, expectedFiles: string[]) {
checkFileNames("configuredProjects project, rootFileNames", project.getRootFiles(), expectedFiles);
function checkProjectRootFiles(project: server.Project, expectedFiles: string[]) {
checkFileNames(`${server.ProjectKind[project.projectKind]} project, rootFileNames`, project.getRootFiles(), expectedFiles);
}
type TimeOutCallback = () => any;
@ -193,7 +209,7 @@ namespace ts {
return ts.matchFiles(path, extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), (dir) => {
const result: FileSystemEntries = {
directories: [],
files : []
files: []
};
const dirEntry = that.fs.get(that.toPath(dir));
if (isFolder(dirEntry)) {
@ -325,8 +341,8 @@ namespace ts {
path: "/a/b/c/module.d.ts",
content: `export let x: number`
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [appFile, moduleFile, libFile]);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: [appFile, moduleFile, libFile], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
const { configFileName } = projectService.openClientFile(appFile.path);
assert(!configFileName, `should not find config, got: '${configFileName}`);
@ -363,8 +379,9 @@ namespace ts {
content: "let z = 1"
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [ configFile, libFile, file1, file2, file3 ]);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: [configFile, libFile, file1, file2, file3], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
const { configFileName, configFileErrors } = projectService.openClientFile(file1.path);
assert(configFileName, "should find config file");
@ -373,8 +390,8 @@ namespace ts {
checkNumberOfConfiguredProjects(projectService, 1);
const project = projectService.configuredProjects[0];
checkConfiguredProjectActualFiles(project, [file1.path, libFile.path, file2.path]);
checkConfiguredProjectRootFiles(project, [file1.path, file2.path]);
checkProjectActualFiles(project, [file1.path, libFile.path, file2.path]);
checkProjectRootFiles(project, [file1.path, file2.path]);
// watching all files except one that was open
checkWatchedFiles(host, [configFile.path, file2.path, libFile.path]);
checkWatchedDirectories(host, [getDirectoryPath(configFile.path)]);
@ -387,10 +404,11 @@ namespace ts {
"files": ["commonFile1.ts"]
}`
};
const filesWithoutConfig = [ libFile, commonFile1, commonFile2 ];
const filesWithConfig = [ libFile, commonFile1, commonFile2, configFile ];
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", filesWithoutConfig);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const filesWithoutConfig = [libFile, commonFile1, commonFile2];
const host = createServerHost({ fileOrFolderList: filesWithoutConfig, libFile });
const filesWithConfig = [libFile, commonFile1, commonFile2, configFile];
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(commonFile1.path);
projectService.openClientFile(commonFile2.path);
@ -420,21 +438,21 @@ namespace ts {
path: "/a/b/tsconfig.json",
content: `{}`
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, libFile, configFile]);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: [commonFile1, libFile, configFile], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(commonFile1.path);
checkWatchedDirectories(host, ["/a/b"]);
checkNumberOfConfiguredProjects(projectService, 1);
const project = projectService.configuredProjects[0];
checkConfiguredProjectRootFiles(project, [commonFile1.path]);
checkProjectRootFiles(project, [commonFile1.path]);
// add a new ts file
host.reloadFS([commonFile1, commonFile2, libFile, configFile]);
host.triggerDirectoryWatcherCallback("/a/b", commonFile2.path);
host.runQueuedTimeoutCallbacks();
// project service waits for 250ms to update the project structure, therefore the assertion needs to wait longer.
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
});
it("should ignore non-existing files specified in the config file", () => {
@ -448,14 +466,14 @@ namespace ts {
]
}`
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, commonFile2, configFile]);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: [commonFile1, commonFile2, configFile], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(commonFile1.path);
projectService.openClientFile(commonFile2.path);
checkNumberOfConfiguredProjects(projectService, 1);
const project = projectService.configuredProjects[0];
checkConfiguredProjectRootFiles(project, [commonFile1.path]);
checkProjectRootFiles(project, [commonFile1.path]);
checkNumberOfInferredProjects(projectService, 1);
});
@ -464,25 +482,25 @@ namespace ts {
path: "/a/b/tsconfig.json",
content: `{}`
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, commonFile2, configFile]);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: [commonFile1, commonFile2, configFile], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(commonFile1.path);
checkNumberOfConfiguredProjects(projectService, 1);
const project = projectService.configuredProjects[0];
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
// delete commonFile2
host.reloadFS([commonFile1, configFile]);
host.triggerDirectoryWatcherCallback("/a/b", commonFile2.path);
host.runQueuedTimeoutCallbacks();
checkConfiguredProjectRootFiles(project, [commonFile1.path]);
checkProjectRootFiles(project, [commonFile1.path]);
// re-add commonFile2
host.reloadFS([commonFile1, commonFile2, configFile]);
host.triggerDirectoryWatcherCallback("/a/b", commonFile2.path);
host.runQueuedTimeoutCallbacks();
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
});
it("should create new inferred projects for files excluded from a configured project", () => {
@ -494,12 +512,12 @@ namespace ts {
}`
};
const files = [commonFile1, commonFile2, configFile];
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", files);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: files, libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(commonFile1.path);
const project = projectService.configuredProjects[0];
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
configFile.content = `{
"compilerOptions": {},
"files": ["${commonFile1.path}"]
@ -508,7 +526,7 @@ namespace ts {
host.triggerFileWatcherCallback(configFile.path);
checkNumberOfConfiguredProjects(projectService, 1);
checkConfiguredProjectRootFiles(project, [commonFile1.path]);
checkProjectRootFiles(project, [commonFile1.path]);
projectService.openClientFile(commonFile2.path);
checkNumberOfInferredProjects(projectService, 1);
@ -527,13 +545,13 @@ namespace ts {
content: `let t = 1;`
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, commonFile2, excludedFile1, configFile]);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: [commonFile1, commonFile2, excludedFile1, configFile], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(commonFile1.path);
checkNumberOfConfiguredProjects(projectService, 1);
const project = projectService.configuredProjects[0];
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
projectService.openClientFile(excludedFile1.path);
checkNumberOfInferredProjects(projectService, 1);
});
@ -561,15 +579,15 @@ namespace ts {
}`
};
const files = [file1, nodeModuleFile, classicModuleFile, configFile];
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", files);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: files, libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(file1.path);
projectService.openClientFile(nodeModuleFile.path);
projectService.openClientFile(classicModuleFile.path);
checkNumberOfConfiguredProjects(projectService, 1);
const project = projectService.configuredProjects[0];
checkConfiguredProjectActualFiles(project, [file1.path, nodeModuleFile.path]);
checkProjectActualFiles(project, [file1.path, nodeModuleFile.path]);
checkNumberOfInferredProjects(projectService, 1);
configFile.content = `{
@ -580,7 +598,7 @@ namespace ts {
}`;
host.reloadFS(files);
host.triggerFileWatcherCallback(configFile.path);
checkConfiguredProjectActualFiles(project, [file1.path, classicModuleFile.path]);
checkProjectActualFiles(project, [file1.path, classicModuleFile.path]);
checkNumberOfInferredProjects(projectService, 1);
});
@ -602,8 +620,8 @@ namespace ts {
"files": [ "main.ts" ]
}`
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [file1, file2, configFile]);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: [file1, file2, configFile], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(file1.path);
projectService.closeClientFile(file1.path);
projectService.openClientFile(file2.path);
@ -629,13 +647,56 @@ namespace ts {
"files": [ "main.ts" ]
}`
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [file1, file2, configFile]);
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken);
const host = createServerHost({ fileOrFolderList: [file1, file2, configFile], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false);
projectService.openClientFile(file1.path);
projectService.closeClientFile(file1.path);
projectService.openClientFile(file2.path);
checkNumberOfConfiguredProjects(projectService, 1);
checkNumberOfInferredProjects(projectService, 0);
});
it("should use only one inferred project if 'useOneInferredProject' is set", () => {
const file1 = {
path: "/a/b/main.ts",
content: "let x =1;"
};
const configFile: FileOrFolder = {
path: "/a/b/tsconfig.json",
content: `{
"compilerOptions": {
"target": "es6"
},
"files": [ "main.ts" ]
}`
};
const file2 = {
path: "/a/c/main.ts",
content: "let x =1;"
};
const file3 = {
path: "/a/d/main.ts",
content: "let x =1;"
};
const host = createServerHost({ fileOrFolderList: [file1, file2, file3, libFile], libFile });
const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ true);
projectService.openClientFile(file1.path);
projectService.openClientFile(file2.path);
projectService.openClientFile(file3.path);
checkNumberOfConfiguredProjects(projectService, 0);
checkNumberOfInferredProjects(projectService, 1);
checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path, libFile.path]);
host.reloadFS([file1, configFile, file2, file3, libFile]);
host.triggerDirectoryWatcherCallback(getDirectoryPath(configFile.path), configFile.path);
checkNumberOfConfiguredProjects(projectService, 1);
checkNumberOfInferredProjects(projectService, 1);
checkProjectActualFiles(projectService.inferredProjects[0], [file2.path, file3.path, libFile.path]);
});
});
}