store project errors on project so they can be reported later

This commit is contained in:
Vladimir Matveev 2016-08-26 14:37:49 -07:00
parent 3953d6ba96
commit 8075a0dd72
9 changed files with 303 additions and 40 deletions

View File

@ -1,5 +1,6 @@
/// <reference path="types.ts"/>
/// <reference path="performance.ts" />
/// <reference path="diagnosticInformationMap.generated.ts" />
/* @internal */

View File

@ -36,7 +36,7 @@ namespace ts {
}
safeFileList = <Path>"";
postInstallActions: (( map: (t: string[]) => string[]) => void)[] = [];
postInstallActions: ((map: (t: string[]) => string[]) => void)[] = [];
runPostInstallActions(map: (t: string[]) => string[]) {
for (const f of this.postInstallActions) {
@ -281,7 +281,7 @@ namespace ts {
private timeoutCallbacks = new Callbacks();
private immediateCallbacks = new Callbacks();
readonly watchedDirectories = createMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
readonly watchedDirectories = createMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
readonly watchedFiles = createMap<FileWatcherCallback[]>();
private filesOrFolders: FileOrFolder[];
@ -2011,7 +2011,7 @@ namespace ts {
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const p = projectService.configuredProjects[0];
checkProjectActualFiles(p, [ file1.path ]);
checkProjectActualFiles(p, [file1.path]);
assert(host.fileExists(combinePaths(installer.cachePath, "tsd.json")));
@ -2021,10 +2021,10 @@ namespace ts {
return ["jquery/jquery.d.ts"];
});
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(p, [ file1.path, jquery.path ]);
checkProjectActualFiles(p, [file1.path, jquery.path]);
});
it ("inferred project (tsd installed)", () => {
it("inferred project (tsd installed)", () => {
const file1 = {
path: "/a/b/app.js",
content: ""
@ -2051,7 +2051,7 @@ namespace ts {
checkNumberOfProjects(projectService, { inferredProjects: 1 });
const p = projectService.inferredProjects[0];
checkProjectActualFiles(p, [ file1.path ]);
checkProjectActualFiles(p, [file1.path]);
assert(host.fileExists(combinePaths(installer.cachePath, "tsd.json")));
@ -2061,10 +2061,10 @@ namespace ts {
return ["jquery/jquery.d.ts"];
});
checkNumberOfProjects(projectService, { inferredProjects: 1 });
checkProjectActualFiles(p, [ file1.path, jquery.path ]);
checkProjectActualFiles(p, [file1.path, jquery.path]);
});
it ("external project - no typing options, no .d.ts/js files", () => {
it("external project - no typing options, no .d.ts/js files", () => {
const file1 = {
path: "/a/b/app.ts",
content: ""
@ -2091,7 +2091,7 @@ namespace ts {
projectService.checkNumberOfProjects({ externalProjects: 1 });
});
it ("external project - no autoDiscovery in typing options, no .d.ts/js files", () => {
it("external project - no autoDiscovery in typing options, no .d.ts/js files", () => {
const file1 = {
path: "/a/b/app.ts",
content: ""
@ -2119,7 +2119,7 @@ namespace ts {
projectService.checkNumberOfProjects({ externalProjects: 1 });
});
it ("external project - autoDiscovery = true, no .d.ts/js files", () => {
it("external project - autoDiscovery = true, no .d.ts/js files", () => {
const file1 = {
path: "/a/b/app.ts",
content: ""
@ -2156,4 +2156,209 @@ namespace ts {
assert.isTrue(runTsdIsCalled, "expected 'runTsdIsCalled' to be true");
});
});
describe("Project errors", () => {
function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: string[]) {
assert.isTrue(projectFiles !== undefined, "missing project files");
const errors = projectFiles.projectErrors;
assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`);
if (expectedErrors.length) {
for (let i = 0; i < errors.length; i++) {
const actualMessage = flattenDiagnosticMessageText(errors[i].messageText, "\n");
const expectedMessage = expectedErrors[i];
assert.equal(actualMessage, expectedMessage, "error message does not match");
}
}
}
it("external project - diagnostics for missing files", () => {
const file1 = {
path: "/a/b/app.ts",
content: ""
};
const file2 = {
path: "/a/b/lib.ts",
content: ""
};
// only file1 exists - expect error
const host = createServerHost([file1]);
const projectService = createProjectService(host);
const projectFileName = "/a/b/test.csproj";
{
projectService.openExternalProject({
projectFileName,
options: {},
rootFiles: toExternalFiles([file1.path, file2.path])
});
projectService.checkNumberOfProjects({ externalProjects: 1 });
const knownProjects = projectService.synchronizeProjectList([]);
checkProjectErrors(knownProjects[0], ["File '/a/b/lib.ts' not found."]);
}
// only file2 exists - expect error
host.reloadFS([file2]);
{
projectService.openExternalProject({
projectFileName,
options: {},
rootFiles: toExternalFiles([file1.path, file2.path])
});
projectService.checkNumberOfProjects({ externalProjects: 1 });
const knownProjects = projectService.synchronizeProjectList([]);
checkProjectErrors(knownProjects[0], ["File '/a/b/app.ts' not found."]);
}
// both files exist - expect no errors
host.reloadFS([file1, file2]);
{
projectService.openExternalProject({
projectFileName,
options: {},
rootFiles: toExternalFiles([file1.path, file2.path])
});
projectService.checkNumberOfProjects({ externalProjects: 1 });
const knownProjects = projectService.synchronizeProjectList([]);
checkProjectErrors(knownProjects[0], []);
}
});
it("configured projects - diagnostics for missing files", () => {
const file1 = {
path: "/a/b/app.ts",
content: ""
};
const file2 = {
path: "/a/b/lib.ts",
content: ""
};
const config = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({ files: [file1, file2].map(f => getBaseFileName(f.path)) })
};
const host = createServerHost([file1, config]);
const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectErrors(projectService.synchronizeProjectList([])[0], ["File '/a/b/lib.ts' not found."]);
host.reloadFS([file1, file2, config]);
projectService.openClientFile(file1.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectErrors(projectService.synchronizeProjectList([])[0], []);
});
it("configured projects - diagnostics for corrupted config 1", () => {
const file1 = {
path: "/a/b/app.ts",
content: ""
};
const file2 = {
path: "/a/b/lib.ts",
content: ""
};
const correctConfig = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({ files: [file1, file2].map(f => getBaseFileName(f.path)) })
};
const corruptedConfig = {
path: correctConfig.path,
content: correctConfig.content.substr(1)
};
const host = createServerHost([file1, file2, corruptedConfig]);
const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
{
projectService.checkNumberOfProjects({ inferredProjects: 1, configuredProjects: 1 });
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
assert.isTrue(configuredProject !== undefined, "should find configured project");
checkProjectErrors(configuredProject, [`Failed to parse file \'/a/b/tsconfig.json\': Unexpected token : in JSON at position 7.`]);
}
// fix config and trigger watcher
host.reloadFS([file1, file2, correctConfig]);
host.triggerFileWatcherCallback(correctConfig.path, /*false*/);
{
projectService.checkNumberOfProjects({ configuredProjects: 1 });
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
assert.isTrue(configuredProject !== undefined, "should find configured project");
checkProjectErrors(configuredProject, []);
}
});
it("configured projects - diagnostics for corrupted config 2", () => {
const file1 = {
path: "/a/b/app.ts",
content: ""
};
const file2 = {
path: "/a/b/lib.ts",
content: ""
};
const correctConfig = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({ files: [file1, file2].map(f => getBaseFileName(f.path)) })
};
const corruptedConfig = {
path: correctConfig.path,
content: correctConfig.content.substr(1)
};
const host = createServerHost([file1, file2, correctConfig]);
const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
{
projectService.checkNumberOfProjects({ configuredProjects: 1 });
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
assert.isTrue(configuredProject !== undefined, "should find configured project");
checkProjectErrors(configuredProject, []);
}
// fix config and trigger watcher
host.reloadFS([file1, file2, corruptedConfig]);
host.triggerFileWatcherCallback(corruptedConfig.path, /*false*/);
{
projectService.checkNumberOfProjects({ inferredProjects: 1, configuredProjects: 1 });
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
assert.isTrue(configuredProject !== undefined, "should find configured project");
checkProjectErrors(configuredProject, [`Failed to parse file \'/a/b/tsconfig.json\': Unexpected token : in JSON at position 7.`]);
}
});
});
describe("Proper errors", () => {
it("document is not contained in project", () => {
const file1 = {
path: "/a/b/app.ts",
content: ""
};
const corruptedConfig = {
path: "/a/b/tsconfig.json",
content: "{"
};
const host = createServerHost([file1, corruptedConfig]);
const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
projectService.checkNumberOfProjects({ inferredProjects: 1, configuredProjects: 1 });
const project = projectService.findProject(corruptedConfig.path);
let expectedMessage: string;
try {
server.Errors.ThrowProjectDoesNotContainDocument(file1.path, project);
assert(false, "should not get there");
}
catch (e) {
expectedMessage = (<Error>e).message;
}
try {
project.getScriptInfo(file1.path);
}
catch (e) {
assert.equal((<Error>e).message, expectedMessage, "Unexpected error");
}
});
});
}

View File

@ -30,7 +30,7 @@ namespace ts.server {
interface ConfigFileConversionResult {
success: boolean;
errors?: Diagnostic[];
configFileErrors?: Diagnostic[];
projectOptions?: ProjectOptions;
}
@ -73,6 +73,10 @@ namespace ts.server {
}
}
function createFileNotFoundDiagnostic(fileName: string) {
return createCompilerDiagnostic(Diagnostics.File_0_not_found, fileName);
}
/**
* TODO: enforce invariants:
* - script info can be never migrate to state - root file in inferred project, this is only a starting point
@ -655,7 +659,7 @@ namespace ts.server {
const configObj = parseConfigFileTextToJson(configFilename, this.host.readFile(configFilename));
if (configObj.error) {
return { success: false, errors: [configObj.error] };
return { success: false, configFileErrors: [configObj.error] };
}
const parsedCommandLine = parseJsonConfigFileContent(
@ -668,12 +672,12 @@ namespace ts.server {
Debug.assert(!!parsedCommandLine.fileNames);
if (parsedCommandLine.errors && (parsedCommandLine.errors.length > 0)) {
return { success: false, errors: parsedCommandLine.errors };
return { success: false, configFileErrors: parsedCommandLine.errors };
}
if (parsedCommandLine.fileNames.length === 0) {
const error = createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename);
return { success: false, errors: [error] };
return { success: false, configFileErrors: [error] };
}
const projectOptions: ProjectOptions = {
@ -714,10 +718,9 @@ namespace ts.server {
/*languageServiceEnabled*/ !this.exceededTotalSizeLimitForNonTsFiles(options, files, externalFilePropertyReader),
options.compileOnSave === undefined ? true : options.compileOnSave);
const errors = this.addFilesToProjectAndUpdateGraph(project, files, externalFilePropertyReader, /*clientFileName*/ undefined, typingOptions);
this.addFilesToProjectAndUpdateGraph(project, files, externalFilePropertyReader, /*clientFileName*/ undefined, typingOptions);
this.externalProjects.push(project);
return { project, errors };
return project;
}
private createAndAddConfiguredProject(configFileName: NormalizedPath, projectOptions: ProjectOptions, clientFileName?: string) {
@ -732,7 +735,7 @@ namespace ts.server {
/*languageServiceEnabled*/ !sizeLimitExceeded,
projectOptions.compileOnSave === undefined ? false : projectOptions.compileOnSave);
const errors = this.addFilesToProjectAndUpdateGraph(project, projectOptions.files, fileNamePropertyReader, clientFileName, projectOptions.typingOptions);
this.addFilesToProjectAndUpdateGraph(project, projectOptions.files, fileNamePropertyReader, clientFileName, projectOptions.typingOptions);
project.watchConfigFile(project => this.onConfigChangedForConfiguredProject(project));
if (!sizeLimitExceeded) {
@ -741,7 +744,7 @@ namespace ts.server {
project.watchWildcards((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
this.configuredProjects.push(project);
return { project, errors };
return project;
}
private watchConfigDirectoryForProject(project: ConfiguredProject, options: ProjectOptions): void {
@ -750,7 +753,7 @@ namespace ts.server {
}
}
private addFilesToProjectAndUpdateGraph<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, clientFileName: string, typingOptions: TypingOptions): Diagnostic[] {
private addFilesToProjectAndUpdateGraph<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, clientFileName: string, typingOptions: TypingOptions): void {
let errors: Diagnostic[];
for (const f of files) {
const rootFilename = propertyReader.getFileName(f);
@ -761,32 +764,37 @@ namespace ts.server {
project.addRoot(info);
}
else {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename));
(errors || (errors = [])).push(createFileNotFoundDiagnostic(rootFilename));
}
}
project.setProjectErrors(errors);
project.setTypingOptions(typingOptions);
project.updateGraph();
return errors;
}
private openConfigFile(configFileName: NormalizedPath, clientFileName?: string): OpenConfigFileResult {
const conversionResult = this.convertConfigFileContentToProjectOptions(configFileName);
if (!conversionResult.success) {
return { success: false, errors: conversionResult.errors };
// open project with no files and set errors on the project
const project = this.createAndAddConfiguredProject(configFileName, { files: [], compilerOptions: {} }, clientFileName);
project.setProjectErrors(conversionResult.configFileErrors);
return { success: false, errors: conversionResult.configFileErrors };
}
const { project, errors } = this.createAndAddConfiguredProject(configFileName, conversionResult.projectOptions, clientFileName);
return { success: true, project, errors };
const project = this.createAndAddConfiguredProject(configFileName, conversionResult.projectOptions, clientFileName);
return { success: true, project, errors: project.getProjectErrors() };
}
private updateNonInferredProject<T>(project: ExternalProject | ConfiguredProject, newUncheckedFiles: T[], propertyReader: FilePropertyReader<T>, newOptions: CompilerOptions, newTypingOptions: TypingOptions, compileOnSave: boolean) {
private updateNonInferredProject<T>(project: ExternalProject | ConfiguredProject, newUncheckedFiles: T[], propertyReader: FilePropertyReader<T>, newOptions: CompilerOptions, newTypingOptions: TypingOptions, compileOnSave: boolean, configFileErrors: Diagnostic[]) {
const oldRootScriptInfos = project.getRootScriptInfos();
const newRootScriptInfos: ScriptInfo[] = [];
const newRootScriptInfoMap: NormalizedPathMap<ScriptInfo> = createNormalizedPathMap<ScriptInfo>();
let projectErrors: Diagnostic[];
let rootFilesChanged = false;
for (const f of newUncheckedFiles) {
const newRootFile = propertyReader.getFileName(f);
if (!this.host.fileExists(newRootFile)) {
(projectErrors || (projectErrors = [])).push(createFileNotFoundDiagnostic(newRootFile));
continue;
}
const normalizedPath = toNormalizedPath(newRootFile);
@ -840,6 +848,8 @@ namespace ts.server {
project.setCompilerOptions(newOptions);
(<ExternalProject | ConfiguredProject>project).setTypingOptions(newTypingOptions);
project.compileOnSaveEnabled = !!compileOnSave;
project.setProjectErrors(concatenate(configFileErrors, projectErrors));
project.updateGraph();
}
@ -850,9 +860,11 @@ namespace ts.server {
return;
}
const { success, projectOptions, errors } = this.convertConfigFileContentToProjectOptions(project.configFileName);
const { success, projectOptions, configFileErrors } = this.convertConfigFileContentToProjectOptions(project.configFileName);
if (!success) {
return errors;
// reset project settings to default
this.updateNonInferredProject(project, [], fileNamePropertyReader, {}, {}, /*compileOnSave*/false, configFileErrors);
return configFileErrors;
}
if (this.exceededTotalSizeLimitForNonTsFiles(projectOptions.compilerOptions, projectOptions.files, fileNamePropertyReader)) {
@ -869,7 +881,7 @@ namespace ts.server {
project.enableLanguageService();
}
this.watchConfigDirectoryForProject(project, projectOptions);
this.updateNonInferredProject(project, projectOptions.files, fileNamePropertyReader, projectOptions.compilerOptions, projectOptions.typingOptions, projectOptions.compileOnSave);
this.updateNonInferredProject(project, projectOptions.files, fileNamePropertyReader, projectOptions.compilerOptions, projectOptions.typingOptions, projectOptions.compileOnSave, configFileErrors);
}
}
@ -1052,15 +1064,15 @@ namespace ts.server {
this.printProjects();
}
private collectChanges(lastKnownProjectVersions: protocol.ProjectVersionInfo[], currentProjects: Project[], result: protocol.ProjectFiles[]): void {
private collectChanges(lastKnownProjectVersions: protocol.ProjectVersionInfo[], currentProjects: Project[], result: ProjectFilesWithTSDiagnostics[]): void {
for (const proj of currentProjects) {
const knownProject = forEach(lastKnownProjectVersions, p => p.projectName === proj.getProjectName() && p);
result.push(proj.getChangesSinceVersion(knownProject && knownProject.version));
}
}
synchronizeProjectList(knownProjects: protocol.ProjectVersionInfo[]): protocol.ProjectFiles[] {
const files: protocol.ProjectFiles[] = [];
synchronizeProjectList(knownProjects: protocol.ProjectVersionInfo[]): ProjectFilesWithTSDiagnostics[] {
const files: ProjectFilesWithTSDiagnostics[] = [];
this.collectChanges(knownProjects, this.externalProjects, files);
this.collectChanges(knownProjects, this.configuredProjects, files);
this.collectChanges(knownProjects, this.inferredProjects, files);
@ -1139,7 +1151,7 @@ namespace ts.server {
openExternalProject(proj: protocol.ExternalProject): void {
const externalProject = this.findExternalProjectByProjectName(proj.projectFileName);
if (externalProject) {
this.updateNonInferredProject(externalProject, proj.rootFiles, externalFilePropertyReader, proj.options, proj.typingOptions, proj.options.compileOnSave);
this.updateNonInferredProject(externalProject, proj.rootFiles, externalFilePropertyReader, proj.options, proj.typingOptions, proj.options.compileOnSave, /*configFileErrors*/ undefined);
return;
}

View File

@ -76,6 +76,10 @@ namespace ts.server {
return this.compilationSettings;
}
useCaseSensitiveFileNames() {
return this.host.useCaseSensitiveFileNames;
}
getCancellationToken() {
return this.cancellationToken;
}

View File

@ -26,6 +26,10 @@ namespace ts.server {
return project.getRootScriptInfos().every(f => fileExtensionIsAny(f.fileName, jsOrDts));
}
export interface ProjectFilesWithTSDiagnostics extends protocol.ProjectFiles {
projectErrors: Diagnostic[];
}
export abstract class Project {
private rootFiles: ScriptInfo[] = [];
private rootFilesMap: FileMap<ScriptInfo> = createFileMap<ScriptInfo>();
@ -57,6 +61,8 @@ namespace ts.server {
private typingFiles: TypingsArray;
protected projectErrors: Diagnostic[];
constructor(
readonly projectKind: ProjectKind,
readonly projectService: ProjectService,
@ -87,6 +93,10 @@ namespace ts.server {
this.markAsDirty();
}
getProjectErrors() {
return this.projectErrors;
}
getLanguageService(ensureSynchronized = true): LanguageService {
if (ensureSynchronized) {
this.updateGraph();
@ -329,7 +339,9 @@ namespace ts.server {
getScriptInfoForNormalizedPath(fileName: NormalizedPath) {
const scriptInfo = this.projectService.getOrCreateScriptInfoForNormalizedPath(fileName, /*openedByClient*/ false);
Debug.assert(!scriptInfo || scriptInfo.isAttached(this));
if (scriptInfo && !scriptInfo.isAttached(this)) {
return Errors.ThrowProjectDoesNotContainDocument(fileName, this);
}
return scriptInfo;
}
@ -371,7 +383,7 @@ namespace ts.server {
return false;
}
getChangesSinceVersion(lastKnownVersion?: number): protocol.ProjectFiles {
getChangesSinceVersion(lastKnownVersion?: number): ProjectFilesWithTSDiagnostics {
this.updateGraph();
const info = {
@ -384,7 +396,7 @@ namespace ts.server {
if (this.lastReportedFileNames && lastKnownVersion === this.lastReportedVersion) {
// if current structure version is the same - return info witout any changes
if (this.projectStructureVersion == this.lastReportedVersion) {
return { info };
return { info, projectErrors: this.projectErrors };
}
// compute and return the difference
const lastReportedFileNames = this.lastReportedFileNames;
@ -406,14 +418,14 @@ namespace ts.server {
this.lastReportedFileNames = currentFiles;
this.lastReportedVersion = this.projectStructureVersion;
return { info, changes: { added, removed } };
return { info, changes: { added, removed }, projectErrors: this.projectErrors };
}
else {
// unknown version - return everything
const projectFileNames = this.getFileNames();
this.lastReportedFileNames = arrayToMap(projectFileNames, x => x);
this.lastReportedVersion = this.projectStructureVersion;
return { info, files: projectFileNames };
return { info, files: projectFileNames, projectErrors: this.projectErrors };
}
}
@ -544,6 +556,10 @@ namespace ts.server {
super(ProjectKind.Configured, projectService, documentRegistry, hasExplicitListOfFiles, languageServiceEnabled, compilerOptions, compileOnSaveEnabled);
}
setProjectErrors(projectErrors: Diagnostic[]) {
this.projectErrors = projectErrors;
}
setTypingOptions(newTypingOptions: TypingOptions): void {
this.typingOptions = newTypingOptions;
}
@ -636,6 +652,10 @@ namespace ts.server {
return this.typingOptions;
}
setProjectErrors(projectErrors: Diagnostic[]) {
this.projectErrors = projectErrors;
}
setTypingOptions(newTypingOptions: TypingOptions): void {
if (!newTypingOptions) {
// set default typings options

View File

@ -535,6 +535,10 @@ declare namespace ts.server.protocol {
changes?: ProjectChanges;
}
export interface ProjectFilesWithDiagnostics extends ProjectFiles {
projectErrors: DiagnosticWithLinePosition[];
}
export interface ChangedOpenFile {
fileName: string;
changes: ts.TextChange[];

View File

@ -1261,7 +1261,21 @@ namespace ts.server {
},
[CommandNames.SynchronizeProjectList]: (request: protocol.SynchronizeProjectListRequest) => {
const result = this.projectService.synchronizeProjectList(request.arguments.knownProjects);
return this.requiredResponse(result);
if (!result.some(p => p.projectErrors && p.projectErrors.length !== 0)) {
return this.requiredResponse(result);
}
const converted = map(result, p => {
if (!p.projectErrors || p.projectErrors.length === 0) {
return p;
}
return {
info: p.info,
changes: p.changes,
files: p.files,
projectErrors: this.convertToDiagnosticsWithLinePosition(p.projectErrors, /*scriptInfo*/ undefined)
};
});
return this.requiredResponse(converted);
},
[CommandNames.ApplyChangedToOpenFiles]: (request: protocol.ApplyChangedToOpenFilesRequest) => {
this.projectService.applyChangesInOpenFiles(request.arguments.openFiles, request.arguments.changedFiles, request.arguments.closedFiles);

View File

@ -64,6 +64,9 @@ namespace ts.server {
export function ThrowProjectLanguageServiceDisabled(): never {
throw new Error("The project's language service is disabled.");
}
export function ThrowProjectDoesNotContainDocument(fileName: string, project: Project): never {
throw new Error(`Project '${project.getProjectName()}' does not contain document '${fileName}'`);
}
}
export function getDefaultFormatCodeSettings(host: ServerHost): FormatCodeSettings {

View File

@ -3053,7 +3053,7 @@ namespace ts {
let program: Program;
let lastProjectVersion: string;
const useCaseSensitivefileNames = false;
const useCaseSensitivefileNames = host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames();
const cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
const currentDirectory = host.getCurrentDirectory();