/**
 * Example Plugin: Async Timeout Wrapper
 *
 * Automatically wraps await expressions with timeout protection
 *
 * @example
 * // Before:
 * const result = await fetch('https://api.example.com');
 *
 * // After:
 * const result = await Promise.race([
 *   fetch('https://api.example.com'),
 *   new Promise((_, reject) =>
 *     setTimeout(() => reject(new Error('Timeout')), 5000)
 *   )
 * ]);
 */
import * as t from '@babel/types';
export class AsyncTimeoutPlugin {
    name = 'async-timeout';
    version = '1.0.0';
    priority = 40; // Run after main transformations
    options;
    transformCount = 0;
    constructor(options = {}) {
        this.options = {
            timeout: options.timeout || 5000,
            patterns: options.patterns || ['fetch', 'axios.*', 'http.*'],
            wrapAll: options.wrapAll || false,
        };
    }
    getVisitor(config) {
        return {
            AwaitExpression: (path) => {
                // Check if should wrap this await
                if (!this.shouldWrap(path.node.argument)) {
                    return;
                }
                // Create timeout promise
                const timeoutPromise = t.newExpression(t.identifier('Promise'), [
                    t.arrowFunctionExpression([t.identifier('_'), t.identifier('reject')], t.blockStatement([
                        t.expressionStatement(t.callExpression(t.identifier('setTimeout'), [
                            t.arrowFunctionExpression([], t.callExpression(t.identifier('reject'), [
                                t.newExpression(t.identifier('Error'), [
                                    t.stringLiteral(`Timeout after ${this.options.timeout}ms`),
                                ]),
                            ])),
                            t.numericLiteral(this.options.timeout),
                        ])),
                    ])),
                ]);
                // Wrap in Promise.race
                const raceCall = t.callExpression(t.memberExpression(t.identifier('Promise'), t.identifier('race')), [t.arrayExpression([path.node.argument, timeoutPromise])]);
                // Replace await expression
                path.node.argument = raceCall;
                this.transformCount++;
            },
        };
    }
    getMetadata() {
        return {
            // Custom metadata
            loopCount: 0,
            arrayMethodCount: 0,
            parallelCallCount: this.transformCount,
            batchableCount: 0,
        };
    }
    reset() {
        this.transformCount = 0;
    }
    /**
     * Check if this await should be wrapped with timeout
     */
    shouldWrap(node) {
        if (this.options.wrapAll) {
            return true;
        }
        // Check if matches patterns
        if (t.isCallExpression(node)) {
            const funcName = this.getFunctionName(node);
            if (funcName) {
                return this.options.patterns.some((pattern) => {
                    const regex = new RegExp(pattern.replace('*', '.*'));
                    return regex.test(funcName);
                });
            }
        }
        return false;
    }
    /**
     * Get function name from call expression
     */
    getFunctionName(node) {
        if (t.isIdentifier(node.callee)) {
            return node.callee.name;
        }
        if (t.isMemberExpression(node.callee)) {
            const obj = t.isIdentifier(node.callee.object) ? node.callee.object.name : '';
            const prop = t.isIdentifier(node.callee.property) ? node.callee.property.name : '';
            return `${obj}.${prop}`;
        }
        return null;
    }
}
//# sourceMappingURL=timeout-plugin.js.map