package schema import ( "fmt" "gopkg.in/yaml.v3" ) type GlossaryEntry struct { Name string `yaml:"name"` Aliases []string `yaml:"aliases,omitempty"` Plural string `yaml:"plural,omitempty"` Category string `yaml:"category"` Summary string `yaml:"summary"` } type Glossary struct { Entries []GlossaryEntry `yaml:"glossary"` } func ParseGlossaryYAML(raw []byte) (*Glossary, error) { var top map[string]any if err := yaml.Unmarshal(raw, &top); err != nil { return nil, &ParseError{Message: fmt.Sprintf("glossary is not valid YAML: %v", err)} } var g Glossary if err := yaml.Unmarshal(raw, &g); err != nil { return nil, &ParseError{Message: fmt.Sprintf("failed to parse glossary: %v", err)} } if err := validateGlossary(&g); err != nil { return nil, err } return &g, nil } func validateGlossary(g *Glossary) error { if len(g.Entries) == 0 { return &ValidationError{Field: "glossary", Message: "must contain at least one entry"} } for i, e := range g.Entries { entryLabel := fmt.Sprintf("glossary[%d]", i) if e.Name == "" { return &ValidationError{Field: fmt.Sprintf("%s.name", entryLabel), Message: "must not be empty"} } if e.Category == "" { return &ValidationError{Field: fmt.Sprintf("%s.category", entryLabel), Message: "must not be empty"} } if e.Summary == "" { return &ValidationError{Field: fmt.Sprintf("%s.summary", entryLabel), Message: "must not be empty"} } for j, alias := range e.Aliases { if alias == "" { return &ValidationError{ Field: fmt.Sprintf("%s.aliases[%d]", entryLabel, j), Message: "must not be empty", } } } if e.Plural != "" && len(e.Plural) == 0 { return &ValidationError{Field: fmt.Sprintf("%s.plural", entryLabel), Message: "must not be empty if present"} } } return nil }