Skip to content

Commit

Permalink
Merge pull request #1765 from endojs/markm-tolerate-hide-extra-args
Browse files Browse the repository at this point in the history
fix(exo)!: extra undeclared args dropped
  • Loading branch information
erights authored Sep 18, 2023
2 parents 25c44ba + 9de852b commit 9ef7e38
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 10 deletions.
41 changes: 31 additions & 10 deletions packages/exo/src/exo-tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,31 @@ const { defineProperties, fromEntries } = Object;
*/
const MinMethodGuard = M.call().rest(M.any()).returns(M.any());

const defendSyncArgs = (args, methodGuardPayload, label) => {
/**
* @param {Passable[]} syncArgs
* @param {MethodGuardPayload} methodGuardPayload
* @param {string} [label]
* @returns {Passable[]} Returns the args that should be passed to the
* raw method
*/
const defendSyncArgs = (syncArgs, methodGuardPayload, label = undefined) => {
const { argGuards, optionalArgGuards, restArgGuard } = methodGuardPayload;
const paramsPattern = M.splitArray(
argGuards,
optionalArgGuards,
restArgGuard,
);
mustMatch(harden(args), paramsPattern, label);
mustMatch(harden(syncArgs), paramsPattern, label);
if (restArgGuard !== undefined) {
return syncArgs;
}
const declaredLen =
argGuards.length + (optionalArgGuards ? optionalArgGuards.length : 0);
if (syncArgs.length <= declaredLen) {
return syncArgs;
}
// Ignore extraneous arguments, as a JS function call would do.
return syncArgs.slice(0, declaredLen);
};

/**
Expand All @@ -52,9 +69,13 @@ const defendSyncMethod = (method, methodGuardPayload, label) => {
const { returnGuard } = methodGuardPayload;
const { syncMethod } = {
// Note purposeful use of `this` and concise method syntax
syncMethod(...args) {
defendSyncArgs(harden(args), methodGuardPayload, label);
const result = apply(method, this, args);
syncMethod(...syncArgs) {
const realArgs = defendSyncArgs(
harden(syncArgs),
methodGuardPayload,
label,
);
const result = apply(method, this, realArgs);
mustMatch(harden(result), returnGuard, `${label}: result`);
return result;
},
Expand Down Expand Up @@ -83,9 +104,9 @@ const desync = methodGuardPayload => {
return {
awaitIndexes,
rawMethodGuardPayload: {
...methodGuardPayload,
argGuards: rawArgGuards.slice(0, argGuards.length),
optionalArgGuards: rawArgGuards.slice(argGuards.length),
restArgGuard,
},
};
};
Expand All @@ -98,13 +119,13 @@ const defendAsyncMethod = (method, methodGuardPayload, label) => {
asyncMethod(...args) {
const awaitList = awaitIndexes.map(i => args[i]);
const p = Promise.all(awaitList);
const rawArgs = [...args];
const syncArgs = [...args];
const resultP = E.when(p, awaitedArgs => {
for (let j = 0; j < awaitIndexes.length; j += 1) {
rawArgs[awaitIndexes[j]] = awaitedArgs[j];
syncArgs[awaitIndexes[j]] = awaitedArgs[j];
}
defendSyncArgs(rawArgs, rawMethodGuardPayload, label);
return apply(method, this, rawArgs);
const realArgs = defendSyncArgs(syncArgs, rawMethodGuardPayload, label);
return apply(method, this, realArgs);
});
return E.when(resultP, result => {
mustMatch(harden(result), returnGuard, `${label}: result`);
Expand Down
13 changes: 13 additions & 0 deletions packages/exo/test/test-heap-classes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ import {
} from '../src/exo-makers.js';
import { GET_INTERFACE_GUARD } from '../src/exo-tools.js';

const NoExtraI = M.interface('NoExtra', {
foo: M.call().returns(),
});

test('what happens with extra arguments', t => {
const exo = makeExo('WithExtra', NoExtraI, {
foo(x) {
t.is(x, undefined);
},
});
exo.foo('an extra arg');
});

const UpCounterI = M.interface('UpCounter', {
incr: M.call()
// TODO M.number() should not be needed to get a better error message
Expand Down

0 comments on commit 9ef7e38

Please sign in to comment.