all repos

clerk @ cf9c1d930d43e1c0015820114a18abaf71ae60f3

missing tooling for ledger/hledger
3 files changed, 36 insertions(+), 34 deletions(-)
analyzer: build payee templates lazily
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-09-02 18:22:35 +0300
Authored at: 2026-09-02 17:47:40 +0300
Change ID: wmwskmuqzkpotvvspszmytuwvsoymwyz
Parent: a2ef079
M internal/analyzer/analyzer.go
···
        20
        20
         	AccountAliases  map[string]string     // maps alias names to the account they resovle to

      
        21
        21
         	AliasDirectives []*ast.AliasDirective // holds every top-level "alias A = B" directive in entry order

      
        22
        22
         

      
        23
        
        -	AccountNames     []string                     // sorted for binary search

      
        24
        
        -	PayeeNames       []string                     // sorted, all payee names from directives + usage

      
        25
        
        -	PayeeTemplates   map[string][]PostingTemplate // holds the last transaction's postings per payee name

      
        26
        
        -	AccountsByPrefix map[string][]string          // "expenses:" -> ["expenses:food", "expenses:taxi"]

      
        
        23
        +	AccountNames     []string            // sorted for binary search

      
        
        24
        +	PayeeNames       []string            // sorted, all payee names from directives + usage

      
        
        25
        +	AccountsByPrefix map[string][]string // "expenses:" -> ["expenses:food", "expenses:taxi"]

      
        27
        26
         

      
        28
        27
         	Tags      map[string]*TagInfo

      
        29
        28
         	TagNames  []string // unique tag names, sorted

      
M internal/analyzer/analyzer_test.go
···
        227
        227
         	}

      
        228
        228
         

      
        229
        229
         	// payee templates

      
        230
        
        -	payeeNames := make([]string, 0, len(a.PayeeTemplates))

      
        231
        
        -	for name := range a.PayeeTemplates {

      
        
        230
        +	payeeTemplates := a.PayeeTemplates()

      
        
        231
        +	payeeNames := make([]string, 0, len(payeeTemplates))

      
        
        232
        +	for name := range payeeTemplates {

      
        232
        233
         		payeeNames = append(payeeNames, name)

      
        233
        234
         	}

      
        234
        235
         	sort.Strings(payeeNames)

      
        235
        
        -	fmt.Fprintf(w, "\npayee templates (%d):\n", len(a.PayeeTemplates))

      
        
        236
        +	fmt.Fprintf(w, "\npayee templates (%d):\n", len(payeeTemplates))

      
        236
        237
         	for _, name := range payeeNames {

      
        237
        
        -		templates := a.PayeeTemplates[name]

      
        
        238
        +		templates := payeeTemplates[name]

      
        238
        239
         		fmt.Fprintf(w, "  %s\n", name)

      
        239
        240
         		for _, t := range templates {

      
        240
        241
         			fmt.Fprintf(w, "    %s", t.Account)

      
M internal/analyzer/build.go
···
        23
        23
         		Payees:                  make(map[string]*PayeeInfo),

      
        24
        24
         		Tags:                    make(map[string]*TagInfo),

      
        25
        25
         		AccountsByPrefix:        make(map[string][]string),

      
        26
        
        -		PayeeTemplates:          make(map[string][]PostingTemplate),

      
        27
        26
         		TransactionsByKey:       make(map[string][]*ast.Transaction),

      
        28
        27
         		TransactionsCountByDate: make(map[string]int),

      
        29
        28
         	}

      ···
        57
        56
         	return b.String()

      
        58
        57
         }

      
        59
        58
         

      
        
        59
        +// PayeeTemplates returns  the last Transactions's postings per payee name.

      
        
        60
        +func (a *Analysis) PayeeTemplates() map[string][]PostingTemplate {

      
        
        61
        +	templates := make(map[string][]PostingTemplate)

      
        
        62
        +	for _, tx := range a.Transactions {

      
        
        63
        +		payee := ""

      
        
        64
        +		if tx.Payee != nil {

      
        
        65
        +			payee = tx.Payee.Name

      
        
        66
        +		}

      
        
        67
        +		if payee == "" {

      
        
        68
        +			continue

      
        
        69
        +		}

      
        
        70
        +

      
        
        71
        +		t := make([]PostingTemplate, len(tx.Postings))

      
        
        72
        +		for i, p := range tx.Postings {

      
        
        73
        +			t[i] = PostingTemplate{

      
        
        74
        +				Account:    p.Account.String(),

      
        
        75
        +				IsInferred: p.Amount == nil,

      
        
        76
        +			}

      
        
        77
        +			if p.Amount != nil {

      
        
        78
        +				t[i].Amount = p.Amount.Quantity.String()

      
        
        79
        +				t[i].Commodity = p.Amount.Commodity

      
        
        80
        +			}

      
        
        81
        +		}

      
        
        82
        +		templates[payee] = t

      
        
        83
        +	}

      
        
        84
        +	return templates

      
        
        85
        +}

      
        
        86
        +

      
        60
        87
         func (a *Analysis) addEntry(fileIndex int, entry ast.Entry) {

      
        61
        88
         	switch e := entry.(type) {

      
        62
        89
         	case *ast.AccountDirective:

      ···
        75
        102
         		a.Transactions = append(a.Transactions, e)

      
        76
        103
         		a.addPostings(fileIndex, e.Postings, &e.Date)

      
        77
        104
         		a.addPayee(fileIndex, e.Payee)

      
        78
        
        -		a.addPayeeTemplate(e)

      
        79
        105
         		a.addCommentTags(fileIndex, &e.Date, e.Comment)

      
        80
        106
         		for _, c := range e.HeaderComments {

      
        81
        107
         			a.addCommentTags(fileIndex, &e.Date, c)

      ···
        231
        257
         			a.addCommentTags(fileIndex, date, &posting.Comments[i])

      
        232
        258
         		}

      
        233
        259
         	}

      
        234
        
        -}

      
        235
        
        -

      
        236
        
        -func (a *Analysis) addPayeeTemplate(tx *ast.Transaction) {

      
        237
        
        -	payee := ""

      
        238
        
        -	if tx.Payee != nil {

      
        239
        
        -		payee = tx.Payee.Name

      
        240
        
        -	}

      
        241
        
        -	if payee == "" {

      
        242
        
        -		return

      
        243
        
        -	}

      
        244
        
        -

      
        245
        
        -	templates := make([]PostingTemplate, len(tx.Postings))

      
        246
        
        -	for i, p := range tx.Postings {

      
        247
        
        -		t := PostingTemplate{

      
        248
        
        -			Account:    p.Account.String(),

      
        249
        
        -			IsInferred: p.Amount == nil,

      
        250
        
        -		}

      
        251
        
        -		if p.Amount != nil {

      
        252
        
        -			t.Amount = p.Amount.Quantity.String()

      
        253
        
        -			t.Commodity = p.Amount.Commodity

      
        254
        
        -		}

      
        255
        
        -		templates[i] = t

      
        256
        
        -	}

      
        257
        
        -	a.PayeeTemplates[payee] = templates

      
        258
        260
         }

      
        259
        261
         

      
        260
        262
         func (a *Analysis) collectDates() {