Skip to content

Commit

Permalink
refactor(marshal): split promise own prop check
Browse files Browse the repository at this point in the history
  • Loading branch information
mhofman committed Aug 24, 2022
1 parent e896ac2 commit cc41295
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 22 deletions.
42 changes: 22 additions & 20 deletions packages/marshal/src/helpers/safe-promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ const { details: X, quote: q } = assert;
const { isFrozen, getPrototypeOf } = Object;
const { ownKeys } = Reflect;

/**
* @param {Promise} pr The value to examine
* @param {Checker} [check]
* @returns {pr is Promise} Whether it is a safe promise
*/
const checkPromiseOwnKeys = (pr, check = x => x) => {
const keys = ownKeys(pr);

return check(
keys.length === 0,
X`${pr} - Must not have any own properties: ${q(keys)}`,
);
};

/**
* Under Hardened JS a promise is "safe" if its `then` method can be called
* synchronously without giving the promise an opportunity for a
Expand All @@ -27,26 +41,14 @@ const { ownKeys } = Reflect;
* @param {Checker} [check]
* @returns {pr is Promise} Whether it is a safe promise
*/
const checkSafePromise = (pr, check = x => x) => {
let keys;
return (
check(isFrozen(pr), X`${pr} - Must be frozen`) &&
check(isPromise(pr), X`${pr} - Must be a promise`) &&
check(
getPrototypeOf(pr) === Promise.prototype,
X`${pr} - Must inherit from Promise.prototype: ${q(getPrototypeOf(pr))}`,
) &&
check(
// Suppressing prettier for the following line because it wants to
// remove the "extra" parens around `pr`. However, these parens are
// required for the TypeScript case syntax. We know this case is safe
// because we only get here if `ifPromise(pr)` already passed.
// eslint-disable-next-line prettier/prettier
(keys = ownKeys(/** @type {Promise} pr */(pr))).length === 0,
X`{pr} - Must not have any own properties: ${q(keys)}`,
)
);
};
const checkSafePromise = (pr, check = x => x) =>
check(isFrozen(pr), X`${pr} - Must be frozen`) &&
check(isPromise(pr), X`${pr} - Must be a promise`) &&
check(
getPrototypeOf(pr) === Promise.prototype,
X`${pr} - Must inherit from Promise.prototype: ${q(getPrototypeOf(pr))}`,
) &&
checkPromiseOwnKeys(/** @type {Promise} */ (pr), check);
harden(checkSafePromise);

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/marshal/test/test-passStyleOf.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ test('some passStyleOf rejections', t => {
prbad2.extra = 'unexpected own property';
harden(prbad2);
t.throws(() => passStyleOf(prbad2), {
message: /{pr} - Must not have any own properties: \["extra"\]/,
message: /\[Promise\]" - Must not have any own properties: \["extra"\]/,
});

const prbad3 = Promise.resolve();
Object.defineProperty(prbad3, 'then', { value: () => 'bad then' });
harden(prbad3);
t.throws(() => passStyleOf(prbad3), {
message: /{pr} - Must not have any own properties: \["then"\]/,
message: /\[Promise\]" - Must not have any own properties: \["then"\]/,
});

const thenable1 = harden({ then: () => 'thenable' });
Expand Down

0 comments on commit cc41295

Please sign in to comment.