A sweet little formatter for YAML
go install github.com/chainguard-dev/yam@latestTo update file contents to match your formatting configuration, just specify one or more YAML files.
yam a.yaml b.yamlYou can also specify directories with YAML files in them. (Yam doesn't recurse through directories in directories.)
yam ./dir-with-some-yamlsAnd you can format files in the current working directory if you don't pass any arguments:
yamTo 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 --lintWhen 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 4You can also sort sequences so that for example you get alphabetized packages
list using --sort where --sort takes in a yq-style path to the node that
should be sorted.
yam a.yaml --sort .packagesNote This is only meant to be used for scalars, behavior for objects is not supported.
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()