# `Beancount.Renderer`
[🔗](https://github.com/thanos/beancount_ex/blob/v0.6.0/lib/beancount/renderer.ex#L1)

Deterministic rendering of directive streams into Beancount text.

Rendering is intentionally pure and deterministic: rendering the same
directive stream twice always produces byte-identical output. This property
is essential for golden-file regression testing and for using Beancount as a
behavioral oracle.

The module also exposes the low-level formatting helpers
(`format_date/1`, `format_decimal/1`, `quote_string/1`, ...) used by the
individual `Beancount.Directive` implementations.

# `format_date`

```elixir
@spec format_date(Date.t()) :: binary()
```

Format a `Date` as an ISO-8601 `YYYY-MM-DD` string.

## Examples

    iex> Beancount.Renderer.format_date(~D[2026-01-31])
    "2026-01-31"

# `format_decimal`

```elixir
@spec format_decimal(Decimal.t()) :: binary()
```

Format a `Decimal` using plain (non-scientific) notation.

## Examples

    iex> Beancount.Renderer.format_decimal(Decimal.new("-5000"))
    "-5000"

    iex> Beancount.Renderer.format_decimal(Decimal.new("12.50"))
    "12.50"

# `format_value`

```elixir
@spec format_value(term()) :: binary()
```

Render a scalar value as used in metadata and `custom` directives.

- binaries become quoted strings
- `Decimal` and numbers become bare numbers
- `Date` becomes an ISO date
- booleans become `TRUE`/`FALSE`
- atoms become barewords (useful for accounts/currencies)
- `Beancount.Value.Account`, `Tag`, and `Amount` for custom directives

## Examples

    iex> Beancount.Renderer.format_value("hello") == Beancount.Renderer.quote_string("hello")
    true

    iex> Beancount.Renderer.format_value(Decimal.new("42"))
    "42"

    iex> Beancount.Renderer.format_value(~D[2026-01-01])
    "2026-01-01"

    iex> Beancount.Renderer.format_value(Beancount.account_value("Assets:Bank"))
    "Assets:Bank"

# `lines_to_fragment`

```elixir
@spec lines_to_fragment([binary()]) :: binary()
```

Join header text, metadata lines and body lines into a single fragment.

Used by directives that span multiple lines (such as transactions).

## Examples

    iex> Beancount.Renderer.lines_to_fragment(["header", "  posting"])
    "header\n  posting"

# `quote_string`

```elixir
@spec quote_string(binary()) :: binary()
```

Quote and escape a string the way Beancount expects.

## Examples

    iex> Beancount.Renderer.quote_string(~S(a "quoted" value))
    ~S("a \"quoted\" value")

# `render`

```elixir
@spec render([Beancount.Directive.t()]) :: binary()
```

Render a list of directives into a complete `.bean` document.

Directives are separated by a single blank line and the document ends with a
trailing newline.

## Examples

    iex> ledger = [
    ...>   Beancount.open(~D[2026-01-01], "Assets:Bank", ["USD"]),
    ...>   Beancount.close(~D[2026-12-31], "Assets:Bank")
    ...> ]
    iex> Beancount.Renderer.render(ledger)
    "2026-01-01 open Assets:Bank USD\n\n2026-12-31 close Assets:Bank\n"

# `render_metadata`

```elixir
@spec render_metadata(map(), non_neg_integer()) :: [binary()]
```

Render a metadata map into indented `key: value` lines.

Keys are emitted in deterministic (sorted) order. Returns an empty list when
there is no metadata.

## Examples

    iex> lines = Beancount.Renderer.render_metadata(%{"note" => "reviewed"})
    iex> hd(lines) =~ "note:"
    true

    iex> Beancount.Renderer.render_metadata(%{})
    []

# `render_postings`

```elixir
@spec render_postings([Beancount.Directives.Posting.t()]) :: [binary()]
```

Render the postings of a transaction as aligned, indented lines.

Amounts are right-aligned so that decimal values line up, matching the
conventional Beancount layout. Posting-level metadata is rendered indented
beneath its posting.

## Examples

    iex> postings = [
    ...>   Beancount.posting("Assets:Bank", Decimal.new("100"), "USD"),
    ...>   Beancount.posting("Income:Salary", Decimal.new("-100"), "USD")
    ...> ]
    iex> lines = Beancount.Renderer.render_postings(postings)
    iex> Enum.all?(lines, &String.starts_with?(&1, "  "))
    true

# `render_tags_and_links`

```elixir
@spec render_tags_and_links([binary()], [binary()]) :: binary()
```

Render `#tag` and `^link` suffixes for a transaction header.

Tags are rendered before links, each in sorted order for determinism.

## Examples

    iex> Beancount.Renderer.render_tags_and_links(["trip"], ["invoice-1"])
    " #trip ^invoice-1"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
