all repos

clerk @ 50bbb41fc735251033f1ce13bc2abca260d0e8ec

missing tooling for ledger/hledger

clerk/internal/linter/linter.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
implement basic linter, 1 month ago
1
package linter
2
3
import (
4
	"olexsmir.xyz/clerk/journal/ast"
5
	"olexsmir.xyz/clerk/journal/token"
6
)
7
8
// A Find represents a single lint finding.
9
type Find struct {
10
	Code     RuleID
11
	Severity Severity
12
	Message  string
13
	Span     token.Span
14
}
15
16
// Linter runs lint rules against a parsed journal.
17
type Linter struct {
18
	rules []Rule
19
}
20
21
// NewLinter creates a [Linter] with the given rules.
22
func NewLinter(rules []Rule) *Linter {
23
	return &Linter{rules: rules}
24
}
25
26
// Run runs all rules against the journal.
27
func (l *Linter) Run(j *ast.Journal) []Find {
28
	var finds []Find
29
30
	// single traversal
31
	for _, entry := range j.Entries {
32
		for _, rule := range l.rules {
33
			if ec, ok := rule.(EntryChecker); ok {
34
				finds = append(finds, ec.CheckEntry(entry)...)
35
			}
36
		}
37
	}
38
39
	// post-traversal
40
	for _, rule := range l.rules {
41
		if jc, ok := rule.(JournalChecker); ok {
42
			finds = append(finds, jc.CheckJournal(j)...)
43
		}
44
	}
45
46
	return finds
47
}
48
49
// Severity represents severity of the litning find.
50
type Severity int
51
52
const (
53
	SeverityError   Severity = 1
54
	SeverityWarning Severity = 2
55
	SeverityInfo    Severity = 3
56
	SeverityHint    Severity = 4
57
)
58
59
func (s Severity) String() string {
60
	switch s {
61
	case SeverityError:
62
		return "error"
63
	case SeverityWarning:
64
		return "warning"
65
	case SeverityInfo:
66
		return "info"
67
	case SeverityHint:
68
		return "hint"
69
	}
70
	panic("impossible severity state")
71
}