Spec-Zone.ru › Node.js 24 LTS

REPL

Стабильность: 2 - Стабильный

Исходный код: lib/repl.js

Модуль node:repl предоставляет реализацию Read-Eval-Print-Loop (REPL), доступную как в виде отдельной программы, так и для включения в другие приложения. К нему можно получить доступ с помощью:

Модули JavaScript
import repl from 'node:repl';
CommonJS
const repl = require('node:repl');

Устройство и возможности

Модуль node:repl экспортирует класс repl.REPLServer. Во время работы экземпляры repl.REPLServer принимают отдельные строки пользовательского ввода, вычисляют их с помощью определяемой пользователем функции вычисления, а затем выводят результат. Ввод и вывод могут выполняться из stdin и stdout соответственно или быть подключены к любому потоку Node.js.

Экземпляры repl.REPLServer поддерживают автоматическое дополнение ввода, предварительный просмотр дополнений, простое редактирование строк в стиле Emacs, многострочный ввод, обратный поиск по истории в стиле ZSH, поиск по подстроке в истории в стиле ZSH, вывод с оформлением ANSI, сохранение и восстановление текущего состояния сеанса REPL, восстановление после ошибок и настраиваемые функции вычисления. В терминалах, не поддерживающих стили ANSI и редактирование строк в стиле Emacs, автоматически используется ограниченный набор возможностей.

Команды и специальные клавиши

Во всех экземплярах REPL поддерживаются следующие специальные команды:

  • .break: При вводе многострочного выражения введите команду .break (или нажмите Ctrl+C), чтобы отменить дальнейший ввод или обработку этого выражения.
  • .clear: Сбрасывает context REPL в пустой объект и очищает вводимое многострочное выражение.
  • .exit: Закрывает поток ввода-вывода, в результате чего REPL завершает работу.
  • .help: Показывает список специальных команд.
  • .save: Сохраняет текущий сеанс REPL в файл: > .save ./file/to/save.js
  • .load: Загружает файл в текущий сеанс REPL. > .load ./file/to/load.js
  • .editor: Переходит в режим редактора (Ctrl+D для завершения, Ctrl+C для отмены).
> .editor
// Entering editor mode (^D to finish, ^C to cancel)
function welcome(name) {
  return `Hello ${name}!`;
}

welcome('Node.js User');

// ^D
'Hello Node.js User!'
> copy

Следующие сочетания клавиш в REPL имеют особые эффекты:

  • Ctrl+C: При однократном нажатии действует так же, как команда .break. При двукратном нажатии на пустой строке действует так же, как команда .exit.
  • Ctrl+D: Действует так же, как команда .exit.
  • Tab: При нажатии на пустой строке отображает глобальные и локальные (область видимости) переменные. При нажатии во время ввода других данных отображает подходящие варианты автодополнения.

Сочетания клавиш для обратного поиска см. в разделе reverse-i-search. Все остальные сочетания клавиш см. в разделе Сочетания клавиш TTY.

Вычисление по умолчанию

По умолчанию все экземпляры repl.REPLServer используют функцию вычисления, которая вычисляет выражения JavaScript и предоставляет доступ к встроенным модулям Node.js. Это поведение по умолчанию можно переопределить, передав альтернативную функцию вычисления при создании экземпляра repl.REPLServer.

Выражения JavaScript

Вычислитель по умолчанию поддерживает непосредственное вычисление выражений JavaScript:

> 1 + 1
2
> const m = 2
undefined
> m + 1
3 copy

Если область видимости не ограничена блоками или функциями, переменные, объявленные неявно или с помощью ключевых слов const, let или var, объявляются в глобальной области видимости.

Глобальная и локальная область видимости

Вычислитель по умолчанию предоставляет доступ ко всем переменным, существующим в глобальной области видимости. Переменную можно явно сделать доступной в REPL, присвоив её объекту context, связанному с каждым REPLServer:

Модули JavaScript
import repl from 'node:repl';
const msg = 'message';

repl.start('> ').context.m = msg;
CommonJS
const repl = require('node:repl');
const msg = 'message';

repl.start('> ').context.m = msg;

Свойства объекта context отображаются в REPL как локальные:

$ node repl_test.js
> m
'message' copy

По умолчанию свойства контекста доступны для записи. Чтобы указать глобальные переменные, доступные только для чтения, свойства контекста необходимо определять с помощью Object.defineProperty():

Модули JavaScript
import repl from 'node:repl';
const msg = 'message';

const r = repl.start('> ');
Object.defineProperty(r.context, 'm', {
  configurable: false,
  enumerable: true,
  value: msg,
});
CommonJS
const repl = require('node:repl');
const msg = 'message';

const r = repl.start('> ');
Object.defineProperty(r.context, 'm', {
  configurable: false,
  enumerable: true,
  value: msg,
});
Доступ к основным модулям Node.js

При использовании вычислитель по умолчанию автоматически загружает основные модули Node.js в среду REPL. Например, если ввод fs ранее не объявлен как глобальная переменная или переменная с ограниченной областью видимости, он будет вычислен по требованию как global.fs = require('node:fs').

> fs.createReadStream('./some/file'); copy
Глобальные необработанные исключения
История
Версия Изменения
v12.3.0

Событие 'uncaughtException' теперь вызывается, если repl используется как отдельная программа.

REPL использует модуль domain, чтобы перехватывать все необработанные исключения в этом сеансе REPL.

Использование модуля domain в REPL имеет следующие побочные эффекты:

  • Необработанные исключения вызывают событие 'uncaughtException' только в автономном REPL. Добавление обработчика этого события в REPL внутри другой программы Node.js приводит к ошибке ERR_INVALID_REPL_INPUT.

    const r = repl.start();
    
    r.write('process.on("uncaughtException", () => console.log("Foobar"));\n');
    // Output stream includes:
    //   TypeError [ERR_INVALID_REPL_INPUT]: Listeners for `uncaughtException`
    //   cannot be used in the REPL
    
    r.close(); copy
  • Попытка использовать process.setUncaughtExceptionCaptureCallback() приводит к ошибке ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE.

Присваивание переменной _ (подчёркивание)
История
Версия Изменения
v9.8.0

Добавлена поддержка _error.

По умолчанию вычислитель присваивает результат последнего вычисленного выражения специальной переменной _ (подчёркивание). Явное присваивание значения _ отключает это поведение.

> [ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
> _.length
3
> _ += 1
Expression assignment to _ now disabled.
4
> 1 + 1
2
> _
4 copy

Аналогично, _error будет ссылаться на последнюю возникшую ошибку, если таковая была. Явное присваивание значения _error отключает это поведение.

> throw new Error('foo');
Uncaught Error: foo
> _error.message
'foo' copy
Ключевое слово await

На верхнем уровне поддерживается ключевое слово await.

> await Promise.resolve(123)
123
> await Promise.reject(new Error('REPL await'))
Uncaught Error: REPL await
    at REPL2:1:54
> const timeout = util.promisify(setTimeout);
undefined
> const old = Date.now(); await timeout(1000); console.log(Date.now() - old);
1002
undefined copy

Одно из известных ограничений использования ключевого слова await в REPL заключается в том, что оно нарушает лексическую область видимости ключевых слов const.

Например:

> const m = await Promise.resolve(123)
undefined
> m
123
> m = await Promise.resolve(234)
234
// redeclaring the constant does error
> const m = await Promise.resolve(345)
Uncaught SyntaxError: Identifier 'm' has already been declared copy

Параметр --no-experimental-repl-await отключает await верхнего уровня в REPL.

Обратный поиск

Добавлено в: v13.6.0, v12.17.0

REPL поддерживает двунаправленный обратный поиск, аналогичный поиску в ZSH. Он запускается нажатием Ctrl+R для поиска назад и Ctrl+S для поиска вперёд.

Повторяющиеся записи истории пропускаются.

Записи принимаются при нажатии любой клавиши, не относящейся к обратному поиску. Поиск можно отменить нажатием Esc или Ctrl+C.

При смене направления сразу выполняется поиск следующей записи в выбранном направлении, начиная с текущей позиции.

Пользовательские функции вычисления

При создании нового экземпляра repl.REPLServer можно указать пользовательскую функцию вычисления. Например, это можно использовать для создания полностью настраиваемых приложений REPL.

Функция вычисления принимает следующие четыре аргумента:

  • code <string> Код для выполнения (например, 1 + 1).
  • context <Object> Контекст, в котором выполняется код. Это может быть контекст JavaScript global или контекст, специфичный для экземпляра REPL, в зависимости от параметра useGlobal.
  • replResourceName <string> Идентификатор ресурса REPL, связанного с текущим вычислением кода. Может быть полезен для отладки.
  • callback <Function> Функция, вызываемая после завершения вычисления кода. Функция обратного вызова принимает два параметра:
    • Объект ошибки, передаваемый в случае возникновения ошибки при вычислении, или null/undefined, если ошибки не произошло.
    • Результат вычисления кода (не имеет значения, если передана ошибка).

В следующем примере показан REPL, который возводит заданное число в квадрат; если введённое значение не является числом, вместо этого выводится ошибка:

Модули JavaScript
import repl from 'node:repl';

function byThePowerOfTwo(number) {
  return number * number;
}

function myEval(code, context, replResourceName, callback) {
  if (isNaN(code)) {
    callback(new Error(`${code.trim()} is not a number`));
  } else {
    callback(null, byThePowerOfTwo(code));
  }
}

repl.start({ prompt: 'Enter a number: ', eval: myEval });
CommonJS
const repl = require('node:repl');

function byThePowerOfTwo(number) {
  return number * number;
}

function myEval(code, context, replResourceName, callback) {
  if (isNaN(code)) {
    callback(new Error(`${code.trim()} is not a number`));
  } else {
    callback(null, byThePowerOfTwo(code));
  }
}

repl.start({ prompt: 'Enter a number: ', eval: myEval });
Восстанавливаемые ошибки

В командной строке REPL нажатие Enter передаёт текущую строку ввода функции eval. Для поддержки многострочного ввода функция eval может вернуть экземпляр repl.Recoverable в переданную функцию обратного вызова:

function myEval(cmd, context, filename, callback) {
  let result;
  try {
    result = vm.runInThisContext(cmd);
  } catch (e) {
    if (isRecoverableError(e)) {
      return callback(new repl.Recoverable(e));
    }
  }
  callback(null, result);
}

function isRecoverableError(error) {
  if (error.name === 'SyntaxError') {
    return /^(Unexpected end of input|Unexpected token)/.test(error.message);
  }
  return false;
} copy

Настройка вывода REPL

По умолчанию экземпляры repl.REPLServer форматируют вывод с помощью метода util.inspect(), прежде чем записать его в предоставленный поток Writable (по умолчанию — process.stdout). Параметр проверки showProxy по умолчанию имеет значение true, а параметр colors получает значение true в зависимости от параметра useColors REPL.

При создании можно указать логический параметр useColors, чтобы указать функции записи по умолчанию использовать коды стилей ANSI для раскрашивания вывода метода util.inspect().

Если REPL запущен как отдельная программа, значения по умолчанию для проверки REPL также можно изменить из самого REPL с помощью свойства inspect.replDefaults, соответствующего параметру defaultOptions из util.inspect().

> util.inspect.replDefaults.compact = false;
false
> [1]
[
  1
]
> copy

Чтобы полностью настроить вывод экземпляра repl.REPLServer, передайте новую функцию для параметра writer при создании. Например, в следующем примере любой введённый текст просто преобразуется в верхний регистр:

Модули JavaScript
import repl from 'node:repl';

const r = repl.start({ prompt: '> ', eval: myEval, writer: myWriter });

function myEval(cmd, context, filename, callback) {
  callback(null, cmd);
}

function myWriter(output) {
  return output.toUpperCase();
}
CommonJS
const repl = require('node:repl');

const r = repl.start({ prompt: '> ', eval: myEval, writer: myWriter });

function myEval(cmd, context, filename, callback) {
  callback(null, cmd);
}

function myWriter(output) {
  return output.toUpperCase();
}

Класс: REPLServer

Добавлено в: v0.1.91
  • options <Object> | <string> См. repl.start()
  • Расширяет: <readline.Interface>

Экземпляры repl.REPLServer создаются с помощью метода repl.start() или непосредственно с помощью ключевого слова JavaScript new.

Модули JavaScript
import repl from 'node:repl';

const options = { useColors: true };

const firstInstance = repl.start(options);
const secondInstance = new repl.REPLServer(options);
CommonJS
const repl = require('node:repl');

const options = { useColors: true };

const firstInstance = repl.start(options);
const secondInstance = new repl.REPLServer(options);

Событие: 'exit'

Добавлено в: v0.7.7

Событие 'exit' вызывается при завершении работы REPL: после получения команды .exit в качестве ввода, двукратного нажатия пользователем Ctrl+C для отправки сигнала SIGINT или нажатия Ctrl+D для отправки сигнала 'end' в поток ввода. Функция обратного вызова обработчика вызывается без аргументов.

replServer.on('exit', () => {
  console.log('Received "exit" event from repl!');
  process.exit();
}); copy

Событие: 'reset'

Добавлено в: v0.11.0

Событие 'reset' вызывается при сбросе контекста REPL. Это происходит при получении команды .clear в качестве ввода, если только REPL не использует вычислитель по умолчанию и экземпляр repl.REPLServer не был создан с параметром useGlobal, установленным в true. Функция обратного вызова обработчика вызывается с ссылкой на объект context в качестве единственного аргумента.

Это можно использовать, прежде всего, для повторной инициализации контекста REPL в заранее определённое состояние:

Модули JavaScript
import repl from 'node:repl';

function initializeContext(context) {
  context.m = 'test';
}

const r = repl.start({ prompt: '> ' });
initializeContext(r.context);

r.on('reset', initializeContext);
CommonJS
const repl = require('node:repl');

function initializeContext(context) {
  context.m = 'test';
}

const r = repl.start({ prompt: '> ' });
initializeContext(r.context);

r.on('reset', initializeContext);

При выполнении этого кода глобальную переменную 'm' можно изменить, а затем вернуть к исходному значению с помощью команды .clear:

$ ./node example.js
> m
'test'
> m = 1
1
> m
1
> .clear
Clearing context...
> m
'test'
> copy

replServer.defineCommand(keyword, cmd)

Добавлено в: v0.3.0
  • keyword <string> Ключевое слово команды (без начального символа .).
  • cmd <Object> | <Function> Функция, вызываемая при обработке команды.

Метод replServer.defineCommand() используется для добавления в экземпляр REPL новых команд с префиксом .. Такие команды вызываются вводом символа ., за которым следует keyword. cmd — это либо Function, либо Object со следующими свойствами:

  • help <string> Справочный текст, отображаемый при вводе .help (необязательный).
  • action <Function> Функция для выполнения, которая может принимать один строковый аргумент.

В следующем примере показано добавление в экземпляр REPL двух новых команд:

Модули JavaScript
import repl from 'node:repl';

const replServer = repl.start({ prompt: '> ' });
replServer.defineCommand('sayhello', {
  help: 'Say hello',
  action(name) {
    this.clearBufferedCommand();
    console.log(`Hello, ${name}!`);
    this.displayPrompt();
  },
});
replServer.defineCommand('saybye', function saybye() {
  console.log('Goodbye!');
  this.close();
});
CommonJS
const repl = require('node:repl');

const replServer = repl.start({ prompt: '> ' });
replServer.defineCommand('sayhello', {
  help: 'Say hello',
  action(name) {
    this.clearBufferedCommand();
    console.log(`Hello, ${name}!`);
    this.displayPrompt();
  },
});
replServer.defineCommand('saybye', function saybye() {
  console.log('Goodbye!');
  this.close();
});

После этого новые команды можно использовать в экземпляре REPL:

> .sayhello Node.js User
Hello, Node.js User!
> .saybye
Goodbye! copy

replServer.displayPrompt([preserveCursor])

Добавлено в: v0.1.91
  • preserveCursor <boolean>

Метод replServer.displayPrompt() подготавливает экземпляр REPL к вводу пользователя: выводит настроенное prompt в новой строке в output и возобновляет input для приёма новых данных.

Во время ввода многострочных данных вместо «приглашения» выводится символ канала '|'.

Если preserveCursor имеет значение true, положение курсора не будет сброшено в 0.

Метод replServer.displayPrompt предназначен главным образом для вызова из функции действия команд, зарегистрированных с помощью метода replServer.defineCommand().

replServer.clearBufferedCommand()

Добавлено в: v9.0.0

Метод replServer.clearBufferedCommand() очищает все буферизованные, но ещё не выполненные команды. Этот метод предназначен главным образом для вызова из функции действия команд, зарегистрированных с помощью метода replServer.defineCommand().

replServer.setupHistory(historyConfig, callback)

История
Версия Изменения
v24.2.0

Параметр historyConfig обновлён: теперь он принимает объект со свойствами filePath, size, removeHistoryDuplicates и onHistoryFileLoaded.

v11.10.0

Добавлено в: v11.10.0

  • historyConfig <Object> | <string> путь к файлу истории. Если это строка, она задаёт путь к файлу истории. Если это объект, он может содержать следующие свойства:
    • filePath <string> путь к файлу истории
    • size <number> Максимальное количество сохраняемых строк истории. Чтобы отключить историю, задайте этому значению 0. Этот параметр имеет смысл только в том случае, если пользователь или внутренняя проверка output установили terminal в значение true; в противном случае механизм кэширования истории вообще не инициализируется. По умолчанию: 30.
    • removeHistoryDuplicates <boolean> Если значение true, при добавлении в список истории новой строки ввода, дублирующей более раннюю, старая строка удаляется из списка. По умолчанию: false.
    • onHistoryFileLoaded <Function> вызывается, когда запись истории готова или произошла ошибка
      • err <Error>
      • repl <repl.REPLServer>
  • callback <Function> вызывается, когда запись истории готова или произошла ошибка (необязательный параметр, если указан как onHistoryFileLoaded в historyConfig)
    • err <Error>
    • repl <repl.REPLServer>

Инициализирует файл журнала истории для экземпляра REPL. При запуске двоичного файла Node.js и использовании REPL командной строки файл истории инициализируется по умолчанию. Однако при программном создании REPL этого не происходит. Используйте этот метод для инициализации файла журнала истории при программной работе с экземплярами REPL.

repl.builtinModules

Добавлено в: v14.5.0Устарело с: v24.0.0
Стабильность: 0 - Устарело. Вместо этого используйте module.builtinModules.
  • Тип: <string[]>

Список имён некоторых модулей Node.js, например 'http'.

Доступна автоматическая миграция (исходный код):

npx codemod@latest @nodejs/repl-builtin-modules copy

repl.start([options])

История
Версия Изменения
v24.1.0

Добавлена возможность добавлять, редактировать и удалять многострочные записи при добавлении многострочной команды.

v24.0.0

Индикатор многострочного ввода теперь — «|» вместо «...». Добавлена поддержка многострочной истории. Теперь можно исправлять многострочные команды с синтаксическими ошибками: достаточно найти команду в истории и отредактировать её. При просмотре многострочной истории из старой версии Node структура строк не сохраняется.

v13.4.0, v12.17.0

Теперь доступен параметр preview.

v12.0.0

Теперь параметр terminal во всех случаях использует описание по умолчанию, а useColors проверяет hasColors(), если он доступен.

v10.0.0

Параметр REPL_MAGIC_MODE replMode удалён.

v6.3.0

Теперь поддерживается параметр breakEvalOnSigint.

v5.8.0

Параметр options теперь является необязательным.

v0.1.91

Добавлено в: v0.1.91

  • options <Object> | <string>
    • prompt <string> Приглашение для ввода. По умолчанию: '> ' (с пробелом в конце).
    • input <stream.Readable> Поток Readable, из которого считывается ввод REPL. По умолчанию: process.stdin.
    • output <stream.Writable> Поток Writable, в который записывается вывод REPL. По умолчанию: process.stdout.
    • terminal <boolean> Если значение true, указывает, что output следует считать терминалом TTY. По умолчанию: проверяется значение свойства isTTY потока output при создании экземпляра.
    • eval <Function> Функция, используемая при вычислении каждой заданной строки ввода. По умолчанию: асинхронная обёртка для функции JavaScript eval(). Функция eval может вызвать ошибку repl.Recoverable, указывая на то, что ввод не завершён и нужно запросить дополнительные строки. Подробнее см. в разделе пользовательские функции вычисления.
    • useColors <boolean> Если значение true, указывает, что функция writer по умолчанию должна добавлять к выводу REPL цветовое оформление ANSI. Если указана пользовательская функция writer, параметр не влияет на результат. По умолчанию: проверка поддержки цвета в потоке output, если значение terminal экземпляра REPL равно true.
    • useGlobal <boolean> Если значение true, указывает, что функция вычисления по умолчанию будет использовать JavaScript global в качестве контекста вместо создания нового отдельного контекста для экземпляра REPL. В REPL интерфейса командной строки Node это значение равно true. По умолчанию: false.
    • ignoreUndefined <boolean> Если значение true, функция записи по умолчанию не будет выводить возвращаемое значение команды, если оно вычисляется в undefined. По умолчанию: false.
    • writer <Function> Функция для форматирования вывода каждой команды перед записью в output. По умолчанию: util.inspect().
    • completer <Function> Необязательная функция для пользовательского автодополнения по клавише Tab. Пример см. в разделе readline.InterfaceCompleter.
    • replMode <symbol> Флаг, указывающий, выполняет ли вычислитель по умолчанию все команды JavaScript в строгом режиме или в обычном (нестрогом) режиме. Допустимые значения:
      • repl.REPL_MODE_SLOPPY для вычисления выражений в нестрогом режиме.
      • repl.REPL_MODE_STRICT для вычисления выражений в строгом режиме. Это эквивалентно добавлению 'use strict' перед каждым оператором repl.
    • breakEvalOnSigint <boolean> Прекращает вычисление текущего фрагмента кода при получении SIGINT, например при нажатии Ctrl+C. Нельзя использовать совместно с пользовательской функцией eval. По умолчанию: false.
    • preview <boolean> Определяет, отображает ли repl предварительный просмотр автодополнения и вывода. По умолчанию: true при использовании функции eval по умолчанию и false при использовании пользовательской функции eval. Если значение terminal ложно, предварительный просмотр не отображается, а значение preview не влияет на результат.
  • Возвращает: <repl.REPLServer>

Метод repl.start() создаёт и запускает экземпляр repl.REPLServer.

Если options — строка, она задаёт приглашение для ввода:

Модули JavaScript
import repl from 'node:repl';

// a Unix style prompt
repl.start('$ ');
CommonJS
const repl = require('node:repl');

// a Unix style prompt
repl.start('$ ');

Интерактивная оболочка Node.js (REPL)

Node.js использует модуль node:repl для предоставления собственного интерактивного интерфейса выполнения JavaScript. Его можно запустить, выполнив бинарный файл Node.js без аргументов (или передав аргумент -i):

$ node
> const a = [1, 2, 3];
undefined
> a
[ 1, 2, 3 ]
> a.forEach((v) => {
...   console.log(v);
...   });
1
2
3 copy

Параметры переменных окружения

Различные параметры поведения REPL Node.js можно настроить с помощью следующих переменных окружения:

  • NODE_REPL_HISTORY: Если указан допустимый путь, история REPL будет сохраняться в указанный файл, а не в .node_repl_history в домашнем каталоге пользователя. Если задать этому параметру значение '' (пустую строку), сохранение истории REPL будет отключено. Пробелы в начале и конце значения удаляются. В Windows переменные окружения с пустыми значениями недопустимы, поэтому задайте этой переменной один или несколько пробелов, чтобы отключить сохранение истории REPL.
  • NODE_REPL_HISTORY_SIZE: Определяет, сколько строк истории будет сохранено, если сохранение истории доступно. Значение должно быть положительным числом. По умолчанию: 1000.
  • NODE_REPL_MODE: Может иметь значение 'sloppy' или 'strict'. По умолчанию: 'sloppy', что позволяет выполнять код в нестрогом режиме.

Сохранение истории

По умолчанию REPL Node.js сохраняет историю между сеансами REPL node, записывая введённые данные в файл .node_repl_history, расположенный в домашнем каталоге пользователя. Сохранение можно отключить, задав переменную окружения NODE_REPL_HISTORY=''.

Использование REPL Node.js с расширенными редакторами командной строки

Чтобы использовать расширенные редакторы командной строки, запустите Node.js с переменной окружения NODE_NO_READLINE=1. Это запустит основную REPL и REPL отладчика с каноническими настройками терминала, что позволит использовать rlwrap.

Например, в файл .bashrc можно добавить следующее:

alias node="env NODE_NO_READLINE=1 rlwrap node" copy

Запуск нескольких экземпляров REPL в одном процессе

Можно создать и запустить несколько экземпляров REPL в одном запущенном экземпляре Node.js, которые будут использовать один объект global (задав для параметра useGlobal значение true), но иметь отдельные интерфейсы ввода-вывода.

Например, следующий пример предоставляет отдельные REPL через stdin, сокет Unix и сокет TCP, используя один и тот же объект global:

Модули JavaScript
import net from 'node:net';
import repl from 'node:repl';
import process from 'node:process';
import fs from 'node:fs';

let connections = 0;

repl.start({
  prompt: 'Node.js via stdin> ',
  useGlobal: true,
  input: process.stdin,
  output: process.stdout,
});

const unixSocketPath = '/tmp/node-repl-sock';

// If the socket file already exists let's remove it
fs.rmSync(unixSocketPath, { force: true });

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via Unix socket> ',
    useGlobal: true,
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(unixSocketPath);

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via TCP socket> ',
    useGlobal: true,
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(5001);
CommonJS
const net = require('node:net');
const repl = require('node:repl');
const fs = require('node:fs');

let connections = 0;

repl.start({
  prompt: 'Node.js via stdin> ',
  useGlobal: true,
  input: process.stdin,
  output: process.stdout,
});

const unixSocketPath = '/tmp/node-repl-sock';

// If the socket file already exists let's remove it
fs.rmSync(unixSocketPath, { force: true });

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via Unix socket> ',
    useGlobal: true,
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(unixSocketPath);

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via TCP socket> ',
    useGlobal: true,
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(5001);

При запуске этого приложения из командной строки REPL будет запущена для стандартного ввода. Другие клиенты REPL могут подключаться через сокет Unix или сокет TCP. Например, telnet удобно использовать для подключения к сокетам TCP, а socat можно использовать для подключения как к сокетам Unix, так и к сокетам TCP.

Если запустить REPL на сервере, использующем сокет Unix, а не стандартный ввод, к длительно работающему процессу Node.js можно подключиться без его перезапуска.

Примеры

Полнофункциональная «терминальная» REPL через net.Server и net.Socket

В этом примере показано, как запустить «полнофункциональную» (терминальную) REPL с помощью net.Server и net.Socket

Следующий скрипт запускает HTTP-сервер на порту 1337, который позволяет клиентам устанавливать сокетные подключения к экземпляру REPL.

Модули JavaScript
// repl-server.js
import repl from 'node:repl';
import net from 'node:net';

net
  .createServer((socket) => {
    const r = repl.start({
      prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `,
      input: socket,
      output: socket,
      terminal: true,
      useGlobal: false,
    });
    r.on('exit', () => {
      socket.end();
    });
    r.context.socket = socket;
  })
  .listen(1337);
CommonJS
// repl-server.js
const repl = require('node:repl');
const net = require('node:net');

net
  .createServer((socket) => {
    const r = repl.start({
      prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `,
      input: socket,
      output: socket,
      terminal: true,
      useGlobal: false,
    });
    r.on('exit', () => {
      socket.end();
    });
    r.context.socket = socket;
  })
  .listen(1337);

Следующий код реализует клиент, который может установить сокетное подключение к описанному выше серверу через порт 1337.

Модули JavaScript
// repl-client.js
import net from 'node:net';
import process from 'node:process';

const sock = net.connect(1337);

process.stdin.pipe(sock);
sock.pipe(process.stdout);

sock.on('connect', () => {
  process.stdin.resume();
  process.stdin.setRawMode(true);
});

sock.on('close', () => {
  process.stdin.setRawMode(false);
  process.stdin.pause();
  sock.removeListener('close', done);
});

process.stdin.on('end', () => {
  sock.destroy();
  console.log();
});

process.stdin.on('data', (b) => {
  if (b.length === 1 && b[0] === 4) {
    process.stdin.emit('end');
  }
});
CommonJS
// repl-client.js
const net = require('node:net');

const sock = net.connect(1337);

process.stdin.pipe(sock);
sock.pipe(process.stdout);

sock.on('connect', () => {
  process.stdin.resume();
  process.stdin.setRawMode(true);
});

sock.on('close', () => {
  process.stdin.setRawMode(false);
  process.stdin.pause();
  sock.removeListener('close', done);
});

process.stdin.on('end', () => {
  sock.destroy();
  console.log();
});

process.stdin.on('data', (b) => {
  if (b.length === 1 && b[0] === 4) {
    process.stdin.emit('end');
  }
});

Чтобы запустить пример, откройте на компьютере два разных терминала: в одном запустите сервер с помощью node repl-server.js, а в другом — node repl-client.js.

Исходный код: https://gist.github.com/TooTallNate/2209310.

REPL через curl

В этом примере показано, как запустить экземпляр REPL через curl()

Следующий скрипт запускает HTTP-сервер на порту 8000, который может принимать соединения, установленные с помощью curl().

Модули JavaScript
import http from 'node:http';
import repl from 'node:repl';

const server = http.createServer((req, res) => {
  res.setHeader('content-type', 'multipart/octet-stream');

  repl.start({
    prompt: 'curl repl> ',
    input: req,
    output: res,
    terminal: false,
    useColors: true,
    useGlobal: false,
  });
});

server.listen(8000);
CommonJS
const http = require('node:http');
const repl = require('node:repl');

const server = http.createServer((req, res) => {
  res.setHeader('content-type', 'multipart/octet-stream');

  repl.start({
    prompt: 'curl repl> ',
    input: req,
    output: res,
    terminal: false,
    useColors: true,
    useGlobal: false,
  });
});

server.listen(8000);

Когда приведённый выше скрипт запущен, можно использовать curl() для подключения к серверу и к его экземпляру REPL, выполнив curl --no-progress-meter -sSNT. localhost:8000.

Предупреждение Этот пример предназначен исключительно для обучения и демонстрирует, как запускать REPL Node.js с использованием различных потоков ввода-вывода. Его не следует использовать в производственной среде или в любом контексте, где важна безопасность, без дополнительных мер защиты. Если вам нужно реализовать REPL в реальном приложении, рассмотрите альтернативные подходы, снижающие эти риски, например использование безопасных механизмов ввода и отказ от открытых сетевых интерфейсов.

Исходный код: https://gist.github.com/TooTallNate/2053342.

© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v24.x/docs/api/repl.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API