From ac2f3e99d8b5cc41e8f1b669138d48278479939a Mon Sep 17 00:00:00 2001 From: hainenber Date: Sun, 19 Oct 2025 20:57:09 +0700 Subject: [PATCH 1/2] repl: tab completion targets `` instead of `new ` Signed-off-by: hainenber --- lib/internal/repl/completion.js | 10 ++++++ .../test-repl-tab-complete-new-expression.js | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 test/parallel/test-repl-tab-complete-new-expression.js diff --git a/lib/internal/repl/completion.js b/lib/internal/repl/completion.js index 8ff58ecd197fb4..403f063464eca2 100644 --- a/lib/internal/repl/completion.js +++ b/lib/internal/repl/completion.js @@ -613,6 +613,16 @@ function findExpressionCompleteTarget(code) { return findExpressionCompleteTarget(argumentCode); } + // If the last statement is an expression statement with "new" syntax + // we want to extract the callee for completion (e.g. for `new Sample` we want `Sample`) + if (lastBodyStatement.type === 'ExpressionStatement' && + lastBodyStatement.expression.type === 'NewExpression' && + lastBodyStatement.expression.callee.type === 'Identifier') { + const callee = lastBodyStatement.expression.callee; + const calleeCode = code.slice(callee.start, callee.end); + return findExpressionCompleteTarget(calleeCode); + } + // Walk the AST for the current block of code, and check whether it contains any // statement or expression type that would potentially have side effects if evaluated. let isAllowed = true; diff --git a/test/parallel/test-repl-tab-complete-new-expression.js b/test/parallel/test-repl-tab-complete-new-expression.js new file mode 100644 index 00000000000000..b9918fb69be851 --- /dev/null +++ b/test/parallel/test-repl-tab-complete-new-expression.js @@ -0,0 +1,32 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { startNewREPLServer } = require('../common/repl'); +const { describe, it } = require('node:test'); + +// This test verifies that tab completion works correctly with `new` operator +// for a class. Property access has higher precedence than `new` so the properties +// should be displayed as autocompletion result. + +describe('REPL tab completion with new expressions', () => { + it('should output completion of class properties', (_, done) => { + const { replServer, input } = startNewREPLServer({ terminal: false }); + + input.run([ + ` + class X { x = 1 }; + X.Y = class Y { y = 2 }; + `, + ]); + + replServer.complete( + 'new X.', + common.mustSucceed((completions) => { + assert.strictEqual(completions[1], 'X.'); + replServer.close(); + done(); + }) + ); + }); +}); From 3549c252ebdc5e1eefcf1d0cb4ee9d3237ab5b8b Mon Sep 17 00:00:00 2001 From: hainenber Date: Tue, 21 Oct 2025 20:52:34 +0700 Subject: [PATCH 2/2] repl: loosen condition to handle case of nested class properties Signed-off-by: hainenber --- lib/internal/repl/completion.js | 2 +- .../test-repl-tab-complete-new-expression.js | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/internal/repl/completion.js b/lib/internal/repl/completion.js index 403f063464eca2..96b646a4e4469d 100644 --- a/lib/internal/repl/completion.js +++ b/lib/internal/repl/completion.js @@ -617,7 +617,7 @@ function findExpressionCompleteTarget(code) { // we want to extract the callee for completion (e.g. for `new Sample` we want `Sample`) if (lastBodyStatement.type === 'ExpressionStatement' && lastBodyStatement.expression.type === 'NewExpression' && - lastBodyStatement.expression.callee.type === 'Identifier') { + lastBodyStatement.expression.callee) { const callee = lastBodyStatement.expression.callee; const calleeCode = code.slice(callee.start, callee.end); return findExpressionCompleteTarget(calleeCode); diff --git a/test/parallel/test-repl-tab-complete-new-expression.js b/test/parallel/test-repl-tab-complete-new-expression.js index b9918fb69be851..ef269f44b7698b 100644 --- a/test/parallel/test-repl-tab-complete-new-expression.js +++ b/test/parallel/test-repl-tab-complete-new-expression.js @@ -10,7 +10,7 @@ const { describe, it } = require('node:test'); // should be displayed as autocompletion result. describe('REPL tab completion with new expressions', () => { - it('should output completion of class properties', (_, done) => { + it('should output completion of class properties', () => { const { replServer, input } = startNewREPLServer({ terminal: false }); input.run([ @@ -20,13 +20,22 @@ describe('REPL tab completion with new expressions', () => { `, ]); + // Handle completion for property of root class. replServer.complete( 'new X.', common.mustSucceed((completions) => { assert.strictEqual(completions[1], 'X.'); - replServer.close(); - done(); }) ); + + // Handle completion for property with another class as value. + replServer.complete( + 'new X.Y.', + common.mustSucceed((completions) => { + assert.strictEqual(completions[1], 'X.Y.'); + }) + ); + + replServer.close(); }); });