diff --git a/lib/internal/repl/completion.js b/lib/internal/repl/completion.js index 8ff58ecd197fb4..96b646a4e4469d 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) { + 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..ef269f44b7698b --- /dev/null +++ b/test/parallel/test-repl-tab-complete-new-expression.js @@ -0,0 +1,41 @@ +'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', () => { + const { replServer, input } = startNewREPLServer({ terminal: false }); + + input.run([ + ` + class X { x = 1 }; + X.Y = class Y { y = 2 }; + `, + ]); + + // Handle completion for property of root class. + replServer.complete( + 'new X.', + common.mustSucceed((completions) => { + assert.strictEqual(completions[1], 'X.'); + }) + ); + + // 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(); + }); +});