Repository: nodejs/node (JavaScript)

Issue:
Different behavior of { a: 1 } in the REPL and the debugger
### Version

v19.7.0

### Platform

_No response_

### Subsystem

_No response_

### What steps will reproduce the bug?

Evaluating `{ a: 1 }` in the REPL and the debugger have different result

```
% node
> { a: 1 }
{ a: 1 }
```

```
% node inspect app.js
debug> { a: 1 }
1
```

### How often does it reproduce? Is there a required condition?

Always

### What is the expected behavior?

Like REPL, the result of debugger will be
```
% node inspect app.js
debug> { a: 1 }
{ a: 1 }
```

### What do you see instead?

```
% node inspect app.js
debug> { a: 1 }
1
```

### Additional information

The results of `{ a: 1 }` in other runtimes: 

- ChromeDevTools: `{ a: 1 }`

- Safari WebInspector: `{ a: 1 }`

We have a similar bug ([#45964](https://github.com/nodejs/node/issues/45964)) but we have not fixed yet and it was closed


Discussion: > We have a similar bug (#45964) but we have not fixed yet and it was closed

That's because it's not considered a bug but working as expected, it's a deliberate choice. Thanks for the report but I'm going to go ahead and close it.
@bnoordhuis We reached the consensus that it's not a bug, so the `node inspect` REPL should have the same behavior.

Current:
```
% node
> { a: 1 }
{ a: 1 }

% node inspect app.js
debug> { a: 1 }
1
```

Expected:
```
% node
> { a: 1 }
{ a: 1 }

% node inspect app.js
debug> { a: 1 }
{ a: 1 }
```

@cola119 who is "we"?
I meant that we have reached the consensus that the REPL's evaluation of `{a: 1}` as `{a: 1}` instead of `1` is not a bug, so `node inspect`'s REPL should behave in the same way.



Fix (patch):
diff --git a/lib/internal/debugger/inspect_repl.js b/lib/internal/debugger/inspect_repl.js
index 8dc5e9823cae6e..2a0bd4e5149fd7 100644
--- a/lib/internal/debugger/inspect_repl.js
+++ b/lib/internal/debugger/inspect_repl.js
@@ -56,6 +56,7 @@ const { fileURLToPath } = require('internal/url');
 
 const { customInspectSymbol, SideEffectFreeRegExpPrototypeSymbolReplace } = require('internal/util');
 const { inspect: utilInspect } = require('internal/util/inspect');
+const { isObjectLiteral } = require('internal/repl/utils');
 const debuglog = require('internal/util/debuglog').debuglog('inspect');
 
 const SHORTCUTS = {
@@ -573,8 +574,15 @@ function createRepl(inspector) {
     if (input === '\n') return lastCommand;
     // Add parentheses: exec process.title => exec("process.title");
     const match = RegExpPrototypeExec(/^\s*(?:exec|p)\s+([^\n]*)/, input);
+    input = match ? match[1] : input;
+
+    if (isObjectLiteral(input)) {
+      // Add parentheses to make sure `input` is parsed as an expression
+      input = `(${StringPrototypeTrim(input)})\n`;
+    }
+
     if (match) {
-      lastCommand = `exec(${JSONStringify(match[1])})`;
+      lastCommand = `exec(${JSONStringify(input)})`;
     } else {
       lastCommand = input;
     }
diff --git a/lib/internal/repl/utils.js b/lib/internal/repl/utils.js
index 126f8ae85d0977..79a2c55dff16d7 100644
--- a/lib/internal/repl/utils.js
+++ b/lib/internal/repl/utils.js
@@ -739,6 +739,22 @@ function setupReverseSearch(repl) {
   return { reverseSearch };
 }
 
+const startsWithBraceRegExp = /^\s*{/;
+const endsWithSemicolonRegExp = /;\s*$/;
+
+/**
+ * Checks if some provided code represents an object literal.
+ * This is helpful to prevent confusing repl code evaluations where
+ * strings such as `{ a : 1 }` would get interpreted as block statements
+ * rather than object literals.
+ * @param {string} code the code to check
+ * @returns {boolean} true if the code represents an object literal, false otherwise
+ */
+function isObjectLiteral(code) {
+  return RegExpPrototypeExec(startsWithBraceRegExp, code) !== null &&
+    RegExpPrototypeExec(endsWithSemicolonRegExp, code) === null;
+}
+
 module.exports = {
   REPL_MODE_SLOPPY: Symbol('repl-sloppy'),
   REPL_MODE_STRICT,
@@ -746,4 +762,5 @@ module.exports = {
   kStandaloneREPL: Symbol('kStandaloneREPL'),
   setupPreview,
   setupReverseSearch,
+  isObjectLiteral,
 };
diff --git a/lib/repl.js b/lib/repl.js
index 6cfceacac620f0..e61a24bb041c7e 100644
--- a/lib/repl.js
+++ b/lib/repl.js
@@ -172,6 +172,7 @@ const {
   kStandaloneREPL,
   setupPreview,
   setupReverseSearch,
+  isObjectLiteral,
 } = require('internal/repl/utils');
 const {
   constants: {
@@ -436,13 +437,8 @@ function REPLServer(prompt,
     let awaitPromise = false;
     const input = code;
 
-    // It's confusing for `{ a : 1 }` to be interpreted as a block
-    // statement rather than an object literal.  So, we first try
-    // to wrap it in parentheses, so that it will be interpreted as
-    // an expression.  Note that if the above condition changes,
-    // lib/internal/repl/utils.js needs to be changed to match.
-    if (RegExpPrototypeExec(/^\s*{/, code) !== null &&
-        RegExpPrototypeExec(/;\s*$/, code) === null) {
+    if (isObjectLiteral(code)) {
+      // Add parentheses to make sure `code` is parsed as an expression
       code = `(${StringPrototypeTrim(code)})\n`;
       wrappedCmd = true;
     }