Skip to content

Commit

Permalink
fix(exo)!: extra undeclared args dropped
Browse files Browse the repository at this point in the history
  • Loading branch information
erights committed Sep 12, 2023
1 parent 5feb9ed commit a154713
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
26 changes: 21 additions & 5 deletions packages/exo/src/exo-tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ const { defineProperties, fromEntries } = Object;
*/
const MinMethodGuard = M.call().rest(M.any()).returns(M.any());

/**
* @param {Passable[]} args
* @param {MethodGuardPayload} methodGuardPayload
* @param {string | undefined} label
* @returns {Passable[]} Returns the args that should be passed to the
* raw method
*/
const defendSyncArgs = (args, methodGuardPayload, label) => {
const { argGuards, optionalArgGuards, restArgGuard } = methodGuardPayload;
const paramsPattern = M.splitArray(
Expand All @@ -40,6 +47,15 @@ const defendSyncArgs = (args, methodGuardPayload, label) => {
restArgGuard,
);
mustMatch(harden(args), paramsPattern, label);
if (restArgGuard !== undefined) {
return args;
}
const declaredLen =
argGuards.length + (optionalArgGuards ? optionalArgGuards.length : 0);
if (args.length <= declaredLen) {
return args;
}
return args.slice(0, declaredLen);
};

/**
Expand All @@ -53,8 +69,8 @@ const defendSyncMethod = (method, methodGuardPayload, label) => {
const { syncMethod } = {
// Note purposeful use of `this` and concise method syntax
syncMethod(...args) {
defendSyncArgs(harden(args), methodGuardPayload, label);
const result = apply(method, this, args);
const realArgs = defendSyncArgs(harden(args), methodGuardPayload, label);
const result = apply(method, this, realArgs);
mustMatch(harden(result), returnGuard, `${label}: result`);
return result;
},
Expand Down Expand Up @@ -83,9 +99,9 @@ const desync = methodGuardPayload => {
return {
awaitIndexes,
rawMethodGuardPayload: {
...methodGuardPayload,
argGuards: rawArgGuards.slice(0, argGuards.length),
optionalArgGuards: rawArgGuards.slice(argGuards.length),
restArgGuard,
},
};
};
Expand All @@ -103,8 +119,8 @@ const defendAsyncMethod = (method, methodGuardPayload, label) => {
for (let j = 0; j < awaitIndexes.length; j += 1) {
rawArgs[awaitIndexes[j]] = awaitedArgs[j];
}
defendSyncArgs(rawArgs, rawMethodGuardPayload, label);
return apply(method, this, rawArgs);
const realArgs = defendSyncArgs(rawArgs, 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(8);
});

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 a154713

Please sign in to comment.