seatgen: a string's enum is one Go constant per value

A caller names a value the seat definition gives, such as the removal
reason retention, and never writes it by hand.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 16:29:57 +01:00
parent 31f6c635f5
commit 9c8d64e28c
3 changed files with 23 additions and 1 deletions
@@ -496,6 +496,7 @@ func goTypes(b *bytes.Buffer, tp *typer, also map[string]*typ) error {
fmt.Fprintf(b, "// %s %s\n", t.name, oneLine(desc))
if t.t.kind != "struct" {
fmt.Fprintf(b, "type %s = %s\n\n", t.name, goType(t.t, kinds, true))
goEnum(b, t.name, t.name, t.t)
continue
}
fmt.Fprintf(b, "type %s struct {\n", t.name)
@@ -510,10 +511,26 @@ func goTypes(b *bytes.Buffer, tp *typer, also map[string]*typ) error {
fmt.Fprintf(b, "\t%s %s `json:%q`\n", ident(f.json), goType(f.t, kinds, f.required), tag)
}
b.WriteString("}\n\n")
for _, f := range t.t.fields {
goEnum(b, t.name+"'s "+f.json, t.name+ident(f.json), f.t)
}
}
return nil
}
// goEnum writes a string's enum as one constant per value, named prefix and the value (RemoveInputReasonRetention), so a
// caller names a value the definition gives and never writes it by hand.
func goEnum(b *bytes.Buffer, what, prefix string, t *typ) {
if t.kind != "string" || len(t.enum) == 0 {
return
}
fmt.Fprintf(b, "// The values of %s.\nconst (\n", what)
for _, v := range t.enum {
fmt.Fprintf(b, "\t%s%s = %q\n", prefix, ident(v), v)
}
b.WriteString(")\n\n")
}
func goType(t *typ, kinds map[string]*typ, required bool) string {
switch t.kind {
case "string":
@@ -4,6 +4,7 @@ import (
"encoding/json"
"go/parser"
"go/token"
re "regexp"
"strings"
"testing"
@@ -71,6 +72,10 @@ func TestEachSeatDefinedWholeIsAGoModuleOfItsOwn(t *testing.T) {
if !strings.Contains(src, "type Ref struct") || !strings.Contains(src, "type PublishedEvent") {
t.Errorf("%s does not hold the part's types whole", seat)
}
// A string's enum is a constant per value, so a caller names the definition's value (A3t: the removal reason).
if !re.MustCompile(`RefReasonRetention\s+= "retention"`).MatchString(src) || !re.MustCompile(`RefReasonTagGone\s+= "tag-gone"`).MatchString(src) {
t.Errorf("%s does not name the part's enum values:\n%s", seat, src)
}
}
if !strings.Contains(string(files["go/seats/seats.go"]), "OneStore") {
t.Error("the seat set does not name the seat at the seat list's grain")
@@ -1,3 +1,3 @@
{"format":1,"part":"registry","verbs":[{"name":"publish","input":{"$ref":"#/defs/Ref"},"answer":{"type":"object"}}],
"events":[{"name":"published","body":{"$ref":"#/defs/Ref"}}],
"defs":{"Ref":{"type":"object","properties":{"digest":{"type":"string"}},"required":["digest"]}}}
"defs":{"Ref":{"type":"object","properties":{"digest":{"type":"string"},"reason":{"type":"string","enum":["tag-gone","retention"]}},"required":["digest"]}}}