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;