From b75103caaaf30d421100db0a0d4d2d0c088790de Mon Sep 17 00:00:00 2001 From: SudhansuBandha Date: Sun, 14 Jun 2026 14:57:44 +0530 Subject: [PATCH 1/3] repl: fix dot command handling in multiline mode Update conditional logic to correctly handle dot commands in multiline REPL input Fixes: https://github.com/nodejs/node/issues/63864 Refs: https://github.com/nodejs/node/pull/63889/ Signed-off-by: SudhansuBandha --- lib/repl.js | 16 ++++++-- ...t-repl-multiline-dot-commands-execution.js | 40 +++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 test/parallel/test-repl-multiline-dot-commands-execution.js diff --git a/lib/repl.js b/lib/repl.js index 17aab1c409beca..3836f8fa17f9b2 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -76,6 +76,7 @@ const { StringPrototypeCharAt, StringPrototypeEndsWith, StringPrototypeIncludes, + StringPrototypeIndexOf, StringPrototypeRepeat, StringPrototypeSlice, StringPrototypeStartsWith, @@ -807,10 +808,17 @@ class REPLServer extends Interface { // Check to see if a REPL keyword was used. If it returns true, // display next prompt and return. if (trimmedCmd) { - if (StringPrototypeCharAt(trimmedCmd, 0) === '.' && - StringPrototypeCharAt(trimmedCmd, 1) !== '.' && - NumberIsNaN(NumberParseFloat(trimmedCmd))) { - const matches = RegExpPrototypeExec(/^\.([^\s]+)\s*(.*)$/, trimmedCmd); + // If condition validates for dot commands at the beginning of the line, + // or dot commands after some whitespace. + const isDotCommandAtStart = StringPrototypeCharAt(trimmedCmd, 0) === '.' && + StringPrototypeCharAt(trimmedCmd, 1) !== '.'; + const dotIndex = StringPrototypeIndexOf(trimmedCmd, '.'); + const isDotCommandAfterWhitespace = dotIndex > 0 && + StringPrototypeCharAt(trimmedCmd, dotIndex + 1) !== '.'; + + if ((isDotCommandAtStart || isDotCommandAfterWhitespace) && + NumberIsNaN(NumberParseFloat(trimmedCmd))) { + const matches = RegExpPrototypeExec(/(?:^|\s)\.([^\s]+)\s*(.*)$/, trimmedCmd); const keyword = matches?.[1]; const rest = matches?.[2]; if (FunctionPrototypeCall(_parseREPLKeyword, self, keyword, rest) === true) { diff --git a/test/parallel/test-repl-multiline-dot-commands-execution.js b/test/parallel/test-repl-multiline-dot-commands-execution.js new file mode 100644 index 00000000000000..b1baac3fc787c9 --- /dev/null +++ b/test/parallel/test-repl-multiline-dot-commands-execution.js @@ -0,0 +1,40 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { startNewREPLServer } = require('../common/repl'); + + +const dotCommandSyntaxError = + /Uncaught SyntaxError: Unexpected token '\.'/; + + +function runDotCommand(command, validate) { + const { replServer, output } = startNewREPLServer(); + + replServer.on('exit', common.mustCall()); + replServer.write('function a() {\n'); + replServer.write(`${command}\n`); + validate(replServer, output); + replServer.write('arr = [1,\n'); + replServer.write(`${command}\n`); + validate(replServer, output); + replServer.close(); +} + +runDotCommand('.break', common.mustCall((replServer, output) => { + replServer.write('1 + 1\n'); + assert.doesNotMatch(output.accumulator, dotCommandSyntaxError); + assert.match(output.accumulator, /2\n/); +}, 2)); + +runDotCommand('.clear', common.mustCall((replServer, output) => { + replServer.write('1 + 1\n'); + assert.doesNotMatch(output.accumulator, dotCommandSyntaxError); + assert.match(output.accumulator, /2\n/); +}, 2)); + +runDotCommand('.help', common.mustCall((replServer, output) => { + replServer.write('1 + 1\n'); + assert.doesNotMatch(output.accumulator, dotCommandSyntaxError); + assert.match(output.accumulator, /2\n/); +}, 2)); From 738694b09ed89c46785c0b30c1b108b3e5535e98 Mon Sep 17 00:00:00 2001 From: SudhansuBandha Date: Mon, 15 Jun 2026 13:46:36 +0530 Subject: [PATCH 2/3] improved validation logic for dot operator commands --- lib/repl.js | 10 +++++----- .../test-repl-multiline-dot-commands-execution.js | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 3836f8fa17f9b2..953732e57a8a0e 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -815,12 +815,12 @@ class REPLServer extends Interface { const dotIndex = StringPrototypeIndexOf(trimmedCmd, '.'); const isDotCommandAfterWhitespace = dotIndex > 0 && StringPrototypeCharAt(trimmedCmd, dotIndex + 1) !== '.'; - - if ((isDotCommandAtStart || isDotCommandAfterWhitespace) && + const matches = RegExpPrototypeExec(/(?:^|\s)\.([^\s]+)\s*(.*)$/, trimmedCmd); + const keyword = matches?.[1]; + const rest = matches?.[2]; + const isValidKeyword = keyword && ObjectKeys(self.commands).includes(keyword); + if ((isDotCommandAtStart || isDotCommandAfterWhitespace && isValidKeyword) && NumberIsNaN(NumberParseFloat(trimmedCmd))) { - const matches = RegExpPrototypeExec(/(?:^|\s)\.([^\s]+)\s*(.*)$/, trimmedCmd); - const keyword = matches?.[1]; - const rest = matches?.[2]; if (FunctionPrototypeCall(_parseREPLKeyword, self, keyword, rest) === true) { return; } diff --git a/test/parallel/test-repl-multiline-dot-commands-execution.js b/test/parallel/test-repl-multiline-dot-commands-execution.js index b1baac3fc787c9..7f0e6a4e33eb84 100644 --- a/test/parallel/test-repl-multiline-dot-commands-execution.js +++ b/test/parallel/test-repl-multiline-dot-commands-execution.js @@ -13,9 +13,11 @@ function runDotCommand(command, validate) { replServer.on('exit', common.mustCall()); replServer.write('function a() {\n'); + replServer.write('console.log("logging");\n'); replServer.write(`${command}\n`); validate(replServer, output); replServer.write('arr = [1,\n'); + replServer.write('console.log("logging");\n'); replServer.write(`${command}\n`); validate(replServer, output); replServer.close(); From 13934b2068e341de5b0c7e8222dc526570245cd9 Mon Sep 17 00:00:00 2001 From: SudhansuBandha Date: Mon, 15 Jun 2026 17:19:21 +0530 Subject: [PATCH 3/3] test: rerun CI - 1