all repos

clerk @ a65ac055446d1d21fbdbbd2b848cf8d988403514

missing tooling for ledger/hledger
7 files changed, 88 insertions(+), 1 deletions(-)
journal/semantic: collect payees
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-06-27 17:53:43 +0300
Authored at: 2026-06-27 17:09:21 +0300
Change ID: yqkzquysxlutzszooxzwprkmxrtsqqsz
Parent: 5491069
M journal/semantic/build.go
···
        12
        12
         		Files:       files,

      
        13
        13
         		Accounts:    make(map[string]*AccountInfo),

      
        14
        14
         		Commodities: make(map[string]*CommodityInfo),

      
        
        15
        +		Payees:      make(map[string]*PayeeInfo),

      
        15
        16
         	}

      
        16
        17
         	for i, pf := range files {

      
        17
        18
         		for _, entry := range pf.Ast.Entries {

      ···
        20
        21
         				c.addAccountDirective(e)

      
        21
        22
         			case *ast.CommodityDirective:

      
        22
        23
         				c.addCommodityDirective(e)

      
        
        24
        +			case *ast.PayeeDirective:

      
        
        25
        +				c.addPayeeDirective(e)

      
        23
        26
         			case *ast.Transaction:

      
        24
        27
         				c.addPostings(i, e.Postings)

      
        
        28
        +				c.addPayee(i, e.Payee)

      
        25
        29
         			case *ast.PeriodicTransaction:

      
        26
        30
         				c.addPostings(i, e.Postings)

      
        27
        31
         			case *ast.AutomatedTransaction:

      ···
        40
        44
         		c.Accounts[aname] = info

      
        41
        45
         	}

      
        42
        46
         	info.Directives = append(info.Directives, ad)

      
        
        47
        +}

      
        
        48
        +

      
        
        49
        +func (c *Context) addPayeeDirective(pd *ast.PayeeDirective) {

      
        
        50
        +	info, ok := c.Payees[pd.Name]

      
        
        51
        +	if !ok {

      
        
        52
        +		info = &PayeeInfo{}

      
        
        53
        +		c.Payees[pd.Name] = info

      
        
        54
        +	}

      
        
        55
        +	info.Directives = append(info.Directives, &ast.Payee{

      
        
        56
        +		Name: pd.Name,

      
        
        57
        +		Span: pd.Span,

      
        
        58
        +	})

      
        43
        59
         }

      
        44
        60
         

      
        45
        61
         func (c *Context) addCommodityDirective(cd *ast.CommodityDirective) {

      ···
        49
        65
         		c.Commodities[cd.Commodity] = info

      
        50
        66
         	}

      
        51
        67
         	info.Directives = append(info.Directives, cd)

      
        
        68
        +}

      
        
        69
        +

      
        
        70
        +func (c *Context) addPayee(fileIndex int, payee *ast.Payee) {

      
        
        71
        +	if payee == nil {

      
        
        72
        +		return

      
        
        73
        +	}

      
        
        74
        +	info, ok := c.Payees[payee.Name]

      
        
        75
        +	if !ok {

      
        
        76
        +		info = &PayeeInfo{}

      
        
        77
        +		c.Payees[payee.Name] = info

      
        
        78
        +	}

      
        
        79
        +	info.Usage = append(info.Usage, PayeeUsage{

      
        
        80
        +		FileIndex: fileIndex,

      
        
        81
        +		Payee:     payee,

      
        
        82
        +	})

      
        52
        83
         }

      
        53
        84
         

      
        54
        85
         func (c *Context) addPostings(fileIndex int, postings []*ast.Posting) {

      
M journal/semantic/context.go
···
        12
        12
         

      
        13
        13
         	Accounts    map[string]*AccountInfo

      
        14
        14
         	Commodities map[string]*CommodityInfo

      
        
        15
        +	Payees      map[string]*PayeeInfo

      
        15
        16
         }

      
        16
        17
         

      
        17
        18
         type AccountInfo struct {

      ···
        39
        40
         	FileIndex int

      
        40
        41
         	Amount    *ast.Amount

      
        41
        42
         }

      
        
        43
        +

      
        
        44
        +type PayeeInfo struct {

      
        
        45
        +	Directives []*ast.Payee

      
        
        46
        +	Usage      []PayeeUsage

      
        
        47
        +}

      
        
        48
        +

      
        
        49
        +type PayeeUsage struct {

      
        
        50
        +	FileIndex int

      
        
        51
        +	Payee     *ast.Payee

      
        
        52
        +}

      
M journal/semantic/dump.go
···
        55
        55
         			fmt.Fprintf(w, "      file %d: %s\n", u.FileIndex, u.Posting.Account.String())

      
        56
        56
         		}

      
        57
        57
         	}

      
        
        58
        +

      
        
        59
        +	// Payees

      
        
        60
        +	pnames := make([]string, 0, len(ctx.Payees))

      
        
        61
        +	for name := range ctx.Payees {

      
        
        62
        +		pnames = append(pnames, name)

      
        
        63
        +	}

      
        
        64
        +	sort.Strings(pnames)

      
        
        65
        +

      
        
        66
        +	fmt.Fprintf(w, "\npayees (%d):\n", len(ctx.Payees))

      
        
        67
        +	for _, name := range pnames {

      
        
        68
        +		info := ctx.Payees[name]

      
        
        69
        +		fmt.Fprintf(w, "  %s\n", name)

      
        
        70
        +		fmt.Fprintf(w, "    directives: %d\n", len(info.Directives))

      
        
        71
        +		for _, d := range info.Directives {

      
        
        72
        +			fmt.Fprintf(w, "      payee %s\n", d.Name)

      
        
        73
        +		}

      
        
        74
        +		fmt.Fprintf(w, "    usages: %d\n", len(info.Usage))

      
        
        75
        +		for _, u := range info.Usage {

      
        
        76
        +			fmt.Fprintf(w, "      file %d: %s\n", u.FileIndex, u.Payee.Name)

      
        
        77
        +		}

      
        
        78
        +	}

      
        58
        79
         }

      
M journal/semantic/testdata/empty.golden
···
        3
        3
         commodities (0):

      
        4
        4
         

      
        5
        5
         accounts (0):

      
        
        6
        +

      
        
        7
        +payees (0):

      
M journal/semantic/testdata/include.golden
···
        18
        18
               account expenses:food

      
        19
        19
             usages: 1

      
        20
        20
               file 1: expenses:food

      
        
        21
        +

      
        
        22
        +payees (1):

      
        
        23
        +  test

      
        
        24
        +    directives: 0

      
        
        25
        +    usages: 1

      
        
        26
        +      file 1: test

      
M journal/semantic/testdata/include1.input
···
        1
        
        -2024/01/01 t

      
        
        1
        +include include0.journal

      
        
        2
        +

      
        
        3
        +2024/01/01 ! test

      
        2
        4
             expenses:food  $10

      
        3
        5
             assets:checking

      
M journal/semantic/testdata/journal.golden
···
        49
        49
               account expenses:transport

      
        50
        50
             usages: 1

      
        51
        51
               file 0: expenses:transport

      
        
        52
        +

      
        
        53
        +payees (3):

      
        
        54
        +  aws

      
        
        55
        +    directives: 0

      
        
        56
        +    usages: 1

      
        
        57
        +      file 0: aws

      
        
        58
        +  groceries

      
        
        59
        +    directives: 0

      
        
        60
        +    usages: 1

      
        
        61
        +      file 0: groceries

      
        
        62
        +  lunch

      
        
        63
        +    directives: 0

      
        
        64
        +    usages: 1

      
        
        65
        +      file 0: lunch