...

Source file src/github.com/bazelbuild/buildtools/buildifier/utils/diagnostics.go

Documentation: github.com/bazelbuild/buildtools/buildifier/utils

     1  /*
     2  Copyright 2020 Google LLC
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      https://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package utils
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"github.com/bazelbuild/buildtools/build"
    23  	"github.com/bazelbuild/buildtools/warn"
    24  	"strings"
    25  )
    26  
    27  // Diagnostics contains diagnostic information returned by formatter and linter
    28  type Diagnostics struct {
    29  	Success bool               `json:"success"` // overall success (whether all files are formatted properly and have no warnings)
    30  	Files   []*FileDiagnostics `json:"files"`   // diagnostics per file
    31  }
    32  
    33  // Format formats a Diagnostics object either as plain text or as json
    34  func (d *Diagnostics) Format(format string, verbose bool) string {
    35  	switch format {
    36  	case "text", "":
    37  		var output strings.Builder
    38  		for _, f := range d.Files {
    39  			for _, w := range f.Warnings {
    40  				formatString := "%s:%d: %s: %s (%s)\n"
    41  				if !w.Actionable {
    42  					formatString = "%s:%d: %s: %s [%s]\n"
    43  				}
    44  				output.WriteString(fmt.Sprintf(formatString,
    45  					f.Filename,
    46  					w.Start.Line,
    47  					w.Category,
    48  					w.Message,
    49  					w.URL))
    50  			}
    51  			if !f.Formatted {
    52  				output.WriteString(fmt.Sprintf("%s # reformat\n", f.Filename))
    53  			}
    54  		}
    55  		return output.String()
    56  	case "json":
    57  		var result []byte
    58  		if verbose {
    59  			result, _ = json.MarshalIndent(*d, "", "    ")
    60  		} else {
    61  			result, _ = json.Marshal(*d)
    62  		}
    63  		return string(result) + "\n"
    64  	}
    65  	return ""
    66  }
    67  
    68  // FileDiagnostics contains diagnostics information for a file
    69  type FileDiagnostics struct {
    70  	Filename  string     `json:"filename"`
    71  	Formatted bool       `json:"formatted"`
    72  	Valid     bool       `json:"valid"`
    73  	Warnings  []*warning `json:"warnings"`
    74  }
    75  
    76  type warning struct {
    77  	Start       position `json:"start"`
    78  	End         position `json:"end"`
    79  	Category    string   `json:"category"`
    80  	Actionable  bool     `json:"actionable"`
    81  	AutoFixable bool     `json:"autoFixable"`
    82  	Message     string   `json:"message"`
    83  	URL         string   `json:"url"`
    84  }
    85  
    86  type position struct {
    87  	Line   int `json:"line"`
    88  	Column int `json:"column"`
    89  }
    90  
    91  // NewDiagnostics returns a new Diagnostics object
    92  func NewDiagnostics(fileDiagnostics ...*FileDiagnostics) *Diagnostics {
    93  	diagnostics := &Diagnostics{
    94  		Success: true,
    95  		Files:   fileDiagnostics,
    96  	}
    97  	for _, file := range diagnostics.Files {
    98  		if !file.Formatted || len(file.Warnings) > 0 {
    99  			diagnostics.Success = false
   100  			break
   101  		}
   102  	}
   103  	return diagnostics
   104  }
   105  
   106  // NewFileDiagnostics returns a new FileDiagnostics object
   107  func NewFileDiagnostics(filename string, warnings []*warn.Finding) *FileDiagnostics {
   108  	fileDiagnostics := FileDiagnostics{
   109  		Filename:  filename,
   110  		Formatted: true,
   111  		Valid:     true,
   112  		Warnings:  []*warning{},
   113  	}
   114  
   115  	for _, w := range warnings {
   116  		fileDiagnostics.Warnings = append(fileDiagnostics.Warnings, &warning{
   117  			Start:       makePosition(w.Start),
   118  			End:         makePosition(w.End),
   119  			Category:    w.Category,
   120  			Actionable:  w.Actionable,
   121  			AutoFixable: w.AutoFixable,
   122  			Message:     w.Message,
   123  			URL:         w.URL,
   124  		})
   125  	}
   126  
   127  	return &fileDiagnostics
   128  }
   129  
   130  // InvalidFileDiagnostics returns a new FileDiagnostics object for an invalid file
   131  func InvalidFileDiagnostics(filename string) *FileDiagnostics {
   132  	fileDiagnostics := &FileDiagnostics{
   133  		Filename:  filename,
   134  		Formatted: false,
   135  		Valid:     false,
   136  		Warnings:  []*warning{},
   137  	}
   138  	if filename == "" {
   139  		fileDiagnostics.Filename = "<stdin>"
   140  	}
   141  	return fileDiagnostics
   142  }
   143  
   144  func makePosition(p build.Position) position {
   145  	return position{
   146  		Line:   p.Line,
   147  		Column: p.LineRune,
   148  	}
   149  }
   150  

View as plain text