"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const autocomplete_1 = require("@mongosh/autocomplete");
const errors_1 = require("@mongosh/errors");
const history_1 = require("@mongosh/history");
const shell_api_1 = require("@mongosh/shell-api");
const shell_evaluator_1 = require("@mongosh/shell-evaluator");
const types_1 = require("@mongosh/types");
const askcharacter_1 = __importDefault(require("askcharacter"));
const askpassword_1 = __importDefault(require("askpassword"));
const console_1 = require("console");
const events_1 = require("events");
const util_1 = require("util");
const asyncRepl = __importStar(require("./async-repl"));
const clr_1 = __importDefault(require("./clr"));
const constants_1 = require("./constants");
const format_output_1 = require("./format-output");
const js_multiline_to_singleline_1 = require("@mongosh/js-multiline-to-singleline");
const line_by_line_input_1 = require("./line-by-line-input");
const startup_timing_1 = require("./startup-timing");
const vm_1 = require("vm");
const repl_paste_support_1 = require("./repl-paste-support");
const util_2 = __importDefault(require("util"));
const node_repl_fix_completer_side_effects_1 = require("./node-repl-fix-completer-side-effects");
const node_repl_fix_history_rewrite_on_error_1 = require("./node-repl-fix-history-rewrite-on-error");
class MongoshNodeRepl {
    constructor(options) {
        this.outputFinishString = '';
        this.inspectCompact = 0;
        this.inspectDepth = 0;
        this.started = false;
        this.showStackTraces = false;
        this.loadNestingLevel = 0;
        this.redactHistory = 'remove';
        this.rawValueToShellResult = new WeakMap();
        this.input = options.input;
        this.lineByLineInput = new line_by_line_input_1.LineByLineInput(this.input);
        this.output = options.output;
        this.bus = options.bus;
        this.nodeReplOptions = options.nodeReplOptions || {};
        this.shellCliOptions = options.shellCliOptions || {};
        this.ioProvider = options.ioProvider;
        this.insideAutoCompleteOrGetPrompt = false;
        this._runtimeState = null;
    }
    setIsInteractive(value) {
        this.runtimeState().instanceState.isInteractive = value;
    }
    get isInteractive() {
        return this.runtimeState().instanceState.isInteractive;
    }
    async initialize(serviceProvider, greeting) {
        const usePlainVMContext = this.shellCliOptions.jsContext === 'plain-vm';
        const instanceState = new shell_api_1.ShellInstanceState(serviceProvider, this.bus, this.shellCliOptions);
        const shellEvaluator = new shell_evaluator_1.ShellEvaluator(instanceState, (value) => value, startup_timing_1.markTime, !!this.shellCliOptions.exposeAsyncRewriter);
        instanceState.setEvaluationListener(this);
        instanceState.setPreFetchCollectionAndDatabaseNames(!usePlainVMContext);
        {
            const connectionInfoPromise = instanceState.fetchConnectionInfo();
            connectionInfoPromise.catch(() => {
            });
            if (!this.shellCliOptions.quiet) {
                const connectionInfo = await connectionInfoPromise;
                (0, startup_timing_1.markTime)(types_1.TimingCategories.REPLInstantiation, 'fetched connection info');
                const { buildInfo, extraInfo } = connectionInfo ?? {};
                let mongodVersion = extraInfo?.is_stream
                    ? 'Atlas Stream Processing'
                    : buildInfo?.version;
                const apiVersion = serviceProvider.getRawClient()?.serverApi?.version;
                if (apiVersion) {
                    mongodVersion =
                        (mongodVersion ? mongodVersion + ' ' : '') +
                            `(API Version ${apiVersion})`;
                }
                await this.greet(mongodVersion, greeting);
            }
        }
        await this.printBasicConnectivityWarning(instanceState);
        (0, startup_timing_1.markTime)(types_1.TimingCategories.REPLInstantiation, 'greeted');
        this.inspectCompact =
            (await this.getConfig('inspectCompact')) ?? this.inspectCompact;
        this.inspectDepth =
            (await this.getConfig('inspectDepth')) ?? this.inspectDepth;
        this.showStackTraces =
            (await this.getConfig('showStackTraces')) ?? this.showStackTraces;
        this.redactHistory =
            (await this.getConfig('redactHistory')) ?? this.redactHistory;
        (0, startup_timing_1.markTime)(types_1.TimingCategories.UserConfigLoading, 'fetched config vars');
        let repl = null;
        let context;
        if (!usePlainVMContext) {
            repl = asyncRepl.start({
                start: require('pretty-repl').start,
                input: this.lineByLineInput,
                output: this.output,
                prompt: '',
                writer: this.writer.bind(this),
                breakEvalOnSigint: true,
                preview: false,
                asyncEval: this.eval.bind(this),
                historySize: await this.getConfig('historyLength'),
                wrapCallbackError: (err) => Object.assign(new errors_1.MongoshInternalError(err.message), {
                    stack: err.stack,
                }),
                onAsyncSigint: this.onAsyncSigint.bind(this),
                ...this.nodeReplOptions,
            });
            (0, repl_paste_support_1.fixNode60446)(repl);
            context = repl.context;
            repl[util_2.default.inspect.custom] = () => {
                return this.clr('[mongosh REPL Server]', 'magenta');
            };
        }
        else {
            const { builtinModules: nodeReplBuiltinModules } = require('repl');
            context = (0, vm_1.createContext)();
            const jsBuiltinGlobalNames = (0, vm_1.runInContext)('globalThis[Symbol.for("@@mongosh.usingPlainVMContext")] = true;' +
                'Object.getOwnPropertyNames(globalThis)', context);
            for (const nodeJsGlobal of Object.getOwnPropertyNames(globalThis)) {
                if (!jsBuiltinGlobalNames.includes(nodeJsGlobal))
                    Object.defineProperty(context, nodeJsGlobal, {
                        ...Object.getOwnPropertyDescriptor(globalThis, nodeJsGlobal),
                    });
            }
            for (const builtin of nodeReplBuiltinModules) {
                let value;
                Object.defineProperty(context, builtin, {
                    enumerable: false,
                    configurable: true,
                    get() {
                        return (value ??=
                            typeof __non_webpack_require__ === 'function'
                                ? __non_webpack_require__(builtin)
                                : require(builtin));
                    },
                    set(v) {
                        value = v;
                    },
                });
            }
            context.global = context;
            context.require = require('node:module').createRequire(process.cwd() + '/index.js');
        }
        const console = new console_1.Console({
            stdout: this.output,
            stderr: this.output,
            colorMode: this.getFormatOptions().colors,
        });
        delete context.parcelRequire;
        delete context.__webpack_require__;
        delete context.__non_webpack_require__;
        this.onClearCommand = console.clear.bind(console);
        context.console = console;
        context.Date = Date;
        {
            const globalCryptoDescriptor = Object.getOwnPropertyDescriptor(context, 'crypto') ?? {};
            if (globalCryptoDescriptor.value?.subtle ||
                globalCryptoDescriptor.get?.call(null)?.subtle) {
                delete context.crypto;
                context.crypto = await import('node:crypto');
            }
        }
        this._runtimeState = {
            shellEvaluator,
            instanceState,
            repl,
            context,
            console,
        };
        (0, startup_timing_1.markTime)(types_1.TimingCategories.REPLInstantiation, 'basic repl/vm initialization complete');
        await this.finishInitializingNodeRepl();
        instanceState.setCtx(context);
        this.setupHistoryCommand();
        if (!this.shellCliOptions.nodb && !this.shellCliOptions.quiet) {
            const { shellApi } = instanceState;
            const connectionInfo = instanceState.cachedConnectionInfo();
            const bannerCommands = connectionInfo?.extraInfo?.is_local_atlas ||
                this.shellCliOptions.skipStartupWarnings
                ? ['automationNotices', 'nonGenuineMongoDBCheck']
                : ['startupWarnings', 'automationNotices', 'nonGenuineMongoDBCheck'];
            const banners = await Promise.all(bannerCommands.map(async (command) => await shellApi._untrackedShow(command)));
            for (const banner of banners) {
                if (banner.value) {
                    await shellApi.print(banner);
                }
            }
        }
        (0, startup_timing_1.markTime)(types_1.TimingCategories.REPLInstantiation, 'finished initialization');
        return { __initialized: 'yes' };
    }
    setupHistoryCommand() {
        const history = () => {
            const replHistory = this.runtimeState().repl.history;
            const formattedHistory = replHistory.slice(1).reverse();
            formattedHistory[util_2.default.inspect.custom] = ((depth, options, inspect) => {
                return inspect(formattedHistory.concat(), {
                    ...options,
                    depth,
                    maxArrayLength: Infinity,
                });
            });
            return formattedHistory;
        };
        this.runtimeState().context.history = history;
    }
    async finishInitializingNodeRepl() {
        const { repl, instanceState } = this.runtimeState();
        if (!repl)
            return;
        this.outputFinishString += (0, repl_paste_support_1.installPasteSupport)(repl);
        const origReplCompleter = await (0, node_repl_fix_completer_side_effects_1.fixNodeReplCompleterSideEffectHandling)((0, util_1.promisify)(repl.completer.bind(repl)));
        await (0, node_repl_fix_history_rewrite_on_error_1.fixNodeReplHistoryHandler)(repl);
        let newMongoshCompleter;
        let oldMongoshCompleter;
        if (process.env.USE_NEW_AUTOCOMPLETE !== '0') {
        }
        else {
            const autocompleteParams = instanceState.getAutocompleteParameters();
            oldMongoshCompleter = autocomplete_1.completer.bind(null, autocompleteParams);
        }
        const innerCompleter = async (text) => {
            const [[replResults, replOrig], [mongoshResults, , mongoshResultsExclusive],] = await Promise.all([
                (async () => {
                    const nodeResults = (await origReplCompleter(text)) || [[]];
                    return nodeResults;
                })(),
                (async () => {
                    if (process.env.USE_NEW_AUTOCOMPLETE !== '0') {
                        if (!newMongoshCompleter) {
                            newMongoshCompleter = await (0, autocomplete_1.initNewAutocompleter)(instanceState);
                        }
                        return newMongoshCompleter(text);
                    }
                    else {
                        return oldMongoshCompleter(text);
                    }
                })(),
            ]);
            if (mongoshResultsExclusive) {
                return [mongoshResults, text];
            }
            const replResultPrefix = replOrig
                ? text.substr(0, text.lastIndexOf(replOrig))
                : '';
            const longReplResults = replResults.map((result) => replResultPrefix + result);
            const deduped = [...new Set([...longReplResults, ...mongoshResults])];
            return [deduped, text];
        };
        const nodeReplCompleter = (0, util_1.callbackify)(async (text) => {
            this.insideAutoCompleteOrGetPrompt = true;
            try {
                let [results, completeOn] = await innerCompleter(text);
                results = results.filter((result) => !format_output_1.CONTROL_CHAR_REGEXP.test(result));
                this.bus.emit('mongosh:autocompletion-complete');
                return [results, completeOn];
            }
            finally {
                this.insideAutoCompleteOrGetPrompt = false;
            }
        });
        repl.completer = nodeReplCompleter;
        let originalHistory = null;
        asyncRepl.addReplEventForEvalReady(repl, () => !!this.started, () => this.lineByLineInput.nextLine());
        if (repl.commands.editor) {
            const originalEditorAction = repl.commands.editor.action.bind(repl);
            repl.commands.editor.action = (...args) => {
                originalHistory = [...repl.history];
                this.lineByLineInput.disableBlockOnNewline();
                return originalEditorAction(...args);
            };
        }
        repl.defineCommand('clear', {
            help: '',
            action: () => {
                repl.displayPrompt();
            },
        });
        repl.line = '';
        (0, startup_timing_1.markTime)(types_1.TimingCategories.REPLInstantiation, 'created repl object');
        const historyFile = this.ioProvider.getHistoryFilePath();
        await (0, util_1.promisify)(repl.setupHistory).call(repl, historyFile);
        repl.on('line', () => {
            if (this.redactHistory !== 'keep') {
                const history = repl.history;
                (0, history_1.changeHistory)(history, this.redactHistory === 'remove-redact'
                    ? 'redact-sensitive-data'
                    : 'keep-sensitive-data');
            }
        });
        repl.on(asyncRepl.evalFinish, (ev) => {
            if (this.insideAutoCompleteOrGetPrompt) {
                return;
            }
            const history = repl.history;
            if (ev.success === false && ev.recoverable) {
                if (originalHistory === null) {
                    originalHistory = history.slice(1);
                }
            }
            else if (originalHistory !== null) {
                const newHistoryEntry = (0, js_multiline_to_singleline_1.makeMultilineJSIntoSingleLine)(ev.input);
                if (newHistoryEntry.length > 0) {
                    originalHistory.unshift(newHistoryEntry);
                }
                history.splice(0, history.length, ...originalHistory);
                originalHistory = null;
            }
        });
        (0, startup_timing_1.markTime)(types_1.TimingCategories.UserConfigLoading, 'set up history file');
        repl.on(asyncRepl.evalStart, () => {
            this.bus.emit('mongosh:evaluate-started');
        });
        repl.on(asyncRepl.evalFinish, () => {
            this.bus.emit('mongosh:evaluate-finished');
        });
        repl.on('exit', () => {
            if (this._runtimeState)
                this._runtimeState.repl = null;
            this.onExit().catch(() => {
            });
        });
    }
    async startRepl(_initializationToken) {
        this.started = true;
        const { repl } = this.runtimeState();
        if (!repl) {
            throw new errors_1.MongoshInternalError('Cannot start REPL when not in REPL evaluation mode');
        }
        repl.setPrompt(await this.getShellPrompt());
        this.lineByLineInput.start();
        this.input.resume();
        repl.displayPrompt();
    }
    async greet(mongodVersion, greeting) {
        if (this.shellCliOptions.quiet) {
            return;
        }
        const { version } = require('../package.json');
        let text = '';
        if (!this.shellCliOptions.nodb) {
            text += `Using MongoDB:\t\t${mongodVersion}\n`;
        }
        text += `${this.clr('Using Mongosh', 'mongosh:section-header')}:\t\t${version}\n`;
        if (greeting?.moreRecentMongoshVersion) {
            if (greeting?.isHomebrew) {
                text += `mongosh ${this.clr(greeting.moreRecentMongoshVersion, 'bold')} is available, run ${this.clr('brew upgrade mongosh', 'mongosh:uri')} to update\n`;
            }
            else {
                text += `mongosh ${this.clr(greeting.moreRecentMongoshVersion, 'bold')} is available for download: ${this.clr('https://www.mongodb.com/try/download/shell', 'mongosh:uri')}\n`;
            }
        }
        if (greeting?.currentVersionCTA) {
            for (const run of greeting.currentVersionCTA) {
                text += this.clr(run.text, run.style);
            }
            text += '\n';
        }
        text += `${constants_1.MONGOSH_WIKI}\n`;
        if (!(await this.getConfig('disableGreetingMessage'))) {
            text += `${constants_1.TELEMETRY_GREETING_MESSAGE}\n`;
            await this.setConfig('disableGreetingMessage', true);
        }
        this.output.write(text);
    }
    async printBasicConnectivityWarning(instanceState) {
        if (this.shellCliOptions.nodb || this.shellCliOptions.quiet) {
            return;
        }
        let err;
        try {
            await instanceState.currentDb.adminCommand({ ping: 1 });
            return;
        }
        catch (error) {
            err = error;
        }
        const text = this.clr('The server failed to respond to a ping and may be unavailable:', 'mongosh:warning');
        this.output.write(text + '\n' + this.formatError(err) + '\n');
    }
    async eval(originalEval, input, context, filename) {
        (0, startup_timing_1.markTime)(types_1.TimingCategories.Eval, 'start repl eval');
        if (!this.insideAutoCompleteOrGetPrompt) {
            this.lineByLineInput.enableBlockOnNewLine();
        }
        const { repl, shellEvaluator } = this.runtimeState();
        let interrupted = false;
        try {
            const rawValue = await shellEvaluator.customEval(originalEval, input, context, filename);
            if ((typeof rawValue === 'object' && rawValue !== null) ||
                typeof rawValue === 'function') {
                this.rawValueToShellResult.set(rawValue, await (0, shell_api_1.toShellResult)(rawValue));
            }
            if (!this.insideAutoCompleteOrGetPrompt ||
                (0, shell_api_1.getShellApiType)(rawValue) === null) {
                return rawValue;
            }
            return Object.fromEntries(Object.entries(rawValue).filter(([key]) => !key.startsWith('_')));
        }
        catch (err) {
            if (this.runtimeState().instanceState.interrupted.isSet()) {
                interrupted = true;
                this.bus.emit('mongosh:eval-interrupted');
                return undefined;
            }
            if (!isErrorLike(err)) {
                throw new Error(this.formatOutput({
                    value: err,
                }));
            }
            throw err;
        }
        finally {
            (0, startup_timing_1.markTime)(types_1.TimingCategories.Eval, 'done repl eval');
            if (!this.insideAutoCompleteOrGetPrompt && !interrupted && repl) {
                repl.setPrompt(await this.getShellPrompt());
            }
            if (this.loadNestingLevel <= 1) {
                this.bus.emit('mongosh:eval-complete');
            }
            (0, startup_timing_1.markTime)(types_1.TimingCategories.Eval, 're-set prompt');
        }
    }
    async onLoad(filename) {
        const { contents, absolutePath } = await this.ioProvider.readFileUTF8(filename);
        return {
            resolvedFilename: absolutePath,
            evaluate: async () => {
                this.loadNestingLevel += 1;
                try {
                    await this.loadExternalCode(contents, absolutePath);
                }
                finally {
                    this.loadNestingLevel -= 1;
                }
            },
        };
    }
    async loadExternalFile(filename) {
        await this.runtimeState().instanceState.shellApi.load(filename);
    }
    async loadExternalCode(input, filename) {
        const { repl, context } = this.runtimeState();
        if (repl) {
            return await (0, util_1.promisify)(repl.eval.bind(repl))(input, context, filename);
        }
        let asyncSigintHandler;
        const asyncSigintPromise = new Promise((resolve, reject) => {
            asyncSigintHandler = () => {
                void this.onAsyncSigint();
                setImmediate(() => reject(new Error('Asynchronous execution was interrupted by `SIGINT`')));
            };
        });
        this.bus.emit('mongosh:evaluate-started');
        try {
            process.addListener('SIGINT', asyncSigintHandler);
            return await Promise.race([
                asyncSigintPromise,
                this.eval((input, context, filename) => new vm_1.Script(input, { filename }).runInContext(context, {
                    breakOnSigint: true,
                }), input, context, filename),
            ]);
        }
        finally {
            process.removeListener('SIGINT', asyncSigintHandler);
            this.bus.emit('mongosh:evaluate-finished');
        }
    }
    async onAsyncSigint() {
        if (!this._runtimeState)
            return true;
        const { instanceState } = this.runtimeState();
        if (instanceState.interrupted.isSet()) {
            return true;
        }
        this.output.write('Stopping execution...');
        const mongodVersion = instanceState.cachedConnectionInfo()?.buildInfo?.version;
        if (mongodVersion?.match(/^(4\.0\.|3\.)\d+/)) {
            this.output.write(this.clr(`\nWARNING: Operations running on the server cannot be killed automatically for MongoDB ${mongodVersion}.` +
                '\n         Please make sure to kill them manually. Killing operations is supported starting with MongoDB 4.1.', 'mongosh:warning'));
        }
        const fullyInterrupted = await instanceState.onInterruptExecution();
        await Promise.race([
            new Promise((resolve) => this.bus.once('mongosh:eval-interrupted', resolve)),
            new Promise(setImmediate),
        ]);
        const fullyResumed = await instanceState.onResumeExecution();
        if (!fullyInterrupted || !fullyResumed) {
            this.output.write(this.formatError({
                name: 'MongoshInternalError',
                message: 'Could not re-establish all connections, we suggest to restart the shell.',
            }));
        }
        this.bus.emit('mongosh:interrupt-complete');
        if (!this._runtimeState)
            return true;
        const { repl } = this.runtimeState();
        if (repl) {
            repl.setPrompt(await this.getShellPrompt());
        }
        return true;
    }
    writer(result, extraFormatOptions) {
        if (isErrorLike(result)) {
            const output = {
                ...result,
                message: result.message || result.errmsg,
                name: result.name || 'MongoshInternalError',
                stack: result.stack,
                cause: result.cause,
            };
            this.bus.emit('mongosh:error', output, 'repl');
            return this.formatError(output);
        }
        return this.formatShellResult(this.rawValueToShellResult.get(result) ?? {
            type: null,
            printable: result,
        }, extraFormatOptions);
    }
    formatShellResult(result, extraFormatOptions = {}) {
        return this.formatOutput({ type: result.type, value: result.printable }, extraFormatOptions);
    }
    onPrint(values, type) {
        let extraOptions = {
            allowControlCharacters: true,
        };
        if (type === 'printjson') {
            extraOptions = {
                ...extraOptions,
                compact: false,
                depth: Infinity,
                maxArrayLength: Infinity,
                maxStringLength: Infinity,
            };
        }
        const joined = values
            .map((value) => this.formatShellResult(value, extraOptions))
            .join(' ');
        this.output.write(joined + '\n');
    }
    async onPrompt(question, type) {
        await enterAsynchronousExecutionForPrompt();
        if (type === 'password') {
            const passwordPromise = (0, askpassword_1.default)({
                input: this.input,
                output: this.output,
                replacementCharacter: '*',
            });
            this.output.write(question + '\n');
            return (await passwordPromise).toString();
        }
        else if (type === 'yesno') {
            let result = '';
            while (true) {
                const charPromise = (0, askcharacter_1.default)({
                    input: this.input,
                    output: this.output,
                });
                this.output.write(question + ': ');
                result = await charPromise;
                if (result.length > 0 && !/^[yYnN\r\n]$/.exec(result)) {
                    this.output.write('\nPlease enter Y or N: ');
                }
                else {
                    break;
                }
            }
            this.output.write('\n');
            return { Y: 'yes', N: 'no' }[result.toUpperCase()] ?? '';
        }
        throw new Error(`Unrecognized prompt type ${type}`);
    }
    formatOutput(value, extraFormatOptions = {}) {
        return (0, format_output_1.formatOutput)(value, {
            ...this.getFormatOptions(),
            ...extraFormatOptions,
        });
    }
    formatError(value) {
        return (0, format_output_1.formatError)(value, this.getFormatOptions());
    }
    clr(text, style) {
        return (0, clr_1.default)(text, style, this.getFormatOptions());
    }
    getFormatOptions() {
        const output = this.output;
        return {
            colors: this._runtimeState?.repl?.useColors ??
                !!(output.isTTY && (output?.getColorDepth?.() ?? 0) > 1),
            compact: this.inspectCompact,
            depth: this.inspectDepth,
            showStackTraces: this.showStackTraces,
            bugReportErrorMessageInfo: this.ioProvider.bugReportErrorMessageInfo?.(),
        };
    }
    runtimeState() {
        if (this._runtimeState === null) {
            throw new errors_1.MongoshInternalError(`mongosh not initialized yet\nCurrent trace: ${new Error().stack}\nClose trace: ${this.closeTrace}`);
        }
        return this._runtimeState;
    }
    async close() {
        const rs = this._runtimeState;
        if (rs) {
            this._runtimeState = null;
            this.closeTrace = new Error().stack;
            if (rs.repl) {
                rs.repl.close();
                await (0, events_1.once)(rs.repl, 'exit');
            }
            await rs.instanceState.close();
            if (!this.output.writableEnded && !this.output.destroyed) {
                await new Promise((resolve) => this.output.write(this.outputFinishString, resolve));
            }
        }
    }
    async onExit(exitCode) {
        return (this.exitPromise ??= (async () => {
            await this.close();
            return this.ioProvider.exit(exitCode);
        })());
    }
    async getConfig(key) {
        return this.ioProvider.getConfig(key);
    }
    getLogPath() {
        return this.ioProvider.getLogPath();
    }
    async setConfig(key, value) {
        const result = await this.ioProvider.setConfig(key, value);
        if (result === 'success') {
            if (key === 'historyLength' && this._runtimeState) {
                const historyManager = this.runtimeState().repl.historyManager;
                if (historyManager) {
                    const historyManagerSymbols = Object.getOwnPropertySymbols(historyManager);
                    const kSize = historyManagerSymbols.find((symbol) => String(symbol).includes('(_kSize)'));
                    if (kSize) {
                        historyManager[kSize] = value;
                    }
                }
                else {
                    this.runtimeState().repl.historySize = value;
                }
            }
            if (key === 'inspectCompact') {
                this.inspectCompact = value;
            }
            if (key === 'inspectDepth') {
                this.inspectDepth = value;
            }
            if (key === 'showStackTraces') {
                this.showStackTraces = value;
            }
            if (key === 'redactHistory') {
                this.redactHistory = value;
            }
        }
        return result;
    }
    async resetConfig(key) {
        return await this.setConfig(key, new types_1.CliUserConfig()[key]);
    }
    async validateConfig(key, value) {
        return types_1.CliUserConfigValidator.validate(key, value);
    }
    listConfigOptions() {
        return this.ioProvider.listConfigOptions();
    }
    async getCryptLibraryOptions() {
        return this.ioProvider.getCryptLibraryOptions();
    }
    async getShellPrompt() {
        const { context, instanceState } = this.runtimeState();
        try {
            this.insideAutoCompleteOrGetPrompt = true;
            if (typeof context.prompt !== 'undefined') {
                const promptResult = await this.loadExternalCode(`
        (() => {
          switch (typeof prompt) {
            case 'function':
              return prompt();
            case 'string':
              return prompt;
          }
        })()`, '<prompt loader>');
                if (typeof promptResult === 'string') {
                    return promptResult;
                }
            }
        }
        catch {
        }
        finally {
            this.insideAutoCompleteOrGetPrompt = false;
        }
        try {
            return await instanceState.getDefaultPrompt();
        }
        catch {
        }
        return '> ';
    }
    jsContext() {
        return this.runtimeState().repl ? 'repl' : 'plain-vm';
    }
}
function isErrorLike(value) {
    try {
        return (value &&
            (0, shell_api_1.getShellApiType)(value) === null &&
            ((value.message !== undefined && typeof value.stack === 'string') ||
                (value.code !== undefined && value.errmsg !== undefined)));
    }
    catch (err) {
        throw new errors_1.MongoshInternalError(err?.message || String(err));
    }
}
async function enterAsynchronousExecutionForPrompt() {
    await new Promise(setImmediate);
}
exports.default = MongoshNodeRepl;
//# sourceMappingURL=mongosh-repl.js.map