Extract out tags validations from all validations

This commit is contained in:
Your Name
2026-02-02 20:00:24 +00:00
parent 938ef0f7a7
commit 92de205642

View File

@@ -154,28 +154,10 @@ func (reg *registry) ExtractValidations(context Context, tags ...codetags.Tag) (
if !reg.initialized.Load() {
panic("registry.init() was not called")
}
validations := Validations{}
// Run tag-validators first.
phases := reg.sortTagsIntoPhases(tags)
for _, tags := range phases {
for _, tag := range tags {
tv := reg.tagValidators[tag.Name]
// At this point we know tv exists and is not nil due to the upfront check
if scopes := tv.ValidScopes(); !scopes.Has(context.Scope) {
return Validations{}, fmt.Errorf("tag %q cannot be specified on %s", tv.TagName(), context.Scope)
}
if err := typeCheck(tag, tv.Docs()); err != nil {
return Validations{}, fmt.Errorf("tag %q: %w", tv.TagName(), err)
}
if theseValidations, err := tv.GetValidations(context, tag); err != nil {
return Validations{}, fmt.Errorf("tag %q: %w", tv.TagName(), err)
} else {
validations.Add(theseValidations)
}
}
validations, err := reg.ExtractTagValidations(context, tags...)
if err != nil {
return Validations{}, err
}
// Run type-validators after tag validators are done.
if context.Scope == ScopeType {
// Run all type-validators.
@@ -203,6 +185,33 @@ func (reg *registry) ExtractValidations(context Context, tags ...codetags.Tag) (
return validations, nil
}
func (reg *registry) ExtractTagValidations(context Context, tags ...codetags.Tag) (Validations, error) {
if !reg.initialized.Load() {
panic("registry.init() was not called")
}
validations := Validations{}
// Run tag-validators first.
phases := reg.sortTagsIntoPhases(tags)
for _, tags := range phases {
for _, tag := range tags {
tv := reg.tagValidators[tag.Name]
// At this point we know tv exists and is not nil due to the upfront check
if scopes := tv.ValidScopes(); !scopes.Has(context.Scope) {
return Validations{}, fmt.Errorf("tag %q cannot be specified on %s", tv.TagName(), context.Scope)
}
if err := typeCheck(tag, tv.Docs()); err != nil {
return Validations{}, fmt.Errorf("tag %q: %w", tv.TagName(), err)
}
if theseValidations, err := tv.GetValidations(context, tag); err != nil {
return Validations{}, fmt.Errorf("tag %q: %w", tv.TagName(), err)
} else {
validations.Add(theseValidations)
}
}
}
return validations, nil
}
func (reg *registry) sortTagsIntoPhases(tags []codetags.Tag) [][]codetags.Tag {
// First sort all tags by their name, so the final output is deterministic.
// It is important to do this before validations are generated.
@@ -285,6 +294,11 @@ type Validator interface {
// logic.
ExtractValidations(context Context, Tags ...codetags.Tag) (Validations, error)
// ExtractTagValidations extracts all validations associated with the given tags.
// Some tag validators may return empty validations and update internal state
// that is then used by FieldValidators.
ExtractTagValidations(context Context, Tags ...codetags.Tag) (Validations, error)
// Docs returns documentation for each known tag.
Docs() []TagDoc