yaml

package
v0.0.0-...-7d79ef2 Latest Latest
Warning

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

Go to latest
Published: Jan 1, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

README

YAML Naming Convention Wrapper

This package provides YAML marshal/unmarshal functions that use custom naming conventions (kebab-case or snake_case) for struct fields by default, while respecting explicit yaml: tags.

Features

  • Automatic kebab-case or snake_case conversion: Struct fields without explicit yaml: tags are automatically converted
  • Tag precedence: Explicit yaml: tags are always respected
  • Recursive transformation: Works with nested structs, slices, and maps
  • Thread-safe: Safe for concurrent use (inherits from underlying github.com/goccy/go-yaml)
  • File I/O helpers: Convenience functions for reading/writing YAML files

Installation

go get codeberg.org/basvanbeek/run/pkg/yaml

Usage

Using Kebab-case
package main

import (
    "fmt"
    "codeberg.org/basvanbeek/run/pkg/yaml"
)

type Config struct {
    ServerName string  // Will be marshaled as "server-name"
    ListenPort int     // Will be marshaled as "listen-port"
    EnableTLS  bool    // Will be marshaled as "enable-tls"
}

func main() {
    cfg := Config{
        ServerName: "my-server",
        ListenPort: 8080,
        EnableTLS:  true,
    }

    // Marshal to YAML with kebab-case
    data, err := yaml.MarshalKebab(cfg)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(data))
    // Output:
    // server-name: my-server
    // listen-port: 8080
    // enable-tls: true

    // Unmarshal from YAML with kebab-case
    var loaded Config
    err = yaml.UnmarshalKebab(data, &loaded)
    if err != nil {
        panic(err)
    }
}
Using Snake_case

The same functionality is available with snake_case naming:

package main

import (
    "fmt"
    "codeberg.org/basvanbeek/run/pkg/yaml"
)

type Config struct {
    ServerName string  // Will be marshaled as "server_name"
    ListenPort int     // Will be marshaled as "listen_port"
    EnableTLS  bool    // Will be marshaled as "enable_tls"
}

func main() {
    cfg := Config{
        ServerName: "my-server",
        ListenPort: 8080,
        EnableTLS:  true,
    }

    // Marshal to YAML with snake_case
    data, err := yaml.MarshalSnake(cfg)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(data))
    // Output:
    // server_name: my-server
    // listen_port: 8080
    // enable_tls: true

    // Unmarshal from YAML with snake_case
    var loaded Config
    err = yaml.UnmarshalSnake(data, &loaded)
    if err != nil {
        panic(err)
    }
}
Using Explicit Tags

Fields with explicit yaml: tags will use the tag value instead of automatic conversion:

type Config struct {
    ServerName string `yaml:"custom_server_name"`  // Uses "custom_server_name"
    ListenPort int                                  // Uses "listen-port" (kebab-case)
    EnableTLS  bool   `yaml:"tls_enabled"`         // Uses "tls_enabled"
}
Nested Structs

The wrapper recursively transforms nested structs:

type AppConfig struct {
    ServerSettings ServerSettings  // Will be "server-settings"
    DatabaseConfig DatabaseConfig  // Will be "database-config"
}

type ServerSettings struct {
    HostName   string  // Will be "host-name"
    ListenPort int     // Will be "listen-port"
}

type DatabaseConfig struct {
    ConnectionString string           // Will be "connection-string"
    MaxConnections   int `yaml:"max_conn"`  // Uses explicit tag "max_conn"
}
File I/O
// Write to file
cfg := Config{ServerName: "test", ListenPort: 8080}
err := yaml.MarshalKebabToFile("config.yaml", cfg)

// Read from file
var loaded Config
err = yaml.UnmarshalKebabFromFile("config.yaml", &loaded)
Embedded Structs

Exported embedded struct fields are processed normally:

type BaseConfig struct {
    ServerName string
}

type AppConfig struct {
    BaseConfig  // Fields will be inlined
    ExtraField  string
}
Ignoring Fields

Use yaml:"-" to ignore fields:

type Config struct {
    VisibleField string
    IgnoredField string `yaml:"-"`  // Will not be marshaled
}

API Reference

Kebab-case Functions
  • MarshalKebab(v interface{}) ([]byte, error)
    Marshals v to YAML using kebab-case for field names without explicit tags.

  • UnmarshalKebab(data []byte, v interface{}) error
    Unmarshals YAML data into v, expecting kebab-case field names for fields without explicit tags.

  • MarshalKebabToFile(filename string, v interface{}) error
    Marshals v to a YAML file using kebab-case naming convention.

  • UnmarshalKebabFromFile(filename string, v interface{}) error
    Unmarshals YAML from a file into v using kebab-case naming convention.

Snake_case Functions
  • MarshalSnake(v interface{}) ([]byte, error)
    Marshals v to YAML using snake_case for field names without explicit tags.

  • UnmarshalSnake(data []byte, v interface{}) error
    Unmarshals YAML data into v, expecting snake_case field names for fields without explicit tags.

  • MarshalSnakeToFile(filename string, v interface{}) error
    Marshals v to a YAML file using snake_case naming convention.

  • UnmarshalSnakeFromFile(filename string, v interface{}) error
    Unmarshals YAML from a file into v using snake_case naming convention.

Behavior

Naming Conventions

Kebab-case conversion:

  • ServerNameserver-name
  • ListenPortlisten-port
  • TLSEnabledtls-enabled
  • HTTPServerhttp-server
  • MaxHTTPConnectionsmax-http-connections

Snake_case conversion:

  • ServerNameserver_name
  • ListenPortlisten_port
  • TLSEnabledtls_enabled
  • HTTPServerhttp_server
  • MaxHTTPConnectionsmax_http_connections
Field Processing
  1. Unexported fields: Skipped (standard Go behavior)
  2. Exported fields without tags: Converted to kebab-case or snake_case (depending on which function is used)
  3. Exported fields with yaml: tags: Use the tag value
  4. Embedded structs: Inlined at the parent level (standard YAML behavior)
  5. Fields with yaml:"-": Ignored
Type Support

The wrapper supports all standard Go types:

  • Basic types: string, int, bool, float64, etc.
  • Structs (including nested)
  • Slices and arrays
  • Maps
  • Pointers

Thread Safety

This package is thread-safe for concurrent marshal/unmarshal operations, as the underlying github.com/goccy/go-yaml library is stateless and thread-safe.

License

Copyright (c) 2026 Bas van Beek. Licensed under the Apache License Version 2.0.

Documentation

Overview

Package yaml provides YAML marshal/unmarshal functions with custom naming conventions.

Package yaml provides YAML marshal/unmarshal functions with custom naming conventions.

Package yaml provides YAML marshal/unmarshal functions with custom naming conventions.

Example

Example demonstrates basic usage of MarshalKebab and UnmarshalKebab.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type Config struct {
		ServerName string
		ListenPort int
		EnableTLS  bool
	}

	cfg := Config{
		ServerName: "my-server",
		ListenPort: 8080,
		EnableTLS:  true,
	}

	// Marshal to YAML with kebab-case
	data, err := yaml.MarshalKebab(cfg)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(data))

	// Unmarshal from YAML with kebab-case
	var loaded Config
	if err := yaml.UnmarshalKebab(data, &loaded); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Loaded: %+v\n", loaded)
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MarshalKebab

func MarshalKebab(v interface{}) ([]byte, error)

MarshalKebab marshals v to YAML bytes using kebab-case for field names that don't have explicit yaml tags. Fields with explicit yaml:"name" tags will use the tag value.

This function uses reflection to transform struct field names to kebab-case before marshaling. Only exported fields are processed (standard Go behavior).

Example

ExampleMarshalKebab demonstrates marshaling with explicit tags.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type Config struct {
		ServerName string `yaml:"custom_server_name"`
		ListenPort int    // Will use kebab-case: listen-port
		EnableTLS  bool   `yaml:"tls_enabled"`
	}

	cfg := Config{
		ServerName: "test-server",
		ListenPort: 8080,
		EnableTLS:  true,
	}

	data, err := yaml.MarshalKebab(cfg)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(data))
}

func MarshalKebabToFile

func MarshalKebabToFile(filename string, v interface{}) error

MarshalKebabToFile marshals v to a YAML file using kebab-case naming convention.

Example

ExampleMarshalKebabToFile demonstrates writing YAML to a file.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type Config struct {
		ServerName string
		ListenPort int
	}

	cfg := Config{
		ServerName: "file-server",
		ListenPort: 9090,
	}

	// Write to file
	if err := yaml.MarshalKebabToFile("/tmp/config.yaml", cfg); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Config written to /tmp/config.yaml")
}

func MarshalSnake

func MarshalSnake(v interface{}) ([]byte, error)

MarshalSnake marshals v to YAML bytes using snake_case for field names that don't have explicit yaml tags. Fields with explicit yaml:"name" tags will use the tag value.

This function uses reflection to transform struct field names to snake_case before marshaling. Only exported fields are processed (standard Go behavior).

Example

ExampleMarshalSnake demonstrates basic usage of MarshalSnake.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type Config struct {
		ServerName string
		ListenPort int
		EnableTLS  bool
	}

	cfg := Config{
		ServerName: "my-server",
		ListenPort: 8080,
		EnableTLS:  true,
	}

	data, err := yaml.MarshalSnake(cfg)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(data))
}

func MarshalSnakeToFile

func MarshalSnakeToFile(filename string, v interface{}) error

MarshalSnakeToFile marshals v to a YAML file using snake_case naming convention.

Example

ExampleMarshalSnakeToFile demonstrates writing YAML with snake_case to a file.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type Config struct {
		ServerName string
		ListenPort int
	}

	cfg := Config{
		ServerName: "file-server",
		ListenPort: 9090,
	}

	// Write to file
	if err := yaml.MarshalSnakeToFile("/tmp/config-snake.yaml", cfg); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Config written to /tmp/config-snake.yaml")
}

func UnmarshalKebab

func UnmarshalKebab(data []byte, v interface{}) error

UnmarshalKebab unmarshals YAML bytes into v, expecting kebab-case field names for fields without explicit yaml tags. Fields with explicit yaml:"name" tags will use the tag value.

This function uses reflection to transform struct field names to kebab-case before unmarshaling. Only exported fields are processed (standard Go behavior).

Example

ExampleUnmarshalKebab demonstrates unmarshaling with nested structs.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type ServerSettings struct {
		HostName   string
		ListenPort int
	}

	type DatabaseConfig struct {
		ConnectionString string
		MaxConnections   int `yaml:"max_conn"`
	}

	type AppConfig struct {
		ServerSettings ServerSettings
		DatabaseConfig DatabaseConfig
	}

	yamlData := []byte(`
server-settings:
  host-name: localhost
  listen-port: 8080
database-config:
  connection-string: postgres://localhost
  max_conn: 10
`)

	var cfg AppConfig
	if err := yaml.UnmarshalKebab(yamlData, &cfg); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Server: %s:%d\n", cfg.ServerSettings.HostName, cfg.ServerSettings.ListenPort)
	fmt.Printf("Database: %s (max %d connections)\n",
		cfg.DatabaseConfig.ConnectionString,
		cfg.DatabaseConfig.MaxConnections)
}

func UnmarshalKebabFromFile

func UnmarshalKebabFromFile(filename string, v interface{}) error

UnmarshalKebabFromFile unmarshals YAML from a file into v using kebab-case naming convention.

Example

ExampleUnmarshalKebabFromFile demonstrates reading YAML from a file.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type Config struct {
		ServerName string
		ListenPort int
	}

	var cfg Config
	if err := yaml.UnmarshalKebabFromFile("/tmp/config.yaml", &cfg); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Loaded config: %+v\n", cfg)
}

func UnmarshalSnake

func UnmarshalSnake(data []byte, v interface{}) error

UnmarshalSnake unmarshals YAML bytes into v, expecting snake_case field names for fields without explicit yaml tags. Fields with explicit yaml:"name" tags will use the tag value.

This function uses reflection to transform struct field names to snake_case before unmarshaling. Only exported fields are processed (standard Go behavior).

Example

ExampleUnmarshalSnake demonstrates unmarshaling with snake_case.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type Config struct {
		ServerName string
		ListenPort int
		EnableTLS  bool
	}

	yamlData := []byte(`
server_name: test-server
listen_port: 8080
enable_tls: true
`)

	var cfg Config
	if err := yaml.UnmarshalSnake(yamlData, &cfg); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Server: %s:%d (TLS: %v)\n", cfg.ServerName, cfg.ListenPort, cfg.EnableTLS)
}

func UnmarshalSnakeFromFile

func UnmarshalSnakeFromFile(filename string, v interface{}) error

UnmarshalSnakeFromFile unmarshals YAML from a file into v using snake_case naming convention.

Example

ExampleUnmarshalSnakeFromFile demonstrates reading YAML with snake_case from a file.

package main

import (
	"fmt"
	"log"

	"codeberg.org/basvanbeek/run/pkg/yaml"
)

func main() {
	type Config struct {
		ServerName string
		ListenPort int
	}

	var cfg Config
	if err := yaml.UnmarshalSnakeFromFile("/tmp/config-snake.yaml", &cfg); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Loaded config: %+v\n", cfg)
}

Types

This section is empty.

Jump to

Keyboard shortcuts

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