Name a reusable constraint
Build a `uint8`/`port` vocabulary as a `type()`-marked block of ordinary fields.
Rendered from
docs/how-to/name-a-reusable-constraint.md
in the engine repository, where a correction belongs, and where the
test suite executes every example on this page.
aontu has no uint8, int8 or port keyword, and does not need
one: a constraint is a value, so a name for one is a field. A
type()-marked block gives you a library of them that unifies like
everything else and emits nothing:
type: type({})
type: {
uint8: integer & min(0) & max(255)
int8: integer & min(-128) & max(127)
port: integer & min(1) & max(65535)
}
listen: $.type.port
listen: 8080
{ "listen": 8080 }
The block is absent from the output and present for unification, and
the key name is not reserved: type here is a field that happens to
be type()-marked, so defs or schema reads the same.
An out-of-range value is refused at the field that holds it. Write
the same document with listen: 70000 as types.aon:
type: type({})
type: {
uint8: integer & min(0) & max(255)
int8: integer & min(-128) & max(127)
port: integer & min(1) & max(65535)
}
listen: $.type.port
listen: 70000
$ aontu types.aon
[aontu/constraint]: Cannot unify values at path $.listen
...
Cannot unify value: 70000 with value: integer&min(1)&max(65535)
...
$ echo $?
1
The refusal states the normalised residual the value had to satisfy, not the alias’s name: the constraint travelled, the label did not.
Lead with the kind. min(0) & max(255) alone bounds a number, so
1.5 satisfies it:
loose: type({})
loose: byteish: min(0) & max(255)
a: $.loose.byteish
a: 1.5
{ "a": 1.5 }
A sized integer is integer & min(0) & max(255), which is why every
alias above starts with integer.
Aliases are ordinary values, so they compose: one can be defined in
terms of another, and a use site can narrow one further
($.type.uint8 & max(15)). For a file-local name that skips the
path entirely, %port = integer & min(1) & max(65535) declares an
alias used as bare %port.
The idiom is specified in Named constraint
aliases; the
type() mark’s mechanics are the subject of keep schema out of the
output.