Formatter¶
ryl format rewrites YAML files in place to a consistent layout. The formatter edits
only the spans that are off-style rather than reprinting the document, so the first run
on an existing project produces a small diff, and every later run on formatted files
changes nothing.
Biome does not format YAML, so there is no Biome YAML style to migrate.
ryl format¶
# Format every YAML file under the current directory, in place
ryl format .
# Write nothing; exit 1 if any file would change, listing why
ryl format --check .
# Write nothing; print a unified diff of the changes
ryl format --diff path/to/file.yaml
# Read stdin, write the formatted text to stdout
cat file.yaml | ryl format - --stdin-filename file.yaml
Inputs, file discovery, .gitignore handling and config discovery are the same as
ryl check. Unlike ryl check, ryl format needs no config: with none it formats
with the defaults below.
--check reports each line ryl format would change as a diagnostic from the rule
whose fix changes it, through the same reporters as ryl check, so it honours
--output-format and [output] and picks the GitHub format in
GitHub Actions.
Already formatted files are skipped on later runs through the
content-hash cache. --check can also
reuse a clean result; --diff always generates the requested diff.
Guarantees¶
Every edit ryl format makes is checked by property tests to be:
- Value-preserving. The document loads to the same data, with the same tags, anchors, aliases, key order and duplicate keys, resolved under the document's YAML version.
- Comment-safe. Every comment stays beside the node it annotates.
- Idempotent. Formatting formatted output changes nothing.
A file that does not parse is left alone and reported on stderr as
skipped by ryl format.
See File encodings for encoding
preservation and --check/--diff behavior when a text patch cannot be emitted.
A document-prefix BOM stays before an added --- marker, including in later
documents; the BOM does not count toward indentation. Diagnostic columns still
count a document-prefix BOM that remains in the source text.
The same exit behavior applies when a patch is skipped because the YAML ends in a
bare carriage return or the filename cannot be represented in a diff header.
Configuration¶
ryl format reads the [format] table of the same .ryl.toml, ryl.toml or
pyproject.toml ([tool.ryl.format]) that ryl check uses. A YAML
config cannot set it, so YAML-configured projects get the defaults.
[format]
quote-style = "single"
line-ending = "lf"
document-start = "preserve"
document-end = "preserve"
fold-long-lines = false
brace-spacing = false
comment-spacing = 2
comment-starting-space = "add"
max-blank-lines = 2
preview = false
sequence-style = "preserve"
mapping-style = "preserve"
indent-sequences = true
dash-on-own-line = false
| Key | Default | Values | What it sets |
|---|---|---|---|
quote-style |
"single" |
"single", "double", "preserve" |
The quote used where a string needs quoting; "preserve" leaves all quoting alone. See Quote style. |
line-ending |
"lf" |
"lf", "cr-lf", "native", "auto" |
Line endings, including the final newline; "native" is the platform's, and "auto" keeps the ending most of the file's lines use ("lf" on a tie or a file without line breaks). |
document-start |
"preserve" |
"add", "preserve" |
Whether to add a missing --- document start marker. |
document-end |
"preserve" |
"add", "preserve" |
Whether to add a missing ... document end marker. |
fold-long-lines |
false |
true, false |
Whether to split plain, quoted and folded (>) scalar lines longer than line-length at single spaces. See Long lines. |
brace-spacing |
false |
true, false |
Whether to write one space inside non-empty flow mapping braces, { a: 1 }. Empty braces and brackets stay unpadded. |
comment-spacing |
2 |
1 to 255 |
Exact number of spaces between content and an inline comment. |
comment-starting-space |
"add" |
"add", "preserve" |
Whether to add a missing space after a comment's #. |
max-blank-lines |
2 |
0 to 255 |
Most blank lines kept in a row between content lines; leading and trailing runs are removed. Scalar content is preserved, including keep-chomping (\|+/>+) tails; clip/strip tails can be trimmed. |
indent-sequences |
true |
true, false |
Whether a block sequence under a mapping key is indented past the key; false keeps it flush. |
dash-on-own-line |
false |
true, false |
Whether a block mapping in a block sequence starts on the line after its -; false joins them as - name: web. |
preview |
false |
true, false |
Opt in to style changes before they become stable. See Preview style. |
sequence-style |
"preserve" |
"preserve", "block", "flow" |
Collection style for sequences. See Collection style. |
mapping-style |
"preserve" |
"preserve", "block", "flow" |
Collection style for mappings. See Collection style. |
The top-level line-length and indent-width keys are shared with ryl check, where
they set the defaults for the line-length and indentation rules (see
Quick start). ryl format
re-indents every block level to indent-width, and uses both as the fold width and
continuation indent under fold-long-lines.
Without indent-width, an inline value under an explicit block key (? key followed by
: value) uses 2 if the value establishes the file's consistent indentation step.
An explicit key directly inside a sequence item does not establish that step.
Otherwise, ryl format keeps each file's own width: of the widths 2 to 8, the one whose
re-indent changes the fewest lines, block scalar bodies and comments included. A tie,
or a file the re-indent leaves alone at every width, falls back to 2.
A file mostly at 4 with one block at 2 is re-indented to 4.
If restyling a collection changes which width best fits the file, the formatter
re-detects the width and completes the re-indent in the same run.
If the detected width would leave inconsistent indentation, ryl format keeps that
document's indentation and reports the sites it cannot fix.
The rest of the layout is fixed:
| Concern | ryl format writes |
|---|---|
| Own-line comments | Aligned with the content they precede |
| Flow collections | No spaces inside [] or empty {}, and inside other {} per brace-spacing; no space before a comma, one after |
| Blank lines | None at the start or end of the file |
| Line ends | Remove trailing whitespace outside scalar content; add a final newline |
After -, ? and : |
One space, re-indenting a compact collection that hangs on it |
Block scalar headers lose trailing spaces and tabs. A header or body at EOF gains
a final newline and, with document-end = "add", a ... marker.
An indentation-only final line loses its spaces when they are not scalar content.
For keep-chomped scalars (|+ or >+), the formatter adds a line break after
removing those spaces to preserve the YAML 1.2 reference parser's value.
When adding a document end marker, it removes only indentation spaces from a final
blank block-scalar line. A root explicit-indent scalar keeps value-bearing spaces;
the marker is left unfixed if appending it would change the reference value.
A document that a tab indents, or that re-indenting would parse differently, is left as it is and named on stderr.
Default profile¶
With no [format] table, ryl format writes the profile below. It preserves
existing document start markers, can remove redundant quotes or switch required
double quotes to single, and can indent flush sequences. Migration writes
quote-style = "preserve" when quoted-strings is disabled in the source preset.
| Default | Why |
|---|---|
quote-style = "single" |
yamlfix's default; see Quote style for when it applies |
line-ending = "lf" |
The default of prettier |
document-start = "preserve" |
prettier keeps a file's markers as written |
document-end = "preserve" |
No formatter adds ...; prettier keeps it |
fold-long-lines = false |
Prose keeps its line breaks, as under prettier's proseWrap: "preserve" |
brace-spacing = false |
yamlfix also leaves braces unpadded; prettier pads them |
comment-spacing = 2 |
The default of ruff and yamlfix |
comment-starting-space = "add" |
Adds a space after # |
max-blank-lines = 2 |
Keeps short gaps between content |
sequence-style = "preserve" |
Restyling a collection is opt-in |
mapping-style = "preserve" |
Restyling a collection is opt-in |
indent-sequences = true |
prettier also indents them |
dash-on-own-line = false |
prettier writes - name: web |
preview = false |
Preview styles are opt-in, as in ruff |
line-length = 80 |
The default of prettier |
indent-width = 2 |
The default of prettier and yamlfix, for a file that shows no width of its own |
| Fixed layout above | Every formatter probed agrees |
Long lines¶
With fold-long-lines = true, ryl format splits scalar lines longer than the top-level
line-length (default 80) at single spaces. Folding applies to plain and quoted values
in block context, and folded (>) scalar lines at their content indent. For plain and
quoted values, the new line takes the indent of the scalar's existing continuation
lines, or else sits indent-width past the column of the collection that owns the value:
# before
items:
- description: This single line is well over eighty characters wide and so the formatter should fold it.
# after, with fold-long-lines = true
items:
- description: This single line is well over eighty characters wide and so the
formatter should fold it.
Folded (>) scalars keep their content indent; more-indented lines stay whole.
Keys, flow collections, literal (|) scalars, and words with no space to break at
stay as they are. Folding ignores the line-length rule's own options, and
ryl check --fix never folds.
Collection style¶
With sequence-style or mapping-style set to "block", ryl format rewrites flow
collections of that kind in block style, indented by indent-width, copying each
entry's text. An inline comment after the collection moves to its key's line:
When the width is inferred, a conversion stays in flow style with a notice if the
result would fail the indentation rule's consistent-width check. A compact sequence
mapping with explicit keys can fix the lint rule's inferred step independently of the
formatter's detected width.
Empty [] and {} stay flow. A collection that holds a comment, a multi-line entry, a
collection or empty key, or an entry some loaders would read differently in block style
stays as written, and ryl format says why on stderr.
If the document cannot be re-indented safely, flow collections in that document stay
flow, with a refusal notice. Block-to-flow conversions and conversions in other
documents can still proceed.
When a nested block scalar has only blank body lines before content dedents past its
header, ryl format leaves the file unchanged and reports a refusal: the YAML
reference parser can still read the dedented text as scalar content. A sibling key
at the same indent can trigger the same refusal when a sequence dash may move. The same
protection applies when indented # text and blank lines form scalar content.
ryl check --fix also reports the file, line and reason on stderr and leaves the
file unchanged, apart from independently safe key ordering. In Markdown the refusal
covers only the embedded YAML region that holds the scalar; other regions are still
formatted and fixed.
Compact explicit-key sequences with blank scalar lines are refused when spacing the
header would change the scalar's content indent.
For other block scalars, re-indentation moves value-bearing blank-line spaces with
the scalar header.
With "flow", a block collection of scalars and aliases that is not the document root
becomes one flow line, such as items: [one, two], when it holds no comment and the
line fits line-length. Block scalars, multi-line or empty entries, and plain scalars
holding ,[]{} or starting with : or ? keep it block. Flow collections already
written are left alone, even long ones.
Quote style¶
ryl format quotes a string only where its plain form would load as something else,
using quote-style:
# after, with quote-style = "single"
a: x
b: '123'
c: it's
d: "tab\there"
e: "it's: x"
f: 'say "hi": x'
A string that needs quoting takes whichever quotes avoid an escape: single when it
contains ", double when it contains only ', else quote-style. A string that needs
escape sequences stays double-quoted. Physical line breaks alone do not require
double quotes: conversion to single quotes preserves the continuation lines and blank
lines, including their YAML folding. A string that YAML 1.1 loads
as a boolean, such as "yes", "NO" or "on", keeps its quotes, so truthy stays
clean. So do "y", "Y", "n" and "N", which go-yaml v2, and so Kubernetes, loads
as booleans. Mapping keys follow the same rules.
Preview style¶
preview = true opts in to style changes before they become stable. As in ruff, the
stable style changes only in a minor release, by promoting a preview style, while a
preview style can change in any release. A fix for invalid output, a changed value or a
lost comment can ship in any release. No preview styles exist yet, so preview changes
nothing today.
YAML in Markdown¶
ryl format formats YAML front matter and fenced YAML blocks in Markdown files matched
by [files].markdown, as described in YAML in Markdown, or every input
given --markdown, as with ryl check.
If formatting would create a line that closes a YAML fence, ryl leaves that region
unchanged and names the refusal on stderr. Other regions still format. The same guard
applies to editor formatting. When formatting would change a region that mixes CRLF
and LF line endings, ryl leaves the region unchanged with a notice and --check /
--diff exit 1. An already formatted mixed region is quiet.
Suppression¶
ryl format honours the same inline directives as ryl check: a
# ryl disable-file comment leaves the file alone, and
# ryl disable rule:quoted-strings or disable-line rule:quoted-strings stops
that rule's formatting where it applies. There is no format-only directive.
Lint configuration's [[lint.per-line-ignores]] and [lint.per-file-ignores] suppress
lint findings and safe check --fix edits, but do not gate ryl format.
Conflicting lint rules¶
The formatter's layout is also checked by lint rules, and they stay lint rules:
ryl check still reports them, and ryl check --fix still fixes the fixable ones. When
one of them is enabled with options that reject what ryl format writes, every
ryl format run warns on stderr, for example:
warning: the quoted-strings lint rule's options are incompatible with the formatter's `[format] quote-style = "single"`. Disable quoted-strings when using `ryl format`, or set its options `quote-type = "single"`, `required = "only-when-needed"`, `allow-double-quotes-for-escaping = true`, `allow-quoted-quotes = true`.
--no-warnings silences it. A rule left at its defaults conflicts only where the table
says so.
| Rule | Conflicts with ryl format when |
|---|---|
braces |
forbid is set and [format] mapping-style is not "preserve", min-spaces-inside-empty is above 0, or min-spaces-inside to max-spaces-inside excludes the brace-spacing padding (0, or 1 when true) |
brackets |
forbid is set and [format] sequence-style is not "preserve", or min-spaces-inside or min-spaces-inside-empty is above 0 |
commas |
min-spaces-after is above 1, or max-spaces-after is 0 |
comments |
min-spaces-from-content is above [format] comment-spacing, or max-spaces-from-content is below it (-1, the default, is unlimited); or ignore-shebangs = false while require-starting-space = true under [format] comment-starting-space = "add", since a shebang keeps its #! |
comments-indentation |
Never |
document-start |
present = false with [format] document-start = "add" |
document-end |
present = false with [format] document-end = "add" |
empty-lines |
max is below [format] max-blank-lines |
new-line-at-end-of-file |
Never |
new-lines |
type resolves to a different ending from [format] line-ending, or line-ending = "auto", which writes either |
quoted-strings |
See below; never under quote-style = "preserve" |
trailing-spaces |
Never |
colons |
max-spaces-after is 0 |
hyphens |
max-spaces-after is 0, or dash-on-own-line = true while [format] dash-on-own-line = false |
indentation |
spaces is a number other than indent-width, or any number while indent-width is unset; or indent-sequences is the opposite of [format] indent-sequences |
line-length |
Never; folding is opt-in and leaves lines it cannot break |
The table compares formatter settings with lint options; it does not promise every
finding can be fixed. A keep-chomped (|+/>+) tail can exceed empty-lines max, and
trailing spaces inside a block scalar can remain findings after ryl format and
ryl check --fix because removing them would change the scalar value.
quoted-strings accepts the formatter's output when required is "only-when-needed"
or false, extra-required is empty, and quote-type is either "any" or matches
quote-style. A quote-type of "single" or "double" also needs
allow-quoted-quotes = true, for strings quoted to avoid an escape, and "single"
needs allow-double-quotes-for-escaping = true, for the strings that need escapes. The rule's
defaults (required = true) conflict:
These quoted-strings configs accept the formatter's output:
[lint.rules.quoted-strings]
quote-type = "single"
required = "only-when-needed"
allow-double-quotes-for-escaping = true
allow-quoted-quotes = true
[format]
quote-style = "double"
[lint.rules.quoted-strings]
quote-type = "double"
required = "only-when-needed"
allow-quoted-quotes = true
A YAML config cannot set allow-double-quotes-for-escaping, so there use
quote-type: any:
The other conflicts follow the table:
[format]
brace-spacing = true
[lint.rules.braces]
min-spaces-inside = 1
max-spaces-inside = 1
min-spaces-inside-empty = 0
max-spaces-inside-empty = 0
The other eleven rules check things ryl format never changes, so they never conflict
with it: anchors,
block-scalar-chomping,
empty-values, float-values,
key-duplicates, key-ordering,
merge-keys, octal-values,
tags, truthy and
unicode-line-breaks. truthy and key-ordering keep
their ryl check --fix fixes.
Recommended lint config¶
To lint alongside ryl format, start from the
recommended starter config,
which enables only rules the formatter never touches and leaves layout to
ryl format --check.
Running with ryl check --fix¶
Run ryl check --fix before ryl format, in a pre-commit or prek config as on the
command line, so the formatter has the last word on layout; ruff gives the same order
for ruff check --fix and ruff format. Re-indenting can still push a line past
line-length, which the line-length rule then reports (see
Conflicting lint rules), so lint a formatted file rather than
relying on the check that ran before formatting.
Exit codes¶
| Code | ryl format |
ryl format --check / --diff |
|---|---|---|
0 |
Files formatted, or nothing to do | No file would change; a symlinked input is refused on stderr but still exits 0 |
1 |
Not used | At least one file would change, a mixed-newline Markdown region needs formatting, or a ragged Markdown region retains layout findings |
2 |
A usage or config error, an unreadable or unwritable file, or a file no [files] glob matches |
A usage or config error, an unreadable file, or a file no [files] glob matches |
A failed write names the file on stderr; formatting continues with the remaining files. A file skipped for a syntax error does not change the exit code.