SvEx. Config. Shape
(SvEx v0.4.2)
The shape of a resolved SvEx.Config, read off the sections themselves.
target.exs records four keys. What those four keys RESOLVE to is a
twenty-nine-field struct across eight sections, and until this module the only
way to see it was to read lib/sv_ex/config/*.ex. The mix task sv_ex.gen.config
writes it into the generated file as a comment block, so a project carries the
shape of its own configuration next to the four values that chose it.
Nothing here is a second copy of the schema
Every column is read from the section that defines it, at runtime:
- the fields and their order —
__info__(:struct), which reports them in declaration order - the type — the section's own
t()typespec, read out of the beam's type chunk - the value — the resolved config that was passed in, so it is what this project actually gets rather than what the struct defaults to
- the domain — the
inclusion:option of the section's own validation, which is the same literalSvEx.Config.Enumshands the validator
A field added to a section appears here with no edit. That is the whole design: a hand-maintained table is a second schema, and a second schema is one that can be wrong.
Except the rules, which are data on purpose
rules/0 and constraints/0 ARE written out, because the four implications
and two constraints live in SvEx.Config's finalize step as code and no
introspection recovers them. They are declarative — each one names the input
that triggers it and the output it forces — so SvEx.Config.ShapeTest runs
every one of them against the real constructor rather than reading them back.
A rule that stops holding fails a test; it does not quietly become a wrong
comment.
Summary
Types
A combination the constructor refuses outright.
One leaf field of a resolved config.
An implication: given this input, the constructor forces forces to to.
Functions
The combinations SvEx.Config refuses, raising SvEx.Config.InvalidError.
Every leaf field of config, in declaration order, deepest-last per section.
Renders config's shape as plain lines: a header, the field table, the
implications and the constraints.
The implications SvEx.Config applies while resolving a config.
Types
A combination the constructor refuses outright.
One leaf field of a resolved config.
An implication: given this input, the constructor forces forces to to.
Functions
@spec constraints() :: [constraint()]
The combinations SvEx.Config refuses, raising SvEx.Config.InvalidError.
@spec describe(SvEx.Config.t()) :: [row()]
Every leaf field of config, in declaration order, deepest-last per section.
Nested blocks are walked, so container.sidecars.valkey is one row rather
than a container.sidecars row holding a struct.
@spec render(SvEx.Config.t(), atom()) :: [String.t()]
Renders config's shape as plain lines: a header, the field table, the
implications and the constraints.
base names the preset the config came from and appears in the header only.
@spec rules() :: [rule()]
The implications SvEx.Config applies while resolving a config.