Skip to content

Commit e8862a7

Browse files
committed
Merge pull request #8504 from zhengbli/i8334
Tolerate non-existing files specified for tsserver
2 parents 0275fe2 + 2252b17 commit e8862a7

File tree

3 files changed

+82
-51
lines changed

3 files changed

+82
-51
lines changed

src/server/client.ts

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// <reference path="session.ts" />
2-
2+
33
namespace ts.server {
44

55
export interface SessionClientHost extends LanguageServiceHost {
@@ -25,23 +25,23 @@ namespace ts.server {
2525
private lineMaps: ts.Map<number[]> = {};
2626
private messages: string[] = [];
2727
private lastRenameEntry: RenameEntry;
28-
28+
2929
constructor(private host: SessionClientHost) {
3030
}
3131

32-
public onMessage(message: string): void {
32+
public onMessage(message: string): void {
3333
this.messages.push(message);
3434
}
3535

36-
private writeMessage(message: string): void {
36+
private writeMessage(message: string): void {
3737
this.host.writeMessage(message);
3838
}
3939

40-
private getLineMap(fileName: string): number[] {
40+
private getLineMap(fileName: string): number[] {
4141
var lineMap = ts.lookUp(this.lineMaps, fileName);
4242
if (!lineMap) {
4343
var scriptSnapshot = this.host.getScriptSnapshot(fileName);
44-
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));
44+
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));
4545
}
4646
return lineMap;
4747
}
@@ -82,34 +82,29 @@ namespace ts.server {
8282
}
8383

8484
private processResponse<T extends protocol.Response>(request: protocol.Request): T {
85-
var lastMessage = this.messages.shift();
86-
Debug.assert(!!lastMessage, "Did not receive any responses.");
87-
88-
// Read the content length
89-
var contentLengthPrefix = "Content-Length: ";
90-
var lines = lastMessage.split("\r\n");
91-
Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response.");
92-
93-
var contentLengthText = lines[0];
94-
Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header.");
95-
var contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length));
96-
97-
// Read the body
98-
var responseBody = lines[2];
99-
100-
// Verify content length
101-
Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length.");
102-
103-
try {
104-
var response: T = JSON.parse(responseBody);
105-
}
106-
catch (e) {
107-
throw new Error("Malformed response: Failed to parse server response: " + lastMessage + ". \r\n Error details: " + e.message);
85+
let foundResponseMessage = false;
86+
let lastMessage: string;
87+
let response: T;
88+
while (!foundResponseMessage) {
89+
lastMessage = this.messages.shift();
90+
Debug.assert(!!lastMessage, "Did not receive any responses.");
91+
const responseBody = processMessage(lastMessage);
92+
try {
93+
response = JSON.parse(responseBody);
94+
// the server may emit events before emitting the response. We
95+
// want to ignore these events for testing purpose.
96+
if (response.type === "response") {
97+
foundResponseMessage = true;
98+
}
99+
}
100+
catch (e) {
101+
throw new Error("Malformed response: Failed to parse server response: " + lastMessage + ". \r\n Error details: " + e.message);
102+
}
108103
}
109104

110105
// verify the sequence numbers
111106
Debug.assert(response.request_seq === request.seq, "Malformed response: response sequence number did not match request sequence number.");
112-
107+
113108
// unmarshal errors
114109
if (!response.success) {
115110
throw new Error("Error " + response.message);
@@ -118,9 +113,27 @@ namespace ts.server {
118113
Debug.assert(!!response.body, "Malformed response: Unexpected empty response body.");
119114

120115
return response;
116+
117+
function processMessage(message: string) {
118+
// Read the content length
119+
const contentLengthPrefix = "Content-Length: ";
120+
const lines = message.split("\r\n");
121+
Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response.");
122+
123+
const contentLengthText = lines[0];
124+
Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header.");
125+
const contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length));
126+
127+
// Read the body
128+
const responseBody = lines[2];
129+
130+
// Verify content length
131+
Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length.");
132+
return responseBody;
133+
}
121134
}
122135

123-
openFile(fileName: string, content?: string, scriptKindName?: "TS" | "JS" | "TSX" | "JSX"): void {
136+
openFile(fileName: string, content?: string, scriptKindName?: "TS" | "JS" | "TSX" | "JSX"): void {
124137
var args: protocol.OpenRequestArgs = { file: fileName, fileContent: content, scriptKindName };
125138
this.processRequest(CommandNames.Open, args);
126139
}
@@ -186,7 +199,7 @@ namespace ts.server {
186199
fileNames: response.body.fileNames
187200
};
188201
}
189-
202+
190203
getCompletionsAtPosition(fileName: string, position: number): CompletionInfo {
191204
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
192205
var args: protocol.CompletionsRequestArgs = {
@@ -199,13 +212,13 @@ namespace ts.server {
199212
var request = this.processRequest<protocol.CompletionsRequest>(CommandNames.Completions, args);
200213
var response = this.processResponse<protocol.CompletionsResponse>(request);
201214

202-
return {
215+
return {
203216
isMemberCompletion: false,
204217
isNewIdentifierLocation: false,
205218
entries: response.body
206219
};
207220
}
208-
221+
209222
getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails {
210223
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
211224
var args: protocol.CompletionDetailsRequestArgs = {
@@ -234,7 +247,7 @@ namespace ts.server {
234247
var fileName = entry.file;
235248
var start = this.lineOffsetToPosition(fileName, entry.start);
236249
var end = this.lineOffsetToPosition(fileName, entry.end);
237-
250+
238251
return {
239252
name: entry.name,
240253
containerName: entry.containerName || "",
@@ -264,7 +277,7 @@ namespace ts.server {
264277
var request = this.processRequest<protocol.FormatRequest>(CommandNames.Format, args);
265278
var response = this.processResponse<protocol.FormatResponse>(request);
266279

267-
return response.body.map(entry=> this.convertCodeEditsToTextChange(fileName, entry));
280+
return response.body.map(entry => this.convertCodeEditsToTextChange(fileName, entry));
268281
}
269282

270283
getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): ts.TextChange[] {
@@ -284,7 +297,7 @@ namespace ts.server {
284297
var request = this.processRequest<protocol.FormatOnKeyRequest>(CommandNames.Formatonkey, args);
285298
var response = this.processResponse<protocol.FormatResponse>(request);
286299

287-
return response.body.map(entry=> this.convertCodeEditsToTextChange(fileName, entry));
300+
return response.body.map(entry => this.convertCodeEditsToTextChange(fileName, entry));
288301
}
289302

290303
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] {
@@ -339,7 +352,7 @@ namespace ts.server {
339352
});
340353
}
341354

342-
findReferences(fileName: string, position: number): ReferencedSymbol[]{
355+
findReferences(fileName: string, position: number): ReferencedSymbol[] {
343356
// Not yet implemented.
344357
return [];
345358
}
@@ -444,7 +457,7 @@ namespace ts.server {
444457
text: item.text,
445458
kind: item.kind,
446459
kindModifiers: item.kindModifiers || "",
447-
spans: item.spans.map(span=> createTextSpanFromBounds(this.lineOffsetToPosition(fileName, span.start), this.lineOffsetToPosition(fileName, span.end))),
460+
spans: item.spans.map(span => createTextSpanFromBounds(this.lineOffsetToPosition(fileName, span.start), this.lineOffsetToPosition(fileName, span.end))),
448461
childItems: this.decodeNavigationBarItems(item.childItems, fileName),
449462
indent: 0,
450463
bolded: false,
@@ -478,10 +491,10 @@ namespace ts.server {
478491
line: lineOffset.line,
479492
offset: lineOffset.offset
480493
};
481-
494+
482495
var request = this.processRequest<protocol.SignatureHelpRequest>(CommandNames.SignatureHelp, args);
483496
var response = this.processResponse<protocol.SignatureHelpResponse>(request);
484-
497+
485498
if (!response.body) {
486499
return undefined;
487500
}
@@ -490,7 +503,7 @@ namespace ts.server {
490503
var span = helpItems.applicableSpan;
491504
var start = this.lineOffsetToPosition(fileName, span.start);
492505
var end = this.lineOffsetToPosition(fileName, span.end);
493-
506+
494507
var result: SignatureHelpItems = {
495508
items: helpItems.items,
496509
applicableSpan: {
@@ -499,7 +512,7 @@ namespace ts.server {
499512
},
500513
selectedItemIndex: helpItems.selectedItemIndex,
501514
argumentIndex: helpItems.argumentIndex,
502-
argumentCount: helpItems.argumentCount,
515+
argumentCount: helpItems.argumentCount,
503516
}
504517
return result;
505518
}
@@ -561,15 +574,15 @@ namespace ts.server {
561574
}
562575

563576
getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] {
564-
throw new Error("Not Implemented Yet.");
577+
throw new Error("Not Implemented Yet.");
565578
}
566-
579+
567580
getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion {
568-
throw new Error("Not Implemented Yet.");
581+
throw new Error("Not Implemented Yet.");
569582
}
570583

571584
isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean {
572-
throw new Error("Not Implemented Yet.");
585+
throw new Error("Not Implemented Yet.");
573586
}
574587

575588
getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[] {

src/server/editorServices.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,8 +1122,13 @@ namespace ts.server {
11221122
return { configFileName, configFileErrors: configResult.errors };
11231123
}
11241124
else {
1125+
// even if opening config file was successful, it could still
1126+
// contain errors that were tolerated.
11251127
this.log("Opened configuration file " + configFileName, "Info");
11261128
this.configuredProjects.push(configResult.project);
1129+
if (configResult.errors && configResult.errors.length > 0) {
1130+
return { configFileName, configFileErrors: configResult.errors };
1131+
}
11271132
}
11281133
}
11291134
else {
@@ -1261,14 +1266,14 @@ namespace ts.server {
12611266
}
12621267
else {
12631268
const project = this.createProject(configFilename, projectOptions);
1269+
let errors: Diagnostic[];
12641270
for (const rootFilename of projectOptions.files) {
12651271
if (this.host.fileExists(rootFilename)) {
12661272
const info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename);
12671273
project.addRoot(info);
12681274
}
12691275
else {
1270-
const error = createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename);
1271-
return { success: false, errors: [error] };
1276+
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename));
12721277
}
12731278
}
12741279
project.finishGraph();
@@ -1279,7 +1284,7 @@ namespace ts.server {
12791284
path => this.directoryWatchedForSourceFilesChanged(project, path),
12801285
/*recursive*/ true
12811286
);
1282-
return { success: true, project: project };
1287+
return { success: true, project: project, errors };
12831288
}
12841289
}
12851290

@@ -1295,7 +1300,7 @@ namespace ts.server {
12951300
}
12961301
else {
12971302
const oldFileNames = project.compilerService.host.roots.map(info => info.fileName);
1298-
const newFileNames = projectOptions.files;
1303+
const newFileNames = ts.filter(projectOptions.files, f => this.host.fileExists(f));
12991304
const fileNamesToRemove = oldFileNames.filter(f => newFileNames.indexOf(f) < 0);
13001305
const fileNamesToAdd = newFileNames.filter(f => oldFileNames.indexOf(f) < 0);
13011306

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path="../fourslash.ts"/>
2+
3+
// @Filename: a.ts
4+
////export var test = "test String"
5+
6+
// @Filename: b.ts
7+
////export var test2 = "test String"
8+
9+
// @Filename: tsconfig.json
10+
////{ "files": ["a.ts", "c.ts", "b.ts"] }
11+
12+
goTo.file("a.ts");
13+
verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts"])

0 commit comments

Comments
 (0)