Schema to Formatter
Value formatters work in VibeLang exactly as in Effect. A schema-derived formatter renders decoded values as readable strings for diagnostics or display. It does not validate input or serialize a value for transport; use a codec for serialization and an issue formatter for failures. Plain builders follow the trusted call rules.
Deriving value formatters from schemas
// run: Console.log(displayDispatch({ depot: "east", counts: [2, 4] }))
import { Console } from "effect"
const Dispatch = Schema.Struct({
depot: Schema.String,
counts: Schema.Array(Schema.Int)
})
function displayDispatch(input: unknown) {
const dispatch = Schema.decodeUnknownEffect(Dispatch)(input)
return try((schema, dispatch) => Schema.toFormatter(schema)(dispatch), Dispatch, dispatch)
}
// For { depot: "east", counts: [2, 4] }, produces a readable object representation.{ "depot": "east", "counts": [2, 4] }toFormatter walks structs, arrays, unions, and supported declarations. Its argument type is the schema's decoded type, even when the codec accepts a different wire representation. The example decodes first so the formatter receives valid data. The explicit boundary accounts for exceptions from generated or custom formatting callbacks.
Customizing formatting at selected syntax-tree nodes
// run: Console.log(displayManifest({ label: "crate", weight: 2 }))
const Weight = Schema.Finite.pipe(Schema.overrideToFormatter(
() => (value) => `${value} kg`
))
schema Manifest { label: string; weight: Weight }
function displayManifest(input: unknown) {
const manifest = Schema.decodeUnknownEffect(Manifest)(input)
return try((schema, manifest) => Schema.toFormatter(schema, {
onBefore: (ast) => ast._tag === "String"
? (value: string) => `[${value}]`
: undefined
})(manifest), Manifest, manifest)
}{ "label": [crate], "weight": 2 kg }overrideToFormatter replaces formatting at one schema node, such as the weight above. onBefore intercepts selected AST nodes after any toFormatter annotation has taken priority and before built-in derivation; returning undefined keeps the default behavior. The example changes string rendering while retaining the weight formatter.
Opaque declarations can supply toFormatter when declared. A parameterized declaration receives the formatter for each parameter. Keep hooks and generated formatter functions synchronous and pure; compute service-dependent display data before formatting. Review custom output for secret exposure before using it in logs.
The matching Effect page: effect.website/docs/v4/schema/formatter