all repos

clerk @ 8489d4c

missing tooling for ledger/hledger
2 files changed, 41 insertions(+), 18 deletions(-)
linter: report all output in one json array (for json output)
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-06-22 18:38:26 +0300
Authored at: 2026-06-20 18:29:03 +0300
Change ID: poxsprrrluypzqrvywywquullkxrkowp
Parent: 7638389
M internal/linter/report.go
···
        2
        2
         

      
        3
        3
         import (

      
        4
        4
         	"encoding/json"

      
        
        5
        +	"errors"

      
        5
        6
         	"fmt"

      
        6
        7
         	"io"

      
        7
        8
         	"os"

      ···
        50
        51
         		}

      
        51
        52
         	}

      
        52
        53
         	return json.NewEncoder(w).Encode(jsonFinds)

      
        
        54
        +}

      
        
        55
        +

      
        
        56
        +// Reporter collects lint findings across files and flushes them in the desired format.

      
        
        57
        +type Reporter struct {

      
        
        58
        +	w     io.Writer

      
        
        59
        +	finds []Find

      
        
        60
        +	style PathStyle

      
        
        61
        +}

      
        
        62
        +

      
        
        63
        +func NewReporter(w io.Writer, style PathStyle) *Reporter {

      
        
        64
        +	return &Reporter{w: w, style: style}

      
        
        65
        +}

      
        
        66
        +

      
        
        67
        +func (r *Reporter) Collect(finds []Find) {

      
        
        68
        +	r.finds = append(r.finds, finds...)

      
        
        69
        +}

      
        
        70
        +

      
        
        71
        +func (r *Reporter) Flush(format string) error {

      
        
        72
        +	switch format {

      
        
        73
        +	case "json":

      
        
        74
        +		return FprintJSON(r.w, r.style, r.finds)

      
        
        75
        +	case "text":

      
        
        76
        +		Fprint(r.w, r.style, r.finds)

      
        
        77
        +		return nil

      
        
        78
        +	default:

      
        
        79
        +		return errors.New("unsupported format")

      
        
        80
        +	}

      
        53
        81
         }

      
        54
        82
         

      
        55
        83
         func formatPath(style PathStyle, p string) string {

      
M lint.go
···
        24
        24
         

      
        25
        25
         	style := parsePathStyle(*pathStyle)

      
        26
        26
         	l := linter.NewLinter(linter.Rules)

      
        
        27
        +	reporter := linter.NewReporter(os.Stdout, style)

      
        27
        28
         	paths := fs.Args()

      
        28
        29
         

      
        29
        30
         	if len(paths) == 0 {

      
        30
        31
         		finds := lintStdin(l)

      
        31
        
        -		report(finds, *format, style)

      
        
        32
        +		reporter.Collect(finds)

      
        
        33
        +		reporter.Flush(*format)

      
        32
        34
         		if hasFatal(finds) {

      
        33
        35
         			os.Exit(1)

      
        34
        36
         		}

      ···
        48
        50
         				if err != nil || finfo.IsDir() || !journal.IsJournalFile(fpath) {

      
        49
        51
         					return nil

      
        50
        52
         				}

      
        51
        
        -				fatal := lintFileAndReport(l, fpath, *format, style)

      
        
        53
        +				finds, fatal := lintFile(l, fpath)

      
        
        54
        +				reporter.Collect(finds)

      
        52
        55
         				if fatal {

      
        53
        56
         					exitCode = 1

      
        54
        57
         				}

      ···
        56
        59
         			})

      
        57
        60
         			continue

      
        58
        61
         		}

      
        59
        
        -		if lintFileAndReport(l, path, *format, style) {

      
        
        62
        +		finds, fatal := lintFile(l, path)

      
        
        63
        +		reporter.Collect(finds)

      
        
        64
        +		if fatal {

      
        60
        65
         			exitCode = 1

      
        61
        66
         		}

      
        62
        67
         	}

      
        
        68
        +	reporter.Flush(*format)

      
        63
        69
         	os.Exit(exitCode)

      
        64
        70
         }

      
        65
        71
         

      
        66
        
        -// lintFileAndReport reads, lints, reports, and returns whether a fatal finding was found.

      
        67
        
        -func lintFileAndReport(l *linter.Linter, path, format string, style linter.PathStyle) bool {

      
        
        72
        +func lintFile(l *linter.Linter, path string) ([]linter.Find, bool) {

      
        68
        73
         	src, err := os.ReadFile(path)

      
        69
        74
         	if err != nil {

      
        70
        75
         		fmt.Fprintf(os.Stderr, "error: %s: %v\n", path, err)

      
        71
        
        -		return true

      
        
        76
        +		return nil, true

      
        72
        77
         	}

      
        73
        78
         	pf, err := journal.NewLoader().LoadBytes(path, src)

      
        74
        79
         	if err != nil {

      
        75
        80
         		fmt.Fprintf(os.Stderr, "error: %s: %v\n", path, err)

      
        76
        
        -		return true

      
        
        81
        +		return nil, true

      
        77
        82
         	}

      
        78
        83
         	finds := l.Run(pf.Ast)

      
        79
        
        -	report(finds, format, style)

      
        80
        
        -	return hasFatal(finds)

      
        
        84
        +	return finds, hasFatal(finds)

      
        81
        85
         }

      
        82
        86
         

      
        83
        87
         func lintStdin(l *linter.Linter) []linter.Find {

      ···
        92
        96
         		os.Exit(1)

      
        93
        97
         	}

      
        94
        98
         	return l.Run(pf.Ast)

      
        95
        
        -}

      
        96
        
        -

      
        97
        
        -func report(finds []linter.Find, format string, style linter.PathStyle) {

      
        98
        
        -	switch format {

      
        99
        
        -	case "json":

      
        100
        
        -		linter.FprintJSON(os.Stdout, style, finds)

      
        101
        
        -	default:

      
        102
        
        -		linter.Fprint(os.Stdout, style, finds)

      
        103
        
        -	}

      
        104
        99
         }

      
        105
        100
         

      
        106
        101
         func hasFatal(finds []linter.Find) bool {