diff --git a/go/seatdef/callers.go b/go/seatdef/callers.go index 2ef7edd..177e4c1 100644 --- a/go/seatdef/callers.go +++ b/go/seatdef/callers.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "strings" ) // Callers says who may call a verb or send an accepted kind. It is read as text (the form every definition on main @@ -53,13 +54,53 @@ func checkCallers(where string, c *Callers) Problems { } var ps Problems for i, e := range c.List { - if e == "" { - ps = append(ps, Problem{fmt.Sprintf("%s[%d]", where, i), "is empty"}) + if why := CallerEntryProblem(e); why != "" { + ps = append(ps, Problem{fmt.Sprintf("%s[%d]", where, i), why}) } } return ps } +// The entries of a list of callers that are not a name (design 47 G §336). +const ( + CallerOperator = "operator" + CallerHealers = "healers" + CallerPersons = "persons" + CallerSessions = "sessions" + CallerInvokers = "invokers" +) + +// The prefixes of the entries that name a seat's holder or a module (design 47 G §392, §336). +const ( + CallerSeatPrefix = "seat:" + CallerModulePrefix = "module:" + CallerHolderPrefix = "holder:" + CallerSameNode = "@same-node" +) + +// CallerEntryProblem says why an entry of a list of callers is none of the forms of design 47 G §336, §392; empty +// when it is one: `operator`, `healers`, `persons`, `sessions`, `invokers`, `seat:`, `module:` and +// `holder:@same-node`. A bare name is refused, since a name such as `mesh-grants` is both a seat and a module. +func CallerEntryProblem(e string) string { + switch e { + case CallerOperator, CallerHealers, CallerPersons, CallerSessions, CallerInvokers: + return "" + } + if n, ok := strings.CutPrefix(e, CallerSeatPrefix); ok && wordName.MatchString(n) { + return "" + } + if n, ok := strings.CutPrefix(e, CallerModulePrefix); ok && wordName.MatchString(n) { + return "" + } + if n, ok := strings.CutPrefix(e, CallerHolderPrefix); ok { + if seat, ok := strings.CutSuffix(n, CallerSameNode); ok && wordName.MatchString(seat) { + return "" + } + } + return fmt.Sprintf("%q is none of operator, healers, persons, sessions, invokers, seat:, module: and "+ + "holder:@same-node", e) +} + // The classes of a verb (design 47 G §391). const ( ClassRead = "read" diff --git a/go/seatdef/seatdef_test.go b/go/seatdef/seatdef_test.go index 74cc1fb..d2073f8 100644 --- a/go/seatdef/seatdef_test.go +++ b/go/seatdef/seatdef_test.go @@ -118,7 +118,12 @@ func TestADefinitionIsReadStrictlyNamingWhatIsWrong(t *testing.T) { {"callers as text", strings.Replace(whole, `"name":"list",`, `"name":"list","callers":"a person",`, 1), ""}, {"callers as a list", strings.Replace(whole, `"name":"list",`, `"name":"list","callers":["operator","seat:mesh-grants","invokers"],"class":"read",`, 1), ""}, {"callers as neither", strings.Replace(whole, `"name":"list",`, `"name":"list","callers":7,`, 1), "callers is a text or a list"}, - {"a list with an empty entry", strings.Replace(whole, `"name":"list",`, `"name":"list","callers":["operator",""],`, 1), "verbs[0].callers[1]: is empty"}, + {"a list with an empty entry", strings.Replace(whole, `"name":"list",`, `"name":"list","callers":["operator",""],`, 1), "verbs[0].callers[1]"}, + {"a bare name among callers", strings.Replace(whole, `"name":"list",`, `"name":"list","callers":["mesh-grants"],`, 1), `"mesh-grants" is none of operator`}, + {"a class of the old branches", strings.Replace(whole, `"name":"list",`, `"name":"list","callers":["holder","invokes","reviewers"],`, 1), `"holder" is none of operator`}, + {"every form among callers", strings.Replace(whole, `"name":"list",`, + `"name":"list","callers":["operator","healers","persons","sessions","invokers","seat:mesh-grants","module:mesh-grants","holder:node-backup@same-node"],`, 1), ""}, + {"a holder not on the same node", strings.Replace(whole, `"name":"list",`, `"name":"list","callers":["holder:node-backup"],`, 1), "none of operator"}, {"a class that is none", strings.Replace(whole, `"name":"list",`, `"name":"list","class":"free",`, 1), `verbs[0].class: "free" is not a class (read, act, warrant)`}, {"an accepted kind's callers", strings.Replace(whole, `"events":`, `"accepts":[{"name":"step","body":{},"callers":["seat:mesh-pipeline-runner"]}],"events":`, 1), ""}, {"an event's callers", strings.Replace(whole, `"name":"created"`, `"name":"created","callers":["operator"]`, 1), "only an accepted kind carries callers"},