diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 598315197fe255..678a6e7f085140 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -3733,9 +3733,12 @@ changes: - version: REPLACEME pr-url: https://github.com/nodejs/node/pull/54842 description: Documentation-only deprecation. + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/TODO + description: Runtime deprecation. --> -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 f9de6cd77c71f4..cad11c35133957 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -100,7 +100,7 @@ function isError(e) { // each one once. const codesWarned = new SafeSet(); -let validateString; +const lazyValidateString = getLazy(() => require('internal/validators').validateString); function getDeprecationWarningEmitter( code, msg, deprecated, useEmitSync, @@ -148,12 +148,8 @@ function pendingDeprecate(fn, msg, code) { // Returns a modified function which warns once by default. // If --no-deprecation is set, then it is a no-op. function deprecate(fn, msg, code, useEmitSync) { - // Lazy-load to avoid a circular dependency. - if (validateString === undefined) - ({ validateString } = require('internal/validators')); - if (code !== undefined) - validateString(code, 'code'); + lazyValidateString()(code, 'code'); const emitDeprecationWarning = getDeprecationWarningEmitter( code, msg, deprecated, useEmitSync, @@ -182,6 +178,15 @@ function deprecate(fn, msg, code, useEmitSync) { return deprecated; } +function deprecateInstantation(target, code, ...args) { + if (code !== undefined) + lazyValidateString()(code, 'code'); + + 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; @@ -902,6 +907,7 @@ module.exports = { defineLazyProperties, defineReplaceableLazyAttribute, deprecate, + deprecateInstantation, emitExperimentalWarning, encodingsMap, exposeInterface, diff --git a/lib/repl.js b/lib/repl.js index 6e2d8120ad2167..613c978c2bd607 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -111,6 +111,7 @@ const { decorateErrorStack, isError, deprecate, + deprecateInstantation, 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 deprecateInstantation(REPLServer, 'DEP0185', prompt, stream, eval_, useGlobal, ignoreUndefined, replMode); } let options; @@ -1849,6 +1845,8 @@ function defineDefaultCommands(repl) { } function Recoverable(err) { + if (!(this instanceof Recoverable)) + return deprecateInstantation(Recoverable, 'DEP0185'); this.err = err; } ObjectSetPrototypeOf(Recoverable.prototype, SyntaxErrorPrototype); diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index 4d406a8a36caaf..9fee3885f0e2a1 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -1014,3 +1014,13 @@ function event(ee, expected) { })); }); } + +{ + const server = repl.REPLServer(); + common.expectWarning({ + DeprecationWarning: { + DEP0185: 'Instantiating REPLServer without the \'new\' keyword has been deprecated.', + } + }); + server.emit('line', '.exit'); +}