import { DiagnosticLevel } from './configOptions' ; import { Diagnostic , DiagnosticAction , DiagnosticCategory } from './diagnostic' ; import { convertOffsetsToRange } from './positionUtils' ; import { hashString } from './stringUtils' ; import { Range , TextRange } from './textRange' ; import { TextRangeCollection } from './textRangeCollection' ; export interface FileDiagnostics { filePath : string ; version : number | undefined ; diagnostics : Diagnostic [ ] ; } export class DiagnosticSink { private _diagnosticList : Diagnostic [ ] ; private _diagnosticMap : Map < string , Diagnostic > ; constructor ( diagnostics ? ) { this . _diagnosticList = diagnostics || [ ] ; this . _diagnosticMap = new Map < string , Diagnostic > ( ) ; } fetchAndClear ( ) { const prevDiagnostics = this . _diagnosticList ; this . _diagnosticList = [ ] ; this . _diagnosticMap . clear ( ) ; return prevDiagnostics ; } addError ( message , range ) { return this . addDiagnostic ( new Diagnostic ( DiagnosticCategory . Error , message , range ) ) ; } addWarning ( message , range ) { return this . addDiagnostic ( new Diagnostic ( DiagnosticCategory . Warning , message , range ) ) ; } addInformation ( message , range ) { return this . addDiagnostic ( new Diagnostic ( DiagnosticCategory . Information , message , range ) ) ; } addUnusedCode ( message , range , action ? ) { const diag = new Diagnostic ( DiagnosticCategory . UnusedCode , message , range ) ; if ( action ) { diag . addAction ( action ) ; } return this . addDiagnostic ( diag ) ; } addDeprecated ( message , range , action ? ) { const diag = new Diagnostic ( DiagnosticCategory . Deprecated , message , range ) ; if ( action ) { diag . addAction ( action ) ; } return this . addDiagnostic ( diag ) ; } addDiagnostic ( diag ) { const key = `${ diag . range . start . line },${ diag . range . start . character }-` + `${ diag . range . end . line }-${ diag . range . end . character }:${ hashString ( diag . message ) }}` ; if ( ! this . _diagnosticMap . has ( key ) ) { this . _diagnosticList . push ( diag ) ; this . _diagnosticMap . set ( key , diag ) ; } return diag ; } addDiagnostics ( diagsToAdd ) { this . _diagnosticList . push ( ... diagsToAdd ) ; } getErrors ( ) { return this . _diagnosticList . filter ( ( diag ) => diag . category === DiagnosticCategory . Error ) ; } getWarnings ( ) { return this . _diagnosticList . filter ( ( diag ) => diag . category === DiagnosticCategory . Warning ) ; } getInformation ( ) { return this . _diagnosticList . filter ( ( diag ) => diag . category === DiagnosticCategory . Information ) ; } getUnusedCode ( ) { return this . _diagnosticList . filter ( ( diag ) => diag . category === DiagnosticCategory . UnusedCode ) ; } getDeprecated ( ) { return this . _diagnosticList . filter ( ( diag ) => diag . category === DiagnosticCategory . Deprecated ) ; } } export class TextRangeDiagnosticSink extends DiagnosticSink { private _lines : TextRangeCollection < TextRange > ; constructor ( lines , diagnostics ? ) { super ( diagnostics ) ; this . _lines = lines ; } addDiagnosticWithTextRange ( level , message , range ) { const positionRange = convertOffsetsToRange ( range . start , range . start + range . length , this . _lines ) ; switch ( level ) { case 'error' : return this . addError ( message , positionRange ) ; case 'warning' : return this . addWarning ( message , positionRange ) ; case 'information' : return this . addInformation ( message , positionRange ) ; default : throw new Error ( `${ level } is not expected value` ) ; } } addUnusedCodeWithTextRange ( message , range , action ? ) { return this . addUnusedCode ( message , convertOffsetsToRange ( range . start , range . start + range . length , this . _lines ) , action ) ; } addDeprecatedWithTextRange ( message , range , action ? ) { return this . addDeprecated ( message , convertOffsetsToRange ( range . start , range . start + range . length , this . _lines ) , action ) ; } }