silphius/app/swcx/evaluators/call.js
2024-06-17 05:20:01 -05:00

54 lines
1.6 KiB
JavaScript

import fastCall from '@/util/fast-call.js';
import {
isComputed,
isMemberExpression,
unwrap,
} from '@/swcx/types.js';
export default function(node, {evaluate, scope}) {
let asyncArgs = false;
const args = [];
for (let i = 0; i < node.arguments.length; i++) {
const {expression: arg} = node.arguments[i];
const {async, value} = evaluate(arg, {scope});
asyncArgs ||= async;
args.push(value);
}
const {callee: wrappedCallee} = node;
const callee = unwrap(wrappedCallee);
const callOptional = callee.wrapper?.optional || node.wrapper?.optional;
const invoke = (fn, holder, args) => {
if (callOptional && !fn) {
return undefined;
}
return fastCall(fn, holder, args);
};
if (!isMemberExpression(callee)) {
const {async, value} = evaluate(callee, {scope});
if (asyncArgs || async) {
return {
async: true,
value: Promise
.all([value, Promise.all(args)])
.then(([callee, args]) => invoke(callee, undefined, args)),
};
}
return {value: invoke(value, undefined, args)};
}
const {
object,
property,
} = callee;
const O = evaluate(object, {scope});
const P = isComputed(property) ? evaluate(property, {scope}) : {value: property.value};
if (asyncArgs || O.async || P.async) {
return {
async: true,
value: Promise
.all([O.value, P.value, Promise.all(args)])
.then(([O, P, args]) => invoke(callOptional ? O?.[P] : O[P], O, args)),
};
}
return {value: invoke(callOptional ? O.value?.[P.value] : O.value[P.value], O.value, args)};
}