"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShellEvaluator = void 0;
const contextless_eval_1 = require("./contextless-eval");
const shell_api_1 = require("@mongosh/shell-api");
const async_rewriter2_1 = __importDefault(require("@mongosh/async-rewriter2"));
const mongodb_redact_1 = require("mongodb-redact");
const types_1 = require("@mongosh/types");
let hasAlreadyRunGlobalRuntimeSupportEval = false;
let v8;
try {
    v8 = require('v8');
}
catch {
}
if (v8?.startupSnapshot?.isBuildingSnapshot?.()) {
    v8.startupSnapshot.addSerializeCallback(() => {
        (0, contextless_eval_1.contextlessEval)(new async_rewriter2_1.default().runtimeSupportCode());
        (0, contextless_eval_1.contextlessEval)(new async_rewriter2_1.default().process('1+1'));
        hasAlreadyRunGlobalRuntimeSupportEval = true;
    });
}
class ShellEvaluator {
    constructor(instanceState, resultHandler = shell_api_1.toShellResult, markTime, exposeAsyncRewriter) {
        this.hasAppliedAsyncWriterRuntimeSupport = true;
        this.instanceState = instanceState;
        this.resultHandler = resultHandler;
        this.asyncWriter = new async_rewriter2_1.default();
        this.hasAppliedAsyncWriterRuntimeSupport = false;
        this.exposeAsyncRewriter = !!exposeAsyncRewriter;
        this.markTime = markTime;
    }
    async innerEval(originalEval, input, context, filename) {
        const { shellApi } = this.instanceState;
        const trimmedInput = input.trim();
        const argv = trimmedInput.replace(/;$/, '').split(/\s+/g);
        const cmd = argv.shift();
        if (shellApi[cmd]?.isDirectShellCommand &&
            shellApi[cmd]?.acceptsRawInput &&
            !(argv[0] ?? '').startsWith('(')) {
            const rawArg = trimmedInput.replace(/^\S+\s*/, '');
            return shellApi[cmd](rawArg);
        }
        if (shellApi[cmd]?.isDirectShellCommand &&
            !(argv[0] ?? '').startsWith('(')) {
            return shellApi[cmd](...argv);
        }
        if (this.exposeAsyncRewriter) {
            context.__asyncRewrite = (rewriteInput) => this.asyncWriter.process(rewriteInput);
        }
        this.markTime?.(types_1.TimingCategories.AsyncRewrite, 'start async rewrite');
        let rewrittenInput = this.asyncWriter.process(input);
        this.markTime?.(types_1.TimingCategories.AsyncRewrite, 'done async rewrite');
        if (!(0, mongodb_redact_1.shouldRedactCommand)(input) && !(0, mongodb_redact_1.shouldRedactCommand)(rewrittenInput)) {
            this.instanceState.messageBus.emit('mongosh:evaluate-input', {
                input: (0, mongodb_redact_1.redact)(trimmedInput),
            });
        }
        if (!this.hasAppliedAsyncWriterRuntimeSupport) {
            this.hasAppliedAsyncWriterRuntimeSupport = true;
            this.markTime?.(types_1.TimingCategories.AsyncRewrite, 'start runtimeSupportCode processing');
            const supportCode = this.asyncWriter.runtimeSupportCode();
            if (!hasAlreadyRunGlobalRuntimeSupportEval) {
                (0, contextless_eval_1.contextlessEval)(supportCode);
                hasAlreadyRunGlobalRuntimeSupportEval = true;
            }
            this.markTime?.(types_1.TimingCategories.AsyncRewrite, 'done global runtimeSupportCode processing');
            rewrittenInput = supportCode + ';\n' + rewrittenInput;
        }
        try {
            this.markTime?.(types_1.TimingCategories.Eval, 'started evaluating processed code');
            return await originalEval(rewrittenInput, context, filename);
        }
        catch (err) {
            throw this.instanceState.transformError(err);
        }
        finally {
            this.markTime?.(types_1.TimingCategories.Eval, 'finished evaluating processed code');
        }
    }
    async customEval(originalEval, input, context, filename) {
        const evaluationResult = await this.innerEval(originalEval, input, context, filename);
        return await this.resultHandler(evaluationResult);
    }
}
exports.ShellEvaluator = ShellEvaluator;
//# sourceMappingURL=shell-evaluator.js.map