diff --git a/packages/cli-repl/src/mongosh-repl.spec.ts b/packages/cli-repl/src/mongosh-repl.spec.ts index b9f5f8fd90..e8121c2895 100644 --- a/packages/cli-repl/src/mongosh-repl.spec.ts +++ b/packages/cli-repl/src/mongosh-repl.spec.ts @@ -531,6 +531,24 @@ describe('MongoshNodeRepl', () => { await tick(); expect(stripAnsi(output)).to.equal('\n> '); }); + + context('thrown non-Errors', () => { + it('allows `throw null`', async() => { + output = ''; + input.write('throw null;\n'); + await waitEval(bus); + // We do verify that both `Error` and `null` are syntax-highlighted here. + expect(output).to.match(/\x1b\[\d+mError\x1b\[\d+m: \x1b\[\d+mnull\x1b\[\d+m/); + }); + + it('allows `throw number`', async() => { + output = ''; + input.write('throw 123;\n'); + await waitEval(bus); + // We do verify that both `Error` and `123` are syntax-highlighted here. + expect(output).to.match(/\x1b\[\d+mError\x1b\[\d+m: \x1b\[\d+m123\x1b\[\d+m/); + }); + }); }); context('with fake TTY', () => { diff --git a/packages/cli-repl/src/mongosh-repl.ts b/packages/cli-repl/src/mongosh-repl.ts index 21599903cf..888664cccb 100644 --- a/packages/cli-repl/src/mongosh-repl.ts +++ b/packages/cli-repl/src/mongosh-repl.ts @@ -343,6 +343,13 @@ class MongoshNodeRepl implements EvaluationListener { // topology, server version, etc., so for those, we do not autocomplete // at all and instead leave that to the @mongosh/autocomplete package. return shellResult.type !== null ? null : shellResult.rawValue; + } catch (err) { + if (!isErrorLike(err)) { + throw new Error(this.formatOutput({ + value: err + })); + } + throw err; } finally { if (!this.insideAutoCompleteOrGetPrompt) { repl.setPrompt(await this.getShellPrompt()); @@ -379,10 +386,7 @@ class MongoshNodeRepl implements EvaluationListener { // This checks for error instances. // The writer gets called immediately by the internal `repl.eval` // in case of errors. - if (result && ( - (result.message !== undefined && typeof result.stack === 'string') || - (result.code !== undefined && result.errmsg !== undefined) - )) { + if (isErrorLike(result)) { // eslint-disable-next-line chai-friendly/no-unused-expressions this._runtimeState?.shellEvaluator.revertState(); @@ -415,7 +419,7 @@ class MongoshNodeRepl implements EvaluationListener { return (await passwordPromise).toString(); } - formatOutput(value: any): string { + formatOutput(value: { value: any, type?: string }): string { return formatOutput(value, this.getFormatOptions()); } @@ -519,4 +523,15 @@ class MongoshNodeRepl implements EvaluationListener { } } +function isErrorLike(value: any): boolean { + try { + return value && ( + (value.message !== undefined && typeof value.stack === 'string') || + (value.code !== undefined && value.errmsg !== undefined) + ); + } catch (err) { + throw new MongoshInternalError(err?.message || String(err)); + } +} + export default MongoshNodeRepl;