toml

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: May 3, 2026 License: MIT Imports: 17 Imported by: 0

README

go-rotini/toml

A Go TOML encoding and decoding package that implements the TOML 1.1.0 specification backed by the TOML Test Suite conformance tests.

This package is used as the default TOML support package for rotini.

Features

  • Full TOML 1.1.0 specification support including Unicode bare keys, \e/\xHH escapes, inline table newlines, and trailing commas
  • Tested against the official TOML Test Suite for conformance
  • Generic UnmarshalTo[T] API and type-safe custom marshaler/unmarshaler registration
  • Multi-document streaming with Encoder/Decoder
  • Struct field tags: omitempty, inline, multiline, literal, commented, hex/octal/binary, required, default=<value>
  • Encode options: indent, indent tables, inline tables, multiline arrays, literal strings, table separators, comments
  • Decode options: strict mode, ordered maps, struct validation, local time zone, JSON unmarshaler fallback
  • AST access via Parse, Walk, Filter, and Node tree manipulation
  • JSONPath-like query engine (PathString) with read, replace, append, and delete operations
  • Bidirectional JSON conversion (ToJSON/FromJSON)
  • Valid function for quick syntax validation without full decoding
  • FormatError for human-readable error output with source line and column pointer
  • Context-aware encoding/decoding via EncodeContext/DecodeContext
  • Local date/time types: LocalDate, LocalTime, LocalDateTime
  • Deferred decoding with RawValue and file decoding with DecodeFile
  • DoS protection: depth limiting, key count limiting, document size limiting, node count limiting

Installation

go get github.com/go-rotini/toml

Requires Go 1.26 or later.

Quick Start

package main

import (
	"fmt"
	"log"

	"github.com/go-rotini/toml"
)

type Config struct {
	Title    string   `toml:"title"`
	Owner    Owner    `toml:"owner"`
	Database Database `toml:"database"`
}

type Owner struct {
	Name string `toml:"name"`
}

type Database struct {
	Ports   []int `toml:"ports"`
	Enabled bool  `toml:"enabled"`
	ConnMax int   `toml:"connection_max"`
}

func main() {
	// Marshal
	cfg := Config{
		Title: "Example",
		Owner: Owner{Name: "Alice"},
		Database: Database{
			Ports:   []int{8000, 8001, 8002},
			Enabled: true,
			ConnMax: 5000,
		},
	}
	b, err := toml.Marshal(cfg)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(b))

	// Unmarshal
	var cfg2 Config
	if err := toml.Unmarshal(b, &cfg2); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", cfg2)

	// Generic unmarshal (no pointer required)
	cfg3, err := toml.UnmarshalTo[Config](b)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", cfg3)
}

Documentation

Full API reference is available on pkg.go.dev.

Contributing

See CONTRIBUTING.md for guidelines on how to contribute to this project.

Code of Conduct

This project follows a code of conduct to ensure a welcoming community. See CODE_OF_CONDUCT.md.

Security

To report a vulnerability, see SECURITY.md.

License

This project is licensed under the MIT License. See LICENSE for details.

Documentation

Overview

Package toml implements TOML 1.1.0 encoding and decoding.

The API follows the conventions of encoding/json: use Marshal and Unmarshal for one-shot conversions, Encoder and Decoder for streaming, and struct field tags to control mapping between TOML keys and Go fields.

For low-level AST access, Parse returns a File containing a Node tree that can be inspected, mutated with Path queries, and re-serialized with NodeToBytes.

Struct Tags

Struct fields may be annotated with "toml" tags:

type Config struct {
    Name    string `toml:"name"`
    Count   int    `toml:"count,omitempty"`
    Ignored string `toml:"-"`
}

The tag format is "keyname,opts" where opts is a comma-separated list of:

  • omitempty: omit the field if it has its zero value
  • omitzero: omit the field if it has its zero value (explicit alias)
  • inline: encode the struct or map as an inline table
  • multiline: encode strings as multi-line basic strings
  • literal: encode strings as literal (single-quoted) strings
  • commented: encode the field as a commented-out line
  • hex: encode integers in hexadecimal (0x) format
  • octal: encode integers in octal (0o) format
  • binary: encode integers in binary (0b) format
  • required: return an error during decoding if the key is absent
  • default=<value>: set field to <value> during decoding if the key is absent (requires WithDefaults; scalar types only)

A tag of "-" excludes the field from encoding and decoding.

Custom Marshalers

Types can implement Marshaler, BytesMarshaler, MarshalerContext, Unmarshaler, BytesUnmarshaler, or UnmarshalerContext for custom serialization logic.

Error Handling

Decoding errors are returned as typed values that support errors.Is:

if errors.Is(err, toml.ErrSyntax) { ... }
if errors.Is(err, toml.ErrDuplicateKey) { ... }

Use FormatError to produce a human-readable error with a source pointer.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrSyntax indicates malformed TOML input.
	ErrSyntax = &SyntaxError{}
	// ErrType indicates one or more TOML values could not be assigned to the target Go types.
	ErrType = &TypeError{}
	// ErrUnknownField indicates a TOML key has no corresponding struct field (with [WithStrict]).
	ErrUnknownField = &UnknownFieldError{}
	// ErrDuplicateKey indicates a TOML key was defined more than once within a table.
	ErrDuplicateKey = &DuplicateKeyError{}
	// ErrValidation indicates a [StructValidator] rejected a decoded struct.
	ErrValidation = &ValidationError{}
	// ErrDefault indicates a default struct tag value could not be applied.
	ErrDefault = &DefaultError{}
	// ErrOverflow indicates a TOML integer overflows the target Go type.
	ErrOverflow = &OverflowError{}
	// ErrInlineTable indicates an inline table was modified after its initial definition.
	ErrInlineTable = &InlineTableError{}
	// ErrConflict indicates a key conflicts with an existing definition.
	ErrConflict = &ConflictError{}

	// ErrPathSyntax indicates an invalid [Path] expression.
	ErrPathSyntax = errors.New("toml: invalid path syntax")
	// ErrPathNotFound indicates no node matched a [Path] query.
	ErrPathNotFound = errors.New("toml: path not found")
	// ErrNilPointer indicates a nil pointer was passed where a non-nil pointer is required.
	ErrNilPointer = errors.New("toml: non-nil pointer required")
	// ErrDocumentSize indicates the input exceeds the configured [WithMaxDocumentSize] limit.
	ErrDocumentSize = errors.New("toml: document size exceeds limit")
	// ErrMarshalTop indicates the top-level value passed to [Marshal] is not a struct or map.
	ErrMarshalTop = errors.New("toml: top-level value must be a table (struct or map)")
)

Sentinel errors for use with errors.Is.

Functions

func DecodeFile

func DecodeFile(path string, v any, opts ...DecodeOption) error

DecodeFile reads and decodes the TOML file at path into v.

Example
package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/go-rotini/toml"
)

func main() {
	// Create a temporary TOML file for demonstration.
	dir, err := os.MkdirTemp("", "toml-example")
	if err != nil {
		panic(err)
	}
	defer os.RemoveAll(dir)

	path := filepath.Join(dir, "config.toml")
	if err := os.WriteFile(path, []byte("name = \"from-file\"\n"), 0644); err != nil {
		panic(err)
	}

	type Config struct {
		Name string `toml:"name"`
	}
	var cfg Config
	if err := toml.DecodeFile(path, &cfg); err != nil {
		panic(err)
	}
	fmt.Println(cfg.Name)
}
Output:
from-file

func FormatError

func FormatError(data []byte, err error, color ...bool) string

FormatError returns a human-readable string for errors that carry a Position (such as SyntaxError, DuplicateKeyError, OverflowError, InlineTableError, ConflictError, or ValidationError). The output includes the offending source line and a column pointer. For other error types it returns err.Error(). Set color to true to include ANSI color escape sequences.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	input := []byte("key =\nother = 1")
	var m map[string]any
	err := toml.Unmarshal(input, &m)
	if err != nil {
		formatted := toml.FormatError(input, err)
		fmt.Print(formatted)
	}
}
Output:
toml: line 1, column 6: unexpected token NEWLINE in value
  key =
       ^

func FromJSON

func FromJSON(jsonData []byte) ([]byte, error)

FromJSON converts JSON data to TOML.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	tomlOut, err := toml.FromJSON([]byte(`{"name":"bob","score":99}`))
	if err != nil {
		panic(err)
	}
	fmt.Print(string(tomlOut))
}
Output:
name = "bob"
score = 99

func Marshal

func Marshal(v any) ([]byte, error)

Marshal encodes v as TOML. The top-level value must be a struct or map.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	type Server struct {
		Host string `toml:"host"`
		Port int    `toml:"port"`
	}
	type Config struct {
		Title  string `toml:"title"`
		Server Server `toml:"server"`
	}
	out, err := toml.Marshal(Config{
		Title:  "My App",
		Server: Server{Host: "localhost", Port: 8080},
	})
	if err != nil {
		panic(err)
	}
	fmt.Print(string(out))
}
Output:
title = "My App"

[server]
host = "localhost"
port = 8080

func MarshalWithOptions

func MarshalWithOptions(v any, opts ...EncodeOption) ([]byte, error)

MarshalWithOptions encodes v as TOML with the given options.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	type Config struct {
		Name  string `toml:"name"`
		Debug bool   `toml:"debug"`
		Port  int    `toml:"port"`
	}
	out, err := toml.MarshalWithOptions(
		Config{Name: "app", Port: 3000},
		toml.WithOmitEmpty(true),
	)
	if err != nil {
		panic(err)
	}
	fmt.Print(string(out))
}
Output:
name = "app"
port = 3000

func NodeToBytes

func NodeToBytes(n *Node) ([]byte, error)

NodeToBytes serializes a Node tree back into TOML bytes using default encoding options.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	file, err := toml.Parse([]byte(`name = "roundtrip"
value = 100
`))
	if err != nil {
		panic(err)
	}
	out, err := toml.NodeToBytes(file.Root)
	if err != nil {
		panic(err)
	}
	fmt.Print(string(out))
}
Output:
name = "roundtrip"
value = 100

func NodeToBytesWithOptions

func NodeToBytesWithOptions(n *Node, opts ...EncodeOption) ([]byte, error)

NodeToBytesWithOptions serializes a Node tree back into TOML bytes using the provided encoding options.

func ToJSON

func ToJSON(tomlData []byte) ([]byte, error)

ToJSON converts TOML data to JSON.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	jsonOut, err := toml.ToJSON([]byte(`name = "alice"
age = 30
`))
	if err != nil {
		panic(err)
	}
	fmt.Println(string(jsonOut))
}
Output:
{"age":30,"name":"alice"}

func Unmarshal

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

Unmarshal decodes TOML data into v. The top-level value in v must be a pointer to a struct or map.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	input := []byte(`
title = "TOML Example"

[server]
host = "localhost"
port = 8080
`)
	type Server struct {
		Host string `toml:"host"`
		Port int    `toml:"port"`
	}
	type Config struct {
		Title  string `toml:"title"`
		Server Server `toml:"server"`
	}

	var cfg Config
	if err := toml.Unmarshal(input, &cfg); err != nil {
		panic(err)
	}
	fmt.Printf("title=%s host=%s port=%d\n", cfg.Title, cfg.Server.Host, cfg.Server.Port)
}
Output:
title=TOML Example host=localhost port=8080

func UnmarshalTo

func UnmarshalTo[T any](data []byte, opts ...DecodeOption) (T, error)

UnmarshalTo decodes TOML data into a new value of type T.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	type Config struct {
		Name    string `toml:"name"`
		Version int    `toml:"version"`
	}
	cfg, err := toml.UnmarshalTo[Config]([]byte(`
name = "myapp"
version = 2
`))
	if err != nil {
		panic(err)
	}
	fmt.Printf("%s v%d\n", cfg.Name, cfg.Version)
}
Output:
myapp v2

func UnmarshalWithOptions

func UnmarshalWithOptions(data []byte, v any, opts ...DecodeOption) error

UnmarshalWithOptions decodes TOML data into v with the given options.

Example (Defaults)
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	type Config struct {
		Host string `toml:"host,default=localhost"`
		Port int    `toml:"port,default=8080"`
	}
	var cfg Config
	if err := toml.UnmarshalWithOptions([]byte(""), &cfg, toml.WithDefaults()); err != nil {
		panic(err)
	}
	fmt.Printf("host=%s port=%d\n", cfg.Host, cfg.Port)
}
Output:
host=localhost port=8080
Example (Strict)
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	type Config struct {
		Name string `toml:"name"`
	}
	err := toml.UnmarshalWithOptions(
		[]byte("name = \"test\"\nunknown = true\n"),
		&Config{},
		toml.WithStrict(),
	)
	fmt.Println(err)
}
Output:
toml: line 2: unknown field "unknown"

func Valid

func Valid(data []byte) bool

Valid reports whether data is valid TOML.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	fmt.Println(toml.Valid([]byte(`key = "value"`)))
	fmt.Println(toml.Valid([]byte(`key = `)))
}
Output:
true
false

func Walk

func Walk(n *Node, fn WalkFunc)

Walk traverses the AST rooted at n in depth-first pre-order, calling fn for each node. If fn returns false, the node's children are not visited.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/go-rotini/toml"
)

func main() {
	file, err := toml.Parse([]byte(`
name = "test"
version = 1

[server]
host = "0.0.0.0"
`))
	if err != nil {
		panic(err)
	}
	toml.Walk(file.Root, func(n *toml.Node) bool {
		if n.Kind == toml.KeyValueNode {
			fmt.Println(strings.Join(n.Key, "."))
		}
		return true
	})
}
Output:
name
version
host

Types

type BytesMarshaler

type BytesMarshaler interface {
	MarshalTOML() ([]byte, error)
}

BytesMarshaler is implemented by types that can encode themselves directly into raw TOML bytes.

type BytesUnmarshaler

type BytesUnmarshaler interface {
	UnmarshalTOML(data []byte) error
}

BytesUnmarshaler is implemented by types that can decode themselves directly from raw TOML bytes.

type Comment

type Comment struct {
	Position CommentPosition
	Text     string
}

Comment attaches a comment to a TOML node identified by key path when encoding with WithComment.

type CommentPosition

type CommentPosition int

CommentPosition specifies where a Comment appears relative to its node.

const (
	HeadCommentPos CommentPosition = iota // before the node
	LineCommentPos                        // on the same line, after the value
	FootCommentPos                        // after the node
)

type ConflictError

type ConflictError struct {
	Key     string
	Message string
	Pos     Position
}

ConflictError is returned when a key conflicts with an existing definition, such as defining a key as both a table and an array of tables.

func (*ConflictError) Error

func (e *ConflictError) Error() string

func (*ConflictError) Is

func (e *ConflictError) Is(target error) bool

type DecodeOption

type DecodeOption func(*decoderOptions)

DecodeOption configures the behavior of Unmarshal, UnmarshalWithOptions, and Decoder.

func WithCustomUnmarshaler

func WithCustomUnmarshaler[T any](fn func(*T, []byte) error) DecodeOption

WithCustomUnmarshaler registers a function that decodes TOML bytes into a value of type T, overriding the default decoding for that type.

func WithDefaults

func WithDefaults() DecodeOption

WithDefaults enables applying default values from struct tags when a TOML key is absent from the input. Default values are specified with the "default=<value>" tag option (e.g. `toml:"port,default=8080"`). Only scalar types are supported: string, bool, int/uint variants, float variants, and time.Duration. Without this option, default tags are ignored.

func WithJSONUnmarshaler

func WithJSONUnmarshaler() DecodeOption

WithJSONUnmarshaler causes the decoder to try a type's UnmarshalJSON method if no TOML-specific unmarshaler is found.

func WithLocalTimeZone

func WithLocalTimeZone(loc *time.Location) DecodeOption

WithLocalTimeZone sets the time.Location used when decoding local date-time values into time.Time. Default is time.Local.

func WithMaxDepth

func WithMaxDepth(n int) DecodeOption

WithMaxDepth limits the nesting depth of the decoded value (default 100). Deeply nested documents are rejected with a SyntaxError.

func WithMaxDocumentSize

func WithMaxDocumentSize(n int) DecodeOption

WithMaxDocumentSize rejects input that exceeds n bytes before parsing begins.

func WithMaxKeys

func WithMaxKeys(n int) DecodeOption

WithMaxKeys limits the total number of keys the parser may encounter. Zero means no limit.

func WithMaxNodes

func WithMaxNodes(n int) DecodeOption

WithMaxNodes limits the total number of AST nodes the parser may create. Zero means no limit.

func WithOrderedMap

func WithOrderedMap() DecodeOption

WithOrderedMap causes decoding into any (interface{}) to produce MapSlice values for tables instead of map[string]any, preserving key order.

func WithStrict

func WithStrict() DecodeOption

WithStrict causes decoding to return an UnknownFieldError if a TOML key does not correspond to any field in the target struct.

func WithValidator

func WithValidator(v StructValidator) DecodeOption

WithValidator registers a StructValidator that is called after each struct is fully decoded.

type Decoder

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

Decoder reads TOML values from an input stream. Since TOML does not support multi-document streams, the first call to Decoder.Decode reads the entire input; subsequent calls return io.EOF.

func NewDecoder

func NewDecoder(r io.Reader, opts ...DecodeOption) *Decoder

NewDecoder creates a new Decoder that reads from r.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/go-rotini/toml"
)

func main() {
	input := strings.NewReader(`name = "decoded"
value = 42
`)
	type Config struct {
		Name  string `toml:"name"`
		Value int    `toml:"value"`
	}
	var cfg Config
	dec := toml.NewDecoder(input)
	if err := dec.Decode(&cfg); err != nil {
		panic(err)
	}
	fmt.Printf("%s: %d\n", cfg.Name, cfg.Value)
}
Output:
decoded: 42

func (*Decoder) Decode

func (dec *Decoder) Decode(v any) error

Decode reads the TOML input and decodes it into v.

func (*Decoder) DecodeContext

func (dec *Decoder) DecodeContext(ctx context.Context, v any) error

DecodeContext reads the TOML input and decodes it into v with context.

func (*Decoder) SetContext

func (dec *Decoder) SetContext(ctx context.Context)

SetContext sets the context for subsequent Decode calls.

type DefaultError

type DefaultError struct {
	Field   string
	Message string
	Pos     Position
}

DefaultError is returned when a default value from a struct tag cannot be applied.

func (*DefaultError) Error

func (e *DefaultError) Error() string

func (*DefaultError) Is

func (e *DefaultError) Is(target error) bool

type DuplicateKeyError

type DuplicateKeyError struct {
	Key string
	Pos Position
}

DuplicateKeyError is returned when a TOML key is defined more than once. TOML requires unique keys within a table; this error is always active.

func (*DuplicateKeyError) Error

func (e *DuplicateKeyError) Error() string

func (*DuplicateKeyError) Is

func (e *DuplicateKeyError) Is(target error) bool

type EncodeOption

type EncodeOption func(*encoderOptions)

EncodeOption configures the behavior of Marshal, MarshalWithOptions, and Encoder.

func WithArrayMultiline

func WithArrayMultiline(b bool) EncodeOption

WithArrayMultiline encodes all arrays in multiline format (one element per line).

func WithBasicStrings

func WithBasicStrings(b bool) EncodeOption

WithBasicStrings forces all string values to use basic (double-quoted) strings instead of the encoder's default choice. This overrides the per-field literal tag.

func WithComment

func WithComment(comments map[string][]Comment) EncodeOption

WithComment attaches comments to nodes by dot-path key (e.g. "server.port"). Each key maps to a slice of Comment values specifying position and text.

func WithCustomMarshaler

func WithCustomMarshaler[T any](fn func(T) ([]byte, error)) EncodeOption

WithCustomMarshaler registers a function that encodes values of type T to TOML bytes, overriding the default encoding for that type.

func WithIndent

func WithIndent(n int) EncodeOption

WithIndent sets the number of spaces per indentation level (default 0). TOML convention uses no indentation, but some users prefer indented sub-tables.

func WithIndentTables

func WithIndentTables(b bool) EncodeOption

WithIndentTables indents key/value pairs within sub-tables relative to their table header.

func WithInlineTable

func WithInlineTable(b bool) EncodeOption

WithInlineTable encodes all nested tables as inline tables ({...}).

func WithLiteralString

func WithLiteralString(b bool) EncodeOption

WithLiteralString prefers literal strings (single-quoted) when the value contains no characters that would require a basic string.

func WithMultiLineString

func WithMultiLineString(b bool) EncodeOption

WithMultiLineString encodes strings containing newlines as multi-line basic strings (triple-quoted).

func WithOmitEmpty

func WithOmitEmpty(b bool) EncodeOption

WithOmitEmpty omits struct fields and map entries whose values are zero/empty, equivalent to adding ",omitempty" to every field tag.

func WithTableSeparator

func WithTableSeparator(b bool) EncodeOption

WithTableSeparator controls whether a blank line is emitted between top-level tables for readability (default true).

type Encoder

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

Encoder writes TOML values to an output stream.

func NewEncoder

func NewEncoder(w io.Writer, opts ...EncodeOption) *Encoder

NewEncoder creates a new Encoder that writes to w.

Example
package main

import (
	"bytes"
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	type Config struct {
		Name string `toml:"name"`
		Port int    `toml:"port"`
	}
	var buf bytes.Buffer
	enc := toml.NewEncoder(&buf)
	if err := enc.Encode(Config{Name: "app", Port: 9090}); err != nil {
		panic(err)
	}
	fmt.Print(buf.String())
}
Output:
name = "app"
port = 9090

func (*Encoder) Close

func (enc *Encoder) Close() error

Close flushes any buffered data. For TOML, this is a no-op since each Encode call writes completely.

func (*Encoder) Encode

func (enc *Encoder) Encode(v any) error

Encode encodes v as TOML and writes it to the underlying writer.

func (*Encoder) EncodeContext

func (enc *Encoder) EncodeContext(ctx context.Context, v any) error

EncodeContext encodes v as TOML with the given context.

func (*Encoder) SetContext

func (enc *Encoder) SetContext(ctx context.Context)

SetContext sets the context for subsequent Encode calls.

type File

type File struct {
	Root     *Node
	Warnings []string
}

File is the result of parsing a TOML byte stream.

func Parse

func Parse(data []byte) (*File, error)

Parse tokenizes and parses data into an AST.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	file, err := toml.Parse([]byte(`
title = "Example"

[database]
port = 5432
`))
	if err != nil {
		panic(err)
	}
	fmt.Printf("root kind: TableNode=%v\n", file.Root.Kind == toml.TableNode)
	fmt.Printf("children: %d\n", len(file.Root.Children))
}
Output:
root kind: TableNode=true
children: 2

type InlineTableError

type InlineTableError struct {
	Table string
	Pos   Position
}

InlineTableError is returned when an inline table is modified after its initial definition.

func (*InlineTableError) Error

func (e *InlineTableError) Error() string

func (*InlineTableError) Is

func (e *InlineTableError) Is(target error) bool

type LocalDate

type LocalDate struct {
	Year  int
	Month time.Month
	Day   int
}

LocalDate represents a date without a timezone, as specified in TOML's local date type (e.g., 1979-05-27). Go's time.Time always carries timezone information, so this type preserves TOML's semantics.

Example
package main

import (
	"fmt"
	"time"

	"github.com/go-rotini/toml"
)

func main() {
	d := toml.LocalDate{Year: 2024, Month: time.March, Day: 15}
	fmt.Println(d.String())

	t := d.AsTime(time.UTC)
	fmt.Println(t.Format("2006-01-02"))
}
Output:
2024-03-15
2024-03-15

func (LocalDate) AsTime

func (d LocalDate) AsTime(loc *time.Location) time.Time

AsTime converts the local date to a time.Time in the given location.

func (LocalDate) MarshalText

func (d LocalDate) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (LocalDate) String

func (d LocalDate) String() string

String returns the date in RFC 3339 full-date format (YYYY-MM-DD).

func (*LocalDate) UnmarshalText

func (d *LocalDate) UnmarshalText(data []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

type LocalDateTime

type LocalDateTime struct {
	LocalDate
	LocalTime
}

LocalDateTime represents a date and time without a timezone, as specified in TOML's local date-time type (e.g., 1979-05-27T07:32:00).

Example
package main

import (
	"fmt"
	"time"

	"github.com/go-rotini/toml"
)

func main() {
	dt := toml.LocalDateTime{
		LocalDate: toml.LocalDate{Year: 2024, Month: time.March, Day: 15},
		LocalTime: toml.LocalTime{Hour: 14, Minute: 30, Second: 0},
	}
	fmt.Println(dt.String())

	t := dt.AsTime(time.UTC)
	fmt.Println(t.Format(time.RFC3339))
}
Output:
2024-03-15T14:30:00
2024-03-15T14:30:00Z

func (LocalDateTime) AsTime

func (dt LocalDateTime) AsTime(loc *time.Location) time.Time

AsTime converts the local date-time to a time.Time in the given location.

func (LocalDateTime) MarshalText

func (dt LocalDateTime) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (LocalDateTime) String

func (dt LocalDateTime) String() string

String returns the date-time in RFC 3339 format without a timezone offset (YYYY-MM-DDTHH:MM:SS).

func (*LocalDateTime) UnmarshalText

func (dt *LocalDateTime) UnmarshalText(data []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

type LocalTime

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

LocalTime represents a time of day without a date or timezone, as specified in TOML's local time type (e.g., 07:32:00).

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	t := toml.LocalTime{Hour: 14, Minute: 30, Second: 0}
	fmt.Println(t.String())
}
Output:
14:30:00

func (LocalTime) MarshalText

func (t LocalTime) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (LocalTime) String

func (t LocalTime) String() string

String returns the time in HH:MM:SS format, with fractional seconds appended if non-zero.

func (*LocalTime) UnmarshalText

func (t *LocalTime) UnmarshalText(data []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

type MapItem

type MapItem struct {
	Key   any
	Value any
}

MapItem is a single key-value pair within a MapSlice.

type MapSlice

type MapSlice []MapItem

MapSlice is an ordered slice of key-value pairs. It is used as the decoded representation of TOML tables when WithOrderedMap is enabled, preserving the original key order that a plain map[string]any would lose.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	ms := toml.MapSlice{
		{Key: "first", Value: 1},
		{Key: "second", Value: 2},
		{Key: "third", Value: 3},
	}
	for _, item := range ms {
		fmt.Printf("%s=%v\n", item.Key, item.Value)
	}
}
Output:
first=1
second=2
third=3

type Marshaler

type Marshaler interface {
	MarshalTOML() (any, error)
}

Marshaler is implemented by types that can encode themselves into a TOML-compatible Go value. The returned value is then encoded normally.

type MarshalerContext

type MarshalerContext interface {
	MarshalTOML(ctx context.Context) (any, error)
}

MarshalerContext is like Marshaler but receives a context.

type Node

type Node struct {
	Kind        NodeKind
	Key         []string    // key path segments for KeyValueNode/TableNode/ArrayTableNode
	Value       string      // raw string representation of the value (for scalar nodes)
	Style       StringStyle // for StringNode: which string style was used
	Inline      bool        // for tables: inline table format ({...})
	Children    []*Node     // child nodes
	Pos         Position
	Comment     string // line comment (after value on same line)
	HeadComment string // comment block before this node
	FootComment string // comment block after this node
}

Node is a TOML AST node.

func Filter

func Filter(n *Node, fn func(*Node) bool) []*Node

Filter walks the AST rooted at n and returns all nodes for which fn returns true.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	file, err := toml.Parse([]byte(`
name = "test"
count = 42
active = true
`))
	if err != nil {
		panic(err)
	}
	strings := toml.Filter(file.Root, func(n *toml.Node) bool {
		return n.Kind == toml.StringNode
	})
	for _, n := range strings {
		fmt.Println(n.Value)
	}
}
Output:
test

func (*Node) String

func (n *Node) String() string

String returns the dotted key path for table/key-value nodes, or the value for scalar nodes.

func (*Node) Validate

func (n *Node) Validate() error

Validate checks structural invariants of the node tree: key uniqueness, table/array-of-table conflicts, inline table immutability. Returns nil if the tree is valid.

type NodeKind

type NodeKind int

NodeKind identifies the type of a TOML Node in the AST.

const (
	TableNode         NodeKind = iota // a TOML table ([table])
	ArrayTableNode                    // an array of tables ([[array]])
	KeyValueNode                      // a key/value pair
	ArrayNode                         // an array value
	InlineTableNode                   // an inline table ({...})
	StringNode                        // a string scalar
	IntegerNode                       // an integer scalar
	FloatNode                         // a float scalar
	BooleanNode                       // a boolean scalar
	DateTimeNode                      // an offset date-time
	LocalDateTimeNode                 // a local date-time
	LocalDateNode                     // a local date
	LocalTimeNode                     // a local time
	CommentNode                       // a comment
)

type OverflowError

type OverflowError struct {
	Value string
	Type  string
	Pos   Position
}

OverflowError is returned when a TOML integer overflows the target Go type.

func (*OverflowError) Error

func (e *OverflowError) Error() string

func (*OverflowError) Is

func (e *OverflowError) Is(target error) bool

type Path

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

Path represents a compiled path expression for querying TOML AST nodes.

func PathString

func PathString(expr string) (*Path, error)

PathString compiles a path expression string into a Path.

Syntax:

  • $.key — root child access
  • $.parent.child — nested key access
  • $.array[0] — array index access
  • $.array[-1] — negative index (from end)
  • $.table.* — wildcard (all children)
  • $..key — recursive descent
Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	file, err := toml.Parse([]byte(`
[server]
host = "example.com"
port = 443
`))
	if err != nil {
		panic(err)
	}
	path, err := toml.PathString("$.server.host")
	if err != nil {
		panic(err)
	}
	val, err := path.ReadString(file.Root)
	if err != nil {
		panic(err)
	}
	fmt.Println(val)
}
Output:
example.com

func (*Path) Append

func (p *Path) Append(n, value *Node) error

Append adds a child node to the first matching node.

func (*Path) Delete

func (p *Path) Delete(n *Node) error

Delete removes the first matching node.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	file, err := toml.Parse([]byte(`name = "keep"
remove_me = true
`))
	if err != nil {
		panic(err)
	}
	path, err := toml.PathString("$.remove_me")
	if err != nil {
		panic(err)
	}
	if err := path.Delete(file.Root); err != nil {
		panic(err)
	}
	out, err := toml.NodeToBytes(file.Root)
	if err != nil {
		panic(err)
	}
	fmt.Print(string(out))
}
Output:
name = "keep"

func (*Path) Read

func (p *Path) Read(n *Node) ([]*Node, error)

Read returns all nodes matching the path expression.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	file, err := toml.Parse([]byte(`
[server]
host = "example.com"
port = 443
`))
	if err != nil {
		panic(err)
	}
	path, err := toml.PathString("$.server")
	if err != nil {
		panic(err)
	}
	nodes, err := path.Read(file.Root)
	if err != nil {
		panic(err)
	}
	fmt.Printf("found %d node(s), kind=TableNode: %v\n", len(nodes), nodes[0].Kind == toml.TableNode)
}
Output:
found 1 node(s), kind=TableNode: true

func (*Path) ReadPositions

func (p *Path) ReadPositions(n *Node) ([]Position, error)

ReadPositions returns the positions of all matching nodes.

func (*Path) ReadString

func (p *Path) ReadString(n *Node) (string, error)

ReadString reads a single scalar node matching the path and returns its value.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	file, err := toml.Parse([]byte(`title = "Hello"
`))
	if err != nil {
		panic(err)
	}
	path, err := toml.PathString("$.title")
	if err != nil {
		panic(err)
	}
	val, err := path.ReadString(file.Root)
	if err != nil {
		panic(err)
	}
	fmt.Println(val)
}
Output:
Hello

func (*Path) Replace

func (p *Path) Replace(n, replacement *Node) error

Replace replaces the first matching node with the given replacement.

func (*Path) String

func (p *Path) String() string

String returns the original path expression.

type Position

type Position struct {
	Line   int
	Column int
	Offset int
}

Position identifies a location within TOML source text.

func (Position) String

func (p Position) String() string

String returns the position formatted as "line:column".

type RawValue

type RawValue []byte

RawValue is raw TOML that has not been decoded. It can be used to delay decoding or to pass through a TOML value without interpreting it.

Example
package main

import (
	"fmt"

	"github.com/go-rotini/toml"
)

func main() {
	raw := toml.RawValue([]byte(`"hello world"`))
	var s struct {
		Raw string `toml:"_raw_"`
	}
	if err := raw.Unmarshal(&s); err != nil {
		panic(err)
	}
	fmt.Println(s.Raw)
}
Output:
hello world

func (RawValue) Unmarshal

func (r RawValue) Unmarshal(v any) error

Unmarshal decodes the raw TOML value into v.

type StringStyle

type StringStyle int

StringStyle indicates how a string was (or should be) represented in TOML.

const (
	BasicStyle            StringStyle = iota // double-quoted ("...")
	MultiLineBasicStyle                      // triple double-quoted ("""...""")
	LiteralStyle                             // single-quoted ('...')
	MultiLineLiteralStyle                    // triple single-quoted (”'...”')
)

type StructValidator

type StructValidator interface {
	Struct(v any) error
}

StructValidator validates a struct after all fields have been decoded. Implement this interface to integrate with validation libraries.

type SyntaxError

type SyntaxError struct {
	Message string
	Pos     Position
	Token   string
}

SyntaxError is returned when the TOML input is malformed. Use errors.Is(err, ErrSyntax) to test for syntax errors generically.

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

func (*SyntaxError) Is

func (e *SyntaxError) Is(target error) bool

type TypeError

type TypeError struct {
	Errors []string
}

TypeError is returned when one or more TOML values cannot be assigned to the target Go types. Errors contains a message for each failed conversion.

func (*TypeError) Error

func (e *TypeError) Error() string

func (*TypeError) Is

func (e *TypeError) Is(target error) bool

type UnknownFieldError

type UnknownFieldError struct {
	Field string
	Pos   Position
}

UnknownFieldError is returned when decoding with WithStrict and a TOML key has no corresponding struct field.

func (*UnknownFieldError) Error

func (e *UnknownFieldError) Error() string

func (*UnknownFieldError) Is

func (e *UnknownFieldError) Is(target error) bool

type Unmarshaler

type Unmarshaler interface {
	UnmarshalTOML(unmarshal func(any) error) error
}

Unmarshaler is implemented by types that control their own TOML decoding. The unmarshal function decodes the TOML value into the provided Go value, similar to Unmarshal.

type UnmarshalerContext

type UnmarshalerContext interface {
	UnmarshalTOML(ctx context.Context, unmarshal func(any) error) error
}

UnmarshalerContext is like Unmarshaler but receives a context.

type ValidationError

type ValidationError struct {
	Err error
	Pos Position
}

ValidationError wraps an error returned by a StructValidator with the Position of the TOML node that was decoded into the struct.

func (*ValidationError) Error

func (e *ValidationError) Error() string

func (*ValidationError) Is

func (e *ValidationError) Is(target error) bool

func (*ValidationError) Unwrap

func (e *ValidationError) Unwrap() error

type WalkFunc

type WalkFunc func(n *Node) bool

WalkFunc is the callback for Walk. Return true to recurse into the node's children, or false to skip the subtree.

Jump to

Keyboard shortcuts

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