### Install goccy/go-yaml Source: https://github.com/goccy/go-yaml/blob/master/README.md Use go get to install the library. This is the standard way to add Go packages to your project. ```sh go get github.com/goccy/go-yaml ``` -------------------------------- ### Installing ycat CLI Tool Source: https://github.com/goccy/go-yaml/blob/master/README.md Install the `ycat` command-line tool for pretty-printing YAML files with color. This involves cloning the repository, navigating to the `cmd/ycat` directory, and running `go install`. ```sh git clone https://github.com/goccy/go-yaml.git cd go-yaml/cmd/ycat && go install . ``` -------------------------------- ### Querying YAML with YAMLPath Source: https://github.com/goccy/go-yaml/blob/master/README.md Use `yaml.PathString` to define a query path for a YAML document and then use the `Read` method to extract specific data. This is useful for selectively retrieving information from complex YAML structures. ```go yml := ` store: book: - author: john price: 10 - author: ken price: 12 bicycle: color: red price: 19.95 ` path, err := yaml.PathString("$.store.book[*].author") if err != nil { //... } var authors []string if err := path.Read(strings.NewReader(yml), &authors); err != nil { //... } fmt.Println(authors) ``` -------------------------------- ### Using MergeKey and Alias in Go Source: https://github.com/goccy/go-yaml/blob/master/README.md Embed a structure with the `inline,alias` tag to utilize MergeKey and Alias for default values and overrides in YAML. This is useful for defining default configurations that can be extended. ```go type Person struct { *Person `yaml:",omitempty,inline,alias"` // embed Person type for default value Name string `yaml:",omitempty" Age int `yaml:",omitempty" } defaultPerson := &Person{ Name: "John Smith", Age: 20, } people := []*Person{ { Person: defaultPerson, // assign default value Name: "Ken", // override Name property Age: 10, // override Age property }, { Person: defaultPerson, // assign default value only }, } var doc struct { Default *Person `yaml:"default,anchor" People []*Person `yaml:"people" } doc.Default = defaultPerson doc.People = people bytes, err := yaml.Marshal(doc) if err != nil { //... } fmt.Println(string(bytes)) ``` -------------------------------- ### Tokenize YAML Content Source: https://github.com/goccy/go-yaml/blob/master/README.md Use the lexer.Tokenize function to break down YAML content into a stream of tokens. This is a foundational step for parsing. ```go package main import ( "fmt" "github.com/goccy/go-yaml/lexer" ) func main() { const src = `name: "example" age: 30 ` tokens, err := lexer.Tokenize(src) if err != nil { panic(err) } for _, token := range tokens { fmt.Println(token) } } ``` -------------------------------- ### MarshalWithOptions — Encode with EncodeOptions Source: https://context7.com/goccy/go-yaml/llms.txt `MarshalWithOptions` is the options-aware variant of `Marshal`. It allows customization of the encoding process using various `EncodeOption` functions. ```APIDOC ## MarshalWithOptions go-yaml ### Description `MarshalWithOptions` is the options-aware variant of `Marshal`. Common encode options include `Indent(n)`, `IndentSequence(bool)`, `UseSingleQuote(bool)`, `Flow(bool)`, `JSON()`, `UseLiteralStyleIfMultiline(bool)`, `OmitEmpty()`, `AutoInt()`, and `WithComment(cm)`. ### Signature `MarshalWithOptions(v interface{}, opts ...EncodeOption) ([]byte, error)` ### Example ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { type Config struct { Host string `yaml:"host"` Ports []int `yaml:"ports"` Tags []string `yaml:"tags"` Timeout float64 `yaml:"timeout"` } cfg := Config{ Host: "localhost", Ports: []int{8080, 9090}, Tags: []string{"web", "api"}, Timeout: 30.0, } // 4-space indent, sequences indented, floats auto-converted to int where whole out, err := yaml.MarshalWithOptions(cfg, yaml.Indent(4), yaml.IndentSequence(true), yaml.AutoInt(), ) if err != nil { panic(err) } fmt.Print(string(out)) // host: localhost // ports: // - 8080 // - 9090 // tags: // - web // - api // timeout: 30 } ``` ``` -------------------------------- ### Convert Between YAML and JSON Formats Source: https://context7.com/goccy/go-yaml/llms.txt Use YAMLToJSON and JSONToYAML for seamless conversion between YAML and JSON data. These functions preserve map key order using MapSlice. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { yamlData := []byte(` name: Gopher skills: - Go - YAML active: true `) jsonData, err := yaml.YAMLToJSON(yamlData) if err != nil { panic(err) } fmt.Println(string(jsonData)) // {"name":"Gopher","skills":["Go","YAML"],"active":true} roundTripped, err := yaml.JSONToYAML(jsonData) if err != nil { panic(err) } fmt.Print(string(roundTripped)) // name: Gopher // skills: // - Go // - YAML // active: true } ``` -------------------------------- ### Convert Go Value to AST Node and Vice Versa Source: https://context7.com/goccy/go-yaml/llms.txt Provides functions to convert Go values to AST nodes (`ValueToNode`) and AST nodes back to Go values (`NodeToValue`). This enables manipulation of YAML structures programmatically. ```go package main import ( "fmt" "github.com/goccy/go-yaml" "github.com/goccy/go-yaml/ast" "github.com/goccy/go-yaml/parser" ) func main() { // Build an AST node from a Go map node, err := yaml.ValueToNode(map[string]any{ "env": "production", "workers": 4, }) if err != nil { panic(err) } fmt.Printf("node type: %s\n", node.Type()) // MappingType // Inject the node into an existing document base := []byte("service: payments\nconfig: {}\n") file, _ := parser.ParseBytes(base, 0) path, _ := yaml.PathString("$.config") _ = path.ReplaceWithNode(file, node) fmt.Println(file.String()) // service: payments // config: // env: production // workers: 4 // Convert an AST node back to a typed Go value var cfg map[string]any _ = yaml.NodeToValue(node, &cfg) fmt.Println(cfg["workers"]) // 4 // Walk AST nodes ast.Walk(file, func(n ast.Node) bool { if n, ok := n.(*ast.MappingValueNode); ok { fmt.Printf("key: %s\n", n.Key) } return true }) } ``` -------------------------------- ### Marshal Go value to YAML with options Source: https://context7.com/goccy/go-yaml/llms.txt Encodes a Go value to YAML using `MarshalWithOptions`, allowing customization of indentation, sequence formatting, float-to-int conversion, and more via `EncodeOption` functions. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { type Config struct { Host string `yaml:"host"` Ports []int `yaml:"ports"` Tags []string `yaml:"tags"` Timeout float64 `yaml:"timeout"` } cfg := Config{ Host: "localhost", Ports: []int{8080, 9090}, Tags: []string{"web", "api"}, Timeout: 30.0, } // 4-space indent, sequences indented, floats auto-converted to int where whole out, err := yaml.MarshalWithOptions(cfg, yaml.Indent(4), yaml.IndentSequence(true), yaml.AutoInt(), ) if err != nil { panic(err) } fmt.Print(string(out)) // host: localhost // ports: // - 8080 // - 9090 // tags: // - web // - api // timeout: 30 } ``` -------------------------------- ### Extract Data Using YAMLPath Filtering Source: https://context7.com/goccy/go-yaml/llms.txt Use PathString to compile a YAMLPath expression and Path.Read to extract matched data into a variable. Supported selectors include $, .key, [n], [*], and ..recursive. ```go package main import ( "fmt" "strings" "github.com/goccy/go-yaml" ) func main() { src := ` catalog: books: - title: "Go Programming" price: 39.99 tags: [go, programming] - title: "YAML in Practice" price: 29.99 tags: [yaml, devops] magazines: - title: "DevOps Weekly" price: 9.99 ` // Extract all book titles path, err := yaml.PathString("$.catalog.books[*].title") if err != nil { panic(err) } var titles []string if err := path.Read(strings.NewReader(src), &titles); err != nil { panic(err) } fmt.Println(titles) // [Go Programming YAML in Practice] // Extract second book price path2, _ := yaml.PathString("$.catalog.books[1].price") var price float64 _ = path2.Read(strings.NewReader(src), &price) fmt.Println(price) // 29.99 } ``` -------------------------------- ### Encode YAML Anchors and Aliases via Struct Tags Source: https://context7.com/goccy/go-yaml/llms.txt Use `yaml:"anchor"` or `yaml:"anchor=name"` tags to emit YAML anchors, and `yaml:"alias"` or `yaml:"alias=name"` tags to emit aliases. When two pointer fields share the same address, the alias is automatically inferred. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) type DBConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` } func main() { primary := &DBConfig{Host: "db-primary", Port: 5432} var cfg struct { Primary *DBConfig `yaml:"primary,anchor=db"` Replica1 *DBConfig `yaml:"replica1,alias=db"` Replica2 *DBConfig `yaml:"replica2,alias=db"` } cfg.Primary = primary cfg.Replica1 = primary // same pointer → alias cfg.Replica2 = primary out, err := yaml.Marshal(cfg) if err != nil { panic(err) } fmt.Print(string(out)) // primary: &db // host: db-primary // port: 5432 // replica1: *db // replica2: *db } ``` -------------------------------- ### Low-Level Tokenization of YAML Source: https://context7.com/goccy/go-yaml/llms.txt Converts raw YAML text into a slice of tokens, each containing type, value, origin, and precise line/column position. Useful for syntax highlighting or custom linters. ```go package main import ( "fmt" "github.com/goccy/go-yaml/lexer" ) func main() { src := `name: Alice scores: - 95 - 87 ` tokens := lexer.Tokenize(src) for _, tok := range tokens { fmt.Printf("type=%-20s value=%q origin=%q line=%d col=%d\n", tok.Type, tok.Value, tok.Origin, tok.Position.Line, tok.Position.Column) } // type=StringType value="name" origin="name" line=1 col=1 // type=MappingValueType value=":" origin=": " line=1 col=5 // type=StringType value="Alice" origin="Alice" line=1 col=7 // ... } ``` -------------------------------- ### Deferred YAML Decoding with RawMessage Source: https://context7.com/goccy/go-yaml/llms.txt Use yaml.RawMessage to defer decoding of specific YAML fields. This is useful when parts of a document need to be processed later or passed through unchanged. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { src := ` type: circle spec: radius: 5 color: red ` // Decode the "spec" field lazily var envelope struct { Type string `yaml:"type"` Spec yaml.RawMessage `yaml:"spec"` } if err := yaml.Unmarshal([]byte(src), &envelope); err != nil { panic(err) } fmt.Println(envelope.Type) // circle fmt.Println(string(envelope.Spec)) // radius: 5 color: red // Decode spec based on type var circle struct { Radius int `yaml:"radius"` Color string `yaml:"color"` } if err := yaml.Unmarshal(envelope.Spec, &circle); err != nil { panic(err) } fmt.Printf("radius=%d color=%s\n", circle.Radius, circle.Color) // radius=5 color=red } ``` -------------------------------- ### Round-trip Comments with WithComment and CommentToMap Source: https://context7.com/goccy/go-yaml/llms.txt Use `yaml.WithComment` during marshaling to attach comments to specific nodes, and `yaml.CommentToMap` during unmarshaling to capture these comments into a `yaml.CommentMap`. This enables full round-trip preservation of comments. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { // Encode with inline and header comments type Config struct { Host string `yaml:"host"` Port int `yaml:"port"` } cfg := Config{Host: "localhost", Port: 8080} out, err := yaml.MarshalWithOptions(cfg, yaml.WithComment(yaml.CommentMap{ "$.host": {yaml.LineComment("primary host")}, "$.port": {yaml.HeadComment("HTTP port", "must be > 1024")}, }), ) if err != nil { panic(err) } fmt.Print(string(out)) // # HTTP port // # must be > 1024 // port: 8080 // host: localhost # primary host // Decode and capture comments cm := yaml.CommentMap{} var cfg2 Config _ = yaml.UnmarshalWithOptions(out, &cfg2, yaml.CommentToMap(cm)) for k, comments := range cm { for _, c := range comments { fmt.Printf("path=%s texts=%v\n", k, c.Texts) } } } ``` -------------------------------- ### PathString and Path.Read Source: https://context7.com/goccy/go-yaml/llms.txt Compiles a YAMLPath expression and extracts the matched subtree from a reader. Supports selectors like $, .key, [n], [*], and ..recursive. ```APIDOC ## PathString / Path.Read — YAMLPath filtering `PathString(s string) (*Path, error)` compiles a JSONPath-like expression. `(*Path).Read(r io.Reader, v interface{}) error` extracts the matched subtree into `v`. Supported selectors: `$` (root), `.key`, `[n]`, `[*]`, `..recursive`. ``` -------------------------------- ### Simple YAML Encode Source: https://github.com/goccy/go-yaml/blob/master/README.md Encodes a Go struct into YAML format using reflection. Ensure the struct fields are exported for marshaling. ```go var v struct { A int B string } v.A = 1 v.B = "hello" bytes, err := yaml.Marshal(v) if err != nil { //... } fmt.Println(string(bytes)) // "a: 1 b: hello\n" ``` -------------------------------- ### Parse YAML Content Source: https://github.com/goccy/go-yaml/blob/master/README.md Utilize the parser.Parse function to convert a stream of tokens into an Abstract Syntax Tree (AST). This AST represents the structure of the YAML document. ```go package main import ( "fmt" "github.com/goccy/go-yaml/parser" "github.com/goccy/go-yaml/lexer" ) func main() { const src = `name: "example" age: 30 ` tokens, err := lexer.Tokenize(src) if err != nil { panic(err) } doc, err := parser.Parse(tokens) if err != nil { panic(err) } fmt.Println(doc.String()) } ``` -------------------------------- ### Register Per-Instance Custom Marshaler/Unmarshaler for Tags Source: https://context7.com/goccy/go-yaml/llms.txt Use `CustomUnmarshaler` and `CustomMarshaler` options with `yaml.NewDecoder` and `yaml.MarshalWithOptions` to override encoding/decoding for a specific type on a single instance. This takes precedence over global settings. ```go package main import ( "fmt" "strings" "github.com/goccy/go-yaml" ) type Tags []string func main() { src := `name: service-a tags: go,web,api ` type Service struct { Name string `yaml:"name"` Tags Tags `yaml:"tags"` } // Decode comma-separated string as []string d := yaml.NewDecoder( strings.NewReader(src), yaml.CustomUnmarshaler[Tags](func(t *Tags, b []byte) error { *t = strings.Split(string(b), ",") return nil }), ) var svc Service if err := dec.Decode(&svc); err != nil { panic(err) } fmt.Println(svc.Tags) // [go web api] // Encode []string back as comma-separated out, _ := yaml.MarshalWithOptions(svc, yaml.CustomMarshaler[Tags](func(t Tags) ([]byte, error) { return []byte(strings.Join(t, ",")), }), ) fmt.Print(string(out)) // name: service-a // tags: go,web,api } ``` -------------------------------- ### YAMLToJSON / JSONToYAML Source: https://context7.com/goccy/go-yaml/llms.txt Converts between YAML and JSON formats while preserving map key order using MapSlice. ```APIDOC ## YAMLToJSON / JSONToYAML — Format conversion `YAMLToJSON([]byte) ([]byte, error)` and `JSONToYAML([]byte) ([]byte, error)` convert between the two formats while preserving map key order via `MapSlice`. ``` -------------------------------- ### Resolve Cross-File Anchors with ReferenceDirs Source: https://context7.com/goccy/go-yaml/llms.txt Use `ReferenceDirs(dirs...)` when creating a `NewDecoder` to resolve anchors defined in external YAML files. This allows for modular and reusable YAML configurations. ```go package main import ( "bytes" "fmt" "os" "github.com/goccy/go-yaml" ) func main() { // Write anchor definition to a temp file os.MkdirAll("shared", 0755) os.WriteFile("shared/defaults.yml", []byte("defaults: &defaults\n timeout: 60\n retries: 5\n"), 0644) // The main document only references the anchor src := "config:\n <<: *defaults\n host: api.example.com\n" dec := yaml.NewDecoder(bytes.NewBufferString(src), yaml.ReferenceDirs("shared")) var v map[string]interface{} if err := dec.Decode(&v); err != nil { panic(err) } cfg := v["config"].(map[string]interface{}) fmt.Printf("host=%s timeout=%v retries=%v\n", cfg["host"], cfg["timeout"], cfg["retries"]) // host=api.example.com timeout=60 retries=5 } ``` -------------------------------- ### Simple YAML Decode Source: https://github.com/goccy/go-yaml/blob/master/README.md Decodes a YAML byte slice into a Go struct. Handles basic YAML syntax and requires error checking. ```go yml := ` %YAML 1.2 --- a: 1 b: c ` var v struct { A int B string } if err := yaml.Unmarshal([]byte(yml), &v); err != nil { //... } ``` -------------------------------- ### Use JSON Marshaler for YAML Source: https://github.com/goccy/go-yaml/blob/master/README.md Configure the YAML marshaler to use the MarshalJSON method if available on the Go type. This allows leveraging existing JSON marshaling logic for YAML output. ```go package main import ( "encoding/json" "fmt" "log" "github.com/goccy/go-yaml" ) type MyJSONType struct { Value string } func (m MyJSONType) MarshalJSON() ([]byte, error) { return json.Marshal(fmt.Sprintf("json-prefixed-%s", m.Value)) } func main() { data := MyJSONType{Value: "test"} // Use JSONMarshaler option yamlData, err := yaml.MarshalWithOption(data, yaml.UseJSONMarshaler()) if err != nil { log.Fatalf("error: %v", err) } fmt.Printf("%s\n", yamlData) } ``` -------------------------------- ### MergeKey / Inline Alias Source: https://context7.com/goccy/go-yaml/llms.txt Supports merge-key syntax (`<<: *anchor`) on encoding by embedding a struct pointer with `yaml:",omitempty,inline,alias"`. This allows for overriding default values in nested structures. ```APIDOC ## MergeKey / Inline Alias Embed a struct pointer with `yaml:",omitempty,inline,alias"` to produce `<<: *anchor` merge-key syntax on encoding. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) type ServiceDefaults struct { *ServiceDefaults `yaml:",omitempty,inline,alias"` Timeout int `yaml:",omitempty"` Retries int `yaml:",omitempty"` LogLevel string `yaml:",omitempty"` } func main() { defaults := &ServiceDefaults{Timeout: 30, Retries: 3, LogLevel: "info"} var doc struct { Defaults *ServiceDefaults `yaml:"defaults,anchor"` Services []*ServiceDefaults `yaml:"services"` } doc.Defaults = defaults doc.Services = []*ServiceDefaults{ {ServiceDefaults: defaults, Timeout: 10}, // override Timeout {ServiceDefaults: defaults, LogLevel: "debug"}, // override LogLevel } out, err := yaml.Marshal(doc) if err != nil { panic(err) } fmt.Print(string(out)) // defaults: &defaults // timeout: 30 // retries: 3 // loglevel: info // services: // - <<: *defaults // timeout: 10 // - <<: *defaults // loglevel: debug } ``` ``` -------------------------------- ### Marshal Go Struct to YAML Source: https://github.com/goccy/go-yaml/blob/master/README.md Marshal a Go struct into YAML format. This is useful for generating YAML configuration files or data structures. ```go package main import ( "fmt" "log" "gopkg.in/yaml.v3" ) type Person struct { Name string `yaml:"name"` Age int `yaml:"age"` } func main() { p := Person{ Name: "Taro Yamada", Age: 30, } data, err := yaml.Marshal(&p) if err != nil { log.Fatalf("error: %v", err) } fmt.Printf("%s\n", data) } ``` -------------------------------- ### Struct Validation on Decode with Validator Source: https://context7.com/goccy/go-yaml/llms.txt Integrates struct validation using an external library like `go-playground/validator/v10` during YAML decoding. Ensure the validator is initialized and passed via `yaml.Validator` option. Validation errors are merged and can be formatted. ```go package main import ( "fmt" "github.com/go-playground/validator/v10" "github.com/goccy/go-yaml" ) func main() { type User struct { Name string `yaml:"name" validate:"required,min=2" Email string `yaml:"email" validate:"required,email" Age int `yaml:"age" validate:"gte=0,lte=130" } src := ` name: A email: not-an-email age: 200 ` validate := validator.New() var u User err := yaml.UnmarshalWithOptions([]byte(src), &u, yaml.Validator(validate)) if err != nil { fmt.Println(yaml.FormatError(err, false, false)) // [3:8] Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag // [4:6] Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag // [2:7] Key: 'User.Name' Error:Field validation for 'Name' failed on the 'min' tag } } ``` -------------------------------- ### Stream Encode Multi-Document YAML Source: https://context7.com/goccy/go-yaml/llms.txt Use NewEncoder to create a streaming encoder. Multiple calls to Encode will produce a multi-document YAML stream separated by '---'. Options like Indent can be applied. ```go package main import ( "os" "github.com/goccy/go-yaml" ) func main() { enc := yaml.NewEncoder(os.Stdout, yaml.Indent(2)) defer enc.Close() records := []map[string]any{ {"id": 1, "status": "active"}, {"id": 2, "status": "inactive"}, {"id": 3, "status": "pending"}, } for _, r := range records { if err := enc.Encode(r); err != nil { panic(err) } } // id: 1 // status: active // --- // id: 2 // status: inactive // --- // id: 3 // status: pending } ``` -------------------------------- ### Marshal — Encode a Go value to YAML bytes Source: https://context7.com/goccy/go-yaml/llms.txt `Marshal` serializes any Go value to a YAML document. Struct fields use their lowercased name by default; the `yaml` struct tag controls key names and flags. ```APIDOC ## Marshal go-yaml ### Description Serializes any Go value to a YAML document. Struct fields use their lowercased name by default; the `yaml` struct tag controls key names and flags (`omitempty`, `flow`, `inline`, `anchor`, `alias`). ### Signature `Marshal(v interface{}) ([]byte, error)` ### Example ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) type Address struct { Street string `yaml:"street"` City string `yaml:"city"` } type Person struct { Name string `yaml:"name"` Age int `yaml:"age"` Score float64 `yaml:"score,omitempty"` Address Address `yaml:"address,flow"` } func main() { p := Person{ Name: "Alice", Age: 30, Address: Address{Street: "1 Main St", City: "Springfield"}, } out, err := yaml.Marshal(p) if err != nil { panic(err) } fmt.Print(string(out)) // name: Alice // age: 30 // address: {street: 1 Main St, city: Springfield} } ``` ``` -------------------------------- ### Encode MergeKey / Inline Alias Source: https://context7.com/goccy/go-yaml/llms.txt Embed a struct pointer with `yaml:",omitempty,inline,alias"` to produce `<<: *anchor` merge-key syntax on encoding. This allows overriding specific fields from a referenced anchor. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) type ServiceDefaults struct { *ServiceDefaults `yaml:",omitempty,inline,alias"` Timeout int `yaml:",omitempty"` Retries int `yaml:",omitempty"` LogLevel string `yaml:",omitempty"` } func main() { defaults := &ServiceDefaults{Timeout: 30, Retries: 3, LogLevel: "info"} var doc struct { Defaults *ServiceDefaults `yaml:"defaults,anchor"` Services []*ServiceDefaults `yaml:"services"` } doc.Defaults = defaults doc.Services = []*ServiceDefaults{ {ServiceDefaults: defaults, Timeout: 10}, // override Timeout {ServiceDefaults: defaults, LogLevel: "debug"}, // override LogLevel } out, err := yaml.Marshal(doc) if err != nil { panic(err) } fmt.Print(string(out)) // defaults: &defaults // timeout: 30 // retries: 3 // loglevel: info // services: // - <<: *defaults // timeout: 10 // - <<: *defaults // loglevel: debug } ``` -------------------------------- ### Parse YAML Bytes to AST Source: https://context7.com/goccy/go-yaml/llms.txt Parses YAML bytes into an `*ast.File` structure, which contains `*ast.DocumentNode` slices. Use `parser.ParseComments` to retain comment nodes. The AST supports lossless round-tripping back to YAML. ```go package main import ( "fmt" "github.com/goccy/go-yaml/parser" ) func main() { src := []byte(` # App configuration app: name: myservice # service name version: "1.0.0" features: - auth - metrics `) // ParseComments preserves comment nodes in AST file, err := parser.ParseBytes(src, parser.ParseComments) if err != nil { panic(err) } // Print AST structure fmt.Println(file) // The file round-trips back to equivalent YAML fmt.Println(file.String()) } ``` -------------------------------- ### YAML Decode with External References Source: https://github.com/goccy/go-yaml/blob/master/README.md Decodes YAML that references external files for anchor definitions. Use `yaml.ReferenceDirs` to specify directories to search for these definitions. ```go buf := bytes.NewBufferString("a: *a\n") dec := yaml.NewDecoder(buf, yaml.ReferenceDirs("testdata")) var v struct { A struct { B int C string } } if err := dec.Decode(&v); err != nil { //... } fmt.Printf("%+v\n", v) // {A:{B:1 C:hello}} ``` -------------------------------- ### FormatError Source: https://context7.com/goccy/go-yaml/llms.txt Pretty-prints YAML parse errors, enriching them with location information and optional YAML source snippets. ```APIDOC ## FormatError — Pretty-print YAML parse errors `FormatError(e error, colored bool, inclSource bool) string` enriches any error returned by this library with location information and optional YAML source snippets. ``` -------------------------------- ### Anchor and Alias encoding via struct tags Source: https://context7.com/goccy/go-yaml/llms.txt Enables YAML anchor and alias encoding through struct tags. Fields can be tagged with `anchor` or `anchor=name` to emit anchors, and `alias` or `alias=name` to emit aliases. Aliases are automatically inferred when two pointer fields share the same address. ```APIDOC ## Anchor and Alias encoding via struct tags Struct fields can be tagged with `anchor` or `anchor=name` to emit YAML anchors, and `alias` or `alias=name` to emit YAML aliases. When two pointer fields share the same address, the alias is automatically inferred. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) type DBConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` } func main() { primary := &DBConfig{Host: "db-primary", Port: 5432} var cfg struct { Primary *DBConfig `yaml:"primary,anchor=db"` Replica1 *DBConfig `yaml:"replica1,alias=db"` Replica2 *DBConfig `yaml:"replica2,alias=db"` } cfg.Primary = primary cfg.Replica1 = primary // same pointer → alias cfg.Replica2 = primary out, err := yaml.Marshal(cfg) if err != nil { panic(err) } fmt.Print(string(out)) // primary: &db // host: db-primary // port: 5432 // replica1: *db // replica2: *db } ``` ``` -------------------------------- ### Stream Decode Multi-Document YAML Source: https://context7.com/goccy/go-yaml/llms.txt Use NewDecoder to create a streaming decoder for multi-document YAML files. Decode reads one document at a time. Options like DisallowUnknownField can be applied. ```go package main import ( "fmt" "io" "strings" "github.com/goccy/go-yaml" ) func main() { // Multi-document YAML stream src := ` name: doc1 value: 100 --- name: doc2 value: 200 --- name: doc3 value: 300 ` type Doc struct { Name string `yaml:"name"` Value int `yaml:"value"` } dec := yaml.NewDecoder(strings.NewReader(src), yaml.DisallowUnknownField()) for { var d Doc if err := dec.Decode(&d); err != nil { if err == io.EOF { break } panic(err) } fmt.Printf("%s = %d\n", d.Name, d.Value) } // doc1 = 100 // doc2 = 200 // doc3 = 300 } ``` -------------------------------- ### ReferenceDirs — Cross-file anchor resolution Source: https://context7.com/goccy/go-yaml/llms.txt Enables resolution of anchors defined in external YAML files by passing `ReferenceDirs(dirs...)` (or `ReferenceFiles` / `ReferenceReaders`) to `NewDecoder`. This allows for modular YAML configurations. ```APIDOC ## ReferenceDirs — Cross-file anchor resolution Pass `ReferenceDirs(dirs...)` (or `ReferenceFiles(files...)` / `ReferenceReaders(readers...)`) to `NewDecoder` to let it resolve anchors defined in external YAML files. ```go package main import ( "bytes" "fmt" "os" "github.com/goccy/go-yaml" ) func main() { // Write anchor definition to a temp file os.MkdirAll("shared", 0755) os.WriteFile("shared/defaults.yml", []byte("defaults: &defaults\n timeout: 60\n retries: 5\n"), 0644) // The main document only references the anchor src := "config:\n <<: *defaults\n host: api.example.com\n" dec := yaml.NewDecoder(bytes.NewBufferString(src), yaml.ReferenceDirs("shared")) var v map[string]interface{} if err := dec.Decode(&v); err != nil { panic(err) } cfg := v["config"].(map[string]interface{}) fmt.Printf("host=%s timeout=%v retries=%v\n", cfg["host"], cfg["timeout"], cfg["retries"]) // host=api.example.com timeout=60 retries=5 } ``` ``` -------------------------------- ### In-place AST Mutation with YAMLPath Source: https://context7.com/goccy/go-yaml/llms.txt Use Path.ReplaceWithNode to modify a parsed YAML AST in-place, preserving comments and anchors. This is useful for updating specific values within a YAML structure. ```go package main import ( "fmt" "github.com/goccy/go-yaml" "github.com/goccy/go-yaml/ast" "github.com/goccy/go-yaml/parser" ) func main() { src := `# deployment config replicas: 2 image: myapp:latest resources: cpu: "100m" memory: "128Mi" ` file, err := parser.ParseBytes([]byte(src), parser.ParseComments) if err != nil { panic(err) } // Bump replicas to 5 path, _ := yaml.PathString("$.replicas") newNode, _ := yaml.ValueToNode(5) if err := path.ReplaceWithNode(file, newNode); err != nil { panic(err) } // Update image tag path2, _ := yaml.PathString("$.image") newNode2, _ := yaml.ValueToNode("myapp:v2.3.0") _ = path2.ReplaceWithNode(file, newNode2) fmt.Println(file.String()) // # deployment config // replicas: 5 // image: myapp:v2.3.0 // resources: // cpu: "100m" // memory: "128Mi" } ``` -------------------------------- ### Use JSON Unmarshaler for YAML Source: https://github.com/goccy/go-yaml/blob/master/README.md Configure the YAML unmarshaler to use the UnmarshalJSON method if available on the Go type. This allows leveraging existing JSON unmarshaling logic for YAML input. ```go package main import ( "encoding/json" "fmt" "log" "github.com/goccy/go-yaml" ) type MyJSONType struct { Value string } func (m *MyJSONType) UnmarshalJSON(b []byte) error { var s string if err := json.Unmarshal(b, &s); err != nil { return err } m.Value = s return nil } func main() { const src = `"json-prefixed-test" ` var data MyJSONType // Use JSONUnmarshaler option err := yaml.UnmarshalWithOption([]byte(src), &data, yaml.UseJSONUnmarshaler()) if err != nil { log.Fatalf("error: %v", err) } fmt.Printf("%+v\n", data) } ``` -------------------------------- ### Pretty-Print YAML Parse Errors Source: https://context7.com/goccy/go-yaml/llms.txt Use FormatError to create human-readable error messages from YAML parsing errors, including optional source snippets and colorization. This helps in debugging. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { invalid := ` name: Alice age: not-an-integer scores: [10, 20 ` var v struct { Name string `yaml:"name"` Age int `yaml:"age"` Scores []int `yaml:"scores"` } err := yaml.Unmarshal([]byte(invalid), &v) if err != nil { fmt.Println(yaml.FormatError(err, false, true)) // [3:6] cannot unmarshal !!str `not-an-ப்புகளை` into int // 1 | // 2 | name: Alice // > 3 | age: not-an-integer // ^ // 4 | scores: [10, 20 } } ``` -------------------------------- ### Preserve Map Key Order with UseOrderedMap Source: https://context7.com/goccy/go-yaml/llms.txt Use the `yaml.UseOrderedMap()` decode option to make the decoder use `yaml.MapSlice` instead of `map[string]interface{}`. This guarantees that the original YAML key order is preserved during decoding. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { src := `z_last: 3 a_first: 1 m_middle: 2 ` // Without UseOrderedMap, map iteration order is random var unordered map[string]int _ = yaml.Unmarshal([]byte(src), &unordered) // With UseOrderedMap, order is preserved dec := yaml.NewDecoder( strings.NewReader(src), yaml.UseOrderedMap(), ) // Can also unmarshal directly into MapSlice var ordered yaml.MapSlice _ = yaml.UnmarshalWithOptions([]byte(src), &ordered, yaml.UseOrderedMap()) for _, item := range ordered { fmt.Printf("%s: %v\n", item.Key, item.Value) } // z_last: 3 // a_first: 1 // m_middle: 2 } ``` -------------------------------- ### Annotate YAML Source with Error Location Source: https://context7.com/goccy/go-yaml/llms.txt Use Path.AnnotateSource to highlight a specific node in YAML source with an arrow, useful for displaying validation error locations. Set 'colored' to true for ANSI color output. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { src := []byte(` server: host: localhost port: not-a-number timeout: 30 `) var cfg struct { Server struct { Host string `yaml:"host"` Port int `yaml:"port"` Timeout int `yaml:"timeout"` } `yaml:"server"` } if err := yaml.Unmarshal(src, &cfg); err != nil { // Annotate the offending field in the source path, _ := yaml.PathString("$.server.port") annotated, _ := path.AnnotateSource(src, false) // set true for ANSI color fmt.Printf("Validation failed:\n%s\n", string(annotated)) // Validation failed: // 2 | server: // 3 | host: localhost // > 4 | port: not-a-number // ^ // 5 | timeout: 30 } } ``` -------------------------------- ### YAML Encode with Implicit Anchor and Alias Source: https://github.com/goccy/go-yaml/blob/master/README.md Encodes Go structs with implicit `anchor` tags. Anchor names are derived from field names (lowercased). Aliases are automatically created for fields pointing to the same memory address. ```go type T struct { I int S string } var v struct { A *T `yaml:"a,anchor"` B *T `yaml:"b,anchor"` C *T `yaml:"c"` D *T `yaml:"d"` } v.A = &T{I: 1, S: "hello"} v.B = &T{I: 2, S: "world"} v.C = v.A // C has same pointer address to A v.D = v.B // D has same pointer address to B bytes, err := yaml.Marshal(v) if err != nil { //... } fmt.Println(string(bytes)) /* a: &a i: 1 s: hello b: &b i: 2 s: world c: *a d: *b */ ``` -------------------------------- ### Marshal Go value to YAML Source: https://context7.com/goccy/go-yaml/llms.txt Serializes a Go value into YAML bytes. Struct fields are lowercased by default; use `yaml` struct tags for custom names and options like `omitempty` and `flow`. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) type Address struct { Street string `yaml:"street"` City string `yaml:"city"` } type Person struct { Name string `yaml:"name"` Age int `yaml:"age"` Score float64 `yaml:"score,omitempty"` Address Address `yaml:"address,flow"` } func main() { p := Person{ Name: "Alice", Age: 30, Address: Address{Street: "1 Main St", City: "Springfield"}, } out, err := yaml.Marshal(p) if err != nil { panic(err) } fmt.Print(string(out)) // name: Alice // age: 30 // address: {street: 1 Main St, city: Springfield} } ``` -------------------------------- ### Annotating YAML Source with Errors Source: https://github.com/goccy/go-yaml/blob/master/README.md When unmarshalling YAML, errors can be annotated with the source code context using `path.AnnotateSource`. This helps in debugging by showing the exact location and content of the problematic YAML. ```go package main import ( "fmt" "github.com/goccy/go-yaml" ) func main() { yml := ` a: 1 b: "hello" ` var v struct { A int B string } if err := yaml.Unmarshal([]byte(yml), &v); err != nil { panic(err) } if v.A != 2 { // output error with YAML source path, err := yaml.PathString("$.a") if err != nil { panic(err) } source, err := path.AnnotateSource([]byte(yml), true) if err != nil { panic(err) } fmt.Printf("a value expected 2 but actual %d:\n%s\n", v.A, string(source)) } } ``` -------------------------------- ### YAML Encode with Explicit Anchor and Alias Source: https://github.com/goccy/go-yaml/blob/master/README.md Encodes Go structs with explicit `anchor` and `alias` struct tags. The library automatically sets up aliases if pointer addresses match. ```go type T struct { A int B string } var v struct { C *T `yaml:"c,anchor=x"` D *T `yaml:"d,alias=x"` } v.C = &T{A: 1, B: "hello"} v.D = v.C bytes, err := yaml.Marshal(v) if err != nil { panic(err) } fmt.Println(string(bytes)) /* c: &x a: 1 b: hello d: *x */ ``` -------------------------------- ### Path.AnnotateSource Source: https://context7.com/goccy/go-yaml/llms.txt Renders the YAML source with an arrow pointing to the node matched by the path. This is useful for annotating validation error messages. ```APIDOC ## Path.AnnotateSource — Error source annotation `(*Path).AnnotateSource(source []byte, colored bool) ([]byte, error)` renders the YAML source with an arrow pointing at the node matched by the path, for use in validation error messages. ``` -------------------------------- ### YAML Decode with `json` Tag Source: https://github.com/goccy/go-yaml/blob/master/README.md Decodes YAML into a Go struct, using the `json` struct tag for mapping. The `yaml` tag takes precedence if both are present. Note that not all `json` tag options are significant for YAML. ```go yml := `---` foo: 1 bar: c ` var v struct { A int `json:"foo"` B string `json:"bar"` } if err := yaml.Unmarshal([]byte(yml), &v); err != nil { //... } ```