src/collectArgs.js
/**
* A helper method interpreting a given function definition
* following the function spec from TODO:link-to-func-specification
*/
export default async function collectArgs (func, call, hooks) {
// HACK: just use the first method
// TODO: why would there be multiple ones?
// FIXME: this might be very bad, because Object does
// not have a guaranteed order
const method = Object.values(func.methods)[0]
const unpack = hooks.unpack
let args = []
let namedArgs
// Using `method.params` specification, map the call's arguments onto the method's parameters
let argsIndex = 0
let argsUsed = 0
let namedArgsUsed = []
if (method.params) {
for (let param of method.params) {
if (param.repeats) {
// Put the remaining arguments into an array
let remaining = []
for (; argsIndex < call.args.length; argsIndex++) {
remaining.push(await unpack(call.args[argsIndex]))
argsUsed++
}
args.push(remaining)
break
} else if (param.extends) {
// Put the remaining named arguments into an object
if (call.namedArgs) {
namedArgs = {}
for (let name of Object.keys(call.namedArgs)) {
if (namedArgsUsed.indexOf(name) < 0) {
namedArgs[name] = await unpack(call.namedArgs[name])
namedArgsUsed.push(param.name)
}
}
}
break
} else {
// Get the argument for the parameter either by name or by index
let arg
if (call.namedArgs) {
arg = call.namedArgs[param.name]
if (arg) namedArgsUsed.push(param.name)
}
if (!arg && call.args) {
arg = call.args[argsIndex]
if (arg) argsUsed++
}
if (!arg && !param.default) {
let msg = `Function '${func.name}' requires parameter '${param.name}'`
throw new Error(msg)
}
if (arg) args.push(await unpack(arg))
else args.push(undefined)
}
argsIndex++
}
}
// Check that there are no extra, unused arguments in call
if (call.args && argsUsed < call.args.length) {
const extra = call.args.length - argsUsed
throw new Error(`Function was supplied ${extra} extra arguments`)
}
if (call.namedArgs && namedArgsUsed.length < Object.keys(call.namedArgs).length) {
const extra = Object.keys(call.namedArgs).filter((arg) => namedArgsUsed.indexOf(arg) < 0)
.map((arg) => `"${arg}"`)
.join(', ')
throw new Error(`Function was supplied extra named arguments ${extra}`)
}
return { args, namedArgs }
}