5 files changed,
78 insertions(+),
7 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-06-22 18:00:20 +0300
Authored at:
2026-06-20 17:43:03 +0300
Change ID:
wqlznlrlqxpvpprmmvkzrvppyormxzqu
Parent:
fbfbb0b
M
internal/linter/linter_test.go
··· 9 9 ) 10 10 11 11 var tests = map[string][]Rule{ 12 - "correct": Rules, 13 - "empty-postings": {&EmptyPostings{}}, 14 - "parse-error": {&ParseError{}}, 15 - "omitted-precision": {&OmittedPrecision{}}, 16 - "missing-commodity": {&MissingCommodity{}}, 17 - "missing-status": {&MissingStatus{}}, 18 - "account-depth": {&AccountDepthLimit{MaxDepth: 3}}, 12 + "correct": Rules, 13 + "empty-postings": {&EmptyPostings{}}, 14 + "parse-error": {&ParseError{}}, 15 + "omitted-precision": {&OmittedPrecision{}}, 16 + "missing-commodity": {&MissingCommodity{}}, 17 + "missing-status": {&MissingStatus{}}, 18 + "account-depth": {&AccountDepthLimit{MaxDepth: 3}}, 19 + "multiple-omitted-amounts": {&MultipleOmittedAmounts{}}, 19 20 } 20 21 21 22 func TestLinter(t *testing.T) {
A
internal/linter/rule_multiple_omitted_amounts.go
··· 1 +package linter 2 + 3 +import "olexsmir.xyz/clerk/journal/ast" 4 + 5 +// MultipleOmittedAmounts flags entries where more than one posting has an ommited amount. 6 +type MultipleOmittedAmounts struct{} 7 + 8 +func (MultipleOmittedAmounts) ID() RuleID { return "multiple-omitted-amounts" } 9 +func (MultipleOmittedAmounts) Severity() Severity { return SeverityError } 10 +func (m *MultipleOmittedAmounts) CheckEntry(entry ast.Entry) []Find { 11 + switch e := entry.(type) { 12 + case *ast.Transaction: 13 + return m.check(e.Postings) 14 + case *ast.PeriodicTransaction: 15 + return m.check(e.Postings) 16 + case *ast.AutomatedTransaction: 17 + return m.check(e.Postings) 18 + default: 19 + return nil 20 + } 21 +} 22 + 23 +func (m *MultipleOmittedAmounts) check(postings []*ast.Posting) []Find { 24 + var finds []Find 25 + for _, p := range postings { 26 + // skipping postings with balance assertion, since those are often used as reconciliation entries 27 + if p.Amount == nil && p.Balance == nil { 28 + finds = append(finds, Find{ 29 + Code: m.ID(), 30 + Severity: m.Severity(), 31 + Message: "more than one posting has omitted amount", 32 + Span: p.Span, 33 + }) 34 + } 35 + } 36 + if len(finds) > 1 { 37 + return finds 38 + } 39 + return nil 40 +}
A
internal/linter/testdata/multiple-omitted-amounts.golden
··· 1 +multiple-omitted-amounts.journal:2:1: multiple-omitted-amounts: more than one posting has omitted amount 2 +multiple-omitted-amounts.journal:3:1: multiple-omitted-amounts: more than one posting has omitted amount 3 +multiple-omitted-amounts.journal:7:1: multiple-omitted-amounts: more than one posting has omitted amount 4 +multiple-omitted-amounts.journal:8:1: multiple-omitted-amounts: more than one posting has omitted amount 5 +multiple-omitted-amounts.journal:9:1: multiple-omitted-amounts: more than one posting has omitted amount 6 +multiple-omitted-amounts.journal:11:1: multiple-omitted-amounts: more than one posting has omitted amount
A
internal/linter/testdata/multiple-omitted-amounts.input
··· 1 +2025-01-01 "two omitted amounts" 2 + Expenses:Food 3 + Expenses:Fun 4 + Assets:Cash 100 USD 5 + 6 +2025-01-02 "three omitted amounts" 7 + Expenses:Food 8 + Expenses:Fun 9 + Expenses:Play 10 + Assets:Cash 100 USD 11 + Equity:Opening-Balances 12 + 13 +2025-01-03 "one omitted amount (ok)" 14 + Expenses:Food 50 USD 15 + Assets:Cash 16 + 17 +2025-01-04 "all have amounts (ok)" 18 + Expenses:Food 50 USD 19 + Assets:Cash 50 USD 20 + 21 +2025-01-05 * reconcile or some s..stuff 22 + Assets:Bank = 1.69 UAH 23 + Assets:Cash = 2.00 UAH