import * as t from '@babel/types';
import { PAUSABLE_CALL_PATTERNS } from '../types.js';
export function isPausableCall(node) {
    if (!t.isAwaitExpression(node)) {
        return false;
    }
    const argument = node.argument;
    if (!t.isCallExpression(argument)) {
        return false;
    }
    return isPausableCallExpression(argument);
}
export function isPausableCallExpression(node) {
    const callee = node.callee;
    if (!t.isMemberExpression(callee)) {
        return false;
    }
    const fullPath = getMemberExpressionPath(callee);
    return PAUSABLE_CALL_PATTERNS.some((pattern) => pattern.method === '*'
        ? fullPath.startsWith(`${pattern.namespace}.`)
        : fullPath === `${pattern.namespace}.${pattern.method}`);
}
export function getMemberExpressionPath(node) {
    const parts = [];
    let current = node;
    while (t.isMemberExpression(current)) {
        if (t.isIdentifier(current.property)) {
            parts.unshift(current.property.name);
        }
        current = current.object;
    }
    if (t.isIdentifier(current)) {
        parts.unshift(current.name);
    }
    return parts.join('.');
}
export function containsAwait(node) {
    let hasAwait = false;
    const checkNode = (n) => {
        if (t.isAwaitExpression(n)) {
            hasAwait = true;
            return;
        }
        if (hasAwait)
            return;
        Object.keys(n).forEach((key) => {
            const value = n[key];
            if (Array.isArray(value)) {
                value.forEach((item) => {
                    if (item && typeof item === 'object' && item.type) {
                        checkNode(item);
                    }
                });
            }
            else if (value && typeof value === 'object' && value.type) {
                checkNode(value);
            }
        });
    };
    checkNode(node);
    return hasAwait;
}
export function containsPausableCall(node) {
    let hasPausable = false;
    const checkNode = (n) => {
        if (t.isAwaitExpression(n) && isPausableCall(n)) {
            hasPausable = true;
            return;
        }
        if (hasPausable)
            return;
        Object.keys(n).forEach((key) => {
            const value = n[key];
            if (Array.isArray(value)) {
                value.forEach((item) => {
                    if (item && typeof item === 'object' && item.type) {
                        checkNode(item);
                    }
                });
            }
            else if (value && typeof value === 'object' && value.type) {
                checkNode(value);
            }
        });
    };
    checkNode(node);
    return hasPausable;
}
export function isAsyncFunction(node) {
    return ((t.isFunctionDeclaration(node) ||
        t.isFunctionExpression(node) ||
        t.isArrowFunctionExpression(node)) &&
        node.async === true);
}
export function getNodeLocation(node) {
    if (node.loc) {
        return {
            line: node.loc.start.line,
            column: node.loc.start.column,
        };
    }
    return undefined;
}
export function createRuntimeCall(fnName, args) {
    return t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('__runtime'), t.identifier(fnName)), args));
}
export function wrapInAsyncFunction(body) {
    return t.functionExpression(null, [], t.blockStatement(body), false, true);
}
export function isArrayMethod(node, methodName) {
    if (!t.isCallExpression(node)) {
        return false;
    }
    const callee = node.callee;
    if (!t.isMemberExpression(callee)) {
        return false;
    }
    return t.isIdentifier(callee.property) && callee.property.name === methodName;
}
/**
 * Extract parameter name from ForOfStatement left side
 */
export function extractForOfParamName(left) {
    if (t.isVariableDeclaration(left)) {
        const id = left.declarations[0]?.id;
        return t.isIdentifier(id) ? id.name : 'item';
    }
    else if (t.isIdentifier(left)) {
        return left.name;
    }
    else {
        return 'item';
    }
}
//# sourceMappingURL=utils.js.map