@@ -16,6 +16,87 @@ import (
1616 "github.com/microsoft/typescript-go/internal/tspath"
1717)
1818
19+ type FileLike interface {
20+ FileName () string
21+ Text () string
22+ ECMALineMap () []core.TextPos
23+ }
24+
25+ // Diagnostic interface abstracts over ast.Diagnostic and LSP diagnostics
26+ type Diagnostic interface {
27+ File () FileLike
28+ Pos () int
29+ End () int
30+ Len () int
31+ Code () int32
32+ Category () diagnostics.Category
33+ Message () string
34+ MessageChain () []Diagnostic
35+ RelatedInformation () []Diagnostic
36+ }
37+
38+ // ASTDiagnostic wraps ast.Diagnostic to implement the Diagnostic interface
39+ type ASTDiagnostic struct {
40+ * ast.Diagnostic
41+ }
42+
43+ func (d * ASTDiagnostic ) RelatedInformation () []Diagnostic {
44+ related := d .Diagnostic .RelatedInformation ()
45+ result := make ([]Diagnostic , len (related ))
46+ for i , r := range related {
47+ result [i ] = & ASTDiagnostic {r }
48+ }
49+ return result
50+ }
51+
52+ func (d * ASTDiagnostic ) File () FileLike {
53+ if file := d .Diagnostic .File (); file != nil {
54+ return file
55+ }
56+ return nil
57+ }
58+
59+ func (d * ASTDiagnostic ) MessageChain () []Diagnostic {
60+ chain := d .Diagnostic .MessageChain ()
61+ result := make ([]Diagnostic , len (chain ))
62+ for i , c := range chain {
63+ result [i ] = & ASTDiagnostic {c }
64+ }
65+ return result
66+ }
67+
68+ func WrapASTDiagnostic (d * ast.Diagnostic ) * ASTDiagnostic {
69+ return & ASTDiagnostic {d }
70+ }
71+
72+ func WrapASTDiagnostics (diags []* ast.Diagnostic ) []* ASTDiagnostic {
73+ result := make ([]* ASTDiagnostic , len (diags ))
74+ for i , d := range diags {
75+ result [i ] = WrapASTDiagnostic (d )
76+ }
77+ return result
78+ }
79+
80+ func FromASTDiagnostics (diags []* ast.Diagnostic ) []Diagnostic {
81+ result := make ([]Diagnostic , len (diags ))
82+ for i , d := range diags {
83+ result [i ] = WrapASTDiagnostic (d )
84+ }
85+ return result
86+ }
87+
88+ func ToDiagnostics [T Diagnostic ](diags []T ) []Diagnostic {
89+ result := make ([]Diagnostic , len (diags ))
90+ for i , d := range diags {
91+ result [i ] = d
92+ }
93+ return result
94+ }
95+
96+ func CompareASTDiagnostics (a , b * ASTDiagnostic ) int {
97+ return ast .CompareDiagnostics (a .Diagnostic , b .Diagnostic )
98+ }
99+
19100type FormattingOptions struct {
20101 tspath.ComparePathsOptions
21102 NewLine string
@@ -36,7 +117,7 @@ const (
36117 ellipsis = "..."
37118)
38119
39- func FormatDiagnosticsWithColorAndContext (output io.Writer , diags []* ast. Diagnostic , formatOpts * FormattingOptions ) {
120+ func FormatDiagnosticsWithColorAndContext (output io.Writer , diags []Diagnostic , formatOpts * FormattingOptions ) {
40121 if len (diags ) == 0 {
41122 return
42123 }
@@ -48,10 +129,10 @@ func FormatDiagnosticsWithColorAndContext(output io.Writer, diags []*ast.Diagnos
48129 }
49130}
50131
51- func FormatDiagnosticWithColorAndContext (output io.Writer , diagnostic * ast. Diagnostic , formatOpts * FormattingOptions ) {
132+ func FormatDiagnosticWithColorAndContext (output io.Writer , diagnostic Diagnostic , formatOpts * FormattingOptions ) {
52133 if diagnostic .File () != nil {
53134 file := diagnostic .File ()
54- pos := diagnostic .Loc (). Pos ()
135+ pos := diagnostic .Pos ()
55136 WriteLocation (output , file , pos , formatOpts , writeWithStyleAndReset )
56137 fmt .Fprint (output , " - " )
57138 }
@@ -83,7 +164,7 @@ func FormatDiagnosticWithColorAndContext(output io.Writer, diagnostic *ast.Diagn
83164 }
84165}
85166
86- func writeCodeSnippet (writer io.Writer , sourceFile * ast. SourceFile , start int , length int , squiggleColor string , indent string , formatOpts * FormattingOptions ) {
167+ func writeCodeSnippet (writer io.Writer , sourceFile FileLike , start int , length int , squiggleColor string , indent string , formatOpts * FormattingOptions ) {
87168 firstLine , firstLineChar := scanner .GetECMALineAndCharacterOfPosition (sourceFile , start )
88169 lastLine , lastLineChar := scanner .GetECMALineAndCharacterOfPosition (sourceFile , start + length )
89170 if length == 0 {
@@ -118,7 +199,7 @@ func writeCodeSnippet(writer io.Writer, sourceFile *ast.SourceFile, start int, l
118199 if i < lastLineOfFile {
119200 lineEnd = scanner .GetECMAPositionOfLineAndCharacter (sourceFile , i + 1 , 0 )
120201 } else {
121- lineEnd = sourceFile .Loc . End ( )
202+ lineEnd = len ( sourceFile .Text () )
122203 }
123204
124205 lineContent := strings .TrimRightFunc (sourceFile .Text ()[lineStart :lineEnd ], unicode .IsSpace ) // trim from end
@@ -167,21 +248,25 @@ func writeCodeSnippet(writer io.Writer, sourceFile *ast.SourceFile, start int, l
167248 }
168249}
169250
170- func FlattenDiagnosticMessage (d * ast. Diagnostic , newLine string ) string {
251+ func FlattenDiagnosticMessage (d Diagnostic , newLine string ) string {
171252 var output strings.Builder
172253 WriteFlattenedDiagnosticMessage (& output , d , newLine )
173254 return output .String ()
174255}
175256
176- func WriteFlattenedDiagnosticMessage (writer io.Writer , diagnostic * ast.Diagnostic , newline string ) {
257+ func WriteFlattenedASTDiagnosticMessage (writer io.Writer , diagnostic * ast.Diagnostic , newline string ) {
258+ WriteFlattenedDiagnosticMessage (writer , WrapASTDiagnostic (diagnostic ), newline )
259+ }
260+
261+ func WriteFlattenedDiagnosticMessage (writer io.Writer , diagnostic Diagnostic , newline string ) {
177262 fmt .Fprint (writer , diagnostic .Message ())
178263
179264 for _ , chain := range diagnostic .MessageChain () {
180265 flattenDiagnosticMessageChain (writer , chain , newline , 1 /*level*/ )
181266 }
182267}
183268
184- func flattenDiagnosticMessageChain (writer io.Writer , chain * ast. Diagnostic , newLine string , level int ) {
269+ func flattenDiagnosticMessageChain (writer io.Writer , chain Diagnostic , newLine string , level int ) {
185270 fmt .Fprint (writer , newLine )
186271 for range level {
187272 fmt .Fprint (writer , " " )
@@ -215,7 +300,7 @@ func writeWithStyleAndReset(output io.Writer, text string, formatStyle string) {
215300 fmt .Fprint (output , resetEscapeSequence )
216301}
217302
218- func WriteLocation (output io.Writer , file * ast. SourceFile , pos int , formatOpts * FormattingOptions , writeWithStyleAndReset FormattedWriter ) {
303+ func WriteLocation (output io.Writer , file FileLike , pos int , formatOpts * FormattingOptions , writeWithStyleAndReset FormattedWriter ) {
219304 firstLine , firstChar := scanner .GetECMALineAndCharacterOfPosition (file , pos )
220305 var relativeFileName string
221306 if formatOpts != nil {
@@ -235,12 +320,12 @@ func WriteLocation(output io.Writer, file *ast.SourceFile, pos int, formatOpts *
235320
236321type ErrorSummary struct {
237322 TotalErrorCount int
238- GlobalErrors []* ast. Diagnostic
239- ErrorsByFiles map [* ast. SourceFile ][]* ast. Diagnostic
240- SortedFileList [] * ast. SourceFile
323+ GlobalErrors []Diagnostic
324+ ErrorsByFile map [FileLike ][]Diagnostic
325+ SortedFiles [] FileLike
241326}
242327
243- func WriteErrorSummaryText (output io.Writer , allDiagnostics []* ast. Diagnostic , formatOpts * FormattingOptions ) {
328+ func WriteErrorSummaryText (output io.Writer , allDiagnostics []Diagnostic , formatOpts * FormattingOptions ) {
244329 // Roughly corresponds to 'getErrorSummaryText' from watch.ts
245330
246331 errorSummary := getErrorSummary (allDiagnostics )
@@ -249,12 +334,12 @@ func WriteErrorSummaryText(output io.Writer, allDiagnostics []*ast.Diagnostic, f
249334 return
250335 }
251336
252- firstFile := & ast. SourceFile {}
253- if len (errorSummary .SortedFileList ) > 0 {
254- firstFile = errorSummary .SortedFileList [0 ]
337+ var firstFile FileLike
338+ if len (errorSummary .SortedFiles ) > 0 {
339+ firstFile = errorSummary .SortedFiles [0 ]
255340 }
256- firstFileName := prettyPathForFileError (firstFile , errorSummary .ErrorsByFiles [firstFile ], formatOpts )
257- numErroringFiles := len (errorSummary .ErrorsByFiles )
341+ firstFileName := prettyPathForFileError (firstFile , errorSummary .ErrorsByFile [firstFile ], formatOpts )
342+ numErroringFiles := len (errorSummary .ErrorsByFile )
258343
259344 var message string
260345 if totalErrorCount == 1 {
@@ -287,10 +372,10 @@ func WriteErrorSummaryText(output io.Writer, allDiagnostics []*ast.Diagnostic, f
287372 }
288373}
289374
290- func getErrorSummary (diags []* ast. Diagnostic ) * ErrorSummary {
375+ func getErrorSummary (diags []Diagnostic ) * ErrorSummary {
291376 var totalErrorCount int
292- var globalErrors []* ast. Diagnostic
293- var errorsByFiles map [* ast. SourceFile ][]* ast. Diagnostic
377+ var globalErrors []Diagnostic
378+ var errorsByFile map [FileLike ][]Diagnostic
294379
295380 for _ , diagnostic := range diags {
296381 if diagnostic .Category () != diagnostics .CategoryError {
@@ -301,32 +386,32 @@ func getErrorSummary(diags []*ast.Diagnostic) *ErrorSummary {
301386 if diagnostic .File () == nil {
302387 globalErrors = append (globalErrors , diagnostic )
303388 } else {
304- if errorsByFiles == nil {
305- errorsByFiles = make (map [* ast. SourceFile ][]* ast. Diagnostic )
389+ if errorsByFile == nil {
390+ errorsByFile = make (map [FileLike ][]Diagnostic )
306391 }
307- errorsByFiles [diagnostic .File ()] = append (errorsByFiles [diagnostic .File ()], diagnostic )
392+ errorsByFile [diagnostic .File ()] = append (errorsByFile [diagnostic .File ()], diagnostic )
308393 }
309394 }
310395
311396 // !!!
312397 // Need an ordered map here, but sorting for consistency.
313- sortedFileList := slices .SortedFunc (maps .Keys (errorsByFiles ), func (a , b * ast. SourceFile ) int {
398+ sortedFiles := slices .SortedFunc (maps .Keys (errorsByFile ), func (a , b FileLike ) int {
314399 return strings .Compare (a .FileName (), b .FileName ())
315400 })
316401
317402 return & ErrorSummary {
318403 TotalErrorCount : totalErrorCount ,
319404 GlobalErrors : globalErrors ,
320- ErrorsByFiles : errorsByFiles ,
321- SortedFileList : sortedFileList ,
405+ ErrorsByFile : errorsByFile ,
406+ SortedFiles : sortedFiles ,
322407 }
323408}
324409
325410func writeTabularErrorsDisplay (output io.Writer , errorSummary * ErrorSummary , formatOpts * FormattingOptions ) {
326- sortedFiles := errorSummary .SortedFileList
411+ sortedFiles := errorSummary .SortedFiles
327412
328413 maxErrors := 0
329- for _ , errorsForFile := range errorSummary .ErrorsByFiles {
414+ for _ , errorsForFile := range errorSummary .ErrorsByFile {
330415 maxErrors = max (maxErrors , len (errorsForFile ))
331416 }
332417
@@ -344,7 +429,7 @@ func writeTabularErrorsDisplay(output io.Writer, errorSummary *ErrorSummary, for
344429 fmt .Fprint (output , formatOpts .NewLine )
345430
346431 for _ , file := range sortedFiles {
347- fileErrors := errorSummary .ErrorsByFiles [file ]
432+ fileErrors := errorSummary .ErrorsByFile [file ]
348433 errorCount := len (fileErrors )
349434
350435 fmt .Fprintf (output , "%*d " , leftPaddingGoal , errorCount )
@@ -353,11 +438,11 @@ func writeTabularErrorsDisplay(output io.Writer, errorSummary *ErrorSummary, for
353438 }
354439}
355440
356- func prettyPathForFileError (file * ast. SourceFile , fileErrors []* ast. Diagnostic , formatOpts * FormattingOptions ) string {
441+ func prettyPathForFileError (file FileLike , fileErrors []Diagnostic , formatOpts * FormattingOptions ) string {
357442 if file == nil || len (fileErrors ) == 0 {
358443 return ""
359444 }
360- line := scanner .GetECMALineOfPosition (file , fileErrors [0 ].Loc (). Pos ())
445+ line := scanner .GetECMALineOfPosition (file , fileErrors [0 ].Pos ())
361446 fileName := file .FileName ()
362447 if tspath .PathIsAbsolute (fileName ) && tspath .PathIsAbsolute (formatOpts .CurrentDirectory ) {
363448 fileName = tspath .ConvertToRelativePath (file .FileName (), formatOpts .ComparePathsOptions )
@@ -370,15 +455,15 @@ func prettyPathForFileError(file *ast.SourceFile, fileErrors []*ast.Diagnostic,
370455 )
371456}
372457
373- func WriteFormatDiagnostics (output io.Writer , diagnostics []* ast. Diagnostic , formatOpts * FormattingOptions ) {
458+ func WriteFormatDiagnostics (output io.Writer , diagnostics []Diagnostic , formatOpts * FormattingOptions ) {
374459 for _ , diagnostic := range diagnostics {
375460 WriteFormatDiagnostic (output , diagnostic , formatOpts )
376461 }
377462}
378463
379- func WriteFormatDiagnostic (output io.Writer , diagnostic * ast. Diagnostic , formatOpts * FormattingOptions ) {
464+ func WriteFormatDiagnostic (output io.Writer , diagnostic Diagnostic , formatOpts * FormattingOptions ) {
380465 if diagnostic .File () != nil {
381- line , character := scanner .GetECMALineAndCharacterOfPosition (diagnostic .File (), diagnostic .Loc (). Pos ())
466+ line , character := scanner .GetECMALineAndCharacterOfPosition (diagnostic .File (), diagnostic .Pos ())
382467 fileName := diagnostic .File ().FileName ()
383468 relativeFileName := tspath .ConvertToRelativePath (fileName , formatOpts .ComparePathsOptions )
384469 fmt .Fprintf (output , "%s(%d,%d): " , relativeFileName , line + 1 , character + 1 )
@@ -389,14 +474,14 @@ func WriteFormatDiagnostic(output io.Writer, diagnostic *ast.Diagnostic, formatO
389474 fmt .Fprint (output , formatOpts .NewLine )
390475}
391476
392- func FormatDiagnosticsStatusWithColorAndTime (output io.Writer , time string , diag * ast. Diagnostic , formatOpts * FormattingOptions ) {
477+ func FormatDiagnosticsStatusWithColorAndTime (output io.Writer , time string , diag Diagnostic , formatOpts * FormattingOptions ) {
393478 fmt .Fprint (output , "[" )
394479 writeWithStyleAndReset (output , time , foregroundColorEscapeGrey )
395480 fmt .Fprint (output , "] " )
396481 WriteFlattenedDiagnosticMessage (output , diag , formatOpts .NewLine )
397482}
398483
399- func FormatDiagnosticsStatusAndTime (output io.Writer , time string , diag * ast. Diagnostic , formatOpts * FormattingOptions ) {
484+ func FormatDiagnosticsStatusAndTime (output io.Writer , time string , diag Diagnostic , formatOpts * FormattingOptions ) {
400485 fmt .Fprint (output , time , " - " )
401486 WriteFlattenedDiagnosticMessage (output , diag , formatOpts .NewLine )
402487}
@@ -406,7 +491,7 @@ var ScreenStartingCodes = []int32{
406491 diagnostics .File_change_detected_Starting_incremental_compilation .Code (),
407492}
408493
409- func TryClearScreen (output io.Writer , diag * ast. Diagnostic , options * core.CompilerOptions ) bool {
494+ func TryClearScreen (output io.Writer , diag Diagnostic , options * core.CompilerOptions ) bool {
410495 if ! options .PreserveWatchOutput .IsTrue () &&
411496 ! options .ExtendedDiagnostics .IsTrue () &&
412497 ! options .Diagnostics .IsTrue () &&
0 commit comments