Field builders

Every option of f.text, f.number, f.enum and the rest.

All builders live on f from @qnot/core and return a FieldDef. Pass the result object to defineFields.

Common options

Every builder accepts these.

Builders

values for f.enum / f.multiEnum are plain values or { value, label, children?, disabled? }. search(query, signal) returns a promise of options for remote or huge lists; with search set, option membership isn't validated.

defineFields

defineFields(fields, {
  operators?: OperatorDef[];      // custom operators
  functions?: Record<string, FunctionDef>;
  messages?: Partial<Record<IssueCode, string | ((issue) => string)>>;
});

Returns the fields with literal types pinned and struct fields flattened (FlattenFields). The options are attached to the returned object, so anything that receives these fields (the store, codecs, compile) sees them.

extendFields

Don't spread a schema ({ ...fields, extra }): the custom operators, functions and messages live on a hidden property and would be lost. Use extendFields(base, more, options?) to add or override fields; it merges registries too.

Serializing a schema

fieldsToJSON(fields, { fns }) turns a schema into JSON for sending from a server, with functions (validators, searches) referenced by name from fns; fieldsFromJSON(json, { fns, schema }) rebuilds it. Custom operators and functions must be passed again in schema.