refactor(exo): split exo tools
MODIFY
packages/exo/index.js
packages/exo/index.js
export {
- defendPrototype,
- defendPrototypeKit,
initEmpty,
defineExoClass,
defineExoClassKit,
makeExo,
-} from './src/interface-tools.js';
+} from './src/exo-makers.js';

MODIFY
packages/exo/package.json
packages/exo/package.json
"module": "./index.js",
"exports": {
".": "./index.js",
+ "./tools.js": "./tools.js",
"./package.json": "./package.json"
},
"scripts": {

ADD
packages/exo/src/exo-makers.js
+import { objectMap } from '@endo/patterns';
+
+import { defendPrototype, defendPrototypeKit } from './exo-tools.js';
+
+const { seal, freeze } = Object;
+
+const emptyRecord = harden({});
+
+/**
+ * When calling `defineDurableKind` and
+ * its siblings, used as the `init` function argument to indicate that the
+ * state record of the (virtual/durable) instances of the kind/exoClass
+ * should be empty, and that the returned maker function should have zero
+ * parameters.
+ *
+ * @returns {{}}
+ */
+export const initEmpty = () => emptyRecord;
+
+/**
+ * @template [S = any]
+ * @template [T = any]
+ * @typedef {object} Context
+ * @property {S} state
+ * @property {T} self
+ */
+
+/**
+ * @template A args to init
+ * @template S state from init
+ * @template {Record<string | symbol, CallableFunction>} T 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>)}
+ */
+export const defineExoClass = (
+ tag,
+ interfaceGuard,
+ init,
+ methods,
+ options = undefined,
+) => {
+ /** @type {WeakMap<T,Context<S, T>>} */
+ const contextMap = new WeakMap();
+ const prototype = defendPrototype(
+ tag,
+ contextMap,
+ methods,
+ true,
+ interfaceGuard,
+ );
+ const makeInstance = (...args) => {
+ // Be careful not to freeze the state record
+ const state = seal(init(...args));
+ /** @type {T} */
+ // @ts-expect-error could be instantiated with different subtype
+ const self = harden({ __proto__: prototype });
+ // Be careful not to freeze the state record
+ /** @type {Context<S,T>} */
+ const context = freeze({ state, self });
+ contextMap.set(self, context);
+ if (options) {
+ const { finish = undefined } = options;
+ if (finish) {
+ finish(context);
+ }
+ }
+ return self;
+ };
+ // @ts-expect-error could be instantiated with different subtype
+ return harden(makeInstance);
+};
+harden(defineExoClass);
+
+/**
+ * @template A args to init
+ * @template S state from init
+ * @template {Record<string, Record<string | symbol, CallableFunction>>} F 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}
+ */
+export const defineExoClassKit = (
+ tag,
+ interfaceGuardKit,
+ init,
+ methodsKit,
+ options = undefined,
+) => {
+ const contextMapKit = objectMap(methodsKit, () => new WeakMap());
+ const prototypeKit = defendPrototypeKit(
+ tag,
+ contextMapKit,
+ methodsKit,
+ true,
+ interfaceGuardKit,
+ );
+ const makeInstanceKit = (...args) => {
+ // Be careful not to freeze the state record
+ const state = seal(init(...args));
+ // Don't freeze context until we add facets
+ const context = { state };
+ const facets = objectMap(prototypeKit, (prototype, facetName) => {
+ const self = harden({ __proto__: prototype });
+ contextMapKit[facetName].set(self, context);
+ return self;
+ });
+ context.facets = facets;
+ // Be careful not to freeze the state record
+ freeze(context);
+ if (options) {
+ const { finish = undefined } = options;
+ if (finish) {
+ finish(context);
+ }
+ }
+ return facets;
+ };
+ return harden(makeInstanceKit);
+};
+harden(defineExoClassKit);
+
+/**
+ * @template {Record<string, Method>} T
+ * @param {string} tag
+ * @param {InterfaceGuard | undefined} interfaceGuard CAVEAT: static typing does not yet support `callWhen` transformation
+ * @param {T} methods
+ * @param {object} [options]
+ * @returns {T & import('@endo/eventual-send').RemotableBrand<{}, T>}
+ */
+export const makeExo = (tag, interfaceGuard, methods, options = undefined) => {
+ const makeInstance = defineExoClass(
+ tag,
+ interfaceGuard,
+ initEmpty,
+ methods,
+ options,
+ );
+ return makeInstance();
+};
+harden(makeExo);

RENAME
packages/exo/src/interface-tools.js
packages/exo/src/exo-tools.js
@@ -3,7 +3,7 @@ import { listDifference, objectMap, mustMatch, M } from '@endo/patterns';
const { quote: q, Fail } = assert;
const { apply, ownKeys } = Reflect;
-const { defineProperties, seal, freeze } = Object;
+const { defineProperties } = Object;
/**
* A method guard, for inclusion in an interface guard, that enforces only that
@@ -278,145 +278,3 @@ export const defendPrototypeKit = (
),
);
};
-
-const emptyRecord = harden({});
-
-/**
- * When calling `defineDurableKind` and
- * its siblings, used as the `init` function argument to indicate that the
- * state record of the (virtual/durable) instances of the kind/exoClass
- * should be empty, and that the returned maker function should have zero
- * parameters.
- *
- * @returns {{}}
- */
-export const initEmpty = () => emptyRecord;
-
-/**
- * @template [S = any]
- * @template [T = any]
- * @typedef {object} Context
- * @property {S} state
- * @property {T} self
- */
-
-/**
- * @template A args to init
- * @template S state from init
- * @template {Record<string | symbol, CallableFunction>} T 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>)}
- */
-export const defineExoClass = (
- tag,
- interfaceGuard,
- init,
- methods,
- options = undefined,
-) => {
- /** @type {WeakMap<T,Context<S, T>>} */
- const contextMap = new WeakMap();
- const prototype = defendPrototype(
- tag,
- contextMap,
- methods,
- true,
- interfaceGuard,
- );
- const makeInstance = (...args) => {
- // Be careful not to freeze the state record
- const state = seal(init(...args));
- /** @type {T} */
- // @ts-expect-error could be instantiated with different subtype
- const self = harden({ __proto__: prototype });
- // Be careful not to freeze the state record
- /** @type {Context<S,T>} */
- const context = freeze({ state, self });
- contextMap.set(self, context);
- if (options) {
- const { finish = undefined } = options;
- if (finish) {
- finish(context);
- }
- }
- return self;
- };
- // @ts-expect-error could be instantiated with different subtype
- return harden(makeInstance);
-};
-harden(defineExoClass);
-
-/**
- * @template A args to init
- * @template S state from init
- * @template {Record<string, Record<string | symbol, CallableFunction>>} F 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}
- */
-export const defineExoClassKit = (
- tag,
- interfaceGuardKit,
- init,
- methodsKit,
- options = undefined,
-) => {
- const contextMapKit = objectMap(methodsKit, () => new WeakMap());
- const prototypeKit = defendPrototypeKit(
- tag,
- contextMapKit,
- methodsKit,
- true,
- interfaceGuardKit,
- );
- const makeInstanceKit = (...args) => {
- // Be careful not to freeze the state record
- const state = seal(init(...args));
- // Don't freeze context until we add facets
- const context = { state };
- const facets = objectMap(prototypeKit, (prototype, facetName) => {
- const self = harden({ __proto__: prototype });
- contextMapKit[facetName].set(self, context);
- return self;
- });
- context.facets = facets;
- // Be careful not to freeze the state record
- freeze(context);
- if (options) {
- const { finish = undefined } = options;
- if (finish) {
- finish(context);
- }
- }
- return facets;
- };
- return harden(makeInstanceKit);
-};
-harden(defineExoClassKit);
-
-/**
- * @template {Record<string, Method>} T
- * @param {string} tag
- * @param {InterfaceGuard | undefined} interfaceGuard CAVEAT: static typing does not yet support `callWhen` transformation
- * @param {T} methods
- * @param {object} [options]
- * @returns {T & import('@endo/eventual-send').RemotableBrand<{}, T>}
- */
-export const makeExo = (tag, interfaceGuard, methods, options = undefined) => {
- const makeInstance = defineExoClass(
- tag,
- interfaceGuard,
- initEmpty,
- methods,
- options,
- );
- return makeInstance();
-};
-harden(makeExo);

MODIFY
packages/exo/test/test-heap-classes.js
packages/exo/test/test-heap-classes.js
@@ -5,7 +5,7 @@ import {
defineExoClass,
defineExoClassKit,
makeExo,
-} from '../src/interface-tools.js';
+} from '../src/exo-makers.js';
const UpCounterI = M.interface('UpCounter', {
incr: M.call()

ADD
packages/exo/tools.js
+export { defendPrototype, defendPrototypeKit } from './src/exo-tools.js';

refactor(exo): split exo tools (#1474)