"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CodePattern = void 0;
exports.findHighestPattern = findHighestPattern;
const Visitor_1 = require("@swc/core/Visitor");
// Throw an exception when found top-level await to exit earlier from AST traversal
class FoundTopLevelAwaitError extends Error {
}
class FindPatternsVisitor extends Visitor_1.Visitor {
    // Hook class/function visiting functions so we can know the current level
    constructor() {
        super();
        // Set the flag when a dynamic import is found
        this.foundDynamicImport = false;
        // Tell if one await is in top-level or not
        this.currentLevel = 0;
        const visitor = this;
        function hook(methodName) {
            const originalFunction = visitor[methodName];
            visitor[methodName] = function () {
                /* istanbul ignore next */
                // A optimize: if we have already found dynamic imports, don't go deeper
                if (visitor.foundDynamicImport)
                    return arguments[0];
                visitor.currentLevel++;
                const result = originalFunction.apply(this, arguments);
                visitor.currentLevel--;
                return result;
            };
        }
        hook("visitClass");
        hook("visitArrowFunctionExpression");
        hook("visitFunction");
        hook("visitMethodProperty");
    }
    visitAwaitExpression(expr) {
        if (this.currentLevel === 0)
            throw new FoundTopLevelAwaitError();
        return super.visitAwaitExpression(expr);
    }
    visitForOfStatement(stmt) {
        if (stmt.await && this.currentLevel === 0) {
            throw new FoundTopLevelAwaitError();
        }
        return super.visitForOfStatement(stmt);
    }
    visitCallExpression(expr) {
        if (expr.callee.type === "Import")
            this.foundDynamicImport = true;
        return super.visitCallExpression(expr);
    }
}
var CodePattern;
(function (CodePattern) {
    CodePattern["TopLevelAwait"] = "TopLevelAwait";
    CodePattern["DynamicImport"] = "DynamicImport";
})(CodePattern || (exports.CodePattern = CodePattern = {}));
// Return the "highest" pattern found in the code
// i.e. if we found top-level await, we don't care if there're any dynamic imports then
function findHighestPattern(ast) {
    try {
        const visitor = new FindPatternsVisitor();
        visitor.visitModule(ast);
        if (visitor.foundDynamicImport)
            return CodePattern.DynamicImport;
    }
    catch (e) {
        if (e instanceof FoundTopLevelAwaitError)
            return CodePattern.TopLevelAwait;
        /* istanbul ignore next */
        throw e;
    }
    return null;
}
