3 files changed,
69 insertions(+),
14 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-06-22 18:00:13 +0300
Authored at:
2026-06-20 15:31:36 +0300
Change ID:
lstrrlyqzqpuqqstmmnruyvwxulmnwkp
Parent:
470344c
M
internal/linter/rule_missing_commodity.go
··· 8 8 func (MissingCommodity) ID() RuleID { return "missing-commodity" } 9 9 func (MissingCommodity) Severity() Severity { return SeverityWarning } 10 10 func (m *MissingCommodity) CheckEntry(entry ast.Entry) []Find { 11 - txn, ok := entry.(*ast.Transaction) 12 - if !ok || (txn.Postings != nil && len(txn.Postings) == 0) { 13 - return nil 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) 14 28 } 29 + return finds 30 +} 15 31 16 - var finds []Find 17 - for _, posting := range txn.Postings { 32 +func (m *MissingCommodity) checkPostings(finds *[]Find, postings []*ast.Posting) { 33 + for _, posting := range postings { 18 34 if posting.Amount == nil { 19 35 continue 20 36 } 21 - if posting.Amount.Commodity == "" { 22 - finds = append(finds, Find{ 23 - Code: m.ID(), 24 - Severity: m.Severity(), 25 - Message: "amount missing commodity", 26 - Span: posting.Amount.Span, 27 - }) 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 + } 28 46 } 29 47 } 30 - return finds 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 + } 31 59 }
M
internal/linter/testdata/missing-commodity.golden
··· 1 1 missing-commodity.journal:2:21: missing-commodity: amount missing commodity 2 2 missing-commodity.journal:10:21: missing-commodity: amount missing commodity 3 +missing-commodity.journal:11:20: missing-commodity: amount missing commodity 4 +missing-commodity.journal:11:27: missing-commodity: amount missing commodity 5 +missing-commodity.journal:15:18: missing-commodity: amount missing commodity 6 +missing-commodity.journal:19:3: missing-commodity: amount missing commodity 7 +missing-commodity.journal:21:3: missing-commodity: amount missing commodity 8 +missing-commodity.journal:26:20: missing-commodity: amount missing commodity 9 +missing-commodity.journal:30:20: missing-commodity: amount missing commodity
M
internal/linter/testdata/missing-commodity.input
··· 7 7 assets:cash 8 8 9 9 2024-06-03 "another missing" 10 - expenses:food 100 10 + expenses:food 100 @ 1$ 11 + expenses:rent 1000 @ 1 12 + expenses:rent2 1000 USD @ 1 UAH 11 13 assets:cash 14 + 15 +P 2026-06-20 USD 2 16 +P 2026-06-20 USD 2 UAH 17 + 18 +D 100 USD 19 +D 100 20 + 21 +C 1 = 40 UAH 22 +C 1 USD = 40 UAH 23 + 24 +~ monthly 25 + expenses:rent $2000 26 + expenses:food 2000 27 + assets:bank 28 + 29 += /restaurant/ 30 + expenses:food 20.00 31 + assets:checking