Skip to content

keep-sorted

Keeps a list ordered. Eliminates “please sort this” review nits.

Attribute Value Default
keep-sorted asc, desc asc
keep-sorted-pattern regex; the (?P<value>…) group, or the whole match whole line
keep-sorted-format numeric text

keep-sorted-pattern and keep-sorted-format work only next to keep-sorted. On a block without it, they stop the run, because they would do nothing there.

# <block keep-sorted>
"apple",
"banana",
"cherry",
# </block>

Reorder any of those lines and the run fails.

Sort on part of the line rather than the whole thing, using a capture group named value:

items = [
# <block keep-sorted="asc" keep-sorted-pattern="id: (?P<value>\d+)">
"id: 1 orange",
"id: 2 apple",
"id: 3 banana",
# </block>
]

The ids are ordered, the fruit names are not, and the block passes — only the capture group is compared.

Lines that do not match the pattern are skipped.

Values are compared lexicographically by default, so "10" sorts before "2" — character by character, "1" < "2". keep-sorted-format="numeric" compares them as numbers instead:

numbers = [
# <block keep-sorted keep-sorted-format="numeric">
2
10
20
# </block>
]

It combines with keep-sorted-pattern to pull numbers out of mixed content:

items = [
# <block keep-sorted keep-sorted-format="numeric" keep-sorted-pattern="id: (?P<value>\d+)">
"id: 2 banana",
"id: 10 orange",
"id: 20 apple",
# </block>
]

Without keep-sorted-format="numeric" that block would fail, since "10" is lexicographically less than "2".

Values are compared as exact decimals of any length, so identifiers far beyond the range of a 64-bit float still order correctly. A value may carry a sign, a fractional part and an exponent (-1, .5, 1e9); inf and NaN are not numbers a source file can hold and are rejected.

_ is accepted as a digit separator, so long literals keep the spelling their language gives them:

const LIMITS: [u64; 3] = [
// <block keep-sorted keep-sorted-format="numeric" keep-sorted-pattern="(?P<value>[\d_]+)">
1_000,
1_000_000,
1_000_000_000,
// </block>
];

The pattern is what makes this block parse. Under numeric every line has to be a number, and the trimmed line here still carries the trailing comma the language requires; a value the pattern lifts out of the line does not.

A separator must sit between two digits — _1, 1_, 1__0 and 1_.0 are typos, not numbers.

  • Blank lines and lines the pattern does not match are ignored, not treated as out of order. A line whose match is empty is ignored as well. So is a line that matches a branch without the value group: ^(?:none|(?P<value>\w+))$ ignores the line none.
  • Comparison is on the trimmed line, so indentation does not affect ordering. A pattern is applied to the trimmed line too, so ^ and $ anchor to the entry rather than to the indentation.
  • An unrecognized keep-sorted or keep-sorted-format value is a hard error, not a violation.
  • Under numeric, a line whose value is not a number is a hard error too.
  • Pairs naturally with keep-unique on the same block.

← Validators · README