Add an optional Fix to the Failure type in Tsetse. Nothing consumes this for now.
PiperOrigin-RevId: 241706383
diff --git a/internal/tsetse/failure.ts b/internal/tsetse/failure.ts
index 2f055e3..56355ad 100644
--- a/internal/tsetse/failure.ts
+++ b/internal/tsetse/failure.ts
@@ -6,22 +6,45 @@
* (1) The error code is defined by each individual Tsetse rule.
* (2) The optional `source` property is set to `Tsetse` so the host (VS Code
* for instance) would use that to indicate where the error comes from.
+ * (3) There's an optional suggestedFix field.
*/
export class Failure {
constructor(
- private sourceFile: ts.SourceFile, private start: number,
- private end: number, private failureText: string, private code: number) {}
+ private readonly sourceFile: ts.SourceFile,
+ private readonly start: number, private readonly end: number,
+ private readonly failureText: string, private readonly code: number,
+ private readonly suggestedFix?: Fix) {}
- toDiagnostic(): ts.Diagnostic {
+ /**
+ * This returns a structure compatible with ts.Diagnostic, but with added
+ * fields, for convenience and to support suggested fixes.
+ */
+ toDiagnostic(): ts.Diagnostic&{end: number, fix?: Fix} {
return {
file: this.sourceFile,
start: this.start,
+ end: this.end, // Not in ts.Diagnostic, but always useful for
+ // start-end-using systems.
length: this.end - this.start,
messageText: this.failureText,
category: ts.DiagnosticCategory.Error,
code: this.code,
// source is the name of the plugin.
source: 'Tsetse',
+ fix: this.suggestedFix
};
}
}
+
+/**
+ * A Fix is a potential repair to the associated Failure.
+ */
+export interface Fix {
+ /**
+ * The individual text replacements composing that fix.
+ */
+ changes: IndividualChange[],
+}
+export interface IndividualChange {
+ sourceFile: ts.SourceFile, start: number, end: number, replacement: string
+}
diff --git a/internal/tsetse/language_service_plugin.ts b/internal/tsetse/language_service_plugin.ts
index d20343a..4969f4d 100644
--- a/internal/tsetse/language_service_plugin.ts
+++ b/internal/tsetse/language_service_plugin.ts
@@ -1,7 +1,5 @@
import * as ts from 'typescript/lib/tsserverlibrary';
-
import * as pluginApi from '../tsc_wrapped/plugin_api';
-
import {Checker} from './checker';
import {registerRules} from './runner';
@@ -14,10 +12,12 @@
const oldService = info.languageService;
const program = oldService.getProgram();
- // Signature of `getProgram` is `getProgram(): Program | undefined;` in ts 3.1
- // so we must check if the return value is valid to compile with ts 3.1.
+ // Signature of `getProgram` is `getProgram(): Program | undefined;` in
+ // ts 3.1 so we must check if the return value is valid to compile with
+ // ts 3.1.
if (!program) {
- throw new Error('Failed to initialize tsetse language_service_plugin: program is undefined');
+ throw new Error(
+ 'Failed to initialize tsetse language_service_plugin: program is undefined');
}
const checker = new Checker(program);
@@ -31,9 +31,9 @@
const proxy = pluginApi.createProxy(oldService);
proxy.getSemanticDiagnostics = (fileName: string) => {
const result = [...oldService.getSemanticDiagnostics(fileName)];
- result.push(
- ...checker.execute(program.getSourceFile(fileName)!)
- .map(failure => failure.toDiagnostic()));
+ // Note that this ignores suggested fixes.
+ result.push(...checker.execute(program.getSourceFile(fileName)!)
+ .map(failure => failure.toDiagnostic()));
return result;
};
return proxy;