all repos

clerk @ ba9be60442c067fdfb83f50a85a2f6d4cc6d3150

missing tooling for ledger/hledger
6 files changed, 52 insertions(+), 0 deletions(-)
linter: add undeclared-account
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-06-27 12:41:04 +0300
Authored at: 2026-06-26 16:06:43 +0300
Change ID: qunpkuystwsvknmvzkzttwoxnvkntlox
Parent: fd46af1
M internal/linter/linter_test.go
···
        20
        20
         	"orderdate":                {&OrderDate{}},

      
        21
        21
         	"duplicated-account":       {&DuplicatedAccount{}},

      
        22
        22
         	"duplicated-commodity":     {&DuplicatedCommodity{}},

      
        
        23
        +	"undeclared-account":       {&UndeclaredAccount{}},

      
        23
        24
         }

      
        24
        25
         

      
        25
        26
         func TestLinter(t *testing.T) {

      
A internal/linter/rule_undeclared_account.go
···
        
        1
        +package linter

      
        
        2
        +

      
        
        3
        +import "olexsmir.xyz/clerk/journal/ast"

      
        
        4
        +

      
        
        5
        +// UndeclaredAccount flags postings that reference an account not declared via `account` directive.

      
        
        6
        +type UndeclaredAccount struct{}

      
        
        7
        +

      
        
        8
        +func (UndeclaredAccount) ID() RuleID         { return "undeclared-account" }

      
        
        9
        +func (UndeclaredAccount) Severity() Severity { return SeverityWarning }

      
        
        10
        +func (r *UndeclaredAccount) CheckJournal(j *ast.Journal) []Find {

      
        
        11
        +	declared := make(map[string]bool)

      
        
        12
        +

      
        
        13
        +	var finds []Find

      
        
        14
        +	for _, entry := range j.Entries {

      
        
        15
        +		switch e := entry.(type) {

      
        
        16
        +		case *ast.AccountDirective:

      
        
        17
        +			declared[e.Account.String()] = true

      
        
        18
        +		case *ast.Transaction:

      
        
        19
        +			for _, p := range e.Postings {

      
        
        20
        +				name := p.Account.String()

      
        
        21
        +				if !declared[name] {

      
        
        22
        +					finds = append(finds, Find{

      
        
        23
        +						Code:     r.ID(),

      
        
        24
        +						Severity: r.Severity(),

      
        
        25
        +						Message:  "undeclared account: " + name,

      
        
        26
        +						Span:     p.Account.Span,

      
        
        27
        +					})

      
        
        28
        +				}

      
        
        29
        +			}

      
        
        30
        +		}

      
        
        31
        +	}

      
        
        32
        +

      
        
        33
        +	return finds

      
        
        34
        +}

      
M internal/linter/rules.go
···
        34
        34
         	&OrderDate{},

      
        35
        35
         	&DuplicatedAccount{},

      
        36
        36
         	&DuplicatedCommodity{},

      
        
        37
        +	&UndeclaredAccount{},

      
        37
        38
         }

      
M internal/linter/testdata/correct.input
···
        
        1
        +account expenses:food

      
        
        2
        +account assets:cash

      
        
        3
        +

      
        1
        4
         2024-05-01 * "groceries"

      
        2
        5
             expenses:food   50.00 USD

      
        3
        6
             assets:cash

      
A internal/linter/testdata/undeclared-account.golden
···
        
        1
        +undeclared-account.journal:5:3: undeclared-account: undeclared account: Assets:Cash

      
        
        2
        +undeclared-account.journal:9:3: undeclared-account: undeclared account: Assets:Cash

      
A internal/linter/testdata/undeclared-account.input
···
        
        1
        +account Expenses:Food

      
        
        2
        +

      
        
        3
        +2026-01-15 * "Lunch"

      
        
        4
        +  Expenses:Food      $10

      
        
        5
        +  Assets:Cash

      
        
        6
        +

      
        
        7
        +2026-01-16 * "Dinner"

      
        
        8
        +  Expenses:Food      $15

      
        
        9
        +  Assets:Cash

      
        
        10
        +

      
        
        11
        +account Assets:Cash