tomledit

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 9, 2026 License: MIT Imports: 12 Imported by: 0

README

go-toml-edit

Comment-preserving TOML editing for Go.

Why

Every Go TOML library either discards comments during parsing or provides read-only access to them. If you parse a config file, change one value, and write it back, the comments are gone. Python has tomlkit; Go had nothing. go-toml-edit fills this gap with a lossless AST that preserves every comment, blank line, and formatting detail through arbitrary edits.

Before / After

package main

import (
	"fmt"

	"github.com/smm-h/go-toml-edit"
)

func main() {
	doc, _ := tomledit.Parse([]byte(`# Server config
[server]
host = "localhost"  # primary host
port = 8080
`))

	doc.Set("server.port", 9090)
	fmt.Print(string(doc.Bytes()))
}

Output -- comments survive the edit:

# Server config
[server]
host = "localhost"  # primary host
port = 9090

Installation

go get github.com/smm-h/go-toml-edit

Feature Comparison

Feature go-toml-edit BurntSushi/toml pelletier/go-toml/v2
Comment preservation Yes No Read-only (unstable)
Round-trip editing Yes No No
Set/Delete/Rename API Yes No No
Unmarshal to struct Yes Yes Yes
Marshal from struct No (v2) Yes Yes
TOML 1.0 compliance Full Full Full
Formatter Yes No No
Document diffing Yes No No
Deep merge Yes No No

Quick Start

Parse and Read
doc, _ := tomledit.Parse([]byte(`[server]
host = "localhost"
port = 8080
`))
fmt.Println(doc.GetString("server.host")) // "localhost", true
fmt.Println(doc.GetInt("server.port"))    // 8080, true
Edit Values
doc.Set("server.port", 9090)              // update existing key
doc.SetCreate("database.host", "db.local") // create key + intermediate table
doc.Delete("server.debug")                 // remove a key
doc.Rename("server.host", "address")       // rename a key
Fluent Cursor
host, ok := doc.Key("database").Key("host").String()
port, ok := doc.Key("database").Key("port").Int()
Unmarshal
type Config struct {
	Title  string `toml:"title"`
	Server struct {
		Host string `toml:"host"`
		Port int    `toml:"port"`
	} `toml:"server"`
}
var cfg Config
tomledit.Unmarshal(data, &cfg)
Format
formatted := doc.Format(tomledit.WithIndentWidth(2))
Walk
doc.Walk(func(path string, node tomledit.Node) error {
	fmt.Printf("%s = %v\n", path, node.Value())
	return nil
}, tomledit.WalkLeaves)
Diff
changes := tomledit.Diff(a, b)
for _, c := range changes {
	fmt.Printf("%s: %s\n", c.Kind, c.Path)
}
// removed: age
// added: email
// modified: name
Merge
base, _ := tomledit.Parse([]byte(`[server]
host = "localhost"
`))
defaults, _ := tomledit.Parse([]byte(`[server]
host = "0.0.0.0"
port = 8080
`))
base.Merge(defaults)
// host keeps "localhost" (already set); port added from defaults.

Performance

go-toml-edit retains the full AST for comment-preserving round-trip editing, so it allocates more memory than decode-only libraries. Parse speed is competitive.

Benchmarks on a 13th-gen Intel i7-13620H (go test -bench .):

Benchmark go-toml-edit BurntSushi/toml
Parse (small) 15.7 us, 30.8 KB/op 17.9 us, 15.4 KB/op
Unmarshal (small) 23.9 us, 37.1 KB/op 21.8 us, 17.5 KB/op
Parse (large) 274 us, 595 KB/op 246 us, 171 KB/op

Higher memory usage reflects the full AST required for comment-preserving round-trip editing. A decode-only library can discard source positions, trivia tokens, and comment nodes that go-toml-edit must retain.

API Reference

pkg.go.dev/github.com/smm-h/go-toml-edit

Roadmap

Planned for v2: Marshal (struct to TOML), TOML 1.1, streaming parser. See todo/ for details.

License

MIT

Documentation

Overview

Package tomledit provides a comment-preserving TOML parser and editor.

It parses TOML documents into a lossless AST that preserves comments, whitespace, and formatting. Values can be read, set, deleted, and renamed without disturbing unrelated parts of the file. The AST can be serialized back to bytes with Bytes (round-trip fidelity) or reformatted with Format.

Key features:

  • Lossless round-trip: parse and re-serialize without losing comments or formatting
  • Path-based access: read and write values using dot-separated paths (e.g. "server.host")
  • Structural editing: create tables, array-of-tables, rename and delete keys
  • Diff and merge: compare two documents or merge defaults into an existing document
  • Walk: traverse all key-value pairs in document order
  • Unmarshal: decode TOML into Go structs and maps

Index

Examples

Constants

This section is empty.

Variables

View Source
var SkipTable = errors.New("skip table")

SkipTable is a sentinel error returned from a Walk visitor function to skip the current table's children (or inline table's children). Returning SkipTable on a scalar node is a no-op.

Functions

func Unmarshal

func Unmarshal(data []byte, v any) error

Unmarshal parses TOML data and decodes it into v.

v must be a non-nil pointer to a struct or map[string]any. Struct fields are matched by their "toml" tag, then by exact field name, then by case-insensitive name. Unknown TOML keys are silently ignored. Types implementing Unmarshaler or encoding.TextUnmarshaler are handled automatically.

Example
type Config struct {
	Title  string `toml:"title"`
	Server struct {
		Host string `toml:"host"`
		Port int    `toml:"port"`
	} `toml:"server"`
}
var cfg Config
err := tomledit.Unmarshal([]byte(`title = "My App"

[server]
host = "0.0.0.0"
port = 443
`), &cfg)
if err != nil {
	panic(err)
}
fmt.Println(cfg.Title)
fmt.Println(cfg.Server.Host)
fmt.Println(cfg.Server.Port)
Output:
My App
0.0.0.0
443

Types

type ArrayNode

type ArrayNode struct {
	Elements         []Node
	TrailingComments [][]byte // comments after the last element, before ']'
	// contains filtered or unexported fields
}

ArrayNode represents an array value.

func (*ArrayNode) Comment

func (n *ArrayNode) Comment() string

func (*ArrayNode) LeadingComments

func (n *ArrayNode) LeadingComments() []string

func (*ArrayNode) Raw

func (n *ArrayNode) Raw() []byte

func (*ArrayNode) SetComment

func (n *ArrayNode) SetComment(comment string)

func (*ArrayNode) SetLeadingComments

func (n *ArrayNode) SetLeadingComments(comments []string)

func (*ArrayNode) Type

func (n *ArrayNode) Type() NodeType

func (*ArrayNode) Value

func (n *ArrayNode) Value() any

type ArrayTableNode

type ArrayTableNode struct {
	KeyPath  []string
	Children []Node
	// contains filtered or unexported fields
}

ArrayTableNode represents an [[array-table]] header and its children.

func (*ArrayTableNode) Comment

func (n *ArrayTableNode) Comment() string

func (*ArrayTableNode) LeadingComments

func (n *ArrayTableNode) LeadingComments() []string

func (*ArrayTableNode) Raw

func (n *ArrayTableNode) Raw() []byte

func (*ArrayTableNode) SetComment

func (n *ArrayTableNode) SetComment(comment string)

func (*ArrayTableNode) SetLeadingComments

func (n *ArrayTableNode) SetLeadingComments(comments []string)

func (*ArrayTableNode) Type

func (n *ArrayTableNode) Type() NodeType

func (*ArrayTableNode) Value

func (n *ArrayTableNode) Value() any

type BooleanNode

type BooleanNode struct {
	Val bool
	// contains filtered or unexported fields
}

BooleanNode represents a boolean value.

func (*BooleanNode) Comment

func (n *BooleanNode) Comment() string

func (*BooleanNode) LeadingComments

func (n *BooleanNode) LeadingComments() []string

func (*BooleanNode) Raw

func (n *BooleanNode) Raw() []byte

func (*BooleanNode) SetComment

func (n *BooleanNode) SetComment(comment string)

func (*BooleanNode) SetLeadingComments

func (n *BooleanNode) SetLeadingComments(comments []string)

func (*BooleanNode) Type

func (n *BooleanNode) Type() NodeType

func (*BooleanNode) Value

func (n *BooleanNode) Value() any

type Change

type Change struct {
	Kind     ChangeKind
	Path     string
	OldValue any // nil for Added
	NewValue any // nil for Removed
}

Change represents a single difference between two documents. OldValue is nil for Added changes; NewValue is nil for Removed changes.

func Diff

func Diff(a, b *DocumentNode) []Change

Diff returns all differences between documents a and b.

It walks both documents to collect all leaf (scalar) values, then compares them. Container nodes (inline tables, arrays) are not compared directly; instead their individual elements are compared. Changes are sorted by path (alphabetical), then by kind (Removed, Modified, Added).

Example
a, _ := tomledit.Parse([]byte(`name = "Alice"
age = 30
`))
b, _ := tomledit.Parse([]byte(`name = "Bob"
email = "bob@example.com"
`))
changes := tomledit.Diff(a, b)
for _, c := range changes {
	fmt.Printf("%s: %s\n", c.Kind, c.Path)
}
Output:
removed: age
added: email
modified: name

type ChangeKind

type ChangeKind int

ChangeKind identifies the type of difference between two documents.

const (
	Added    ChangeKind = iota // Added means the key exists in b but not in a.
	Removed                    // Removed means the key exists in a but not in b.
	Modified                   // Modified means the key exists in both but with different values.
)

func (ChangeKind) String

func (k ChangeKind) String() string

String returns the human-readable name of the change kind.

type CommentNode

type CommentNode struct {
	Text string
	// contains filtered or unexported fields
}

CommentNode represents a standalone comment line.

func (*CommentNode) Comment

func (n *CommentNode) Comment() string

func (*CommentNode) LeadingComments

func (n *CommentNode) LeadingComments() []string

func (*CommentNode) Raw

func (n *CommentNode) Raw() []byte

func (*CommentNode) SetComment

func (n *CommentNode) SetComment(comment string)

func (*CommentNode) SetLeadingComments

func (n *CommentNode) SetLeadingComments(comments []string)

func (*CommentNode) Type

func (n *CommentNode) Type() NodeType

func (*CommentNode) Value

func (n *CommentNode) Value() any

type Cursor

type Cursor struct {
	// contains filtered or unexported fields
}

Cursor provides a fluent, nil-safe API for navigating a TOML document's AST. A Cursor is never nil. If navigation fails at any point, the cursor captures the error and all subsequent operations (Key, At, String, etc.) become no-ops that propagate the original error. Check Err after a chain of calls to see whether the traversal succeeded.

func (*Cursor) At

func (c *Cursor) At(index int) *Cursor

At navigates to an array index. Supports negative indices.

func (*Cursor) Bool

func (c *Cursor) Bool() (bool, bool)

Bool extracts a boolean value from the current node. Returns (false, false) if the cursor has an error or the node is not a boolean.

func (*Cursor) Err

func (c *Cursor) Err() error

Err returns the first error encountered during navigation.

func (*Cursor) Float

func (c *Cursor) Float() (float64, bool)

Float extracts a float64 value from the current node. Returns (0, false) if the cursor has an error or the node is not a float.

func (*Cursor) Int

func (c *Cursor) Int() (int64, bool)

Int extracts an integer value from the current node. Returns (0, false) if the cursor has an error or the node is not an integer.

func (*Cursor) Items

func (c *Cursor) Items() iter.Seq2[int, Node]

Items returns a range-over-func iterator over elements of the current node. Works with ArrayNode elements and array-of-tables entries. An inert cursor (with error) yields nothing.

func (*Cursor) Key

func (c *Cursor) Key(name string) *Cursor

Key navigates to a named child within the current scope.

func (*Cursor) Len

func (c *Cursor) Len() int

Len returns the number of elements at the current cursor position. Returns -1 if the cursor has an error or the node isn't an array/array-of-tables.

func (*Cursor) Node

func (c *Cursor) Node() Node

Node returns the current node, or nil if the cursor has an error.

func (*Cursor) String

func (c *Cursor) String() (string, bool)

String extracts a string value from the current node. Returns ("", false) if the cursor has an error or the node is not a string.

func (*Cursor) Time

func (c *Cursor) Time() (time.Time, bool)

Time extracts a time.Time value from the current node. Returns (time.Time{}, false) if the cursor has an error or the node is not an offset date-time.

type DateTimeNode

type DateTimeNode struct {
	Val time.Time
	// contains filtered or unexported fields
}

DateTimeNode represents an offset date-time value.

func (*DateTimeNode) Comment

func (n *DateTimeNode) Comment() string

func (*DateTimeNode) LeadingComments

func (n *DateTimeNode) LeadingComments() []string

func (*DateTimeNode) Raw

func (n *DateTimeNode) Raw() []byte

func (*DateTimeNode) SetComment

func (n *DateTimeNode) SetComment(comment string)

func (*DateTimeNode) SetLeadingComments

func (n *DateTimeNode) SetLeadingComments(comments []string)

func (*DateTimeNode) Type

func (n *DateTimeNode) Type() NodeType

func (*DateTimeNode) Value

func (n *DateTimeNode) Value() any

type DocumentNode

type DocumentNode struct {
	Children []Node
	// contains filtered or unexported fields
}

DocumentNode is the root node of a TOML document.

func Parse

func Parse(src []byte) (*DocumentNode, error)

Parse lexes and parses TOML source bytes into a DocumentNode AST.

The returned DocumentNode preserves all whitespace, comments, and formatting from the original source. Serializing it back with Bytes produces the exact original bytes (round-trip fidelity).

Returns a *ParseError on any lexing or parsing error, including duplicate key detection and invalid TOML syntax.

Example
doc, err := tomledit.Parse([]byte(`[server]
host = "localhost"
port = 8080
`))
if err != nil {
	panic(err)
}
fmt.Println(doc.GetString("server.host"))
fmt.Println(doc.GetInt("server.port"))
Output:
localhost true
8080 true

func (*DocumentNode) Bytes

func (d *DocumentNode) Bytes() []byte

Bytes serializes the document back to TOML bytes.

For clean documents (parsed and never modified), it returns the exact original source bytes (round-trip fidelity). For nodes that have been modified via Set, Delete, or other editing operations, only the affected nodes are re-rendered from their semantic values; unmodified nodes retain their original formatting.

func (*DocumentNode) Comment

func (n *DocumentNode) Comment() string

func (*DocumentNode) Decode

func (d *DocumentNode) Decode(v any) error

Decode decodes the document's content into v. v must be a non-nil pointer to a struct or map[string]any. Unlike Unmarshal, Decode operates on an already-parsed DocumentNode, which is useful when you need both the AST (for editing) and the decoded values.

func (*DocumentNode) Delete

func (d *DocumentNode) Delete(path string) error

Delete removes the node at the given path from the document. It handles key-value pairs, tables, array-of-tables, and array elements. Returns nil (no error) if the path does not exist, making it safe to call unconditionally.

Example
doc, err := tomledit.Parse([]byte(`[server]
host = "localhost"
port = 8080
debug = true
`))
if err != nil {
	panic(err)
}
err = doc.Delete("server.debug")
if err != nil {
	panic(err)
}
fmt.Println(doc.GetBool("server.debug"))
Output:
false false

func (*DocumentNode) Format

func (d *DocumentNode) Format(opts ...FormatOption) []byte

Format returns normalized TOML bytes. It does NOT mutate the document -- it produces a new byte slice by walking the AST and re-rendering every node with consistent formatting, ignoring all raw bytes. This is useful for enforcing a canonical style. Pass zero or more FormatOption values (e.g. WithIndentWidth, WithLineWidth) to customize the output.

Example
doc, err := tomledit.Parse([]byte(`name="Alice"
[server]
host="localhost"
port=8080
`))
if err != nil {
	panic(err)
}
formatted := doc.Format(tomledit.WithIndentWidth(2))
fmt.Print(string(formatted))
Output:
name = "Alice"

[server]
  host = "localhost"
  port = 8080

func (*DocumentNode) Get

func (d *DocumentNode) Get(path string) Node

Get resolves the dot-separated path against the document and returns the target node. For key-value pairs, the value node is returned (not the KeyValueNode wrapper). Returns nil if the path is syntactically invalid or the key is not found.

Path syntax uses dots to separate keys (e.g. "server.host"), brackets for array indices (e.g. "items[0]"), and supports negative indices (e.g. "items[-1]" for the last element). Use Resolve for the same operation with error details.

func (*DocumentNode) GetBool

func (d *DocumentNode) GetBool(path string) (bool, bool)

GetBool resolves the path and returns the boolean value. Returns (false, false) if the path is not found or the value is not a boolean.

func (*DocumentNode) GetFloat

func (d *DocumentNode) GetFloat(path string) (float64, bool)

GetFloat resolves the path and returns the float64 value. Returns (0, false) if the path is not found or the value is not a float.

func (*DocumentNode) GetInt

func (d *DocumentNode) GetInt(path string) (int64, bool)

GetInt resolves the path and returns the integer value. Returns (0, false) if the path is not found or the value is not an integer.

func (*DocumentNode) GetString

func (d *DocumentNode) GetString(path string) (string, bool)

GetString resolves the path and returns the string value. Returns ("", false) if the path is not found or the value is not a string.

func (*DocumentNode) GetTime

func (d *DocumentNode) GetTime(path string) (time.Time, bool)

GetTime resolves the path and returns a time.Time value. Returns (time.Time{}, false) if the path is not found or the value is not an offset date-time.

func (*DocumentNode) Items

func (d *DocumentNode) Items(path string) iter.Seq2[int, Node]

Items returns a range-over-func iterator over elements at the given path. Works with ArrayNode elements (inline arrays) and array-of-tables entries. Returns an empty iterator if the path is invalid, not found, or points to a non-array node. Use with a range loop:

for i, node := range doc.Items("servers") { ... }

func (*DocumentNode) Key

func (d *DocumentNode) Key(name string) *Cursor

Key returns a Cursor navigated to the named child of the document root. This is the entry point for the fluent cursor API. Chain additional Key or At calls to traverse deeper, then extract the value with String, Int, etc.

Example
doc, err := tomledit.Parse([]byte(`[database]
host = "localhost"
port = 5432
`))
if err != nil {
	panic(err)
}
host, ok := doc.Key("database").Key("host").String()
fmt.Println(host, ok)

port, ok := doc.Key("database").Key("port").Int()
fmt.Println(port, ok)
Output:
localhost true
5432 true

func (*DocumentNode) LeadingComments

func (n *DocumentNode) LeadingComments() []string

func (*DocumentNode) Len

func (d *DocumentNode) Len(path string) int

Len returns the number of elements at the path. Returns -1 if the path is invalid, does not exist, or does not point to an array or array-of-tables.

func (*DocumentNode) Merge

func (d *DocumentNode) Merge(other *DocumentNode) error

Merge merges all values from the other document into d. Same recursive semantics as MergeDefaults: only keys that do not exist in d are set; existing values are never overwritten.

Comment handling:

  • For existing keys: other's leading comments are appended to d's leading comments; if d has no inline comment and other does, it is copied.
  • For new keys: comments from other are brought along with the value.

Array-of-tables are treated atomically: if d already has entries for a given path, all of other's entries for that path are skipped.

Example
base, _ := tomledit.Parse([]byte(`[server]
host = "localhost"
`))
defaults, _ := tomledit.Parse([]byte(`[server]
host = "0.0.0.0"
port = 8080
`))
err := base.Merge(defaults)
if err != nil {
	panic(err)
}
// host was already set, so it keeps "localhost".
fmt.Println(base.GetString("server.host"))
// port was missing, so it was added from defaults.
fmt.Println(base.GetInt("server.port"))
Output:
localhost true
8080 true

func (*DocumentNode) MergeDefaults

func (d *DocumentNode) MergeDefaults(path string, defaults map[string]any) error

MergeDefaults recursively walks defaults and sets keys that do not exist in the document at the given path. If path is empty, merges at the document root.

Maps (map[string]any) merge recursively: only missing keys are set. Scalars and arrays are atomic: existing keys are never overwritten. This is useful for applying default configuration values to a user-provided TOML file.

func (*DocumentNode) NewArrayTable

func (d *DocumentNode) NewArrayTable(path string) error

NewArrayTable appends a new [[array-table]] entry at the given path. Multiple entries with the same path are valid in TOML and represent successive elements of the array. The path must consist of key segments only (no array indices).

func (*DocumentNode) NewTable

func (d *DocumentNode) NewTable(path string) error

NewTable creates a new [table] header at the given path and appends it to the document. The path must consist of key segments only (no array indices). Returns an error if a table with that exact path already exists.

func (*DocumentNode) Raw

func (n *DocumentNode) Raw() []byte

func (*DocumentNode) Rename

func (d *DocumentNode) Rename(path string, newKey string) error

Rename changes the key name of the node at the given path to newKey. Returns an error if the path does not exist, if newKey conflicts with an existing sibling key, or if the last path segment is an array index (only key segments can be renamed).

func (*DocumentNode) Resolve

func (d *DocumentNode) Resolve(path string) (Node, error)

Resolve resolves the dot-separated path against the document and returns the target node. Unlike Get, it returns descriptive errors for both path syntax errors and resolution failures, making it suitable for cases where the caller needs to distinguish "not found" from "invalid path".

func (*DocumentNode) Set

func (d *DocumentNode) Set(path string, value any) error

Set updates the value at the given path. If the final key does not exist in an existing parent, it is created as a new key-value pair. Returns an error if intermediate path segments do not exist.

Supported value types: string, bool, int/int8-64, uint/uint8-64, float32/64, time.Time, LocalDateTime, LocalDate, LocalTime, []any, map[string]any, and any type implementing the Node interface. Use SetCreate to auto-create intermediate tables.

Example
doc, err := tomledit.Parse([]byte(`[server]
host = "localhost"
port = 8080
`))
if err != nil {
	panic(err)
}
err = doc.Set("server.port", 9090)
if err != nil {
	panic(err)
}
fmt.Println(doc.GetInt("server.port"))
Output:
9090 true

func (*DocumentNode) SetComment

func (d *DocumentNode) SetComment(path string, comment string) error

SetComment sets the inline comment on the node at the given path. The comment string should NOT include the "# " prefix -- it will be added automatically. An empty string removes the comment. For table paths, the comment is set on the table header line. Returns an error if the path does not exist or targets a member of an inline table (TOML forbids comments inside inline tables).

func (*DocumentNode) SetCreate

func (d *DocumentNode) SetCreate(path string, value any) error

SetCreate is like Set but auto-creates intermediate [table] headers when they do not exist. Missing tables are appended to the document. This is convenient for inserting values into deeply nested paths that may not yet exist.

Example
doc, err := tomledit.Parse([]byte(`title = "example"
`))
if err != nil {
	panic(err)
}
// SetCreate auto-creates intermediate [database] table.
err = doc.SetCreate("database.host", "db.example.com")
if err != nil {
	panic(err)
}
fmt.Println(doc.GetString("database.host"))
Output:
db.example.com true

func (*DocumentNode) SetLeadingComments

func (d *DocumentNode) SetLeadingComments(path string, comments []string) error

SetLeadingComments sets the leading comment lines on the node at the given path. Each string should NOT include the "# " prefix -- it will be added automatically. For table paths, the comments are set on the table header. Returns an error if the path does not exist.

func (*DocumentNode) Type

func (n *DocumentNode) Type() NodeType

func (*DocumentNode) Value

func (n *DocumentNode) Value() any

func (*DocumentNode) Walk

func (d *DocumentNode) Walk(fn func(path string, node Node) error, mode WalkMode) error

Walk visits every key-value pair in the document in order, calling fn with the dot-path and the value node. Tables and array-of-tables are walked into (their children are visited), not yielded as standalone entries. Inline tables and arrays are yielded first, then their children are recursed into.

The mode parameter controls which nodes are visited:

  • WalkLeaves: only scalar values (containers are recursed but not yielded)
  • WalkAll: containers AND their children are yielded

The path uses dot-separated keys with bracket indices for array-of-tables entries (e.g. "servers[0].host"). Return SkipTable from fn to skip the children of the current inline table or array. Return any other non-nil error to stop the walk immediately.

Example
doc, err := tomledit.Parse([]byte(`name = "example"

[server]
host = "localhost"
port = 8080
`))
if err != nil {
	panic(err)
}
err = doc.Walk(func(path string, node tomledit.Node) error {
	fmt.Printf("%s = %v\n", path, node.Value())
	return nil
}, tomledit.WalkLeaves)
if err != nil {
	panic(err)
}
Output:
name = example
server.host = localhost
server.port = 8080

type FloatNode

type FloatNode struct {
	Val float64
	// contains filtered or unexported fields
}

FloatNode represents a float value.

func (*FloatNode) Comment

func (n *FloatNode) Comment() string

func (*FloatNode) LeadingComments

func (n *FloatNode) LeadingComments() []string

func (*FloatNode) Raw

func (n *FloatNode) Raw() []byte

func (*FloatNode) SetComment

func (n *FloatNode) SetComment(comment string)

func (*FloatNode) SetLeadingComments

func (n *FloatNode) SetLeadingComments(comments []string)

func (*FloatNode) Type

func (n *FloatNode) Type() NodeType

func (*FloatNode) Value

func (n *FloatNode) Value() any

type FormatConfig

type FormatConfig struct {
	IndentWidth    int  // spaces per indent level (default: 0, no indentation of values)
	LineWidth      int  // max line width before arrays go multi-line (default: 80)
	TableBlankLine bool // insert blank line before tables (default: true)
}

FormatConfig controls how the formatter normalizes TOML output. Use DefaultFormatConfig to get sensible defaults and WithIndentWidth, WithLineWidth, or WithTableBlankLine to override specific settings.

func DefaultFormatConfig

func DefaultFormatConfig() FormatConfig

DefaultFormatConfig returns a FormatConfig with sensible defaults.

type FormatOption

type FormatOption func(*FormatConfig)

FormatOption is a functional option for configuring the formatter.

func WithIndentWidth

func WithIndentWidth(n int) FormatOption

WithIndentWidth sets the number of spaces per indent level for values under table headers.

func WithLineWidth

func WithLineWidth(n int) FormatOption

WithLineWidth sets the maximum line width before arrays are rendered in multi-line format.

func WithTableBlankLine

func WithTableBlankLine(b bool) FormatOption

WithTableBlankLine controls whether a blank line is inserted before table headers.

type InlineTableNode

type InlineTableNode struct {
	Children []Node // KeyValueNode entries
	// contains filtered or unexported fields
}

InlineTableNode represents an inline table value.

func (*InlineTableNode) Comment

func (n *InlineTableNode) Comment() string

func (*InlineTableNode) LeadingComments

func (n *InlineTableNode) LeadingComments() []string

func (*InlineTableNode) Raw

func (n *InlineTableNode) Raw() []byte

func (*InlineTableNode) SetComment

func (n *InlineTableNode) SetComment(comment string)

func (*InlineTableNode) SetLeadingComments

func (n *InlineTableNode) SetLeadingComments(comments []string)

func (*InlineTableNode) Type

func (n *InlineTableNode) Type() NodeType

func (*InlineTableNode) Value

func (n *InlineTableNode) Value() any

type IntegerBase

type IntegerBase int

IntegerBase indicates the numeric base for an integer node.

const (
	IntegerDecimal IntegerBase = iota // IntegerDecimal is base-10 (e.g. 42).
	IntegerHex                        // IntegerHex is base-16 (e.g. 0xFF).
	IntegerOctal                      // IntegerOctal is base-8 (e.g. 0o77).
	IntegerBinary                     // IntegerBinary is base-2 (e.g. 0b1010).
)

type IntegerNode

type IntegerNode struct {
	Val  int64
	Base IntegerBase
	// contains filtered or unexported fields
}

IntegerNode represents an integer value.

func (*IntegerNode) Comment

func (n *IntegerNode) Comment() string

func (*IntegerNode) LeadingComments

func (n *IntegerNode) LeadingComments() []string

func (*IntegerNode) Raw

func (n *IntegerNode) Raw() []byte

func (*IntegerNode) SetComment

func (n *IntegerNode) SetComment(comment string)

func (*IntegerNode) SetLeadingComments

func (n *IntegerNode) SetLeadingComments(comments []string)

func (*IntegerNode) Type

func (n *IntegerNode) Type() NodeType

func (*IntegerNode) Value

func (n *IntegerNode) Value() any

type KeyNode

type KeyNode struct {
	Parts    []string      // semantic parts (e.g. ["server", "host"])
	RawParts [][]byte      // original bytes for each part
	Styles   []StringStyle // quoting style per part
	// contains filtered or unexported fields
}

KeyNode represents a (possibly dotted) key.

func (*KeyNode) Comment

func (n *KeyNode) Comment() string

func (*KeyNode) LeadingComments

func (n *KeyNode) LeadingComments() []string

func (*KeyNode) Raw

func (n *KeyNode) Raw() []byte

func (*KeyNode) SetComment

func (n *KeyNode) SetComment(comment string)

func (*KeyNode) SetLeadingComments

func (n *KeyNode) SetLeadingComments(comments []string)

func (*KeyNode) Type

func (n *KeyNode) Type() NodeType

func (*KeyNode) Value

func (n *KeyNode) Value() any

type KeyValueNode

type KeyValueNode struct {
	Key *KeyNode
	Val Node
	// contains filtered or unexported fields
}

KeyValueNode represents a key = value pair.

func (*KeyValueNode) Comment

func (n *KeyValueNode) Comment() string

func (*KeyValueNode) LeadingComments

func (n *KeyValueNode) LeadingComments() []string

func (*KeyValueNode) Raw

func (n *KeyValueNode) Raw() []byte

func (*KeyValueNode) SetComment

func (n *KeyValueNode) SetComment(comment string)

func (*KeyValueNode) SetLeadingComments

func (n *KeyValueNode) SetLeadingComments(comments []string)

func (*KeyValueNode) Type

func (n *KeyValueNode) Type() NodeType

func (*KeyValueNode) Value

func (n *KeyValueNode) Value() any

type LocalDate

type LocalDate struct {
	Year, Month, Day int
}

LocalDate represents a TOML local date.

type LocalDateNode

type LocalDateNode struct {
	Val LocalDate
	// contains filtered or unexported fields
}

LocalDateNode represents a local date value.

func (*LocalDateNode) Comment

func (n *LocalDateNode) Comment() string

func (*LocalDateNode) LeadingComments

func (n *LocalDateNode) LeadingComments() []string

func (*LocalDateNode) Raw

func (n *LocalDateNode) Raw() []byte

func (*LocalDateNode) SetComment

func (n *LocalDateNode) SetComment(comment string)

func (*LocalDateNode) SetLeadingComments

func (n *LocalDateNode) SetLeadingComments(comments []string)

func (*LocalDateNode) Type

func (n *LocalDateNode) Type() NodeType

func (*LocalDateNode) Value

func (n *LocalDateNode) Value() any

type LocalDateTime

type LocalDateTime struct {
	Year, Month, Day     int
	Hour, Minute, Second int
	Nanosecond           int
}

LocalDateTime represents a TOML local date-time (no timezone).

type LocalDateTimeNode

type LocalDateTimeNode struct {
	Val LocalDateTime
	// contains filtered or unexported fields
}

LocalDateTimeNode represents a local date-time value (no timezone).

func (*LocalDateTimeNode) Comment

func (n *LocalDateTimeNode) Comment() string

func (*LocalDateTimeNode) LeadingComments

func (n *LocalDateTimeNode) LeadingComments() []string

func (*LocalDateTimeNode) Raw

func (n *LocalDateTimeNode) Raw() []byte

func (*LocalDateTimeNode) SetComment

func (n *LocalDateTimeNode) SetComment(comment string)

func (*LocalDateTimeNode) SetLeadingComments

func (n *LocalDateTimeNode) SetLeadingComments(comments []string)

func (*LocalDateTimeNode) Type

func (n *LocalDateTimeNode) Type() NodeType

func (*LocalDateTimeNode) Value

func (n *LocalDateTimeNode) Value() any

type LocalTime

type LocalTime struct {
	Hour, Minute, Second int
	Nanosecond           int
}

LocalTime represents a TOML local time.

type LocalTimeNode

type LocalTimeNode struct {
	Val LocalTime
	// contains filtered or unexported fields
}

LocalTimeNode represents a local time value.

func (*LocalTimeNode) Comment

func (n *LocalTimeNode) Comment() string

func (*LocalTimeNode) LeadingComments

func (n *LocalTimeNode) LeadingComments() []string

func (*LocalTimeNode) Raw

func (n *LocalTimeNode) Raw() []byte

func (*LocalTimeNode) SetComment

func (n *LocalTimeNode) SetComment(comment string)

func (*LocalTimeNode) SetLeadingComments

func (n *LocalTimeNode) SetLeadingComments(comments []string)

func (*LocalTimeNode) Type

func (n *LocalTimeNode) Type() NodeType

func (*LocalTimeNode) Value

func (n *LocalTimeNode) Value() any

type Node

type Node interface {
	Type() NodeType
	Value() any
	Comment() string
	LeadingComments() []string
	Raw() []byte
	// contains filtered or unexported methods
}

Node is the interface implemented by all AST nodes. Every node carries its original raw bytes, trivia (whitespace and comments), and a semantic value accessible via Value. Implementation is restricted to this package.

type NodeType

type NodeType int

NodeType identifies the kind of AST node.

const (
	NodeDocument      NodeType = iota // NodeDocument is the root document node.
	NodeTable                         // NodeTable is a [table] header node.
	NodeArrayTable                    // NodeArrayTable is an [[array-table]] header node.
	NodeKeyValue                      // NodeKeyValue is a key = value pair.
	NodeKey                           // NodeKey is a (possibly dotted) key.
	NodeString                        // NodeString is a string value.
	NodeInteger                       // NodeInteger is an integer value.
	NodeFloat                         // NodeFloat is a float value.
	NodeBoolean                       // NodeBoolean is a boolean value.
	NodeDateTime                      // NodeDateTime is an offset date-time value.
	NodeLocalDateTime                 // NodeLocalDateTime is a local date-time value (no timezone).
	NodeLocalDate                     // NodeLocalDate is a local date value.
	NodeLocalTime                     // NodeLocalTime is a local time value.
	NodeArray                         // NodeArray is an array value.
	NodeInlineTable                   // NodeInlineTable is an inline table value.
	NodeComment                       // NodeComment is a standalone comment line.
)

func (NodeType) String

func (n NodeType) String() string

String returns the human-readable name of the node type.

type ParseError

type ParseError struct {
	Line    int
	Column  int
	Offset  int
	Snippet string
	Message string
}

ParseError represents a lexing or parsing error with position information. Line and Column are 1-based. Snippet may contain a fragment of the source near the error for diagnostic purposes.

func (*ParseError) Error

func (e *ParseError) Error() string

type StringNode

type StringNode struct {
	Val   string
	Style StringStyle
	// contains filtered or unexported fields
}

StringNode represents a string value.

func (*StringNode) Comment

func (n *StringNode) Comment() string

func (*StringNode) LeadingComments

func (n *StringNode) LeadingComments() []string

func (*StringNode) Raw

func (n *StringNode) Raw() []byte

func (*StringNode) SetComment

func (n *StringNode) SetComment(comment string)

func (*StringNode) SetLeadingComments

func (n *StringNode) SetLeadingComments(comments []string)

func (*StringNode) Type

func (n *StringNode) Type() NodeType

func (*StringNode) Value

func (n *StringNode) Value() any

type StringStyle

type StringStyle int

StringStyle indicates the quoting style for a string node.

const (
	StringBasic            StringStyle = iota // StringBasic is a double-quoted string ("...").
	StringLiteral                             // StringLiteral is a single-quoted string ('...').
	StringMultiLineBasic                      // StringMultiLineBasic is a triple-double-quoted string ("""...""").
	StringMultiLineLiteral                    // StringMultiLineLiteral is a triple-single-quoted string (”'...”').
)

type TableNode

type TableNode struct {
	KeyPath  []string
	Children []Node
	// contains filtered or unexported fields
}

TableNode represents a [table] header and its children.

func (*TableNode) Comment

func (n *TableNode) Comment() string

func (*TableNode) LeadingComments

func (n *TableNode) LeadingComments() []string

func (*TableNode) Raw

func (n *TableNode) Raw() []byte

func (*TableNode) SetComment

func (n *TableNode) SetComment(comment string)

func (*TableNode) SetLeadingComments

func (n *TableNode) SetLeadingComments(comments []string)

func (*TableNode) Type

func (n *TableNode) Type() NodeType

func (*TableNode) Value

func (n *TableNode) Value() any

type Token

type Token struct {
	Type   TokenType
	Raw    []byte // exact bytes from source
	Line   int    // 1-based
	Column int    // 1-based
}

Token represents a single lexical token from TOML source.

type TokenType

type TokenType int

TokenType identifies the kind of lexical token.

const (
	TokenBareKey                TokenType = iota // TokenBareKey is an unquoted key (e.g. host).
	TokenBasicString                             // TokenBasicString is a double-quoted string ("...").
	TokenLiteralString                           // TokenLiteralString is a single-quoted string ('...').
	TokenMultiLineBasicString                    // TokenMultiLineBasicString is a triple-double-quoted string.
	TokenMultiLineLiteralString                  // TokenMultiLineLiteralString is a triple-single-quoted string.
	TokenInteger                                 // TokenInteger is an integer literal.
	TokenFloat                                   // TokenFloat is a float literal.
	TokenBoolean                                 // TokenBoolean is true or false.
	TokenOffsetDateTime                          // TokenOffsetDateTime is a date-time with timezone offset.
	TokenLocalDateTime                           // TokenLocalDateTime is a local date-time (no timezone).
	TokenLocalDate                               // TokenLocalDate is a local date (YYYY-MM-DD).
	TokenLocalTime                               // TokenLocalTime is a local time (HH:MM:SS).
	TokenEquals                                  // TokenEquals is the = sign.
	TokenDot                                     // TokenDot is the . separator in dotted keys.
	TokenComma                                   // TokenComma is a , separator.
	TokenLeftBracket                             // TokenLeftBracket is [.
	TokenRightBracket                            // TokenRightBracket is ].
	TokenDoubleLeftBracket                       // TokenDoubleLeftBracket is [[.
	TokenDoubleRightBracket                      // TokenDoubleRightBracket is ]].
	TokenLeftBrace                               // TokenLeftBrace is {.
	TokenRightBrace                              // TokenRightBrace is }.
	TokenComment                                 // TokenComment is a # comment.
	TokenWhitespace                              // TokenWhitespace is spaces or tabs.
	TokenNewline                                 // TokenNewline is a line break.
	TokenEOF                                     // TokenEOF marks end of input.
)

func (TokenType) String

func (t TokenType) String() string

String returns the human-readable name of the token type.

type Trivia

type Trivia struct {
	LeadingWhitespace []byte
	LeadingComments   [][]byte // each is a full "# ...\n" line
	InlineComment     []byte   // "# ..." after value on same line
	TrailingNewline   []byte
}

Trivia holds formatting and comment data attached to a node.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalTOML(node Node) error
}

Unmarshaler is implemented by types that can unmarshal themselves from a TOML Node. The node passed to UnmarshalTOML is the raw AST node (e.g. a StringNode, IntegerNode, or TableNode), allowing custom decoding logic.

type WalkMode added in v0.1.1

type WalkMode int

WalkMode controls which nodes the Walk visitor function is called for.

const (
	// WalkLeaves visits only scalar (leaf) values. Container nodes
	// (InlineTableNode, ArrayNode) are not passed to fn, but their
	// children are still recursed into.
	WalkLeaves WalkMode = iota

	// WalkAll visits containers (inline tables, arrays) AND their children.
	// The visitor is called for every node.
	WalkAll
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL