Skip to content

Commit 505f81f

Browse files
committed
fix(patterns): type guards
1 parent a088e34 commit 505f81f

File tree

5 files changed

+342
-148
lines changed

5 files changed

+342
-148
lines changed

packages/exo/src/exo-tools.js

+13-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { E, Far } from '@endo/far';
22
import { hasOwnPropertyOf } from '@endo/pass-style';
3-
import { listDifference, objectMap, mustMatch, M } from '@endo/patterns';
3+
import {
4+
listDifference,
5+
objectMap,
6+
mustMatch,
7+
M,
8+
isAwaitArgGuard,
9+
assertMethodGuard,
10+
assertInterfaceGuard,
11+
} from '@endo/patterns';
412

513
/** @typedef {import('@endo/patterns').Method} Method */
614
/** @typedef {import('@endo/patterns').MethodGuard} MethodGuard */
@@ -47,9 +55,6 @@ const defendSyncMethod = (method, methodGuard, label) => {
4755
return syncMethod;
4856
};
4957

50-
const isAwaitArgGuard = argGuard =>
51-
argGuard && typeof argGuard === 'object' && argGuard.klass === 'awaitArg';
52-
5358
const desync = methodGuard => {
5459
const { argGuards, optionalArgGuards = [], restArgGuard } = methodGuard;
5560
!isAwaitArgGuard(restArgGuard) ||
@@ -106,8 +111,8 @@ const defendAsyncMethod = (method, methodGuard, label) => {
106111
* @param {string} label
107112
*/
108113
const defendMethod = (method, methodGuard, label) => {
109-
const { klass, callKind } = methodGuard;
110-
assert(klass === 'methodGuard');
114+
assertMethodGuard(methodGuard);
115+
const { callKind } = methodGuard;
111116
if (callKind === 'sync') {
112117
return defendSyncMethod(method, methodGuard, label);
113118
} else {
@@ -257,15 +262,9 @@ export const defendPrototype = (
257262
}
258263
let methodGuards;
259264
if (interfaceGuard) {
260-
const {
261-
klass,
262-
interfaceName,
263-
methodGuards: mg,
264-
sloppy = false,
265-
} = interfaceGuard;
265+
assertInterfaceGuard(interfaceGuard);
266+
const { interfaceName, methodGuards: mg, sloppy = false } = interfaceGuard;
266267
methodGuards = mg;
267-
assert.equal(klass, 'Interface');
268-
assert.typeof(interfaceName, 'string');
269268
{
270269
const methodNames = ownKeys(behaviorMethods);
271270
const methodGuardNames = ownKeys(methodGuards);

packages/patterns/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ export {
5252
assertPattern,
5353
matches,
5454
mustMatch,
55+
isAwaitArgGuard,
56+
assertAwaitArgGuard,
57+
assertMethodGuard,
58+
assertInterfaceGuard,
5559
} from './src/patterns/patternMatchers.js';
5660

5761
// ////////////////// Temporary, until these find their proper home ////////////
Original file line numberDiff line numberDiff line change
@@ -1 +1,67 @@
11
/// <reference types="ses"/>
2+
3+
/** @typedef {import('@endo/marshal').Passable} Passable */
4+
/** @typedef {import('@endo/marshal').PassStyle} PassStyle */
5+
/** @typedef {import('@endo/marshal').CopyTagged} CopyTagged */
6+
/** @template T @typedef {import('@endo/marshal').CopyRecord<T>} CopyRecord */
7+
/** @template T @typedef {import('@endo/marshal').CopyArray<T>} CopyArray */
8+
/** @typedef {import('@endo/marshal').Checker} Checker */
9+
/** @typedef {import('@endo/marshal').RankCompare} RankCompare */
10+
/** @typedef {import('@endo/marshal').RankCover} RankCover */
11+
12+
/** @typedef {import('../types.js').AwaitArgGuard} AwaitArgGuard */
13+
/** @typedef {import('../types.js').ArgGuard} ArgGuard */
14+
/** @typedef {import('../types.js').MethodGuard} MethodGuard */
15+
/** @typedef {import('../types.js').InterfaceGuard} InterfaceGuard */
16+
/** @typedef {import('../types.js').MethodGuardMaker0} MethodGuardMaker0 */
17+
18+
/** @typedef {import('../types').MatcherNamespace} MatcherNamespace */
19+
/** @typedef {import('../types').Key} Key */
20+
/** @typedef {import('../types').Pattern} Pattern */
21+
/** @typedef {import('../types').CheckPattern} CheckPattern */
22+
/** @typedef {import('../types').Limits} Limits */
23+
/** @typedef {import('../types').AllLimits} AllLimits */
24+
/** @typedef {import('../types').GetRankCover} GetRankCover */
25+
26+
/**
27+
* @typedef {object} MatchHelper
28+
* This factors out only the parts specific to each kind of Matcher. It is
29+
* encapsulated, and its methods can make the stated unchecked assumptions
30+
* enforced by the common calling logic.
31+
*
32+
* @property {(allegedPayload: Passable,
33+
* check: Checker
34+
* ) => boolean} checkIsWellFormed
35+
* Reports whether `allegedPayload` is valid as the payload of a CopyTagged
36+
* whose tag corresponds with this MatchHelper's Matchers.
37+
*
38+
* @property {(specimen: Passable,
39+
* matcherPayload: Passable,
40+
* check: Checker,
41+
* ) => boolean} checkMatches
42+
* Assuming validity of `matcherPayload` as the payload of a Matcher corresponding
43+
* with this MatchHelper, reports whether `specimen` is matched by that Matcher.
44+
*
45+
* @property {import('../types').GetRankCover} getRankCover
46+
* Assumes this is the payload of a CopyTagged with the corresponding
47+
* matchTag. Return a RankCover to bound from below and above,
48+
* in rank order, all possible Passables that would match this Matcher.
49+
* The left element must be before or the same rank as any possible
50+
* matching specimen. The right element must be after or the same
51+
* rank as any possible matching specimen.
52+
*/
53+
54+
/**
55+
* @typedef {object} PatternKit
56+
* @property {(specimen: Passable,
57+
* patt: Passable,
58+
* check: Checker,
59+
* label?: string|number
60+
* ) => boolean} checkMatches
61+
* @property {(specimen: Passable, patt: Pattern) => boolean} matches
62+
* @property {(specimen: Passable, patt: Pattern, label?: string|number) => void} mustMatch
63+
* @property {(patt: Pattern) => void} assertPattern
64+
* @property {(patt: Passable) => boolean} isPattern
65+
* @property {GetRankCover} getRankCover
66+
* @property {MatcherNamespace} M
67+
*/

0 commit comments

Comments
 (0)