all repos

clerk @ fd46af1

missing tooling for ledger/hledger

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

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
linter: improve missing commodity, 1 month ago
1
package linter
2
3
import "olexsmir.xyz/clerk/journal/ast"
4
5
// MissingCommodity flags amounts with a missing commodity.
6
type MissingCommodity struct{}
7
8
func (MissingCommodity) ID() RuleID         { return "missing-commodity" }
9
func (MissingCommodity) Severity() Severity { return SeverityWarning }
10
func (m *MissingCommodity) CheckEntry(entry ast.Entry) []Find {
11
	var finds []Find
12
	switch e := entry.(type) {
13
	case *ast.Transaction:
14
		m.checkPostings(&finds, e.Postings)
15
	case *ast.PeriodicTransaction:
16
		m.checkPostings(&finds, e.Postings)
17
	case *ast.AutomatedTransaction:
18
		m.checkPostings(&finds, e.Postings)
19
	case *ast.ConversionDirective:
20
		m.check(&finds, e.From)
21
		m.check(&finds, e.To)
22
	case *ast.CommodityDirective:
23
		m.check(&finds, e.Format)
24
	case *ast.DefaultCommodityDirective:
25
		m.check(&finds, e.Amount)
26
	case *ast.MarketPriceDirective:
27
		m.check(&finds, e.Amount)
28
	}
29
	return finds
30
}
31
32
func (m *MissingCommodity) checkPostings(finds *[]Find, postings []*ast.Posting) {
33
	for _, posting := range postings {
34
		if posting.Amount == nil {
35
			continue
36
		}
37
		m.check(finds, *posting.Amount)
38
		if posting.Cost != nil {
39
			m.check(finds, posting.Cost.Amount)
40
		}
41
		if posting.Balance != nil {
42
			m.check(finds, posting.Balance.Amount)
43
			if posting.Balance.Cost != nil {
44
				m.check(finds, posting.Balance.Cost.Amount)
45
			}
46
		}
47
	}
48
}
49
50
func (m *MissingCommodity) check(finds *[]Find, am ast.Amount) {
51
	if am.Commodity == "" {
52
		*finds = append(*finds, Find{
53
			Code:     m.ID(),
54
			Severity: m.Severity(),
55
			Message:  "amount missing commodity",
56
			Span:     am.Span,
57
		})
58
	}
59
}