G T-4: a TypeScript verb with no callers takes its class's default (issue 1966)
As the Go reader's DefaultCallers: read takes invokers, persons and sessions, act the operator and sessions, warrant the operator; no class reads as read. Builds: design 47 G §391, §456, §196 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
+18
-2
@@ -179,12 +179,28 @@ export function parseConfiguredVerbCallers(raw: unknown, verbs: readonly string[
|
||||
const callerWords = ["operator", "healers", "persons", "sessions", "invokers"];
|
||||
const callerForm = /^(seat:[a-z][a-z0-9-]*|module:[a-z][a-z0-9-]*|holder:[a-z][a-z0-9-]*@same-node)$/;
|
||||
|
||||
/**
|
||||
* The callers a verb that names none takes by its class (design 47 G §391, §456), as the Go reader's DefaultCallers: a
|
||||
* `read` takes invokers, persons and sessions; an `act` the operator and sessions; a `warrant` the operator. A verb that
|
||||
* names no class is a `read`.
|
||||
*/
|
||||
function defaultCallers(cls: string | undefined): readonly string[] {
|
||||
switch (cls) {
|
||||
case "act":
|
||||
return ["operator", "sessions"];
|
||||
case "warrant":
|
||||
return ["operator"];
|
||||
}
|
||||
return ["invokers", "persons", "sessions"];
|
||||
}
|
||||
|
||||
/**
|
||||
* The callers a seat definition names for a verb or an accepted kind (design 47 G §336, §392): a list of entries, each
|
||||
* one of the forms the format knows. Text is refused naming the verb, and so is an entry that is no form (a bare name
|
||||
* among them), as the Go reader does.
|
||||
* among them), as the Go reader does. A verb that names no callers takes the default of its class `cls` (§391).
|
||||
*/
|
||||
export function readDefinitionCallers(verb: string, value: unknown): readonly string[] {
|
||||
export function readDefinitionCallers(verb: string, value: unknown, cls?: string): readonly string[] {
|
||||
if (value === undefined || value === null) return defaultCallers(cls);
|
||||
if (typeof value === "string") {
|
||||
throw new Error(`${verb}: callers are text ("${value}"): a definition gives its callers as a list`);
|
||||
}
|
||||
|
||||
@@ -682,6 +682,13 @@ test("callers and verb callers judge a proved caller by the Go side's rules (ADR
|
||||
["operator", "invokers", "seat:mesh-grants", "holder:node-backup@same-node"]);
|
||||
assert.throws(() => readDefinitionCallers("list", "a person"), /list: callers are text/);
|
||||
assert.throws(() => readDefinitionCallers("list", ["mesh-grants"]), /list: the callers entry "mesh-grants" is none of/);
|
||||
// design 47 G §391, §456: a verb with no callers takes its class's default; no class reads as read; its own list is kept
|
||||
const byClass: [string | undefined, string[]][] = [
|
||||
[undefined, ["invokers", "persons", "sessions"]], ["read", ["invokers", "persons", "sessions"]],
|
||||
["act", ["operator", "sessions"]], ["warrant", ["operator"]],
|
||||
];
|
||||
for (const [cls, want] of byClass) assert.deepEqual(readDefinitionCallers("list", undefined, cls), want, String(cls));
|
||||
assert.deepEqual(readDefinitionCallers("register", ["seat:mesh-broker"], "act"), ["seat:mesh-broker"]);
|
||||
assert.throws(() => parseCallers('{"callers":["a"],"more":1}'), /unknown field "more"/);
|
||||
|
||||
const verbs = parseVerbCallers('{"pull":["*"],"merge-pull":["mesh-delivery-forge-bridge"],"comment":["operator"]}', ["pull", "merge-pull", "comment"], {});
|
||||
|
||||
Reference in New Issue
Block a user