Documentation
¶
Overview ¶
Package fyaml provides a programmatic API for compiling directory-structured YAML/JSON files into a single document.
fyaml compiles a directory tree of YAML or JSON files into a single deterministic document. Directory names become map keys, file names (without extension) become nested keys, and files starting with @ merge their contents into the parent directory.
Example:
package main
import (
"context"
"fmt"
"log"
"github.com/jksmth/fyaml"
)
func main() {
result, err := fyaml.Pack(context.Background(), fyaml.PackOptions{
Dir: "./config",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(string(result))
}
Error Handling:
The package defines sentinel errors for programmatic error handling:
- ErrDirectoryRequired
- ErrInvalidFormat
- ErrInvalidMode
- ErrInvalidMergeStrategy
- ErrInvalidIndent
- ErrCheckMismatch
Use errors.Is() to check for specific errors:
result, err := fyaml.Pack(ctx, opts)
if err != nil {
if errors.Is(err, fyaml.ErrInvalidFormat) {
// Handle invalid format
}
}
err := fyaml.Check(generated, expected, fyaml.CheckOptions{Format: fyaml.FormatYAML})
if err != nil {
if errors.Is(err, fyaml.ErrCheckMismatch) {
// Handle output mismatch
}
}
For more examples, see the examples in the test files.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrDirectoryRequired is returned when Dir is empty or not provided. ErrDirectoryRequired = errors.New("directory is required") // ErrInvalidFormat is returned when Format is not FormatYAML or FormatJSON. ErrInvalidFormat = errors.New("invalid format") // ErrInvalidMode is returned when Mode is not ModeCanonical or ModePreserve. ErrInvalidMode = errors.New("invalid mode") // ErrInvalidMergeStrategy is returned when MergeStrategy is not MergeShallow or MergeDeep. ErrInvalidMergeStrategy = errors.New("invalid merge strategy") // ErrInvalidIndent is returned when Indent is less than 1. ErrInvalidIndent = errors.New("invalid indent") // ErrCheckMismatch is returned when Check() finds differences between // generated output and expected content. ErrCheckMismatch = errors.New("output mismatch") )
Sentinel errors for programmatic error handling. Use errors.Is() to check for specific errors:
result, err := fyaml.Pack(ctx, opts)
if err != nil {
if errors.Is(err, fyaml.ErrInvalidFormat) {
// Handle invalid format error
}
}
Functions ¶
func Check ¶
func Check(generated []byte, expected []byte, opts CheckOptions) error
Check compares generated output with expected content using exact byte comparison. Returns ErrCheckMismatch if contents don't match. Whitespace differences will be detected as mismatches. opts.Format is used to normalize empty expected content to match format-specific empty output. opts defaults to FormatYAML if Format is empty.
Example ¶
package main
import (
"log"
"github.com/jksmth/fyaml"
)
func main() {
generated := []byte("key: value\n")
expected := []byte("key: value\n")
err := fyaml.Check(generated, expected, fyaml.CheckOptions{Format: fyaml.FormatYAML})
if err != nil {
log.Fatal(err)
}
// Output matches
}
Output:
Example (EmptyJSON) ¶
package main
import (
"log"
"github.com/jksmth/fyaml"
)
func main() {
// Empty JSON output is normalized to "null\n"
generated := []byte("null\n")
expected := []byte{} // Empty
err := fyaml.Check(generated, expected, fyaml.CheckOptions{Format: fyaml.FormatJSON})
if err != nil {
log.Fatal(err)
}
// Empty expected is normalized, so it matches
}
Output:
Example (Mismatch) ¶
package main
import (
"errors"
"fmt"
"github.com/jksmth/fyaml"
)
func main() {
generated := []byte("key: value\n")
expected := []byte("key: different\n")
err := fyaml.Check(generated, expected, fyaml.CheckOptions{Format: fyaml.FormatYAML})
if errors.Is(err, fyaml.ErrCheckMismatch) {
fmt.Println("Output mismatch detected")
}
}
Output: Output mismatch detected
func Pack ¶
func Pack(ctx context.Context, opts PackOptions) ([]byte, error)
Pack compiles a directory of YAML/JSON files into a single document.
Pack is safe for concurrent use by multiple goroutines, provided that each call uses a separate PackOptions instance. If multiple goroutines share the same Logger instance, log output may interleave (this does not affect correctness, only log formatting).
The context can be used to cancel the operation. If the context is canceled, Pack will return an error wrapping context.Canceled or context.DeadlineExceeded.
PackOptions.Dir is required. All other options have sensible defaults:
- Format defaults to FormatYAML
- Mode defaults to ModeCanonical
- MergeStrategy defaults to MergeShallow
- Indent defaults to 2
- Logger defaults to a no-op logger if nil
Returns the packed document as bytes, or an error if packing fails.
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/jksmth/fyaml"
)
func main() {
// Pack a directory with default options (YAML output, canonical mode)
result, err := fyaml.Pack(context.Background(), fyaml.PackOptions{
Dir: "./config",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(string(result))
}
Output:
Example (ErrorHandling) ¶
package main
import (
"context"
"errors"
"fmt"
"github.com/jksmth/fyaml"
)
func main() {
_, err := fyaml.Pack(context.Background(), fyaml.PackOptions{
Dir: "",
})
if err != nil {
if errors.Is(err, fyaml.ErrDirectoryRequired) {
// Handle directory required error
fmt.Println("Directory is required")
} else if errors.Is(err, fyaml.ErrInvalidFormat) {
// Handle invalid format error
fmt.Println("Invalid format specified")
}
}
}
Output:
Example (Minimal) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/jksmth/fyaml"
)
func main() {
// Minimal usage - only directory required, all other options use defaults
result, err := fyaml.Pack(context.Background(), fyaml.PackOptions{
Dir: "./config",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(string(result))
}
Output:
Example (WithLogger) ¶
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/jksmth/fyaml"
)
func main() {
// Pack with a logger for verbose output
logger := fyaml.NewLogger(os.Stderr, true)
result, err := fyaml.Pack(context.Background(), fyaml.PackOptions{
Dir: "./config",
Logger: logger,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(string(result))
}
Output:
Example (WithOptions) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/jksmth/fyaml"
)
func main() {
// Pack with all options specified
result, err := fyaml.Pack(context.Background(), fyaml.PackOptions{
Dir: "./config",
Format: fyaml.FormatJSON,
Mode: fyaml.ModePreserve,
MergeStrategy: fyaml.MergeDeep,
EnableIncludes: true,
ConvertBooleans: true,
Indent: 4,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(string(result))
}
Output:
Types ¶
type CheckOptions ¶
type CheckOptions struct {
// Format specifies the format used for normalization.
// Defaults to FormatYAML if empty.
// Used to normalize empty expected content to match format-specific empty output.
Format Format
}
CheckOptions configures how Check compares content. Zero value provides default behavior (exact byte comparison, YAML format).
type Format ¶
type Format string
Format specifies the output format for the packed document.
Example ¶
package main
import (
"github.com/jksmth/fyaml"
)
func main() {
// Use FormatYAML for YAML output (default)
_ = fyaml.FormatYAML
// Use FormatJSON for JSON output
_ = fyaml.FormatJSON
}
Output:
func ParseFormat ¶
ParseFormat parses a format string and returns the corresponding Format. Returns an error if the format is invalid.
Example ¶
package main
import (
"log"
"github.com/jksmth/fyaml"
)
func main() {
format, err := fyaml.ParseFormat("yaml")
if err != nil {
log.Fatal(err)
}
_ = format // Use format
}
Output:
type Logger ¶
type Logger interface {
// Debugf logs verbose/debug information (shown when verbose enabled)
Debugf(format string, args ...interface{})
// Warnf logs warnings (always shown)
Warnf(format string, args ...interface{})
}
Logger defines the logging interface for fyaml. All output is written to the configured io.Writer (typically os.Stderr).
type MergeStrategy ¶
type MergeStrategy string
MergeStrategy controls how maps are merged when multiple files contribute to the same key.
Example ¶
package main
import (
"github.com/jksmth/fyaml"
)
func main() {
// Use MergeShallow for "last wins" behavior (default)
_ = fyaml.MergeShallow
// Use MergeDeep for recursive nested map merging
_ = fyaml.MergeDeep
}
Output:
const ( // MergeShallow uses "last wins" behavior - later values completely replace earlier ones (default). MergeShallow MergeStrategy = "shallow" // MergeDeep recursively merges nested maps, only replacing values at the leaf level. MergeDeep MergeStrategy = "deep" )
func ParseMergeStrategy ¶
func ParseMergeStrategy(s string) (MergeStrategy, error)
ParseMergeStrategy parses a merge strategy string and returns the corresponding MergeStrategy. Returns an error if the strategy is invalid.
Example ¶
package main
import (
"log"
"github.com/jksmth/fyaml"
)
func main() {
strategy, err := fyaml.ParseMergeStrategy("deep")
if err != nil {
log.Fatal(err)
}
_ = strategy // Use strategy
}
Output:
type Mode ¶
type Mode string
Mode controls the output behavior of the packed document.
Example ¶
package main
import (
"github.com/jksmth/fyaml"
)
func main() {
// Use ModeCanonical for sorted keys, no comments (default)
_ = fyaml.ModeCanonical
// Use ModePreserve for authored order and comments
_ = fyaml.ModePreserve
}
Output:
func ParseMode ¶
ParseMode parses a mode string and returns the corresponding Mode. Returns an error if the mode is invalid.
Example ¶
package main
import (
"log"
"github.com/jksmth/fyaml"
)
func main() {
mode, err := fyaml.ParseMode("preserve")
if err != nil {
log.Fatal(err)
}
_ = mode // Use mode
}
Output:
type PackOptions ¶
type PackOptions struct {
// Dir is the directory to pack (required).
Dir string
// Format specifies the output format. Defaults to FormatYAML if empty.
Format Format
// Mode controls output behavior. Defaults to ModeCanonical if empty.
Mode Mode
// MergeStrategy controls merge behavior. Defaults to MergeShallow if empty.
MergeStrategy MergeStrategy
// EnableIncludes processes !include, !include-text, and <<include()>> directives.
EnableIncludes bool
// ConvertBooleans converts unquoted YAML 1.1 booleans (on/off, yes/no) to YAML 1.2 (true/false).
ConvertBooleans bool
// EnableAnchors enables anchor references across different files.
// When enabled, anchors defined in one file can be referenced as aliases in another file.
EnableAnchors bool
// Indent is the number of spaces for indentation. Defaults to 2 if zero.
Indent int
// Chroot is the security/confinement boundary (like chroot).
// If empty, defaults to Dir (current behavior).
// If set, allows includes and other operations from outside Dir but within Chroot.
// Does NOT affect what gets packed - that's still controlled by Dir.
// Does NOT affect path resolution - relative paths in !include tags remain
// relative to the file containing the tag (for portability).
Chroot string
// Logger is an optional logger for verbose output. If nil, no logging is performed.
Logger Logger
}
PackOptions configures how a directory is packed into a single document.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
fyaml
command
|
|
|
internal
|
|
|
filetree
Package filetree provides filesystem traversal for FYAML packing.
|
Package filetree provides filesystem traversal for FYAML packing. |
|
include
Package include provides file inclusion pre-processing for FYAML packing.
|
Package include provides file inclusion pre-processing for FYAML packing. |
|
logger
Package logger provides a simple logging interface for fyaml.
|
Package logger provides a simple logging interface for fyaml. |
|
version
Package version provides version information for fyaml.
|
Package version provides version information for fyaml. |