diff --git a/packages/captp/src/captp.js b/packages/captp/src/captp.js index 81be418cd3..419f7a5715 100644 --- a/packages/captp/src/captp.js +++ b/packages/captp/src/captp.js @@ -1,6 +1,9 @@ // @ts-check /// +/** @template Slot @typedef {import('@endo/marshal').ConvertValToSlot} ConvertValToSlot */ +/** @template Slot @typedef {import('@endo/marshal').ConvertSlotToVal} ConvertSlotToVal */ + // Your app may need to `import '@endo/eventual-send/shim.js'` to get HandledPromise // This logic was mostly lifted from @agoric/swingset-vat liveSlots.js diff --git a/packages/captp/src/types.js b/packages/captp/src/types.js index e07cbe6221..65ee214ab5 100644 --- a/packages/captp/src/types.js +++ b/packages/captp/src/types.js @@ -17,7 +17,7 @@ */ /** - * @typedef {[boolean, CapData]} TrapCompletion The head of the pair + * @typedef {[boolean, import('@endo/marshal').CapData]} TrapCompletion The head of the pair * is the `isRejected` value indicating whether the sync call was an exception, * and tail of the pair is the serialized fulfillment value or rejection reason. * (The fulfillment value is a non-thenable. The rejection reason is normally diff --git a/packages/marshal/NEWS.md b/packages/marshal/NEWS.md index 158f12a165..a8c8972ea6 100644 --- a/packages/marshal/NEWS.md +++ b/packages/marshal/NEWS.md @@ -1,5 +1,17 @@ User-visible changes in `@endo/marshal`: +# Next release + +Switch from ambient to exported types. +Include type declarations (`.d.ts`) generated from JSDoc to avoid requiring +dependents to parse `.js` files in their `node_modules`. + +In order to use the types from `@endo/marshal` you now need to import them +explicitly. For example, to make them available in scope, use the following: +- JSDoc: `/** @typedef {import('@endo/marshal').PassStyle} PassStyle */` +- TypeScript: `import type { PassStyle } from '@endo/marshal'` + + # v0.5.3 (2021-01-27) Includes TypeScript definitions in published artifact. diff --git a/packages/marshal/exported.js b/packages/marshal/exported.js deleted file mode 100644 index f4cba017ea..0000000000 --- a/packages/marshal/exported.js +++ /dev/null @@ -1 +0,0 @@ -import './src/types.js'; diff --git a/packages/marshal/index.js b/packages/marshal/index.js index fcb824728a..8144bdad60 100644 --- a/packages/marshal/index.js +++ b/packages/marshal/index.js @@ -39,3 +39,6 @@ export { isRecord, isCopyArray, } from './src/typeGuards.js'; + +// eslint-disable-next-line import/export +export * from './src/types.js'; diff --git a/packages/marshal/jsconfig.build.json b/packages/marshal/jsconfig.build.json new file mode 100644 index 0000000000..13018509fd --- /dev/null +++ b/packages/marshal/jsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./jsconfig.json", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "emitDeclarationOnly": true, + "declarationMap": true + }, + "exclude": ["test/"] +} diff --git a/packages/marshal/package.json b/packages/marshal/package.json index 016bda94f0..5d76329268 100644 --- a/packages/marshal/package.json +++ b/packages/marshal/package.json @@ -9,6 +9,9 @@ }, "scripts": { "build": "exit 0", + "clean": "tsc --build jsconfig.build.json --clean", + "prepack": "tsc --build jsconfig.build.json", + "postpack": "yarn clean", "test": "ava", "test:c8": "c8 $C8_OPTIONS ava --config=ava-nesm.config.js", "test:xs": "exit 0", @@ -47,9 +50,11 @@ "files": [ "LICENSE*", "SECURITY*", + "NEWS*", "src", "*.js", - "*.ts" + "*.ts", + "*.map" ], "eslintConfig": { "extends": [ diff --git a/packages/marshal/src/deeplyFulfilled.js b/packages/marshal/src/deeplyFulfilled.js index 3084cf31e8..dc2104e9aa 100644 --- a/packages/marshal/src/deeplyFulfilled.js +++ b/packages/marshal/src/deeplyFulfilled.js @@ -3,15 +3,14 @@ /// import { E } from '@endo/eventual-send'; -/** - * @template T - * @typedef {import('@endo/eventual-send').ERef} ERef - */ import { isPromise } from '@endo/promise-kit'; import { getTag, isObject } from './helpers/passStyle-helpers.js'; import { makeTagged } from './makeTagged.js'; import { passStyleOf } from './passStyleOf.js'; +/** @typedef {import('./types.js').Passable} Passable */ +/** @template T @typedef {import('@endo/eventual-send').ERef} ERef */ + const { details: X, quote: q } = assert; const { ownKeys } = Reflect; const { fromEntries } = Object; diff --git a/packages/marshal/src/helpers/copyArray.js b/packages/marshal/src/helpers/copyArray.js index f6ec450546..c492c292f4 100644 --- a/packages/marshal/src/helpers/copyArray.js +++ b/packages/marshal/src/helpers/copyArray.js @@ -2,8 +2,6 @@ /// -import '../types.js'; -import './internal-types.js'; import { assertChecker, checkNormalProperty } from './passStyle-helpers.js'; const { details: X } = assert; @@ -13,7 +11,7 @@ const { isArray, prototype: arrayPrototype } = Array; /** * - * @type {PassStyleHelper} + * @type {import('./internal-types.js').PassStyleHelper} */ export const CopyArrayHelper = harden({ styleName: 'copyArray', diff --git a/packages/marshal/src/helpers/copyRecord.js b/packages/marshal/src/helpers/copyRecord.js index 92dcf4b1bc..05c16e23e1 100644 --- a/packages/marshal/src/helpers/copyRecord.js +++ b/packages/marshal/src/helpers/copyRecord.js @@ -8,9 +8,6 @@ import { checkNormalProperty, } from './passStyle-helpers.js'; -import '../types.js'; -import './internal-types.js'; - const { details: X } = assert; const { ownKeys } = Reflect; const { @@ -21,7 +18,7 @@ const { /** * - * @type {PassStyleHelper} + * @type {import('./internal-types.js').PassStyleHelper} */ export const CopyRecordHelper = harden({ styleName: 'copyRecord', diff --git a/packages/marshal/src/helpers/error.js b/packages/marshal/src/helpers/error.js index b6fa37315e..2f2d745a49 100644 --- a/packages/marshal/src/helpers/error.js +++ b/packages/marshal/src/helpers/error.js @@ -2,10 +2,10 @@ /// -import '../types.js'; -import './internal-types.js'; import { assertChecker } from './passStyle-helpers.js'; +/** @typedef {import('./internal-types.js').PassStyleHelper} PassStyleHelper */ + const { details: X } = assert; const { getPrototypeOf, getOwnPropertyDescriptors } = Object; const { ownKeys } = Reflect; diff --git a/packages/marshal/src/helpers/internal-types.js b/packages/marshal/src/helpers/internal-types.js index c813fe8345..5338fa00f6 100644 --- a/packages/marshal/src/helpers/internal-types.js +++ b/packages/marshal/src/helpers/internal-types.js @@ -2,6 +2,12 @@ /// +export {}; + +/** @typedef {import('../types.js').Checker} Checker */ +/** @typedef {import('../types.js').PassStyle} PassStyle */ +/** @typedef {import('../types.js').PassStyleOf} PassStyleOf */ + /** * The PassStyleHelper are only used to make a `passStyleOf` function. * Thus, it should not depend on an ambient one. Rather, each helper should be diff --git a/packages/marshal/src/helpers/passStyle-helpers.js b/packages/marshal/src/helpers/passStyle-helpers.js index 5eaab77de4..37b3dbfcf3 100644 --- a/packages/marshal/src/helpers/passStyle-helpers.js +++ b/packages/marshal/src/helpers/passStyle-helpers.js @@ -2,8 +2,8 @@ /// -import '../types.js'; -import './internal-types.js'; +/** @typedef {import('../types.js').Checker} Checker */ +/** @typedef {import('../types.js').PassStyle} PassStyle */ const { details: X, quote: q } = assert; const { diff --git a/packages/marshal/src/helpers/remotable.js b/packages/marshal/src/helpers/remotable.js index e563566999..a87a47340b 100644 --- a/packages/marshal/src/helpers/remotable.js +++ b/packages/marshal/src/helpers/remotable.js @@ -2,8 +2,6 @@ /// -import '../types.js'; -import './internal-types.js'; import { assertChecker, canBeMethod, @@ -15,6 +13,12 @@ import { } from './passStyle-helpers.js'; import { getEnvironmentOption } from './environment-options.js'; +/** @typedef {import('../types.js').Checker} Checker */ +/** @typedef {import('../types.js').InterfaceSpec} InterfaceSpec */ +/** @typedef {import('../types.js').MarshalGetInterfaceOf} MarshalGetInterfaceOf */ +/** @typedef {import('./internal-types.js').PassStyleHelper} PassStyleHelper */ +/** @typedef {import('../types.js').Remotable} Remotable */ + const { details: X, quote: q } = assert; const { ownKeys } = Reflect; const { prototype: functionPrototype } = Function; diff --git a/packages/marshal/src/helpers/tagged.js b/packages/marshal/src/helpers/tagged.js index 6bfdf56c36..500db88fd3 100644 --- a/packages/marshal/src/helpers/tagged.js +++ b/packages/marshal/src/helpers/tagged.js @@ -9,16 +9,13 @@ import { checkNormalProperty, } from './passStyle-helpers.js'; -import '../types.js'; -import './internal-types.js'; - const { details: X } = assert; const { ownKeys } = Reflect; const { getPrototypeOf, prototype: objectPrototype } = Object; /** * - * @type {PassStyleHelper} + * @type {import('./internal-types.js').PassStyleHelper} */ export const TaggedHelper = harden({ styleName: 'tagged', diff --git a/packages/marshal/src/make-far.js b/packages/marshal/src/make-far.js index ab431a0a1a..697ac76b23 100644 --- a/packages/marshal/src/make-far.js +++ b/packages/marshal/src/make-far.js @@ -10,6 +10,8 @@ import { } from './helpers/remotable.js'; import { pureCopy } from './pureCopy.js'; +/** @typedef {import('./types.js').InterfaceSpec} InterfaceSpec */ + const { quote: q, details: X } = assert; const { prototype: functionPrototype } = Function; @@ -81,8 +83,8 @@ const assertCanBeRemotable = candidate => * Carol's `iface` as misrepresented by VatA. * @param {undefined} [props=undefined] Currently may only be undefined. * That plan is that own-properties are copied to the remotable - * @param {object} [remotable={}] The object used as the remotable - * @returns {object} remotable, modified for debuggability + * @param {any} [remotable={}] The object used as the remotable + * @returns {any} remotable, modified for debuggability */ export const Remotable = ( iface = 'Remotable', diff --git a/packages/marshal/src/marshal-justin.js b/packages/marshal/src/marshal-justin.js index c9f47c0092..f0006518a3 100644 --- a/packages/marshal/src/marshal-justin.js +++ b/packages/marshal/src/marshal-justin.js @@ -5,11 +5,12 @@ import { Nat } from '@endo/nat'; import { QCLASS } from './marshal.js'; -import './types.js'; import { getErrorConstructor } from './helpers/error.js'; import { isObject } from './helpers/passStyle-helpers.js'; import { AtAtPrefixPattern, passableSymbolForName } from './helpers/symbol.js'; +/** @typedef {import('./types.js').Encoding} Encoding */ + const { ownKeys } = Reflect; const { isArray } = Array; const { stringify: quote } = JSON; diff --git a/packages/marshal/src/marshal-stringify.js b/packages/marshal/src/marshal-stringify.js index d54c655629..d657c14126 100644 --- a/packages/marshal/src/marshal-stringify.js +++ b/packages/marshal/src/marshal-stringify.js @@ -3,15 +3,15 @@ import { makeMarshal } from './marshal.js'; -import './types.js'; +/** @typedef {import('./types.js').OnlyData} OnlyData */ const { details: X } = assert; -/** @type {ConvertValToSlot} */ +/** @type {import('./types.js').ConvertValToSlot} */ const doNotConvertValToSlot = val => assert.fail(X`Marshal's stringify rejects presences and promises ${val}`); -/** @type {ConvertSlotToVal} */ +/** @type {import('./types.js').ConvertSlotToVal} */ const doNotConvertSlotToVal = (slot, _iface) => assert.fail(X`Marshal's parse must not encode any slots ${slot}`); diff --git a/packages/marshal/src/marshal.js b/packages/marshal/src/marshal.js index de832b840b..53d80019b3 100644 --- a/packages/marshal/src/marshal.js +++ b/packages/marshal/src/marshal.js @@ -5,7 +5,6 @@ import { Nat } from '@endo/nat'; import { assertPassable, passStyleOf } from './passStyleOf.js'; -import './types.js'; import { getInterfaceOf } from './helpers/remotable.js'; import { ErrorHelper, getErrorConstructor } from './helpers/error.js'; import { makeTagged } from './makeTagged.js'; @@ -16,6 +15,15 @@ import { passableSymbolForName, } from './helpers/symbol.js'; +/** @typedef {import('./types.js').MakeMarshalOptions} MakeMarshalOptions */ +/** @template Slot @typedef {import('./types.js').ConvertSlotToVal} ConvertSlotToVal */ +/** @template Slot @typedef {import('./types.js').ConvertValToSlot} ConvertValToSlot */ +/** @template Slot @typedef {import('./types.js').Serialize} Serialize */ +/** @template Slot @typedef {import('./types.js').Unserialize} Unserialize */ +/** @typedef {import('./types.js').Passable} Passable */ +/** @typedef {import('./types.js').InterfaceSpec} InterfaceSpec */ +/** @typedef {import('./types.js').Encoding} Encoding */ + const { ownKeys } = Reflect; const { isArray } = Array; const { @@ -34,14 +42,18 @@ const { details: X, quote: q } = assert; const QCLASS = '@qclass'; export { QCLASS }; +/** @type {ConvertValToSlot} */ const defaultValToSlotFn = x => x; +/** @type {ConvertSlotToVal} */ const defaultSlotToValFn = (x, _) => x; /** * @template Slot - * @type {MakeMarshal} + * @param {ConvertValToSlot} [convertValToSlot] + * @param {ConvertSlotToVal} [convertSlotToVal] + * @param {MakeMarshalOptions} [options] */ -export function makeMarshal( +export const makeMarshal = ( convertValToSlot = defaultValToSlotFn, convertSlotToVal = defaultSlotToValFn, { @@ -55,7 +67,7 @@ export function makeMarshal( marshalSaveError = err => console.log('Temporary logging of sent error', err), } = {}, -) { +) => { assert.typeof(marshalName, 'string'); assert( errorTagging === 'on' || errorTagging === 'off', @@ -67,7 +79,6 @@ export function makeMarshal( }; /** - * @template Slot * @type {Serialize} */ const serialize = root => { @@ -482,7 +493,6 @@ export function makeMarshal( }; /** - * @template Slot * @type {Unserialize} */ const unserialize = data => { @@ -507,4 +517,4 @@ export function makeMarshal( serialize, unserialize, }); -} +}; diff --git a/packages/marshal/src/passStyleOf.js b/packages/marshal/src/passStyleOf.js index 6d9d7917c8..ec5cbea1fb 100644 --- a/packages/marshal/src/passStyleOf.js +++ b/packages/marshal/src/passStyleOf.js @@ -11,10 +11,14 @@ import { TaggedHelper } from './helpers/tagged.js'; import { RemotableHelper } from './helpers/remotable.js'; import { ErrorHelper } from './helpers/error.js'; -import './types.js'; -import './helpers/internal-types.js'; import { assertPassableSymbol } from './helpers/symbol.js'; +/** @typedef {import('./helpers/internal-types.js').PassStyleHelper} PassStyleHelper */ +/** @typedef {import('./types.js').Passable} Passable */ +/** @typedef {import('./types.js').PassStyle} PassStyle */ +/** @typedef {import('./types.js').PassStyleOf} PassStyleOf */ +/** @typedef {import('./types.js').PrimitiveStyle} PrimitiveStyle */ + /** @typedef {Exclude} HelperPassStyle */ const { details: X, quote: q } = assert; diff --git a/packages/marshal/src/pureCopy.js b/packages/marshal/src/pureCopy.js index 323d7861cb..0579ef6ce3 100644 --- a/packages/marshal/src/pureCopy.js +++ b/packages/marshal/src/pureCopy.js @@ -4,6 +4,9 @@ import { getTag } from './helpers/passStyle-helpers.js'; import { makeTagged } from './makeTagged.js'; import { passStyleOf } from './passStyleOf.js'; +/** @typedef {import('./types.js').OnlyData} OnlyData */ +/** @typedef {import('./types.js').CopyTagged} CopyTagged */ + const { is } = Object; const { details: X, quote: q } = assert; diff --git a/packages/marshal/src/typeGuards.js b/packages/marshal/src/typeGuards.js index c789689b15..a41b079187 100644 --- a/packages/marshal/src/typeGuards.js +++ b/packages/marshal/src/typeGuards.js @@ -2,6 +2,11 @@ import { passStyleOf } from './passStyleOf.js'; +/** @typedef {import('./types.js').Passable} Passable */ +/** @template T @typedef {import('./types.js').CopyArray} CopyArray */ +/** @template T @typedef {import('./types.js').CopyRecord} CopyRecord */ +/** @typedef {import('./types.js').Remotable} Remotable */ + const { details: X, quote: q } = assert; /** diff --git a/packages/marshal/src/types.js b/packages/marshal/src/types.js index 084887df73..b777892c67 100644 --- a/packages/marshal/src/types.js +++ b/packages/marshal/src/types.js @@ -3,6 +3,8 @@ /// +export {}; + /** * @typedef { "undefined" | "null" | * "boolean" | "number" | "bigint" | "string" | "symbol" @@ -180,7 +182,7 @@ /** * @template Slot - * @typedef CapData + * @typedef {Object} CapData * @property {string} body A JSON.stringify of an Encoding * @property {Slot[]} slots */ @@ -201,22 +203,13 @@ /** * @template Slot - * @typedef Marshal + * @typedef {Object} Marshal * @property {Serialize} serialize * @property {Unserialize} unserialize */ /** - * @template Slot - * @callback MakeMarshal - * @param {ConvertValToSlot=} convertValToSlot - * @param {ConvertSlotToVal=} convertSlotToVal - * @param {MakeMarshalOptions=} options - * @returns {Marshal} - */ - -/** - * @typedef MakeMarshalOptions + * @typedef {Object} MakeMarshalOptions * @property {'on'|'off'=} errorTagging controls whether serialized errors * also carry tagging information, made from `marshalName` and numbers * generated (currently by counting) starting at `errorIdNum`. The diff --git a/packages/marshal/test/test-marshal-far-obj.js b/packages/marshal/test/test-marshal-far-obj.js index 0a9f9fe87f..6d7ecefaef 100644 --- a/packages/marshal/test/test-marshal-far-obj.js +++ b/packages/marshal/test/test-marshal-far-obj.js @@ -59,9 +59,10 @@ test('Remotable/getInterfaceOf', t => { t.is(p2.birthYear(2020), 1956, `birthYear() works`); // Remotables and Fars can be serialized, of course - function convertValToSlot(_val) { + /** @type {import('../src/types.js').ConvertValToSlot} */ + const convertValToSlot = _val => { return 'slot'; - } + }; const m = makeMarshal(convertValToSlot); t.deepEqual(m.serialize(p2), { body: JSON.stringify({