From 9caeff3208a33098418ac2c64414010a3060a362 Mon Sep 17 00:00:00 2001 From: Casper Beyer Date: Tue, 22 Sep 2020 04:09:53 +0800 Subject: [PATCH] fix(cli/repl): interpret object literals as expressions (#7591) --- cli/rt/40_repl.js | 15 ++++++++++++++- cli/tests/integration_tests.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/cli/rt/40_repl.js b/cli/rt/40_repl.js index 650fb7fc8dee94..a249b578d8065d 100644 --- a/cli/rt/40_repl.js +++ b/cli/rt/40_repl.js @@ -52,10 +52,21 @@ // Evaluate code. // Returns true if code is consumed (no error/irrecoverable error). // Returns false if error is recoverable - function evaluate(code) { + function evaluate(code, preprocess = true) { + const rawCode = code; + if (preprocess) { + // It is a bit unexpected that { "foo": "bar" } is interpreted as a block + // statement rather than an object literal so we interpret it as an expression statement + // to match the behavior found in a typical prompt including browser developer tools. + if (code.trimLeft().startsWith("{") && !code.trimRight().endsWith(";")) { + code = `(${code})`; + } + } + // each evalContext is a separate function body, and we want strict mode to // work, so we should ensure that the code starts with "use strict" const [result, errInfo] = core.evalContext(`"use strict";\n\n${code}`); + if (!errInfo) { // when a function is eval'ed with just "use strict" sometimes the result // is "use strict" which should be discarded @@ -65,6 +76,8 @@ if (!isCloseCalled()) { replLog("%o", lastEvalResult); } + } else if (errInfo.isCompileError && code.length != rawCode.length) { + return evaluate(rawCode, false); } else if (errInfo.isCompileError && isRecoverableError(errInfo.thrown)) { // Recoverable compiler error return false; // don't consume code. diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index cb633bdd286a15..3853e6fe4a8d63 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -1058,6 +1058,32 @@ fn repl_test_console_log() { assert!(err.is_empty()); } +#[test] +fn repl_test_object_literal() { + let (out, err) = util::run_and_collect_output( + true, + "repl", + Some(vec!["{}", "{ foo: 'bar' }"]), + Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]), + false, + ); + assert!(out.ends_with("{}\n{ foo: \"bar\" }\n")); + assert!(err.is_empty()); +} + +#[test] +fn repl_test_block_expression() { + let (out, err) = util::run_and_collect_output( + true, + "repl", + Some(vec!["{};", "{\"\"}"]), + Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]), + false, + ); + assert!(out.ends_with("undefined\n\"\"\n")); + assert!(err.is_empty()); +} + #[test] fn repl_cwd() { let (_out, err) = util::run_and_collect_output(