diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 9c5ded0dd3b9dc..0d62af9ba608b6 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -3748,6 +3748,9 @@ It is recommended to use the `new` qualifier instead. This applies to all Zlib c -Type: Documentation-only +Type: Runtime Instantiating classes without the `new` qualifier exported by the `node:repl` module is deprecated. It is recommended to use the `new` qualifier instead. This applies to all REPL classes, including diff --git a/lib/internal/util.js b/lib/internal/util.js index 4d8cf99a3453d9..bb25da74b65d3d 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -63,6 +63,7 @@ const { } = internalBinding('util'); const { isNativeError, isPromise } = internalBinding('types'); const { getOptionValue } = require('internal/options'); +const assert = require('internal/assert'); const { encodings } = internalBinding('string_decoder'); const noCrypto = !process.versions.openssl; @@ -179,6 +180,14 @@ function deprecate(fn, msg, code, useEmitSync) { return deprecated; } +function deprecateInstantiation(target, code, ...args) { + assert(typeof code === 'string'); + + getDeprecationWarningEmitter(code, `Instantiating ${target.name} without the 'new' keyword has been deprecated.`, target)(); + + return ReflectConstruct(target, args); +} + function decorateErrorStack(err) { if (!(isError(err) && err.stack) || err[decorated_private_symbol]) return; @@ -873,6 +882,7 @@ module.exports = { defineLazyProperties, defineReplaceableLazyAttribute, deprecate, + deprecateInstantiation, emitExperimentalWarning, encodingsMap, exposeInterface, diff --git a/lib/repl.js b/lib/repl.js index 37b34af2917643..c195ba428ce6c2 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -111,6 +111,7 @@ const { decorateErrorStack, isError, deprecate, + deprecateInstantiation, SideEffectFreeRegExpPrototypeSymbolReplace, SideEffectFreeRegExpPrototypeSymbolSplit, } = require('internal/util'); @@ -262,12 +263,7 @@ function REPLServer(prompt, ignoreUndefined, replMode) { if (!(this instanceof REPLServer)) { - return new REPLServer(prompt, - stream, - eval_, - useGlobal, - ignoreUndefined, - replMode); + return deprecateInstantiation(REPLServer, 'DEP0185', prompt, stream, eval_, useGlobal, ignoreUndefined, replMode); } let options; diff --git a/test/parallel/test-repl-preview-without-inspector.js b/test/parallel/test-repl-preview-without-inspector.js index 8905d214836c64..67090a928feba4 100644 --- a/test/parallel/test-repl-preview-without-inspector.js +++ b/test/parallel/test-repl-preview-without-inspector.js @@ -65,7 +65,7 @@ function runAndWait(cmds, repl) { return promise; } -const repl = REPLServer({ +const repl = new REPLServer({ prompt: PROMPT, stream: new REPLStream(), ignoreUndefined: true, diff --git a/test/parallel/test-repl-preview.js b/test/parallel/test-repl-preview.js index 6eb2a169918a51..06a044f5a11a13 100644 --- a/test/parallel/test-repl-preview.js +++ b/test/parallel/test-repl-preview.js @@ -57,7 +57,7 @@ function runAndWait(cmds, repl) { } async function tests(options) { - const repl = REPLServer({ + const repl = new REPLServer({ prompt: PROMPT, stream: new REPLStream(), ignoreUndefined: true, diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index 610c7813e0439c..be51efd2143d31 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -1035,3 +1035,17 @@ function event(ee, expected) { })); }); } + +{ + const server = repl.REPLServer(); + common.expectWarning({ + DeprecationWarning: { + DEP0185: 'Instantiating REPLServer without the \'new\' keyword has been deprecated.', + // For the 'url.format' test-case. + DEP0169: + '`url.parse()` behavior is not standardized and prone to errors that have security implications. ' + + 'Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` vulnerabilities.', + } + }); + server.emit('line', '.exit'); +}