Skip to content

Commit 218e881

Browse files
grypezclaude
andcommitted
refactor(kernel-utils): extract buildMethodGuard to eliminate duplication
asyncifyMethodGuards (sheafify.ts) and collectSheafGuard (guard.ts) both contained an identical 4-way if/else for assembling a MethodGuard from its components. The chain order required by @endo/patterns (callWhen → optional → rest → returns) makes each branch non-obvious — a bad candidate for duplication. Extract buildMethodGuard into guard.ts and use it in both sites. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 20737b2 commit 218e881

2 files changed

Lines changed: 45 additions & 35 deletions

File tree

packages/kernel-utils/src/sheaf/guard.ts

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,38 @@ export type MethodGuardPayload = {
1616
returnGuard: Pattern;
1717
};
1818

19+
/**
20+
* Assemble a MethodGuard from its components.
21+
*
22+
* The @endo/patterns builder API requires a strict chain order:
23+
* callWhen → optional → rest → returns. All four combinations of
24+
* optional/rest presence are handled here so callers don't repeat this logic.
25+
*
26+
* @param base - Result of M.callWhen(...requiredArgs).
27+
* @param optionals - Optional positional arg guards (may be empty).
28+
* @param restGuard - Rest arg guard, or undefined if none.
29+
* @param returnGuard - Return value guard.
30+
* @returns The assembled MethodGuard.
31+
*/
32+
export const buildMethodGuard = (
33+
base: ReturnType<typeof M.callWhen>,
34+
optionals: Pattern[],
35+
restGuard: Pattern | undefined,
36+
returnGuard: Pattern,
37+
): MethodGuard => {
38+
if (optionals.length > 0 && restGuard !== undefined) {
39+
return base
40+
.optional(...optionals)
41+
.rest(restGuard)
42+
.returns(returnGuard);
43+
} else if (optionals.length > 0) {
44+
return base.optional(...optionals).returns(returnGuard);
45+
} else if (restGuard === undefined) {
46+
return base.returns(returnGuard);
47+
}
48+
return base.rest(restGuard).returns(returnGuard);
49+
};
50+
1951
/**
2052
* Naive union of guards via M.or — no pattern canonicalization.
2153
*
@@ -121,23 +153,12 @@ export const collectSheafGuard = <Core extends Methods>(
121153
payloads.map((payload) => payload.returnGuard),
122154
);
123155

124-
const base = M.callWhen(...requiredArgGuards);
125-
if (optionalArgGuards.length > 0 && unionRestArgGuard !== undefined) {
126-
unionMethodGuards[methodName] = base
127-
.optional(...optionalArgGuards)
128-
.rest(unionRestArgGuard)
129-
.returns(returnGuard);
130-
} else if (optionalArgGuards.length > 0) {
131-
unionMethodGuards[methodName] = base
132-
.optional(...optionalArgGuards)
133-
.returns(returnGuard);
134-
} else if (unionRestArgGuard === undefined) {
135-
unionMethodGuards[methodName] = base.returns(returnGuard);
136-
} else {
137-
unionMethodGuards[methodName] = base
138-
.rest(unionRestArgGuard)
139-
.returns(returnGuard);
140-
}
156+
unionMethodGuards[methodName] = buildMethodGuard(
157+
M.callWhen(...requiredArgGuards),
158+
optionalArgGuards,
159+
unionRestArgGuard,
160+
returnGuard,
161+
);
141162
}
142163

143164
return M.interface(name, unionMethodGuards);

packages/kernel-utils/src/sheaf/sheafify.ts

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { makeDiscoverableExo } from '../discoverable.ts';
2424
import type { MethodSchema } from '../schema.ts';
2525
import { stringify } from '../stringify.ts';
2626
import { driveLift } from './drive.ts';
27-
import { collectSheafGuard } from './guard.ts';
27+
import { buildMethodGuard, collectSheafGuard } from './guard.ts';
2828
import type { MethodGuardPayload } from './guard.ts';
2929
import { evaluateMetadata, resolveMetaDataSpec } from './metadata.ts';
3030
import type { ResolvedMetaDataSpec } from './metadata.ts';
@@ -140,23 +140,12 @@ const asyncifyMethodGuards = (
140140
const { argGuards, optionalArgGuards, restArgGuard, returnGuard } =
141141
getMethodGuardPayload(methodGuard) as unknown as MethodGuardPayload;
142142
const optionals = optionalArgGuards ?? [];
143-
const base = M.callWhen(...argGuards);
144-
if (optionals.length > 0 && restArgGuard !== undefined) {
145-
asyncMethodGuards[methodName] = base
146-
.optional(...optionals)
147-
.rest(restArgGuard)
148-
.returns(returnGuard);
149-
} else if (optionals.length > 0) {
150-
asyncMethodGuards[methodName] = base
151-
.optional(...optionals)
152-
.returns(returnGuard);
153-
} else if (restArgGuard === undefined) {
154-
asyncMethodGuards[methodName] = base.returns(returnGuard);
155-
} else {
156-
asyncMethodGuards[methodName] = base
157-
.rest(restArgGuard)
158-
.returns(returnGuard);
159-
}
143+
asyncMethodGuards[methodName] = buildMethodGuard(
144+
M.callWhen(...argGuards),
145+
optionals,
146+
restArgGuard,
147+
returnGuard,
148+
);
160149
}
161150
return asyncMethodGuards;
162151
};

0 commit comments

Comments
 (0)