Field validation for human-input requests: a validator is a FUNCTION.
A field carries :validate — one function or a list of them. Each one is
called with the COERCED value, or with the value and the whole coerced
field id -> value map when it asks for a second argument, and answers:
nil or true — the value is fine.false — "is not valid", the message of last resort. Say something better.Validators run in the order they were written and the FIRST message wins, so
a field's :validate list reads like a checklist.
Validation is code, not data, and it never crosses the wire. The ENGINE is
the only authority: it runs every validator when a form is CONFIRMED
(com.blockether.vis.internal.human-input/submit!) and hands the surfaces
the errors it found, keyed by field. Neither the TUI band nor the companion
app owns a validation rule or re-checks anything as the operator types —
they show the engine's verdict, and drop a field's error the moment that
field is touched again, so nobody is scolded mid-word about a value they are
still typing.
A validator NEVER fires on a blank value. Emptiness is :is-required's
single job; a check that also rejected "" would quietly make every optional
field mandatory.
Field validation for human-input requests: a validator is a FUNCTION. A field carries `:validate` — one function or a list of them. Each one is called with the COERCED value, or with the value and the whole coerced `field id -> value` map when it asks for a second argument, and answers: - `nil` or `true` — the value is fine. - a string — that string IS the field's error message. - `false` — "is not valid", the message of last resort. Say something better. - a throw — "could not be validated: …", because swallowing it would ACCEPT the value the validator was written to refuse. Validators run in the order they were written and the FIRST message wins, so a field's `:validate` list reads like a checklist. Validation is code, not data, and it never crosses the wire. The ENGINE is the only authority: it runs every validator when a form is CONFIRMED ([[com.blockether.vis.internal.human-input/submit!]]) and hands the surfaces the errors it found, keyed by field. Neither the TUI band nor the companion app owns a validation rule or re-checks anything as the operator types — they show the engine's verdict, and drop a field's error the moment that field is touched again, so nobody is scolded mid-word about a value they are still typing. A validator NEVER fires on a blank value. Emptiness is `:is-required`'s single job; a check that also rejected "" would quietly make every optional field mandatory.
(check validators value values)The first message a validator has against value, or nil when every one of
them accepts it. values is the whole coerced field id -> value map, which
is how a confirmation field compares itself with the field it confirms.
The first message a validator has against `value`, or nil when every one of them accepts it. `values` is the whole coerced `field id -> value` map, which is how a confirmation field compares itself with the field it confirms.
(normalize-validators raw fail!)raw — one validator or a list of them — as the field's vector of
two-argument functions, or nil when the field declares none. fail! reports
a bad validator the way the surrounding spec reports every other mistake.
The arity question is asked HERE, once, while the spec is being read: a
validator that takes only the value is wrapped into the two-argument shape
check calls, and one that can take neither shape is refused before a
human is ever shown the form it would have crashed.
`raw` — one validator or a list of them — as the field's vector of two-argument functions, or nil when the field declares none. `fail!` reports a bad validator the way the surrounding spec reports every other mistake. The arity question is asked HERE, once, while the spec is being read: a validator that takes only the value is wrapped into the two-argument shape [[check]] calls, and one that can take neither shape is refused before a human is ever shown the form it would have crashed.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |