Repository: nodejs/node
Pull request: repl: eol deprecate instantiating without new

This PR moves instantiating without `new` to End-Of-Life for REPL classes, and with that, converts them to the newer class syntax.

Ref: #54869 - This is a semver-major change.

Changed files:
filename: doc/api/deprecations.md
patch: @@ -3850,6 +3850,9 @@ It is recommended to use the `new` qualifier instead. This applies to all Zlib c
 
 <!-- YAML
 changes:
+  - version: REPLACEME
+    pr-url: https://github.com/nodejs/node/pull/59495
+    description: End-of-Life.
   - version: v24.0.0
     pr-url: https://github.com/nodejs/node/pull/54869
     description: Runtime deprecation.
@@ -3860,10 +3863,10 @@ changes:
     description: Documentation-only deprecation.
 -->
 
-Type: Runtime
+Type: End-of-Life
 
 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
+The `new` qualifier must be used instead. This applies to all REPL classes, including
 `REPLServer` and `Recoverable`.
 
 <!-- md-lint skip-deprecation DEP0186 -->

filename: lib/repl.js
patch: @@ -71,7 +71,6 @@ const {
   ObjectGetOwnPropertyNames,
   ObjectGetPrototypeOf,
   ObjectKeys,
-  ObjectSetPrototypeOf,
   Promise,
   ReflectApply,
   RegExp,
@@ -92,7 +91,6 @@ const {
   StringPrototypeTrimStart,
   Symbol,
   SyntaxError,
-  SyntaxErrorPrototype,
   globalThis,
 } = primordials;
 
@@ -115,7 +113,6 @@ const {
   decorateErrorStack,
   isError,
   deprecate,
-  deprecateInstantiation,
   SideEffectFreeRegExpPrototypeSymbolReplace,
   SideEffectFreeRegExpPrototypeSymbolSplit,
 } = require('internal/util');
@@ -266,231 +263,282 @@ const toDynamicImport = (codeLine) => {
   return dynamicImportStatement;
 };
 
-function REPLServer(prompt,
-                    stream,
-                    eval_,
-                    useGlobal,
-                    ignoreUndefined,
-                    replMode) {
-  if (!(this instanceof REPLServer)) {
-    return deprecateInstantiation(REPLServer, 'DEP0185', prompt, stream, eval_, useGlobal, ignoreUndefined, replMode);
+class Recoverable extends SyntaxError {
+  constructor(err) {
+    super();
+    this.err = err;
   }
+}
 
-  let options;
-  if (prompt !== null && typeof prompt === 'object') {
-    // An options object was given.
-    options = { ...prompt };
-    stream = options.stream || options.socket;
-    eval_ = options.eval;
-    useGlobal = options.useGlobal;
-    ignoreUndefined = options.ignoreUndefined;
-    prompt = options.prompt;
-    replMode = options.replMode;
-  } else {
-    options = {};
-  }
+class REPLServer extends Interface {
+  constructor(prompt,
+              stream,
+              eval_,
+              useGlobal,
+              ignoreUndefined,
+              replMode) {
+    let options;
+    if (prompt !== null && typeof prompt === 'object') {
+      // An options object was given.
+      options = { ...prompt };
+      stream = options.stream || options.socket;
+      eval_ = options.eval;
+      useGlobal = options.useGlobal;
+      ignoreUndefined = options.ignoreUndefined;
+      prompt = options.prompt;
+      replMode = options.replMode;
+    } else {
+      options = {};
+    }
 
-  if (!options.input && !options.output) {
-    // Legacy API, passing a 'stream'/'socket' option.
-    // Use stdin and stdout as the default streams if none were given.
-    stream ||= process;
+    if (!options.input && !options.output) {
+      // Legacy API, passing a 'stream'/'socket' option.
+      // Use stdin and stdout as the default streams if none were given.
+      stream ||= process;
 
-    // We're given a duplex readable/writable Stream, like a `net.Socket`
-    // or a custom object with 2 streams, or the `process` object.
-    options.input = stream.stdin || stream;
-    options.output = stream.stdout || stream;
-  }
+      // We're given a duplex readable/writable Stream, like a `net.Socket`
+      // or a custom object with 2 streams, or the `process` object.
+      options.input = stream.stdin || stream;
+      options.output = stream.stdout || stream;
+    }
 
-  if (options.terminal === undefined) {
-    options.terminal = options.output.isTTY;
-  }
-  options.terminal = !!options.terminal;
+    if (options.terminal === undefined) {
+      options.terminal = options.output.isTTY;
+    }
+    options.terminal = !!options.terminal;
 
-  if (options.terminal && options.useColors === undefined) {
-    // If possible, check if stdout supports colors or not.
-    options.useColors = shouldColorize(options.output);
-  }
+    if (options.terminal && options.useColors === undefined) {
+      // If possible, check if stdout supports colors or not.
+      options.useColors = shouldColorize(options.output);
+    }
 
-  const preview = options.terminal &&
-    (options.preview !== undefined ? !!options.preview : !eval_);
+    const preview = options.terminal &&
+      (options.preview !== undefined ? !!options.preview : !eval_);
 
-  ObjectDefineProperty(this, 'inputStream', {
-    __proto__: null,
-    get: pendingDeprecation ?
-      deprecate(() => this.input,
-                'repl.inputStream and repl.outputStream are deprecated. ' +
+    super({
+      input: options.input,
+      output: options.output,
+      completer: options.completer || completer,
+      terminal: options.terminal,
+      historySize: options.historySize,
+      prompt,
+    });
+
+    ObjectDefineProperty(this, 'inputStream', {
+      __proto__: null,
+      get: pendingDeprecation ?
+        deprecate(() => this.input,
+                  'repl.inputStream and repl.outputStream are deprecated. ' +
                   'Use repl.input and repl.output instead',
-                'DEP0141') :
-      () => this.input,
-    set: pendingDeprecation ?
-      deprecate((val) => this.input = val,
-                'repl.inputStream and repl.outputStream are deprecated. ' +
+                  'DEP0141') :
+        () => this.input,
+      set: pendingDeprecation ?
+        deprecate((val) => this.input = val,
+                  'repl.inputStream and repl.outputStream are deprecated. ' +
                   'Use repl.input and repl.output instead',
-                'DEP0141') :
-      (val) => this.input = val,
-    enumerable: false,
-    configurable: true,
-  });
-  ObjectDefineProperty(this, 'outputStream', {
-    __proto__: null,
-    get: pendingDeprecation ?
-      deprecate(() => this.output,
-                'repl.inputStream and repl.outputStream are deprecated. ' +
+                  'DEP0141') :
+        (val) => this.input = val,
+      enumerable: false,
+      configurable: true,
+    });
+    ObjectDefineProperty(this, 'outputStream', {
+      __proto__: null,
+      get: pendingDeprecation ?
+        deprecate(() => this.output,
+                  'repl.inputStream and repl.outputStream are deprecated. ' +
                   'Use repl.input and repl.output instead',
-                'DEP0141') :
-      () => this.output,
-    set: pendingDeprecation ?
-      deprecate((val) => this.output = val,
-                'repl.inputStream and repl.outputStream are deprecated. ' +
+                  'DEP0141') :
+        () => this.output,
+      set: pendingDeprecation ?
+        deprecate((val) => this.output = val,
+                  'repl.inputStream and repl.outputStream are deprecated. ' +
                   'Use repl.input and repl.output instead',
-                'DEP0141') :
-      (val) => this.output = val,
-    enumerable: false,
-    configurable: true,
-  });
+                  'DEP0141') :
+        (val) => this.output = val,
+      enumerable: false,
+      configurable: true,
+    });
 
-  this.allowBlockingCompletions = !!options.allowBlockingCompletions;
-  this.useColors = !!options.useColors;
-  this._domain = options.domain || domain.create();
-  this.useGlobal = !!useGlobal;
-  this.ignoreUndefined = !!ignoreUndefined;
-  this.replMode = replMode || module.exports.REPL_MODE_SLOPPY;
-  this.underscoreAssigned = false;
-  this.last = undefined;
-  this.underscoreErrAssigned = false;
-  this.lastError = undefined;
-  this.breakEvalOnSigint = !!options.breakEvalOnSigint;
-  this.editorMode = false;
-  // Context id for use with the inspector protocol.
-  this[kContextId] = undefined;
-  this[kLastCommandErrored] = false;
-
-  if (this.breakEvalOnSigint && eval_) {
-    // Allowing this would not reflect user expectations.
-    // breakEvalOnSigint affects only the behavior of the default eval().
-    throw new ERR_INVALID_REPL_EVAL_CONFIG();
-  }
+    this.allowBlockingCompletions = !!options.allowBlockingCompletions;
+    this.useColors = !!options.useColors;
+    this._domain = options.domain || domain.create();
+    this.useGlobal = !!useGlobal;
+    this.ignoreUndefined = !!ignoreUndefined;
+    this.replMode = replMode || module.exports.REPL_MODE_SLOPPY;
+    this.underscoreAssigned = false;
+    this.last = undefined;
+    this.underscoreErrAssigned = false;
+    this.lastError = undefined;
+    this.breakEvalOnSigint = !!options.breakEvalOnSigint;
+    this.editorMode = false;
+    // Context id for use with the inspector protocol.
+    this[kContextId] = undefined;
+    this[kLastCommandErrored] = false;
+
+    if (this.breakEvalOnSigint && eval_) {
+      // Allowing this would not reflect user expectations.
+      // breakEvalOnSigint affects only the behavior of the default eval().
+      throw new ERR_INVALID_REPL_EVAL_CONFIG();
+    }
 
-  if (options[kStandaloneREPL]) {
-    // It is possible to introspect the running REPL accessing this variable
-    // from inside the REPL. This is useful for anyone working on the REPL.
-    module.exports.repl = this;
-  } else if (!addedNewListener) {
-    // Add this listener only once and use a WeakSet that contains the REPLs
-    // domains. Otherwise we'd have to add a single listener to each REPL
-    // instance and that could trigger the `MaxListenersExceededWarning`.
-    process.prependListener('newListener', (event, listener) => {
-      if (event === 'uncaughtException' &&
+    if (options[kStandaloneREPL]) {
+      // It is possible to introspect the running REPL accessing this variable
+      // from inside the REPL. This is useful for anyone working on the REPL.
+      module.exports.repl = this;
+    } else if (!addedNewListener) {
+      // Add this listener only once and use a WeakSet that contains the REPLs
+      // domains. Otherwise we'd have to add a single listener to each REPL
+      // instance and that could trigger the `MaxListenersExceededWarning`.
+      process.prependListener('newListener', (event, listener) => {
+        if (event === 'uncaughtException' &&
           process.domain &&
           listener.name !== 'domainUncaughtExceptionClear' &&
           domainSet.has(process.domain)) {
-        // Throw an error so that the event will not be added and the current
-        // domain takes over. That way the user is notified about the error
-        // and the current code evaluation is stopped, just as any other code
-        // that contains an error.
-        throw new ERR_INVALID_REPL_INPUT(
-          'Listeners for `uncaughtException` cannot be used in the REPL');
-      }
-    });
-    addedNewListener = true;
-  }
+          // Throw an error so that the event will not be added and the current
+          // domain takes over. That way the user is notified about the error
+          // and the current code evaluation is stopped, just as any other code
+          // that contains an error.
+          throw new ERR_INVALID_REPL_INPUT(
+            'Listeners for `uncaughtException` cannot be used in the REPL');
+        }
+      });
+      addedNewListener = true;
+    }
 
-  domainSet.add(this._domain);
+    domainSet.add(this._domain);
 
-  const savedRegExMatches = ['', '', '', '', '', '', '', '', '', ''];
-  const sep = '\u0000\u0000\u0000';
-  const regExMatcher = new RegExp(`^${sep}(.*)${sep}(.*)${sep}(.*)${sep}(.*)` +
-                                  `${sep}(.*)${sep}(.*)${sep}(.*)${sep}(.*)` +
-                                  `${sep}(.*)$`);
+    const savedRegExMatches = ['', '', '', '', '', '', '', '', '', ''];
+    const sep = '\u0000\u0000\u0000';
+    const regExMatcher = new RegExp(`^${sep}(.*)${sep}(.*)${sep}(.*)${sep}(.*)` +
+                                    `${sep}(.*)${sep}(.*)${sep}(.*)${sep}(.*)` +
+                                    `${sep}(.*)$`);
 
-  eval_ ||= defaultEval;
+    eval_ ||= defaultEval;
 
-  const self = this;
+    const self = this;
 
-  // Pause taking in new input, and store the keys in a buffer.
-  const pausedBuffer = [];
-  let paused = false;
-  function pause() {
-    paused = true;
-  }
+    // Pause taking in new input, and store the keys in a buffer.
+    const pausedBuffer = [];
+    let paused = false;
+    function pause() {
+      paused = true;
+    }
 
-  function unpause() {
-    if (!paused) return;
-    paused = false;
-    let entry;
-    const tmpCompletionEnabled = self.isCompletionEnabled;
-    while ((entry = ArrayPrototypeShift(pausedBuffer)) !== undefined) {
-      const { 0: type, 1: payload, 2: isCompletionEnabled } = entry;
-      switch (type) {
-        case 'key': {
-          const { 0: d, 1: key } = payload;
-          self.isCompletionEnabled = isCompletionEnabled;
-          self._ttyWrite(d, key);
-          break;
+    function unpause() {
+      if (!paused) return;
+      paused = false;
+      let entry;
+      const tmpCompletionEnabled = self.isCompletionEnabled;
+      while ((entry = ArrayPrototypeShift(pausedBuffer)) !== undefined) {
+        const { 0: type, 1: payload, 2: isCompletionEnabled } = entry;
+        switch (type) {
+          case 'key': {
+            const { 0: d, 1: key } = payload;
+            self.isCompletionEnabled = isCompletionEnabled;
+            self._ttyWrite(d, key);
+            break;
+          }
+          case 'close':
+            self.emit('exit');
+            break;
         }
-        case 'close':
-          self.emit('exit');
+        if (paused) {
           break;
+        }
       }
-      if (paused) {
-        break;
-      }
-    }
-    self.isCompletionEnabled = tmpCompletionEnabled;
-  }
-
-  function defaultEval(code, context, file, cb) {
-    let result, script, wrappedErr;
-    let err = null;
-    let wrappedCmd = false;
-    let awaitPromise = false;
-    const input = code;
-
-    if (isObjectLiteral(code) && isValidSyntax(code)) {
-      // Add parentheses to make sure `code` is parsed as an expression
-      code = `(${StringPrototypeTrim(code)})\n`;
-      wrappedCmd = true;
+      self.isCompletionEnabled = tmpCompletionEnabled;
     }
 
-    const hostDefinedOptionId = Symbol(`eval:${file}`);
-    let parentURL;
-    try {
-      const { pathToFileURL } = require('internal/url');
-      // Adding `/repl` prevents dynamic imports from loading relative
-      // to the parent of `process.cwd()`.
-      parentURL = pathToFileURL(path.join(process.cwd(), 'repl')).href;
-    } catch {
-      // Continue regardless of error.
-    }
-    async function importModuleDynamically(specifier, _, importAttributes, phase) {
-      const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader();
-      return cascadedLoader.import(specifier, parentURL, importAttributes,
-                                   phase === 'evaluation' ? cascadedLoader.kEvaluationPhase :
-                                     cascadedLoader.kSourcePhase);
-    }
-    // `experimentalREPLAwait` is set to true by default.
-    // Shall be false in case `--no-experimental-repl-await` flag is used.
-    if (experimentalREPLAwait && StringPrototypeIncludes(code, 'await')) {
-      if (processTopLevelAwait === undefined) {
-        ({ processTopLevelAwait } = require('internal/repl/await'));
+    function defaultEval(code, context, file, cb) {
+      let result, script, wrappedErr;
+      let err = null;
+      let wrappedCmd = false;
+      let awaitPromise = false;
+      const input = code;
+
+      if (isObjectLiteral(code) && isValidSyntax(code)) {
+        // Add parentheses to make sure `code` is parsed as an expression
+        code = `(${StringPrototypeTrim(code)})\n`;
+        wrappedCmd = true;
       }
 
+      const hostDefinedOptionId = Symbol(`eval:${file}`);
+      let parentURL;
       try {
-        const potentialWrappedCode = processTopLevelAwait(code);
-        if (potentialWrappedCode !== null) {
-          code = potentialWrappedCode;
-          wrappedCmd = true;
-          awaitPromise = true;
+        const { pathToFileURL } = require('internal/url');
+        // Adding `/repl` prevents dynamic imports from loading relative
+        // to the parent of `process.cwd()`.
+        parentURL = pathToFileURL(path.join(process.cwd(), 'repl')).href;
+      } catch {
+        // Continue regardless of error.
+      }
+      async function importModuleDynamically(specifier, _, importAttributes, phase) {
+        const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader();
+        return cascadedLoader.import(specifier, parentURL, importAttributes,
+                                     phase === 'evaluation' ? cascadedLoader.kEvaluationPhase :
+                                       cascadedLoader.kSourcePhase);
+      }
+      // `experimentalREPLAwait` is set to true by default.
+      // Shall be false in case `--no-experimental-repl-await` flag is used.
+      if (experimentalREPLAwait && StringPrototypeIncludes(code, 'await')) {
+        if (processTopLevelAwait === undefined) {
+          ({ processTopLevelAwait } = require('internal/repl/await'));
+        }
+
+        try {
+          const potentialWrappedCode = processTopLevelAwait(code);
+          if (potentialWrappedCode !== null) {
+            code = potentialWrappedCode;
+            wrappedCmd = true;
+            awaitPromise = true;
+          }
+        } catch (e) {
+          let recoverableError = false;
+          if (e.name === 'SyntaxError') {
+            // Remove all "await"s and attempt running the script
+            // in order to detect if error is truly non recoverable
+            const fallbackCode = SideEffectFreeRegExpPrototypeSymbolReplace(/\bawait\b/g, code, '');
+            try {
+              makeContextifyScript(
+                fallbackCode,            // code
+                file,                    // filename,
+                0,                       // lineOffset
+                0,                       // columnOffset,
+                undefined,               // cachedData
+                false,                   // produceCachedData
+                undefined,               // parsingContext
+                hostDefinedOptionId,     // hostDefinedOptionId
+                importModuleDynamically, // importModuleDynamically
+              );
+            } catch (fallbackError) {
+              if (isRecoverableError(fallbackError, fallbackCode)) {
+                recoverableError = true;
+                err = new Recoverable(e);
+              }
+            }
+          }
+          if (!recoverableError) {
+            decorateErrorStack(e);
+            err = e;
+          }
         }
-      } catch (e) {
-        let recoverableError = false;
-        if (e.name === 'SyntaxError') {
-          // Remove all "await"s and attempt running the script
-          // in order to detect if error is truly non recoverable
-          const fallbackCode = SideEffectFreeRegExpPrototypeSymbolReplace(/\bawait\b/g, code, '');
+      }
+
+      // First, create the Script object to check the syntax
+      if (code === '\n')
+        return cb(null);
+
+      if (err === null) {
+        while (true) {
           try {
-            makeContextifyScript(
-              fallbackCode,            // code
+            if (self.replMode === module.exports.REPL_MODE_STRICT &&
+              RegExpPrototypeExec(/^\s*$/, code) === null) {
+              // "void 0" keeps the repl from returning "use strict" as the result
+              // value for statements and declarations that don't return a value.
+              code = `'use strict'; void 0;\n${code}`;
+            }
+            script = makeContextifyScript(
+              code,                    // code
               file,                    // filename,
               0,                       // lineOffset
               0,                       // columnOffset,
@@ -500,732 +548,695 @@ function REPLServer(prompt,
               hostDefinedOptionId,     // hostDefinedOptionId
               importModuleDynamically, // importModuleDynamically
             );
-          } catch (fallbackError) {
-            if (isRecoverableError(fallbackError, fallbackCode)) {
-              recoverableError = true;
-              err = new Recoverable(e);
+          } catch (e) {
+            debug('parse error %j', code, e);
+            if (wrappedCmd) {
+              // Unwrap and try again
+              wrappedCmd = false;
+              awaitPromise = false;
+              code = input;
+              wrappedErr = e;
+              continue;
             }
-          }
-        }
-        if (!recoverableError) {
-          decorateErrorStack(e);
-          err = e;
-        }
-      }
-    }
+            // Preserve original error for wrapped command
+            const error = wrappedErr || e;
+            if (isRecoverableError(error, code))
+              err = new Recoverable(error);
 
-    // First, create the Script object to check the syntax
-    if (code === '\n')
-      return cb(null);
-
-    if (err === null) {
-      while (true) {
-        try {
-          if (self.replMode === module.exports.REPL_MODE_STRICT &&
-              RegExpPrototypeExec(/^\s*$/, code) === null) {
-            // "void 0" keeps the repl from returning "use strict" as the result
-            // value for statements and declarations that don't return a value.
-            code = `'use strict'; void 0;\n${code}`;
-          }
-          script = makeContextifyScript(
-            code,                    // code
-            file,                    // filename,
-            0,                       // lineOffset
-            0,                       // columnOffset,
-            undefined,               // cachedData
-            false,                   // produceCachedData
-            undefined,               // parsingContext
-            hostDefinedOptionId,     // hostDefinedOptionId
-            importModuleDynamically, // importModuleDynamically
-          );
-        } catch (e) {
-          debug('parse error %j', code, e);
-          if (wrappedCmd) {
-            // Unwrap and try again
-            wrappedCmd = false;
-            awaitPromise = false;
-            code = input;
-            wrappedErr = e;
-            continue;
+            else
+              err = error;
           }
-          // Preserve original error for wrapped command
-          const error = wrappedErr || e;
-          if (isRecoverableError(error, code))
-            err = new Recoverable(error);
-          else
-            err = error;
+          break;
         }
-        break;
       }
-    }
 
-    // This will set the values from `savedRegExMatches` to corresponding
-    // predefined RegExp properties `RegExp.$1`, `RegExp.$2` ... `RegExp.$9`
-    RegExpPrototypeExec(regExMatcher,
-                        ArrayPrototypeJoin(savedRegExMatches, sep));
+      // This will set the values from `savedRegExMatches` to corresponding
+      // predefined RegExp properties `RegExp.$1`, `RegExp.$2` ... `RegExp.$9`
+      RegExpPrototypeExec(regExMatcher,
+                          ArrayPrototypeJoin(savedRegExMatches, sep));
 
-    let finished = false;
-    function finishExecution(err, result) {
-      if (finished) return;
-      finished = true;
+      let finished = false;
+      function finishExecution(err, result) {
+        if (finished) return;
+        finished = true;
 
-      // After executing the current expression, store the values of RegExp
-      // predefined properties back in `savedRegExMatches`
-      for (let idx = 1; idx < savedRegExMatches.length; idx += 1) {
-        savedRegExMatches[idx] = RegExp[`$${idx}`];
-      }
-
-      cb(err, result);
-    }
+        // After executing the current expression, store the values of RegExp
+        // predefined properties back in `savedRegExMatches`
+        for (let idx = 1; idx < savedRegExMatches.length; idx += 1) {
+          savedRegExMatches[idx] = RegExp[`$${idx}`];
+        }
 
-    if (!err) {
-      // Unset raw mode during evaluation so that Ctrl+C raises a signal.
-      let previouslyInRawMode;
-      if (self.breakEvalOnSigint) {
-        // Start the SIGINT watchdog before entering raw mode so that a very
-        // quick Ctrl+C doesn't lead to aborting the process completely.
-        if (!startSigintWatchdog())
-          throw new ERR_CANNOT_WATCH_SIGINT();
-        previouslyInRawMode = self._setRawMode(false);
+        cb(err, result);
       }
 
-      try {
+      if (!err) {
+        // Unset raw mode during evaluation so that Ctrl+C raises a signal.
+        let previouslyInRawMode;
+        if (self.breakEvalOnSigint) {
+          // Start the SIGINT watchdog before entering raw mode so that a very
+          // quick Ctrl+C doesn't lead to aborting the process completely.
+          if (!startSigintWatchdog())
+            throw new ERR_CANNOT_WATCH_SIGINT();
+          previouslyInRawMode = self._setRawMode(false);
+        }
+
         try {
-          const scriptOptions = {
-            displayErrors: false,
-            breakOnSigint: self.breakEvalOnSigint,
-          };
+          try {
+            const scriptOptions = {
+              displayErrors: false,
+              breakOnSigint: self.breakEvalOnSigint,
+            };
 
-          if (self.useGlobal) {
-            result = ReflectApply(runInThisContext, script, [scriptOptions]);
-          } else {
-            result = ReflectApply(runInContext, script, [context, scriptOptions]);
+            if (self.useGlobal) {
+              result = ReflectApply(runInThisContext, script, [scriptOptions]);
+            } else {
+              result = ReflectApply(runInContext, script, [context, scriptOptions]);
+            }
+          } finally {
+            if (self.breakEvalOnSigint) {
+              // Reset terminal mode to its previous value.
+              self._setRawMode(previouslyInRawMode);
+
+              // Returns true if there were pending SIGINTs *after* the script
+              // has terminated without being interrupted itself.
+              if (stopSigintWatchdog()) {
+                self.emit('SIGINT');
+              }
+            }
           }
-        } finally {
-          if (self.breakEvalOnSigint) {
-            // Reset terminal mode to its previous value.
-            self._setRawMode(previouslyInRawMode);
+        } catch (e) {
+          err = e;
 
-            // Returns true if there were pending SIGINTs *after* the script
-            // has terminated without being interrupted itself.
-            if (stopSigintWatchdog()) {
-              self.emit('SIGINT');
-            }
+          if (process.domain) {
+            debug('not recoverable, send to domain');
+            process.domain.emit('error', err);
+            process.domain.exit();
+            return;
           }
         }
-      } catch (e) {
-        err = e;
 
-        if (process.domain) {
-          debug('not recoverable, send to domain');
-          process.domain.emit('error', err);
-          process.domain.exit();
-          return;
-        }
-      }
+        if (awaitPromise && !err) {
+          let sigintListener;
+          pause();
+          let promise = result;
+          if (self.breakEvalOnSigint) {
+            const interrupt = new Promise((resolve, reject) => {
+              sigintListener = () => {
+                const tmp = MainContextError.stackTraceLimit;
+                if (isErrorStackTraceLimitWritable()) MainContextError.stackTraceLimit = 0;
+                const err = new ERR_SCRIPT_EXECUTION_INTERRUPTED();
+                if (isErrorStackTraceLimitWritable()) MainContextError.stackTraceLimit = tmp;
+                reject(err);
+              };
+              prioritizedSigintQueue.add(sigintListener);
+            });
+            promise = SafePromiseRace([promise, interrupt]);
+          }
 
-      if (awaitPromise && !err) {
-        let sigintListener;
-        pause();
-        let promise = result;
-        if (self.breakEvalOnSigint) {
-          const interrupt = new Promise((resolve, reject) => {
-            sigintListener = () => {
-              const tmp = MainContextError.stackTraceLimit;
-              if (isErrorStackTraceLimitWritable()) MainContextError.stackTraceLimit = 0;
-              const err = new ERR_SCRIPT_EXECUTION_INTERRUPTED();
-              if (isErrorStackTraceLimitWritable()) MainContextError.stackTraceLimit = tmp;
-              reject(err);
-            };
-            prioritizedSigintQueue.add(sigintListener);
-          });
-          promise = SafePromiseRace([promise, interrupt]);
+          (async () => {
+            try {
+              const result = (await promise)?.value;
+              finishExecution(null, result);
+            } catch (err) {
+              if (err && process.domain) {
+                debug('not recoverable, send to domain');
+                process.domain.emit('error', err);
+                process.domain.exit();
+                return;
+              }
+              finishExecution(err);
+            } finally {
+              // Remove prioritized SIGINT listener if it was not called.
+              prioritizedSigintQueue.delete(sigintListener);
+              unpause();
+            }
+          })();
         }
+      }
 
-        (async () => {
-          try {
-            const result = (await promise)?.value;
-            finishExecution(null, result);
-          } catch (err) {
-            if (err && process.domain) {
-              debug('not recoverable, send to domain');
-              process.domain.emit('error', err);
-              process.domain.exit();
-              return;
-            }
-            finishExecution(err);
-          } finally {
-            // Remove prioritized SIGINT listener if it was not called.
-            prioritizedSigintQueue.delete(sigintListener);
-            unpause();
-          }
-        })();
+      if (!awaitPromise || err) {
+        finishExecution(err, result);
       }
     }
 
-    if (!awaitPromise || err) {
-      finishExecution(err, result);
-    }
-  }
+    self.eval = self._domain.bind(eval_);
+
+    self._domain.on('error', function debugDomainError(e) {
+      debug('domain error');
+      let errStack = '';
+
+      if (typeof e === 'object' && e !== null) {
+        overrideStackTrace.set(e, (error, stackFrames) => {
+          let frames;
+          if (typeof stackFrames === 'object') {
+            // Search from the bottom of the call stack to
+            // find the first frame with a null function name
+            const idx = ArrayPrototypeFindLastIndex(
+              stackFrames,
+              (frame) => frame.getFunctionName() === null,
+            );
+            // If found, get rid of it and everything below it
+            frames = ArrayPrototypeSlice(stackFrames, 0, idx);
+          } else {
+            frames = stackFrames;
+          }
+          // FIXME(devsnek): this is inconsistent with the checks
+          // that the real prepareStackTrace dispatch uses in
+          // lib/internal/errors.js.
+          if (typeof MainContextError.prepareStackTrace === 'function') {
+            return MainContextError.prepareStackTrace(error, frames);
+          }
+          return ErrorPrepareStackTrace(error, frames);
+        });
+        decorateErrorStack(e);
 
-  self.eval = self._domain.bind(eval_);
-
-  self._domain.on('error', function debugDomainError(e) {
-    debug('domain error');
-    let errStack = '';
-
-    if (typeof e === 'object' && e !== null) {
-      overrideStackTrace.set(e, (error, stackFrames) => {
-        let frames;
-        if (typeof stackFrames === 'object') {
-          // Search from the bottom of the call stack to
-          // find the first frame with a null function name
-          const idx = ArrayPrototypeFindLastIndex(
-            stackFrames,
-            (frame) => frame.getFunctionName() === null,
-          );
-          // If found, get rid of it and everything below it
-          frames = ArrayPrototypeSlice(stackFrames, 0, idx);
-        } else {
-          frames = stackFrames;
-        }
-        // FIXME(devsnek): this is inconsistent with the checks
-        // that the real prepareStackTrace dispatch uses in
-        // lib/internal/errors.js.
-        if (typeof MainContextError.prepareStackTrace === 'function') {
-          return MainContextError.prepareStackTrace(error, frames);
+        if (e.domainThrown) {
+          delete e.domain;
+          delete e.domainThrown;
         }
-        return ErrorPrepareStackTrace(error, frames);
-      });
-      decorateErrorStack(e);
 
-      if (e.domainThrown) {
-        delete e.domain;
-        delete e.domainThrown;
-      }
-
-      if (isError(e)) {
-        if (e.stack) {
-          if (e.name === 'SyntaxError') {
-            // Remove stack trace.
-            e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
-              /^\s+at\s.*\n?/gm,
-              SideEffectFreeRegExpPrototypeSymbolReplace(/^REPL\d+:\d+\r?\n/, e.stack, ''),
-              '');
-            const importErrorStr = 'Cannot use import statement outside a ' +
-              'module';
-            if (StringPrototypeIncludes(e.message, importErrorStr)) {
-              e.message = 'Cannot use import statement inside the Node.js ' +
-                'REPL, alternatively use dynamic import: ' + toDynamicImport(ArrayPrototypeAt(self.lines, -1));
+        if (isError(e)) {
+          if (e.stack) {
+            if (e.name === 'SyntaxError') {
+              // Remove stack trace.
               e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
-                /SyntaxError:.*\n/,
+                /^\s+at\s.*\n?/gm,
+                SideEffectFreeRegExpPrototypeSymbolReplace(/^REPL\d+:\d+\r?\n/, e.stack, ''),
+                '');
+              const importErrorStr = 'Cannot use import statement outside a ' +
+                'module';
+              if (StringPrototypeIncludes(e.message, importErrorStr)) {
+                e.message = 'Cannot use import statement inside the Node.js ' +
+                  'REPL, alternatively use dynamic import: ' + toDynamicImport(ArrayPrototypeAt(self.lines, -1));
+                e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
+                  /SyntaxError:.*\n/,
+                  e.stack,
+                  `SyntaxError: ${e.message}\n`);
+              }
+            } else if (self.replMode === module.exports.REPL_MODE_STRICT) {
+              e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
+                /(\s+at\s+REPL\d+:)(\d+)/,
                 e.stack,
-                `SyntaxError: ${e.message}\n`);
+                (_, pre, line) => pre + (line - 1),
+              );
             }
-          } else if (self.replMode === module.exports.REPL_MODE_STRICT) {
-            e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
-              /(\s+at\s+REPL\d+:)(\d+)/,
-              e.stack,
-              (_, pre, line) => pre + (line - 1),
-            );
           }
-        }
-        errStack = self.writer(e);
+          errStack = self.writer(e);
 
-        // Remove one line error braces to keep the old style in place.
-        if (errStack[0] === '[' && errStack[errStack.length - 1] === ']') {
-          errStack = StringPrototypeSlice(errStack, 1, -1);
+          // Remove one line error braces to keep the old style in place.
+          if (errStack[0] === '[' && errStack[errStack.length - 1] === ']') {
+            errStack = StringPrototypeSlice(errStack, 1, -1);
+          }
         }
       }
-    }
 
-    if (!self.underscoreErrAssigned) {
-      self.lastError = e;
-    }
+      if (!self.underscoreErrAssigned) {
+        self.lastError = e;
+      }
 
-    if (options[kStandaloneREPL] &&
+      if (options[kStandaloneREPL] &&
         process.listenerCount('uncaughtException') !== 0) {
-      process.nextTick(() => {
-        process.emit('uncaughtException', e);
+        process.nextTick(() => {
+          process.emit('uncaughtException', e);
+          self.clearBufferedCommand();
+          self.lines.level = [];
+          if (!self.closed) {
+            self.displayPrompt();
+          }
+        });
+      } else {
+        if (errStack === '') {
+          errStack = self.writer(e);
+        }
+        const lines = SideEffectFreeRegExpPrototypeSymbolSplit(/(?<=\n)/, errStack);
+        let matched = false;
+
+        errStack = '';
+        ArrayPrototypeForEach(lines, (line) => {
+          if (!matched &&
+            RegExpPrototypeExec(/^\[?([A-Z][a-z0-9_]*)*Error/, line) !== null) {
+            errStack += writer.options.breakLength >= line.length ?
+              `Uncaught ${line}` :
+              `Uncaught:\n${line}`;
+            matched = true;
+          } else {
+            errStack += line;
+          }
+        });
+        if (!matched) {
+          const ln = lines.length === 1 ? ' ' : ':\n';
+          errStack = `Uncaught${ln}${errStack}`;
+        }
+        // Normalize line endings.
+        errStack += StringPrototypeEndsWith(errStack, '\n') ? '' : '\n';
+        self.output.write(errStack);
         self.clearBufferedCommand();
         self.lines.level = [];
         if (!self.closed) {
           self.displayPrompt();
         }
-      });
-    } else {
-      if (errStack === '') {
-        errStack = self.writer(e);
-      }
-      const lines = SideEffectFreeRegExpPrototypeSymbolSplit(/(?<=\n)/, errStack);
-      let matched = false;
-
-      errStack = '';
-      ArrayPrototypeForEach(lines, (line) => {
-        if (!matched &&
-            RegExpPrototypeExec(/^\[?([A-Z][a-z0-9_]*)*Error/, line) !== null) {
-          errStack += writer.options.breakLength >= line.length ?
-            `Uncaught ${line}` :
-            `Uncaught:\n${line}`;
-          matched = true;
-        } else {
-          errStack += line;
-        }
-      });
-      if (!matched) {
-        const ln = lines.length === 1 ? ' ' : ':\n';
-        errStack = `Uncaught${ln}${errStack}`;
       }
-      // Normalize line endings.
-      errStack += StringPrototypeEndsWith(errStack, '\n') ? '' : '\n';
-      self.output.write(errStack);
-      self.clearBufferedCommand();
-      self.lines.level = [];
-      if (!self.closed) {
-        self.displayPrompt();
-      }
-    }
-  });
-
-  self.clearBufferedCommand();
-
-  function completer(text, cb) {
-    ReflectApply(complete, self,
-                 [text, self.editorMode ? self.completeOnEditorMode(cb) : cb]);
-  }
-
-  // All the parameters in the object are defining the "input" param of the
-  // InterfaceConstructor.
-  ReflectApply(Interface, this, [{
-    input: options.input,
-    output: options.output,
-    completer: options.completer || completer,
-    terminal: options.terminal,
-    historySize: options.historySize,
-    prompt,
-  }]);
-
-  self.resetContext();
-
-  this.commands = { __proto__: null };
-  defineDefaultCommands(this);
-
-  // Figure out which "writer" function to use
-  self.writer = options.writer || module.exports.writer;
+    });
 
-  if (self.writer === writer) {
-    // Conditionally turn on ANSI coloring.
-    writer.options.colors = self.useColors;
+    self.clearBufferedCommand();
 
-    if (options[kStandaloneREPL]) {
-      ObjectDefineProperty(inspect, 'replDefaults', {
-        __proto__: null,
-        get() {
-          return writer.options;
-        },
-        set(options) {
-          validateObject(options, 'options');
-          return ObjectAssign(writer.options, options);
-        },
-        enumerable: true,
-        configurable: true,
-      });
+    function completer(text, cb) {
+      ReflectApply(complete, self,
+                   [text, self.editorMode ? self.completeOnEditorMode(cb) : cb]);
     }
-  }
 
-  function _parseREPLKeyword(keyword, rest) {
-    const cmd = this.commands[keyword];
-    if (cmd) {
-      ReflectApply(cmd.action, this, [rest]);
-      return true;
+    self.resetContext();
+
+    this.commands = { __proto__: null };
+    defineDefaultCommands(this);
+
+    // Figure out which "writer" function to use
+    self.writer = options.writer || module.exports.writer;
+
+    if (self.writer === writer) {
+      // Conditionally turn on ANSI coloring.
+      writer.options.colors = self.useColors;
+
+      if (options[kStandaloneREPL]) {
+        ObjectDefineProperty(inspect, 'replDefaults', {
+          __proto__: null,
+          get() {
+            return writer.options;
+          },
+          set(options) {
+            validateObject(options, 'options');
+            return ObjectAssign(writer.options, options);
+          },
+          enumerable: true,
+          configurable: true,
+        });
+      }
     }
-    return false;
-  }
 
-  self.on('close', function emitExit() {
-    if (paused) {
-      ArrayPrototypePush(pausedBuffer, ['close']);
-      return;
+    function _parseREPLKeyword(keyword, rest) {
+      const cmd = this.commands[keyword];
+      if (cmd) {
+        ReflectApply(cmd.action, this, [rest]);
+        return true;
+      }
+      return false;
     }
-    self.emit('exit');
-  });
 
-  let sawSIGINT = false;
-  let sawCtrlD = false;
-  const prioritizedSigintQueue = new SafeSet();
-  self.on('SIGINT', function onSigInt() {
-    if (prioritizedSigintQueue.size > 0) {
-      for (const task of prioritizedSigintQueue) {
-        task();
+    self.on('close', function emitExit() {
+      if (paused) {
+        ArrayPrototypePush(pausedBuffer, ['close']);
+        return;
       }
-      return;
-    }
+      self.emit('exit');
+    });
 
-    const empty = self.line.length === 0;
-    self.clearLine();
-    _turnOffEditorMode(self);
+    let sawSIGINT = false;
+    let sawCtrlD = false;
+    const prioritizedSigintQueue = new SafeSet();
+    self.on('SIGINT', function onSigInt() {
+      if (prioritizedSigintQueue.size > 0) {
+        for (const task of prioritizedSigintQueue) {
+          task();
+        }
+        return;
+      }
 
-    const cmd = self[kBufferedCommandSymbol];
-    if (!(cmd && cmd.length > 0) && empty) {
-      if (sawSIGINT) {
-        self.close();
+      const empty = self.line.length === 0;
+      self.clearLine();
+      _turnOffEditorMode(self);
+
+      const cmd = self[kBufferedCommandSymbol];
+      if (!(cmd && cmd.length > 0) && empty) {
+        if (sawSIGINT) {
+          self.close();
+          sawSIGINT = false;
+          return;
+        }
+        self.output.write(
+          '(To exit, press Ctrl+C again or Ctrl+D or type .exit)\n',
+        );
+        sawSIGINT = true;
+      } else {
         sawSIGINT = false;
-        return;
       }
-      self.output.write(
-        '(To exit, press Ctrl+C again or Ctrl+D or type .exit)\n',
-      );
-      sawSIGINT = true;
-    } else {
-      sawSIGINT = false;
-    }
 
-    self.clearBufferedCommand();
-    self.lines.level = [];
-    self.displayPrompt();
-  });
+      self.clearBufferedCommand();
+      self.lines.level = [];
+      self.displayPrompt();
+    });
+
+    self.on('line', function onLine(cmd) {
+      debug('line %j', cmd);
+      cmd ||= '';
+      sawSIGINT = false;
 
-  self.on('line', function onLine(cmd) {
-    debug('line %j', cmd);
-    cmd ||= '';
-    sawSIGINT = false;
-
-    if (self.editorMode) {
-      self[kBufferedCommandSymbol] += cmd + '\n';
-
-      // code alignment
-      const matches = self._sawKeyPress && !self[kLoadingSymbol] ?
-        RegExpPrototypeExec(/^\s+/, cmd) : null;
-      if (matches) {
-        const prefix = matches[0];
-        self.write(prefix);
-        self.line = prefix;
-        self.cursor = prefix.length;
+      if (self.editorMode) {
+        self[kBufferedCommandSymbol] += cmd + '\n';
+
+        // code alignment
+        const matches = self._sawKeyPress && !self[kLoadingSymbol] ?
+          RegExpPrototypeExec(/^\s+/, cmd) : null;
+        if (matches) {
+          const prefix = matches[0];
+          self.write(prefix);
+          self.line = prefix;
+          self.cursor = prefix.length;
+        }
+        ReflectApply(_memory, self, [cmd]);
+        return;
       }
-      ReflectApply(_memory, self, [cmd]);
-      return;
-    }
 
-    // Check REPL keywords and empty lines against a trimmed line input.
-    const trimmedCmd = StringPrototypeTrim(cmd);
+      // Check REPL keywords and empty lines against a trimmed line input.
+      const trimmedCmd = StringPrototypeTrim(cmd);
 
-    // Check to see if a REPL keyword was used. If it returns true,
-    // display next prompt and return.
-    if (trimmedCmd) {
-      if (StringPrototypeCharAt(trimmedCmd, 0) === '.' &&
+      // 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);
-        const keyword = matches?.[1];
-        const rest = matches?.[2];
-        if (ReflectApply(_parseREPLKeyword, self, [keyword, rest]) === true) {
-          return;
-        }
-        if (!self[kBufferedCommandSymbol]) {
-          self.output.write('Invalid REPL keyword\n');
-          finish(null);
-          return;
+          const matches = RegExpPrototypeExec(/^\.([^\s]+)\s*(.*)$/, trimmedCmd);
+          const keyword = matches?.[1];
+          const rest = matches?.[2];
+          if (ReflectApply(_parseREPLKeyword, self, [keyword, rest]) === true) {
+            return;
+          }
+          if (!self[kBufferedCommandSymbol]) {
+            self.output.write('Invalid REPL keyword\n');
+            finish(null);
+            return;
+          }
         }
       }
-    }
 
-    const evalCmd = self[kBufferedCommandSymbol] + cmd + '\n';
+      const evalCmd = self[kBufferedCommandSymbol] + cmd + '\n';
 
-    debug('eval %j', evalCmd);
-    self.eval(evalCmd, self.context, getREPLResourceName(), finish);
+      debug('eval %j', evalCmd);
+      self.eval(evalCmd, self.context, getREPLResourceName(), finish);
 
-    function finish(e, ret) {
-      debug('finish', e, ret);
-      ReflectApply(_memory, self, [cmd]);
+      function finish(e, ret) {
+        debug('finish', e, ret);
+        ReflectApply(_memory, self, [cmd]);
 
-      if (e && !self[kBufferedCommandSymbol] &&
+        if (e && !self[kBufferedCommandSymbol] &&
           StringPrototypeStartsWith(StringPrototypeTrim(cmd), 'npm ') &&
-          !(e instanceof Recoverable)
-      ) {
-        self.output.write('npm should be run outside of the ' +
-                                'Node.js REPL, in your normal shell.\n' +
-                                '(Press Ctrl+D to exit.)\n');
-        self.displayPrompt();
-        return;
-      }
-
-      // If error was SyntaxError and not JSON.parse error
-      // We can start a multiline command
-      if (e instanceof Recoverable && !sawCtrlD) {
-        if (self.terminal) {
-          self[kAddNewLineOnTTY]();
-        } else {
-          self[kBufferedCommandSymbol] += cmd + '\n';
+          !(e instanceof Recoverable)) {
+          self.output.write('npm should be run outside of the ' +
+                            'Node.js REPL, in your normal shell.\n' +
+                            '(Press Ctrl+D to exit.)\n');
           self.displayPrompt();
+          return;
         }
-        return;
-      }
 
-      if (e) {
-        self._domain.emit('error', e.err || e);
-        self[kLastCommandErrored] = true;
-      }
+        // If error was SyntaxError and not JSON.parse error
+        // We can start a multiline command
+        if (e instanceof Recoverable && !sawCtrlD) {
+          if (self.terminal) {
+            self[kAddNewLineOnTTY]();
+          } else {
+            self[kBufferedCommandSymbol] += cmd + '\n';
+            self.displayPrompt();
+          }
+          return;
+        }
 
-      // Clear buffer if no SyntaxErrors
-      self.clearBufferedCommand();
-      sawCtrlD = false;
+        if (e) {
+          self._domain.emit('error', e.err || e);
+          self[kLastCommandErrored] = true;
+        }
+
+        // Clear buffer if no SyntaxErrors
+        self.clearBufferedCommand();
+        sawCtrlD = false;
 
-      // If we got any output - print it (if no error)
-      if (!e &&
+        // If we got any output - print it (if no error)
+        if (!e &&
           // When an invalid REPL command is used, error message is printed
           // immediately. We don't have to print anything else. So, only when
           // the second argument to this function is there, print it.
           arguments.length === 2 &&
           (!self.ignoreUndefined || ret !== undefined)) {
-        if (!self.underscoreAssigned) {
-          self.last = ret;
+          if (!self.underscoreAssigned) {
+            self.last = ret;
+          }
+          self.output.write(self.writer(ret) + '\n');
         }
-        self.output.write(self.writer(ret) + '\n');
-      }
 
-      // If the REPL sever hasn't closed display prompt again (unless we already
-      // did by emitting the 'error' event on the domain instance).
-      if (!self.closed && !e) {
-        self[kLastCommandErrored] = false;
-        self.displayPrompt();
+        // If the REPL sever hasn't closed display prompt again (unless we already
+        // did by emitting the 'error' event on the domain instance).
+        if (!self.closed && !e) {
+          self[kLastCommandErrored] = false;
+          self.displayPrompt();
+        }
       }
-    }
-  });
-
-  self.on('SIGCONT', function onSigCont() {
-    if (self.editorMode) {
-      self.output.write(`${self._initialPrompt}.editor\n`);
-      self.output.write(
-        '// Entering editor mode (Ctrl+D to finish, Ctrl+C to cancel)\n');
-      self.output.write(`${self[kBufferedCommandSymbol]}\n`);
-      self.prompt(true);
-    } else {
-      self.displayPrompt(true);
-    }
-  });
+    });
 
-  const { reverseSearch } = setupReverseSearch(this);
+    self.on('SIGCONT', function onSigCont() {
+      if (self.editorMode) {
+        self.output.write(`${self._initialPrompt}.editor\n`);
+        self.output.write(
+          '// Entering editor mode (Ctrl+D to finish, Ctrl+C to cancel)\n');
+        self.output.write(`${self[kBufferedCommandSymbol]}\n`);
+        self.prompt(true);
+      } else {
+        self.displayPrompt(true);
+      }
+    });
 
-  const {
-    clearPreview,
-    showPreview,
-  } = setupPreview(
-    this,
-    kContextId,
-    kBufferedCommandSymbol,
-    preview,
-  );
+    const { reverseSearch } = setupReverseSearch(this);
 
-  // Wrap readline tty to enable editor mode and pausing.
-  const ttyWrite = FunctionPrototypeBind(self._ttyWrite, self);
-  self._ttyWrite = (d, key) => {
-    key ||= {};
-    if (paused && !(self.breakEvalOnSigint && key.ctrl && key.name === 'c')) {
-      ArrayPrototypePush(pausedBuffer,
-                         ['key', [d, key], self.isCompletionEnabled]);
-      return;
-    }
-    if (!self.editorMode || !self.terminal) {
-      // Before exiting, make sure to clear the line.
-      if (key.ctrl && key.name === 'd' &&
-          self.cursor === 0 && self.line.length === 0) {
-        self.clearLine();
-      }
-      clearPreview(key);
-      if (!reverseSearch(d, key)) {
-        ttyWrite(d, key);
-        const showCompletionPreview = key.name !== 'escape';
-        showPreview(showCompletionPreview);
-      }
-      return;
-    }
+    const {
+      clearPreview, showPreview,
+    } = setupPreview(
+      this,
+      kContextId,
+      kBufferedCommandSymbol,
+      preview,
+    );
 
-    // Editor mode
-    if (key.ctrl && !key.shift) {
-      switch (key.name) {
-        // TODO(BridgeAR): There should not be a special mode necessary for full
-        // multiline support.
-        case 'd': // End editor mode
-          _turnOffEditorMode(self);
-          sawCtrlD = true;
-          ttyWrite(d, { name: 'return' });
-          break;
-        case 'n': // Override next history item
-        case 'p': // Override previous history item
-          break;
-        default:
-          ttyWrite(d, key);
+    // Wrap readline tty to enable editor mode and pausing.
+    const ttyWrite = FunctionPrototypeBind(self._ttyWrite, self);
+    self._ttyWrite = (d, key) => {
+      key ||= {};
+      if (paused && !(self.breakEvalOnSigint && key.ctrl && key.name === 'c')) {
+        ArrayPrototypePush(pausedBuffer,
+                           ['key', [d, key], self.isCompletionEnabled]);
+        return;
       }
-    } else {
-      switch (key.name) {
-        case 'up':   // Override previous history item
-        case 'down': // Override next history item
-          break;
-        case 'tab':
-          // Prevent double tab behavior
-          self._previousKey = null;
-          ttyWrite(d, key);
-          break;
-        default:
+      if (!self.editorMode || !self.terminal) {
+        // Before exiting, make sure to clear the line.
+        if (key.ctrl && key.name === 'd' &&
+          self.cursor === 0 && self.line.length === 0) {
+          self.clearLine();
+        }
+        clearPreview(key);
+        if (!reverseSearch(d, key)) {
           ttyWrite(d, key);
+          const showCompletionPreview = key.name !== 'escape';
+          showPreview(showCompletionPreview);
+        }
+        return;
       }
-    }
-  };
 
-  self.displayPrompt();
-}
-ObjectSetPrototypeOf(REPLServer.prototype, Interface.prototype);
-ObjectSetPrototypeOf(REPLServer, Interface);
-
-// Prompt is a string to print on each line for the prompt,
-// source is a stream to use for I/O, defaulting to stdin/stdout.
-function start(prompt, source, eval_, useGlobal, ignoreUndefined, replMode) {
-  return new REPLServer(
-    prompt, source, eval_, useGlobal, ignoreUndefined, replMode);
-}
-
-REPLServer.prototype.setupHistory = function setupHistory(historyConfig = {}, cb) {
-  // TODO(puskin94): necessary because historyConfig can be a string for backwards compatibility
-  const options = typeof historyConfig === 'string' ?
-    { filePath: historyConfig } :
-    historyConfig;
+      // Editor mode
+      if (key.ctrl && !key.shift) {
+        switch (key.name) {
+          // TODO(BridgeAR): There should not be a special mode necessary for full
+          // multiline support.
+          case 'd': // End editor mode
+            _turnOffEditorMode(self);
+            sawCtrlD = true;
+            ttyWrite(d, { name: 'return' });
+            break;
+          case 'n': // Override next history item
+          case 'p': // Override previous history item
+            break;
+          default:
+            ttyWrite(d, key);
+        }
+      } else {
+        switch (key.name) {
+          case 'up': // Override previous history item
+          case 'down': // Override next history item
+            break;
+          case 'tab':
+            // Prevent double tab behavior
+            self._previousKey = null;
+            ttyWrite(d, key);
+            break;
+          default:
+            ttyWrite(d, key);
+        }
+      }
+    };
 
-  if (typeof cb === 'function') {
-    options.onHistoryFileLoaded = cb;
+    self.displayPrompt();
   }
+  setupHistory(historyConfig = {}, cb) {
+    // TODO(puskin94): necessary because historyConfig can be a string for backwards compatibility
+    const options = typeof historyConfig === 'string' ?
+      { filePath: historyConfig } :
+      historyConfig;
+
+    if (typeof cb === 'function') {
+      options.onHistoryFileLoaded = cb;
+    }
 
-  this.setupHistoryManager(options);
-};
-
-REPLServer.prototype.clearBufferedCommand = function clearBufferedCommand() {
-  this[kBufferedCommandSymbol] = '';
-};
-
-REPLServer.prototype.close = function close() {
-  if (this.terminal && this.historyManager.isFlushing && !this._closingOnFlush) {
-    this._closingOnFlush = true;
-    this.once('flushHistory', () =>
-      ReflectApply(Interface.prototype.close, this, []),
-    );
-
-    return;
+    this.setupHistoryManager(options);
   }
-  process.nextTick(() =>
-    ReflectApply(Interface.prototype.close, this, []),
-  );
-};
+  clearBufferedCommand() {
+    this[kBufferedCommandSymbol] = '';
+  }
+  close() {
+    if (this.terminal && this.historyManager.isFlushing && !this._closingOnFlush) {
+      this._closingOnFlush = true;
+      this.once('flushHistory', () => super.close());
 
-REPLServer.prototype.createContext = function() {
-  let context;
-  if (this.useGlobal) {
-    context = globalThis;
-  } else {
-    sendInspectorCommand((session) => {
-      session.post('Runtime.enable');
-      session.once('Runtime.executionContextCreated', ({ params }) => {
-        this[kContextId] = params.context.id;
+      return;
+    }
+    process.nextTick(() => super.close());
+  }
+  createContext() {
+    let context;
+    if (this.useGlobal) {
+      context = globalThis;
+    } else {
+      sendInspectorCommand((session) => {
+        session.post('Runtime.enable');
+        session.once('Runtime.executionContextCreated', ({ params }) => {
+          this[kContextId] = params.context.id;
+        });
+        context = vm.createContext();
+        session.post('Runtime.disable');
+      }, () => {
+        context = vm.createContext();
       });
-      context = vm.createContext();
-      session.post('Runtime.disable');
-    }, () => {
-      context = vm.createContext();
-    });
-    ArrayPrototypeForEach(ObjectGetOwnPropertyNames(globalThis), (name) => {
-      // Only set properties that do not already exist as a global builtin.
-      if (!globalBuiltins.has(name)) {
-        ObjectDefineProperty(context, name,
-                             {
-                               __proto__: null,
-                               ...ObjectGetOwnPropertyDescriptor(globalThis, name),
-                             });
-      }
+      ArrayPrototypeForEach(ObjectGetOwnPropertyNames(globalThis), (name) => {
+        // Only set properties that do not already exist as a global builtin.
+        if (!globalBuiltins.has(name)) {
+          ObjectDefineProperty(context, name,
+                               {
+                                 __proto__: null,
+                                 ...ObjectGetOwnPropertyDescriptor(globalThis, name),
+                               });
+        }
+      });
+      context.global = context;
+      const _console = new Console(this.output);
+      ObjectDefineProperty(context, 'console', {
+        __proto__: null,
+        configurable: true,
+        writable: true,
+        value: _console,
+      });
+    }
+
+    const replModule = new CJSModule('<repl>');
+    replModule.paths = CJSModule._resolveLookupPaths('<repl>', parentModule);
+
+    ObjectDefineProperty(context, 'module', {
+      __proto__: null,
+      configurable: true,
+      writable: true,
+      value: replModule,
     });
-    context.global = context;
-    const _console = new Console(this.output);
-    ObjectDefineProperty(context, 'console', {
+    ObjectDefineProperty(context, 'require', {
       __proto__: null,
       configurable: true,
       writable: true,
-      value: _console,
+      value: makeRequireFunction(replModule),
     });
-  }
 
-  const replModule = new CJSModule('<repl>');
-  replModule.paths = CJSModule._resolveLookupPaths('<repl>', parentModule);
+    addBuiltinLibsToObject(context, '<REPL>');
 
-  ObjectDefineProperty(context, 'module', {
-    __proto__: null,
-    configurable: true,
-    writable: true,
-    value: replModule,
-  });
-  ObjectDefineProperty(context, 'require', {
-    __proto__: null,
-    configurable: true,
-    writable: true,
-    value: makeRequireFunction(replModule),
-  });
+    return context;
+  }
+  resetContext() {
+    this.context = this.createContext();
+    this.underscoreAssigned = false;
+    this.underscoreErrAssigned = false;
+    // TODO(BridgeAR): Deprecate the lines.
+    this.lines = [];
+    this.lines.level = [];
+
+    ObjectDefineProperty(this.context, '_', {
+      __proto__: null,
+      configurable: true,
+      get: () => this.last,
+      set: (value) => {
+        this.last = value;
+        if (!this.underscoreAssigned) {
+          this.underscoreAssigned = true;
+          this.output.write('Expression assignment to _ now disabled.\n');
+        }
+      },
+    });
 
-  addBuiltinLibsToObject(context, '<REPL>');
+    ObjectDefineProperty(this.context, '_error', {
+      __proto__: null,
+      configurable: true,
+      get: () => this.lastError,
+      set: (value) => {
+        this.lastError = value;
+        if (!this.underscoreErrAssigned) {
+          this.underscoreErrAssigned = true;
+          this.output.write(
+            'Expression assignment to _error now disabled.\n');
+        }
+      },
+    });
 
-  return context;
-};
+    // Allow REPL extensions to extend the new context
+    this.emit('reset', this.context);
+  }
+  displayPrompt(preserveCursor) {
+    let prompt = this._initialPrompt;
+    if (this[kBufferedCommandSymbol].length) {
+      prompt = kMultilinePrompt.description;
+    }
 
-REPLServer.prototype.resetContext = function() {
-  this.context = this.createContext();
-  this.underscoreAssigned = false;
-  this.underscoreErrAssigned = false;
-  // TODO(BridgeAR): Deprecate the lines.
-  this.lines = [];
-  this.lines.level = [];
-
-  ObjectDefineProperty(this.context, '_', {
-    __proto__: null,
-    configurable: true,
-    get: () => this.last,
-    set: (value) => {
-      this.last = value;
-      if (!this.underscoreAssigned) {
-        this.underscoreAssigned = true;
-        this.output.write('Expression assignment to _ now disabled.\n');
-      }
-    },
-  });
+    // Do not overwrite `_initialPrompt` here
+    super.setPrompt(prompt);
+    this.prompt(preserveCursor);
+  }
+  // When invoked as an API method, overwrite _initialPrompt
+  setPrompt(prompt) {
+    this._initialPrompt = prompt;
+    super.setPrompt(prompt);
+  }
+  complete() {
+    ReflectApply(this.completer, this, arguments);
+  }
+  completeOnEditorMode(callback) {
+    return (err, results) => {
+      if (err) return callback(err);
 
-  ObjectDefineProperty(this.context, '_error', {
-    __proto__: null,
-    configurable: true,
-    get: () => this.lastError,
-    set: (value) => {
-      this.lastError = value;
-      if (!this.underscoreErrAssigned) {
-        this.underscoreErrAssigned = true;
-        this.output.write(
-          'Expression assignment to _error now disabled.\n');
-      }
-    },
-  });
+      const { 0: completions, 1: completeOn = '' } = results;
+      let result = ArrayPrototypeFilter(completions, Boolean);
 
-  // Allow REPL extensions to extend the new context
-  this.emit('reset', this.context);
-};
+      if (completeOn && result.length !== 0) {
+        result = [commonPrefix(result)];
+      }
 
-REPLServer.prototype.displayPrompt = function(preserveCursor) {
-  let prompt = this._initialPrompt;
-  if (this[kBufferedCommandSymbol].length) {
-    prompt = kMultilinePrompt.description;
+      callback(null, [result, completeOn]);
+    };
   }
+  defineCommand(keyword, cmd) {
+    if (typeof cmd === 'function') {
+      cmd = { action: cmd };
+    } else {
+      validateFunction(cmd.action, 'cmd.action');
+    }
+    this.commands[keyword] = cmd;
+  }
+}
 
-  // Do not overwrite `_initialPrompt` here
-  ReflectApply(Interface.prototype.setPrompt, this, [prompt]);
-  this.prompt(preserveCursor);
-};
-
-// When invoked as an API method, overwrite _initialPrompt
-REPLServer.prototype.setPrompt = function setPrompt(prompt) {
-  this._initialPrompt = prompt;
-  ReflectApply(Interface.prototype.setPrompt, this, [prompt]);
-};
+// Prompt is a string to print on each line for the prompt,
+// source is a stream to use for I/O, defaulting to stdin/stdout.
+function start(prompt, source, eval_, useGlobal, ignoreUndefined, replMode) {
+  return new REPLServer(
+    prompt, source, eval_, useGlobal, ignoreUndefined, replMode);
+}
 
 const importRE = /\bimport\s*\(\s*['"`](([\w@./:-]+\/)?(?:[\w@./:-]*))(?![^'"`])$/;
 const requireRE = /\brequire\s*\(\s*['"`](([\w@./:-]+\/)?(?:[\w@./:-]*))(?![^'"`])$/;
@@ -1292,9 +1303,6 @@ function getGlobalLexicalScopeNames(contextId) {
   }, () => []);
 }
 
-REPLServer.prototype.complete = function() {
-  ReflectApply(this.completer, this, arguments);
-};
 
 function gracefulReaddir(...args) {
   try {
@@ -1922,27 +1930,6 @@ function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) {
   return callback(false);
 }
 
-REPLServer.prototype.completeOnEditorMode = (callback) => (err, results) => {
-  if (err) return callback(err);
-
-  const { 0: completions, 1: completeOn = '' } = results;
-  let result = ArrayPrototypeFilter(completions, Boolean);
-
-  if (completeOn && result.length !== 0) {
-    result = [commonPrefix(result)];
-  }
-
-  callback(null, [result, completeOn]);
-};
-
-REPLServer.prototype.defineCommand = function(keyword, cmd) {
-  if (typeof cmd === 'function') {
-    cmd = { action: cmd };
-  } else {
-    validateFunction(cmd.action, 'cmd.action');
-  }
-  this.commands[keyword] = cmd;
-};
 
 // TODO(BridgeAR): This should be replaced with acorn to build an AST. The
 // language became more complex and using a simple approach like this is not
@@ -2154,12 +2141,6 @@ function defineDefaultCommands(repl) {
   }
 }
 
-function Recoverable(err) {
-  this.err = err;
-}
-ObjectSetPrototypeOf(Recoverable.prototype, SyntaxErrorPrototype);
-ObjectSetPrototypeOf(Recoverable, SyntaxError);
-
 module.exports = {
   start,
   writer,

filename: test/parallel/test-repl.js
patch: @@ -1050,17 +1050,3 @@ 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');
-}