A sweet little formatter for YAML
go install github.com/chainguard-dev/yam@latest
To update file contents to match your formatting configuration, just specify one or more YAML files.
yam a.yaml b.yaml
You can also specify directories with YAML files in them. (Yam doesn't recurse through directories in directories.)
yam ./dir-with-some-yamls
And you can format files in the current working directory if you don't pass any arguments:
yam
To lint files instead of formatting them, just add --lint
to the command. With this flag, Yam doesn't make any changes to your files, but it will exit 1
if any files don't match your formatting configuration.
yam a.yaml --lint
When linting, if Yam finds any files that don't pass the lint check, it will output a diff of what it got vs. what it expected to see.
To expect a gap (empty line) in between child elements of a given node, just pass a yq
-style path to the node, using --gap
. You can use this flag as many times as needed.
yam a.yaml --gap '.'
yam a.yaml --gap '.foo.bar'
yam a.yaml --gap '.people[].address'
yam a.yaml --gap '.recipes[0].ingredients'
yam a.yaml --gap '.types.*.inputs'
You can also set the indent size (number of spaces) using --indent
. Yam uses 2-space indentation by default.
yam a.yaml --indent 4
Yam will also look for a .yam.yaml
file in the current working directory as a source of configuration. Using a config file is optional. CLI flag values take priority over config file values. The config file can be used to configure indent
and gap
values only.
Example .yam.yaml
:
indent: 4 # Defaults to 2
gap: # Defaults to none
- "."
- ".users"
Yam has a special YAML encoder it uses to handle formatting as it writes out YAML bytes. This encoder is configurable.
Yam bases its encoder on the YAML encoder from https://github.com/go-yaml/yaml, and uses this library's yaml.Node
type as the input to encoding operations.
This means you're able to decode data using https://github.com/go-yaml/yaml, modify data as needed, and then encode the yaml.Node
using yam's encoder instead. This is nifty if you want to write YAML data that's correctly formatted from the beginning.
For example, before:
import (
// ...
"gopkg.in/yaml.v3"
)
func someFunction(myData yaml.Node, w io.Writer) {
enc := yaml.NewEncoder(w)
// use the encoder!
_ = enc.Encode(myData)
}
And after:
import (
// ...
"github.com/chainguard-dev/yam/pkg/yam/formatted"
)
func someFunction(myData yaml.Node, w io.Writer) {
enc := formatted.NewEncoder(w)
// use the encoder!
_ = enc.Encode(myData)
}
Yam's encoder has chainable methods that can be used for configuring its options.
For example:
enc := formatted.NewEncoder(w).SetIndent(2).SetGapExpressions(".", ".users")
You can also tell the encoder to behave similarly to the yam
command, in that a .yam.yaml
is automatically read if available.
enc := formatted.NewEncoder(w).AutomaticConfig()