Add 'info' diagnostics (#22204)

* Add 'info' diagnostics

* Code review
This commit is contained in:
Andy
2018-02-28 11:16:32 -08:00
committed by GitHub
parent e26d4e4729
commit fa4619c5c1
50 changed files with 400 additions and 383 deletions

View File

@@ -75,7 +75,7 @@ namespace ts.server {
return { span: this.decodeSpan(codeEdit, fileName), newText: codeEdit.newText };
}
private processRequest<T extends protocol.Request>(command: string, args?: any): T {
private processRequest<T extends protocol.Request>(command: string, args?: T["arguments"]): T {
const request: protocol.Request = {
seq: this.sequence,
type: "request",
@@ -343,41 +343,31 @@ namespace ts.server {
}
getSyntacticDiagnostics(file: string): Diagnostic[] {
const args: protocol.SyntacticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true };
const request = this.processRequest<protocol.SyntacticDiagnosticsSyncRequest>(CommandNames.SyntacticDiagnosticsSync, args);
const response = this.processResponse<protocol.SyntacticDiagnosticsSyncResponse>(request);
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => this.convertDiagnostic(entry, file));
return this.getDiagnostics(file, CommandNames.SyntacticDiagnosticsSync);
}
getSemanticDiagnostics(file: string): Diagnostic[] {
const args: protocol.SemanticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true };
const request = this.processRequest<protocol.SemanticDiagnosticsSyncRequest>(CommandNames.SemanticDiagnosticsSync, args);
const response = this.processResponse<protocol.SemanticDiagnosticsSyncResponse>(request);
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => this.convertDiagnostic(entry, file));
return this.getDiagnostics(file, CommandNames.SemanticDiagnosticsSync);
}
getSuggestionDiagnostics(file: string): Diagnostic[] {
return this.getDiagnostics(file, CommandNames.SuggestionDiagnosticsSync);
}
convertDiagnostic(entry: protocol.DiagnosticWithLinePosition, _fileName: string): Diagnostic {
let category: DiagnosticCategory;
for (const id in DiagnosticCategory) {
if (isString(id) && entry.category === id.toLowerCase()) {
category = (<any>DiagnosticCategory)[id];
}
}
private getDiagnostics(file: string, command: CommandNames) {
const request = this.processRequest<protocol.SyntacticDiagnosticsSyncRequest | protocol.SemanticDiagnosticsSyncRequest | protocol.SuggestionDiagnosticsSyncRequest>(command, { file, includeLinePosition: true });
const response = this.processResponse<protocol.SyntacticDiagnosticsSyncResponse | protocol.SemanticDiagnosticsSyncResponse | protocol.SuggestionDiagnosticsSyncResponse>(request);
Debug.assert(category !== undefined, "convertDiagnostic: category should not be undefined");
return {
file: undefined,
start: entry.start,
length: entry.length,
messageText: entry.message,
category,
code: entry.code
};
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => {
const category = firstDefined(Object.keys(DiagnosticCategory), id =>
isString(id) && entry.category === id.toLowerCase() ? (<any>DiagnosticCategory)[id] : undefined);
return {
file: undefined,
start: entry.start,
length: entry.length,
messageText: entry.message,
category: Debug.assertDefined(category, "convertDiagnostic: category should not be undefined"),
code: entry.code
};
});
}
getCompilerOptionsDiagnostics(): Diagnostic[] {

View File

@@ -42,6 +42,7 @@ namespace ts.server.protocol {
GeterrForProject = "geterrForProject",
SemanticDiagnosticsSync = "semanticDiagnosticsSync",
SyntacticDiagnosticsSync = "syntacticDiagnosticsSync",
SuggestionDiagnosticsSync = "suggestionDiagnosticsSync",
NavBar = "navbar",
/* @internal */
NavBarFull = "navbar-full",
@@ -2010,6 +2011,14 @@ namespace ts.server.protocol {
body?: Diagnostic[] | DiagnosticWithLinePosition[];
}
export interface SuggestionDiagnosticsSyncRequest extends FileRequest {
command: CommandTypes.SuggestionDiagnosticsSync;
arguments: SuggestionDiagnosticsSyncRequestArgs;
}
export type SuggestionDiagnosticsSyncRequestArgs = SemanticDiagnosticsSyncRequestArgs;
export type SuggestionDiagnosticsSyncResponse = SemanticDiagnosticsSyncResponse;
/**
* Synchronous request for syntactic diagnostics of one file.
*/
@@ -2121,7 +2130,7 @@ namespace ts.server.protocol {
text: string;
/**
* The category of the diagnostic message, e.g. "error" vs. "warning"
* The category of the diagnostic message, e.g. "error", "warning", or "suggestion".
*/
category: string;
@@ -2155,8 +2164,10 @@ namespace ts.server.protocol {
diagnostics: Diagnostic[];
}
export type DiagnosticEventKind = "semanticDiag" | "syntaxDiag" | "suggestionDiag";
/**
* Event message for "syntaxDiag" and "semanticDiag" event types.
* Event message for DiagnosticEventKind event types.
* These events provide syntactic and semantic errors for a file.
*/
export interface DiagnosticEvent extends Event {

View File

@@ -79,7 +79,7 @@ namespace ts.server {
end: scriptInfo.positionToLineOffset(diag.start + diag.length),
text: flattenDiagnosticMessageText(diag.messageText, "\n"),
code: diag.code,
category: DiagnosticCategory[diag.category].toLowerCase(),
category: diagnosticCategoryName(diag),
source: diag.source
};
}
@@ -95,7 +95,7 @@ namespace ts.server {
const end = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
const text = flattenDiagnosticMessageText(diag.messageText, "\n");
const { code, source } = diag;
const category = DiagnosticCategory[diag.category].toLowerCase();
const category = diagnosticCategoryName(diag);
return includeFileName ? { start, end, text, code, category, source, fileName: diag.file && diag.file.fileName } :
{ start, end, text, code, category, source };
}
@@ -466,30 +466,26 @@ namespace ts.server {
}
private semanticCheck(file: NormalizedPath, project: Project) {
try {
let diags: ReadonlyArray<Diagnostic> = emptyArray;
if (!isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) {
diags = project.getLanguageService().getSemanticDiagnostics(file);
}
const bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: bakedDiags }, "semanticDiag");
}
catch (err) {
this.logError(err, "semantic check");
}
const diags = isDeclarationFileInJSOnlyNonConfiguredProject(project, file)
? emptyArray
: project.getLanguageService().getSemanticDiagnostics(file);
this.sendDiagnosticsEvent(file, project, diags, "semanticDiag");
}
private syntacticCheck(file: NormalizedPath, project: Project) {
this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSyntacticDiagnostics(file), "syntaxDiag");
}
private infoCheck(file: NormalizedPath, project: Project) {
this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSuggestionDiagnostics(file), "suggestionDiag");
}
private sendDiagnosticsEvent(file: NormalizedPath, project: Project, diagnostics: ReadonlyArray<Diagnostic>, kind: protocol.DiagnosticEventKind): void {
try {
const diags = project.getLanguageService().getSyntacticDiagnostics(file);
if (diags) {
const bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: bakedDiags }, "syntaxDiag");
}
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)) }, kind);
}
catch (err) {
this.logError(err, "syntactic check");
this.logError(err, kind);
}
}
@@ -499,21 +495,34 @@ namespace ts.server {
let index = 0;
const checkOne = () => {
if (this.changeSeq === seq) {
const checkSpec = checkList[index];
index++;
if (checkSpec.project.containsFile(checkSpec.fileName, requireOpen)) {
this.syntacticCheck(checkSpec.fileName, checkSpec.project);
if (this.changeSeq === seq) {
next.immediate(() => {
this.semanticCheck(checkSpec.fileName, checkSpec.project);
if (checkList.length > index) {
next.delay(followMs, checkOne);
}
});
}
}
if (this.changeSeq !== seq) {
return;
}
const { fileName, project } = checkList[index];
index++;
if (!project.containsFile(fileName, requireOpen)) {
return;
}
this.syntacticCheck(fileName, project);
if (this.changeSeq !== seq) {
return;
}
next.immediate(() => {
this.semanticCheck(fileName, project);
if (this.changeSeq !== seq) {
return;
}
next.immediate(() => {
this.infoCheck(fileName, project);
if (checkList.length > index) {
next.delay(followMs, checkOne);
}
});
});
};
if (checkList.length > index && this.changeSeq === seq) {
@@ -580,7 +589,7 @@ namespace ts.server {
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
start: d.start,
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
category: diagnosticCategoryName(d),
code: d.code,
startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)),
endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length))
@@ -606,7 +615,7 @@ namespace ts.server {
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
start: d.start,
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
category: diagnosticCategoryName(d),
code: d.code,
source: d.source,
startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start),
@@ -756,6 +765,16 @@ namespace ts.server {
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file), args.includeLinePosition);
}
private getSuggestionDiagnosticsSync(args: protocol.SuggestionDiagnosticsSyncRequestArgs): ReadonlyArray<protocol.Diagnostic> | ReadonlyArray<protocol.DiagnosticWithLinePosition> {
const { configFile } = this.getConfigFileAndProject(args);
if (configFile) {
// Currently there are no info diagnostics for config files.
return emptyArray;
}
// isSemantic because we don't want to info diagnostics in declaration files for JS-only users
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSuggestionDiagnostics(file), args.includeLinePosition);
}
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.DocumentHighlightsItem> | ReadonlyArray<DocumentHighlights> {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
@@ -1953,6 +1972,9 @@ namespace ts.server {
[CommandNames.SyntacticDiagnosticsSync]: (request: protocol.SyntacticDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSyntacticDiagnosticsSync(request.arguments));
},
[CommandNames.SuggestionDiagnosticsSync]: (request: protocol.SuggestionDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSuggestionDiagnosticsSync(request.arguments));
},
[CommandNames.Geterr]: (request: protocol.GeterrRequest) => {
this.errorCheck.startNew(next => this.getDiagnostics(next, request.arguments.delay, request.arguments.files));
return this.notRequired();