From faffedc775e4859003ba077d711d441f2149e6d6 Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Fri, 31 Mar 2023 16:57:50 -0700 Subject: [PATCH] fix: sync with shadows in agoric-sdk --- packages/exo/src/exo-makers.js | 84 +++++++++++++++++++++------------- packages/exo/src/exo-tools.js | 1 + packages/patterns/src/types.js | 15 ++++-- 3 files changed, 65 insertions(+), 35 deletions(-) diff --git a/packages/exo/src/exo-makers.js b/packages/exo/src/exo-makers.js index d35c6b95e3..a7e6644a0d 100644 --- a/packages/exo/src/exo-makers.js +++ b/packages/exo/src/exo-makers.js @@ -26,24 +26,44 @@ export const initEmpty = () => emptyRecord; */ /** - * @template A args to init - * @template S state from init - * @template {Record} T methods + * @template [S = any] + * @template [F = any] + * @typedef {object} KitContext + * @property {S} state + * @property {F} facets + */ + +/** + * @typedef {{[name: string]: Pattern}} StateShape + * It looks like a copyRecord pattern, but the interpretation is different. + * Each property is distinct, is checked and changed separately. + */ + +/** + * @template C + * @typedef {object} FarClassOptions + * @property {(context: C) => void} [finish] + * @property {StateShape} [stateShape] + */ + +/** + * @template {(...args: any[]) => any} I init function + * @template {Record} M methods * @param {string} tag * @param {any} interfaceGuard - * @param {(...args: A[]) => S} init - * @param {T & ThisType<{ self: T, state: S }>} methods - * @param {object} [options] - * @returns {(...args: A[]) => (T & import('@endo/eventual-send').RemotableBrand<{}, T>)} + * @param {I} init + * @param {M & ThisType<{ self: M, state: ReturnType }>} methods + * @param {FarClassOptions, M>>} [options] + * @returns {(...args: Parameters) => (M & import('@endo/eventual-send').RemotableBrand<{}, M>)} */ export const defineExoClass = ( tag, interfaceGuard, init, methods, - options = undefined, + { finish = undefined } = {}, ) => { - /** @type {WeakMap>} */ + /** @type {WeakMap, M>>} */ const contextMap = new WeakMap(); const prototype = defendPrototype( tag, @@ -52,21 +72,21 @@ export const defineExoClass = ( true, interfaceGuard, ); + /** + * @param {Parameters} args + */ const makeInstance = (...args) => { // Be careful not to freeze the state record const state = seal(init(...args)); - /** @type {T} */ + /** @type {M} */ // @ts-expect-error could be instantiated with different subtype const self = harden({ __proto__: prototype }); // Be careful not to freeze the state record - /** @type {Context} */ + /** @type {Context,M>} */ const context = freeze({ state, self }); contextMap.set(self, context); - if (options) { - const { finish = undefined } = options; - if (finish) { - finish(context); - } + if (finish) { + finish(context); } return self; }; @@ -76,22 +96,21 @@ export const defineExoClass = ( harden(defineExoClass); /** - * @template A args to init - * @template S state from init - * @template {Record>} F methods + * @template {(...args: any[]) => any} I init function + * @template {Record>} F facet methods * @param {string} tag * @param {any} interfaceGuardKit - * @param {(...args: A[]) => S} init - * @param {F & ThisType<{ facets: F, state: S }> } methodsKit - * @param {object} [options] - * @returns {(...args: A[]) => F} + * @param {I} init + * @param {F & ThisType<{ facets: F, state: ReturnType }> } methodsKit + * @param {FarClassOptions,F>>} [options] + * @returns {(...args: Parameters) => F} */ export const defineExoClassKit = ( tag, interfaceGuardKit, init, methodsKit, - options = undefined, + { finish = undefined } = {}, ) => { const contextMapKit = objectMap(methodsKit, () => new WeakMap()); const prototypeKit = defendPrototypeKit( @@ -101,6 +120,9 @@ export const defineExoClassKit = ( true, interfaceGuardKit, ); + /** + * @param {Parameters} args + */ const makeInstanceKit = (...args) => { // Be careful not to freeze the state record const state = seal(init(...args)); @@ -114,24 +136,24 @@ export const defineExoClassKit = ( context.facets = facets; // Be careful not to freeze the state record freeze(context); - if (options) { - const { finish = undefined } = options; - if (finish) { - finish(context); - } + if (finish) { + // @ts-expect-error `facets` was added + finish(context); } return facets; }; + // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error -- different per package https://github.com/Agoric/agoric-sdk/issues/4620 + // @ts-ignore xxx return harden(makeInstanceKit); }; harden(defineExoClassKit); /** - * @template {Record} T + * @template {Record} T * @param {string} tag * @param {InterfaceGuard | undefined} interfaceGuard CAVEAT: static typing does not yet support `callWhen` transformation * @param {T} methods - * @param {object} [options] + * @param {FarClassOptions>} [options] * @returns {T & import('@endo/eventual-send').RemotableBrand<{}, T>} */ export const makeExo = (tag, interfaceGuard, methods, options = undefined) => { diff --git a/packages/exo/src/exo-tools.js b/packages/exo/src/exo-tools.js index 04d60ad995..6e45ee6148 100644 --- a/packages/exo/src/exo-tools.js +++ b/packages/exo/src/exo-tools.js @@ -231,6 +231,7 @@ export const defendPrototype = ( methodGuards && methodGuards[prop], ); } + return Far(tag, /** @type {T} */ (prototype)); }; harden(defendPrototype); diff --git a/packages/patterns/src/types.js b/packages/patterns/src/types.js index 5ce4a5e8c7..0246a0097a 100644 --- a/packages/patterns/src/types.js +++ b/packages/patterns/src/types.js @@ -493,10 +493,17 @@ /** * @typedef {any} MethodGuardMaker - * a parameter list like foo(a, b, c = d, …e) => f should be guarded by - * something like - * foo: M.call(AShape, BShape).optional(CShape).rest(EShape).returns(FShape) - * optional is for optional (=) params. rest is for … (varargs) params + * A method name and parameter/return signature like: + * ```js + * foo(a, b, c = d, ...e) => f + * ``` + * should be guarded by something like: + * ```js + * { + * ...otherMethodGuards, + * foo: M.call(AShape, BShape).optional(CShape).rest(EShape).returns(FShape), + * } + * ``` */ /** @typedef {{ klass: 'methodGuard', callKind: 'sync' | 'async', returnGuard: unknown }} MethodGuard */