Observation
Every per-kind shape validator now handles the same three modes (see validateValue in src/value.core.ts):
- state — validate an instance value against the shape
- state against model — validate a retrieval result narrowed by a projection template
- model — validate a retrieval template (placeholder)
The mode is currently threaded piecemeal: validateValue takes a model?: boolean flag and forks per kind
(validateText/validateLocale, validateResource/validateTemplate, etc.), while the public validate() in
src/index.ts carries a four-branch dispatch (union, non-resource value, model === true template, keyed-model
result, plain resource) with a separate seal/idempotence check in each branch.
Idea
Generalise the mode into a single parameter carried end to end:
- Pass
model: boolean | Template (or a richer descriptor X) uniformly, matching the union already declared on the
merged validate() options (src/index.ts model?: boolean | Template).
- Thread the remaining options (
entry, plain, depth, limit) through validateValue
(src/value.core.ts L511-554) so each leaf validator receives the full context rather than re-deriving it at the
index.ts layer.
- With the mode and options unified, the four
validate() overload bodies (src/index.ts L179-573) should collapse
to a single generalised method dispatching once on shape kind and mode.
Scope / risks
- Public
validate() overload signatures stay as-is (state / result / template / value); only the shared
implementation body collapses.
- Idempotence sealing currently differs per branch (
Validated seal payload varies by mode); a unified path must
preserve those distinctions.
- Behaviour-preserving refactor: existing test suite must stay green throughout.
Observation
Every per-kind shape validator now handles the same three modes (see
validateValueinsrc/value.core.ts):The mode is currently threaded piecemeal:
validateValuetakes amodel?: booleanflag and forks per kind(
validateText/validateLocale,validateResource/validateTemplate, etc.), while the publicvalidate()insrc/index.tscarries a four-branch dispatch (union, non-resource value,model === truetemplate, keyed-modelresult, plain resource) with a separate seal/idempotence check in each branch.
Idea
Generalise the mode into a single parameter carried end to end:
model: boolean | Template(or a richer descriptorX) uniformly, matching the union already declared on themerged
validate()options (src/index.tsmodel?: boolean | Template).entry,plain,depth,limit) throughvalidateValue(
src/value.core.tsL511-554) so each leaf validator receives the full context rather than re-deriving it at theindex.tslayer.validate()overload bodies (src/index.tsL179-573) should collapseto a single generalised method dispatching once on shape kind and mode.
Scope / risks
validate()overload signatures stay as-is (state / result / template / value); only the sharedimplementation body collapses.
Validatedseal payload varies by mode); a unified path mustpreserve those distinctions.