blob: 61680acfde576663d65afafe01eec4ee6a00af80 [file] [log] [blame]
import * as ts from 'typescript';
/**
* A Tsetse check Failure is almost identical to a Diagnostic from TypeScript
* except that:
* (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 readonly sourceFile: ts.SourceFile,
private readonly start: number, private readonly end: number,
private readonly failureText: string, private readonly code: number,
private readonly suggestedFix?: Fix) {}
/**
* 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
};
}
toString(): string {
return `{ sourceFile:${
this.sourceFile ? this.sourceFile.fileName : 'unknown'}, start:${
this.start}, end:${this.end}, fix:${fixToString(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
}
/**
* Stringifies a Fix, replacing the ts.SourceFile with the matching filename.
*/
export function fixToString(f?: Fix) {
if (!f) return 'undefined';
return '{' + JSON.stringify(f.changes.map(ic => {
return {
start: ic.start,
end: ic.end,
replacement: ic.replacement,
fileName: ic.sourceFile.fileName
};
})) +
'}'
}