diff options
author | Nayeem Rahman <muhammed.9939@gmail.com> | 2019-08-31 20:17:56 +0100 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2019-08-31 15:17:56 -0400 |
commit | df2f54b2a66fa71012c5d263009652c98085b5ed (patch) | |
tree | 06ac06225caeb51240f0e18e69df2c0a4bfb6ccc | |
parent | fdd4252d49ceb022761b92d953d24672ab67ab91 (diff) |
Fix REPL '_' assignment, support '_error' (#2845)
-rw-r--r-- | js/repl.ts | 47 | ||||
-rw-r--r-- | tools/repl_test.py | 25 |
2 files changed, 62 insertions, 10 deletions
diff --git a/js/repl.ts b/js/repl.ts index cbba2b791..08a4fb210 100644 --- a/js/repl.ts +++ b/js/repl.ts @@ -25,7 +25,8 @@ function replError(...args: unknown[]): void { } const helpMsg = [ - "_ Print last execution output", + "_ Get last evaluation result", + "_error Get last thrown error", "exit Exit the REPL", "help Print this help message" ].join("\n"); @@ -70,22 +71,25 @@ function isRecoverableError(e: Error): boolean { return recoverableErrorMessages.includes(e.message); } +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Value = any; + +let lastEvalResult: Value = undefined; +let lastThrownError: Value = undefined; + // Evaluate code. // Returns true if code is consumed (no error/irrecoverable error). -// Also attempts setting window._ to last valid execute output. // Returns false if error is recoverable function evaluate(code: string): boolean { const [result, errInfo] = core.evalContext(code); if (!errInfo) { - // Try setting `window._` to the returned result - try { - window._ = result; - } catch {} // Silently fail on error. + lastEvalResult = result; replLog(result); } else if (errInfo.isCompileError && isRecoverableError(errInfo.thrown)) { // Recoverable compiler error return false; // don't consume code. } else { + lastThrownError = errInfo.thrown; if (errInfo.isNativeError) { const formattedError = formatError( core.errorToJSON(errInfo.thrown as Error) @@ -113,8 +117,35 @@ export async function replLoop(): Promise<void> { exit(exitCode); }; - // Make _ a valid property on window to avoid confusing error. - window._ = undefined; + // Configure window._ to give the last evaluation result. + Object.defineProperty(window, "_", { + configurable: true, + get: (): Value => lastEvalResult, + set: (value: Value): Value => { + Object.defineProperty(window, "_", { + value: value, + writable: true, + enumerable: true, + configurable: true + }); + console.log("Last evaluation result is no longer saved to _."); + } + }); + + // Configure window._error to give the last thrown error. + Object.defineProperty(window, "_error", { + configurable: true, + get: (): Value => lastThrownError, + set: (value: Value): Value => { + Object.defineProperty(window, "_error", { + value: value, + writable: true, + enumerable: true, + configurable: true + }); + console.log("Last thrown error is no longer saved to _error."); + } + }); while (true) { let code = ""; diff --git a/tools/repl_test.py b/tools/repl_test.py index 870824661..544dd6a7e 100644 --- a/tools/repl_test.py +++ b/tools/repl_test.py @@ -58,7 +58,8 @@ class TestRepl(DenoTestCase): def test_help_command(self): out, err, code = self.input("help") expectedOut = '\n'.join([ - "_ Print last execution output", + "_ Get last evaluation result", + "_error Get last thrown error", "exit Exit the REPL", "help Print this help message", "", @@ -151,12 +152,32 @@ class TestRepl(DenoTestCase): self.assertTrue(err.startswith("Unable to save REPL history:")) self.assertEqual(code, 0) - def test_save_last_output(self): + def test_save_last_eval(self): out, err, code = self.input("1", "_") self.assertEqual(out, '1\n1\n') self.assertEqual(err, '') self.assertEqual(code, 0) + def test_save_last_thrown(self): + out, err, code = self.input("throw 1", "_error") + self.assertEqual(out, '1\n') + self.assertEqual(err, 'Thrown: 1\n') + self.assertEqual(code, 0) + + def test_assign_underscore(self): + out, err, code = self.input("_ = 1", "2", "_") + self.assertEqual( + out, 'Last evaluation result is no longer saved to _.\n1\n2\n1\n') + self.assertEqual(err, '') + self.assertEqual(code, 0) + + def test_assign_underscore_error(self): + out, err, code = self.input("_error = 1", "throw 2", "_error") + self.assertEqual( + out, 'Last thrown error is no longer saved to _error.\n1\n1\n') + self.assertEqual(err, 'Thrown: 2\n') + self.assertEqual(code, 0) + if __name__ == "__main__": run_tests() |