140 lines
6.4 KiB
JavaScript
140 lines
6.4 KiB
JavaScript
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
};
|
|
var _CallExpression_instances, _CallExpression_throwError, _CallExpression_getCalleeString;
|
|
import BaseJSNode from './BaseJSNode.js';
|
|
import { JinterError } from '../utils/index.js';
|
|
export default class CallExpression extends BaseJSNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
_CallExpression_instances.add(this);
|
|
}
|
|
run() {
|
|
let exp_object;
|
|
let exp_property;
|
|
if (this.node.callee.type === 'MemberExpression') {
|
|
exp_object = this.visitor.getName(this.node.callee.object);
|
|
exp_property = this.visitor.getName(this.node.callee.property);
|
|
}
|
|
else if (this.node.callee.type === 'Identifier') {
|
|
exp_property = this.node.callee.name;
|
|
}
|
|
// Obj.fn(...);
|
|
if (exp_object && this.visitor.listeners[exp_object]) {
|
|
const cb = this.visitor.listeners[exp_object](this.node, this.visitor);
|
|
if (cb !== '__continue_exec') {
|
|
return cb;
|
|
}
|
|
}
|
|
// ?.fn(...);
|
|
if (exp_property && exp_property !== 'toString' && this.visitor.listeners[exp_property]) {
|
|
const cb = this.visitor.listeners[exp_property](this.node, this.visitor);
|
|
if (cb !== '__continue_exec') {
|
|
return cb;
|
|
}
|
|
}
|
|
if (this.node.callee.type === 'MemberExpression') {
|
|
if (Builtins.has(this.node, this.visitor)) {
|
|
return Builtins.execute(this.node, this.visitor);
|
|
}
|
|
const obj = this.visitor.visitNode(this.node.callee.object);
|
|
const prop = this.node.callee.computed ? this.visitor.visitNode(this.node.callee.property) : this.visitor.getName(this.node.callee.property);
|
|
const args = this.node.arguments.map((arg) => this.visitor.visitNode(arg));
|
|
if (!obj)
|
|
__classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_throwError).call(this);
|
|
if (typeof obj[prop] !== 'function')
|
|
__classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_throwError).call(this);
|
|
if (obj[prop].toString().includes('[native code]'))
|
|
return obj[prop](...args);
|
|
return obj[prop](args);
|
|
}
|
|
const fn = this.visitor.visitNode(this.node.callee);
|
|
const args = this.node.arguments.map((arg) => this.visitor.visitNode(arg));
|
|
if (typeof fn !== 'function')
|
|
__classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_throwError).call(this);
|
|
return fn(args);
|
|
}
|
|
}
|
|
_CallExpression_instances = new WeakSet(), _CallExpression_throwError = function _CallExpression_throwError() {
|
|
if (this.node.callee.type === 'MemberExpression' || this.node.callee.type === 'Identifier') {
|
|
const callee_string = __classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_getCalleeString).call(this, this.node.callee);
|
|
throw new JinterError(`${callee_string} is not a function`);
|
|
}
|
|
else if (this.node.callee.type === 'SequenceExpression') {
|
|
const call = [];
|
|
const items = [];
|
|
call.push('(');
|
|
this.node.callee.expressions.forEach((expr) => {
|
|
if (expr.type === 'Literal') {
|
|
items.push(expr.raw || '');
|
|
}
|
|
else if (expr.type === 'Identifier') {
|
|
items.push(expr.name);
|
|
}
|
|
else if (expr.type === 'MemberExpression') {
|
|
if (expr.computed) {
|
|
items.push(`${this.visitor.getName(expr.object)}[${this.visitor.getName(expr.property) || '...'}]`);
|
|
}
|
|
else {
|
|
items.push(`${this.visitor.getName(expr.object)}.${this.visitor.getName(expr.property)}`);
|
|
}
|
|
}
|
|
});
|
|
call.push(items.join(', '));
|
|
call.push(')');
|
|
throw new JinterError(`${call.join('')} is not a function`);
|
|
}
|
|
}, _CallExpression_getCalleeString = function _CallExpression_getCalleeString(node) {
|
|
if (node.type === 'Identifier') {
|
|
return node.name;
|
|
}
|
|
else if (node.type === 'MemberExpression') {
|
|
const object_string = __classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_getCalleeString).call(this, node.object);
|
|
const property_string = node.computed ? `[${this.visitor.getName(node.property) || '...'}]` : `.${this.visitor.getName(node.property)}`;
|
|
return `${object_string}${property_string}`;
|
|
}
|
|
return '<unknown>';
|
|
};
|
|
class Builtins {
|
|
static has(node, visitor) {
|
|
var _a;
|
|
if (node.callee.type === 'MemberExpression') {
|
|
return !!((_a = this.builtins) === null || _a === void 0 ? void 0 : _a[visitor.getName(node.callee.property) || '']);
|
|
}
|
|
return false;
|
|
}
|
|
static execute(node, visitor) {
|
|
if (node.callee.type === 'MemberExpression') {
|
|
return this.builtins[visitor.getName(node.callee.property) || ''](node, visitor);
|
|
}
|
|
}
|
|
}
|
|
Builtins.builtins = {
|
|
// Override the forEach method so that the "this" arg is set correctly
|
|
forEach: (node, visitor) => {
|
|
const args = node.arguments.map((arg) => visitor.visitNode(arg));
|
|
if (node.callee.type === 'MemberExpression') {
|
|
const arr = visitor.visitNode(node.callee.object);
|
|
// Set forEach's “this” arg
|
|
if (args.length > 1) {
|
|
visitor.scope.set('_this', args.slice(-1)[0]);
|
|
}
|
|
// Execute callback function
|
|
let index = 0;
|
|
for (const element of arr) {
|
|
args[0]([element, index++, arr]);
|
|
}
|
|
}
|
|
else {
|
|
console.warn('Unhandled callee type:', node.callee.type);
|
|
}
|
|
},
|
|
// Also override the toString method so that it stringifies the correct object
|
|
toString: (node, visitor) => {
|
|
if (node.callee.type === 'MemberExpression') {
|
|
return visitor.visitNode(node.callee.object).toString();
|
|
}
|
|
}
|
|
};
|