From 5762dd48e814e2e8435f666019e527d982eddbbd Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Sun, 18 Feb 2024 12:26:09 -0800 Subject: [PATCH] fix(ses,pass-style,marshal): tolerate platforms prior to AggregateError --- packages/common/NEWS.md | 4 ++-- packages/errors/NEWS.md | 2 +- packages/marshal/NEWS.md | 2 +- packages/marshal/test/test-marshal-capdata.js | 19 ++++++++---------- .../marshal/test/test-marshal-smallcaps.js | 14 +++++++------ packages/pass-style/NEWS.md | 2 +- packages/pass-style/src/error.js | 9 ++++++++- packages/pass-style/src/passStyleOf.js | 6 ++++-- .../pass-style/test/test-extended-errors.js | 7 +++++-- packages/patterns/NEWS.md | 2 +- packages/ses/NEWS.md | 2 +- packages/ses/src/error/assert.js | 5 ++++- packages/ses/src/permits.js | 20 +++++++++++++++---- .../test-aggregate-error-console-demo.js | 4 ++++ .../error/test-aggregate-error-console.js | 4 ++++ .../ses/test/error/test-aggregate-error.js | 8 ++++++++ packages/ses/test/error/test-error-cause.js | 4 ++++ 17 files changed, 80 insertions(+), 34 deletions(-) diff --git a/packages/common/NEWS.md b/packages/common/NEWS.md index 59e2df12c3..74e7f95707 100644 --- a/packages/common/NEWS.md +++ b/packages/common/NEWS.md @@ -1,8 +1,8 @@ User-visible changes in `@endo/common`: -# next release +# Next release -- Change to `throwLabeled` +- `throwLabeled` parameterized error construction - Like the assertion functions/methods that were parameterized by an error constructor (`makeError`, `assert`, `assert.fail`, `assert.equal`), `throwLabeled` now also accepts named options `cause` and `errors` in its diff --git a/packages/errors/NEWS.md b/packages/errors/NEWS.md index 721867a95e..7cc4c2fbd4 100644 --- a/packages/errors/NEWS.md +++ b/packages/errors/NEWS.md @@ -1,6 +1,6 @@ User-visible changes in `@endo/errors`: -# next release +# Next release - `AggegateError` support - Assertion functions/methods that were parameterized by an error constructor diff --git a/packages/marshal/NEWS.md b/packages/marshal/NEWS.md index bcf9f35117..79f302c736 100644 --- a/packages/marshal/NEWS.md +++ b/packages/marshal/NEWS.md @@ -1,6 +1,6 @@ User-visible changes in `@endo/marshal`: -# next release +# Next release - Sending and receiving extended errors. - As of the previous release, `@endo/marshal` tolerates extra error diff --git a/packages/marshal/test/test-marshal-capdata.js b/packages/marshal/test/test-marshal-capdata.js index e0251a97e8..10712862a3 100644 --- a/packages/marshal/test/test-marshal-capdata.js +++ b/packages/marshal/test/test-marshal-capdata.js @@ -154,12 +154,13 @@ test('unserialize errors', t => { }); test('unserialize extended errors', t => { + if (typeof AggregateError === 'undefined') { + t.pass('skip test on platforms prior to AggregateError'); + return; + } const { unserialize } = makeTestMarshal(); const uns = body => unserialize({ body, slots: [] }); - // TODO cause, errors, and AggregateError will eventually be recognized. - // See https://github.com/endojs/endo/pull/2042 - const refErr = uns( '{"@qclass":"error","message":"msg","name":"ReferenceError","extraProp":"foo","cause":"bar","errors":["zip","zap"]}', ); @@ -167,7 +168,6 @@ test('unserialize extended errors', t => { t.false('extraProp' in refErr); t.false('cause' in refErr); t.false('errors' in refErr); - console.log('error with extra prop', refErr); const aggErr = uns( '{"@qclass":"error","message":"msg","name":"AggregateError","extraProp":"foo","cause":"bar","errors":["zip","zap"]}', @@ -176,7 +176,6 @@ test('unserialize extended errors', t => { t.false('extraProp' in aggErr); t.false('cause' in aggErr); t.is(aggErr.errors.length, 0); - console.log('error with extra prop', aggErr); const unkErr = uns( '{"@qclass":"error","message":"msg","name":"UnknownError","extraProp":"foo","cause":"bar","errors":["zip","zap"]}', @@ -185,10 +184,12 @@ test('unserialize extended errors', t => { t.false('extraProp' in unkErr); t.false('cause' in unkErr); t.false('errors' in unkErr); - console.log('error with extra prop', unkErr); }); -test('unserialize errors w recognized extensions', t => { +const testIfAggregateError = + typeof AggregateError !== 'undefined' ? test : test.skip; + +testIfAggregateError('unserialize errors w recognized extensions', t => { const { unserialize } = makeTestMarshal(); const uns = body => unserialize({ body, slots: [] }); @@ -201,7 +202,6 @@ test('unserialize errors w recognized extensions', t => { t.false('extraProp' in refErr); t.is(getPrototypeOf(refErr.cause), URIError.prototype); t.is(getPrototypeOf(refErr.errors[0]), URIError.prototype); - console.log('error with extra prop', refErr); const aggErr = uns( `{"@qclass":"error","message":"msg","name":"AggregateError","extraProp":"foo","cause":${errEnc},"errors":[${errEnc}]}`, @@ -210,7 +210,6 @@ test('unserialize errors w recognized extensions', t => { t.false('extraProp' in aggErr); t.is(getPrototypeOf(aggErr.cause), URIError.prototype); t.is(getPrototypeOf(aggErr.errors[0]), URIError.prototype); - console.log('error with extra prop', aggErr); const unkErr = uns( `{"@qclass":"error","message":"msg","name":"UnknownError","extraProp":"foo","cause":${errEnc},"errors":[${errEnc}]}`, @@ -219,8 +218,6 @@ test('unserialize errors w recognized extensions', t => { t.false('extraProp' in unkErr); t.is(getPrototypeOf(unkErr.cause), URIError.prototype); t.is(getPrototypeOf(unkErr.errors[0]), URIError.prototype); - - console.log('error with extra prop', unkErr); }); test('passStyleOf null is "null"', t => { diff --git a/packages/marshal/test/test-marshal-smallcaps.js b/packages/marshal/test/test-marshal-smallcaps.js index 9b285dbe02..917d7e03d0 100644 --- a/packages/marshal/test/test-marshal-smallcaps.js +++ b/packages/marshal/test/test-marshal-smallcaps.js @@ -160,6 +160,10 @@ test('smallcaps unserialize errors', t => { }); test('smallcaps unserialize extended errors', t => { + if (typeof AggregateError === 'undefined') { + t.pass('skip test on platforms prior to AggregateError'); + return; + } const { unserialize } = makeTestMarshal(); const uns = body => unserialize({ body, slots: [] }); @@ -170,7 +174,6 @@ test('smallcaps unserialize extended errors', t => { t.false('extraProp' in refErr); t.false('cause' in refErr); t.false('errors' in refErr); - console.log('error with extra prop', refErr); const aggErr = uns( '#{"#error":"msg","name":"AggregateError","extraProp":"foo","cause":"bar","errors":["zip","zap"]}', @@ -179,7 +182,6 @@ test('smallcaps unserialize extended errors', t => { t.false('extraProp' in aggErr); t.false('cause' in aggErr); t.is(aggErr.errors.length, 0); - console.log('error with extra prop', aggErr); const unkErr = uns( '#{"#error":"msg","name":"UnknownError","extraProp":"foo","cause":"bar","errors":["zip","zap"]}', @@ -188,10 +190,13 @@ test('smallcaps unserialize extended errors', t => { t.false('extraProp' in unkErr); t.false('cause' in unkErr); t.false('errors' in unkErr); - console.log('error with extra prop', unkErr); }); test('smallcaps unserialize errors w recognized extensions', t => { + if (typeof AggregateError === 'undefined') { + t.pass('skip test on platforms prior to AggregateError'); + return; + } const { unserialize } = makeTestMarshal(); const uns = body => unserialize({ body, slots: [] }); @@ -204,7 +209,6 @@ test('smallcaps unserialize errors w recognized extensions', t => { t.false('extraProp' in refErr); t.is(getPrototypeOf(refErr.cause), URIError.prototype); t.is(getPrototypeOf(refErr.errors[0]), URIError.prototype); - console.log('error with extra prop', refErr); const aggErr = uns( `#{"#error":"msg","name":"AggregateError","extraProp":"foo","cause":${errEnc},"errors":[${errEnc}]}`, @@ -213,7 +217,6 @@ test('smallcaps unserialize errors w recognized extensions', t => { t.false('extraProp' in aggErr); t.is(getPrototypeOf(refErr.cause), URIError.prototype); t.is(getPrototypeOf(refErr.errors[0]), URIError.prototype); - console.log('error with extra prop', aggErr); const unkErr = uns( `#{"#error":"msg","name":"UnknownError","extraProp":"foo","cause":${errEnc},"errors":[${errEnc}]}`, @@ -222,7 +225,6 @@ test('smallcaps unserialize errors w recognized extensions', t => { t.false('extraProp' in unkErr); t.is(getPrototypeOf(refErr.cause), URIError.prototype); t.is(getPrototypeOf(refErr.errors[0]), URIError.prototype); - console.log('error with extra prop', unkErr); }); test('smallcaps mal-formed @qclass', t => { diff --git a/packages/pass-style/NEWS.md b/packages/pass-style/NEWS.md index 767cc5cc17..45b41050ac 100644 --- a/packages/pass-style/NEWS.md +++ b/packages/pass-style/NEWS.md @@ -1,6 +1,6 @@ User-visible changes in `@endo/pass-style`: -# next release +# Next release - Now supports `AggegateError`, `error.errors`, `error.cause`. - A `Passable` error can now include an `error.cause` property whose diff --git a/packages/pass-style/src/error.js b/packages/pass-style/src/error.js index dc9d4afae5..5e70ec8baf 100644 --- a/packages/pass-style/src/error.js +++ b/packages/pass-style/src/error.js @@ -24,10 +24,17 @@ const errorConstructors = new Map( ['URIError', URIError], // https://github.com/endojs/endo/issues/550 - ['AggregateError', AggregateError], + // To accommodate platforms prior to AggregateError, we comment out the + // following line and instead conditionally add it to the map below. + // ['AggregateError', AggregateError], ]), ); +if (typeof AggregateError !== 'undefined') { + // Conditional, to accommodate platforms prior to AggregateError + errorConstructors.set('AggregateError', AggregateError); +} + /** * Because the error constructor returned by this function might be * `AggregateError`, which has different construction parameters diff --git a/packages/pass-style/src/passStyleOf.js b/packages/pass-style/src/passStyleOf.js index 1f2ddb05a8..f77e673bd5 100644 --- a/packages/pass-style/src/passStyleOf.js +++ b/packages/pass-style/src/passStyleOf.js @@ -239,9 +239,11 @@ harden(assertPassable); * * TODO Deprecate and ultimately delete @agoric/base-zone's `isPassable' in * favor of this one. + * See https://github.com/endojs/endo/issues/2096 * * TODO implement an isPassable that does not rely on try/catch. - * This implementation is just a standin until then + * This implementation is just a standin until then. + * See https://github.com/endojs/endo/issues/2096 * * @param {any} specimen * @returns {specimen is Passable} @@ -299,7 +301,7 @@ export const assertPassableError = err => { * Return a new passable error that propagates the diagnostic info of the * original, and is linked to the original as a note. * - * @param {Error | AggregateError} err + * @param {Error} err * @returns {Error} */ export const toPassableError = err => { diff --git a/packages/pass-style/test/test-extended-errors.js b/packages/pass-style/test/test-extended-errors.js index 0f653bf39a..1f24f4b5e5 100644 --- a/packages/pass-style/test/test-extended-errors.js +++ b/packages/pass-style/test/test-extended-errors.js @@ -18,6 +18,9 @@ test('style of extended errors', t => { const u3 = harden(URIError('u3', { cause: e1 })); t.is(passStyleOf(u3), 'error'); - const a4 = harden(AggregateError([e2, u3], 'a4', { cause: e1 })); - t.is(passStyleOf(a4), 'error'); + if (typeof AggregateError !== 'undefined') { + // Conditional, to accommodate platforms prior to AggregateError + const a4 = harden(AggregateError([e2, u3], 'a4', { cause: e1 })); + t.is(passStyleOf(a4), 'error'); + } }); diff --git a/packages/patterns/NEWS.md b/packages/patterns/NEWS.md index f2a706836c..e8281da1e0 100644 --- a/packages/patterns/NEWS.md +++ b/packages/patterns/NEWS.md @@ -1,6 +1,6 @@ User-visible changes in `@endo/patterns`: -# next release +# Next release - Add `M.tagged(tagPattern, payloadPattern)` for making patterns that match Passable Tagged objects. diff --git a/packages/ses/NEWS.md b/packages/ses/NEWS.md index b35dca6a43..c1bc12e6d3 100644 --- a/packages/ses/NEWS.md +++ b/packages/ses/NEWS.md @@ -1,6 +1,6 @@ User-visible changes in SES: -# next release +# Next release - Now supports `Promise.any`, `AggegateError`, `error.errors`, and `error.cause`. diff --git a/packages/ses/src/error/assert.js b/packages/ses/src/error/assert.js index 6dae9e3ae4..bacf5124c9 100644 --- a/packages/ses/src/error/assert.js +++ b/packages/ses/src/error/assert.js @@ -274,7 +274,10 @@ const makeError = ( const messageString = getMessageString(hiddenDetails); const opts = cause && { cause }; let error; - if (errConstructor === AggregateError) { + if ( + typeof AggregateError !== 'undefined' && + errConstructor === AggregateError + ) { error = AggregateError(errors || [], messageString, opts); } else { error = /** @type {ErrorConstructor} */ (errConstructor)( diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index bf3d33f4d2..611671dd6e 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1,4 +1,8 @@ /* eslint-disable no-restricted-globals */ +/* eslint max-lines: 0 */ + +import { arrayPush } from './commons.js'; + /** * @file Exports {@code whitelist}, a recursively defined * JSON record enumerating all intrinsics and their properties @@ -8,8 +12,6 @@ * @author Mark S. Miller */ -/* eslint max-lines: 0 */ - /** * constantProperties * non-configurable, non-writable data properties of all global objects. @@ -187,7 +189,8 @@ export const uniqueGlobalPropertyNames = { // All the "subclasses" of Error. These are collectively represented in the // ECMAScript spec by the meta variable NativeError. -export const NativeErrors = [ +/** @type {GenericErrorConstructor[]} */ +const NativeErrors = [ EvalError, RangeError, ReferenceError, @@ -195,9 +198,18 @@ export const NativeErrors = [ TypeError, URIError, // https://github.com/endojs/endo/issues/550 - AggregateError, + // Commented out to accommodate platforms prior to AggregateError. + // Instead, conditional push below. + // AggregateError, ]; +if (typeof AggregateError !== 'undefined') { + // Conditional, to accommodate platforms prior to AggregateError + arrayPush(NativeErrors, AggregateError); +} + +export { NativeErrors }; + /** *

Each JSON record enumerates the disposition of the properties on * some corresponding intrinsic object. diff --git a/packages/ses/test/error/test-aggregate-error-console-demo.js b/packages/ses/test/error/test-aggregate-error-console-demo.js index 8472d7ce91..ba2da6ae16 100644 --- a/packages/ses/test/error/test-aggregate-error-console-demo.js +++ b/packages/ses/test/error/test-aggregate-error-console-demo.js @@ -10,6 +10,10 @@ import '../../index.js'; lockdown(); test('aggregate error console demo', t => { + if (typeof AggregateError === 'undefined') { + t.pass('skip test on platforms prior to AggregateError'); + return; + } const e3 = Error('e3'); const e2 = Error('e2', { cause: e3 }); const u4 = URIError('u4', { cause: e2 }); diff --git a/packages/ses/test/error/test-aggregate-error-console.js b/packages/ses/test/error/test-aggregate-error-console.js index 417fcc85c8..ba192546be 100644 --- a/packages/ses/test/error/test-aggregate-error-console.js +++ b/packages/ses/test/error/test-aggregate-error-console.js @@ -5,6 +5,10 @@ import { throwsAndLogs } from './throws-and-logs.js'; lockdown(); test('aggregate error console', t => { + if (typeof AggregateError === 'undefined') { + t.pass('skip test on platforms prior to AggregateError'); + return; + } const e3 = Error('e3'); const e2 = Error('e2', { cause: e3 }); const u4 = URIError('u4', { cause: e2 }); diff --git a/packages/ses/test/error/test-aggregate-error.js b/packages/ses/test/error/test-aggregate-error.js index a95fbd114c..5c0b0b2466 100644 --- a/packages/ses/test/error/test-aggregate-error.js +++ b/packages/ses/test/error/test-aggregate-error.js @@ -6,6 +6,10 @@ const { getOwnPropertyDescriptor } = Object; lockdown(); test('aggregate error', t => { + if (typeof AggregateError === 'undefined') { + t.pass('skip test on platforms prior to AggregateError'); + return; + } const e1 = Error('e1'); const e2 = Error('e2', { cause: e1 }); const u3 = URIError('u3', { cause: e1 }); @@ -28,6 +32,10 @@ test('aggregate error', t => { }); test('Promise.any aggregate error', async t => { + if (typeof AggregateError === 'undefined') { + t.pass('skip test on platforms prior to AggregateError'); + return; + } const e1 = Error('e1'); const e2 = Error('e2', { cause: e1 }); const u3 = URIError('u3', { cause: e1 }); diff --git a/packages/ses/test/error/test-error-cause.js b/packages/ses/test/error/test-error-cause.js index 0416285afd..5cd32091f5 100644 --- a/packages/ses/test/error/test-error-cause.js +++ b/packages/ses/test/error/test-error-cause.js @@ -27,6 +27,10 @@ test('error cause', t => { enumerable: false, configurable: true, }); + if (typeof AggregateError === 'undefined') { + t.pass('skip rest of test on platforms prior to AggregateError'); + return; + } const a4 = AggregateError([e2, u3], 'a4', { cause: e1 }); t.is(a4.message, 'a4'); t.is(a4.cause, e1);