fig-schema
The schema layer over fig's value tree: what a
field expects — its type, its allowed values, and how to present it.
fig parses bytes into a fig::Value and edits losslessly; it has no notion of
"what is valid here". This crate adds that knowledge as a generic,
embedder-agnostic engine. It never learns the word "prov" or "flower": a
consumer defines its own constraint type and implements Validate on it, and
FieldRule/Schema are generic over that type — so the path-matching and
commit-time validation plumbing is written once, here, and reused everywhere.
What lives here
| Type | Role |
|---|---|
PathPat / SegPat |
Match a fig path, including every item of a list (EachItem) and whole subtrees (AnyDepth) |
FieldType |
The expected type, and type-directed coercion of an edit buffer (FieldType::coerce) |
Term / Cardinality / validate_enum |
A controlled vocabulary and the logic to check a value against one |
Validation / Issue / IssueKind |
Why a value failed, as data rather than prose |
Presentation / Icon / Tint |
Renderer-neutral display hints, carried but never interpreted |
Deliberately not here: a Constraint enum. Whether a field's constraint is a
controlled vocabulary, a reference into a workspace, a range, or a pattern is the
embedder's call.
Example
use Value;
use ;
// The embedder's own constraint type — the seam this crate is built around.
let schema = new;
let path = ;
let rule = schema.rule_for.expect;
assert!;
let rejected = rule.validate;
assert!;
assert_eq!;
Design notes
Rule precedence is declaration order. Schema::rule_for returns the first
matching rule, so list a specific rule before a broader one that would also match.
Retired terms warn, they don't reject. A Term marked retired is still a
known value — it is merely no longer offered in a picker. A document that
already holds one stays committable, even under a closed vocabulary.
Validation failures are structured. Issue carries the offending value, the
kind of failure, and a near-miss suggestion when one exists. Display renders
a reasonable English default; a frontend that wants to localize the text, or
offer the suggestion as a one-tap correction, has the parts it needs.
Coercion falls back to text. FieldType::coerce never destroys an edit: a
value that doesn't fit the declared type becomes a Value::Str, leaving the
caller's own reparse as the final backstop.
Licence
Licensed under either of Apache License, Version 2.0 or MIT license at your option.