blob: 1a50a64b3b85cd7c4c5daa1282256c8c4f0f2579 [file] [log] [blame] [edit]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ejson2csv
import (
"encoding/csv"
"encoding/json"
"io"
"strconv"
)
func must(err error) {
if err != nil {
panic(err)
}
}
// sliceOf converts string/int args into a 5-element slice of string,
// reusing the input slice (pointer) s.
func sliceOf(s *[]string, args ...any) []string {
*s = (*s)[:0]
for _, x := range args {
switch x := x.(type) {
case int:
*s = append(*s, strconv.FormatInt(int64(x), 10))
case string:
*s = append(*s, x)
}
}
for len(*s) < 5 {
*s = append(*s, "")
}
return *s
}
// Process converts JSON read from r into CSV written to w, filtered
// according to the various flags. The default is to include only
// diagnostic messages (all false), errors specifies errors,
// others specifies all lines that are neither error nor diagnostics,
// and all means all. One limits the output to the first line (error,
// diagnostic, or neither) from each module in the JSON stream.
func Process(r io.Reader, w io.Writer, errors, others, all, one bool) {
var stuff any
buf, err := io.ReadAll(r)
must(err)
err = json.Unmarshal(buf, &stuff)
must(err)
slice := stuff.([]any)
out := csv.NewWriter(w)
var line []string
line = sliceOf(&line, "ModulePath", "mpIndex", "Message/error", "meIndex", "Position")
out.Write(line)
outer:
for i, a := range slice {
ma := a.(map[string]any)
if s, ok := ma["Diagnostics"].([]any); ok {
// sawDiagnostic indicates non-empty error/message
// this should always be true here, but just in case, track it.
sawDiagnostic := false
for j, d := range s {
md := d.(map[string]any)
if m, ok := md["Error"].(string); ok && m != "" {
// error messages print if errors or all.
if errors || all {
out.Write(sliceOf(&line, ma["ModulePath"], i, m, j, md["Position"]))
if one {
continue outer
}
}
sawDiagnostic = true
}
if m, ok := md["Message"].(string); ok && m != "" {
// diagnostic messages print if present and either all or not-errors-and-not-others
if !errors && !others || all {
out.Write(sliceOf(&line, ma["ModulePath"], i, m, j, md["Position"]))
if one {
continue outer
}
}
sawDiagnostic = true
}
}
if sawDiagnostic {
continue outer
}
}
// Here if no diagnostic message or error lines were printed.
if others || all {
out.Write(sliceOf(&line, ma["ModulePath"], i))
}
}
out.Flush()
}