GeezerVison is showing github.com — debugger: fix behavior of plain object exec in debugger repl · nodejs/node@1f08864
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/debugger/inspect_repl.js +9-1Lines changed: 9 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -56,6 +56,7 @@ const { fileURLToPath } = require('internal/url'); | 56 | 56 |
| 57 | 57 | const { customInspectSymbol, SideEffectFreeRegExpPrototypeSymbolReplace } = require('internal/util'); | 58 | 58 | const { inspect: utilInspect } = require('internal/util/inspect'); | | 59 | +const { isObjectLiteral } = require('internal/repl/utils'); | 59 | 60 | const debuglog = require('internal/util/debuglog').debuglog('inspect'); | 60 | 61 |
| 61 | 62 | const SHORTCUTS = { | @@ -573,8 +574,15 @@ function createRepl(inspector) { | 573 | 574 | if (input === '\n') return lastCommand; | 574 | 575 | // Add parentheses: exec process.title => exec("process.title"); | 575 | 576 | const match = RegExpPrototypeExec(/^\s*(?:exec|p)\s+([^\n]*)/, input); | | 577 | + input = match ? match[1] : input; | | 578 | + | | 579 | + if (isObjectLiteral(input)) { | | 580 | + // Add parentheses to make sure `input` is parsed as an expression | | 581 | + input = `(${StringPrototypeTrim(input)})\n`; | | 582 | + } | | 583 | + | 576 | 584 | if (match) { | 577 | | - lastCommand = `exec(${JSONStringify(match[1])})`; | | 585 | + lastCommand = `exec(${JSONStringify(input)})`; | 578 | 586 | } else { | 579 | 587 | lastCommand = input; | 580 | 588 | } | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/repl/utils.js +17Lines changed: 17 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -739,11 +739,28 @@ function setupReverseSearch(repl) { | 739 | 739 | return { reverseSearch }; | 740 | 740 | } | 741 | 741 |
| | 742 | +const startsWithBraceRegExp = /^\s*{/; | | 743 | +const endsWithSemicolonRegExp = /;\s*$/; | | 744 | + | | 745 | +/** | | 746 | + * Checks if some provided code represents an object literal. | | 747 | + * This is helpful to prevent confusing repl code evaluations where | | 748 | + * strings such as `{ a : 1 }` would get interpreted as block statements | | 749 | + * rather than object literals. | | 750 | + * @param {string} code the code to check | | 751 | + * @returns {boolean} true if the code represents an object literal, false otherwise | | 752 | + */ | | 753 | +function isObjectLiteral(code) { | | 754 | + return RegExpPrototypeExec(startsWithBraceRegExp, code) !== null && | | 755 | + RegExpPrototypeExec(endsWithSemicolonRegExp, code) === null; | | 756 | +} | | 757 | + | 742 | 758 | module.exports = { | 743 | 759 | REPL_MODE_SLOPPY: Symbol('repl-sloppy'), | 744 | 760 | REPL_MODE_STRICT, | 745 | 761 | isRecoverableError, | 746 | 762 | kStandaloneREPL: Symbol('kStandaloneREPL'), | 747 | 763 | setupPreview, | 748 | 764 | setupReverseSearch, | | 765 | + isObjectLiteral, | 749 | 766 | }; |
Collapse file Copy file name to clipboardExpand all lines: lib/repl.js +3-7Lines changed: 3 additions & 7 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -171,6 +171,7 @@ const { | 171 | 171 | kStandaloneREPL, | 172 | 172 | setupPreview, | 173 | 173 | setupReverseSearch, | | 174 | + isObjectLiteral, | 174 | 175 | } = require('internal/repl/utils'); | 175 | 176 | const { | 176 | 177 | constants: { | @@ -440,13 +441,8 @@ function REPLServer(prompt, | 440 | 441 | let awaitPromise = false; | 441 | 442 | const input = code; | 442 | 443 |
| 443 | | - // It's confusing for `{ a : 1 }` to be interpreted as a block | 444 | | - // statement rather than an object literal. So, we first try | 445 | | - // to wrap it in parentheses, so that it will be interpreted as | 446 | | - // an expression. Note that if the above condition changes, | 447 | | - // lib/internal/repl/utils.js needs to be changed to match. | 448 | | - if (RegExpPrototypeExec(/^\s*{/, code) !== null && | 449 | | - RegExpPrototypeExec(/;\s*$/, code) === null) { | | 444 | + if (isObjectLiteral(code)) { | | 445 | + // Add parentheses to make sure `code` is parsed as an expression | 450 | 446 | code = `(${StringPrototypeTrim(code)})\n`; | 451 | 447 | wrappedCmd = true; | 452 | 448 | } | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-debugger-exec.js +5Lines changed: 5 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -60,6 +60,11 @@ async function waitInitialBreak() { | 60 | 60 | /\[ 'undefined', 'function' \]/, | 61 | 61 | 'non-paused exec can see global but not module-scope values' | 62 | 62 | ); | | 63 | + | | 64 | + // Ref: https://github.com/nodejs/node/issues/46808 | | 65 | + await cli.waitForPrompt(); | | 66 | + await cli.command('exec { a: 1 }'); | | 67 | + assert.match(cli.output, /\{ a: 1 \}/); | 63 | 68 | } finally { | 64 | 69 | await cli.quit(); | 65 | 70 | } | |
|