Spec-Zone.ru › Node.js 22 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(historyPath, callback)

Добавлено в: v11.10.0
  • historyPath <string> путь к файлу истории
  • callback <Function> вызывается, когда запись истории готова или произошла ошибка
    • err <Error>
    • repl <repl.REPLServer>

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

repl.builtinModules

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

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

repl.start([options])

История
Версия Изменения
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 по умолчанию должна использовать оформление цветов ANSI для вывода REPL. Если предоставлена пользовательская функция 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('$ ');

REPL Node.js

Сам 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 в stdin. Другие клиенты REPL могут подключаться через сокет Unix или сокет TCP. Например, telnet удобно использовать для подключения к сокетам TCP, а socat можно использовать для подключения как к сокетам Unix, так и к сокетам TCP.

Запустив REPL на сервере, использующем сокет Unix, вместо stdin, можно подключиться к длительно работающему процессу 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-v22.x/docs/api/repl.html

Spec-Zone.ru

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